Skip to content

Commit 373fb63

Browse files
committed
Organize .project.ssp.transport
- Sort variables and functions. - Split main() to prepare_method_A(). - Add main(…, method=…) argument. - Add stub prepare_method_B().
1 parent 35b0cf0 commit 373fb63

File tree

1 file changed

+104
-83
lines changed

1 file changed

+104
-83
lines changed

message_ix_models/project/ssp/transport.py

Lines changed: 104 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414

1515
from genno.types import AnyQuantity
1616

17+
#: Expression for IAMC ‘variable’ names used in :func:`main`.
18+
EXPR = r"^Emissions\|(?P<e>[^\|]+)\|Energy\|Demand\|Transportation(?:\|(?P<t>.*))?$"
19+
1720

1821
def aviation_share(ref: "AnyQuantity") -> "AnyQuantity":
1922
"""Return (dummy) data for the share of aviation in emissions.
@@ -39,57 +42,6 @@ def aviation_share(ref: "AnyQuantity") -> "AnyQuantity":
3942
)
4043

4144

42-
def finalize(
43-
q_all: "AnyQuantity",
44-
q_update: "AnyQuantity",
45-
model_name: str,
46-
scenario_name: str,
47-
path_out: "pathlib.Path",
48-
) -> None:
49-
"""Finalize output.
50-
51-
1. Reattach "Model" and "Scenario" labels.
52-
2. Reassemble the "Variable" dimension/coords of `q_update`; drop "e" and "t".
53-
3. Convert both `q_all` and `q_update` to :class:`pandas.Series`; update the former
54-
with the contents of the latter.
55-
4. Adjust to IAMC ‘wide’ structure and write to `path_out`.
56-
57-
Parameters
58-
----------
59-
q_all :
60-
All data.
61-
q_update :
62-
Revised data to overwrite corresponding values in `q_all`.
63-
"""
64-
65-
def _expand(qty):
66-
return qty.expand_dims(
67-
{"Model": [model_name], "Scenario": [scenario_name]}
68-
).rename({"n": "Region", "UNIT": "Unit", "VARIABLE": "Variable"})
69-
70-
s_all = q_all.pipe(_expand).to_series()
71-
72-
s_all.update(
73-
q_update.pipe(_expand)
74-
.to_frame()
75-
.reset_index()
76-
.assign(
77-
Variable=lambda df: (
78-
"Emissions|" + df["e"] + "|Energy|Demand|Transportation|" + df["t"]
79-
).str.replace("|_T", "")
80-
)
81-
.drop(["e", "t"], axis=1)
82-
.set_index(s_all.index.names)[0]
83-
)
84-
85-
(
86-
s_all.unstack("y")
87-
.reorder_levels(["Model", "Scenario", "Region", "Variable", "Unit"])
88-
.reset_index()
89-
.to_csv(path_out, index=False)
90-
)
91-
92-
9345
def extract_dims(
9446
qty: "AnyQuantity", dim_expr: dict, *, drop: bool = True, fillna: str = "_T"
9547
) -> "AnyQuantity":
@@ -145,56 +97,81 @@ def extract_dims1(qty: "AnyQuantity", dim: dict) -> "AnyQuantity": # pragma: no
14597
return result
14698

14799

148-
def select_re(qty: "AnyQuantity", indexers: dict) -> "AnyQuantity":
149-
"""Select using regular expressions for each dimension."""
150-
new_indexers = dict()
151-
for dim, expr in indexers.items():
152-
new_indexers[dim] = list(
153-
map(str, filter(re.compile(expr).match, qty.coords[dim].data.astype(str)))
154-
)
155-
return qty.sel(new_indexers)
100+
def finalize(
101+
q_all: "AnyQuantity",
102+
q_update: "AnyQuantity",
103+
model_name: str,
104+
scenario_name: str,
105+
path_out: "pathlib.Path",
106+
) -> None:
107+
"""Finalize output.
156108
109+
1. Reattach "Model" and "Scenario" labels.
110+
2. Reassemble the "Variable" dimension/coords of `q_update`; drop "e" and "t".
111+
3. Convert both `q_all` and `q_update` to :class:`pandas.Series`; update the former
112+
with the contents of the latter.
113+
4. Adjust to IAMC ‘wide’ structure and write to `path_out`.
157114
158-
#: Expression for IAMC ‘variable’ names used in :func:`main`.
159-
EXPR = r"^Emissions\|(?P<e>[^\|]+)\|Energy\|Demand\|Transportation(?:\|(?P<t>.*))?$"
115+
Parameters
116+
----------
117+
q_all :
118+
All data.
119+
q_update :
120+
Revised data to overwrite corresponding values in `q_all`.
121+
"""
122+
123+
def _expand(qty):
124+
return qty.expand_dims(
125+
{"Model": [model_name], "Scenario": [scenario_name]}
126+
).rename({"n": "Region", "UNIT": "Unit", "VARIABLE": "Variable"})
127+
128+
s_all = q_all.pipe(_expand).to_series()
129+
130+
s_all.update(
131+
q_update.pipe(_expand)
132+
.to_frame()
133+
.reset_index()
134+
.assign(
135+
Variable=lambda df: (
136+
"Emissions|" + df["e"] + "|Energy|Demand|Transportation|" + df["t"]
137+
).str.replace("|_T", "")
138+
)
139+
.drop(["e", "t"], axis=1)
140+
.set_index(s_all.index.names)[0]
141+
)
142+
143+
(
144+
s_all.unstack("y")
145+
.reorder_levels(["Model", "Scenario", "Region", "Variable", "Unit"])
146+
.reset_index()
147+
.to_csv(path_out, index=False)
148+
)
160149

161150

162151
@minimum_version("genno 1.25")
163-
def main(path_in: "pathlib.Path", path_out: "pathlib.Path"):
152+
def main(path_in: "pathlib.Path", path_out: "pathlib.Path", method: str) -> None:
164153
"""Postprocess aviation emissions for SSP 2024.
165154
166155
1. Read input data from `path_in`.
167-
2. Select data with variable names matching :data:`EXPR`.
168-
3. Calculate (identical) values for:
169-
170-
- ``Emissions|*|Energy|Demand|Transportation|Aviation``
171-
- ``Emissions|*|Energy|Demand|Transportation|Aviation|International``
172-
173-
These are currently calculated as the product of :func:`aviation_share` and
174-
``Emissions|*|Energy|Demand|Transportation``.
175-
4. Subtract (3) from:
176-
``Emissions|*|Energy|Demand|Transportation|Road Rail and Domestic Shipping``
177-
5. Recombine with all other, unmodified data.
178-
6. Write to `path_out`.
156+
2. Call either :func:`prepare_method_A` or :func:`prepare_method_B` according to
157+
the value of `method`.
158+
3. Write to `path_out`.
179159
180160
Parameters
181161
----------
182162
path_in :
183163
Input data path.
184164
path_out :
185165
Output data path.
166+
method :
167+
either 'A' or 'B'.
186168
"""
187169
import pandas as pd
188170

189-
# Shorthand
190-
e_t = ("e", "t")
191-
t = "t"
192-
k_input = genno.Key("input", ("n", "y", "VARIABLE", "UNIT"))
193-
k = genno.KeySeq("result", ("n", "y", "UNIT") + e_t)
194-
195171
c = genno.Computer()
196172

197173
# Read the data from `path`
174+
k_input = genno.Key("input", ("n", "y", "VARIABLE", "UNIT"))
198175
c.add(
199176
k_input,
200177
iamc_like_data_for_query,
@@ -207,6 +184,38 @@ def main(path_in: "pathlib.Path", path_out: "pathlib.Path"):
207184
df = pd.read_csv(path_in, nrows=1)
208185
c.add("model name", genno.quote(df["Model"].iloc[0]))
209186
c.add("scenario name", genno.quote(df["Scenario"].iloc[0]))
187+
c.add("path out", path_out)
188+
189+
# Call a function to prepare the remaining calculations
190+
prepare_func = {
191+
"A": prepare_method_A,
192+
"B": prepare_method_B,
193+
}[method]
194+
prepare_func(c, k_input)
195+
196+
# Execute
197+
c.get("target")
198+
199+
200+
def prepare_method_A(c: "genno.Computer", k_input: "genno.Key") -> None:
201+
"""Prepare calculations using method 'A'.
202+
203+
1. Select data with variable names matching :data:`EXPR`.
204+
2. Calculate (identical) values for:
205+
206+
- ``Emissions|*|Energy|Demand|Transportation|Aviation``
207+
- ``Emissions|*|Energy|Demand|Transportation|Aviation|International``
208+
209+
These are currently calculated as the product of :func:`aviation_share` and
210+
``Emissions|*|Energy|Demand|Transportation``.
211+
3. Subtract (2) from:
212+
``Emissions|*|Energy|Demand|Transportation|Road Rail and Domestic Shipping``
213+
4. Recombine with all other, unmodified data.
214+
"""
215+
# Shorthand
216+
e_t = ("e", "t")
217+
t = "t"
218+
k = genno.KeySeq("result", ("n", "y", "UNIT") + e_t)
210219

211220
# Filter on "VARIABLE"
212221
c.add(k[0] / e_t, select_re, k_input, indexers={"VARIABLE": EXPR})
@@ -256,8 +265,20 @@ def main(path_in: "pathlib.Path", path_out: "pathlib.Path"):
256265
k[5],
257266
"model name",
258267
"scenario name",
259-
path_out=path_out,
268+
"path out",
260269
)
261270

262-
# Execute
263-
c.get("target")
271+
272+
def prepare_method_B(c, k_input: "genno.Key"):
273+
"""Prepare calculations using method 'B'."""
274+
raise NotImplementedError
275+
276+
277+
def select_re(qty: "AnyQuantity", indexers: dict) -> "AnyQuantity":
278+
"""Select from `qty` using regular expressions for each dimension."""
279+
new_indexers = dict()
280+
for dim, expr in indexers.items():
281+
new_indexers[dim] = list(
282+
map(str, filter(re.compile(expr).match, qty.coords[dim].data.astype(str)))
283+
)
284+
return qty.sel(new_indexers)

0 commit comments

Comments
 (0)