Skip to content

Commit 93819ec

Browse files
committed
Handle input share of LDV PHEV technology
- Add data/transport/input-share.csv, .transport.files.input_share. - Incorporate via .ldv.prepare_tech_econ(). - Simplify key handling in prepare_tech_econ()
1 parent dfcdf2a commit 93819ec

File tree

4 files changed

+67
-52
lines changed

4 files changed

+67
-52
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Share of input of LDV technologies from each commodity
2+
#
3+
# Units: dimensionless
4+
#
5+
technology, commodity, year, value
6+
PHEV_ptrp, electr, *, 0.4
7+
PHEV_ptrp, lightoil, *, 0.6
8+
# NB the following lines are needed for a balanced output
9+
# from broadcast_wildcard()
10+
*, electr, *, 1.0
11+
*, lightoil, *, 1.0
12+
*, *, *, 1.0

message_ix_models/model/transport/build.py

+1
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,7 @@ def add_structure(c: Computer) -> None:
401401
("cg", quote(spec.add.set["consumer_group"])),
402402
("indexers:cg", spec.add.set["consumer_group indexers"]),
403403
("nodes", quote(info.set["node"])),
404+
# TODO Use "LED" where appropriate
404405
("indexers:scenario", quote(dict(scenario=repr(config.ssp).split(":")[1]))),
405406
("t::transport", quote(spec.add.set["technology"])),
406407
("t::transport agg", quote(dict(t=t_groups))),

message_ix_models/model/transport/files.py

+6
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,12 @@ def read_structures() -> "sdmx.message.StructureMessage":
369369
required=False,
370370
)
371371

