Theory#
This section explains some of the theory behind time-explicit LCAs with bw_timex. In contrast to the Getting Started section, we explain a bit more of what`s going on in the background here. If this is still too vague for you, you can always check out our API reference.
Terminology#
LCA terminology can be confusing sometimes, also for experienced practitioners. Particularly, we found the terminology around temporal aspects of LCA confusing, where different terms have been used to describe the same temporal aspect or the same term has been used to describe different temporal aspects.
In an attempt for improved clarity, we use the term “time-explicit LCA”. Essentially, time-explicit LCA jointly considers “temporal distribution”, i.e., how processes, emissions and environmental responses are spread out over time, and “temporal evolution”, i.e., how processes, emissions and environmental responses change over time. Very broadly speaking, the former is frequently considered in dynamic LCA, while the latter is frequently considered in prospective LCA.
Below, you find a visualization of the time-explicit approach. Our decision tree might also help to understand the differences between the different types of LCA.
Data requirements#
For a time-explicit LCA, three inputs are required:
a static product system model with
temporal information using the attribute
temporal_distributionon technosphere or biosphere exchanges in the product system model, anda set of time-specific background databases, which must have a reference in time.
Note
The foreground system must have exchanges linked to one of the time-specific background databases. These exchanges at the intersection between foreground and background databases will be relinked by
bw_timex.Temporal distributions can occur at technosphere and biosphere exchanges and can be given in various forms, see bw_temporalis, including absolute (e.g. 2024-03-18) or relative (e.g. 3 years before) types and can have different temporal resolution (down to seconds but later aggregation supports resolutions down to hours).
Temporal distributions are optional. If none are provided, no delay between producing and consuming process is assumed and the timing of the consuming process is adopted also for the producing process.
Temporal distributions and graph traversal#
To determine the timing of the exchanges within the production system, we add the temporal_distribution attribute to the respective exchanges, using the TemporalDistribution class from bw_temporalis. This class carries the information how the amount of the exchange is spread over time in two numpy arrays (dateand amount). So, it tells you what share of an exchange happens at what point in time. If two consecutive edges in the supply chain graph carry a TemporalDistribution, they are convolved, combining the two temporal profiles.
Example: Convolution
Let’s say we have two temporal distributions. The first dates 30% of some exchange two years into the future, and 70% of that exchange four years into the future:
import numpy as np
from bw_temporalis import TemporalDistribution
two_and_four_years_ahead = TemporalDistribution(
date=np.array([2, 4], dtype="timedelta64[Y]"),
amount=np.array([0.3, 0.7])
)
two_and_four_years_ahead.graph(resolution="Y")
The other distribution spreads an amount over the following 4 months, with decreasing shares:
spread_over_four_months = TemporalDistribution(
date=np.array([0, 1, 2, 3], dtype="timedelta64[M]"),
amount=np.array([0.4, 0.3, 0.2, 0.1])
)
spread_over_four_months.graph(resolution="M")
Now, let’s see what happens when we convolute these temporal distributions:
convolved_distribution = two_and_four_years_ahead * spread_over_four_months
convolved_distribution.graph(resolution="M")
Note how both the dates and the amounts of the output distribution get scaled.
To convolute all the temporal information from the supply chain graph, bw_timex uses the graph traversal from
bw_temporalis. An in-depth
description of how this works is available in the brightway-docs. The default is a best-first supply chain graph traversal, following the most
impactful node in the graph based on the static pre-calculated LCIA score
for a chosen impact category. A breadth-first traversal is an optional alternative. Several input arguments for the graph traversal,
such as maximum calculation count or cut-off, can be passed to the TimexLCA
instance.
By default, only the foreground system is traversed, but nodes to be
skipped during traversal can be specified by a edge_filter_function.
At each process, the graph traversal uses convolution to combine the
temporal distributions of the process and the exchange it consumes into
the resulting combined temporal distribution of the upstream producer
of the exchange.
Temporal evolution in the foreground system#
bw_timex (>0.3.4) allows you to also implement time-dependent modifications to the foreground exchanges. This optional feature is useful if you want to simulate changes in the foreground system over time, such as technological learning, efficiency improvements or changing market structures. Such changes are not covered by the linking to time-specific background processes.
You can specify temporal evolution attributes on exchanges using either time-dependent scaling factors or absolute amounts. bw_timex, then, adjusts the base exchange amount based on the timing of the process, interpolating if needed between closest available scaling data. For scaling factors, it will multiply the base exchange amount with the time-specific scaling factor and for absolute amounts, it will directly set the value to the time-specific amount. These modified time-specific exchange amounts are then used throughout the rest of the timexLCA.
This temporal evolution of exchanges is optional, and if no temporal evolution is given, the exchange amounts remain constant over time.
Example: temporal evolution
Foreground exchange amounts can be modified with a dictionary of either time-dependent scaling factors or absolute amounts:
from datetime import datetime
exchange["temporal_evolution_factors"] = {
datetime(2020, 1, 1): 1.0, # 100% of base amount in 2020
datetime(2030, 1, 1): 0.75, # 75% of base amount in 2030
datetime(2040, 1, 1): 0.6, # 60% of base amount in 2040
}
exchange["temporal_evolution_amounts"] = {
datetime(2020, 1, 1): 60, # 60 MJ in 2020
datetime(2030, 1, 1): 45, # 45 MJ in 2030
datetime(2040, 1, 1): 36, # 36 MJ in 2040
}
Building the process timeline#
The graph traversal returns a timeline that lists the time of each
technosphere exchange in the temporalized foreground system. Exchanges
that flow from same producer to the same consumer within a certain
time-window (temporal_grouping, default is ‘year’) are grouped
together. This is done to avoid countless exchanges in the timeline, as
the temporal distributions at the exchange level can have temporal
resolutions down to seconds while one may not have a similar temporal
resolution for the databases. We recommend aligning temporal_grouping
to the temporal resolution of the available databases.
Example: Timeline
Let’s consider the following system: a process A consumes an exchange b from a process B. Both A and B emit CO2. The emission of CO2 from B decreases in the future. All exchanges occur at a certain point in time, relative to process A, which takes place “now” (2024). This example does not contain include temporal evolution of foregound exchanges.
The resulting timeline looks like this:
date_producer |
producer_name |
date_consumer |
consumer_name |
amount |
temporal_market_shares |
|---|---|---|---|---|---|
2022-01-01 |
B |
2024-01-01 |
A |
0.9 |
{‘background’: 0.8, ‘background_2030’: 0.2} |
2024-01-01 |
B |
2024-01-01 |
A |
1.5 |
{‘background’: 0.6, ‘background_2030’: 0.4} |
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} |
Time mapping#
Based on the timing of the processes in the timeline, bw_timex matches
the processes at the intersection between foreground and background to
the best available, time-specific background databases. Available matching strategies
are closest database or linear interpolation between two closest
databases based on temporal proximity. The column temporal_market_shares in the timeline specifies how much of that temporalized exchange is taken from the respective background databases. As only exchanges between foreground and background are relinked, this field is None for exchanges within the foreground system, e.g., A to -1 (the functional unit). The new best-fitting background
producer(s) are mapped on the same name, reference product and location
as the old background producer.
Modifying the matrices#
bw_timex now modifies the technosphere and biosphere matrices using
datapackages from
bw_processing. In order to store reference to multiple time points in a single matrix, we add a new element (row-column pair) for each process at a specific time to the matrices.
Technosphere matrix modifications#
For each temporalized process in the timeline, a new process copy, a “temporalized process” is created, which links to its new temporalized producer and consumer. The timing of the processes is stored in the
activity_time_mapping, which maps the process ids to process timing.For those processes linking to the background databases,
bw_timexcreates “temporal markets”, a new row-column pair that relinks the exchanges to the new producing processes from the best-fitting background database(s). Temporal markets are similar to regional markets in LCI databases, that distribute a commodity between different regional providers, only here across different temporal providers.
Biosphere matrix modifications#
Depending on the user’s choice, two different biosphere matrices are created:
The basic command
TimexLCA.lci()defaults to creating the dynamic biosphere matrix (TimexLCA.lci(build_dynamic_biosphere=True)). The dynamic biosphere matrix contains both the time-explicit inventories from the links to the time-specific background databases as well as the timing of the emissions. The timing of the emissions is realized through adding a separate biosphere flow for each time of emission. The inventories from the time-specific background databases are aggregated at the temporal markets as these have the correct timing from the timeline. The matrixTimexLCA.dynamic_inventoryand the more readable DataFrameTimexLCA.dynamic_inventory_dfcontain the emissions of the system per biosphere flow including its timestamp and its emitting process.If you are only interested in the new inventories, but not their timings, you can set
build_dynamic_biosphere=False, which will only create an inventory linking to the new background processes but without the timing of the biosphere flows and is stored underTimexLCA.lca.inventory.
Example: Matrix modifications
For the simple system above, these are the modifications we apply to the matrices:
The timings from the timeline and the inventory information from the time-specific databases is inserted into the new time-explicit matrices. For each specific point in time that product b is demanded, temporal markets are created, distributing the demand for b between the time-specific background databases. The dynamic biosphere matrix is created, containing the timing of emissions. You can see that the CO2 emission at process A occurs both in 2024 and 2025, based on the temporal distribution on this biosphere exchange.
Static or dynamic impact assessment#
bw_timex allows to use conventional static impact assessment methods (LCIA),
which are executed using TimexLCA.static_lcia(). Conventional LCIA methods have one characterization factor per substance, regardless of the timing of emission.
To take advantage of the detailed temporal information at the inventory
level of TimexLCA.dynamic_inventory, dynamic LCIA can be applied, using TimexLCA.dynamic_lcia().
Users can define or import their own dynamic LCIA functions. Out of the
box, we provide dynamic LCIA functions for the climate change metrics
‘radiative forcing’ and ‘global warming potential (GWP)’ for all
greenhouse gases in the IPCC AR6 report Chapter 7 Table
7.SM.7 from the brightway package dynamic_characterization.
The time_horizon, over which both metrics are evaluated,
defaults to 100 years, but can be set flexibly in years. Additionally,
both metrics can be applied with a fixed or flexible time horizon. Fixed
time horizon means that the all emissions are evaluated starting from
the timing of the functional unit until the end of the time horizon,
meaning that later emissions are counted for shorter, and flexible time
horizon means that each emission is evaluated starting from its own
timing until the end of the time horizon. The former is the approach of
Levasseur et al. 2010.
This behavior is set with the boolean fixed_time_horizon.
Contribution assessment of impacts#
Sometimes it might be helpful to understand where the time-explicit environmental
impacts actually originate from. While the default is to aggregate background
emissions at the respective temporal markets (to keep the correct timing), there is the option to disaggregate them
to their original emitting processes from the time-specific background databases. This is helpful for an in-depth contribution
analysis and can be executed with TimexLCA.dynamic_lcia(use_disaggregated_lci=True).
This overwrites the TimexLCA.dynamic_inventory and TimexLCA.dynamic_inventory_df
with versions, in which the background emissions are retained at corresponding
background processes, and uses these when calculating the dynamic LCIA results.
Unsure about the different options? Check out the decision tree for guidance for your time-explicit LCA.