Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Transport improvements for 2024-W36 #225

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
4 changes: 2 additions & 2 deletions .github/workflows/transport.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ env:

on:
# Uncomment these lines for debugging, but leave them commented on 'main'
# pull_request:
# branches: [ main ]
pull_request:
branches: [ main ]
# push:
# branches: [ main ]
schedule:
Expand Down
6 changes: 6 additions & 0 deletions doc/pkg-data/codelists.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ These codes have the following annotations:
.. literalinclude:: ../../message_ix_models/data/commodity.yaml
:language: yaml

Emission species (:file:`emission.yaml`)
========================================

.. literalinclude:: ../../message_ix_models/data/emission.yaml
:language: yaml

.. _level-yaml:

Levels (``level.yaml``)
Expand Down
13 changes: 13 additions & 0 deletions doc/project/ssp.rst
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,16 @@ Data
.. autosummary::
SSPOriginal
SSPUpdate

2024 update
===========

Transport
---------

.. currentmodule:: message_ix_models.project.ssp.transport

.. automodule:: message_ix_models.project.ssp.transport
:members:

Use :program:`mix-models ssp transport --help in.xlsx out.xlsx` to invoke :func:`.main`.
2 changes: 1 addition & 1 deletion message_ix_models/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ def _log_threads(k: int, n: int):
"message_ix_models.model.water.cli",
"message_ix_models.project.circeular.cli",
"message_ix_models.project.edits.cli",
"message_ix_models.project.ssp",
"message_ix_models.project.ssp.cli",
"message_ix_models.report.cli",
"message_ix_models.model.material.cli",
"message_ix_models.testing.cli",
Expand Down
75 changes: 75 additions & 0 deletions message_ix_models/data/emission.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
BCA:
name: Black carbon
report: BC

CH4:
name: Methane

CO:
name: Carbon monoxide

CO2:
name: Carbon dioxide

N2O:
name: Nitrous oxide

NH3:
name: Ammonia

NOx:
name: Nitrogen oxides

OCA:
name: Organic carbon
report: OC

SO2:
name: Sulfur dioxide
report: Sulfur

VOC:
name: Volatile organic compounds

# The following codes also appear in
# ixmp://ixmp-dev/SSP_dev_SSP4_v0.1_Blv0.18/materials_low_dem_scen#1
# (2024-10-02) but are not currently used by code in message_ix_models.
#
# Agri_CH4
# Agri_N2O
# Agri_N2O_calc
# BCA_LandUseChangeEM
# BCA_SavanBurnEM
# CF4
# CH4_LandUseChangeEM
# CH4_SavanBurnEM
# CO_LandUseChangeEM
# CO_SavanBurnEM
# CO2_industry
# CO2_transformation
# CO2_transport
# HFC
# LU_CH4
# LU_CH4_Agri
# LU_CH4_BioBurn
# LU_CO2
# LU_N2O
# NH3_LandUseChangeEM
# NH3_ManureEM
# NH3_RiceEM
# NH3_SavanBurnEM
# NH3_SoilEM
# NOx_LandUseChangeEM
# NOx_SavanBurnEM
# NOx_SoilEM
# OCA_LandUseChangeEM
# OCA_SavanBurnEM
# PM2p5
# SF6
# SO2_LandUseChangeEM
# SO2_SavanBurnEM
# TCE
# TCE_CO2
# TCE_non-CO2
# VOC_LandUseChangeEM
# VOC_SavanBurnEM

Large diffs are not rendered by default.

35 changes: 31 additions & 4 deletions message_ix_models/data/transport/technology.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,24 @@ FR_FCm:
input: {commodity: methanol}
report: FRT_MFC

f road electr:
name: Freight road vehicle powered by electricity
input: {commodity: electr}

f rail electr:
name: Freight rail powered by electricity
input: {commodity: electr}

f rail lightoil:
name: Freight rail powered by light oil
input: {commodity: lightoil}

F RAIL:
name: Freight rail
child: [f rail elec, f rail loil]
units: Gv km
iea-eweb-flow: [RAIL]

