Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,43 @@

All notable changes to this project are documented in this file.

## [2.4.9.2]

### Added
- Added `NewDatabase.write_scenario_array_db_to_brightway` for modern
Brightway. It writes one union database and one compressed `bw_processing`
ZIP containing synchronized technosphere and biosphere arrays, ordered as
`original` followed by the generated scenarios.
- Added `bw_processing >= 1.0` to the Brightway 2.5 optional dependencies.

### Changed
- Reused the superstructure preparation pipeline for scenario-array export,
preserving existing superstructure CSV, Excel, and Feather behavior while
applying the same loading, validation, duplicate aggregation, reporting, and
cleanup to both export paths.
- Stored only changing matrix coordinates in deterministic sequential arrays;
the written base database retains the `original` state when the ZIP is not
loaded.

### Fixed
- Included matching production rows when changed self-consumption exchanges
are netted into technosphere diagonals, preventing invalid or singular
scenario matrices.

### Documentation
- Added a complete three-pathway IMAGE 2050 example for the
`ecoinvent-3.12-cutoff` project to the examples notebook, loading guide,
and README, including multi-activity scoring, base-database validation,
synchronized scenario selection, and wraparound behavior.

### Tests
- Added unit and orchestration coverage for scenario ordering, values, indices,
technosphere flips, biosphere placement, structural zeros, validation errors,
atomic ZIP output, and production/self-consumption netting.
- Validated the export end to end with IMAGE SSP1-L, SSP2-M, and SSP3-H for
2050, checking three activities against the original database and confirming
deterministic scenario selection and wraparound.

## [2.4.9.1]

### Added
Expand Down
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,30 @@ How to use it?

