dynamic-characterization 0.0.1.dev1__tar.gz → 0.0.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {dynamic_characterization-0.0.1.dev1/dynamic_characterization.egg-info → dynamic_characterization-0.0.2}/PKG-INFO +3 -1
- {dynamic_characterization-0.0.1.dev1 → dynamic_characterization-0.0.2}/dynamic_characterization/__init__.py +1 -1
- dynamic_characterization-0.0.2/dynamic_characterization/temporalis/__init__.py +15 -0
- dynamic_characterization-0.0.2/dynamic_characterization/temporalis/radiative_forcing.py +139 -0
- dynamic_characterization-0.0.2/dynamic_characterization/timex/__init__.py +23 -0
- dynamic_characterization-0.0.2/dynamic_characterization/timex/radiative_forcing.py +482 -0
- {dynamic_characterization-0.0.1.dev1 → dynamic_characterization-0.0.2/dynamic_characterization.egg-info}/PKG-INFO +3 -1
- {dynamic_characterization-0.0.1.dev1 → dynamic_characterization-0.0.2}/dynamic_characterization.egg-info/SOURCES.txt +5 -1
- {dynamic_characterization-0.0.1.dev1 → dynamic_characterization-0.0.2}/dynamic_characterization.egg-info/requires.txt +2 -0
- {dynamic_characterization-0.0.1.dev1 → dynamic_characterization-0.0.2}/pyproject.toml +7 -1
- {dynamic_characterization-0.0.1.dev1 → dynamic_characterization-0.0.2}/LICENSE +0 -0
- {dynamic_characterization-0.0.1.dev1 → dynamic_characterization-0.0.2}/MANIFEST.in +0 -0
- {dynamic_characterization-0.0.1.dev1 → dynamic_characterization-0.0.2}/README.md +0 -0
- {dynamic_characterization-0.0.1.dev1 → dynamic_characterization-0.0.2}/dynamic_characterization.egg-info/dependency_links.txt +0 -0
- {dynamic_characterization-0.0.1.dev1 → dynamic_characterization-0.0.2}/dynamic_characterization.egg-info/top_level.txt +0 -0
- {dynamic_characterization-0.0.1.dev1 → dynamic_characterization-0.0.2}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: dynamic_characterization
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.2
|
|
4
4
|
Summary: Collection of dynamic characterization functions for life cycle inventories with temporal information
|
|
5
5
|
Author-email: Timo Diepers <timo.diepers@ltt.rwth-aachen.de>
|
|
6
6
|
Maintainer-email: Timo Diepers <timo.diepers@ltt.rwth-aachen.de>
|
|
@@ -20,6 +20,8 @@ Classifier: Topic :: Scientific/Engineering
|
|
|
20
20
|
Requires-Python: >=3.9
|
|
21
21
|
Description-Content-Type: text/markdown
|
|
22
22
|
License-File: LICENSE
|
|
23
|
+
Requires-Dist: pandas
|
|
24
|
+
Requires-Dist: numpy
|
|
23
25
|
Provides-Extra: testing
|
|
24
26
|
Requires-Dist: dynamic_characterization; extra == "testing"
|
|
25
27
|
Requires-Dist: pytest; extra == "testing"
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Dynamic characterization functions from the bw_temporalis package (https://github.com/brightway-lca/bw_temporalis).
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
__all__ = (
|
|
6
|
+
"__version__",
|
|
7
|
+
"characterize_co2",
|
|
8
|
+
"characterize_methane",
|
|
9
|
+
# Add functions and variables you want exposed in `dynamic_characterization.` namespace here
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
__version__ = "0.0.1"
|
|
13
|
+
|
|
14
|
+
from .radiative_forcing import characterize_co2
|
|
15
|
+
from .radiative_forcing import characterize_methane
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import pandas as pd
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def characterize_co2(
|
|
6
|
+
series,
|
|
7
|
+
period: int | None = 100,
|
|
8
|
+
cumulative: bool | None = False,
|
|
9
|
+
) -> pd.DataFrame:
|
|
10
|
+
"""
|
|
11
|
+
Calculate the cumulative or marginal radiative forcing (CRF) from CO2 for each year in a given period.
|
|
12
|
+
|
|
13
|
+
If `cumulative` is True, the cumulative CRF is calculated. If `cumulative` is False, the marginal CRF is calculated.
|
|
14
|
+
Takes a single row of the TimeSeries Pandas DataFrame (corresponding to a set of (`date`/`amount`/`flow`/`activity`).
|
|
15
|
+
For each year in the given period, the CRF is calculated.
|
|
16
|
+
Units are watts/square meter/kilogram of CO2.
|
|
17
|
+
|
|
18
|
+
Returns
|
|
19
|
+
-------
|
|
20
|
+
A TimeSeries dataframe with the following columns:
|
|
21
|
+
- date: datetime64[s]
|
|
22
|
+
- amount: float
|
|
23
|
+
- flow: str
|
|
24
|
+
- activity: str
|
|
25
|
+
|
|
26
|
+
Notes
|
|
27
|
+
-----
|
|
28
|
+
See also the relevant scientific publication on CRF: https://doi.org/10.5194/acp-13-2793-2013
|
|
29
|
+
See also the relevant scientific publication on the numerical calculation of CRF: http://pubs.acs.org/doi/abs/10.1021/acs.est.5b01118
|
|
30
|
+
|
|
31
|
+
See Also
|
|
32
|
+
--------
|
|
33
|
+
characterize_methane: The same function for CH4
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
# functional variables and units (from publications listed in docstring)
|
|
37
|
+
RE = 1.76e-15 # Radiative forcing (W/m2/kg)
|
|
38
|
+
alpha_0, alpha_1, alpha_2, alpha_3 = 0.2173, 0.2240, 0.2824, 0.2763
|
|
39
|
+
tau_1, tau_2, tau_3 = 394.4, 36.54, 4.304
|
|
40
|
+
decay_term = lambda year, alpha, tau: alpha * tau * (1 - np.exp(-year / tau))
|
|
41
|
+
|
|
42
|
+
date_beginning: np.datetime64 = series["date"].to_numpy()
|
|
43
|
+
date_characterized: np.ndarray = date_beginning + np.arange(
|
|
44
|
+
start=0, stop=period, dtype="timedelta64[Y]"
|
|
45
|
+
).astype("timedelta64[s]")
|
|
46
|
+
|
|
47
|
+
decay_multipliers: np.ndarray = np.array(
|
|
48
|
+
[
|
|
49
|
+
RE
|
|
50
|
+
* (
|
|
51
|
+
alpha_0 * year
|
|
52
|
+
+ decay_term(year, alpha_1, tau_1)
|
|
53
|
+
+ decay_term(year, alpha_2, tau_2)
|
|
54
|
+
+ decay_term(year, alpha_3, tau_3)
|
|
55
|
+
)
|
|
56
|
+
for year in range(period)
|
|
57
|
+
]
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
forcing = pd.Series(data=series.amount * decay_multipliers, dtype="float64")
|
|
61
|
+
if not cumulative:
|
|
62
|
+
forcing = forcing.diff(periods=1).fillna(0)
|
|
63
|
+
|
|
64
|
+
return pd.DataFrame(
|
|
65
|
+
{
|
|
66
|
+
"date": pd.Series(data=date_characterized, dtype="datetime64[s]"),
|
|
67
|
+
"amount": forcing,
|
|
68
|
+
"flow": series.flow,
|
|
69
|
+
"activity": series.activity,
|
|
70
|
+
}
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def characterize_methane(series, period: int = 100, cumulative=False) -> pd.DataFrame:
|
|
75
|
+
"""
|
|
76
|
+
Calculate the cumulative or marginal radiative forcing (CRF) from CH4 for each year in a given period.
|
|
77
|
+
|
|
78
|
+
If `cumulative` is True, the cumulative CRF is calculated. If `cumulative` is False, the marginal CRF is calculated.
|
|
79
|
+
Takes a single row of the TimeSeries Pandas DataFrame (corresponding to a set of (`date`/`amount`/`flow`/`activity`).
|
|
80
|
+
For earch year in the given period, the CRF is calculated.
|
|
81
|
+
Units are watts/square meter/kilogram of CH4.
|
|
82
|
+
|
|
83
|
+
Parameters
|
|
84
|
+
----------
|
|
85
|
+
series : array-like
|
|
86
|
+
A single row of the TimeSeries dataframe.
|
|
87
|
+
period : int, optional
|
|
88
|
+
Time period for calculation (number of years), by default 100
|
|
89
|
+
cumulative : bool, optional
|
|
90
|
+
Should the RF amounts be summed over time?
|
|
91
|
+
|
|
92
|
+
Returns
|
|
93
|
+
-------
|
|
94
|
+
A TimeSeries dataframe with the following columns:
|
|
95
|
+
- date: datetime64[s]
|
|
96
|
+
- amount: float
|
|
97
|
+
- flow: str
|
|
98
|
+
- activity: str
|
|
99
|
+
|
|
100
|
+
Notes
|
|
101
|
+
-----
|
|
102
|
+
See also the relevant scientific publication on CRF: https://doi.org/10.5194/acp-13-2793-2013
|
|
103
|
+
See also the relevant scientific publication on the numerical calculation of CRF: http://pubs.acs.org/doi/abs/10.1021/acs.est.5b01118
|
|
104
|
+
|
|
105
|
+
See Also
|
|
106
|
+
--------
|
|
107
|
+
characterize_co2: The same function for CO2
|
|
108
|
+
"""
|
|
109
|
+
|
|
110
|
+
# functional variables and units (from publications listed in docstring)
|
|
111
|
+
f1 = 0.5 # Unitless
|
|
112
|
+
f2 = 0.15 # Unitless
|
|
113
|
+
alpha = 1.27e-13 # Radiative forcing (W/m2/kg)
|
|
114
|
+
tau = 12.4 # Lifetime (years)
|
|
115
|
+
|
|
116
|
+
date_beginning: np.datetime64 = series["date"].to_numpy()
|
|
117
|
+
date_characterized: np.ndarray = date_beginning + np.arange(
|
|
118
|
+
start=0, stop=period, dtype="timedelta64[Y]"
|
|
119
|
+
).astype("timedelta64[s]")
|
|
120
|
+
|
|
121
|
+
decay_multipliers: list = np.array(
|
|
122
|
+
[
|
|
123
|
+
(1 + f1 + f2) * alpha * tau * (1 - np.exp(-year / tau))
|
|
124
|
+
for year in range(period)
|
|
125
|
+
]
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
forcing = pd.Series(data=series.amount * decay_multipliers, dtype="float64")
|
|
129
|
+
if not cumulative:
|
|
130
|
+
forcing = forcing.diff(periods=1).fillna(0)
|
|
131
|
+
|
|
132
|
+
return pd.DataFrame(
|
|
133
|
+
{
|
|
134
|
+
"date": pd.Series(data=date_characterized, dtype="datetime64[s]"),
|
|
135
|
+
"amount": forcing,
|
|
136
|
+
"flow": series.flow,
|
|
137
|
+
"activity": series.activity,
|
|
138
|
+
}
|
|
139
|
+
)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Dynamic characterization functions from the bw_timex package (https://github.com/brightway-lca/bw_timex).
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
__all__ = (
|
|
6
|
+
"__version__",
|
|
7
|
+
"characterize_co2",
|
|
8
|
+
"characterize_co2_uptake",
|
|
9
|
+
"characterize_co",
|
|
10
|
+
"characterize_ch4",
|
|
11
|
+
"characterize_n2o",
|
|
12
|
+
"create_generic_characterization_function",
|
|
13
|
+
# Add functions and variables you want exposed in `dynamic_characterization.` namespace here
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
__version__ = "0.0.1"
|
|
17
|
+
|
|
18
|
+
from .radiative_forcing import characterize_co2
|
|
19
|
+
from .radiative_forcing import characterize_co2_uptake
|
|
20
|
+
from .radiative_forcing import characterize_co
|
|
21
|
+
from .radiative_forcing import characterize_ch4
|
|
22
|
+
from .radiative_forcing import characterize_n2o
|
|
23
|
+
from .radiative_forcing import create_generic_characterization_function
|
|
@@ -0,0 +1,482 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
import numpy as np
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def IRF_co2(year) -> callable:
|
|
6
|
+
"""
|
|
7
|
+
Impulse Resonse Function (IRF) of CO2
|
|
8
|
+
|
|
9
|
+
Parameters
|
|
10
|
+
----------
|
|
11
|
+
year : int
|
|
12
|
+
The year after emission for which the IRF is calculated.
|
|
13
|
+
|
|
14
|
+
Returns
|
|
15
|
+
-------
|
|
16
|
+
float
|
|
17
|
+
The IRF value for the given year.
|
|
18
|
+
|
|
19
|
+
"""
|
|
20
|
+
alpha_0, alpha_1, alpha_2, alpha_3 = 0.2173, 0.2240, 0.2824, 0.2763
|
|
21
|
+
tau_1, tau_2, tau_3 = 394.4, 36.54, 4.304
|
|
22
|
+
exponentials = lambda year, alpha, tau: alpha * tau * (1 - np.exp(-year / tau))
|
|
23
|
+
return (
|
|
24
|
+
alpha_0 * year
|
|
25
|
+
+ exponentials(year, alpha_1, tau_1)
|
|
26
|
+
+ exponentials(year, alpha_2, tau_2)
|
|
27
|
+
+ exponentials(year, alpha_3, tau_3)
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def characterize_co2(
|
|
32
|
+
series,
|
|
33
|
+
period: int | None = 100,
|
|
34
|
+
cumulative: bool | None = False,
|
|
35
|
+
) -> pd.DataFrame:
|
|
36
|
+
"""
|
|
37
|
+
Calculate the cumulative or marginal radiative forcing (CRF) from CO2 for each year in a given period.
|
|
38
|
+
|
|
39
|
+
Based on characterize_co2 from bw_temporalis, but updated numerical values from IPCC AR6 Ch7 & SM.
|
|
40
|
+
|
|
41
|
+
If `cumulative` is True, the cumulative CRF is calculated. If `cumulative` is False, the marginal CRF is calculated.
|
|
42
|
+
Takes a single row of the TimeSeries Pandas DataFrame (corresponding to a set of (`date`/`amount`/`flow`/`activity`).
|
|
43
|
+
For each year in the given period, the CRF is calculated.
|
|
44
|
+
Units are watts/square meter/kilogram of CO2.
|
|
45
|
+
|
|
46
|
+
Returns
|
|
47
|
+
-------
|
|
48
|
+
A TimeSeries dataframe with the following columns:
|
|
49
|
+
- date: datetime64[s]
|
|
50
|
+
- amount: float
|
|
51
|
+
- flow: str
|
|
52
|
+
- activity: str
|
|
53
|
+
|
|
54
|
+
See also
|
|
55
|
+
--------
|
|
56
|
+
Joos2013: Relevant scientific publication on CRF: https://doi.org/10.5194/acp-13-2793-2013
|
|
57
|
+
Schivley2015: Relevant scientific publication on the numerical calculation of CRF: https://doi.org/10.1021/acs.est.5b01118
|
|
58
|
+
Forster2023: Updated numerical values from IPCC AR6 Chapter 7 (Table 7.15): https://doi.org/10.1017/9781009157896.009
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
# functional variables and units (from publications listed in docstring)
|
|
62
|
+
radiative_efficiency_ppb = (
|
|
63
|
+
1.33e-5 # W/m2/ppb; 2019 background co2 concentration; IPCC AR6 Table 7.15
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
# for conversion from ppb to kg-CO2
|
|
67
|
+
M_co2 = 44.01 # g/mol
|
|
68
|
+
M_air = 28.97 # g/mol, dry air
|
|
69
|
+
m_atmosphere = 5.135e18 # kg [Trenberth and Smith, 2005]
|
|
70
|
+
|
|
71
|
+
radiative_efficiency_kg = (
|
|
72
|
+
radiative_efficiency_ppb * M_air / M_co2 * 1e9 / m_atmosphere
|
|
73
|
+
) # W/m2/kg-CO2
|
|
74
|
+
|
|
75
|
+
date_beginning: np.datetime64 = series["date"].to_numpy()
|
|
76
|
+
date_characterized: np.ndarray = date_beginning + np.arange(
|
|
77
|
+
start=0, stop=period, dtype="timedelta64[Y]"
|
|
78
|
+
).astype("timedelta64[s]")
|
|
79
|
+
|
|
80
|
+
decay_multipliers: np.ndarray = np.array(
|
|
81
|
+
[radiative_efficiency_kg * IRF_co2(year) for year in range(period)]
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
forcing = pd.Series(data=series.amount * decay_multipliers, dtype="float64")
|
|
85
|
+
|
|
86
|
+
if not cumulative:
|
|
87
|
+
forcing = forcing.diff(periods=1).fillna(0)
|
|
88
|
+
|
|
89
|
+
return pd.DataFrame(
|
|
90
|
+
{
|
|
91
|
+
"date": pd.Series(data=date_characterized, dtype="datetime64[s]"),
|
|
92
|
+
"amount": forcing,
|
|
93
|
+
"flow": series.flow,
|
|
94
|
+
"activity": series.activity,
|
|
95
|
+
}
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def characterize_co2_uptake(
|
|
100
|
+
series,
|
|
101
|
+
period: int | None = 100,
|
|
102
|
+
cumulative: bool | None = False,
|
|
103
|
+
) -> pd.DataFrame:
|
|
104
|
+
"""
|
|
105
|
+
The same as characterize_co2, but with a negative sign for uptake of CO2.
|
|
106
|
+
|
|
107
|
+
Based on characterize_co2 from bw_temporalis, but updated numerical values from IPCC AR6 Ch7 & SM.
|
|
108
|
+
|
|
109
|
+
Calculate the negative cumulative or marginal radiative forcing (CRF) from CO2-uptake for each year in a given period.
|
|
110
|
+
|
|
111
|
+
If `cumulative` is True, the cumulative CRF is calculated. If `cumulative` is False, the marginal CRF is calculated.
|
|
112
|
+
Takes a single row of the TimeSeries Pandas DataFrame (corresponding to a set of (`date`/`amount`/`flow`/`activity`).
|
|
113
|
+
For each year in the given period, the CRF is calculated.
|
|
114
|
+
Units are watts/square meter/kilogram of CO2.
|
|
115
|
+
|
|
116
|
+
Returns
|
|
117
|
+
-------
|
|
118
|
+
A TimeSeries dataframe with the following columns:
|
|
119
|
+
- date: datetime64[s]
|
|
120
|
+
- amount: float
|
|
121
|
+
- flow: str
|
|
122
|
+
- activity: str
|
|
123
|
+
|
|
124
|
+
See also
|
|
125
|
+
--------
|
|
126
|
+
Joos2013: Relevant scientific publication on CRF: https://doi.org/10.5194/acp-13-2793-2013
|
|
127
|
+
Schivley2015: Relevant scientific publication on the numerical calculation of CRF: https://doi.org/10.1021/acs.est.5b01118
|
|
128
|
+
Forster2023: Updated numerical values from IPCC AR6 Chapter 7 (Table 7.15): https://doi.org/10.1017/9781009157896.009
|
|
129
|
+
"""
|
|
130
|
+
|
|
131
|
+
# functional variables and units (from publications listed in docstring)
|
|
132
|
+
radiative_efficiency_ppb = (
|
|
133
|
+
1.33e-5 # W/m2/ppb; 2019 background co2 concentration; IPCC AR6 Table 7.15
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
# for conversion from ppb to kg-CO2
|
|
137
|
+
M_co2 = 44.01 # g/mol
|
|
138
|
+
M_air = 28.97 # g/mol, dry air
|
|
139
|
+
m_atmosphere = 5.135e18 # kg [Trenberth and Smith, 2005]
|
|
140
|
+
|
|
141
|
+
radiative_efficiency_kg = (
|
|
142
|
+
radiative_efficiency_ppb * M_air / M_co2 * 1e9 / m_atmosphere
|
|
143
|
+
) # W/m2/kg-CO2
|
|
144
|
+
|
|
145
|
+
date_beginning: np.datetime64 = series["date"].to_numpy()
|
|
146
|
+
date_characterized: np.ndarray = date_beginning + np.arange(
|
|
147
|
+
start=0, stop=period, dtype="timedelta64[Y]"
|
|
148
|
+
).astype("timedelta64[s]")
|
|
149
|
+
|
|
150
|
+
decay_multipliers: np.ndarray = np.array(
|
|
151
|
+
[radiative_efficiency_kg * IRF_co2(year) for year in range(period)]
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
forcing = pd.Series(data=series.amount * decay_multipliers, dtype="float64")
|
|
155
|
+
|
|
156
|
+
forcing = (
|
|
157
|
+
-forcing
|
|
158
|
+
) # flip the sign of the characterization function for CO2 uptake and not release
|
|
159
|
+
|
|
160
|
+
if not cumulative:
|
|
161
|
+
forcing = forcing.diff(periods=1).fillna(0)
|
|
162
|
+
|
|
163
|
+
return pd.DataFrame(
|
|
164
|
+
{
|
|
165
|
+
"date": pd.Series(data=date_characterized, dtype="datetime64[s]"),
|
|
166
|
+
"amount": forcing,
|
|
167
|
+
"flow": series.flow,
|
|
168
|
+
"activity": series.activity,
|
|
169
|
+
}
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def characterize_co(
|
|
174
|
+
series,
|
|
175
|
+
period: int | None = 100,
|
|
176
|
+
cumulative: bool | None = False,
|
|
177
|
+
) -> pd.DataFrame:
|
|
178
|
+
"""
|
|
179
|
+
Calculate the cumulative or marginal radiative forcing (CRF) from CO for each year in a given period.
|
|
180
|
+
|
|
181
|
+
This is exactly the same function as for CO2, it's just scaled by the ratio of molar masses of CO and CO2. This is because CO is very short-lived (lifetime ~2 months) and we assume that it completely reacts to CO2 within the first year.
|
|
182
|
+
|
|
183
|
+
Based on characterize_co2 from bw_temporalis, but updated numerical values from IPCC AR6 Ch7 & SM.
|
|
184
|
+
|
|
185
|
+
Calculate the cumulative or marginal radiative forcing (CRF) from CO2 for each year in a given period.
|
|
186
|
+
|
|
187
|
+
If `cumulative` is True, the cumulative CRF is calculated. If `cumulative` is False, the marginal CRF is calculated.
|
|
188
|
+
Takes a single row of the TimeSeries Pandas DataFrame (corresponding to a set of (`date`/`amount`/`flow`/`activity`).
|
|
189
|
+
For each year in the given period, the CRF is calculated.
|
|
190
|
+
Units are watts/square meter/kilogram of CO2.
|
|
191
|
+
|
|
192
|
+
Returns
|
|
193
|
+
-------
|
|
194
|
+
A TimeSeries dataframe with the following columns:
|
|
195
|
+
- date: datetime64[s]
|
|
196
|
+
- amount: float
|
|
197
|
+
- flow: str
|
|
198
|
+
- activity: str
|
|
199
|
+
|
|
200
|
+
See also
|
|
201
|
+
--------
|
|
202
|
+
Joos2013: Relevant scientific publication on CRF: https://doi.org/10.5194/acp-13-2793-2013
|
|
203
|
+
Schivley2015: Relevant scientific publication on the numerical calculation of CRF: https://doi.org/10.1021/acs.est.5b01118
|
|
204
|
+
Forster2023: Updated numerical values from IPCC AR6 Chapter 7 (Table 7.15): https://doi.org/10.1017/9781009157896.009
|
|
205
|
+
"""
|
|
206
|
+
|
|
207
|
+
# functional variables and units (from publications listed in docstring)
|
|
208
|
+
radiative_efficiency_ppb = (
|
|
209
|
+
1.33e-5 # W/m2/ppb; 2019 background co2 concentration; IPCC AR6 Table 7.15
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
# for conversion from ppb to kg-CO2
|
|
213
|
+
M_co2 = 44.01 # g/mol
|
|
214
|
+
M_co = 28.01 # g/mol
|
|
215
|
+
M_air = 28.97 # g/mol, dry air
|
|
216
|
+
m_atmosphere = 5.135e18 # kg [Trenberth and Smith, 2005]
|
|
217
|
+
|
|
218
|
+
radiative_efficiency_kg = (
|
|
219
|
+
radiative_efficiency_ppb * M_air / M_co2 * 1e9 / m_atmosphere
|
|
220
|
+
) # W/m2/kg-CO2
|
|
221
|
+
|
|
222
|
+
date_beginning: np.datetime64 = series["date"].to_numpy()
|
|
223
|
+
date_characterized: np.ndarray = date_beginning + np.arange(
|
|
224
|
+
start=0, stop=period, dtype="timedelta64[Y]"
|
|
225
|
+
).astype("timedelta64[s]")
|
|
226
|
+
|
|
227
|
+
decay_multipliers: np.ndarray = np.array(
|
|
228
|
+
[
|
|
229
|
+
M_co2 / M_co * radiative_efficiency_kg * IRF_co2(year)
|
|
230
|
+
for year in range(period)
|
|
231
|
+
] # <-- Scaling from co2 to co is done here
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
forcing = pd.Series(data=series.amount * decay_multipliers, dtype="float64")
|
|
235
|
+
|
|
236
|
+
if not cumulative:
|
|
237
|
+
forcing = forcing.diff(periods=1).fillna(0)
|
|
238
|
+
|
|
239
|
+
return pd.DataFrame(
|
|
240
|
+
{
|
|
241
|
+
"date": pd.Series(data=date_characterized, dtype="datetime64[s]"),
|
|
242
|
+
"amount": forcing,
|
|
243
|
+
"flow": series.flow,
|
|
244
|
+
"activity": series.activity,
|
|
245
|
+
}
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
def characterize_ch4(
|
|
250
|
+
series,
|
|
251
|
+
period: int = 100,
|
|
252
|
+
cumulative=False,
|
|
253
|
+
) -> pd.DataFrame:
|
|
254
|
+
"""
|
|
255
|
+
Calculate the cumulative or marginal radiative forcing (CRF) from CH4 for each year in a given period.
|
|
256
|
+
|
|
257
|
+
Based on characterize_methane from bw_temporalis, but updated numerical values from IPCC AR6 Ch7 & SM.
|
|
258
|
+
|
|
259
|
+
This DOES include indirect effects of CH4 on ozone and water vapor, but DOES NOT include the decay to CO2.
|
|
260
|
+
For more info on that, see the deprecated version of bw_temporalis.
|
|
261
|
+
|
|
262
|
+
If `cumulative` is True, the cumulative CRF is calculated. If `cumulative` is False, the marginal CRF is calculated.
|
|
263
|
+
Takes a single row of the TimeSeries Pandas DataFrame (corresponding to a set of (`date`/`amount`/`flow`/`activity`).
|
|
264
|
+
For earch year in the given period, the CRF is calculated.
|
|
265
|
+
Units are watts/square meter/kilogram of CH4.
|
|
266
|
+
|
|
267
|
+
Parameters
|
|
268
|
+
----------
|
|
269
|
+
series : array-like
|
|
270
|
+
A single row of the TimeSeries dataframe.
|
|
271
|
+
period : int, optional
|
|
272
|
+
Time period for calculation (number of years), by default 100
|
|
273
|
+
cumulative : bool, optional
|
|
274
|
+
Should the RF amounts be summed over time?
|
|
275
|
+
|
|
276
|
+
Returns
|
|
277
|
+
-------
|
|
278
|
+
A TimeSeries dataframe with the following columns:
|
|
279
|
+
- date: datetime64[s]
|
|
280
|
+
- amount: float
|
|
281
|
+
- flow: str
|
|
282
|
+
- activity: str
|
|
283
|
+
|
|
284
|
+
See also
|
|
285
|
+
--------
|
|
286
|
+
Joos2013: Relevant scientific publication on CRF: https://doi.org/10.5194/acp-13-2793-2013
|
|
287
|
+
Schivley2015: Relevant scientific publication on the numerical calculation of CRF: https://doi.org/10.1021/acs.est.5b01118
|
|
288
|
+
Forster2023: Updated numerical values from IPCC AR6 Chapter 7 (Table 7.15): https://doi.org/10.1017/9781009157896.009
|
|
289
|
+
"""
|
|
290
|
+
|
|
291
|
+
# functional variables and units (from publications listed in docstring)
|
|
292
|
+
radiative_efficiency_ppb = 5.7e-4 # # W/m2/ppb; 2019 background cch4 concentration; IPCC AR6 Table 7.15. This number includes indirect effects.
|
|
293
|
+
|
|
294
|
+
# for conversion from ppb to kg-CH4
|
|
295
|
+
M_ch4 = 16.04 # g/mol
|
|
296
|
+
M_air = 28.97 # g/mol, dry air
|
|
297
|
+
m_atmosphere = 5.135e18 # kg [Trenberth and Smith, 2005]
|
|
298
|
+
|
|
299
|
+
radiative_efficiency_kg = (
|
|
300
|
+
radiative_efficiency_ppb * M_air / M_ch4 * 1e9 / m_atmosphere
|
|
301
|
+
) # W/m2/kg-CH4
|
|
302
|
+
|
|
303
|
+
tau = 11.8 # Lifetime (years)
|
|
304
|
+
|
|
305
|
+
date_beginning: np.datetime64 = series["date"].to_numpy()
|
|
306
|
+
date_characterized: np.ndarray = date_beginning + np.arange(
|
|
307
|
+
start=0, stop=period, dtype="timedelta64[Y]"
|
|
308
|
+
).astype("timedelta64[s]")
|
|
309
|
+
|
|
310
|
+
decay_multipliers: list = np.array(
|
|
311
|
+
[
|
|
312
|
+
radiative_efficiency_kg * tau * (1 - np.exp(-year / tau))
|
|
313
|
+
for year in range(period)
|
|
314
|
+
]
|
|
315
|
+
)
|
|
316
|
+
|
|
317
|
+
forcing = pd.Series(data=series.amount * decay_multipliers, dtype="float64")
|
|
318
|
+
|
|
319
|
+
if not cumulative:
|
|
320
|
+
forcing = forcing.diff(periods=1).fillna(0)
|
|
321
|
+
|
|
322
|
+
return pd.DataFrame(
|
|
323
|
+
{
|
|
324
|
+
"date": pd.Series(data=date_characterized, dtype="datetime64[s]"),
|
|
325
|
+
"amount": forcing,
|
|
326
|
+
"flow": series.flow,
|
|
327
|
+
"activity": series.activity,
|
|
328
|
+
}
|
|
329
|
+
)
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
def characterize_n2o(
|
|
333
|
+
series,
|
|
334
|
+
period: int = 100,
|
|
335
|
+
cumulative=False,
|
|
336
|
+
) -> pd.DataFrame:
|
|
337
|
+
"""
|
|
338
|
+
Calculate the cumulative or marginal radiative forcing (CRF) from N2O for each year in a given period.
|
|
339
|
+
|
|
340
|
+
Based on characterize_methane from bw_temporalis, but updated numerical values from IPCC AR6 Ch7 & SM.
|
|
341
|
+
|
|
342
|
+
If `cumulative` is True, the cumulative CRF is calculated. If `cumulative` is False, the marginal CRF is calculated.
|
|
343
|
+
Takes a single row of the TimeSeries Pandas DataFrame (corresponding to a set of (`date`/`amount`/`flow`/`activity`).
|
|
344
|
+
For earch year in the given period, the CRF is calculated.
|
|
345
|
+
Units are watts/square meter/kilogram of N2O.
|
|
346
|
+
|
|
347
|
+
Parameters
|
|
348
|
+
----------
|
|
349
|
+
series : array-like
|
|
350
|
+
A single row of the TimeSeries dataframe.
|
|
351
|
+
period : int, optional
|
|
352
|
+
Time period for calculation (number of years), by default 100
|
|
353
|
+
cumulative : bool, optional
|
|
354
|
+
Should the RF amounts be summed over time?
|
|
355
|
+
|
|
356
|
+
Returns
|
|
357
|
+
-------
|
|
358
|
+
A TimeSeries dataframe with the following columns:
|
|
359
|
+
- date: datetime64[s]
|
|
360
|
+
- amount: float
|
|
361
|
+
- flow: str
|
|
362
|
+
- activity: str
|
|
363
|
+
|
|
364
|
+
See also
|
|
365
|
+
--------
|
|
366
|
+
Joos2013: Relevant scientific publication on CRF: https://doi.org/10.5194/acp-13-2793-2013
|
|
367
|
+
Schivley2015: Relevant scientific publication on the numerical calculation of CRF: https://doi.org/10.1021/acs.est.5b01118
|
|
368
|
+
Forster2023: Updated numerical values from IPCC AR6 Chapter 7 (Table 7.15): https://doi.org/10.1017/9781009157896.009
|
|
369
|
+
"""
|
|
370
|
+
|
|
371
|
+
# functional variables and units (from publications listed in docstring)
|
|
372
|
+
radiative_efficiency_ppb = 2.8e-3 # # W/m2/ppb; 2019 background cch4 concentration; IPCC AR6 Table 7.15. This number includes indirect effects.
|
|
373
|
+
|
|
374
|
+
# for conversion from ppb to kg-CH4
|
|
375
|
+
M_n2o = 44.01 # g/mol
|
|
376
|
+
M_air = 28.97 # g/mol, dry air
|
|
377
|
+
m_atmosphere = 5.135e18 # kg [Trenberth and Smith, 2005]
|
|
378
|
+
|
|
379
|
+
radiative_efficiency_kg = (
|
|
380
|
+
radiative_efficiency_ppb * M_air / M_n2o * 1e9 / m_atmosphere
|
|
381
|
+
) # W/m2/kg-N2O
|
|
382
|
+
|
|
383
|
+
tau = 109 # Lifetime (years)
|
|
384
|
+
|
|
385
|
+
date_beginning: np.datetime64 = series["date"].to_numpy()
|
|
386
|
+
date_characterized: np.ndarray = date_beginning + np.arange(
|
|
387
|
+
start=0, stop=period, dtype="timedelta64[Y]"
|
|
388
|
+
).astype("timedelta64[s]")
|
|
389
|
+
|
|
390
|
+
decay_multipliers: list = np.array(
|
|
391
|
+
[
|
|
392
|
+
radiative_efficiency_kg * tau * (1 - np.exp(-year / tau))
|
|
393
|
+
for year in range(period)
|
|
394
|
+
]
|
|
395
|
+
)
|
|
396
|
+
|
|
397
|
+
forcing = pd.Series(data=series.amount * decay_multipliers, dtype="float64")
|
|
398
|
+
if not cumulative:
|
|
399
|
+
forcing = forcing.diff(periods=1).fillna(0)
|
|
400
|
+
|
|
401
|
+
return pd.DataFrame(
|
|
402
|
+
{
|
|
403
|
+
"date": pd.Series(data=date_characterized, dtype="datetime64[s]"),
|
|
404
|
+
"amount": forcing,
|
|
405
|
+
"flow": series.flow,
|
|
406
|
+
"activity": series.activity,
|
|
407
|
+
}
|
|
408
|
+
)
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
def create_generic_characterization_function(decay_series) -> pd.DataFrame:
|
|
412
|
+
"""
|
|
413
|
+
Creates a characterization function for a GHG based on a decay series, by calling the nested method `characterize_generic()`.
|
|
414
|
+
|
|
415
|
+
Parameters
|
|
416
|
+
----------
|
|
417
|
+
decay_series : np.ndarray
|
|
418
|
+
A decay series for a specific GHG. This is retrieved from `../data/decay_multipliers.pkl`
|
|
419
|
+
|
|
420
|
+
Returns
|
|
421
|
+
-------
|
|
422
|
+
A function called `characterize_generic`, which in turn returns a TimeSeries dataframe that contains the forcing of the emission of the row over the given period based on the decay series of that biosphere flow.
|
|
423
|
+
|
|
424
|
+
"""
|
|
425
|
+
|
|
426
|
+
def characterize_generic(
|
|
427
|
+
series,
|
|
428
|
+
period: int = 100,
|
|
429
|
+
cumulative=False,
|
|
430
|
+
) -> pd.DataFrame:
|
|
431
|
+
"""
|
|
432
|
+
Uses lookup generated in /dev/calculate_metrics.ipynb
|
|
433
|
+
Data originates from https://doi.org/10.1029/2019RG000691
|
|
434
|
+
|
|
435
|
+
Parameters
|
|
436
|
+
----------
|
|
437
|
+
series : array-like
|
|
438
|
+
A single row of the dynamic inventory dataframe.
|
|
439
|
+
period : int, optional
|
|
440
|
+
Time period for calculation (number of years), by default 100
|
|
441
|
+
cumulative : bool,
|
|
442
|
+
cumulative impact
|
|
443
|
+
|
|
444
|
+
Returns
|
|
445
|
+
-------
|
|
446
|
+
A TimeSeries dataframe that contains the forcing of the point emission from the row for each year in the given period.
|
|
447
|
+
date: datetime64[s]
|
|
448
|
+
amount: float (forcing at this timestep)
|
|
449
|
+
flow: str
|
|
450
|
+
activity: str
|
|
451
|
+
|
|
452
|
+
See also
|
|
453
|
+
--------
|
|
454
|
+
Joos2013: Relevant scientific publication on CRF: https://doi.org/10.5194/acp-13-2793-2013
|
|
455
|
+
Schivley2015: Relevant scientific publication on the numerical calculation of CRF: https://doi.org/10.1021/acs.est.5b01118
|
|
456
|
+
Forster2023: Updated numerical values from IPCC AR6 Chapter 7 (Table 7.15): https://doi.org/10.1017/9781009157896.009
|
|
457
|
+
|
|
458
|
+
"""
|
|
459
|
+
|
|
460
|
+
date_beginning: np.datetime64 = series["date"].to_numpy()
|
|
461
|
+
|
|
462
|
+
dates_characterized: np.ndarray = date_beginning + np.arange(
|
|
463
|
+
start=0, stop=period, dtype="timedelta64[Y]"
|
|
464
|
+
).astype("timedelta64[s]")
|
|
465
|
+
|
|
466
|
+
decay_multipliers = decay_series[:period]
|
|
467
|
+
|
|
468
|
+
forcing = pd.Series(data=series.amount * decay_multipliers, dtype="float64")
|
|
469
|
+
|
|
470
|
+
if not cumulative:
|
|
471
|
+
forcing = forcing.diff(periods=1).fillna(0)
|
|
472
|
+
|
|
473
|
+
return pd.DataFrame(
|
|
474
|
+
{
|
|
475
|
+
"date": pd.Series(data=dates_characterized, dtype="datetime64[s]"),
|
|
476
|
+
"amount": forcing,
|
|
477
|
+
"flow": series.flow,
|
|
478
|
+
"activity": series.activity,
|
|
479
|
+
}
|
|
480
|
+
)
|
|
481
|
+
|
|
482
|
+
return characterize_generic
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: dynamic_characterization
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.2
|
|
4
4
|
Summary: Collection of dynamic characterization functions for life cycle inventories with temporal information
|
|
5
5
|
Author-email: Timo Diepers <timo.diepers@ltt.rwth-aachen.de>
|
|
6
6
|
Maintainer-email: Timo Diepers <timo.diepers@ltt.rwth-aachen.de>
|
|
@@ -20,6 +20,8 @@ Classifier: Topic :: Scientific/Engineering
|
|
|
20
20
|
Requires-Python: >=3.9
|
|
21
21
|
Description-Content-Type: text/markdown
|
|
22
22
|
License-File: LICENSE
|
|
23
|
+
Requires-Dist: pandas
|
|
24
|
+
Requires-Dist: numpy
|
|
23
25
|
Provides-Extra: testing
|
|
24
26
|
Requires-Dist: dynamic_characterization; extra == "testing"
|
|
25
27
|
Requires-Dist: pytest; extra == "testing"
|
|
@@ -7,4 +7,8 @@ dynamic_characterization.egg-info/PKG-INFO
|
|
|
7
7
|
dynamic_characterization.egg-info/SOURCES.txt
|
|
8
8
|
dynamic_characterization.egg-info/dependency_links.txt
|
|
9
9
|
dynamic_characterization.egg-info/requires.txt
|
|
10
|
-
dynamic_characterization.egg-info/top_level.txt
|
|
10
|
+
dynamic_characterization.egg-info/top_level.txt
|
|
11
|
+
dynamic_characterization/temporalis/__init__.py
|
|
12
|
+
dynamic_characterization/temporalis/radiative_forcing.py
|
|
13
|
+
dynamic_characterization/timex/__init__.py
|
|
14
|
+
dynamic_characterization/timex/radiative_forcing.py
|
|
@@ -31,6 +31,8 @@ requires-python = ">=3.9"
|
|
|
31
31
|
dependencies = [
|
|
32
32
|
# dependencies as strings with quotes, e.g. "foo"
|
|
33
33
|
# You can add version requirements like "foo>2.0"
|
|
34
|
+
"pandas",
|
|
35
|
+
"numpy",
|
|
34
36
|
]
|
|
35
37
|
|
|
36
38
|
[project.urls]
|
|
@@ -60,7 +62,11 @@ dev = [
|
|
|
60
62
|
[tool.setuptools]
|
|
61
63
|
license-files = ["LICENSE"]
|
|
62
64
|
include-package-data = true
|
|
63
|
-
packages = [
|
|
65
|
+
packages = [
|
|
66
|
+
"dynamic_characterization",
|
|
67
|
+
"dynamic_characterization.temporalis",
|
|
68
|
+
"dynamic_characterization.timex",
|
|
69
|
+
]
|
|
64
70
|
|
|
65
71
|
[tool.setuptools.dynamic]
|
|
66
72
|
version = {attr = "dynamic_characterization.__version__"}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|