crail_pub:
description: >-
Coal-powered urban public rail transport: aggregate of metro/underground,
Expand Down Expand Up @@ -404,13 +422,22 @@ LDV:
units: Gv km
iea-eweb-flow: [ROAD]

freight truck:
name: Freight trucks
F ROAD:
name: Freight road vehicle
report: Truck
description: >-
In MESSAGE-V, the output of all freight technologies was labelled: f-u
child: [FR_ICE_H, FR_ICE_M, FR_ICE_L, FR_ICG, FR_ICAe, FR_ICH, FR_FCH,
FR_FCg, FR_FCm]
child:
- f road electr
- FR_FCg
- FR_FCH
- FR_FCm
- FR_ICAe
- FR_ICE_H
- FR_ICE_L
- FR_ICE_M
- FR_ICG
- FR_ICH
units: Gv km
iea-eweb-flow: [ROAD]

Expand Down
2 changes: 1 addition & 1 deletion message_ix_models/model/transport/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ def navigate_ele(
to_constrain.append(code.id)

# Item (2): identify diesel-fueled freight truck technologies
for code in map(lambda t: techs[techs.index(t)], t_groups["t"]["freight truck"]):
for code in map(lambda t: techs[techs.index(t)], t_groups["t"]["F ROAD"]):
if "diesel" in str(code.description):
to_constrain.append(code.id)

Expand Down
2 changes: 1 addition & 1 deletion message_ix_models/model/transport/freight.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def get_freight_data(
info = context.transport.spec.add
info.set["commodity"].extend(get_codes("commodity"))

technologies = techs[techs.index(Code(id="freight truck"))].child
technologies = techs[techs.index(Code(id="F ROAD"))].child

# Information for data creation
common = dict(
Expand Down
4 changes: 2 additions & 2 deletions message_ix_models/model/transport/non_ldv.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ def _(nodes, technologies, y0, config: dict) -> Quantity:
rows: List[List] = []
cols = ["n", "t", "c", "value"]
for (n, modes, c), value in cfg.minimum_activity.items():
for m in ["2W", "BUS", "freight truck"] if modes == "ROAD" else ["RAIL"]:
for m in ["2W", "BUS", "F ROAD"] if modes == "ROAD" else ["RAIL"]:
m_idx = technologies.index(m)
rows.extend([n, t, c, value] for t in techs_for(technologies[m_idx], c))

Expand Down Expand Up @@ -264,7 +264,7 @@ def constraint_data(
# Non-LDV modes passenger modes
modes = set(t for t in t_modes if t != "LDV")
# Freight modes
modes.add("freight truck")
modes.add("F ROAD")

# Lists of technologies to constrain
# All technologies under the non-LDV modes
Expand Down
6 changes: 3 additions & 3 deletions message_ix_models/model/transport/operator.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,8 +279,8 @@ def distance_ldv(config: dict) -> "AnyQuantity":
EEI_TECH_MAP = {
"Buses": "BUS",
"Cars/light trucks": "LDV",
"Freight trains": "freight rail",
"Freight trucks": "freight truck",
"Freight trains": "F RAIL",
"Freight trucks": "F ROAD",
"Motorcycles": "2W",
"Passenger trains": "RAIL",
}
Expand Down Expand Up @@ -459,7 +459,7 @@ def _not_disutility(tech):
"2W": 1.5,
"BUS": 1.5,
"LDV": 1.5,
"freight truck": 2.0,
"F ROAD": 2.0,
"AIR": 1.3,
}.items():
value.update({t: 1 - (v / 100.0) for t in t_groups[group]})
Expand Down
44 changes: 4 additions & 40 deletions message_ix_models/model/transport/report.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
if TYPE_CHECKING:
import ixmp
from genno import Computer
from genno.types import AnyQuantity

from message_ix_models import Spec

Expand Down Expand Up @@ -519,6 +518,9 @@ def multi(context: Context, targets):
"""Report outputs from multiple scenarios."""
import plotnine as p9

from message_ix_models.report.operator import quantity_from_iamc
from message_ix_models.tools.iamc import _drop_unique

report_dir = context.get_local_path("report")
platform = context.get_platform()

Expand All @@ -542,23 +544,14 @@ def multi(context: Context, targets):

dfs.append(df)

# FIXME This duplicates code from message_ix_models.tools.exo_data; deduplicate
def drop_unique(df, names) -> pd.DataFrame:
names_list = names.split()
for name in names_list:
values = df[name].unique()
if len(values) > 1:
raise RuntimeError(f"Not unique {name!r}: {values}")
return df.drop(names_list, axis=1)

# Convert to a genno.Quantity
cols = ["Variable", "Model", "Scenario", "Region", "Unit"]
data = genno.Quantity(
pd.concat(dfs)
.sort_values(cols)
.melt(id_vars=cols, var_name="y")
.astype({"y": int})
.pipe(drop_unique, "Model")
.pipe(_drop_unique, columns="Model", record=dict())
.rename(columns={"Variable": "v", "Scenario": "s", "Region": "n"})
.dropna(subset=["value"])
.set_index("v s n y Unit".split())["value"]
Expand All @@ -580,32 +573,3 @@ def drop_unique(df, names) -> pd.DataFrame:
plot.save("debug.pdf")

return data


def quantity_from_iamc(qty: "AnyQuantity", variable: str) -> "AnyQuantity":
"""Extract data for a single measure from `qty` with (at least) dimensions v, u.

.. todo:: Move upstream, to either :mod:`ixmp` or :mod:`genno`.

Parameters
----------
variable : str
Regular expression to match the ``v`` dimension of `qty`.
"""
import re

from genno.operator import relabel, select

expr = re.compile(variable)
variables, replacements = [], {}
for var in qty.coords["v"].data:
if match := expr.fullmatch(var):
variables.append(match.group(0))
replacements[match.group(0)] = match.group(1)

subset = qty.pipe(select, {"v": variables}).pipe(relabel, {"v": replacements})

unique_units = subset.coords["Unit"].data
assert 1 == len(unique_units)
subset.units = unique_units[0]
return subset.sel(Unit=unique_units[0], drop=True)
7 changes: 2 additions & 5 deletions message_ix_models/project/advance/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,8 @@

from genno import Computer, Key

from message_ix_models.tools.exo_data import (
ExoDataSource,
iamc_like_data_for_query,
register_source,
)
from message_ix_models.tools.exo_data import ExoDataSource, register_source
from message_ix_models.tools.iamc import iamc_like_data_for_query
from message_ix_models.util import (
HAS_MESSAGE_DATA,
iter_keys,
Expand Down
7 changes: 2 additions & 5 deletions message_ix_models/project/gea/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,8 @@

import genno

from message_ix_models.tools.exo_data import (
ExoDataSource,
iamc_like_data_for_query,
register_source,
)
from message_ix_models.tools.exo_data import ExoDataSource, register_source
from message_ix_models.tools.iamc import iamc_like_data_for_query
from message_ix_models.util import package_data_path, path_fallback

if TYPE_CHECKING:
Expand Down
7 changes: 2 additions & 5 deletions message_ix_models/project/shape/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,8 @@

import logging

from message_ix_models.tools.exo_data import (
ExoDataSource,
iamc_like_data_for_query,
register_source,
)
from message_ix_models.tools.exo_data import ExoDataSource, register_source
from message_ix_models.tools.iamc import iamc_like_data_for_query
from message_ix_models.util import path_fallback

log = logging.getLogger(__name__)
Expand Down
17 changes: 0 additions & 17 deletions message_ix_models/project/ssp/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,6 @@
import re
from typing import Union

import click

from message_ix_models.util.click import common_params

from .structure import SSP, SSP_2017, SSP_2024, generate

__all__ = [
Expand Down Expand Up @@ -55,16 +51,3 @@ def __set__(self, obj, value):
if value is None:
value = self._default
setattr(obj, self._name, parse(value))


@click.group("ssp")
def cli():
"""Shared Socioeconomic Pathways (SSP) project."""


@cli.command("gen-structures")
@common_params("dry_run")
@click.pass_obj
def gen_structures(context, **kwargs):
"""(Re)Generate the SSP data structures in SDMX."""
generate(context)
Loading
Loading