The best way is to follow [the examples from the Jupyter Notebook](https://github.com/polca/premise/blob/master/examples/examples.ipynb).

Sequential scenario arrays in Brightway 2.5
--------------------------------------------

With modern Brightway (`bw2data >= 4`), one export call can write a union
database plus a compressed, deterministic scenario-array ZIP:

```python
array_path = ndb.write_scenario_array_db_to_brightway(
name="scenario-ensemble",
)
```

The initial array state is `original`; successive `next(lca)` calls select each
generated scenario in `ndb.scenarios` order and then wrap to `original`.
Append `array_path` after the database datapackages passed to `bc.LCA` so that
the joint technosphere and biosphere arrays override the base database. The ZIP
is project-specific and provides deterministic scenario enumeration, not
probability-weighted Monte Carlo sampling.

See the [complete three-IMAGE-scenario notebook example](https://github.com/polca/premise/blob/master/examples/examples.ipynb)
and the [Brightway loading guide](https://premise.readthedocs.io/en/latest/load.html#sequential-scenario-arrays-modern-brightway)
for database creation, exact activity matching, multi-activity LCIA, and
wraparound/base-database checks.

## Disclaimer on the Use of IAM-Based Scenarios in Premise

It is essential to recognize the nature and
Expand Down
191 changes: 191 additions & 0 deletions docs/load.rst
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,197 @@ Finally, you can also give a name to the superstructure database:

Superstructure databases can only be used by Activity-Browser at the moment.

Sequential scenario arrays (modern Brightway)
**********************************************

With modern Brightway (``bw2data >= 4``), *premise* can write one union
database and one compressed ``bw_processing`` ZIP for deterministic scenario
enumeration. The package contains joint technosphere and biosphere arrays in
this order: ``original`` first, followed by the generated scenarios in
``ndb.scenarios`` order.

This export is useful when the same functional unit must be evaluated across
many *premise* scenarios without writing one Brightway database per scenario.
It is separate from the Activity Browser superstructure workflow: no scenario
difference CSV is created.

Requirements and output
^^^^^^^^^^^^^^^^^^^^^^^

The export requires all of the following:

* modern Brightway (``bw2data >= 4``) and ``bw_processing >= 1.0``;
* an active Brightway project containing the source and configured biosphere
databases;
* at least two generated scenarios with unique labels; and
* a completed scenario transformation, normally ``ndb.update()``.

Calling ``write_scenario_array_db_to_brightway`` writes the union database to
the active project before resolving the Brightway IDs used by the array ZIP.
The return value is the absolute path to the ZIP. If ``filepath`` is omitted,
the package is written to
``export/scenario arrays/scenario_array_<sanitized-name>.zip``. When supplied,
``filepath`` is the complete destination filename and must end in ``.zip``;
missing parent directories are created and an existing ZIP is replaced
atomically.

Complete three-scenario IMAGE example
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The following example uses the ``ecoinvent-3.12-cutoff`` project and applies
all sector updates to three IMAGE pathways for 2050. Set ``PREMISE_KEY`` in the
environment before running it. The source and biosphere database names must
match the names registered in your project.

.. code-block:: python

import os

import bw2data as bd

from premise import NewDatabase

PROJECT = "ecoinvent-3.12-cutoff"
SOURCE_DATABASE = "ecoinvent-3.12-cutoff"
BIOSPHERE_DATABASE = "ecoinvent-3.12-biosphere"
DATABASE_NAME = "premise-image-2050-three-pathways-array"
SCENARIOS = [
{"model": "image", "pathway": "SSP1-L", "year": 2050},
{"model": "image", "pathway": "SSP2-M", "year": 2050},
{"model": "image", "pathway": "SSP3-H", "year": 2050},
]

bd.projects.set_current(PROJECT)
missing = [
name
for name in (SOURCE_DATABASE, BIOSPHERE_DATABASE)
if name not in bd.databases
]
if missing:
raise ValueError(f"Missing Brightway databases: {missing}")

ndb = NewDatabase(
scenarios=SCENARIOS,
source_db=SOURCE_DATABASE,
source_version="3.12",
source_type="brightway",
system_model="cutoff",
biosphere_name=BIOSPHERE_DATABASE,
key=os.environ["PREMISE_KEY"],
)
ndb.update() # apply all sector transformations

array_path = ndb.write_scenario_array_db_to_brightway(
name=DATABASE_NAME,
)
print(array_path)

The one export call writes both ``DATABASE_NAME`` to the active Brightway
project and the returned array ZIP. Do not call ``write_db_to_brightway`` first
for the same database name.

Calculate and enumerate scores
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Select activities by their name, reference product, and location, and require
exactly one match. This example evaluates one kilowatt-hour of Swiss
low-voltage electricity with the ecoinvent 3.12 EF v3.1 GWP100 method.

.. code-block:: python

import bw2calc as bc
import numpy as np

from premise.utils import create_scenario_list

method = (
"ecoinvent-3.12",
"EF v3.1",
"climate change",
"global warming potential (GWP100)",
)
if method not in bd.methods:
raise ValueError(f"Missing LCIA method: {method}")

database = bd.Database(DATABASE_NAME)
matches = [
activity
for activity in database
if activity.get("name") == "market for electricity, low voltage"
and activity.get("reference product") == "electricity, low voltage"
and activity.get("location") == "CH"
]
if len(matches) != 1:
raise ValueError(f"Expected one matching activity; found {len(matches)}")
functional_unit = matches[0]

demand, data_objs, remapping = bd.prepare_lca_inputs(
{functional_unit: 1},
method=method,
)

lca = bc.LCA(
demand,
data_objs=[*data_objs, array_path],
remapping_dicts=remapping,
use_arrays=True,
use_distributions=False,
)

lca.lci()
lca.lcia()
scores = [lca.score] # original

for _ in ndb.scenarios:
next(lca)
scores.append(lca.score)

labels = ["original", *create_scenario_list(ndb.scenarios)]
print(dict(zip(labels, scores)))

# The next selection after the final scenario wraps to original.
next(lca)
assert np.isclose(lca.score, scores[0])

The returned ZIP must be appended *after* the database datapackages in
``data_objs`` so its values override the changing coordinates in the base
database. The initial LCA represents ``original``. Each ``next(lca)`` advances
the technosphere and biosphere arrays together to the next complete scenario;
the selection after the final scenario wraps to ``original``.

To confirm that the written database remains at its original values without
the overlay, create a second LCA with the unmodified ``data_objs``:

.. code-block:: python

base_lca = bc.LCA(
demand,
data_objs=data_objs,
remapping_dicts=remapping,
use_arrays=False,
use_distributions=False,
)
base_lca.lci()
base_lca.lcia()
assert np.isclose(base_lca.score, scores[0])

Only coordinates that vary across ``original`` and the generated scenarios are
stored in the ZIP. Existing exchange uncertainty distributions are not copied
to the scenario arrays, and this version does not combine array selection with
parameter uncertainty, weights, seeds, or random sampling.

.. warning::

The ZIP is tied to the active Brightway project and to the IDs assigned to
the written database. Regenerate it after moving, deleting, or rewriting
that database. These arrays enumerate scenarios deterministically; they are
not probability-weighted Monte Carlo samples.

The repository's `examples notebook`_ includes the complete three-activity
workflow and reference scores from an ecoinvent 3.12 validation run.

.. _examples notebook: https://github.com/polca/premise/blob/master/examples/examples.ipynb

As sparse matrices
------------------

Expand Down
Loading
Loading