diff --git a/bw_timex/dynamic_biosphere_builder.py b/bw_timex/dynamic_biosphere_builder.py index d7e4812..97bfa2b 100644 --- a/bw_timex/dynamic_biosphere_builder.py +++ b/bw_timex/dynamic_biosphere_builder.py @@ -6,13 +6,13 @@ from scipy import sparse as sp from .helper_classes import SetList -from .utils import convert_date_string_to_datetime, resolve_temporalized_node_name +from .utils import convert_date_string_to_datetime class DynamicBiosphereBuilder: """ - This class is used to build a dynamic biosphere matrix, which in contrast to the normal biosphere matrix has rows for each biosphere flow at their time of emission. - Thus, the dimensions are (bio_flows at a specific timestep) x (processes). + Class for building a dynamic biosphere matrix with dimensions + (biosphere flow at a specific point in time) x (processes) """ def __init__( @@ -37,25 +37,31 @@ def __init__( lca_obj : LCA objecct instance of the bw2calc LCA class, e.g. TimexLCA.lca activity_time_mapping_dict : dict - A dictionary mapping activity to their respective timing in the format (('database', 'code'), datetime_as_integer): time_mapping_id) + A dictionary mapping activity to their respective timing in the format + (('database', 'code'), datetime_as_integer): time_mapping_id) biosphere_time_mapping_dict : dict - A dictionary mapping biosphere flows to their respective timing in the format (('database', 'code'), datetime_as_integer): time_mapping_id), at this point still empty. + A dictionary mapping biosphere flows to their respective timing in the format + (('database', 'code'), datetime_as_integer): time_mapping_id), empty at this point. demand_timing_dict : dict A dictionary mapping of the demand to demand time node_id_collection_dict : dict A dictionary containing lists of node ids for different node subsets temporal_grouping : str - A string indicating the temporal grouping of the processes, e.g. 'year', 'month', 'day', 'hour' + A string indicating the temporal grouping of the processes, e.g. 'year', 'month', + 'day', 'hour' database_date_dict : dict A dictionary mapping database names to their respective date database_date_dict_static_only : dict - A dictionary mapping database names to their respective date, but only containing static databases, which are the background databases. + A dictionary mapping database names to their respective date, but only containing + static databases, which are the background databases. timeline: pd.DataFrame The edge timeline, created from TimexLCA.build_timeline() interdatabase_activity_mapping : SetList - A list of sets, where each set contains the activity ids of the same activity in different databases + A list of sets, where each set contains the activity ids of the same activity in + different databases from_timeline : bool, optional - A boolean indicating if the dynamic biosphere matrix is built directly from the timeline. Default is False. + A boolean indicating if the dynamic biosphere matrix is built directly from the + timeline. Default is False. Returns ------- @@ -99,18 +105,20 @@ def build_dynamic_biosphere_matrix( from_timeline: bool = False, ): """ - This function creates a separate biosphere matrix, with the dimenions (bio_flows at a specific timestep) x (processes). - Every temporally resolved biosphere flow has its own row in the matrix, making it highly sparse. - The timing of the emitting process and potential additional temporal information of the bioshpere flow (e.g. delay of emission compared to timing of process) are considered. + This function creates a separate biosphere matrix, with the dimenions + (bio_flows at a specific timestep) x (processes). - Absolute Temporal Distributions for biosphere exchanges are dealt with as a look up function: - If an activity happens at timestamp X then and the biosphere exchange has an absolute temporal - distribution (ATD), it looks up the amount from from the ATD correspnding to timestamp X. - E.g.: X = 2024, TD=(data=[2020,2021,2022,2023,2024,.....,2120 ], amount=[3,4,4,5,6,......,3]), - it will look up the value 6 corresponding 2024. If timestamp X does not exist it find the nearest - timestamp available (if two timestamps are equally close, it will take the first in order of - apearance (see numpy.argmin() for this behabiour). + Every temporally resolved biosphere flow has its own row in the matrix, making it highly + sparse. The timing of the emitting process and potential additional temporal information of + the bioshpere flow (e.g. delay of emission compared to timing of process) are considered. + Absolute Temporal Distributions for biosphere exchanges are dealt with as a look up + function: If an activity happens at timestamp X then and the biosphere exchange has an + absolute temporal distribution (ATD), it looks up the amount from from the ATD correspnding + to timestamp X. E.g.: X = 2024, TD=(data=[2020,2021,2022,2023,2024,.....,2120 ], + amount=[3,4,4,5,6,......,3]), it will look up the value 6 corresponding 2024. If timestamp X + does not exist it find the nearest timestamp available (if two timestamps are equally close, + it will take the first in order of appearance (see numpy.argmin() for this behabiour). Parameters ---------- @@ -119,7 +127,8 @@ def build_dynamic_biosphere_matrix( Returns ------- dynamic_biomatrix : scipy.sparse.csr_matrix - A sparse matrix with the dimensions (bio_flows at a specific timestep) x (processes), where every row represents a biosphere flow at a specific time. + A sparse matrix with the dimensions (bio_flows at a specific timestep) x (processes), + where every row represents a biosphere flow at a specific time. """ for row in self.timeline.itertuples(): @@ -131,12 +140,12 @@ def build_dynamic_biosphere_matrix( idx ] # get the matrix column index + # time is here an integer, with various length depending on temporal grouping, e.g. + # [Y] -> 2024, [M] - > 202401 ( (original_db, original_code), time, - ) = self.activity_time_mapping_dict.reversed()[ # time is here an integer, with various length depending on temporal grouping, e.g. [Y] -> 2024, [M] - > 202401 - idx - ] + ) = self.activity_time_mapping_dict.reversed()[idx] if idx in self.node_id_collection_dict["temporalized_processes"]: @@ -159,9 +168,9 @@ def build_dynamic_biosphere_matrix( if exc.get("temporal_distribution"): td_dates = exc["temporal_distribution"].date td_values = exc["temporal_distribution"].amount - if ( - type(td_dates[0]) == np.datetime64 - ): # If the biosphere flows have an absolute TD, this means we have to look up the biosphere flow for the activity time (td_producer) + # If the biosphere flows have an absolute TD, this means we have to look up + # the biosphere flow for the activity time (td_producer) + if isinstance(td_dates[0], np.datetime64): dates = td_producer # datetime array, same time as producer values = [ exc["amount"] @@ -175,9 +184,8 @@ def build_dynamic_biosphere_matrix( ] ] # look up the value correponding to the absolute producer time else: - dates = ( - td_producer + td_dates - ) # we can add a datetime of length 1 to a timedelta of length N without problems + # we can add a datetime of len(1)to a timedelta of len(N) easily + dates = td_producer + td_dates values = exc["amount"] * td_values else: # exchange has no TD @@ -199,12 +207,12 @@ def build_dynamic_biosphere_matrix( amount=amount, ) elif idx in self.node_id_collection_dict["temporal_markets"]: + # time is here an integer, with various length depending on temporal grouping, e.g. + # [Y] -> 2024, [M] - > 202401 ( (original_db, original_code), time, - ) = self.activity_time_mapping_dict.reversed()[ # time is here an integer, with various length depending on temporal grouping, e.g. [Y] -> 2024, [M] - > 202401 - idx - ] + ) = self.activity_time_mapping_dict.reversed()[idx] if from_timeline: demand = self.demand_from_timeline(row, original_db) @@ -213,10 +221,9 @@ def build_dynamic_biosphere_matrix( if demand: self.lca_obj.redo_lci(demand) - - aggregated_inventory = self.lca_obj.inventory.sum( - axis=1 - ) # aggregated biosphere flows of background supply chain emissions. Rows are bioflows. + # aggregated biosphere flows of background supply chain emissions. + # Rows are bioflows. + aggregated_inventory = self.lca_obj.inventory.sum(axis=1) for row_idx, amount in enumerate(aggregated_inventory.A1): bioflow = self.lca_obj.dicts.biosphere.reversed[row_idx] @@ -260,7 +267,6 @@ def demand_from_timeline(self, row, original_db): """ demand = {} for db, amount in row.interpolation_weights.items(): - # if not db in act_time_combinations.get(original_code): #check if act time combination already exists [(timed_act_id, _)] = [ (act, db_name) for (act, db_name) in self.interdatabase_activity_mapping[ @@ -268,7 +274,6 @@ def demand_from_timeline(self, row, original_db): ] if db == db_name ] - # t_act = bd.get_activity(timed_act_id) demand[timed_act_id] = amount return demand @@ -299,8 +304,9 @@ def demand_from_technosphere(self, idx, process_col_index): def add_matrix_entry_for_biosphere_flows(self, row, col, amount): """ - Adds an entry to the lists of row, col and values, which are then used to construct the dynamic biosphere matrix. - Only unqiue entries are added, i.e. if the same row and col index already exists, the value is not added again. + Adds an entry to the lists of row, col and values, which are then used to construct the + dynamic biosphere matrix. Only unqiue entries are added, i.e. if the same row and col index + already exists, the value is not added again. Parameters ---------- diff --git a/bw_timex/timeline_builder.py b/bw_timex/timeline_builder.py index a539996..6b8e129 100644 --- a/bw_timex/timeline_builder.py +++ b/bw_timex/timeline_builder.py @@ -74,7 +74,8 @@ def __init__( self.cutoff = cutoff self.max_calc = max_calc - # Finding indices of activities from background databases that are known to be static, i.e. have no temporal distributions connecting to them. These will be be skipped in the graph traversal. + # Finding indices of activities from background databases that are known to be static, i.e. have no temporal distributions connecting to them. + # These will be be skipped in the graph traversal. static_activity_db_indices = [ node_id for node_id in self.node_id_collection_dict[ diff --git a/bw_timex/timex_lca.py b/bw_timex/timex_lca.py index b76092a..ade8399 100644 --- a/bw_timex/timex_lca.py +++ b/bw_timex/timex_lca.py @@ -38,32 +38,38 @@ class TimexLCA: """ Class to perform time-explicit LCA calculations. - A TimexLCA retrieves the LCI of processes occuring at explicit points in time and relinks their technosphere - exchanges to match the technology landscape at that point in time, while keeping track of the timing of the - resulting emissions. As such, it combines prospective and dynamic LCA approaches. - - TimexLCA first calculates a static LCA, which informs a priority-first graph traversal. From the graph traversal, - temporal relationships between exchanges and processes are derived. Based on the timing of the processes, bw_timex - matches the processes at the intersection between foreground and background to the best available background - databases. This temporal relinking is achieved by using datapackages to add new time-specific processes. The new - processes and their exchanges to other technosphere processes or biosphere flows extent the technopshere and + A TimexLCA retrieves the LCI of processes occuring at explicit points in time and relinks their + technosphere exchanges to match the technology landscape at that point in time, while keeping + track of the timing of the resulting emissions. As such, it combines prospective and dynamic LCA + approaches. + + TimexLCA first calculates a static LCA, which informs a priority-first graph traversal. From the + graph traversal, temporal relationships between exchanges and processes are derived. Based on + the timing of the processes, bw_timex matches the processes at the intersection between + foreground and background to the best available background databases. This temporal relinking is + achieved by using datapackages to add new time-specific processes. The new processes and their + exchanges to other technosphere processes or biosphere flows extent the technopshere and biosphere matrices. - Temporal information of both processes and biosphere flows are retained, allowing for dynamic LCIA. + Temporal information of both processes and biosphere flows are retained, allowing for dynamic + LCIA. - Currently absolute Temporal Distributions for biosphere exchanges are dealt with as a look up function: - If an activity happens at timestamp X then and the biosphere exchange has an absolute temporal - distribution (ATD), it looks up the amount from from the ATD correspnding to timestamp X. - E.g.: X = 2024, TD=(data=[2020,2021,2022,2023,2024,.....,2120 ], amount=[3,4,4,5,6,......,3]), - it will look up the value 6 corresponding 2024. If timestamp X does not exist it find the nearest - timestamp available (if two timestamps are equally close, it will take the first in order of - apearance (see numpy.argmin() for this behabiour). + Currently absolute Temporal Distributions for biosphere exchanges are dealt with as a look up + function: If an activity happens at timestamp X then and the biosphere exchange has an absolute + temporal distribution (ATD), it looks up the amount from from the ATD correspnding to timestamp + X. E.g.: X=2024, TD=(data=[2020,2021,2022,2023,2024,.....,2120 ], amount=[3,4,4,5,6,......,3]), + it will look up the value 6 corresponding 2024. If timestamp X does not exist it find the + nearest timestamp available (if two timestamps are equally close, it will take the first in + order of apearance (see numpy.argmin() for this behabiour). TimexLCA calculates: - 1) a static LCA score (`TimexLCA.base_lca.score`, same as `bw2calc.lca.score`), - 2) a static time-explicit LCA score (`TimexLCA.static_score`), which links LCIs to the respective background databases but without additional temporal dynamics of the biosphere flows, - 3) a dynamic time-explicit LCA score (`TimexLCA.dynamic_score`), with dynamic inventory and dynamic charaterization factors. These are provided for radiative forcing and GWP but can also be user-defined. + 1) a static "base" LCA score (`TimexLCA.base_score`, same as `bw2calc.lca.score`), + 2) a static time-explicit LCA score (`TimexLCA.static_score`), which links LCIs to the + respective background databases, but without temporal dynamics of the biosphere flows, + 3) a dynamic time-explicit LCA score (`TimexLCA.dynamic_score`), with dynamic inventory and + dynamic charaterization. These are provided for radiative forcing and GWP but can also be + user-defined. Example ------- @@ -75,11 +81,11 @@ class TimexLCA: 'my_foreground_database':'dynamic' } >>> bw_timex = TimexLCA(demand, method, database_date_dict) - >>> bw_timex.build_timeline() # you can pass many optional arguments here, also for the graph traversal + >>> bw_timex.build_timeline() # has many optional arguments >>> bw_timex.lci() >>> bw_timex.static_lcia() >>> print(bw_timex.static_score) - >>> bw_timex.dynamic_lcia(metric="radiative_forcing") # different metrics can be used, e.g. "GWP", "radiative_forcing" + >>> bw_timex.dynamic_lcia(metric="radiative_forcing") # also available: "GWP" >>> print(bw_timex.dynamic_score) """ """""" @@ -91,7 +97,9 @@ def __init__( database_date_dict: dict = None, ) -> None: """ - Instantiating a `TimexLCA` object calculates a static LCA, initializes time mapping dicts for activities and biosphere flows, and stores useful subsets of ids in the node_id_collection_dict. + Instantiating a `TimexLCA` object calculates a static LCA, initializes time mapping dicts + for activities and biosphere flows, and stores useful subsets of ids in the + node_id_collection_dict. Parameters ---------- @@ -99,7 +107,8 @@ def __init__( The demand for which the LCA will be calculated. The keys can be Brightway `Node` instances, `(database, code)` tuples, or integer ids. method : tuple - Tuple defining the LCIA method, such as `('foo', 'bar')` or default methods, such as `("EF v3.1", "climate change", "global warming potential (GWP100)")` + Tuple defining the LCIA method, such as `('foo', 'bar')` or default methods, such as + `("EF v3.1", "climate change", "global warming potential (GWP100)")` database_date_dict : dict, optional Dictionary mapping database names to dates. """ @@ -110,19 +119,24 @@ def __init__( if not self.database_date_dict: warnings.warn( - "No database_date_dict provided. Treating the databases containing the functional unit as dynamic. No remapping to time explicit databases will be done." + "No database_date_dict provided. Treating the databases containing the functional \ + unit as dynamic. No remapping to time explicit databases will be done." ) self.database_date_dict = {key[0]: "dynamic" for key in demand.keys()} - # Create static_only dict that excludes dynamic processes that will be exploded later. This way we only have the "background databases" that we can later link to from the dates of the timeline. + # Create static_only dict that excludes dynamic processes that will be exploded later. + # This way we only have the "background databases" that we can later link to from the dates + # of the timeline. self.database_date_dict_static_only = { k: v for k, v in self.database_date_dict.items() if isinstance(v, datetime) } - # Create some collections of nodes that will be useful down the line, e.g. all nodes from the background databases that link to foregroud nodes. + # Create some collections of nodes that will be useful down the line, e.g. all nodes from + # the background databases that link to foregroud nodes. self.create_node_id_collection_dict() - # Calculate static LCA results using a custom prepare_lca_inputs function that includes all background databases in the LCA. We need all the IDs for the time mapping dict. + # Calculate static LCA results using a custom prepare_lca_inputs function that includes all + # background databases in the LCA. We need all the IDs for the time mapping dict. fu, data_objs, remapping = self.prepare_base_lca_inputs( demand=self.demand, method=self.method ) @@ -130,12 +144,13 @@ def __init__( self.base_lca.lci() self.base_lca.lcia() - # Create a time mapping dict that maps each activity to a activity_time_mapping_id in the format (('database', 'code'), datetime_as_integer): time_mapping_id) + # Create a time mapping dict that maps each activity to a activity_time_mapping_id in the + # format (('database', 'code'), datetime_as_integer): time_mapping_id) self.activity_time_mapping_dict = TimeMappingDict( start_id=bd.backends.ActivityDataset.select(fn.MAX(AD.id)).scalar() + 1 - ) # making sure to use unique ids for the time mapped processes by counting up from the highest current activity id + ) # making sure we get unique ids by counting up from the highest current activity id - # Create a similar dict for the biosphere flows. This is populated by the dynamic_biosphere_builder + # Create a similar dict for the biosphere flows. Populated by the dynamic_biosphere_builder self.biosphere_time_mapping_dict = TimeMappingDict(start_id=0) ######################################## @@ -153,32 +168,35 @@ def build_timeline( **kwargs, ) -> pd.DataFrame: """ - Creates a `TimelineBuilder` instance that does the graph traversal (similar to bw_temporalis) and extracts all - edges with their temporal information. Creates the `TimexLCA.timeline` of exchanges. + Creates a `TimelineBuilder` instance that does the graph traversal (similar to + bw_temporalis) and extracts all edges with their temporal information. Creates the + `TimexLCA.timeline` of exchanges. Parameters ---------- temporal_grouping : str, optional - Time resolution for grouping exchanges over time in the timeline. Default is 'year', other options are - 'month', 'day', 'hour'. + Time resolution for grouping exchanges over time in the timeline. Default is 'year', + other options are 'month', 'day', 'hour'. interpolation_type : str, optional - Type of interpolation when sourcing the new producers in the time-explicit background databases. Default is - 'linear', which means linear interpolation between the closest 2 databases, other options are 'closest', - which selects only the closest database. + Type of interpolation when sourcing the new producers in the time-explicit background + databases. Default is 'linear', which means linear interpolation between the closest 2 + databases, other options are 'closest', which selects only the closest database. edge_filter_function : Callable, optional - Function to skip edges in the graph traversal. Default is to skip all edges within background databases. + Function to skip edges in the graph traversal. Default is to skip all edges within + background databases. cutoff: float, optional The cutoff value for the graph traversal. Default is 1e-9. max_calc: float, optional - The maximum number of calculations to be performed by the graph traversal. Default is 1e4. + The maximum number of calculations to be performed by the graph traversal. Default is + 1e4. *args : iterable - Positional arguments for the graph traversal. for `bw_temporalis.TemporalisLCA` passed to the - `EdgeExtractor` class, which inherits from `TemporalisLCA`. - See `bw_temporalis` documentation for more information. + Positional arguments for the graph traversal. for `bw_temporalis.TemporalisLCA` passed + to the `EdgeExtractor` class, which inherits from `TemporalisLCA`. See `bw_temporalis` + documentation for more information. **kwargs : dict - Additional keyword arguments for `bw_temporalis.TemporalisLCA` passed to the EdgeExtractor class, which - inherits from TemporalisLCA. - See bw_temporalis documentation for more information. + Additional keyword arguments for `bw_temporalis.TemporalisLCA` passed to the + EdgeExtractor class, which inherits from TemporalisLCA. See bw_temporalis documentation + for more information. Returns ------- @@ -210,9 +228,9 @@ def build_timeline( # Doing this here because we need the temporal grouping for consistent times resolution. self.add_static_activities_to_time_mapping_dict() - # Create timeline builder that does the graph traversal (similar to bw_temporalis) and extracts - # all edges with their temporal information. Can later be used to build a timeline with the - # TimelineBuilder.build_timeline() method. + # Create timeline builder that does the graph traversal (similar to bw_temporalis) and + # extracts all edges with their temporal information. Can later be used to build a timeline + # with the TimelineBuilder.build_timeline() method. self.timeline_builder = TimelineBuilder( self.base_lca, self.edge_filter_function, @@ -248,12 +266,13 @@ def lci( """ Calculates the time-explicit LCI. - Generates the biosphere and technosphere modifications via the `MatrixModifier` class by calling `TimexLCA. - build_datapackage() if `expand_technosphere' is True. Otherwise it generates a dynamic inventory directly from - from the timeline. Optionally, the dynamic biosphere matrix and dynamic inventory is calculated via - `TimexLCA.calculate_dynamic_inventory()`. Set `build_dynamic_biosphere` to False if you only want to get a new - overall score and don't care about the timing - of the emissions. This saves time and memory. + Generates the biosphere and technosphere modifications via the `MatrixModifier` class by + calling `TimexLCA. build_datapackage() if `expand_technosphere' is True. Otherwise it + generates a dynamic inventory directly from from the timeline. Optionally, the dynamic + biosphere matrix and dynamic inventory is calculated via + `TimexLCA.calculate_dynamic_inventory()`. Set `build_dynamic_biosphere` to False if you only + want to get a new overall score and don't care about the timing of the emissions. This saves + time and memory. Parameters ---------- @@ -261,13 +280,15 @@ def lci( if True, build the dynamic biosphere matrix and calculate the dynamic LCI. Default is True. expand_technosphere: bool - if True, creates an expanded time-explicit technosphere and calculates the LCI from it. If False, creates no - new technosphere, but calculates the dynamic inventory directly from the timeline. Building from the timeline - currently only works if `build_dynamic_biosphere` is also True. + if True, creates an expanded time-explicit technosphere and calculates the LCI from it. + If False, creates no new technosphere, but calculates the dynamic inventory directly + from the timeline. Building from the timeline currently only works if + `build_dynamic_biosphere` is also True. Returns ------- - None, but calls LCI calculations from bw2calc and calculates the dynamic inventory, if `build_dynamic_biosphere` is True. + None, but calls LCI calculations from bw2calc and calculates the dynamic inventory, if + `build_dynamic_biosphere` is True. See also -------- @@ -315,15 +336,16 @@ def lci( if expand_technosphere: self.lca.lci(factorize=True) self.calculate_dynamic_inventory(from_timeline=False) - self.lca.redo_lci( - self.fu - ) # to get back the original LCI - necessary because we do some redo_lci's in the dynamic inventory calculation + # to get back the original LCI - necessary because we do some redo_lci's in the + # dynamic inventory calculation + self.lca.redo_lci(self.fu) else: self.calculate_dynamic_inventory(from_timeline=True) def static_lcia(self) -> None: """ - Calculates static LCIA using time-explicit LCIs with the standard static characterization factors of the selected LCIA method using `bw2calc.lcia()`. + Calculates static LCIA using time-explicit LCIs with the standard static characterization + factors of the selected LCIA method using `bw2calc.lcia()`. Parameters ---------- @@ -337,8 +359,8 @@ def static_lcia(self) -> None: raise AttributeError("LCI not yet calculated. Call TimexLCA.lci() first.") if not self.expanded_technosphere: raise ValueError( - "Currently the static lcia score can only be calculated if the expanded matrix has been built\ - Please call TimexLCA.lci(expand_technosphere=True) first." + "Currently the static lcia score can only be calculated if the expanded matrix has \ + been built. Please call TimexLCA.lci(expand_technosphere=True) first." ) self.lca.lcia() @@ -352,36 +374,46 @@ def dynamic_lcia( characterization_function_co2: dict = None, ) -> pd.DataFrame: """ - Calculates dynamic LCIA with the `DynamicCharacterization` class using the dynamic inventory and dynamic - characterization functions. Dynamic characterization is handled by the separate package - `dynamic_characterization` (https://dynamic-characterization.readthedocs.io/en/latest/). + Calculates dynamic LCIA with the `DynamicCharacterization` class using the dynamic inventory + and dynamic characterization functions. Dynamic characterization is handled by the separate + package `dynamic_characterization` (https://dynamic-characterization.readthedocs.io). Dynamic characterization functions in the form of a dictionary {biosphere_flow_database_id: characterization_function} can be given by the user. - If none are given, a set of default dynamic characterization functions based on IPCC AR6 are provided from - `dynamic_characterization` package. These are mapped to the biosphere3 flows of the chosen static climate - change impact category. If there is no characterization function for a biosphere flow, it will be ignored. + If none are given, a set of default dynamic characterization functions based on IPCC AR6 are + provided from `dynamic_characterization` package. These are mapped to the biosphere3 flows + of the chosen static climate change impact category. If there is no characterization + function for a biosphere flow, it will be ignored. Two dynamic climate change metrics are provided: "GWP" and "radiative_forcing". - The time horizon for the impact assessment can be set with the `time_horizon` parameter, defaulting to 100 years. - The `fixed_time_horizon` parameter determines whether the emission time horizon for all emissions is calculated from the - functional unit (`fixed_time_horizon=True`) or from the time of the emission (`fixed_time_horizon=False`). + The time horizon for the impact assessment can be set with the `time_horizon` parameter, + defaulting to 100 years. The `fixed_time_horizon` parameter determines whether the emission + time horizon for all emissions is calculated from the functional unit + (`fixed_time_horizon=True`) or from the time of the emission (`fixed_time_horizon=False`). The former is the implementation of the Levasseur approach (see https://doi.org/10.1021/es9030003), while the latter is how conventional LCA is done. Parameters ---------- metric : str, optional - the metric for which the dynamic LCIA should be calculated. Default is "radiative_forcing". Available: "GWP" and "radiative_forcing" + the metric for which the dynamic LCIA should be calculated. Default is + "radiative_forcing". Available: "GWP" and "radiative_forcing" time_horizon: int, optional the time horizon for the impact assessment. Unit is years. Default is 100. fixed_time_horizon: bool, optional - Whether the emission time horizon for all emissions is calculated from the functional unit (fixed_time_horizon=True) or from the time of the emission (fixed_time_horizon=False). Default is False. + Whether the emission time horizon for all emissions is calculated from the functional + unit (fixed_time_horizon=True) or from the time of the emission + (fixed_time_horizon=False). Default is False. time_horizon_start: pd.Timestamp, optional - The starting timestamp of the time horizon for the dynamic characterization. Only needed for fixed time horizons. Default is datetime.now(). + The starting timestamp of the time horizon for the dynamic characterization. Only needed + for fixed time horizons. Default is datetime.now(). characterization_function_dict: dict, optional - Dict of the form {biosphere_flow_database_id: characterization_function}. Default is None, which triggers the use of the provided dynamic characterization functions based on IPCC AR6 Chapter 7. + Dict of the form {biosphere_flow_database_id: characterization_function}. Default is + None, which triggers the use of the provided dynamic characterization functions based on + IPCC AR6 Chapter 7. characterization_function_co2: Callable, optional - Characterization function for CO2 emissions. Necessary if GWP metrix is chosen. Default is None, which triggers the use of the provided dynamic characterization function of co2 based on IPCC AR6 Chapter 7. + Characterization function for CO2 emissions. Necessary if GWP metrix is chosen. Default + is None, which triggers the use of the provided dynamic characterization function of co2 + based on IPCC AR6 Chapter 7. Returns @@ -411,7 +443,8 @@ def dynamic_lcia( last_emission = self.dynamic_inventory_df.date.max() if latest_considered_impact < last_emission: warnings.warn( - "An emission occurs outside of the specified time horizon and will not be characterized. Please make sure this is intended." + "An emission occurs outside of the specified time horizon and will not be \ + characterized. Please make sure this is intended." ) inventory_in_time_horizon = self.dynamic_inventory_df[ self.dynamic_inventory_df.date <= latest_considered_impact @@ -471,7 +504,8 @@ def dynamic_score(self) -> float: def build_datapackage(self) -> list: """ - Creates the datapackages that contain the modifications to the technopshere and biosphere matrix using the `MatrixModifier` class. + Creates the datapackages that contain the modifications to the technopshere and biosphere + matrix using the `MatrixModifier` class. Parameters ---------- @@ -480,7 +514,8 @@ def build_datapackage(self) -> list: Returns ------- list - List of datapackages that contain the modifications to the technopshere and biosphere matrix + List of datapackages that contain the modifications to the technopshere and biosphere + matrix See also -------- @@ -503,9 +538,10 @@ def calculate_dynamic_inventory( from_timeline: bool = False, ) -> None: """ - Calculates the dynamic inventory, by first creating a dynamic biosphere matrix using the `DynamicBiosphereBuilder` - class and then multiplying it with the dynamic supply array. The dynamic inventory matrix is stored in the attribute `dynamic_inventory`. - It is also converted to a DataFrame and stored in the attribute `dynamic_inventory_df`. + Calculates the dynamic inventory, by first creating a dynamic biosphere matrix using the + `DynamicBiosphereBuilder` class and then multiplying it with the dynamic supply array. The + dynamic inventory matrix is stored in the attribute `dynamic_inventory`. It is also + converted to a DataFrame and stored in the attribute `dynamic_inventory_df`. Parameters ---------- @@ -513,7 +549,8 @@ class and then multiplying it with the dynamic supply array. The dynamic invento Returns ------- - None, but calculates the dynamic inventory and stores it in the attribute `dynamic_inventory` as a matrix and in `dynamic_inventory_df` as a DataFrame. + None, but calculates the dynamic inventory and stores it in the attribute + `dynamic_inventory` as a matrix and in `dynamic_inventory_df` as a DataFrame. See also -------- @@ -551,9 +588,11 @@ class and then multiplying it with the dynamic supply array. The dynamic invento # Build the dynamic inventory count = len(self.dynamic_biosphere_builder.dynamic_supply_array) + # diagnolization of supply array keeps the dimension of the process, which we want to pass + # as additional information to the dynamic inventory dict diagonal_supply_array = sparse.spdiags( [self.dynamic_biosphere_builder.dynamic_supply_array], [0], count, count - ) # diagnolization of supply array keeps the dimension of the process, which we want to pass as additional information to the dynamic inventory dict + ) self.dynamic_inventory = self.dynamic_biomatrix @ diagonal_supply_array self.biosphere_time_mapping_dict_reversed = { @@ -568,10 +607,11 @@ class and then multiplying it with the dynamic supply array. The dynamic invento ) def create_dynamic_inventory_dataframe(self, from_timeline=False) -> pd.DataFrame: - """Brings the dynamic inventory from its matrix form in `dynamic_inventory` into the the format - of a pandas.DataFrame, with the right structure to later apply dynamic characterization functions. + """Brings the dynamic inventory from its matrix form in `dynamic_inventory` into the the + format of a pandas.DataFrame, with the right structure to later apply dynamic + characterization functions. - Format needs to be: + Format is: +------------+--------+------+----------+ | date | amount | flow | activity | @@ -613,9 +653,9 @@ def create_dynamic_inventory_dataframe(self, from_timeline=False) -> pd.DataFram else: emitting_process_id = self.lca.activity_dict.reversed[col] - bioflow_id, date = self.biosphere_time_mapping_dict_reversed[ - row - ] # indices are already the same as in the matrix, as we create an entirely new biosphere instead of adding new entries (like we do with the technosphere matrix) + # indices are already the same as in the matrix, as we create an entirely new + # biosphere instead of adding new entries (like we do with the technosphere matrix) + bioflow_id, date = self.biosphere_time_mapping_dict_reversed[row] dataframe_rows.append( ( date, @@ -652,8 +692,10 @@ def prepare_base_lca_inputs( Adapted bw2data.compat.py - The difference to the original method is that we load all available databases into the matrices instead of just the ones depending on the demand. - We need this for the creation of the time mapping dict that creates a mapping between the producer id and the reference timing of the databases in the `database_date_dict`. + The difference to the original method is that we load all available databases into the + matrices instead of just the ones depending on the demand. We need this for the creation of + the time mapping dict that creates a mapping between the producer id and the reference + timing of the databases in the `database_date_dict`. Parameters ---------- @@ -881,7 +923,8 @@ def prepare_bw_timex_inputs( def create_node_id_collection_dict(self) -> None: """ - Creates a dict of collections of nodes that will be useful down the line, e.g. to determine static nodes for the graph traversal or create the dynamic biosphere matrix. + Creates a dict of collections of nodes that will be useful down the line, e.g. to determine + static nodes for the graph traversal or create the dynamic biosphere matrix. Available collections are: - ``demand_database_names``: set of database names of the demand processes @@ -893,14 +936,19 @@ def create_node_id_collection_dict(self) -> None: - ``first_level_background_node_ids_all``: like first_level_background_node_ids_static, but includes first level background processes from other time explicit databases. - ``first_level_background_node_id_dbs``: dictionary with the first_level_background_node_ids_static as keys returning their database - It also initiates an instance of SetList which contains all mappings of equivalent activieties across time-specific databases. + It also initiates an instance of SetList which contains all mappings of equivalent + activities across time-specific databases: + - ``self.interdatabase_activity_mapping``: instance of SetList + + Parameters ---------- None Returns ------- - None, but adds the `node_id_collection_dict containing` the above-mentioned collections, as well as interdatabase_activity_mapping + None, but adds the `node_id_collection_dict containing` the above-mentioned collections, + as well as interdatabase_activity_mapping """ self.node_id_collection_dict = {} self.interdatabase_activity_mapping = SetList() @@ -967,7 +1015,10 @@ def create_node_id_collection_dict(self) -> None: act_set.add((other_node.id, background_db)) except KeyError as e: warnings.warn( - f"Failed to find process in database {background_db} for name='{exc.input['name']}', reference product='{exc.input['reference product']}', location='{exc.input['location']}': {e}" + f"Failed to find process in database {background_db} for \ + name='{exc.input['name']}', \ + reference product='{exc.input['reference product']}', \ + location='{exc.input['location']}': {e}" ) self.interdatabase_activity_mapping.add(act_set) @@ -1017,11 +1068,12 @@ def collect_temporalized_processes_from_timeline(self) -> None: def add_static_activities_to_time_mapping_dict(self) -> None: """ - Adds all activities from the static LCA to `activity_time_mapping_dict`, an instance of `TimeMappingDict`. - This gives a unique mapping in the form of (('database', 'code'), datetime_as_integer): time_mapping_id) - that is later used to uniquely identify time-resolved processes. This is the pre-population of the time - mapping dict with the static activities. Further time-explicit activities (from other temporalized - background databases) are added lateron by in the TimelineBuilder. + Adds all activities from the static LCA to `activity_time_mapping_dict`, an instance of + `TimeMappingDict`. This gives a unique mapping in the form of + (('database', 'code'), datetime_as_integer): time_mapping_id) that is later used to uniquely + identify time-resolved processes. This is the pre-population of the time mapping dict with + the static activities. Further time-explicit activities (from other temporalized background + databases) are added lateron by in the TimelineBuilder. Parameters ---------- @@ -1048,9 +1100,11 @@ def add_static_activities_to_time_mapping_dict(self) -> None: def create_demand_timing_dict(self) -> dict: """ - Generate a dictionary that maps producer (key) to timing (value) for the demands in the product system. - It searches the timeline for those rows that contain the functional units (demand-processes as producer and -1 as consumer) and returns the time of the demand as an integer. - Time of demand can have flexible resolution (year=YYYY, month=YYYYMM, day=YYYYMMDD, hour=YYYYMMDDHH) defined in `temporal_grouping`. + Generate a dictionary that maps producer (key) to timing (value) for the demands in the + product system. It searches the timeline for those rows that contain the functional units + (demand-processes as producer and -1 as consumer) and returns the time of the demand as an + integer. Time of demand can have flexible resolution (year=YYYY, month=YYYYMM, day=YYYYMMDD, + hour=YYYYMMDDHH) defined in `temporal_grouping`. Parameters ---------- @@ -1084,7 +1138,8 @@ def create_labelled_technosphere_dataframe(self) -> pd.DataFrame: Returns ------- - pd.DataFrame, technosphere matrix as a pandas.DataFrame with comprehensible labels instead of ids. + pd.DataFrame, technosphere matrix as a pandas.DataFrame with comprehensible labels instead + of ids. """ df = pd.DataFrame(self.technosphere_matrix.toarray()) @@ -1110,7 +1165,8 @@ def create_labelled_biosphere_dataframe(self) -> pd.DataFrame: Returns ------- - pd.DataFrame, biosphere matrix as a pandas.DataFrame with comprehensible labels instead of ids. + pd.DataFrame, biosphere matrix as a pandas.DataFrame with comprehensible labels instead of + ids. """ df = pd.DataFrame(self.biosphere_matrix.toarray()) @@ -1121,7 +1177,7 @@ def create_labelled_biosphere_dataframe(self) -> pd.DataFrame: ) df.rename( index=self.remapping_dicts["biosphere"], # from activity id to bioflow name - columns=self.activity_time_mapping_dict.reversed(), # from activity id to ((database, code), time) + columns=self.activity_time_mapping_dict.reversed(), # act id to ((database, code), time) inplace=True, ) @@ -1129,7 +1185,8 @@ def create_labelled_biosphere_dataframe(self) -> pd.DataFrame: def create_labelled_dynamic_biosphere_dataframe(self) -> pd.DataFrame: """ - Returns the dynamic biosphere matrix as a dataframe with comprehensible labels instead of ids. + Returns the dynamic biosphere matrix as a dataframe with comprehensible labels instead of + ids. Parameters ---------- @@ -1137,7 +1194,8 @@ def create_labelled_dynamic_biosphere_dataframe(self) -> pd.DataFrame: Returns ------- - pd.DataFrame, dynamic biosphere matrix as a pandas.DataFrame with comprehensible labels instead of ids. + pd.DataFrame, dynamic biosphere matrix as a pandas.DataFrame with comprehensible labels + instead of ids. """ df = pd.DataFrame(self.dynamic_biomatrix.toarray()) df.rename( # from matrix id to activity id @@ -1156,7 +1214,8 @@ def create_labelled_dynamic_biosphere_dataframe(self) -> pd.DataFrame: def create_labelled_dynamic_inventory_dataframe(self) -> pd.DataFrame: """ - Returns the dynamic_inventory_df with comprehensible labels for flows and activities instead of ids. + Returns the dynamic_inventory_df with comprehensible labels for flows and activities instead + of ids. Parameters ---------- @@ -1164,12 +1223,14 @@ def create_labelled_dynamic_inventory_dataframe(self) -> pd.DataFrame: Returns ------- - pd.DataFrame, dynamic inventory matrix as a pandas.DataFrame with comprehensible labels instead of ids. + pd.DataFrame, dynamic inventory matrix as a pandas.DataFrame with comprehensible labels + instead of ids. """ if not hasattr(self, "dynamic_inventory_df"): warnings.warn( - "Dynamic inventory not yet calculated. Call TimexLCA.lci(build_dynamic_biosphere=True) first." + "Dynamic inventory not yet calculated. Call \ + TimexLCA.lci(build_dynamic_biosphere=True) first." ) df = self.dynamic_inventory_df.copy() @@ -1189,7 +1250,8 @@ def create_labelled_dynamic_inventory_dataframe(self) -> pd.DataFrame: def plot_dynamic_inventory(self, bio_flows, cumulative=False) -> None: """ - Simple plot of dynamic inventory of a biosphere flow over time, with optional cumulative plotting. + Simple plot of dynamic inventory of a biosphere flow over time, with optional cumulative + plotting. Parameters ---------- @@ -1320,5 +1382,7 @@ def remap_inventory_dicts(self) -> None: """ warnings.warn( - "bw25's original mapping function doesn't work with our new time-mapped matrix entries. The Timex mapping can be found in acvitity_time_mapping_dict and biosphere_time_mapping_dict." + "bw25's original mapping function doesn't work with our new time-mapped matrix entries.\ + The Timex mapping can be found in acvitity_time_mapping_dict and \ + biosphere_time_mapping_dict." ) diff --git a/docs/_static/custom.css b/docs/_static/custom.css index 29a67cb..c8d7429 100644 --- a/docs/_static/custom.css +++ b/docs/_static/custom.css @@ -72,4 +72,4 @@ div.admonition.admonition-example { div.admonition.admonition-example > .admonition-title::after { content: "\f518"; color: var(--pst-color-text-base); -} \ No newline at end of file +} diff --git a/docs/_templates/autoapi_templates/index.rst b/docs/_templates/autoapi_templates/index.rst index 6840e5b..2431d7f 100644 --- a/docs/_templates/autoapi_templates/index.rst +++ b/docs/_templates/autoapi_templates/index.rst @@ -25,4 +25,4 @@ The functionalities of bw_timex are distributed over several submodules. Here's bw_timex/index -.. [#f1] Created with `sphinx-autoapi `_ \ No newline at end of file +.. [#f1] Created with `sphinx-autoapi `_ diff --git a/docs/content/data/dynamic_characterized_inventory_gwp.svg b/docs/content/data/dynamic_characterized_inventory_gwp.svg index 65f517c..0ff6296 100644 --- a/docs/content/data/dynamic_characterized_inventory_gwp.svg +++ b/docs/content/data/dynamic_characterized_inventory_gwp.svg @@ -21,33 +21,33 @@ - - - - @@ -58,49 +58,49 @@ L 0 3.5 - - @@ -113,8 +113,8 @@ z - @@ -126,36 +126,36 @@ L 279.818705 51.84 - @@ -168,8 +168,8 @@ z - @@ -181,23 +181,23 @@ L 398.128318 51.84 - @@ -210,8 +210,8 @@ z - @@ -223,29 +223,29 @@ L 516.762068 51.84 - @@ -258,8 +258,8 @@ z - @@ -271,34 +271,34 @@ L 635.071682 51.84 - @@ -311,8 +311,8 @@ z - @@ -324,14 +324,14 @@ L 753.381295 51.84 - @@ -344,8 +344,8 @@ z - @@ -357,43 +357,43 @@ L 871.690909 51.84 - @@ -408,93 +408,93 @@ z - - - - @@ -508,14 +508,14 @@ z - - @@ -531,8 +531,8 @@ L -3.5 0 - @@ -549,8 +549,8 @@ L 907.2 339.239307 - @@ -567,8 +567,8 @@ L 907.2 293.998613 - @@ -585,8 +585,8 @@ L 907.2 248.75792 - @@ -603,8 +603,8 @@ L 907.2 203.517227 - @@ -616,18 +616,18 @@ L 907.2 158.276533 - @@ -638,8 +638,8 @@ z - @@ -657,8 +657,8 @@ L 907.2 113.03584 - @@ -678,99 +678,99 @@ L 907.2 67.795147 - - - - @@ -785,15 +785,15 @@ z - @@ -816,50 +816,50 @@ z - - - - - - @@ -871,20 +871,20 @@ z - @@ -893,15 +893,15 @@ z - @@ -913,36 +913,36 @@ z - diff --git a/docs/content/data/dynamic_characterized_inventory_radiative_forcing.svg b/docs/content/data/dynamic_characterized_inventory_radiative_forcing.svg index 2be7b9b..4e21606 100644 --- a/docs/content/data/dynamic_characterized_inventory_radiative_forcing.svg +++ b/docs/content/data/dynamic_characterized_inventory_radiative_forcing.svg @@ -21,33 +21,33 @@ - - - - @@ -58,49 +58,49 @@ L 0 3.5 - - @@ -113,8 +113,8 @@ z - @@ -126,23 +126,23 @@ L 277.59107 51.84 - @@ -155,8 +155,8 @@ z - @@ -168,34 +168,34 @@ L 414.168937 51.84 - @@ -208,8 +208,8 @@ z - @@ -221,43 +221,43 @@ L 550.746804 51.84 - @@ -270,8 +270,8 @@ z - @@ -283,18 +283,18 @@ L 687.324671 51.84 - @@ -307,8 +307,8 @@ z - @@ -330,93 +330,93 @@ L 823.883841 51.84 - - - - @@ -430,14 +430,14 @@ z - - @@ -448,11 +448,11 @@ L -3.5 0 - @@ -464,8 +464,8 @@ z - @@ -477,29 +477,29 @@ L 907.2 316.084399 - @@ -511,8 +511,8 @@ z - @@ -531,8 +531,8 @@ L 907.2 247.688798 - @@ -551,8 +551,8 @@ L 907.2 179.293197 - @@ -573,99 +573,99 @@ L 907.2 110.897596 - - - - @@ -681,11 +681,11 @@ z - @@ -699,15 +699,15 @@ z - @@ -2200,50 +2200,50 @@ z - - - - - - @@ -2255,20 +2255,20 @@ z - @@ -2277,15 +2277,15 @@ z - @@ -2297,36 +2297,36 @@ z - diff --git a/docs/content/data/dynamic_prospective_timeexplicit_dark.svg b/docs/content/data/dynamic_prospective_timeexplicit_dark.svg index d85cc8e..288e874 100644 --- a/docs/content/data/dynamic_prospective_timeexplicit_dark.svg +++ b/docs/content/data/dynamic_prospective_timeexplicit_dark.svg @@ -1 +1 @@ -time-explicitdynamicprospectiveUseUseUseEoLConstr.environmental impacts2025203020352040204520252030203520402045databases:Constr.ConstrUseEoLenvironmental impacts2025203020352040204520252030203520402045databases:UseEoLstaticprospectiveevolving production systemdatabases:UseUseUseConstr.environmental impacts2025203020352040204520252030203520402045EoL+ \ No newline at end of file +time-explicitdynamicprospectiveUseUseUseEoLConstr.environmental impacts2025203020352040204520252030203520402045databases:Constr.ConstrUseEoLenvironmental impacts2025203020352040204520252030203520402045databases:UseEoLstaticprospectiveevolving production systemdatabases:UseUseUseConstr.environmental impacts2025203020352040204520252030203520402045EoL+ diff --git a/docs/content/data/dynamic_prospective_timeexplicit_light.svg b/docs/content/data/dynamic_prospective_timeexplicit_light.svg index e45a20b..ca66371 100644 --- a/docs/content/data/dynamic_prospective_timeexplicit_light.svg +++ b/docs/content/data/dynamic_prospective_timeexplicit_light.svg @@ -1 +1 @@ -time-explicitdynamicprospectiveUseUseUseEoLConstr.environmental impacts2025203020352040204520252030203520402045databases:Constr.ConstrUseEoLenvironmental impacts2025203020352040204520252030203520402045databases:UseEoLstaticprospectiveevolving production systemdatabases:UseUseUseConstr.environmental impacts2025203020352040204520252030203520402045EoL+ \ No newline at end of file +time-explicitdynamicprospectiveUseUseUseEoLConstr.environmental impacts2025203020352040204520252030203520402045databases:Constr.ConstrUseEoLenvironmental impacts2025203020352040204520252030203520402045databases:UseEoLstaticprospectiveevolving production systemdatabases:UseUseUseConstr.environmental impacts2025203020352040204520252030203520402045EoL+ diff --git a/docs/content/data/matrix_stuff_dark.svg b/docs/content/data/matrix_stuff_dark.svg index dcf75cb..eca4d6f 100644 --- a/docs/content/data/matrix_stuff_dark.svg +++ b/docs/content/data/matrix_stuff_dark.svg @@ -1 +1 @@ -process Aprocess Bproduct Aproduct B10-31511CO2temporalizetechnospheretemporalizebiosphereforbothtechnosphere&biosphereexchanges*sourcenewvaluesfromtime-explicitdatabases*CO2process B @ 2020process B @ 2030product A @ 2024product B @ 2020product B @ 2030process A @ 20240010011000-0.8-0.60-0.20-0.8-0.2-0.40-1.500-0.90001010-0.600010product B @ 2022product B @ 2024product B @ 2028temp. market B @ 2022temp. market B @ 2024temp. market B @ 20285711000CO2 @2022process B @ 2020process B @ 2030product A @ 2024product B @ 2020product B @ 2030process A @ 20240010011000-0.8-0.60-0.20-0.8-0.2-0.40-1.500-0.90001010-0.600010product B @ 2022product B @ 2024product B @ 2028temp. market B @ 2022temp. market B @ 2024temp. market B @ 202800010.20030009.40200000000007.8CO2 @ 2024CO2 @ 2025CO2 @ 2028 \ No newline at end of file +process Aprocess Bproduct Aproduct B10-31511CO2temporalizetechnospheretemporalizebiosphereforbothtechnosphere&biosphereexchanges*sourcenewvaluesfromtime-explicitdatabases*CO2process B @ 2020process B @ 2030product A @ 2024product B @ 2020product B @ 2030process A @ 20240010011000-0.8-0.60-0.20-0.8-0.2-0.40-1.500-0.90001010-0.600010product B @ 2022product B @ 2024product B @ 2028temp. market B @ 2022temp. market B @ 2024temp. market B @ 20285711000CO2 @2022process B @ 2020process B @ 2030product A @ 2024product B @ 2020product B @ 2030process A @ 20240010011000-0.8-0.60-0.20-0.8-0.2-0.40-1.500-0.90001010-0.600010product B @ 2022product B @ 2024product B @ 2028temp. market B @ 2022temp. market B @ 2024temp. market B @ 202800010.20030009.40200000000007.8CO2 @ 2024CO2 @ 2025CO2 @ 2028 diff --git a/docs/content/data/matrix_stuff_light.svg b/docs/content/data/matrix_stuff_light.svg index 9f3e1c3..e5923e7 100644 --- a/docs/content/data/matrix_stuff_light.svg +++ b/docs/content/data/matrix_stuff_light.svg @@ -1 +1 @@ -process Aprocess Bproduct Aproduct B10-31511CO2temporalizetechnospheretemporalizebiosphereforbothtechnosphere&biosphereexchanges*sourcenewvaluesfromtime-explicitdatabases*CO2process B @ 2020process B @ 2030product A @ 2024product B @ 2020product B @ 2030process A @ 20240010011000-0.8-0.60-0.20-0.8-0.2-0.40-1.500-0.90001010-0.600010product B @ 2022product B @ 2024product B @ 2028temp. market B @ 2022temp. market B @ 2024temp. market B @ 20285711000CO2 @2022process B @ 2020process B @ 2030product A @ 2024product B @ 2020product B @ 2030process A @ 20240010011000-0.8-0.60-0.20-0.8-0.2-0.40-1.500-0.90001010-0.600010product B @ 2022product B @ 2024product B @ 2028temp. market B @ 2022temp. market B @ 2024temp. market B @ 202800010.20030009.40200000000007.8CO2@ 2024CO2@ 2025CO2@ 2028 \ No newline at end of file +process Aprocess Bproduct Aproduct B10-31511CO2temporalizetechnospheretemporalizebiosphereforbothtechnosphere&biosphereexchanges*sourcenewvaluesfromtime-explicitdatabases*CO2process B @ 2020process B @ 2030product A @ 2024product B @ 2020product B @ 2030process A @ 20240010011000-0.8-0.60-0.20-0.8-0.2-0.40-1.500-0.90001010-0.600010product B @ 2022product B @ 2024product B @ 2028temp. market B @ 2022temp. market B @ 2024temp. market B @ 20285711000CO2 @2022process B @ 2020process B @ 2030product A @ 2024product B @ 2020product B @ 2030process A @ 20240010011000-0.8-0.60-0.20-0.8-0.2-0.40-1.500-0.90001010-0.600010product B @ 2022product B @ 2024product B @ 2028temp. market B @ 2022temp. market B @ 2024temp. market B @ 202800010.20030009.40200000000007.8CO2@ 2024CO2@ 2025CO2@ 2028 diff --git a/docs/content/data/method_small_steps_dark.svg b/docs/content/data/method_small_steps_dark.svg index 726f06b..14a6202 100644 --- a/docs/content/data/method_small_steps_dark.svg +++ b/docs/content/data/method_small_steps_dark.svg @@ -1 +1 @@ -temporalinformationtemporalized system modelenvironmental impactsprocess timelinetime-explicitinventorystatic system modeltime-explicit databasesbuild_timeline()lci()dynamic_lcia()Step 1Step 2Step 3Step 4 \ No newline at end of file +temporalinformationtemporalized system modelenvironmental impactsprocess timelinetime-explicitinventorystatic system modeltime-explicit databasesbuild_timeline()lci()dynamic_lcia()Step 1Step 2Step 3Step 4 diff --git a/docs/content/data/method_small_steps_light.svg b/docs/content/data/method_small_steps_light.svg index cf507f4..7291b05 100644 --- a/docs/content/data/method_small_steps_light.svg +++ b/docs/content/data/method_small_steps_light.svg @@ -1 +1 @@ -temporalinformationtemporalized system modelenvironmental impactsprocess timelinetime-explicitinventorystatic system modeltime-explicit databasesbuild_timeline()lci()dynamic_lcia()Step 1Step 2Step 3Step 4 \ No newline at end of file +temporalinformationtemporalized system modelenvironmental impactsprocess timelinetime-explicitinventorystatic system modeltime-explicit databasesbuild_timeline()lci()dynamic_lcia()Step 1Step 2Step 3Step 4 diff --git a/docs/content/data/td_convoluted.svg b/docs/content/data/td_convoluted.svg index a849cc0..32940d4 100644 --- a/docs/content/data/td_convoluted.svg +++ b/docs/content/data/td_convoluted.svg @@ -21,27 +21,27 @@ - - - @@ -49,53 +49,53 @@ L 100.103081 15.12 - - @@ -106,8 +106,8 @@ z - @@ -115,57 +115,57 @@ L 163.279848 15.12 - - @@ -176,8 +176,8 @@ z - @@ -191,8 +191,8 @@ L 226.456616 15.12 - @@ -200,23 +200,23 @@ L 289.633384 15.12 - @@ -227,8 +227,8 @@ z - @@ -242,8 +242,8 @@ L 352.810152 15.12 - @@ -259,237 +259,237 @@ L 415.986919 15.12 - - - - - - - - - - - - @@ -512,8 +512,8 @@ z - @@ -521,11 +521,11 @@ L 445.68 259.930364 - @@ -538,8 +538,8 @@ z - @@ -547,18 +547,18 @@ L 445.68 209.454 - @@ -571,8 +571,8 @@ z - @@ -588,8 +588,8 @@ L 445.68 158.977636 - @@ -605,8 +605,8 @@ L 445.68 108.501273 - @@ -624,42 +624,42 @@ L 445.68 58.024909 - - @@ -673,25 +673,25 @@ z - - @@ -707,23 +707,23 @@ z - - - - diff --git a/docs/content/data/td_spread_over_four_months.svg b/docs/content/data/td_spread_over_four_months.svg index 31faece..a805d81 100644 --- a/docs/content/data/td_spread_over_four_months.svg +++ b/docs/content/data/td_spread_over_four_months.svg @@ -21,27 +21,27 @@ - - - @@ -49,32 +49,32 @@ L 87.467727 15.12 - - @@ -86,8 +86,8 @@ z - @@ -95,29 +95,29 @@ L 144.326818 15.12 - @@ -129,8 +129,8 @@ z - @@ -138,18 +138,18 @@ L 201.185909 15.12 - @@ -161,8 +161,8 @@ z - @@ -177,8 +177,8 @@ L 258.045 15.12 - @@ -186,28 +186,28 @@ L 314.904091 15.12 - @@ -219,8 +219,8 @@ z - @@ -235,8 +235,8 @@ L 371.763182 15.12 - @@ -244,36 +244,36 @@ L 428.622273 15.12 - @@ -287,237 +287,237 @@ z - - - - - - - - - - - - @@ -540,8 +540,8 @@ z - @@ -557,8 +557,8 @@ L 445.68 280.120909 - @@ -574,8 +574,8 @@ L 445.68 238.057273 - @@ -591,8 +591,8 @@ L 445.68 195.993636 - @@ -608,8 +608,8 @@ L 445.68 153.93 - @@ -625,8 +625,8 @@ L 445.68 111.866364 - @@ -642,8 +642,8 @@ L 445.68 69.802727 - @@ -651,23 +651,23 @@ L 445.68 27.739091 - @@ -682,42 +682,42 @@ z - - @@ -731,21 +731,21 @@ z - - @@ -757,23 +757,23 @@ z - - - - diff --git a/docs/content/data/td_two_and_four_years_ahead.svg b/docs/content/data/td_two_and_four_years_ahead.svg index 8d0ad22..722dab9 100644 --- a/docs/content/data/td_two_and_four_years_ahead.svg +++ b/docs/content/data/td_two_and_four_years_ahead.svg @@ -21,27 +21,27 @@ - - - @@ -49,56 +49,56 @@ L 87.467727 15.12 - - - @@ -110,8 +110,8 @@ z - @@ -119,29 +119,29 @@ L 172.756364 15.12 - @@ -153,8 +153,8 @@ z - @@ -162,36 +162,36 @@ L 258.045 15.12 - @@ -203,8 +203,8 @@ z - @@ -219,8 +219,8 @@ L 343.333636 15.12 - @@ -228,23 +228,23 @@ L 428.622273 15.12 - @@ -258,203 +258,203 @@ z - - - - - - - - - - @@ -476,8 +476,8 @@ z - @@ -493,8 +493,8 @@ L 445.68 280.120909 - @@ -510,8 +510,8 @@ L 445.68 248.573182 - @@ -527,8 +527,8 @@ L 445.68 217.025455 - @@ -544,8 +544,8 @@ L 445.68 185.477727 - @@ -561,8 +561,8 @@ L 445.68 153.93 - @@ -578,8 +578,8 @@ L 445.68 122.382273 - @@ -587,34 +587,34 @@ L 445.68 90.834545 - @@ -627,8 +627,8 @@ z - @@ -644,8 +644,8 @@ L 445.68 59.286818 - @@ -653,14 +653,14 @@ L 445.68 27.739091 - @@ -675,103 +675,103 @@ z - - - - - @@ -785,19 +785,19 @@ z - - @@ -807,23 +807,23 @@ z - - - - diff --git a/docs/content/getting_started/adding_temporal_information.md b/docs/content/getting_started/adding_temporal_information.md index 1fdd79d..d2efb1c 100644 --- a/docs/content/getting_started/adding_temporal_information.md +++ b/docs/content/getting_started/adding_temporal_information.md @@ -147,14 +147,14 @@ td_b_to_a = TemporalDistribution( amount=np.array([0.3, 0.5, 0.2]), ) -# Now add the temporal distribution to the corresponding exchange. In +# Now add the temporal distribution to the corresponding exchange. In # principle, you just have to do the following: -# exchange_object["temporal_distribution"] = TemporalDistribution -# We currently don't have the exchange-object at hand here, but we can +# exchange_object["temporal_distribution"] = TemporalDistribution +# We currently don't have the exchange-object at hand here, but we can # use the utility function add_temporal_distribution_to_exchange to help. add_temporal_distribution_to_exchange( - temporal_distribution=td_b_to_a, - input_code="B", + temporal_distribution=td_b_to_a, + input_code="B", input_database="background", output_code="A", output_database="foreground" @@ -166,11 +166,11 @@ td_a_to_co2 = TemporalDistribution( amount=np.array([0.6, 0.4]), ) -# We actually only have to define enough fields to uniquely identify the +# We actually only have to define enough fields to uniquely identify the # exchange here add_temporal_distribution_to_exchange( - temporal_distribution=td_a_to_co2, - input_code="CO2", + temporal_distribution=td_a_to_co2, + input_code="CO2", output_code="A" ) ``` @@ -242,7 +242,7 @@ So, as you can see, the prospective processes can reside within your normal brig ```python from datetime import datetime -# Note: The foreground does not represent a specific point in time, but should +# Note: The foreground does not represent a specific point in time, but should # later be dynamically distributed over time database_date_dict = { "background": datetime.strptime("2020", "%Y"), @@ -254,4 +254,3 @@ database_date_dict = { :::{note} You can use whatever data source you want for this prospective data. A nice package from the Brightway cosmos that can help you is [premise](https://premise.readthedocs.io/en/latest/introduction.html). ::: - diff --git a/docs/content/getting_started/build_process_timeline.md b/docs/content/getting_started/build_process_timeline.md index 650c5e0..4eb1f5c 100644 --- a/docs/content/getting_started/build_process_timeline.md +++ b/docs/content/getting_started/build_process_timeline.md @@ -26,4 +26,4 @@ The timeline that is returned looks like this: | 2024-01-01 | A | 2024-01-01 | -1 | 1.0 | None | | 2028-01-01 | B | 2024-01-01 | A | 0.6 | {'background': 0.2, 'background_2030': 0.8} | -Here we can see which share of which exchange happens at what point in time. Additionally, the "interpolation_weights" already tell us what share of an exchange should come from which database. With this info, we can calculate our time-explicit LCI in the next step. \ No newline at end of file +Here we can see which share of which exchange happens at what point in time. Additionally, the "interpolation_weights" already tell us what share of an exchange should come from which database. With this info, we can calculate our time-explicit LCI in the next step. diff --git a/docs/content/getting_started/index.md b/docs/content/getting_started/index.md index d45437c..9ff00ea 100644 --- a/docs/content/getting_started/index.md +++ b/docs/content/getting_started/index.md @@ -32,4 +32,4 @@ Step 1 - Adding temporal information Step 2 - Building the process timeline Step 3 - Calculating the time-explicit LCI Step 4 - Impact assessment -``` \ No newline at end of file +``` diff --git a/docs/content/getting_started/lcia.md b/docs/content/getting_started/lcia.md index 1066f3b..63b4816 100644 --- a/docs/content/getting_started/lcia.md +++ b/docs/content/getting_started/lcia.md @@ -15,7 +15,7 @@ print(tlca.static_score) ``` ## Dynamic LCIA -The inventory calculated by a `TimexLCA` retains temporal information. That means that in addition to knowing which process emitts what substance, we also know the timing of each emission. This allows for more advanced, dynamic characterization using characterization functions instead of just factors. In `bw_timex`, users can either use their own curstom functions or use some existing ones, e.g., from the package [`dynamic_characterization`](https://dynamic-characterization.readthedocs.io/en/latest/). We'll do the latter here. +The inventory calculated by a `TimexLCA` retains temporal information. That means that in addition to knowing which process emitts what substance, we also know the timing of each emission. This allows for more advanced, dynamic characterization using characterization functions instead of just factors. In `bw_timex`, users can either use their own curstom functions or use some existing ones, e.g., from the package [`dynamic_characterization`](https://dynamic-characterization.readthedocs.io/en/latest/). We'll do the latter here. First, we need to define which characterization function we want to apply to which biosphere flow: @@ -92,8 +92,3 @@ tlca.plot_dynamic_characterized_inventory()
For most of the functions we used here, there are numerous optional arguments and settings you can tweak. We explore some of them in our other [Examples](../examples/index.md), but when in doubt: Our code is pretty well documented and there are [docstrings](../api/index) everywhere - so please use them ☀️ - - - - - diff --git a/docs/content/getting_started/time_explicit_lci.md b/docs/content/getting_started/time_explicit_lci.md index b992813..a13a323 100644 --- a/docs/content/getting_started/time_explicit_lci.md +++ b/docs/content/getting_started/time_explicit_lci.md @@ -8,4 +8,4 @@ tlca.lci() Under the hood, we re-build the technosphere and biosphere matrices, adding new rows and columns to carry the extra temporal information. More on that in the [Theory Section](../theory.md#time-mapping). -Now that the inventory is calculated, we can characterize it in the next step. \ No newline at end of file +Now that the inventory is calculated, we can characterize it in the next step. diff --git a/notebooks/data/method.svg b/notebooks/data/method.svg index cf507f4..7291b05 100644 --- a/notebooks/data/method.svg +++ b/notebooks/data/method.svg @@ -1 +1 @@ -temporalinformationtemporalized system modelenvironmental impactsprocess timelinetime-explicitinventorystatic system modeltime-explicit databasesbuild_timeline()lci()dynamic_lcia()Step 1Step 2Step 3Step 4 \ No newline at end of file +temporalinformationtemporalized system modelenvironmental impactsprocess timelinetime-explicitinventorystatic system modeltime-explicit databasesbuild_timeline()lci()dynamic_lcia()Step 1Step 2Step 3Step 4