From 25e484aac9744a88fe6f9f3d717cb1fe46687506 Mon Sep 17 00:00:00 2001 From: TimoDiepers Date: Wed, 18 Sep 2024 08:36:02 +0200 Subject: [PATCH] add starting datetime argument to build_timeline --- bw_timex/timeline_builder.py | 5 ++ bw_timex/timex_lca.py | 6 ++ tests/test_starting_datetime.py | 117 ++++++++++++++++++++++++++++++++ 3 files changed, 128 insertions(+) create mode 100644 tests/test_starting_datetime.py diff --git a/bw_timex/timeline_builder.py b/bw_timex/timeline_builder.py index f1b5680..9e42600 100644 --- a/bw_timex/timeline_builder.py +++ b/bw_timex/timeline_builder.py @@ -28,6 +28,7 @@ class TimelineBuilder: def __init__( self, slca: LCA, + starting_datetime: datetime, edge_filter_function: Callable, database_date_dict: dict, database_date_dict_static_only: dict, @@ -45,6 +46,8 @@ def __init__( ---------- slca: LCA A static LCA object. + starting_datetime: datetime | str, optional + Point in time when the demand occurs. edge_filter_function: Callable A callable that filters edges. If not provided, a function that always returns False is used. database_date_dict: dict @@ -65,6 +68,7 @@ def __init__( Keyword arguments passed to the EdgeExtractor which inherits from TemporalisLCA. """ self.slca = slca + self.starting_datetime = starting_datetime self.edge_filter_function = edge_filter_function self.database_date_dict = database_date_dict self.database_date_dict_static_only = database_date_dict_static_only @@ -90,6 +94,7 @@ def __init__( self.edge_extractor = EdgeExtractor( slca, + starting_datetime=self.starting_datetime, *args, edge_filter_function=edge_filter_function, cutoff=self.cutoff, diff --git a/bw_timex/timex_lca.py b/bw_timex/timex_lca.py index 4fb747f..9b1ce50 100644 --- a/bw_timex/timex_lca.py +++ b/bw_timex/timex_lca.py @@ -163,6 +163,7 @@ def __init__( def build_timeline( self, + starting_datetime: datetime | str = "now", temporal_grouping: str = "year", interpolation_type: str = "linear", edge_filter_function: Callable = None, @@ -178,6 +179,9 @@ def build_timeline( Parameters ---------- + starting_datetime: datetime | str, optional + Point in time when the demand occurs. This is the initial starting point of the + timeline. Something like `"now"` or `"2023-01-01"`. Default is `"now"`. temporal_grouping : str, optional Time resolution for grouping exchanges over time in the timeline. Default is 'year', other options are 'month', 'day', 'hour'. @@ -223,6 +227,7 @@ def build_timeline( else: self.edge_filter_function = edge_filter_function + self.starting_datetime = starting_datetime self.temporal_grouping = temporal_grouping self.interpolation_type = interpolation_type self.cutoff = cutoff @@ -237,6 +242,7 @@ def build_timeline( # with the TimelineBuilder.build_timeline() method. self.timeline_builder = TimelineBuilder( self.base_lca, + self.starting_datetime, self.edge_filter_function, self.database_date_dict, self.database_date_dict_static_only, diff --git a/tests/test_starting_datetime.py b/tests/test_starting_datetime.py new file mode 100644 index 0000000..cc500f2 --- /dev/null +++ b/tests/test_starting_datetime.py @@ -0,0 +1,117 @@ +import math +from datetime import datetime + +import bw2data as bd +import pytest +from bw2data.tests import bw2test + +from bw_timex import TimexLCA + +@pytest.fixture +@bw2test +def ab_db(): + bd.Database("bio").write( + { + ("bio", "CO2"): { + "type": "biosphere", + "name": "carbon dioxide", + }, + }, + ) + + bd.Database("db_2030").write( + { + ("db_2030", "B"): { + "name": "B", + "location": "somewhere", + "reference product": "B", + "exchanges": [ + { + "amount": 1, + "type": "production", + "input": ("db_2030", "B"), + }, + { + "amount": 10, + "input": ("bio", "CO2"), + "type": "biosphere", + }, + ], + }, + }, + ) + + bd.Database("db_2020").write( + { + ("db_2020", "B"): { + "name": "B", + "location": "somewhere", + "reference product": "B", + "exchanges": [ + { + "amount": 1, + "type": "production", + "input": ("db_2020", "B"), + }, + { + "amount": 15, + "input": ("bio", "CO2"), + "type": "biosphere", + }, + ], + }, + }, + ) + + bd.Database("foreground").write( + { + ("foreground", "A"): { + "name": "A", + "location": "somewhere", + "reference product": "A", + "exchanges": [ + { + "amount": 1, + "type": "production", + "input": ("foreground", "A"), + }, + { + "amount": 1, + "input": ("db_2020", "B"), + "type": "technosphere", + }, + ], + }, + } + ) + + bd.Method(("GWP", "example")).write( + [ + (("bio", "CO2"), 1), + ] + ) + +def test_starting_datetime(ab_db): + method = ("GWP", "example") + database_date_dict = { + "db_2020": datetime.strptime("2020", "%Y"), + "db_2030": datetime.strptime("2030", "%Y"), + "foreground": "dynamic", + } + fu = ("foreground", "A") + tlca = TimexLCA({fu: 1}, method, database_date_dict) + + tlca.build_timeline(starting_datetime="2020-01-01") + tlca.lci() + tlca.static_lcia() + assert math.isclose(tlca.static_score, 15, rel_tol=1e-9) + + tlca.build_timeline(starting_datetime="2030-01-01") + tlca.lci() + tlca.static_lcia() + assert math.isclose(tlca.static_score, 10, rel_tol=1e-9) + + tlca.build_timeline(starting_datetime="2025-01-01") + tlca.lci() + tlca.static_lcia() + assert math.isclose(tlca.static_score, 12.5, rel_tol=1e-3)