Add premise temporal-distribution annotation - #197
Open
TimoDiepers wants to merge 14 commits into
Open
Conversation
Add bw_timex/premise_temporal.py with TemporalSpecs and AnnotationReport dataclasses and premise_params_to_td() converter for distribution codes 1/3/4/5/6. All 7 unit tests pass; full suite (222 tests) remains green.
…ise_params_to_td Issue 1: easy_timedelta_distribution evaluates norm.pdf on a normalized [-0.5, 0.5] axis (not in years), so passing temporal_scale in years made all normal TDs nearly flat. Fix: convert to normalized axis via scale / (end - start) before the call. Issue 2: when temporal_min == temporal_max, start == end after _bounds(), causing easy_timedelta_distribution to raise "Start value is later than end". Fix: early return _single_pulse(start) for the degenerate case, covering codes 3/4/5. Tests added: test_normal_peak_near_loc (verifies mass concentration and narrow>wide spread ratio), test_degenerate_min_equals_max_codes_345 (verifies single pulse for each code). Also added missing yrs.min()==0 assertion to test_triangular_code_5. All 224 tests pass, no regressions.
Appends annotate_database() (+ _clean/_supplier_key helpers) to bw_timex/premise_temporal.py; mirrors premise's biomass-growth, stock-asset, maintenance (uniform[0,lifetime]), and end-of-life (pulse@lifetime) placement rules on an existing bw2 database via an injected TemporalSpecs — no premise import required. Adds 5 bw2-fixture tests (RED→GREEN verified, 229 total passing).
Add _import_premise_trails (lazy, feature-detects TrailsDataPackage + FILEPATH_TEMPORAL_PARAMETERS), _DummySelf stand-in, and load_temporal_specs(path=None) -> TemporalSpecs that delegates CSV parsing to premise's own loader. premise is kept as an optional dep; core bw_timex imports are unaffected. Two new tests: monkeypatched ImportError test passes; importorskip test skips (premise not installed).
Add `add_premise_temporal_distributions(databases, *, overwrite=False)` as the public entry point for premise temporal annotation; export it from `bw_timex.__init__`; declare `[project.optional-dependencies] premise` in pyproject.toml; add the two Task-4 tests (17 passed, 1 skipped).
premise 2.5.0 is not yet on PyPI, making the pinned requirement unresolvable. The runtime feature-detect guard in _import_premise_trails already gates on temporal-support, so the version floor is unnecessary.
Append test_core_import_does_not_require_premise to tests/test_premise_temporal.py. Validates that bw_timex.premise_temporal can be imported and used (premise_params_to_td converter) without premise installed, proving the core is premise-free. Test monkeypatches builtins.__import__ to block premise, reloads the module, and confirms the converter still works.
Replace unguarded `_apply(exc, premise_params_to_td(...))` calls with a `_convert_and_apply(ds, exc, params)` helper that catches any Exception, routes it to `_fault`, and continues — so a single bad exchange never aborts the whole database pass. Remove the now-unused `_apply`. Add `test_malformed_stock_asset_params_is_faulted_not_raised`: proves code-99 stock_asset_params produces a fault, not a raised exception. Add `test_end_of_life_pulse_at_lifetime`: proves the end_of_life path emits a single-date pulse at the correct year. All 235 tests pass; 1 premise-gated skip.
premise pins scipy<1.14 (incompatible with bw2calc>2.0.1), but scipy<1.14 has no Python 3.13 wheels. Declaring a `premise` optional extra forced the unified uv lock to scipy 1.13.1 across the board, so `uv sync` failed to build scipy on the 3.13 CI matrix jobs. Remove the extra and restore pyproject.toml/uv.lock to main (scipy 1.17.1). premise stays a lazily-imported, feature-detected optional runtime dependency; the import-error message now tells users to install premise themselves.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #197 +/- ##
==========================================
+ Coverage 76.10% 76.56% +0.46%
==========================================
Files 10 11 +1
Lines 2113 2300 +187
==========================================
+ Hits 1608 1761 +153
- Misses 505 539 +34 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
TimoDiepers
force-pushed
the
feat/premise-temporal
branch
from
June 24, 2026 15:30
25c3c07 to
8c6acb7
Compare
create_biosphere_datapackage hardcoded flip_array to length 1, so any descended/temporalized background producer with more than one biosphere flow raised ShapeMismatch under traverse_background=True. Build a per-flow all-False flip_array (biosphere flows are never flipped). Add a multibio fixture (descended bg_B carrying CO2 + CH4) and a parametrized test (priority & bfs) that reproduced the crash.
…riangular) - load_temporal_specs: strip a UTF-8 BOM before handing the path to premise's CSV loader. premise's bundled temporal_distributions.csv ships a BOM and its loader opens it without utf-8-sig, corrupting the 'name' column. - Correct install guidance in docstring/errors: premise's trails work is unreleased (git branch), and its scipy<1.14 pin means Python <=3.12. - premise_params_to_td: add code 2 (lognormal of fleet age; median = -loc, fixed log-space sigma 0.55, negative-loc convention, truncated to [min,max]), and degrade a code-5 triangular whose integer span is too narrow for >=3 steps to uniform. All curated stock_asset/biomass rows now convert.
Showcases add_premise_temporal_distributions on the REMIND/ecoinvent variants: annotates every background variant (required for traverse_background to shift dates), inspects the written TemporalDistributions, and runs a time-explicit TimexLCA.
Superseded by example_premise_temporal_distributions.ipynb, which does the same background temporalization automatically from premise's curated trails data instead of by hand.
Simplify the install note (install bw_timex + premise trails branch together on Python 3.12), drop the removed sibling-notebook reference, and add dynamic LCIA + characterized-inventory waterfall steps.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds
bw_timex.add_premise_temporal_distributions(...)to annotate existing premise-generated, year-specific bw2 databases withbw_temporalis.TemporalDistributions, so a premise background can be used for time-explicit LCA without hand-defining temporal data.The temporal parameters and placement rules are sourced from premise's own
temporal_distributions.csv(theTrailsDataPackagework, premise ≥ 2.5.0): biomass-growth params go on the dataset's"Carbon dioxide, in air"biosphere exchange; stock-asset / maintenance / end-of-life params go on supplier-keyed technosphere exchanges (maintenance = uniform over[0, lifetime], end-of-life = pulse at lifetime). Ambiguous tags, missing supplier products, missing lifetimes, and malformed rows are recorded as faults and skipped — annotation never aborts mid-database.No materialization /
unfold: this operates on databases the user already has.Design / API
premise_params_to_td(params)— pure converter from premise distribution codes (1 discrete, 3 normal, 4 uniform, 5 triangular, 6 discrete-empirical) to a years-resolutionTemporalDistribution(normal scale normalized to the year range; degeneratemin==max→ single pulse).annotate_database(db_name, specs, *, overwrite=False)— applies premise's placement rules to one bw2 database using an injectedTemporalSpecs(premise-free, fully unit-tested).load_temporal_specs()— reuses premise's CSV loader; premise is imported lazily and feature-detected (not version-gated), so corebw_timeximports without premise.add_premise_temporal_distributions(databases, *, overwrite=False)— public entry point; returns an aggregatedAnnotationReport.premiseis a lazily-imported, feature-detected optional runtime dependency. It is not declared as a packaging extra because premise pinsscipy<1.14, which has no Python 3.13 wheels; install premise separately (e.g.pip install premise>=2.5.0) in an environment that satisfies that constraint.Tests
New
tests/test_premise_temporal.py: converter shapes for every code, placement rules on synthetic bw2 fixtures (biomass-growth, maintenance, end-of-life, ambiguity, idempotency/overwrite, unknown DB, malformed-row fault), the premise-loader adapter (premise-gated /importorskip), and a guard that core import + the converter work with premise blocked. Full suite: 235 passed, 1 skipped.