372+
input_share = add(
373+
key="input-share:t-c-y:exo",
374+
name="Share of input of LDV technologies from each commodity",
375+
units="dimensionless",
376+
)
377+
372378
# NB This differs from emi_intensity in (a) having no 't[echnology]' dimension and (b)
373379
# including only CO₂.
374380
fuel_emi_intensity = add(

message_ix_models/model/transport/ldv.py

+48-52
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
from .util import wildcard
3232

3333
if TYPE_CHECKING:
34-
from genno.core.key import KeyLike # TODO Import from genno.types
3534
from genno.types import AnyQuantity
3635

3736
from message_ix_models.types import ParameterData
@@ -40,7 +39,7 @@
4039

4140
log = logging.getLogger(__name__)
4241

43-
#: Shorthand for tags on keys
42+
#: Shorthand for tags on keys.
4443
Li = "::LDV+ixmp"
4544

4645
#: Target key that collects all data generated in this module.
@@ -200,9 +199,9 @@ def prepare_computer(c: Computer):
200199
else:
201200
c.apply(
202201
prepare_tech_econ,
203-
k_efficiency=k.eff[2],
204-
k_inv_cost="inv_cost:n-t-y:LDV+exo",
205-
k_fix_cost="fix_cost:n-t-y:LDV+exo",
202+
efficiency=k.eff[2],
203+
inv_cost=Key("inv_cost:n-t-y:LDV+exo"),
204+
fix_cost=Key("fix_cost:n-t-y:LDV+exo"),
206205
)
207206

208207
# Usage
@@ -257,6 +256,10 @@ def prepare_computer(c: Computer):
257256
c.add("transport_data", __name__, key=TARGET)
258257

259258

259+
#: Common, fixed values for :func:`.prepare_tech_econ` and :func:`.get_dummy`.
260+
COMMON = dict(mode="all", time="year", time_dest="year", time_origin="year")
261+
262+
#: Mapping from short dimension IDs to MESSAGE index names.
260263
DIMS = dict(
261264
commodity="c",
262265
level="l",
@@ -267,80 +270,73 @@ def prepare_computer(c: Computer):
267270
year_act="ya",
268271
year_vtg="yv",
269272
)
270-
COMMON = dict(mode="all", time="year", time_dest="year", time_origin="year")
271273

272274

273275
def prepare_tech_econ(
274-
c: Computer,
275-
*,
276-
k_efficiency: "KeyLike",
277-
k_inv_cost: "KeyLike",
278-
k_fix_cost: "KeyLike",
276+
c: Computer, *, efficiency: Key, inv_cost: Key, fix_cost: Key
279277
) -> None:
280278
"""Prepare `c` to calculate techno-economic parameters for LDVs.
281279
282280
This prepares `k_target` to return a data structure with MESSAGE-ready data for the
283281
parameters ``input``, ``ouput``, ``fix_cost``, and ``inv_cost``.
284282
"""
285-
# Collection of KeySeq for starting-points
286-
k = Keys(input=Key("input::LDV"), output=Key("output::LDV"))
287-
288283
# Identify periods to include
289284
# FIXME Avoid hard-coding this period
290285
c.add("y::LDV", lambda y: list(filter(lambda x: 1995 <= x, y)), "y")
291286

292287
# Create base quantity for "output" parameter
293-
nty = tuple("nty")
294-
c.add(k.output[0] * nty, wildcard(1.0, "Gv km", nty))
295-
for i, coords in enumerate(["n::ex world", "t::LDV", "y::model"]):
296-
c.add(
297-
k.output[i + 1] * nty,
298-
"broadcast_wildcard",
299-
k.output[i] * nty,
300-
coords,
301-
dim=coords[0],
302-
)
303-
304-
### Convert input, output to MESSAGE data structure
305-
for par_name, base, ks, i in (
306-
("input", k_efficiency, k.input, 0),
307-
("output", k.output[3] * nty, k.output, 4),
288+
k = output_base = Key("output:n-t-y:LDV")
289+
c.add(k[0], wildcard(1.0, "Gv km", k.dims))
290+
291+
# Broadcast over (n, t, y) dimensions
292+
coords = ["n::ex world", "t::LDV", "y::model"]
293+
c.add(k[1], "broadcast_wildcard", k[0], *coords, dim=k.dims)
294+
295+
# Broadcast `exo.input_share` over (c, t) dimensions. This produces a large Quantity
296+
# with 1.0 everywhere except explicit entries in the input data file.
297+
# NB Order matters here
298+
k = exo.input_share
299+
coords = ["t::LDV", "c::transport+base", "y::model"]
300+
c.add(k[0], "broadcast_wildcard", k, *coords, dim=k.dims)
301+
302+
# Multiply by `bcast_tcl.input` to keep only the entries that correspond to actual
303+
# input commodities of particular technologies.
304+
input_bcast = c.add("input broadcast::LDV", "mul", k[0], bcast_tcl.input)
305+
306+
### Convert input and output to MESSAGE data structure
307+
for par_name, base, bcast in (
308+
("input", efficiency, input_bcast),
309+
("output", output_base[1], bcast_tcl.output),
308310
):
311+
k = Key(par_name, base.dims, "LDV")
312+
309313
# Extend data over missing periods in the model horizon
310-
c.add(ks[i], "extend_y", base, "y::LDV")
314+
c.add(k[0], "extend_y", base, "y::LDV")
311315

312-
# Produce the full quantity for input/output efficiency
313-
prev = c.add(ks[i + 1], "mul", ks[i], getattr(bcast_tcl, par_name), bcast_y.all)
316+
# Broadcast from (y) to (yv, ya) dims to produce the full quantity for
317+
# input/output efficiency
318+
prev = c.add(k[1], "mul", k[0], bcast, bcast_y.all)
314319

315320
# Convert to ixmp/MESSAGEix-structured pd.DataFrame
316-
# NB quote() is necessary with dask 2024.11.0, not with earlier versions
317-
c.add(ks[i + 2], "as_message_df", prev, name=par_name, dims=DIMS, common=COMMON)
321+
c.add(k[2], "as_message_df", prev, name=par_name, dims=DIMS, common=COMMON)
318322

319-
# Convert to target units
320-
_add(c, par_name, convert_units, ks[i + 2], "transport info")
323+
# Convert to target units and append to `TARGET`
324+
_add(c, par_name, convert_units, k[2], "transport info")
321325

322326
### Transform costs
323-
for par_name, base in (("fix_cost", k_fix_cost), ("inv_cost", k_inv_cost)):
324-
prev = c.add(
325-
f"{par_name}::LDV+0",
326-
"interpolate",
327-
base,
328-
"y::coords",
329-
kwargs=dict(fill_value="extrapolate"),
330-
)
327+
kw = dict(fill_value="extrapolate")
328+
for name, base in (("fix_cost", fix_cost), ("inv_cost", inv_cost)):
329+
prev = c.add(f"{par_name}::LDV+0", "interpolate", base, "y::coords", kwargs=kw)
331330
prev = c.add(f"{par_name}::LDV+1", "mul", prev, bcast_y.all)
332-
_add(
333-
c, par_name, "as_message_df", prev, name=par_name, dims=DIMS, common=COMMON
334-
)
331+
_add(c, name, "as_message_df", prev, name=par_name, dims=DIMS, common=COMMON)
335332

336333
### Compute CO₂ emissions factors
337-
338334
# Extract the 'input' data frame
339-
k.other = Key("other::LDV")
340-
c.add(k.other[0], itemgetter("input"), f"input{Li}")
335+
other = Key("other::LDV")
336+
c.add(other[0], itemgetter("input"), f"input{Li}")
341337

342-
# Use ef_for_input
343-
_add(c, "emission_factor", ef_for_input, "context", k.other[0], species="CO2")
338+
# Apply ef_for_input; append to `TARGET`
339+
_add(c, "emission_factor", ef_for_input, "context", other[0], species="CO2")
344340

345341

346342
def get_dummy(context) -> "ParameterData":

0 commit comments

Comments
 (0)