From c7dc3e2005b31135374d58c3e88a7ae7dc3d5ee0 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Wed, 28 Jan 2026 23:04:05 +0100 Subject: [PATCH 01/73] Send transport output_cap_ret to l=end_of_life --- message_ix_models/model/transport/material.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/message_ix_models/model/transport/material.py b/message_ix_models/model/transport/material.py index 64707566ee..93ce53bdbf 100644 --- a/message_ix_models/model/transport/material.py +++ b/message_ix_models/model/transport/material.py @@ -81,7 +81,7 @@ name="input_cap_new", dims=DIMS, common=util.COMMON | dict(level="demand") ) _OCR_KW = dict( - name="output_cap_ret", dims=DIMS, common=util.COMMON | dict(level="scrap") + name="output_cap_ret", dims=DIMS, common=util.COMMON | dict(level="end_of_life") ) From 3e293b0be85e6c20fbdd3409ef07b8aa051d8055 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Wed, 28 Jan 2026 23:05:16 +0100 Subject: [PATCH 02/73] Use better variable names in .circeular.structure --- message_ix_models/project/circeular/structure.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/message_ix_models/project/circeular/structure.py b/message_ix_models/project/circeular/structure.py index 6548fdcde9..f5d46a785d 100644 --- a/message_ix_models/project/circeular/structure.py +++ b/message_ix_models/project/circeular/structure.py @@ -32,11 +32,14 @@ def create(cls) -> "common.Codelist": is_final=True, ) - for id_, market, material in ( + for id_, market, fuel_economy in ( + # 'Narrow' is one of the following 2 ("_CC_C_D_D", "Compact car", "default"), ("_CC_C_I_D", "Compact car", "improvement"), + # 'Slow', 'Close', and 'SSP' are one of the following 2 ("_CT_C_D_D", "Continuing trends", "default"), ("_CT_C_I_D", "Continuing trends", "improvement"), + # Sensitivity cases ("_ES_C_D_D", "Extreme SUVs", "default"), ("_ES_C_I_D", "Extreme SUVs", "improvement"), ("_NoS_C_D_D", "No SUVs", "default"), @@ -45,7 +48,7 @@ def create(cls) -> "common.Codelist": cl.append( common.Code( id=id_, - name=f"{market}, {material}", + name=f"{market}, {fuel_economy}", description="regional=convergence, material=default", ) ) From e06dab101b07a1aacd2088ac707963722e599bb8 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Wed, 28 Jan 2026 23:19:41 +0100 Subject: [PATCH 03/73] Handle no existing file in StructureFactory.get() --- message_ix_models/util/sdmx.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/message_ix_models/util/sdmx.py b/message_ix_models/util/sdmx.py index 8807358bec..dd55ff01c6 100644 --- a/message_ix_models/util/sdmx.py +++ b/message_ix_models/util/sdmx.py @@ -444,17 +444,24 @@ def get(cls, *, force: bool = False) -> MaintainableT: and up-to-date version of the artefact as of :attr:`version`. This updated version is stored using :func:`write`. """ - existing = read(cls.urn) + try: + # Read the existing artefact from file + existing = read(cls.urn) + except FileNotFoundError: + # No existing file + existing = None - if existing.version != cls.version or force: + if existing is None or existing.version != cls.version or force: result = cls.create() # Touch up `existing` for a fair comparison - existing.maintainer = result.maintainer + if existing is not None: + existing.maintainer = result.maintainer # Compare `existing` and `result` - if not existing.compare(result, strict=True): + if existing is None or not existing.compare(result, strict=True): # `result` somehow differs from `existing`: + # - No existing artefact. # - `existing` is an older version; cls.version has been bumped. # - Some other change to cls.generate()` From 55687f76d51cca30a848d0132306d0218947d493 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Wed, 28 Jan 2026 23:29:06 +0100 Subject: [PATCH 04/73] Add "Mt / Mv" to transport units --- message_ix_models/data/transport/set.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/message_ix_models/data/transport/set.yaml b/message_ix_models/data/transport/set.yaml index 5215664259..c6bbf0a7e2 100644 --- a/message_ix_models/data/transport/set.yaml +++ b/message_ix_models/data/transport/set.yaml @@ -255,6 +255,9 @@ unit: # tax_emission USD / t: USD per tonne carbon-equivalent; same as "USD/tC" + # Transport—Materials integration + Mt / Mv: megatonne of material per 10⁶ vehicles + # MA3T sets census_division: add: From 018865507a019cd5dabd997e19be7620634b0410 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Wed, 28 Jan 2026 23:40:40 +0100 Subject: [PATCH 05/73] Reduce transport output_cap_ret vs. input_cap_new --- message_ix_models/model/transport/material.py | 38 +++++++++++++------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/message_ix_models/model/transport/material.py b/message_ix_models/model/transport/material.py index 93ce53bdbf..bec6350cd6 100644 --- a/message_ix_models/model/transport/material.py +++ b/message_ix_models/model/transport/material.py @@ -50,7 +50,25 @@ # "zinc": "", # Missing } -# FIXME Do not hard code this +DIMS = dict( + commodity="c", + node_loc="n", + node_dest="n", + node_origin="n", + year_vtg="y", + technology="t", +) + +#: Portion of the ``input_cap_new`` that is available as ``output_cap_ret`` at the end +#: of lifetime of a technology. Dimensionless. +#: +#: .. todo:: Retrieve from a file. +OUTPUT_SHARE = 0.8 + +#: Mapping from values appearing in :data:`.input_cap_new` to MESSAGEix-Transport +#: technology IDs. +#: +#: .. todo:: Read this from a configuration file instead of hard-coding. TECHNOLOGY = { "BEV": {"ELC_100"}, "ICE": { @@ -66,15 +84,6 @@ "PHEV": {"PHEV_ptrp"}, } -DIMS = dict( - commodity="c", - node_loc="n", - node_dest="n", - node_origin="n", - year_vtg="y", - technology="t", -) - # Keyword arguments for as_message_df() for different parameters _DEMAND_KW = dict(name="demand", dims=DIMS, common=dict()) _ICN_KW = dict( @@ -122,9 +131,14 @@ def prepare_computer(c: "Computer") -> None: # Convert units: (material commodities [Mt]) / (transport CAP/CAP_NEW [Mvehicle]) c.add(k.exo[2], "convert_units", k.exo[1], units="Mt / Mvehicle") - # Convert data to MESSAGE-format data frames + # Convert to MESSAGE-format data frame collect("input_cap_new", "as_message_df", k.exo[2], **_ICN_KW) - collect("output_cap_ret", "as_message_df", k.exo[2], **_OCR_KW) + + # Reduce share available for recycling + c.add(k.exo[3], "mul", k.exo[2], OUTPUT_SHARE) + + # Convert to MESSAGE-format data frame + collect("output_cap_ret", "as_message_df", k.exo[3], **_OCR_KW) # Multiply base-period LDV sales by material intensity tmp = single_key(c.add("demand::MT+0", "mul", k.exo[2], k.sales, sums=True)) From a346d923f4c97a672e6dadccb11641f6daadffbb Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Wed, 4 Feb 2026 21:16:06 +0100 Subject: [PATCH 06/73] Add 'ref' setting to "transport" CI workflow --- .github/workflows/transport.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/transport.yaml b/.github/workflows/transport.yaml index 0e5f7eef5b..ff2b4e3b0d 100644 --- a/.github/workflows/transport.yaml +++ b/.github/workflows/transport.yaml @@ -6,6 +6,10 @@ env: target-ref: dev target-workflow: transport + # Ref to clone in the workflow. + # Default: use github.ref, e.g. 'main' for the schedule trigger. + ref: "" + # Starting point of the workflow. # # Use this value to build from a certain scenario: @@ -79,7 +83,7 @@ jobs: - name: Assemble JSON payload run: | echo '{ - "ref": "${{ github.ref }}", + "ref": "${{ env.ref || github.ref }}", "base": "${{ env.base }}", "from-step": "${{ env.from-step }}", "labels": ${{ env.labels }} From c93ac6380dbf3dc5bf2aa297eaa11115b4426c65 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Wed, 4 Feb 2026 21:17:22 +0100 Subject: [PATCH 07/73] Run "transport" CI workflow from the 'main' branch --- .github/workflows/transport.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/transport.yaml b/.github/workflows/transport.yaml index ff2b4e3b0d..18fa6e58b6 100644 --- a/.github/workflows/transport.yaml +++ b/.github/workflows/transport.yaml @@ -8,7 +8,7 @@ env: # Ref to clone in the workflow. # Default: use github.ref, e.g. 'main' for the schedule trigger. - ref: "" + ref: "main" # Starting point of the workflow. # From d99b3d9f726c4f0c07a01cbf877581a26d4c3361 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Wed, 4 Feb 2026 21:21:06 +0100 Subject: [PATCH 08/73] Reduce default label set in "transport" workflow --- .github/workflows/transport.yaml | 30 ++---------------------------- 1 file changed, 2 insertions(+), 28 deletions(-) diff --git a/.github/workflows/transport.yaml b/.github/workflows/transport.yaml index 18fa6e58b6..fc5728c723 100644 --- a/.github/workflows/transport.yaml +++ b/.github/workflows/transport.yaml @@ -26,40 +26,14 @@ env: # 'mix-models transport run'. Each label triggers 1 job in the target-repo/ # target-workflow. # - # - Delete lines to disable some runs. # - Ensure there is NO trailing comma on the last line. labels: >- [ - "SSP1", - "SSP1 exo price", - "SSP1 tax", "SSP2", - "SSP2 exo price", - "SSP2 tax", - "SSP3", - "SSP3 exo price", - "SSP3 tax", - "SSP4", - "SSP4 exo price", - "SSP4 tax", - "SSP5", - "SSP5 exo price", - "SSP5 tax", - "DIGSY-BEST-C", - "DIGSY-BEST-S", - "DIGSY-WORST-C", - "DIGSY-WORST-S", - "EDITS-CA", - "EDITS-HA", - "LED-SSP1", - "LED-SSP2" + "SSP2 exo price c59e", + "SSP2 tax" ] - # Currently disabled: - # [ - # - # ] - on: # Uncomment these lines for debugging, but leave them commented on 'main' # pull_request: From 586de99e8a1dbb1e96b2e1fa2664109bf2aacfc7 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Wed, 4 Feb 2026 21:54:12 +0100 Subject: [PATCH 09/73] Use transport annotations in CL_CIRCEULAR_SCENARIO --- message_ix_models/project/circeular/structure.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/message_ix_models/project/circeular/structure.py b/message_ix_models/project/circeular/structure.py index f5d46a785d..9ed5a51ed9 100644 --- a/message_ix_models/project/circeular/structure.py +++ b/message_ix_models/project/circeular/structure.py @@ -1,3 +1,4 @@ +from copy import deepcopy from typing import TYPE_CHECKING from message_ix_models.util.sdmx import StructureFactory @@ -19,11 +20,16 @@ class CL_TRANSPORT_SCENARIO(StructureFactory["common.Codelist"]): def create(cls) -> "common.Codelist": from sdmx.model import common + from message_ix_models.model.transport.config import CL_SCENARIO from message_ix_models.util.sdmx import read # Other data structures IIASA_ECE = read("IIASA_ECE:AGENCIES")["IIASA_ECE"] + # Retrieve the code "M SSP2" from IIASA_ECE:CL_TRANSPORT_SCENARIO. + # The annotations on this code control .model.transport.build(). + transport_ssp2 = CL_SCENARIO.get()["M SSP2"] + cl: "common.Codelist" = common.Codelist( id=cls.urn.partition(":")[-1], maintainer=IIASA_ECE, @@ -50,6 +56,7 @@ def create(cls) -> "common.Codelist": id=id_, name=f"{market}, {fuel_economy}", description="regional=convergence, material=default", + annotations=deepcopy(transport_ssp2.annotations), ) ) From fc9ee3bcc9278b70db1ad47dcd00b700e02ef602 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Wed, 4 Feb 2026 21:55:20 +0100 Subject: [PATCH 10/73] Simplify CL_CIRCEULAR_SCENARIO code IDs - Adjust test. --- .../project/circeular/structure.py | 22 +++++++++---------- .../tests/project/circeular/test_structure.py | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/message_ix_models/project/circeular/structure.py b/message_ix_models/project/circeular/structure.py index 9ed5a51ed9..dfb1075467 100644 --- a/message_ix_models/project/circeular/structure.py +++ b/message_ix_models/project/circeular/structure.py @@ -8,13 +8,13 @@ class CL_TRANSPORT_SCENARIO(StructureFactory["common.Codelist"]): - """SDMX code list ``IIASA_ECE:CL_CIRCEULAR_TRANSPORT_SCENARIO``. + """SDMX code list ``IIASA_ECE:CL_CIRCEULAR_SCENARIO``. This code lists contains unique IDs for CircEUlar transport scenarios. """ - urn = "IIASA_ECE:CL_CIRCEULAR_TRANSPORT_SCENARIO" - version = "1.0.0" + urn = "IIASA_ECE:CL_CIRCEULAR_SCENARIO" + version = "1.1.0" @classmethod def create(cls) -> "common.Codelist": @@ -40,16 +40,16 @@ def create(cls) -> "common.Codelist": for id_, market, fuel_economy in ( # 'Narrow' is one of the following 2 - ("_CC_C_D_D", "Compact car", "default"), - ("_CC_C_I_D", "Compact car", "improvement"), + ("CC-C-D-D", "Compact car", "default"), + ("CC-C-I-D", "Compact car", "improvement"), # 'Slow', 'Close', and 'SSP' are one of the following 2 - ("_CT_C_D_D", "Continuing trends", "default"), - ("_CT_C_I_D", "Continuing trends", "improvement"), + ("CT-C-D-D", "Continuing trends", "default"), + ("CT-C-I-D", "Continuing trends", "improvement"), # Sensitivity cases - ("_ES_C_D_D", "Extreme SUVs", "default"), - ("_ES_C_I_D", "Extreme SUVs", "improvement"), - ("_NoS_C_D_D", "No SUVs", "default"), - ("_NoS_C_I_D", "No SUVs", "improvement"), + ("ES-C-D-D", "Extreme SUVs", "default"), + ("ES-C-I-D", "Extreme SUVs", "improvement"), + ("NoS-C-D-D", "No SUVs", "default"), + ("NoS-C-I-D", "No SUVs", "improvement"), ): cl.append( common.Code( diff --git a/message_ix_models/tests/project/circeular/test_structure.py b/message_ix_models/tests/project/circeular/test_structure.py index cb8c9184fa..c28286afc0 100644 --- a/message_ix_models/tests/project/circeular/test_structure.py +++ b/message_ix_models/tests/project/circeular/test_structure.py @@ -10,6 +10,6 @@ def test_create(self) -> None: assert 8 == len(result) # An expected item is in the code list - item = result["_CC_C_D_D"] + item = result["CC-C-D-D"] # Description contains scenario information assert "regional=convergence, material=default" == str(item.description) From 0c8e5756bd906c8ddd03587d93b21ac889d3f144 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Wed, 4 Feb 2026 21:56:18 +0100 Subject: [PATCH 11/73] Add .transport.workflow.generate() docstring --- message_ix_models/model/transport/workflow.py | 1 + 1 file changed, 1 insertion(+) diff --git a/message_ix_models/model/transport/workflow.py b/message_ix_models/model/transport/workflow.py index 32fa5f81ea..fcad1cf0cb 100644 --- a/message_ix_models/model/transport/workflow.py +++ b/message_ix_models/model/transport/workflow.py @@ -143,6 +143,7 @@ def generate( dry_run: bool = False, **options, ) -> "Workflow": + """Generate the MESSAGEix-Transport :class:`.Workflow`.""" from message_ix.tools.migrate import initial_new_capacity_up_v311 from message_ix_models import Workflow From 78e09e0420dbbbe91626811d24c9325420e98919 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Wed, 4 Feb 2026 22:00:23 +0100 Subject: [PATCH 12/73] Move short_hash() from transport to common .util --- message_ix_models/model/transport/config.py | 3 +-- message_ix_models/model/transport/util.py | 6 ------ message_ix_models/model/transport/workflow.py | 4 +--- message_ix_models/util/__init__.py | 6 ++++++ 4 files changed, 8 insertions(+), 11 deletions(-) diff --git a/message_ix_models/model/transport/config.py b/message_ix_models/model/transport/config.py index fbc1ce4f6c..cd36bde3cc 100644 --- a/message_ix_models/model/transport/config.py +++ b/message_ix_models/model/transport/config.py @@ -11,12 +11,11 @@ from message_ix_models.project.navigate import T35_POLICY as NAVIGATE_SCENARIO from message_ix_models.project.ssp import SSP_2024, ssp_field from message_ix_models.project.transport_futures import SCENARIO as FUTURES_SCENARIO -from message_ix_models.util import package_data_path +from message_ix_models.util import package_data_path, short_hash from message_ix_models.util.config import ConfigHelper from message_ix_models.util.sdmx import AnnotationsMixIn, StructureFactory from .policy import ExogenousEmissionPrice, TaxEmission -from .util import short_hash if TYPE_CHECKING: from sdmx.model import common diff --git a/message_ix_models/model/transport/util.py b/message_ix_models/model/transport/util.py index b571763273..9547697bd7 100644 --- a/message_ix_models/model/transport/util.py +++ b/message_ix_models/model/transport/util.py @@ -2,7 +2,6 @@ import logging from collections.abc import Hashable, Iterable, Sequence -from hashlib import blake2s from pathlib import Path from typing import TYPE_CHECKING @@ -71,11 +70,6 @@ def region_path_fallback(context_or_regions: Context | str, *parts) -> Path: raise FileNotFoundError(candidates) -def short_hash(value: str, len: int = 3) -> str: - """Return a short (length `len`) hash of `value`.""" - return blake2s(value.encode()).hexdigest()[:len] - - def sum_numeric(iterable: Iterable, /, start=0) -> "numbers.Real": """Sum only the numeric values in `iterable`.""" result = start diff --git a/message_ix_models/model/transport/workflow.py b/message_ix_models/model/transport/workflow.py index fcad1cf0cb..1af97ffe09 100644 --- a/message_ix_models/model/transport/workflow.py +++ b/message_ix_models/model/transport/workflow.py @@ -5,9 +5,7 @@ from genno import KeyExistsError from message_ix_models.model.workflow import Config as WorkflowConfig -from message_ix_models.util import minimum_version - -from .util import short_hash +from message_ix_models.util import minimum_version, short_hash if TYPE_CHECKING: from message_ix_models.util.context import Context diff --git a/message_ix_models/util/__init__.py b/message_ix_models/util/__init__.py index dd21ec9784..2645e591a1 100644 --- a/message_ix_models/util/__init__.py +++ b/message_ix_models/util/__init__.py @@ -3,6 +3,7 @@ from collections.abc import Collection, Iterable, Mapping, MutableMapping, Sequence from datetime import datetime from functools import partial, singledispatch +from hashlib import blake2s from itertools import count from pathlib import Path from typing import TYPE_CHECKING, Any, Literal, Protocol @@ -781,6 +782,11 @@ def _(data: "MutableParameterData") -> "MutableParameterData": return data +def short_hash(value: str, len: int = 3) -> str: + """Return a short (length `len`) hash of `value`.""" + return blake2s(value.encode()).hexdigest()[:len] + + def show_versions() -> str: """Output of :func:`ixmp.show_versions`, as a :class:`str`.""" from io import StringIO From 5f60f191e1676958ca72a1e7d9107297cb5ad5e8 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Wed, 4 Feb 2026 22:17:56 +0100 Subject: [PATCH 13/73] =?UTF-8?q?Move=20scenario=5Furl()=20=E2=86=92=20Con?= =?UTF-8?q?fig.get=5Ftarget=5Furl()?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Use "-T-" or "-MT-" in model name as appropriate - Omit leading "M " from scenario name. - Omit trailing " policy" from scenario name, as this is reflected in code IDs. - Adjust usage. --- message_ix_models/model/transport/config.py | 44 +++++++++++++++++++ message_ix_models/model/transport/workflow.py | 41 ++--------------- message_ix_models/project/ssp/transport.py | 4 +- 3 files changed, 48 insertions(+), 41 deletions(-) diff --git a/message_ix_models/model/transport/config.py b/message_ix_models/model/transport/config.py index cd36bde3cc..22d83d55d8 100644 --- a/message_ix_models/model/transport/config.py +++ b/message_ix_models/model/transport/config.py @@ -392,6 +392,50 @@ def check(self): if all(map(lambda s: s.value > 0, [s1, s2])): raise ValueError(f"Scenario settings {s1} and {s2} are not compatible") + def get_target_url(self, context: "Context") -> str: + """Construct a target URL for a built MESSAGEix-Transport scenario. + + If the :attr:`.dest` URL is set on `context` (for instance, provided via the + :program:`--dest` CLI option), this URL returned with `label` appended to the + scenario name. + + If not, a form is used like: + + - :py:`model = "MESSAGEix-GLOBIOM 1.1-T-{regions}"`. Any value of the "model" + key from :attr:`.core.Config.dest_scenario` is appended. + - :py:`scenario = "{label}"`. Any value of the "scenario" key from + :attr:`.core.Config.dest_scenario` is appended; if this is not set, then + either "policy" (if :attr:`.transport.Config.policy` is set) or "baseline". + """ + if context.core.dest: + raise NotImplementedError + # Value from --dest CLI option + # TODO Check that this works if a version # is specified + return f"{context.dest} {self.label or ''}".strip() + else: + # Model name + model_name = ( + "MESSAGEix-GLOBIOM 1.1-" + + ("MT" if "material" in self.modules else "T") + + f"-{context.model.regions} " + # Append value from --model-extra CLI option + + context.core.dest_scenario.get("model", "") + ).rstrip() + + # Scenario name + scenario_name = ( + f"{self.label or ''} " + # Append value from --scenario-extra CLI option + + ( + context.core.dest_scenario.get("scenario") + or ("" if self.policy else "baseline") + ) + ).rstrip() + # Strip leading "M ", which is reflected in `model_name` + scenario_name = re.sub("^M ", "", scenario_name) + + return f"{model_name}/{scenario_name}" + def set_futures_scenario(self, value: str | None) -> None: """Update :attr:`project` from a string indicating a Transport Futures scenario. diff --git a/message_ix_models/model/transport/workflow.py b/message_ix_models/model/transport/workflow.py index 1af97ffe09..a272f0124d 100644 --- a/message_ix_models/model/transport/workflow.py +++ b/message_ix_models/model/transport/workflow.py @@ -98,41 +98,6 @@ def maybe_use_temporary_platform(context: "Context") -> None: log.info("No --platform/--url; using temporary, in-memory database") -def scenario_url(context: "Context", label: str | None = None) -> str: - """Construct a target URL for a built MESSAGEix-Transport scenario. - - If the :attr:`.dest` URL is set on `context` (for instance, provided via the - :program:`--dest` CLI option), this URL returned with `label` appended to the - scenario name. - - If not, a form is used like: - - - :py:`model = "MESSAGEix-GLOBIOM 1.1-T-{regions}"`. Any value of the "model" key - from :attr:`.core.Config.dest_scenario` is appended. - - :py:`scenario = "{label}"`. Any value of the "scenario" key from - :attr:`.core.Config.dest_scenario` is appended; if this is not set, then either - "policy" (if :attr:`.transport.Config.policy` is set) or "baseline". - """ - # Construct a URL template for MESSAGEix-Transport scenarios - if context.core.dest: - # Value from --dest CLI option - # TODO Check that this works if a version # is specified - return f"{context.dest} {label or ''}".strip() - else: - # Values from --model-extra, --scenario-extra CLI options - m_extra = context.core.dest_scenario.get("model", "") - s_extra = context.core.dest_scenario.get("scenario") or ( - "policy" if context.transport.policy else "baseline" - ) - - return "/".join( - ( - f"MESSAGEix-GLOBIOM 1.1-T-{context.model.regions} {m_extra}".rstrip(), - f"{label or ''} {s_extra}".strip(), - ) - ) - - @minimum_version("message_ix 3.11") def generate( context: "Context", @@ -181,8 +146,8 @@ def generate( # Update the .transport.Config from the `scenario_code` config.code = scenario_code - # Short and long labels for workflow step names and scenario names - label, label_full = config.code.id, config.label + # Short label for workflow step names + label = config.code.id # Identify the base scenario base_url = base_scenario_url(context, config, base_scenario_method) @@ -201,7 +166,7 @@ def generate( pass # Identify the target of the build step - target_url = scenario_url(context, label_full) + target_url = config.get_target_url(context) targets.append(target_url) # Build MESSAGEix-Transport on the scenario diff --git a/message_ix_models/project/ssp/transport.py b/message_ix_models/project/ssp/transport.py index a4398d4eab..eeed881084 100644 --- a/message_ix_models/project/ssp/transport.py +++ b/message_ix_models/project/ssp/transport.py @@ -363,7 +363,6 @@ def get_computer( """ from message_ix_models.model import Config as ModelConfig from message_ix_models.model.transport import Config as TransportConfig - from message_ix_models.model.transport import workflow # Create a Computer instance c = genno.Computer() @@ -394,9 +393,8 @@ def get_computer( # - Retrieve a 'label' used to construct a target scenario URL. cfg = TransportConfig.from_context(context) cfg.code = sc - label_full = cfg.label # Construct the target scenario URL - url = workflow.scenario_url(context, label_full) + url = cfg.get_target_url(context) # Optionally apply a regex substitution URL_SUB = { "LED-SSP1": ("$", "#162"), # Point to a specific version From df2989c566cc38bfcc966ea5df86a89848bed0ff Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Wed, 4 Feb 2026 23:42:26 +0100 Subject: [PATCH 14/73] Add .transport.workflow.add_steps() --- message_ix_models/model/transport/workflow.py | 104 ++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/message_ix_models/model/transport/workflow.py b/message_ix_models/model/transport/workflow.py index a272f0124d..ee2b30fb59 100644 --- a/message_ix_models/model/transport/workflow.py +++ b/message_ix_models/model/transport/workflow.py @@ -8,6 +8,8 @@ from message_ix_models.util import minimum_version, short_hash if TYPE_CHECKING: + from sdmx.model.common import Code + from message_ix_models.util.context import Context from message_ix_models.workflow import Workflow @@ -39,6 +41,108 @@ ) +def add_steps(wf: "Workflow", base: str, scenario_code: "Code") -> str: + """Add 0 or more MESSAGEix-Transport workflow steps to `wf`. + + If `scenario_code` does not contain annotations necessary to configure + MESSAGEix-Transport, `base` is returned and no changes are made to `wf`. + + Otherwise, the following steps are added: + + 1. :func:`.transport.build.main`. This step clones the Scenario from `base` to a + URL given by :meth:`.Config.get_target_url`. + 2. If :attr:`.Config.policy` is truth-y (that is, contains any :class:`.Policy` + instances), call :func:`.model.workflow.step_0` and remove values for the + "bound_emission" parameter. Otherwise, no action. + 3. :func:`message_ix.tools.migrate.initial_new_capacity_up_v311`. + + The name of (3) is returned. + + As well, the following additional steps are added: + + - "[…] debug build". This is the same as (1), except giving :py:`dry_run=True`, + so the scenario is not modified; only debug output is generated. See + :func:`.transport.build.main`. + - "T debug multi": Collects all "[…] debug build" steps. Repeated calls to + :func:`.add_steps` extend the list. + - "T report multi": :func:`.transport.report.multi`, called on all the target URLs + for (1). Repeated calls to :func:`.add_steps` extend the list. + """ + from message_ix.tools.migrate import initial_new_capacity_up_v311 + + from message_ix_models.model.workflow import step_0 + + from . import build + from .config import Config + from .report import callback, multi + + # Retrieve the Context used for the Workflow + context: "Context" = wf.graph["context"] + + try: + # Retrieve .transport.Config and make a copy for this particular workflow branch + config = deepcopy(context.transport) + except AttributeError: + # Not yet configured → use defaults + config = Config.from_context(context) + + try: + # Update the .transport.Config from the `scenario_code` + config.code = scenario_code + except KeyError: + # `scenario_code` does not contain annotations for .model.transport; do nothing + return base + + # Use transport reporting + if callback not in context.report.callback: + context.report.register(callback) + + # Short label for workflow step names + label = f"{config.code.id} T" + + # Identify the target of the build step + target_url = config.get_target_url(context) + + # Build MESSAGEix-Transport on the scenario + name = wf.add_step( + f"{label} built", base, build.main, target=target_url, clone=True, config=config + ) + + if config.policy: + # Prepare emissions accounting for carbon pricing + kw = dict(remove_emission_parameters=("bound_emission",)) + name = wf.add_step(f"{label} step_0", name, step_0, **kw) + + # Adjust initial_new_capacity_up values for message_ix#924 + name = wf.add_step( + f"{label} incu adjusted", + name, + lambda _, s: initial_new_capacity_up_v311(s, safety_factor=1.05), + ) + + # 'Simulate' build and produce debug outputs + debug = f"{label} debug build" + wf.add_step(debug, base, build.main, config=config, dry_run=True) + + # Compare debug outputs from multiple simulated builds + if "T debug build" not in wf: + # NB Here we use genno.Computer.add(), not .Workflow.add_step(). This is because + # because the operations are not WorkflowSteps that receive, modify, and + # return Scenario objects—only ordinary Python functions. + wf.add("T debug build", build.debug_multi, "context") + # Append the step ID for the debug step + wf.graph["T debug build"] += (debug,) + + # Report (including plot) using data from multiple, solved scenarios + if "T report multi" not in wf: + wf.add("T report multi", multi, "context", "T targets") + wf.add("T targets", []) + # Append this target URL to the list of target URLs + wf.graph["T targets"].append(target_url) + + return name + + def base_scenario_url( context: "Context", config: "Config", method: Literal["auto", "bare"] = "bare" ) -> str: From 1c59857d9623b694f13196db7311c6d85e9fb31f Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Wed, 4 Feb 2026 23:43:30 +0100 Subject: [PATCH 15/73] Add .model.workflow.from_codelist() - Generalize .transport.workflow.generate(). - Call .transport.workflow.add_steps() to, optionally, add steps to build the transport model. - Add test. --- message_ix_models/model/workflow.py | 72 ++++++++++++++++++- .../tests/model/test_workflow.py | 63 +++++++++++++++- 2 files changed, 131 insertions(+), 4 deletions(-) diff --git a/message_ix_models/model/workflow.py b/message_ix_models/model/workflow.py index c5d0b7939f..7c53ac7263 100644 --- a/message_ix_models/model/workflow.py +++ b/message_ix_models/model/workflow.py @@ -8,13 +8,15 @@ from message_ix import Scenario -from message_ix_models.util import identify_nodes +from message_ix_models import Workflow +from message_ix_models.util import identify_nodes, minimum_version, short_hash from message_ix_models.util.config import ConfigHelper if TYPE_CHECKING: from typing import TypedDict - from message_ix_models import Context + from message_ix_models import Context, Workflow + from message_ix_models.util.sdmx import StructureFactory class CommonArgs(TypedDict): relation_name: str @@ -62,6 +64,72 @@ class Config(ConfigHelper): ) +@minimum_version("message_ix 3.11") # Same as .transport.add_steps() +def from_codelist(context: "Context", cl: type["StructureFactory"]) -> "Workflow": + """Generate a workflow using a code list. + + - IDs of codes in `cl` are used to label steps. + - The following are invoked automatically: + + - :func:`.model.transport.workflow.add_steps` + + .. todo:: Add and also invoke functions like: + + - :py:`model.buildings.workflow.add_steps` + - :py:`model.material.workflow.add_steps` + + …in a standard or configurable order. + + See also + -------- + .project.circeular.workflow.generate + .model.transport.workflow.generate + """ + from genno import KeyExistsError + + from message_ix_models.model.transport import workflow as transport + from message_ix_models.report import report + + # Create the workflow + wf = Workflow(context) + + # Collection of step names + reported = [] + + # Iterate over all scenarios in IIASA_ECE:CL_CIRCEULAR_TRANSPORT_SCENARIO + for scenario_code in cl.get(force=True): + # Identify the URL of the base scenario + base_url = scenario_code.eval_annotation(id="base-scenario-URL") + + # Short label for subsequent steps + label = scenario_code.id + + # Name of the base step + name = f"base {short_hash(base_url)}" + try: + # Load the base model scenario + wf.add_step(name, None, target=base_url) + except KeyExistsError: + # Base scenario URL is identical to another (ssp, policy) combination; use + # the scenario returned by that step + pass + + name = transport.add_steps(wf, name, scenario_code) + + # Solve + wf.add_step(f"{label} solved", name, solve) + + # Report + reported.append(f"{label} reported") + wf.add_step(reported[-1], f"{label} solved", report) + + # Report all the scenarios + wf.add("all reported", reported) + wf.default_key = "all reported" + + return wf + + def solve( context: "Context", scenario: Scenario, diff --git a/message_ix_models/tests/model/test_workflow.py b/message_ix_models/tests/model/test_workflow.py index 9b1ea175b2..59624f8366 100644 --- a/message_ix_models/tests/model/test_workflow.py +++ b/message_ix_models/tests/model/test_workflow.py @@ -1,18 +1,77 @@ +import re from typing import TYPE_CHECKING -from message_ix_models.model.workflow import step_0 +from sdmx.model import common, v21 + +from message_ix_models.model.transport.workflow import SOLVE_CONFIG +from message_ix_models.model.workflow import from_codelist, step_0 from message_ix_models.testing import bare_res from message_ix_models.tools import ( add_AFOLU_CO2_accounting, add_alternative_TCE_accounting, ) +from message_ix_models.util.sdmx import StructureFactory if TYPE_CHECKING: - from pytest import FixtureRequest + from pytest import FixtureRequest, LogCaptureFixture from message_ix_models import Context +class CL_SCENARIO_TEST(StructureFactory): + """A scenario code list for testing.""" + + urn = "IIASA_ECE:CL_SCENARIO_TEST" + version = "1.0.0" + base_url = "" + + @classmethod + def create(cls) -> "common.Codelist": + from sdmx.model import common + + from message_ix_models.util.sdmx import read + + IIASA_ECE = read("IIASA_ECE:AGENCIES")["IIASA_ECE"] + cl: "common.Codelist" = common.Codelist( + id=cls.urn.partition(":")[-1], + maintainer=IIASA_ECE, + version="1.0.0", + is_external_reference=False, + is_final=True, + ) + + anno: list["common.BaseAnnotation"] = [ + v21.Annotation(id="base-scenario-URL", text=repr(cls.base_url)) + ] + + for id_ in "FOO BAR BAZ".split(): + cl.append(common.Code(id=id_, annotations=anno)) + + return cl + + +@from_codelist.minimum_version +def test_from_codelist( + caplog: "LogCaptureFixture", request: "FixtureRequest", test_context: "Context" +) -> None: + test_context.model.regions = "R12" + scenario = bare_res(request, test_context, solved=False) + + # Use the `scenario` as the base for a new Workflow + CL_SCENARIO_TEST.base_url = f"ixmp://{scenario.platform.name}/{scenario.url}" + + # Use specific, non-default solve config + test_context.solve = SOLVE_CONFIG + + # from_codelist() runs without error + wf = from_codelist(test_context, CL_SCENARIO_TEST) + + # Specific CPLEX options from SOLVE_CONFIG are used in the solve step + wf.get("FOO solved") + + assert any(re.match("^Use CPLEX options.*'iis': 1", msg) for msg in caplog.messages) + + def test_step_0(request: "FixtureRequest", test_context: "Context") -> None: """Test :func:`.model.workflow.step_0`.""" test_context.model.regions = "R12" From 765ab45586b4570fc717c780be5d24d687de41dd Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Wed, 4 Feb 2026 23:56:10 +0100 Subject: [PATCH 16/73] Use context.solve, if set, in workflow.solve() --- message_ix_models/model/workflow.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/message_ix_models/model/workflow.py b/message_ix_models/model/workflow.py index 7c53ac7263..f7f9ebc0b6 100644 --- a/message_ix_models/model/workflow.py +++ b/message_ix_models/model/workflow.py @@ -139,8 +139,12 @@ def solve( ): """Common model solve step for ENGAGE, NAVIGATE, and other workflows. - The steps respond settings from an optional instance of :class:`Config` passed as a - keyword argument. + The steps respond to settings from a :class:`Config` instance. In order of + precedence: + + 1. The keyword argument `config`. + 2. The "solve" key on `context`. + 3. A default instance of :class:`Config` *Before* `scenario` is solved: @@ -163,10 +167,15 @@ def solve( :obj:`True`. """ - config = config or Config() + # Identify configuration + try: + config = config or context.solve + except AttributeError: + config = Config() # Set reserve margin values if config.reserve_margin: + # FIXME Use an analogous function in message-ix-models, with tests from message_data.scenario_generation.reserve_margin import res_marg res_marg.main(scenario) @@ -180,6 +189,7 @@ def solve( if config.demand_scenario: # Retrieve DEMAND variable data from a different scenario and set as values # for the demand parameter + # FIXME Use an analogous function in message-ix-models, with tests from message_data.tools.utilities import transfer_demands source = Scenario(scenario.platform, **config.demand_scenario) From ee79dd28534e285e0a7645ad4b19f3764185e746 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Wed, 4 Feb 2026 23:46:29 +0100 Subject: [PATCH 17/73] Simplify .transport.workflow.generate() - Invoke .model.workflow.from_codelist() with CL_TRANSPORT_SCENARIO. - This in turn invokes .transport.workflow.add_steps(). - Output is identical. - Remove unused dry_run keyword argument. - Adjust tests. --- message_ix_models/model/transport/workflow.py | 106 ++---------------- .../tests/model/transport/test_demand.py | 2 +- .../tests/model/transport/test_workflow.py | 20 ++-- 3 files changed, 20 insertions(+), 108 deletions(-) diff --git a/message_ix_models/model/transport/workflow.py b/message_ix_models/model/transport/workflow.py index ee2b30fb59..7053c54e16 100644 --- a/message_ix_models/model/transport/workflow.py +++ b/message_ix_models/model/transport/workflow.py @@ -2,10 +2,8 @@ from copy import deepcopy from typing import TYPE_CHECKING, Literal -from genno import KeyExistsError - from message_ix_models.model.workflow import Config as WorkflowConfig -from message_ix_models.util import minimum_version, short_hash +from message_ix_models.util import minimum_version if TYPE_CHECKING: from sdmx.model.common import Code @@ -204,28 +202,20 @@ def maybe_use_temporary_platform(context: "Context") -> None: @minimum_version("message_ix 3.11") def generate( - context: "Context", - *, - report_key: str = "transport all", - dry_run: bool = False, - **options, + context: "Context", *, report_key: str = "transport all", **options ) -> "Workflow": """Generate the MESSAGEix-Transport :class:`.Workflow`.""" - from message_ix.tools.migrate import initial_new_capacity_up_v311 - from message_ix_models import Workflow - from message_ix_models.model.workflow import solve, step_0 - from message_ix_models.report import report + from message_ix_models.model.workflow import from_codelist - from . import build from .config import CL_SCENARIO, Config - from .report import multi # Handle CLI options # TODO respect quiet options.pop("target_model_name", None) # Stored on context.core.dest_scenario options.pop("target_scenario_name", None) # Stored on context.core.dest_scenario base_scenario_method = options.pop("base_scenario") + del base_scenario_method maybe_use_temporary_platform(context) @@ -234,90 +224,8 @@ def generate( # Set the default .report.Config key for ".* reported" steps context.report.key = report_key - context.report.register("model.transport") - - # Create the workflow - wf = Workflow(context) - - # Collections of step names - debug, reported, targets = [], [], [] - - # Iterate over all scenarios in IIASA_ECE:CL_TRANSPORT_SCENARIO - for scenario_code in CL_SCENARIO.get(): - # Make a copy of the base .transport.Config for this particular workflow branch - config = deepcopy(context.transport) - - # Update the .transport.Config from the `scenario_code` - config.code = scenario_code - - # Short label for workflow step names - label = config.code.id - - # Identify the base scenario - base_url = base_scenario_url(context, config, base_scenario_method) - # log.debug(f"Base scenario for scenario={label_full!r}: {base_url}") - # log.debug(f"{config.policy = }") - - # Name of the base step - base = f"base {short_hash(base_url)}" - - try: - # Load the base model scenario - wf.add_step(base, None, target=base_url) - except KeyExistsError: - # Base scenario URL is identical to another (ssp, policy) combination; use - # the scenario returned by that step - pass - - # Identify the target of the build step - target_url = config.get_target_url(context) - targets.append(target_url) - - # Build MESSAGEix-Transport on the scenario - name = wf.add_step( - f"{label} built", - base, - build.main, - target=target_url, - clone=True, - config=config, - ) - - if config.policy: - # Prepare emissions accounting for carbon pricing - kw = dict(remove_emission_parameters=("bound_emission",)) - name = wf.add_step(f"{label} step_0", name, step_0, **kw) - - # Adjust initial_new_capacity_up values for message_ix#924 - name = wf.add_step( - f"{label} incu adjusted", - name, - lambda _, s: initial_new_capacity_up_v311(s, safety_factor=1.05), - ) - - # 'Simulate' build and produce debug outputs - debug.append(f"{label} debug build") - wf.add_step(debug[-1], base, build.main, config=config, dry_run=True) - - # Solve - wf.add_step(f"{label} solved", name, solve, config=SOLVE_CONFIG) - - # Report - reported.append(f"{label} reported") - wf.add_step(reported[-1], f"{label} solved", report) - - # NB the following use genno.Computer.add(), not .Workflow.add_step(). This is - # because the operations are not WorkflowSteps that receive, modify, and return - # Scenario objects—only ordinary Python functions. - - # Compare debug outputs from multiple simulated builds - wf.add("debug build", build.debug_multi, "context", *debug) - - # Report (including plot) using data from multiple, solved scenarios - wf.add("report multi", multi, "context", targets=targets) - # Report all the scenarios - wf.add("all reported", reported) - wf.default_key = "all reported" + # Set options for solving + context.solve = SOLVE_CONFIG - return wf + return from_codelist(context, CL_SCENARIO) diff --git a/message_ix_models/tests/model/transport/test_demand.py b/message_ix_models/tests/model/transport/test_demand.py index 36faacf178..0c0720ef17 100644 --- a/message_ix_models/tests/model/transport/test_demand.py +++ b/message_ix_models/tests/model/transport/test_demand.py @@ -252,7 +252,7 @@ def test_cli(tmp_path, mix_models_cli, test_context, nodes, target): """Transport CLI can be used to generate build-phase debug outputs.""" # NB test_context is necessary so that the temporary, in-memory platform established # by .transport.workflow.generate() does not carry to other tests - cmd = ["transport", "run", f"--nodes={nodes}", f"{target} debug build", "--go"] + cmd = ["transport", "run", f"--nodes={nodes}", f"{target} T debug build", "--go"] result = mix_models_cli.assert_exit_0(cmd) # Identify the path containing the outputs diff --git a/message_ix_models/tests/model/transport/test_workflow.py b/message_ix_models/tests/model/transport/test_workflow.py index 5e1bc573f7..ab0ec74cfb 100644 --- a/message_ix_models/tests/model/transport/test_workflow.py +++ b/message_ix_models/tests/model/transport/test_workflow.py @@ -1,6 +1,6 @@ import pytest -from message_ix_models.model.transport.workflow import generate +from message_ix_models.model.transport.workflow import SOLVE_CONFIG, generate from message_ix_models.project.digsy.structure import SCENARIO as DIGSY from message_ix_models.project.edits.structure import SCENARIO as EDITS @@ -22,6 +22,13 @@ def test_generate(test_context, base_scenario) -> None: # Workflow is generated wf = generate(test_context, base_scenario=base_scenario) + # SOLVE_CONFIG is stored to be used for "… solve" steps + ctx = wf.graph["context"] + assert ctx.solve == SOLVE_CONFIG + + # The default reporting key is set to "transport all" + assert "transport all" == ctx.report.key + # Workflow contains some expected steps assert "EDITS-HA reported" in wf assert "LED-SSP1 reported" in wf @@ -31,12 +38,9 @@ def test_generate(test_context, base_scenario) -> None: assert "SSP5 exo price 5cab reported" in wf # WorkflowStep objects store expected configuration for certain projects - assert ( - DIGSY["BEST-C"] - is wf.graph["DIGSY-BEST-C built"][0].kwargs["config"].project["DIGSY"] - ) - assert ( - EDITS["HA"] is wf.graph["EDITS-HA built"][0].kwargs["config"].project["EDITS"] - ) + step = wf.graph["DIGSY-BEST-C T built"][0] + assert DIGSY["BEST-C"] is step.kwargs["config"].project["DIGSY"] + step = wf.graph["EDITS-HA T built"][0] + assert EDITS["HA"] is step.kwargs["config"].project["EDITS"] # wf.run("LED-SSP1 reported") # NB Only works with base_scenario="bare" From f69a0fd84b3b27a14df840c75195f3f643e8edcb Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Wed, 28 Jan 2026 23:19:06 +0100 Subject: [PATCH 18/73] Add .circeular.workflow.generate() - Generate from the CircEUlar scenarios codelist. - Add `mix-models circeular run` CLI. - Add test. --- message_ix_models/project/circeular/cli.py | 11 +++++++++ .../project/circeular/workflow.py | 23 +++++++++++++++++++ .../tests/project/circeular/test_workflow.py | 10 ++++++++ 3 files changed, 44 insertions(+) create mode 100644 message_ix_models/project/circeular/workflow.py create mode 100644 message_ix_models/tests/project/circeular/test_workflow.py diff --git a/message_ix_models/project/circeular/cli.py b/message_ix_models/project/circeular/cli.py index 44d128f24f..889e345116 100644 --- a/message_ix_models/project/circeular/cli.py +++ b/message_ix_models/project/circeular/cli.py @@ -1,5 +1,7 @@ import click +from message_ix_models.workflow import make_click_command + @click.group("circeular") def cli(): @@ -7,3 +9,12 @@ def cli(): https://docs.messageix.org/projects/models/en/latest/project/circeular.html """ + + +cli.add_command( + make_click_command( + f"{__package__}.workflow.generate", + name="CircEUlar", + slug="circeular", + ) +) diff --git a/message_ix_models/project/circeular/workflow.py b/message_ix_models/project/circeular/workflow.py new file mode 100644 index 0000000000..0643471b64 --- /dev/null +++ b/message_ix_models/project/circeular/workflow.py @@ -0,0 +1,23 @@ +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from message_ix_models.util.context import Context + from message_ix_models.workflow import Workflow + + +def generate( + context: "Context", *, report_key: str = "transport_all", **options +) -> "Workflow": + """Generate the CircEUlar scenario workflow.""" + from message_ix_models.model.transport.workflow import SOLVE_CONFIG + from message_ix_models.model.workflow import from_codelist + + from .structure import CL_TRANSPORT_SCENARIO + + # Set the default .report.Config key for ".* reported" steps + context.report.key = report_key + + # Set options for solving + context.solve = SOLVE_CONFIG + + return from_codelist(context, CL_TRANSPORT_SCENARIO) diff --git a/message_ix_models/tests/project/circeular/test_workflow.py b/message_ix_models/tests/project/circeular/test_workflow.py new file mode 100644 index 0000000000..83916aa60e --- /dev/null +++ b/message_ix_models/tests/project/circeular/test_workflow.py @@ -0,0 +1,10 @@ +from message_ix_models import Context +from message_ix_models.model.workflow import from_codelist +from message_ix_models.project.circeular.workflow import generate + + +@from_codelist.minimum_version +def test_generate(test_context: Context) -> None: + wf = generate(test_context) + # TODO Expand with additional assertions + del wf From dd0954023e2b658e6522be94253b1cbc3d21d9f5 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Mon, 9 Feb 2026 09:05:45 +0100 Subject: [PATCH 19/73] Continue on failed import in .cli.submodules --- message_ix_models/cli.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/message_ix_models/cli.py b/message_ix_models/cli.py index 5e0e104e6c..335246752c 100644 --- a/message_ix_models/cli.py +++ b/message_ix_models/cli.py @@ -206,7 +206,9 @@ def _log_threads(k: int, n: int): try: __import__(name) except ImportError as e: - print(e) + print(f"{name} not available: {e}") + continue + cmd = getattr(sys.modules[name], "cli") # Avoid replacing message-ix-models CLI with message_data CLI From da2f4d5d5610cc6df067e31b09950f3152622c47 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Mon, 9 Feb 2026 09:08:18 +0100 Subject: [PATCH 20/73] Don't import genno.testing in .transport.operator --- message_ix_models/model/transport/operator.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/message_ix_models/model/transport/operator.py b/message_ix_models/model/transport/operator.py index 82b19ca1dd..3095ca8f0a 100644 --- a/message_ix_models/model/transport/operator.py +++ b/message_ix_models/model/transport/operator.py @@ -14,7 +14,6 @@ import xarray as xr from genno import Computer, Key, Operator, quote from genno.operator import apply_units, as_quantity, rename_dims -from genno.testing import assert_qty_allclose, assert_units from scipy import integrate from sdmx.model.common import Code, Codelist @@ -145,6 +144,7 @@ def base_shares( def broadcast_advance(data: "AnyQuantity", y0: int, config: dict) -> "AnyQuantity": """Broadcast ADVANCE `data` from native `n` coords to :py:`config["regions"]`.""" from genno.operator import sum + from genno.testing import assert_qty_allclose assert "R12" == config["regions"], "ADVANCE data mapping only for R12 regions" @@ -1152,7 +1152,7 @@ def votm(gdp_ppp_cap: "AnyQuantity") -> "AnyQuantity": from genno.operator import assign_units u = gdp_ppp_cap.units - assert_units(gdp_ppp_cap, "kUSD / passenger / year") + # assert_units(gdp_ppp_cap, "kUSD / passenger / year") # DEBUG n = gdp_ppp_cap.coords["n"].data result = 1 / ( @@ -1164,7 +1164,7 @@ def votm(gdp_ppp_cap: "AnyQuantity") -> "AnyQuantity": units="", ) ) - assert_units(result, "") + result.units == "dimensionless" return result From 745da8c79418fd4bcb6496ff685a0b294d04d29f Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Mon, 9 Feb 2026 09:20:00 +0100 Subject: [PATCH 21/73] Add "genno[graphviz]" to "transport" dependencies --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 932c271f4f..f911d76bd2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -87,6 +87,7 @@ tests = [ "gamsapi > 47.6.0", ] transport = [ + "genno[graphviz]", "message-ix-models[iea-web,report]", "requests-cache", "transport-energy", From 27487a3c50a877e3c32518e624d8d5a224cc77d9 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Mon, 16 Feb 2026 12:18:03 +0100 Subject: [PATCH 22/73] Add "ntnu-vmi-tech" annotations for LDV techs --- message_ix_models/data/transport/technology.yaml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/message_ix_models/data/transport/technology.yaml b/message_ix_models/data/transport/technology.yaml index 340d454c21..e2dc20f506 100644 --- a/message_ix_models/data/transport/technology.yaml +++ b/message_ix_models/data/transport/technology.yaml @@ -33,6 +33,7 @@ ELC_100: report: BEV input: {commodity: electr} message-v-report: LDV_ELE + ntnu-vmi-technology: BEV gfei-2017-technology: Electric HFC_ptrp: @@ -40,6 +41,7 @@ HFC_ptrp: description: Hybridized fuel cell light-duty vehicle using hydrogen input: {commodity: hydrogen} message-v-report: LDV_HFC + ntnu-vmi-technology: ICE gfei-2017-technology: Hydrogen IAHe_ptrp: @@ -48,6 +50,7 @@ IAHe_ptrp: Hybridized internal combustion engine light-duty vehicle using biofuels input: {commodity: ethanol} message-v-report: LDV_EHYB + ntnu-vmi-technology: ICE IAHm_ptrp: report: Methanol hybrid @@ -56,6 +59,7 @@ IAHm_ptrp: synthetic fossil liquids input: {commodity: methanol} message-v-report: LDV_MHYB + ntnu-vmi-technology: ICE ICAe_ffv: report: Biofuel ICEV @@ -66,6 +70,7 @@ ICAe_ffv: ethanol and lightoil, this technology uses only ethanol. input: {commodity: ethanol} message-v-report: LDV_ffv + ntnu-vmi-technology: ICE gfei-2017-technology: Diesel ICAm_ptrp: @@ -75,6 +80,7 @@ ICAm_ptrp: fossil liquids input: {commodity: methanol} message-v-report: LDV_meth + ntnu-vmi-technology: ICE gfei-2017-technology: Flexfuel ICE_conv: @@ -84,6 +90,7 @@ ICE_conv: light-duty vehicle using gasoline/diesel input: {commodity: lightoil} message-v-report: LDV_conv + ntnu-vmi-technology: ICE gfei-2017-technology: Petrol ICE_L_ptrp: @@ -94,6 +101,7 @@ ICE_L_ptrp: input: {commodity: lightoil} historical-only: True message-v-report: LDV_ICE_L + ntnu-vmi-technology: ICE ICE_nga: report: Gas ICEV @@ -102,6 +110,7 @@ ICE_nga: input: {commodity: gas} message-v-report: LDV_NGA gfei-2017-technology: [CNG, LPG] + ntnu-vmi-technology: ICE ICH_chyb: report: Hybrid @@ -110,6 +119,7 @@ ICH_chyb: gasoline/diesel input: {commodity: lightoil} message-v-report: LDV_CHYB + ntnu-vmi-technology: ICE gfei-2017-technology: Hybrid IGH_ghyb: @@ -118,6 +128,7 @@ IGH_ghyb: Hybridized internal combustion engine light-duty vehicle using natural gas input: {commodity: gas} message-v-report: LDV_GHYB + ntnu-vmi-technology: ICE PHEV_ptrp: report: PHEV @@ -126,6 +137,7 @@ PHEV_ptrp: all-electric range) input: {commodity: [electr, lightoil]} message-v-report: LDV_PHEV + ntnu-vmi-technology: PHEV gfei-2017-technology: Plug-in ICE_H_moto: From 2d7538b3ee55f662df928c51298c12e8089af763 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Mon, 16 Feb 2026 12:19:20 +0100 Subject: [PATCH 23/73] =?UTF-8?q?Adjust=20transport=E2=80=A6test=5Fdebug?= =?UTF-8?q?=20for=20#471?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Adjust condition for material build tests to enable. - Add check of demand quantity. - Remove XFAIL mark on test_debug case with extra_modules=["material"]. --- message_ix_models/model/transport/check.py | 8 +++++++- message_ix_models/tests/model/transport/test_build.py | 7 +------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/message_ix_models/model/transport/check.py b/message_ix_models/model/transport/check.py index 8414b81eb3..7938d59bb0 100644 --- a/message_ix_models/model/transport/check.py +++ b/message_ix_models/model/transport/check.py @@ -272,11 +272,17 @@ def run(self, obj): ), ) }, - 'context.transport.modules == "FOO"': { + '"material" in context.transport.modules': { material.TARGET: ( ContainsDataForParameters({"demand", "input_cap_new", "output_cap_ret"}), NoDuplicates(), ), + # This key/quantity is the computed total demand for materials for transport + # vehicles. The adjusted `demand` values that actually enter the model cannot + # be computed without dummy or real data in the base scenario used for testing. + "demand:c-h-l-n-y:base+MT+1": ( + HasCoords({"commodity": ["aluminum", "steel"]}), + ), }, } diff --git a/message_ix_models/tests/model/transport/test_build.py b/message_ix_models/tests/model/transport/test_build.py index 216dee5f48..627db00d4b 100644 --- a/message_ix_models/tests/model/transport/test_build.py +++ b/message_ix_models/tests/model/transport/test_build.py @@ -143,12 +143,7 @@ def test_bare_res( ("R12", "B", dict(code="LED-SSP2")), ("R12", "B", dict(code="EDITS-CA")), ("R12", "B", dict(code="DIGSY-BEST-C")), - pytest.param( - "R12", - "B", - dict(code="SSP2", extra_modules=["material"]), - marks=pytest.mark.xfail(raises=NotImplementedError), - ), + pytest.param("R12", "B", dict(code="SSP2", extra_modules=["material"])), # param("R14", "B", {}, marks=MARK[9]), # param("ISR", "A", {}, marks=MARK[3]), ), From e414903dceff551258f1ffa7a45a8c419f8d9a7c Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Mon, 16 Feb 2026 12:20:03 +0100 Subject: [PATCH 24/73] =?UTF-8?q?Add=20n=E2=86=92node,=20y=E2=86=92year=20?= =?UTF-8?q?to=20.transport.util.DIMS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- message_ix_models/model/transport/util.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/message_ix_models/model/transport/util.py b/message_ix_models/model/transport/util.py index 9547697bd7..fb041b9f44 100644 --- a/message_ix_models/model/transport/util.py +++ b/message_ix_models/model/transport/util.py @@ -22,7 +22,9 @@ #: Mapping from :mod:`message_ix` parameter dimensions to source dimensions in some #: quantities. DIMS = dict( + node="n", node_loc="nl", + year="y", year_vtg="yv", year_act="ya", technology="t", From 449a59ca0b7630b5918faf62fc3abebf8f092282 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Mon, 16 Feb 2026 12:22:05 +0100 Subject: [PATCH 25/73] Add .transport.material.get_groups() - Retrieve technology mapping from technology.yaml annotations. - Remove TECHNOLOGY local mapping. - Remove structure logic from prepare_computer(). - Add test of get_groups(). --- message_ix_models/model/transport/material.py | 71 ++++++++++--------- .../tests/model/transport/test_material.py | 15 ++++ 2 files changed, 54 insertions(+), 32 deletions(-) create mode 100644 message_ix_models/tests/model/transport/test_material.py diff --git a/message_ix_models/model/transport/material.py b/message_ix_models/model/transport/material.py index bec6350cd6..346d6619a9 100644 --- a/message_ix_models/model/transport/material.py +++ b/message_ix_models/model/transport/material.py @@ -23,6 +23,8 @@ if TYPE_CHECKING: from genno import Computer + from .config import Config + #: Target key that collects all data generated in this module. TARGET = "transport::material+ixmp" @@ -65,25 +67,6 @@ #: .. todo:: Retrieve from a file. OUTPUT_SHARE = 0.8 -#: Mapping from values appearing in :data:`.input_cap_new` to MESSAGEix-Transport -#: technology IDs. -#: -#: .. todo:: Read this from a configuration file instead of hard-coding. -TECHNOLOGY = { - "BEV": {"ELC_100"}, - "ICE": { - "IAHe_ptrp", - "IAHm_ptrp", - "ICAe_ptrp", - "ICE_conv", - "ICE_nga", - "ICEm_ptrp", - "ICH_chyb", - "IGH_ghyb", - }, - "PHEV": {"PHEV_ptrp"}, -} - # Keyword arguments for as_message_df() for different parameters _DEMAND_KW = dict(name="demand", dims=DIMS, common=dict()) _ICN_KW = dict( @@ -94,8 +77,43 @@ ) +def get_groups(config: "Config") -> dict[str, dict[str, list[str]]]: + """Return groups for a :func:`~genno.operator.aggregate` operation on NTNU VMI data. + + These include: + + - ``c`` (commodity) dimension: 1 or more original (NTNU VMI) commodity IDs + aggregated to :mod:`.model.material` commodity IDs. + - ``t`` (technology) dimension: 1:1 from original (NTNU VMI) technology IDs to + :mod:`.model.transport` technology IDs. This effects rename and broadcast + operations simultaneously. + """ + + # Aggregate ≥1 original commodity IDs into .model.material commodity IDs + c_groups = defaultdict(list) + for c_original, c_model in COMMODITY_INFO.items(): + c_groups[c_model].append(c_original) + + # Retrieve all codes for LDV technologies + t_all = config.spec.add.set["technology"] + t_LDV = t_all[t_all.index("LDV")].child + + # Aggregate each original technology ID into 1 or more 'groups' of length 1 + # (this is equivalent to a broadcast operation) + t_groups = {} + for t_model in t_LDV: + t_groups[t_model.id] = [ + str(t_model.get_annotation(id="ntnu-vmi-technology").text) + ] + + return dict(c=c_groups, t=t_groups) + + def prepare_computer(c: "Computer") -> None: """Prepare `c` to calculate and add data for materiality of transport.""" + # Retrieve transport configuration + config = c.graph["context"].transport + # Collect data in `TARGET` and connect to the "add transport data" key collect.computer = c c.add("transport_data", __name__, key=TARGET) @@ -114,19 +132,8 @@ def prepare_computer(c: "Computer") -> None: indexers = dict(scenario="_CT_C_D_D") c.add(k.exo[0], "select", key.exo.input_cap_new, indexers=indexers) - # Aggregate ≥1 original commodity IDs into .model.material commodity IDs - c_groups = defaultdict(list) - for c_original, c_model in COMMODITY_INFO.items(): - c_groups[c_model].append(c_original) - # Aggregate each original technology ID into 1 or more 'groups' of length 1 - # (this is equivalent to a broadcast operation) - t_groups = {} - for t_original, t_model in TECHNOLOGY.items(): - t_groups.update({t: [t_original] for t in t_model}) - - c.add( - k.exo[1], "aggregate", k.exo[0], groups=dict(c=c_groups, t=t_groups), keep=False - ) + # Transform VMI data labels to MESSAGE -MT- labels + c.add(k.exo[1], "aggregate", k.exo[0], groups=get_groups(config), keep=False) # Convert units: (material commodities [Mt]) / (transport CAP/CAP_NEW [Mvehicle]) c.add(k.exo[2], "convert_units", k.exo[1], units="Mt / Mvehicle") diff --git a/message_ix_models/tests/model/transport/test_material.py b/message_ix_models/tests/model/transport/test_material.py new file mode 100644 index 0000000000..832f344e8f --- /dev/null +++ b/message_ix_models/tests/model/transport/test_material.py @@ -0,0 +1,15 @@ +from message_ix_models import Context +from message_ix_models.model.transport import Config +from message_ix_models.model.transport.material import get_groups + + +def test_get_groups(test_context: Context) -> None: + # Prepare a Config instance + cfg = Config.from_context(test_context) + + # Function runs without error + result = get_groups(cfg) + + # Does not contain mispellings of the technologies in technology.yaml + assert "ICAe_ptrp" not in result["t"] + assert "ICEm_ptrp" not in result["t"] From 51a443b2938a57d190295453cfe885ef84b3adae Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Mon, 16 Feb 2026 12:22:23 +0100 Subject: [PATCH 26/73] Use .util.DIMS in .transport.material --- message_ix_models/model/transport/material.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/message_ix_models/model/transport/material.py b/message_ix_models/model/transport/material.py index 346d6619a9..cd69583fc4 100644 --- a/message_ix_models/model/transport/material.py +++ b/message_ix_models/model/transport/material.py @@ -68,7 +68,7 @@ OUTPUT_SHARE = 0.8 # Keyword arguments for as_message_df() for different parameters -_DEMAND_KW = dict(name="demand", dims=DIMS, common=dict()) +_DEMAND_KW = dict(name="demand", dims=util.DIMS, common=util.COMMON) _ICN_KW = dict( name="input_cap_new", dims=DIMS, common=util.COMMON | dict(level="demand") ) From cdb430a44473c45c1b5114b5553919d3a28a07cc Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Mon, 16 Feb 2026 19:01:58 +0100 Subject: [PATCH 27/73] Add .testing.check.InRange --- message_ix_models/testing/check.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/message_ix_models/testing/check.py b/message_ix_models/testing/check.py index 18cccb343d..0242a2d7ce 100644 --- a/message_ix_models/testing/check.py +++ b/message_ix_models/testing/check.py @@ -10,6 +10,7 @@ from typing import TYPE_CHECKING, ClassVar, TypeVar import genno +import numpy as np import pandas as pd if TYPE_CHECKING: @@ -240,6 +241,35 @@ def run(self, obj): return True, f"Units are {self.units!r}" +@dataclass +class InRange(Check): + """Values are in expected range.""" + + #: Minimum value, if any. + min: float = -np.inf + + #: Maximum value, if any. + max: float = np.inf + + #: Absolute tolerance. + atol: float = 1e-8 + + types = (genno.Quantity,) + + def run(self, obj): + data = obj.to_series().rename("value").reset_index() + + result = data["value"] < (self.min - self.atol) + if result.any(axis=None): + return False, f"Values <{self.min} for {result.sum()} observations" + + result = data["value"] > (self.max + self.atol) + if result.any(axis=None): + return False, f"Values >{self.max} for {result.sum()} observations" + + return True, self._description + + @dataclass class NoDuplicates(Check): """No duplicate indices in parameter data.""" From 482c0811efb50cac7b32ad5a7aecd7c5731a4fb7 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Mon, 16 Feb 2026 19:02:37 +0100 Subject: [PATCH 28/73] Add range of material share to transport checks --- message_ix_models/model/transport/check.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/message_ix_models/model/transport/check.py b/message_ix_models/model/transport/check.py index 7938d59bb0..d06492918d 100644 --- a/message_ix_models/model/transport/check.py +++ b/message_ix_models/model/transport/check.py @@ -20,6 +20,7 @@ ContainsDataForParameters, HasCoords, HasUnits, + InRange, NoDuplicates, NoneMissing, NonNegative, @@ -277,12 +278,12 @@ def run(self, obj): ContainsDataForParameters({"demand", "input_cap_new", "output_cap_ret"}), NoDuplicates(), ), + # Share of non-transport demand in the total must be in the range (0.2, 1.0) + "demand:c-h-l-n-y:MT+share": (InRange(min=0.2, max=1.0),), # This key/quantity is the computed total demand for materials for transport # vehicles. The adjusted `demand` values that actually enter the model cannot # be computed without dummy or real data in the base scenario used for testing. - "demand:c-h-l-n-y:base+MT+1": ( - HasCoords({"commodity": ["aluminum", "steel"]}), - ), + "demand:c-h-l-n-y:MT+1": (HasCoords({"commodity": ["aluminum", "steel"]}),), }, } From 4e2f08b546220285d475abf44cf1e05a1e7921ef Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Mon, 16 Feb 2026 19:06:29 +0100 Subject: [PATCH 29/73] Add .transport.testing.prepare_computer() - Add a test data file with material demand data from an existing scenario. --- .../demand.csv | 344 ++++++++++++++++++ message_ix_models/model/transport/testing.py | 32 +- 2 files changed, 374 insertions(+), 2 deletions(-) create mode 100644 message_ix_models/data/test/transport/MESSAGEix-GLOBIOM_2.2-BMT-R12_baseline_BM_20260216/demand.csv diff --git a/message_ix_models/data/test/transport/MESSAGEix-GLOBIOM_2.2-BMT-R12_baseline_BM_20260216/demand.csv b/message_ix_models/data/test/transport/MESSAGEix-GLOBIOM_2.2-BMT-R12_baseline_BM_20260216/demand.csv new file mode 100644 index 0000000000..290d28de5b --- /dev/null +++ b/message_ix_models/data/test/transport/MESSAGEix-GLOBIOM_2.2-BMT-R12_baseline_BM_20260216/demand.csv @@ -0,0 +1,344 @@ +# Test data from ixmp://ixmp-dev/MESSAGEix-GLOBIOM 2.2-BMT-R12/baseline_BM_20260216 +# +# The units given below match what appears in the database, +# but are likely incorrect and should instead be "Mt". +# +# Units: t +# +node,commodity,level,year,time,value +R12_AFR,steel,demand,2020,year,14.49368 +R12_AFR,steel,demand,2025,year,14.49368 +R12_AFR,steel,demand,2030,year,14.168 +R12_AFR,steel,demand,2035,year,40.0476 +R12_AFR,steel,demand,2040,year,60.6188 +R12_AFR,steel,demand,2045,year,99.2404 +R12_AFR,steel,demand,2050,year,142.7288 +R12_AFR,steel,demand,2055,year,211.9128 +R12_AFR,steel,demand,2060,year,279.6892 +R12_AFR,steel,demand,2070,year,433.78 +R12_AFR,steel,demand,2080,year,571.642 +R12_AFR,steel,demand,2090,year,694.83 +R12_AFR,steel,demand,2100,year,809.3884 +R12_AFR,steel,demand,2110,year,809.3884 +R12_AFR,aluminum,demand,2020,year,2.74966163484653 +R12_AFR,aluminum,demand,2025,year,3.39049440411999 +R12_AFR,aluminum,demand,2030,year,3.41432097024767 +R12_AFR,aluminum,demand,2035,year,3.51178337969508 +R12_AFR,aluminum,demand,2040,year,3.38434379431125 +R12_AFR,aluminum,demand,2045,year,3.28217843644309 +R12_AFR,aluminum,demand,2050,year,3.60055188392637 +R12_AFR,aluminum,demand,2055,year,4.76576841711365 +R12_AFR,aluminum,demand,2060,year,7.16875878523775 +R12_AFR,aluminum,demand,2070,year,16.7613672539 +R12_AFR,aluminum,demand,2080,year,32.8023109318924 +R12_AFR,aluminum,demand,2090,year,53.3163478692439 +R12_AFR,aluminum,demand,2100,year,75.2367919962744 +R12_AFR,aluminum,demand,2110,year,98.6684059858436 +R12_EEU,steel,demand,2020,year,31.5441 +R12_EEU,steel,demand,2025,year,31.581 +R12_EEU,steel,demand,2030,year,31.581 +R12_EEU,steel,demand,2035,year,33.273 +R12_EEU,steel,demand,2040,year,32.904 +R12_EEU,steel,demand,2045,year,32.121 +R12_EEU,steel,demand,2050,year,31.734 +R12_EEU,steel,demand,2055,year,31.428 +R12_EEU,steel,demand,2060,year,31.131 +R12_EEU,steel,demand,2070,year,30.375 +R12_EEU,steel,demand,2080,year,29.214 +R12_EEU,steel,demand,2090,year,28.278 +R12_EEU,steel,demand,2100,year,27.342 +R12_EEU,steel,demand,2110,year,27.342 +R12_EEU,aluminum,demand,2020,year,5.29958883267973 +R12_EEU,aluminum,demand,2025,year,5.70400458763263 +R12_EEU,aluminum,demand,2030,year,5.92103375295703 +R12_EEU,aluminum,demand,2035,year,5.80242182184509 +R12_EEU,aluminum,demand,2040,year,5.42254445250959 +R12_EEU,aluminum,demand,2045,year,4.9400532365558 +R12_EEU,aluminum,demand,2050,year,4.51164775816695 +R12_EEU,aluminum,demand,2055,year,4.19130522730181 +R12_EEU,aluminum,demand,2060,year,3.9751416672614 +R12_EEU,aluminum,demand,2070,year,3.74160922815117 +R12_EEU,aluminum,demand,2080,year,3.62090055037246 +R12_EEU,aluminum,demand,2090,year,3.55120420501844 +R12_EEU,aluminum,demand,2100,year,3.50766119964727 +R12_EEU,aluminum,demand,2110,year,3.46617192256995 +R12_LAM,steel,demand,2020,year,53.3763 +R12_LAM,steel,demand,2025,year,64.8 +R12_LAM,steel,demand,2030,year,72.792 +R12_LAM,steel,demand,2035,year,110.844 +R12_LAM,steel,demand,2040,year,136.827 +R12_LAM,steel,demand,2045,year,157.284 +R12_LAM,steel,demand,2050,year,176.544 +R12_LAM,steel,demand,2055,year,189.603 +R12_LAM,steel,demand,2060,year,201.294 +R12_LAM,steel,demand,2070,year,216.945 +R12_LAM,steel,demand,2080,year,224.001 +R12_LAM,steel,demand,2090,year,225.567 +R12_LAM,steel,demand,2100,year,223.056 +R12_LAM,steel,demand,2110,year,223.056 +R12_LAM,aluminum,demand,2020,year,2.60008440679671 +R12_LAM,aluminum,demand,2025,year,3.92917152614197 +R12_LAM,aluminum,demand,2030,year,5.30490819218595 +R12_LAM,aluminum,demand,2035,year,7.03144119919714 +R12_LAM,aluminum,demand,2040,year,9.15178266439931 +R12_LAM,aluminum,demand,2045,year,11.516278985294 +R12_LAM,aluminum,demand,2050,year,13.9459142267265 +R12_LAM,aluminum,demand,2055,year,16.3197494580619 +R12_LAM,aluminum,demand,2060,year,18.5466518180047 +R12_LAM,aluminum,demand,2070,year,22.4244441980128 +R12_LAM,aluminum,demand,2080,year,25.2866993755641 +R12_LAM,aluminum,demand,2090,year,27.1575871272148 +R12_LAM,aluminum,demand,2100,year,28.2673397105002 +R12_LAM,aluminum,demand,2110,year,29.0787484203409 +R12_MEA,steel,demand,2020,year,62.10828 +R12_MEA,steel,demand,2025,year,69 +R12_MEA,steel,demand,2030,year,77.7676 +R12_MEA,steel,demand,2035,year,112.5252 +R12_MEA,steel,demand,2040,year,140.1528 +R12_MEA,steel,demand,2045,year,162.0672 +R12_MEA,steel,demand,2050,year,185.9964 +R12_MEA,steel,demand,2055,year,204.9668 +R12_MEA,steel,demand,2060,year,224.8664 +R12_MEA,steel,demand,2070,year,254.104 +R12_MEA,steel,demand,2080,year,273.5252 +R12_MEA,steel,demand,2090,year,287.2792 +R12_MEA,steel,demand,2100,year,296.608 +R12_MEA,steel,demand,2110,year,296.608 +R12_MEA,aluminum,demand,2020,year,2.20039765674893 +R12_MEA,aluminum,demand,2025,year,3.46029608341049 +R12_MEA,aluminum,demand,2030,year,5.32742950075796 +R12_MEA,aluminum,demand,2035,year,7.67515454314301 +R12_MEA,aluminum,demand,2040,year,10.5536676757249 +R12_MEA,aluminum,demand,2045,year,13.6862647160816 +R12_MEA,aluminum,demand,2050,year,16.8520671365669 +R12_MEA,aluminum,demand,2055,year,19.9461908209164 +R12_MEA,aluminum,demand,2060,year,22.9020664204434 +R12_MEA,aluminum,demand,2070,year,28.1280742717591 +R12_MEA,aluminum,demand,2080,year,32.2654669819869 +R12_MEA,aluminum,demand,2090,year,35.5083941226939 +R12_MEA,aluminum,demand,2100,year,37.9704898966942 +R12_MEA,aluminum,demand,2110,year,40.2048364191876 +R12_NAM,steel,demand,2020,year,78.71935 +R12_NAM,steel,demand,2025,year,93.5 +R12_NAM,steel,demand,2030,year,96.9935 +R12_NAM,steel,demand,2035,year,104.55 +R12_NAM,steel,demand,2040,year,111.503 +R12_NAM,steel,demand,2045,year,117.64 +R12_NAM,steel,demand,2050,year,123.2415 +R12_NAM,steel,demand,2055,year,127.976 +R12_NAM,steel,demand,2060,year,132.039 +R12_NAM,steel,demand,2070,year,138.0995 +R12_NAM,steel,demand,2080,year,141.814 +R12_NAM,steel,demand,2090,year,143.99 +R12_NAM,steel,demand,2100,year,145.1375 +R12_NAM,steel,demand,2110,year,145.1375 +R12_NAM,aluminum,demand,2020,year,13.9999285342406 +R12_NAM,aluminum,demand,2025,year,15.1611473921284 +R12_NAM,aluminum,demand,2030,year,16.0202992789882 +R12_NAM,aluminum,demand,2035,year,16.7378030570288 +R12_NAM,aluminum,demand,2040,year,17.3449987646736 +R12_NAM,aluminum,demand,2045,year,17.8830906060463 +R12_NAM,aluminum,demand,2050,year,18.3935596634726 +R12_NAM,aluminum,demand,2055,year,18.8842043489018 +R12_NAM,aluminum,demand,2060,year,19.3807008617894 +R12_NAM,aluminum,demand,2070,year,20.3667641918489 +R12_NAM,aluminum,demand,2080,year,21.2146240419358 +R12_NAM,aluminum,demand,2090,year,21.8083485334632 +R12_NAM,aluminum,demand,2100,year,22.1839536188971 +R12_NAM,aluminum,demand,2110,year,22.5350499390702 +R12_SAS,steel,demand,2020,year,94.28344 +R12_SAS,steel,demand,2025,year,142.6 +R12_SAS,steel,demand,2030,year,161.6256 +R12_SAS,steel,demand,2035,year,297.9604 +R12_SAS,steel,demand,2040,year,384.1736 +R12_SAS,steel,demand,2045,year,443.348 +R12_SAS,steel,demand,2050,year,515.1908 +R12_SAS,steel,demand,2055,year,553.4168 +R12_SAS,steel,demand,2060,year,606.9516 +R12_SAS,steel,demand,2070,year,670.0728 +R12_SAS,steel,demand,2080,year,703.5332 +R12_SAS,steel,demand,2090,year,720.4612 +R12_SAS,steel,demand,2100,year,727.2876 +R12_SAS,steel,demand,2110,year,727.2876 +R12_SAS,aluminum,demand,2020,year,4.79947232521726 +R12_SAS,aluminum,demand,2025,year,6.40069200339453 +R12_SAS,aluminum,demand,2030,year,9.27976550971231 +R12_SAS,aluminum,demand,2035,year,13.2007558091847 +R12_SAS,aluminum,demand,2040,year,17.9586864995716 +R12_SAS,aluminum,demand,2045,year,23.5685113474604 +R12_SAS,aluminum,demand,2050,year,29.9989251698545 +R12_SAS,aluminum,demand,2055,year,37.0932479549381 +R12_SAS,aluminum,demand,2060,year,44.539458618742 +R12_SAS,aluminum,demand,2070,year,59.0051971467932 +R12_SAS,aluminum,demand,2080,year,71.0098930875013 +R12_SAS,aluminum,demand,2090,year,79.7267876373874 +R12_SAS,aluminum,demand,2100,year,85.6516923330805 +R12_SAS,aluminum,demand,2110,year,90.6121694091066 +R12_WEU,steel,demand,2020,year,117.09345 +R12_WEU,steel,demand,2025,year,131.75 +R12_WEU,steel,demand,2030,year,135.0735 +R12_WEU,steel,demand,2035,year,144.9675 +R12_WEU,steel,demand,2040,year,152.0565 +R12_WEU,steel,demand,2045,year,158.8565 +R12_WEU,steel,demand,2050,year,163.9565 +R12_WEU,steel,demand,2055,year,168.096 +R12_WEU,steel,demand,2060,year,170.833 +R12_WEU,steel,demand,2070,year,174.1055 +R12_WEU,steel,demand,2080,year,173.6295 +R12_WEU,steel,demand,2090,year,172.5585 +R12_WEU,steel,demand,2100,year,169.7025 +R12_WEU,steel,demand,2110,year,169.7025 +R12_WEU,aluminum,demand,2020,year,6.00085662437608 +R12_WEU,aluminum,demand,2025,year,7.67868025548736 +R12_WEU,aluminum,demand,2030,year,8.90760758538225 +R12_WEU,aluminum,demand,2035,year,10.5585893455211 +R12_WEU,aluminum,demand,2040,year,12.6359050084323 +R12_WEU,aluminum,demand,2045,year,14.8249264771741 +R12_WEU,aluminum,demand,2050,year,16.8045739967204 +R12_WEU,aluminum,demand,2055,year,18.4306387862293 +R12_WEU,aluminum,demand,2060,year,19.7074850014359 +R12_WEU,aluminum,demand,2070,year,21.4244111961004 +R12_WEU,aluminum,demand,2080,year,22.4178748483023 +R12_WEU,aluminum,demand,2090,year,22.9586736624652 +R12_WEU,aluminum,demand,2100,year,23.1642851702228 +R12_WEU,aluminum,demand,2110,year,23.3185561174193 +R12_FSU,steel,demand,2020,year,49.9392 +R12_FSU,steel,demand,2025,year,49.995 +R12_FSU,steel,demand,2030,year,51.489 +R12_FSU,steel,demand,2035,year,65.079 +R12_FSU,steel,demand,2040,year,69.777 +R12_FSU,steel,demand,2045,year,72.216 +R12_FSU,steel,demand,2050,year,76.446 +R12_FSU,steel,demand,2055,year,80.217 +R12_FSU,steel,demand,2060,year,84.312 +R12_FSU,steel,demand,2070,year,89.856 +R12_FSU,steel,demand,2080,year,92.781 +R12_FSU,steel,demand,2090,year,95.337 +R12_FSU,steel,demand,2100,year,96.516 +R12_FSU,steel,demand,2110,year,96.516 +R12_FSU,aluminum,demand,2020,year,4.84968756775019 +R12_FSU,aluminum,demand,2025,year,5.41748507334742 +R12_FSU,aluminum,demand,2030,year,5.86522690591112 +R12_FSU,aluminum,demand,2035,year,6.37779265857682 +R12_FSU,aluminum,demand,2040,year,6.69823559682082 +R12_FSU,aluminum,demand,2045,year,6.91707632176842 +R12_FSU,aluminum,demand,2050,year,7.15076502209288 +R12_FSU,aluminum,demand,2055,year,7.48476010533571 +R12_FSU,aluminum,demand,2060,year,7.93657375751533 +R12_FSU,aluminum,demand,2070,year,8.97194530219384 +R12_FSU,aluminum,demand,2080,year,9.95163943219347 +R12_FSU,aluminum,demand,2090,year,10.8332440149553 +R12_FSU,aluminum,demand,2100,year,11.5717104679913 +R12_FSU,aluminum,demand,2110,year,12.2112611326823 +R12_PAO,steel,demand,2020,year,49.1113 +R12_PAO,steel,demand,2025,year,49.113 +R12_PAO,steel,demand,2030,year,48.0335 +R12_PAO,steel,demand,2035,year,47.6595 +R12_PAO,steel,demand,2040,year,46.2995 +R12_PAO,steel,demand,2045,year,45.5175 +R12_PAO,steel,demand,2050,year,44.846 +R12_PAO,steel,demand,2055,year,44.353 +R12_PAO,steel,demand,2060,year,43.826 +R12_PAO,steel,demand,2070,year,42.9165 +R12_PAO,steel,demand,2080,year,41.4375 +R12_PAO,steel,demand,2090,year,39.78 +R12_PAO,steel,demand,2100,year,38.1055 +R12_PAO,steel,demand,2110,year,38.1055 +R12_PAO,aluminum,demand,2020,year,3.60010076844248 +R12_PAO,aluminum,demand,2025,year,3.90374192259837 +R12_PAO,aluminum,demand,2030,year,4.13374454951351 +R12_PAO,aluminum,demand,2035,year,4.40267981187414 +R12_PAO,aluminum,demand,2040,year,4.68452129221248 +R12_PAO,aluminum,demand,2045,year,4.96385503268694 +R12_PAO,aluminum,demand,2050,year,5.21043415134317 +R12_PAO,aluminum,demand,2055,year,5.40472203989015 +R12_PAO,aluminum,demand,2060,year,5.54664769128425 +R12_PAO,aluminum,demand,2070,year,5.68805831363484 +R12_PAO,aluminum,demand,2080,year,5.69992072473573 +R12_PAO,aluminum,demand,2090,year,5.65775270187358 +R12_PAO,aluminum,demand,2100,year,5.55646328379756 +R12_PAO,aluminum,demand,2110,year,5.44798874180773 +R12_PAS,steel,demand,2020,year,110.1258 +R12_PAS,steel,demand,2025,year,110.1258 +R12_PAS,steel,demand,2030,year,118.224 +R12_PAS,steel,demand,2035,year,149.085 +R12_PAS,steel,demand,2040,year,166.203 +R12_PAS,steel,demand,2045,year,178.641 +R12_PAS,steel,demand,2050,year,190.287 +R12_PAS,steel,demand,2055,year,195.606 +R12_PAS,steel,demand,2060,year,202.437 +R12_PAS,steel,demand,2070,year,211.248 +R12_PAS,steel,demand,2080,year,213.858 +R12_PAS,steel,demand,2090,year,212.49 +R12_PAS,steel,demand,2100,year,207.702 +R12_PAS,steel,demand,2110,year,207.702 +R12_PAS,aluminum,demand,2020,year,4.800174208708 +R12_PAS,aluminum,demand,2025,year,6.76016645889741 +R12_PAS,aluminum,demand,2030,year,9.41828590532265 +R12_PAS,aluminum,demand,2035,year,11.7570568044041 +R12_PAS,aluminum,demand,2040,year,13.9511093553672 +R12_PAS,aluminum,demand,2045,year,15.9757156904768 +R12_PAS,aluminum,demand,2050,year,17.7855789256735 +R12_PAS,aluminum,demand,2055,year,19.4037332884306 +R12_PAS,aluminum,demand,2060,year,20.829801292015 +R12_PAS,aluminum,demand,2070,year,23.1285696767395 +R12_PAS,aluminum,demand,2080,year,24.7075352319659 +R12_PAS,aluminum,demand,2090,year,25.6561054573989 +R12_PAS,aluminum,demand,2100,year,26.0903604952366 +R12_PAS,aluminum,demand,2110,year,26.3904473346956 +R12_CHN,steel,demand,2020,year,898.3566 +R12_CHN,steel,demand,2025,year,787.5 +R12_CHN,steel,demand,2030,year,723.888 +R12_CHN,steel,demand,2035,year,666.909 +R12_CHN,steel,demand,2040,year,590.337 +R12_CHN,steel,demand,2045,year,523.53 +R12_CHN,steel,demand,2050,year,474.93 +R12_CHN,steel,demand,2055,year,434.826 +R12_CHN,steel,demand,2060,year,407.331 +R12_CHN,steel,demand,2070,year,366.957 +R12_CHN,steel,demand,2080,year,332.982 +R12_CHN,steel,demand,2090,year,304.245 +R12_CHN,steel,demand,2100,year,277.083 +R12_CHN,steel,demand,2110,year,277.083 +R12_CHN,aluminum,demand,2020,year,27.2984446468399 +R12_CHN,aluminum,demand,2025,year,34.6184960626711 +R12_CHN,aluminum,demand,2030,year,40.0382152412497 +R12_CHN,aluminum,demand,2035,year,43.4302526653914 +R12_CHN,aluminum,demand,2040,year,44.5705539541717 +R12_CHN,aluminum,demand,2045,year,44.891745615895 +R12_CHN,aluminum,demand,2050,year,44.8741194995006 +R12_CHN,aluminum,demand,2055,year,44.6289520209487 +R12_CHN,aluminum,demand,2060,year,44.3924579841476 +R12_CHN,aluminum,demand,2070,year,43.5395962580639 +R12_CHN,aluminum,demand,2080,year,41.8116672158444 +R12_CHN,aluminum,demand,2090,year,39.5520778773728 +R12_CHN,aluminum,demand,2100,year,37.1672856258216 +R12_CHN,aluminum,demand,2110,year,34.7884782867452 +R12_RCPA,steel,demand,2020,year,22.2318 +R12_RCPA,steel,demand,2025,year,22.2272 +R12_RCPA,steel,demand,2030,year,22.08 +R12_RCPA,steel,demand,2035,year,30.5348 +R12_RCPA,steel,demand,2040,year,33.0556 +R12_RCPA,steel,demand,2045,year,34.5184 +R12_RCPA,steel,demand,2050,year,36.754 +R12_RCPA,steel,demand,2055,year,38.042 +R12_RCPA,steel,demand,2060,year,40.1488 +R12_RCPA,steel,demand,2070,year,42.7248 +R12_RCPA,steel,demand,2080,year,43.976 +R12_RCPA,steel,demand,2090,year,44.5188 +R12_RCPA,steel,demand,2100,year,44.1232 +R12_RCPA,steel,demand,2110,year,44.1232 +R12_RCPA,aluminum,demand,2020,year,1.99976722146765 +R12_RCPA,aluminum,demand,2025,year,2.20976490805966 +R12_RCPA,aluminum,demand,2030,year,2.66413925860674 +R12_RCPA,aluminum,demand,2035,year,3.09977715100009 +R12_RCPA,aluminum,demand,2040,year,3.39057152208613 +R12_RCPA,aluminum,demand,2045,year,3.59199956735501 +R12_RCPA,aluminum,demand,2050,year,3.78597611505884 +R12_RCPA,aluminum,demand,2055,year,4.01968730528238 +R12_RCPA,aluminum,demand,2060,year,4.29109041933336 +R12_RCPA,aluminum,demand,2070,year,4.85905917694507 +R12_RCPA,aluminum,demand,2080,year,5.30255915385771 +R12_RCPA,aluminum,demand,2090,year,5.60469202852908 +R12_RCPA,aluminum,demand,2100,year,5.80190869285345 +R12_RCPA,aluminum,demand,2110,year,5.9488910021113 diff --git a/message_ix_models/model/transport/testing.py b/message_ix_models/model/transport/testing.py index 392d1e426c..475e423c88 100644 --- a/message_ix_models/model/transport/testing.py +++ b/message_ix_models/model/transport/testing.py @@ -15,9 +15,9 @@ from message_ix_models import ScenarioInfo, testing from message_ix_models.report.sim import add_simulated_solution from message_ix_models.testing import GHA, SOLVE_OPTIONS, bare_res -from message_ix_models.util import silence_log +from message_ix_models.util import package_data_path, silence_log -from . import build +from . import build, key from .config import CL_SCENARIO, Config if TYPE_CHECKING: @@ -181,6 +181,34 @@ def built_transport( return result +def prepare_computer(c: "Computer") -> None: + """Adjust the transport build computer `c` for tests. + + Data used by :mod:`.transport.material` is read from a file instead of the base + scenario. + """ + from ixmp.report.common import RENAME_DIMS + + context = c.graph["context"] + + if context.transport.with_scenario and context.model.regions == "R12": + # Remove existing task to load data from the base scenario + c.graph.pop(key.demand_base) + + # Replace with data from a file + c.add( + "load_file", + package_data_path( + "test", + "transport", + "MESSAGEix-GLOBIOM_2.2-BMT-R12_baseline_BM_20260216", + "demand.csv", + ), + key=key.demand_base, + dims=RENAME_DIMS, + ) + + @cache def _default_scenario_code() -> "Code": """Return a default scenario code for :meth:`.configure_build`.""" From d591f8d429e8014a1823bff234bb8c644355b5b4 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Mon, 16 Feb 2026 19:05:03 +0100 Subject: [PATCH 30/73] Improve .transport.testing.configure_build() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add argument with_base=… and prepare a bare RES scenario if it is given. - Add .transport.testing.prepare_computer() to model-building callbacks, only when testing. --- message_ix_models/model/transport/testing.py | 18 ++++++++++++------ .../tests/model/transport/test_build.py | 7 +++---- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/message_ix_models/model/transport/testing.py b/message_ix_models/model/transport/testing.py index 475e423c88..7a27e8eb29 100644 --- a/message_ix_models/model/transport/testing.py +++ b/message_ix_models/model/transport/testing.py @@ -91,14 +91,19 @@ def assert_units( def configure_build( - test_context: "Context", + context: "Context", regions: str, years: str, tmp_path: Path | None = None, + with_base: "pytest.FixtureRequest | None" = None, **kwargs, ) -> tuple["Computer", ScenarioInfo]: """:func:`.transport.build.get_computer` wrapper for testing.""" - test_context.update(regions=regions, years=years, output_path=tmp_path) + context.update(regions=regions, years=years, output_path=tmp_path) + + # Fixture: a base scenario with the given `regions` and `years` + if with_base is not None: + kwargs.setdefault("scenario", bare_res(with_base, context)) # Set defaults for some arguments to get_computer kwargs.setdefault("visualize", False) @@ -109,13 +114,14 @@ def configure_build( # Use scenario code "SSP2" options.setdefault("code", _default_scenario_code()) - # Omit plots for shorter test run times + # - Call prepare_computer() in this module to add test-specific data + # - Omit plots for shorter test run times options.setdefault("extra_modules", []) - options["extra_modules"].append("-plot") + options["extra_modules"].extend(["testing", "-plot"]) - c = build.get_computer(test_context, **kwargs) + c = build.get_computer(context, **kwargs) - return c, test_context.transport.base_model_info + return c, context.transport.base_model_info def built_transport( diff --git a/message_ix_models/tests/model/transport/test_build.py b/message_ix_models/tests/model/transport/test_build.py index 627db00d4b..1a3b8fcdad 100644 --- a/message_ix_models/tests/model/transport/test_build.py +++ b/message_ix_models/tests/model/transport/test_build.py @@ -175,10 +175,9 @@ def test_debug( Passed to :func:`.verbose_check`. """ # Get a Computer prepared to build the model with the given options - c, _ = configure_build(test_context, regions, years, tmp_path, options=options) - - # Fixture: a scenario - c.add("scenario", bare_res(request, test_context)) + c, _ = configure_build( + test_context, regions, years, tmp_path, with_base=request, options=options + ) # Insert key-specific and common checks result = check.insert(c, N_node, verbosity, tmp_path) From a6d2b4d7e8acb4718d07d7a0a1e3f73aa435d292 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Mon, 16 Feb 2026 19:08:15 +0100 Subject: [PATCH 31/73] Adjust .transport.material handling of base demand - Force units on base model material demand. - Clip transport share in the range (0, 0.8). - Change sense of k.demand["share"] to share of *non* transport. - Apply demand share to *all* periods, not only the first. --- message_ix_models/model/transport/material.py | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/message_ix_models/model/transport/material.py b/message_ix_models/model/transport/material.py index cd69583fc4..f716fa1c06 100644 --- a/message_ix_models/model/transport/material.py +++ b/message_ix_models/model/transport/material.py @@ -13,7 +13,8 @@ from collections import defaultdict from typing import TYPE_CHECKING -from genno import Keys +import genno +from genno import Key, Keys from genno.core.key import single_key from message_ix_models.util.genno import Collector @@ -27,9 +28,9 @@ #: Target key that collects all data generated in this module. -TARGET = "transport::material+ixmp" +TARGET = "transport::MT+ixmp" -collect = Collector(TARGET, "{}::material+ixmp".format) +collect = Collector(TARGET, "{}::MT+ixmp".format) # FIXME Do not hard-code this. Instead, use 1 or more of: # - Labels in input_cap_new.csv that align with .model.materials. @@ -123,7 +124,7 @@ def prepare_computer(c: "Computer") -> None: # Same key as used in .transport.ldv.stock # TODO Move to .key sales="sales:n-t-y:LDV", - demand=key.demand_base + "MT", + demand=Key("demand", key.demand_base.dims, "MT"), ) # From input_cap_new.csv, select: @@ -156,11 +157,24 @@ def prepare_computer(c: "Computer") -> None: # Convert units: material commodities demand [Mt/year] c.add(k.demand[1], "convert_units", k.demand[0], units="Mt / year") + # Force units for existing model data + # FIXME Adjust to trust the base model's units + c.add(k.demand[2], "apply_units", key.demand_base, units="Mt / year") + # Share of this transport total in existing material demand as of y₀ - c.add(k.demand["share"], "div", key.demand_base, k.demand[1]) + c.add(k.demand[3], "div", k.demand[1], k.demand[2]) + + # Clip values to be in (0, 0.8) + c.add(k.demand[4], lambda q: q.clip(0.0, 0.8), k.demand[3]) + + # Difference with 1.0: should be in range (0.2, 1.0) + c.add(k.demand[5], "sub", genno.Quantity(1.0, units=""), k.demand[4]) + + # Select only values for y0 + c.add(k.demand["share"], "select", k.demand[5], "y0::coord") # Multiply existing material demand by this share - c.add(k.demand["adj"], "mul", key.demand_base, k.demand["share"]) + c.add(k.demand["adj"], "mul", k.demand[2], k.demand["share"]) # Convert data to MESSAGE-format data frame collect("demand", "as_message_df", k.demand["adj"], **_DEMAND_KW) From 58f1aa0957c21a3b07700222ad404a570d89a54a Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Mon, 9 Mar 2026 16:49:23 +0100 Subject: [PATCH 32/73] Add _local_data_factory(*parts) kwargs --- message_ix_models/util/config.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/message_ix_models/util/config.py b/message_ix_models/util/config.py index 6f01f313e7..a57e3b5ed8 100644 --- a/message_ix_models/util/config.py +++ b/message_ix_models/util/config.py @@ -38,7 +38,7 @@ def _cache_path_factory() -> Path: ) -def _local_data_factory() -> Path: +def _local_data_factory(*parts: str) -> Path: """Default value for :attr:`.Config.local_data.""" from platformdirs import user_data_path @@ -50,6 +50,7 @@ def _local_data_factory() -> Path: ) .expanduser() .resolve() + .joinpath(*parts) ) From 3929a463e938aaeb2b2b25064a73ecfcb5082ab9 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Mon, 9 Mar 2026 17:04:36 +0100 Subject: [PATCH 33/73] Add commented debug lines for generating graphs --- message_ix_models/tests/model/transport/test_report.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/message_ix_models/tests/model/transport/test_report.py b/message_ix_models/tests/model/transport/test_report.py index ba1930dd72..561d2727d2 100644 --- a/message_ix_models/tests/model/transport/test_report.py +++ b/message_ix_models/tests/model/transport/test_report.py @@ -180,6 +180,10 @@ def test_bare( rep, key1 = prepare_reporter(test_context, scenario) + # commented: Generate 'full' task graphs for presentation materials + # rep.visualize("transport-report.svg", "transport all", rankdir="LR") + # rep.visualize("transport-build.svg", "add transport data", rankdir="LR") + # Reporting `key` succeeds rep.get(key1) From 571b3e28b709fb81cb4dc1f0a8786271ebf28437 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Mon, 9 Mar 2026 17:31:39 +0100 Subject: [PATCH 34/73] Add URNLookupMixin.__str__() Add tests. --- message_ix_models/tests/util/test_sdmx.py | 20 ++++++++++++++++++++ message_ix_models/util/sdmx.py | 5 +++++ 2 files changed, 25 insertions(+) diff --git a/message_ix_models/tests/util/test_sdmx.py b/message_ix_models/tests/util/test_sdmx.py index 8ebd2cb7c9..9084ce3c79 100644 --- a/message_ix_models/tests/util/test_sdmx.py +++ b/message_ix_models/tests/util/test_sdmx.py @@ -185,6 +185,26 @@ def _get_item_scheme(self): assert _exp_max_value(E2) == max(member.value for member in E2) +class TestURNLookupEnum: + @pytest.fixture + def obj(self): + class Foo(URNLookupEnum, metaclass=ItemSchemeEnumType): + def _get_item_scheme(self): + return read("AGENCIES") + + return Foo["IIASA_ECE"] + + def test_urn(self, obj: URNLookupEnum) -> None: + """:attr:`.urn` retrieves the string URN for an enumeration member.""" + assert re.fullmatch( + rf"{_urn_prefix}.base.Agency=IIASA_ECE:AGENCIES.*\.IIASA_ECE", obj.urn + ) + + def test_str(self, obj: URNLookupEnum) -> None: + """:func:`str` on a member retrieves a partial URN.""" + assert re.fullmatch(r"IIASA_ECE:AGENCIES.*\.IIASA_ECE", str(obj)) + + def test_eval_anno(caplog, recwarn): c = Code() diff --git a/message_ix_models/util/sdmx.py b/message_ix_models/util/sdmx.py index dd55ff01c6..cc0360d167 100644 --- a/message_ix_models/util/sdmx.py +++ b/message_ix_models/util/sdmx.py @@ -502,6 +502,11 @@ def urn(self) -> str: break return result + def __str__(self) -> str: + return self.urn.partition("=")[2] + + __repr__ = __str__ + class URNLookupEnum(URNLookupMixin, Enum): """Class constructed by ItemSchemeEnumType.""" From fa6a076a38f1ac9c54c3500176a6aaf88c632ee1 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Tue, 10 Mar 2026 14:10:53 +0100 Subject: [PATCH 35/73] Adjust LoadFactorLDV to match str(URNLookupMixin) --- message_ix_models/model/transport/data.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/message_ix_models/model/transport/data.py b/message_ix_models/model/transport/data.py index 67347be8e5..bc5281557a 100644 --- a/message_ix_models/model/transport/data.py +++ b/message_ix_models/model/transport/data.py @@ -313,7 +313,10 @@ def filename(self) -> str: ("^M ", ""), # No distinction for materials scenarios ("^DIGSY-WORST-C", str(self.options.config.ssp)), # Use the respective SSP ("^(LED)-SSP.$", r"\1"), # For LED-SSP labels, use common 'LED - (r"^(SSP_\d+)\.(\d)", r"\1_\2"), # "SSP_2024.1" → "SSP_2024_1" + ( # "ICONICS:SSP(2024).1" or "SSP_2024.1" → "SSP_2024_1" + r"^(?:ICONICS:SSP\(|SSP_)(\d+)\)?\.(\d)", + r"SSP_\1_\2", + ), (r"^((SSP|DIGSY)[\w-]+)( \w*)*$", r"\1"), # Remove trailing suffix (" foo") ): label = re.sub(pattern, repl, label) From 9d03ef58f86b95074f45d1ac227f3ab99516ae96 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Tue, 10 Mar 2026 00:19:19 +0100 Subject: [PATCH 36/73] =?UTF-8?q?Rename=20ldv-activity.csv=20=E2=86=92=20a?= =?UTF-8?q?ctivity-vehicle.csv?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add 'scenario' dimension. - Add placeholder values for non-LDV technologies. --- .../data/transport/R11/activity-vehicle.csv | 73 +++++++++ .../data/transport/R11/ldv-activity.csv | 60 ------- .../data/transport/R12/activity-vehicle.csv | 152 ++++++++++++++++++ .../data/transport/R12/ldv-activity.csv | 139 ---------------- .../data/transport/R14/activity-vehicle.csv | 49 ++++++ .../data/transport/R14/ldv-activity.csv | 36 ----- 6 files changed, 274 insertions(+), 235 deletions(-) create mode 100644 message_ix_models/data/transport/R11/activity-vehicle.csv delete mode 100644 message_ix_models/data/transport/R11/ldv-activity.csv create mode 100644 message_ix_models/data/transport/R12/activity-vehicle.csv delete mode 100644 message_ix_models/data/transport/R12/ldv-activity.csv create mode 100644 message_ix_models/data/transport/R14/activity-vehicle.csv delete mode 100644 message_ix_models/data/transport/R14/ldv-activity.csv diff --git a/message_ix_models/data/transport/R11/activity-vehicle.csv b/message_ix_models/data/transport/R11/activity-vehicle.csv new file mode 100644 index 0000000000..7c40e9c4b7 --- /dev/null +++ b/message_ix_models/data/transport/R11/activity-vehicle.csv @@ -0,0 +1,73 @@ +# Activity (driving distance) per light-duty vehicle +# +# Source: Extracted from ldv-cost-efficiency.xlsx by D.L. McCollum; +# see also comments in that file, most of which are copied here: +# +# - “Note: Modest and Frequent mileages for all non-NAM regions are +# scaled relative to the NAM values from MA3T. This is because we +# only have driving data for the average driver (supplied by Page +# Kyle of the GCAM team in March 2014).” +# +# Unit: kilometre / year +# +scenario, technology, node, year, value +# driver_type="M" (moderate) +# *, LDV, R11_NAM, 2020, 13930 +# *, LDV, R11_NAM, 2110, 13930 +# driver_type="A" (average) +*, LDV, R11_NAM, 2020, 25860 +*, LDV, R11_NAM, 2110, 25860 +# driver_type="F" (frequent) +# *, LDV, R11_NAM, 2020, 45550 +# *, LDV, R11_NAM, 2110, 45550 +# DLM: “See the "vkt_veh_yr_GCAM.xlsx" spreadsheet that Page Kyle sent +# me in late-March 2014. The value in this cell is an average of GCAM's +# Brazil and Latin America regions.” +*, LDV, R11_LAM, 2020, 14600 +*, LDV, R11_LAM, 2110, 14600 +# “…GCAM's Western Europe region.” +*, LDV, R11_WEU, 2020, 11646 +*, LDV, R11_WEU, 2110, 11646 +# “…GCAM's Eastern Europe region.” +*, LDV, R11_EEU, 2020, 8962 +*, LDV, R11_EEU, 2110, 8962 +# “…GCAM's Former Soviet Union region.” +*, LDV, R11_FSU, 2020, 11482 +*, LDV, R11_FSU, 2110, 11482 +# “…GCAM's Middle East region.” +*, LDV, R11_MEA, 2020, 14000 +*, LDV, R11_MEA, 2110, 14000 +# “…GCAM's Africa region.” +*, LDV, R11_AFR, 2020, 10391 +*, LDV, R11_AFR, 2110, 10391 +# “…GCAM's China region. Actually, GCAM assumes an average value of +# ~20500 km/yr for China, which seems too high in my opinion, so I +# revised this value downwards. I made an assumption that the value +# should be 20% lower, an estimate I arrived at based on the +# consideration that GCAM assumes that average annual driving distances +# in the US are 20% lower than what MA3T shows for the average driver +# (19200 in GCAM vs. 25860 in MA3T). +*, LDV, R11_CPA, 2020, 16000 +*, LDV, R11_CPA, 2110, 16000 +# “…GCAM's Japan and Australia-NZ regions.” +*, LDV, R11_PAO, 2020, 10000 +*, LDV, R11_PAO, 2110, 10000 +# “…GCAM's Korea and Southeast Asia regions.” +*, LDV, R11_PAS, 2020, 12000 +*, LDV, R11_PAS, 2110, 12000 +# “…GCAM's India region.” +*, LDV, R11_SAS, 2020, 10400 +*, LDV, R11_SAS, 2110, 10400 + +*, AIR, *, 2020, 10000 +*, AIR, *, 2110, 10000 +*, 2W, *, 2020, 10000 +*, 2W, *, 2110, 10000 +*, BUS, *, 2020, 10000 +*, BUS, *, 2110, 10000 +*, P RAIL, *, 2020, 10000 +*, P RAIL, *, 2110, 10000 +*, F RAIL, *, 2020, 10000 +*, F RAIL, *, 2110, 10000 +*, F ROAD, *, 2020, 10000 +*, F ROAD, *, 2110, 10000 diff --git a/message_ix_models/data/transport/R11/ldv-activity.csv b/message_ix_models/data/transport/R11/ldv-activity.csv deleted file mode 100644 index 49c7055b7e..0000000000 --- a/message_ix_models/data/transport/R11/ldv-activity.csv +++ /dev/null @@ -1,60 +0,0 @@ -# Activity (driving distance) per light-duty vehicle -# -# Source: Extracted from ldv-cost-efficiency.xlsx by D.L. McCollum; -# see also comments in that file, most of which are copied here: -# -# - “Note: Modest and Frequent mileages for all non-NAM regions are -# scaled relative to the NAM values from MA3T. This is because we -# only have driving data for the average driver (supplied by Page -# Kyle of the GCAM team in March 2014).” -# -# Unit: kilometre / year -# -scenario, node, year, value -# driver_type="M" (moderate) -# *, R11_NAM, 2020, 13930 -# *, R11_NAM, 2110, 13930 -# driver_type="A" (average) -*, R11_NAM, 2020, 25860 -*, R11_NAM, 2110, 25860 -# driver_type="F" (frequent) -# *, R11_NAM, 2020, 45550 -# *, R11_NAM, 2110, 45550 -# DLM: “See the "vkt_veh_yr_GCAM.xlsx" spreadsheet that Page Kyle sent -# me in late-March 2014. The value in this cell is an average of GCAM's -# Brazil and Latin America regions.” -*, R11_LAM, 2020, 14600 -*, R11_LAM, 2110, 14600 -# “…GCAM's Western Europe region.” -*, R11_WEU, 2020, 11646 -*, R11_WEU, 2110, 11646 -# “…GCAM's Eastern Europe region.” -*, R11_EEU, 2020, 8962 -*, R11_EEU, 2110, 8962 -# “…GCAM's Former Soviet Union region.” -*, R11_FSU, 2020, 11482 -*, R11_FSU, 2110, 11482 -# “…GCAM's Middle East region.” -*, R11_MEA, 2020, 14000 -*, R11_MEA, 2110, 14000 -# “…GCAM's Africa region.” -*, R11_AFR, 2020, 10391 -*, R11_AFR, 2110, 10391 -# “…GCAM's China region. Actually, GCAM assumes an average value of -# ~20500 km/yr for China, which seems too high in my opinion, so I -# revised this value downwards. I made an assumption that the value -# should be 20% lower, an estimate I arrived at based on the -# consideration that GCAM assumes that average annual driving distances -# in the US are 20% lower than what MA3T shows for the average driver -# (19200 in GCAM vs. 25860 in MA3T). -*, R11_CPA, 2020, 16000 -*, R11_CPA, 2110, 16000 -# “…GCAM's Japan and Australia-NZ regions.” -*, R11_PAO, 2020, 10000 -*, R11_PAO, 2110, 10000 -# “…GCAM's Korea and Southeast Asia regions.” -*, R11_PAS, 2020, 12000 -*, R11_PAS, 2110, 12000 -# “…GCAM's India region.” -*, R11_SAS, 2020, 10400 -*, R11_SAS, 2110, 10400 diff --git a/message_ix_models/data/transport/R12/activity-vehicle.csv b/message_ix_models/data/transport/R12/activity-vehicle.csv new file mode 100644 index 0000000000..7aec03c4bc --- /dev/null +++ b/message_ix_models/data/transport/R12/activity-vehicle.csv @@ -0,0 +1,152 @@ +# Activity (driving distance) per light-duty vehicle +# +# Sources: +# +# - Values commented "TH 2024-04-11": calculation by T. Hara, shared at +# https://iiasa-ece.slack.com/archives/CCFHDNA6P/p1712831476181449 +# - R12_AFR, R12_FSU, R12_NAM, R12_PAO, R12_PAS, R12_SAS: see the documentation +# at https://docs.messageix.org/projects/models/en/latest/transport/input.html +# - All others: +# +# - Duplicate of R11/ldv-activity.csv; see comments there. +# - R11_CPA value repeated for R12_RCPA and R12_CHN. +# - scenario=LED: SharePoint ECE.prog > Documents > Transport > LED Scenario > +# input files > ldv-act per veh-LDV.xlsx as of 2025-03-18. +# +# Unit: kilometre / year +# +scenario, technology, node, year, value +# *, LDV, R12_AFR, 2020, 11000 # TH low +# *, LDV, R12_AFR, 2110, 11000 # TH low +*, LDV, R12_AFR, 2020, 15500 +*, LDV, R12_AFR, 2110, 15500 +# *, LDV, R12_AFR, 2020, 19000 # TH high +# *, LDV, R12_AFR, 2110, 19000 # TH high + +# *, LDV, R12_CHN, 2020, 9500 # TH low +# *, LDV, R12_CHN, 2110, 9500 # TH low +*, LDV, R12_CHN, 2020, 15000 # TH high +*, LDV, R12_CHN, 2110, 15000 # TH high +# *, LDV, R12_CHN, 2020, 16000 # Previous value +# *, LDV, R12_CHN, 2110, 16000 # Previous value + +# *, LDV, R12_EEU, 2020, 8962 # Previous value +# *, LDV, R12_EEU, 2110, 8962 # Previous value +*, LDV, R12_EEU, 2020, 9000 # TH low +*, LDV, R12_EEU, 2110, 9000 # TH low +# *, LDV, R12_EEU, 2020, 10000 # TH high +# *, LDV, R12_EEU, 2110, 10000 # TH high +# *, LDV, R12_EEU, 2020, 12500 # Experimental #392 +# *, LDV, R12_EEU, 2110, 15000 # Experimental #392 + +# *, LDV, R12_FSU, 2020, 11000 # TH low +# *, LDV, R12_FSU, 2110, 11000 # TH low +*, LDV, R12_FSU, 2020, 13000 # TH high = previous value +*, LDV, R12_FSU, 2110, 13000 # TH high = previous value + +# *, LDV, R12_LAM, 2020, 13000 # TH low +# *, LDV, R12_LAM, 2110, 13000 # TH low +*, LDV, R12_LAM, 2020, 13500 +*, LDV, R12_LAM, 2110, 13500 +# *, LDV, R12_LAM, 2020, 15000 # TH high +# *, LDV, R12_LAM, 2110, 15000 # TH high + +# *, LDV, R12_MEA, 2020, 13000 # TH low +# *, LDV, R12_MEA, 2110, 13000 # TH low +*, LDV, R12_MEA, 2020, 14500 +*, LDV, R12_MEA, 2110, 14500 +# *, LDV, R12_MEA, 2020, 16000 # TH high +# *, LDV, R12_MEA, 2110, 16000 # TH high + +# *, LDV, R12_NAM, 2020, 16000 # TH low +# *, LDV, R12_NAM, 2110, 16000 # TH low +*, LDV, R12_NAM, 2020, 18400 +*, LDV, R12_NAM, 2110, 18400 +# *, LDV, R12_NAM, 2020, 19000 # TH high +# *, LDV, R12_NAM, 2110, 19000 # TH high + +*, LDV, R12_PAO, 2020, 9000 # TH low = previous value +*, LDV, R12_PAO, 2110, 9000 # TH low = previous value +# *, LDV, R12_PAO, 2020, 10000 # TH high +# *, LDV, R12_PAO, 2110, 10000 # TH high +# *, LDV, R12_PAO, 2020, 10000 # Experimental #392 +# *, LDV, R12_PAO, 2110, 13000 # Experimental #392 + +# *, LDV, R12_PAS, 2020, 11000 # TH low +# *, LDV, R12_PAS, 2110, 11000 # TH low +*, LDV, R12_PAS, 2020, 13000 # TH high = previous value +*, LDV, R12_PAS, 2110, 13000 # TH high = previous value + +# *, LDV, R12_RCPA, 2020, 11000 # TH low +# *, LDV, R12_RCPA, 2110, 11000 # TH low +*, LDV, R12_RCPA, 2020, 12000 # TH high +*, LDV, R12_RCPA, 2110, 12000 # TH high +# *, LDV, R12_RCPA, 2020, 15000 # Experimental #392 +# *, LDV, R12_RCPA, 2110, 15000 # Experimental #392 +# *, LDV, R12_RCPA, 2020, 16000 # Previous value +# *, LDV, R12_RCPA, 2110, 16000 # Previous value + +*, LDV, R12_SAS, 2020, 12000 # TH low = previous value +*, LDV, R12_SAS, 2110, 12000 # TH low = previous value +# *, LDV, R12_SAS, 2020, 15000 # TH high +# *, LDV, R12_SAS, 2110, 15000 # TH high +# *, LDV, R12_SAS, 2020, 18000 # Experimental #392 +# *, LDV, R12_SAS, 2110, 18000 # Experimental #392 + +# *, LDV, R12_WEU, 2020, 11000 # TH low +# *, LDV, R12_WEU, 2110, 11000 # TH low +*, LDV, R12_WEU, 2020, 11700 +*, LDV, R12_WEU, 2110, 11700 +# *, LDV, R12_WEU, 2020, 12000 # TH high +# *, LDV, R12_WEU, 2110, 12000 # TH high +# *, LDV, R12_WEU, 2110, 15000 # Experimental #392 + +LED, LDV, R12_AFR, 2020, 15500 +LED, LDV, R12_AFR, 2050, 15113 +LED, LDV, R12_AFR, 2110, 15113 +LED, LDV, R12_CHN, 2020, 15000 +LED, LDV, R12_CHN, 2050, 15113 +LED, LDV, R12_CHN, 2110, 15113 +LED, LDV, R12_EEU, 2020, 9000 +LED, LDV, R12_EEU, 2050, 14087 +LED, LDV, R12_EEU, 2110, 14087 +LED, LDV, R12_FSU, 2020, 13000 +LED, LDV, R12_FSU, 2050, 14087 +LED, LDV, R12_FSU, 2110, 14087 +LED, LDV, R12_LAM, 2020, 13500 +LED, LDV, R12_LAM, 2050, 15113 +LED, LDV, R12_LAM, 2110, 15113 +LED, LDV, R12_MEA, 2020, 14500 +LED, LDV, R12_MEA, 2050, 15113 +LED, LDV, R12_MEA, 2110, 15113 +LED, LDV, R12_NAM, 2020, 18400 +LED, LDV, R12_NAM, 2050, 14087 +LED, LDV, R12_NAM, 2110, 14087 +LED, LDV, R12_PAO, 2020, 9000 +LED, LDV, R12_PAO, 2050, 14087 +LED, LDV, R12_PAO, 2110, 14087 +LED, LDV, R12_PAS, 2020, 13000 +LED, LDV, R12_PAS, 2050, 15113 +LED, LDV, R12_PAS, 2110, 15113 +LED, LDV, R12_RCPA, 2020, 12000 +LED, LDV, R12_RCPA, 2050, 15113 +LED, LDV, R12_RCPA, 2110, 15113 +LED, LDV, R12_SAS, 2020, 12000 +LED, LDV, R12_SAS, 2050, 15113 +LED, LDV, R12_SAS, 2110, 15113 +LED, LDV, R12_WEU, 2020, 11700 +LED, LDV, R12_WEU, 2050, 14087 +LED, LDV, R12_WEU, 2110, 14087 + +*, AIR, *, 2020, 10000 +*, AIR, *, 2110, 10000 +*, 2W, *, 2020, 10000 +*, 2W, *, 2110, 10000 +*, BUS, *, 2020, 10000 +*, BUS, *, 2110, 10000 +*, P RAIL, *, 2020, 10000 +*, P RAIL, *, 2110, 10000 +*, F RAIL, *, 2020, 10000 +*, F RAIL, *, 2110, 10000 +*, F ROAD, *, 2020, 10000 +*, F ROAD, *, 2110, 10000 diff --git a/message_ix_models/data/transport/R12/ldv-activity.csv b/message_ix_models/data/transport/R12/ldv-activity.csv deleted file mode 100644 index 8c3572e64b..0000000000 --- a/message_ix_models/data/transport/R12/ldv-activity.csv +++ /dev/null @@ -1,139 +0,0 @@ -# Activity (driving distance) per light-duty vehicle -# -# Sources: -# -# - Values commented "TH 2024-04-11": calculation by T. Hara, shared at -# https://iiasa-ece.slack.com/archives/CCFHDNA6P/p1712831476181449 -# - R12_AFR, R12_FSU, R12_NAM, R12_PAO, R12_PAS, R12_SAS: see the documentation -# at https://docs.messageix.org/projects/models/en/latest/transport/input.html -# - All others: -# -# - Duplicate of R11/ldv-activity.csv; see comments there. -# - R11_CPA value repeated for R12_RCPA and R12_CHN. -# - scenario=LED: SharePoint ECE.prog > Documents > Transport > LED Scenario > -# input files > ldv-act per veh-LDV.xlsx as of 2025-03-18. -# -# Unit: kilometre / year -# -scenario, node, year, value -# *, R12_AFR, 2020, 11000 # TH low -# *, R12_AFR, 2110, 11000 # TH low -*, R12_AFR, 2020, 15500 -*, R12_AFR, 2110, 15500 -# *, R12_AFR, 2020, 19000 # TH high -# *, R12_AFR, 2110, 19000 # TH high - -# *, R12_CHN, 2020, 9500 # TH low -# *, R12_CHN, 2110, 9500 # TH low -*, R12_CHN, 2020, 15000 # TH high -*, R12_CHN, 2110, 15000 # TH high -# *, R12_CHN, 2020, 16000 # Previous value -# *, R12_CHN, 2110, 16000 # Previous value - -# *, R12_EEU, 2020, 8962 # Previous value -# *, R12_EEU, 2110, 8962 # Previous value -*, R12_EEU, 2020, 9000 # TH low -*, R12_EEU, 2110, 9000 # TH low -# *, R12_EEU, 2020, 10000 # TH high -# *, R12_EEU, 2110, 10000 # TH high -# *, R12_EEU, 2020, 12500 # Experimental #392 -# *, R12_EEU, 2110, 15000 # Experimental #392 - -# *, R12_FSU, 2020, 11000 # TH low -# *, R12_FSU, 2110, 11000 # TH low -*, R12_FSU, 2020, 13000 # TH high = previous value -*, R12_FSU, 2110, 13000 # TH high = previous value - -# *, R12_LAM, 2020, 13000 # TH low -# *, R12_LAM, 2110, 13000 # TH low -*, R12_LAM, 2020, 13500 -*, R12_LAM, 2110, 13500 -# *, R12_LAM, 2020, 15000 # TH high -# *, R12_LAM, 2110, 15000 # TH high - -# *, R12_MEA, 2020, 13000 # TH low -# *, R12_MEA, 2110, 13000 # TH low -*, R12_MEA, 2020, 14500 -*, R12_MEA, 2110, 14500 -# *, R12_MEA, 2020, 16000 # TH high -# *, R12_MEA, 2110, 16000 # TH high - -# *, R12_NAM, 2020, 16000 # TH low -# *, R12_NAM, 2110, 16000 # TH low -*, R12_NAM, 2020, 18400 -*, R12_NAM, 2110, 18400 -# *, R12_NAM, 2020, 19000 # TH high -# *, R12_NAM, 2110, 19000 # TH high - -*, R12_PAO, 2020, 9000 # TH low = previous value -*, R12_PAO, 2110, 9000 # TH low = previous value -# *, R12_PAO, 2020, 10000 # TH high -# *, R12_PAO, 2110, 10000 # TH high -# *, R12_PAO, 2020, 10000 # Experimental #392 -# *, R12_PAO, 2110, 13000 # Experimental #392 - -# *, R12_PAS, 2020, 11000 # TH low -# *, R12_PAS, 2110, 11000 # TH low -*, R12_PAS, 2020, 13000 # TH high = previous value -*, R12_PAS, 2110, 13000 # TH high = previous value - -# *, R12_RCPA, 2020, 11000 # TH low -# *, R12_RCPA, 2110, 11000 # TH low -*, R12_RCPA, 2020, 12000 # TH high -*, R12_RCPA, 2110, 12000 # TH high -# *, R12_RCPA, 2020, 15000 # Experimental #392 -# *, R12_RCPA, 2110, 15000 # Experimental #392 -# *, R12_RCPA, 2020, 16000 # Previous value -# *, R12_RCPA, 2110, 16000 # Previous value - -*, R12_SAS, 2020, 12000 # TH low = previous value -*, R12_SAS, 2110, 12000 # TH low = previous value -# *, R12_SAS, 2020, 15000 # TH high -# *, R12_SAS, 2110, 15000 # TH high -# *, R12_SAS, 2020, 18000 # Experimental #392 -# *, R12_SAS, 2110, 18000 # Experimental #392 - -# *, R12_WEU, 2020, 11000 # TH low -# *, R12_WEU, 2110, 11000 # TH low -*, R12_WEU, 2020, 11700 -*, R12_WEU, 2110, 11700 -# *, R12_WEU, 2020, 12000 # TH high -# *, R12_WEU, 2110, 12000 # TH high -# *, R12_WEU, 2110, 15000 # Experimental #392 - -LED, R12_AFR, 2020, 15500 -LED, R12_AFR, 2050, 15113 -LED, R12_AFR, 2110, 15113 -LED, R12_CHN, 2020, 15000 -LED, R12_CHN, 2050, 15113 -LED, R12_CHN, 2110, 15113 -LED, R12_EEU, 2020, 9000 -LED, R12_EEU, 2050, 14087 -LED, R12_EEU, 2110, 14087 -LED, R12_FSU, 2020, 13000 -LED, R12_FSU, 2050, 14087 -LED, R12_FSU, 2110, 14087 -LED, R12_LAM, 2020, 13500 -LED, R12_LAM, 2050, 15113 -LED, R12_LAM, 2110, 15113 -LED, R12_MEA, 2020, 14500 -LED, R12_MEA, 2050, 15113 -LED, R12_MEA, 2110, 15113 -LED, R12_NAM, 2020, 18400 -LED, R12_NAM, 2050, 14087 -LED, R12_NAM, 2110, 14087 -LED, R12_PAO, 2020, 9000 -LED, R12_PAO, 2050, 14087 -LED, R12_PAO, 2110, 14087 -LED, R12_PAS, 2020, 13000 -LED, R12_PAS, 2050, 15113 -LED, R12_PAS, 2110, 15113 -LED, R12_RCPA, 2020, 12000 -LED, R12_RCPA, 2050, 15113 -LED, R12_RCPA, 2110, 15113 -LED, R12_SAS, 2020, 12000 -LED, R12_SAS, 2050, 15113 -LED, R12_SAS, 2110, 15113 -LED, R12_WEU, 2020, 11700 -LED, R12_WEU, 2050, 14087 -LED, R12_WEU, 2110, 14087 diff --git a/message_ix_models/data/transport/R14/activity-vehicle.csv b/message_ix_models/data/transport/R14/activity-vehicle.csv new file mode 100644 index 0000000000..00052d13c8 --- /dev/null +++ b/message_ix_models/data/transport/R14/activity-vehicle.csv @@ -0,0 +1,49 @@ +# Activity (driving distance) per light-duty vehicle +# +# Source: duplicate of R11/ldv-activity.csv; see comments there. The +# value for R11_FSU is repeated for R14_{CAS,RUS,SCS,UBM}. +# +# Unit: kilometre / year +# +scenario, technology, node, year, value +*, LDV, R14_AFR, 2020, 10391 +*, LDV, R14_AFR, 2110, 10391 +*, LDV, R14_CPA, 2020, 16000 +*, LDV, R14_CPA, 2110, 16000 +*, LDV, R14_EEU, 2020, 8962 +*, LDV, R14_EEU, 2110, 8962 +*, LDV, R14_LAM, 2020, 14600 +*, LDV, R14_LAM, 2110, 14600 +*, LDV, R14_MEA, 2020, 14000 +*, LDV, R14_MEA, 2110, 14000 +*, LDV, R14_NAM, 2020, 25860 +*, LDV, R14_NAM, 2110, 25860 +*, LDV, R14_PAO, 2020, 10000 +*, LDV, R14_PAO, 2110, 10000 +*, LDV, R14_PAS, 2020, 12000 +*, LDV, R14_PAS, 2110, 12000 +*, LDV, R14_RUS, 2020, 11482 +*, LDV, R14_RUS, 2110, 11482 +*, LDV, R14_SAS, 2020, 10400 +*, LDV, R14_SAS, 2110, 10400 +*, LDV, R14_WEU, 2020, 11646 +*, LDV, R14_WEU, 2110, 11646 +*, LDV, R14_CAS, 2020, 11482 +*, LDV, R14_CAS, 2110, 11482 +*, LDV, R14_SCS, 2020, 11482 +*, LDV, R14_SCS, 2110, 11482 +*, LDV, R14_UBM, 2020, 11482 +*, LDV, R14_UBM, 2110, 11482 + +*, AIR, *, 2020, 10000 +*, AIR, *, 2110, 10000 +*, 2W, *, 2020, 10000 +*, 2W, *, 2110, 10000 +*, BUS, *, 2020, 10000 +*, BUS, *, 2110, 10000 +*, P RAIL, *, 2020, 10000 +*, P RAIL, *, 2110, 10000 +*, F RAIL, *, 2020, 10000 +*, F RAIL, *, 2110, 10000 +*, F ROAD, *, 2020, 10000 +*, F ROAD, *, 2110, 10000 diff --git a/message_ix_models/data/transport/R14/ldv-activity.csv b/message_ix_models/data/transport/R14/ldv-activity.csv deleted file mode 100644 index 27cd475809..0000000000 --- a/message_ix_models/data/transport/R14/ldv-activity.csv +++ /dev/null @@ -1,36 +0,0 @@ -# Activity (driving distance) per light-duty vehicle -# -# Source: duplicate of R11/ldv-activity.csv; see comments there. The -# value for R11_FSU is repeated for R14_{CAS,RUS,SCS,UBM}. -# -# Unit: kilometre / year -# -scenario, node, year, value -*, R14_AFR, 2020, 10391 -*, R14_AFR, 2110, 10391 -*, R14_CPA, 2020, 16000 -*, R14_CPA, 2110, 16000 -*, R14_EEU, 2020, 8962 -*, R14_EEU, 2110, 8962 -*, R14_LAM, 2020, 14600 -*, R14_LAM, 2110, 14600 -*, R14_MEA, 2020, 14000 -*, R14_MEA, 2110, 14000 -*, R14_NAM, 2020, 25860 -*, R14_NAM, 2110, 25860 -*, R14_PAO, 2020, 10000 -*, R14_PAO, 2110, 10000 -*, R14_PAS, 2020, 12000 -*, R14_PAS, 2110, 12000 -*, R14_RUS, 2020, 11482 -*, R14_RUS, 2110, 11482 -*, R14_SAS, 2020, 10400 -*, R14_SAS, 2110, 10400 -*, R14_WEU, 2020, 11646 -*, R14_WEU, 2110, 11646 -*, R14_CAS, 2020, 11482 -*, R14_CAS, 2110, 11482 -*, R14_SCS, 2020, 11482 -*, R14_SCS, 2110, 11482 -*, R14_UBM, 2020, 11482 -*, R14_UBM, 2110, 11482 From 760344b3da82514597dab8e5cd55ff1666a5d6d3 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Tue, 10 Mar 2026 14:49:06 +0100 Subject: [PATCH 37/73] =?UTF-8?q?Rename=20lifetime-ldv.csv=20=E2=86=92=20l?= =?UTF-8?q?ifetime.csv?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/transport/R12/lifetime-ldv.csv | 71 ---------------- .../data/transport/R12/lifetime.csv | 82 +++++++++++++++++++ .../data/transport/lifetime-ldv.csv | 7 -- message_ix_models/data/transport/lifetime.csv | 7 ++ 4 files changed, 89 insertions(+), 78 deletions(-) delete mode 100644 message_ix_models/data/transport/R12/lifetime-ldv.csv create mode 100644 message_ix_models/data/transport/R12/lifetime.csv delete mode 100644 message_ix_models/data/transport/lifetime-ldv.csv create mode 100644 message_ix_models/data/transport/lifetime.csv diff --git a/message_ix_models/data/transport/R12/lifetime-ldv.csv b/message_ix_models/data/transport/R12/lifetime-ldv.csv deleted file mode 100644 index ba353d3d34..0000000000 --- a/message_ix_models/data/transport/R12/lifetime-ldv.csv +++ /dev/null @@ -1,71 +0,0 @@ -# Technical lifetime (maximum age) of LDVs -# -# Sources -# - scenario=*: see https://github.com/iiasa/message-ix-models/pull/213 -# - scenario=LED: SharePoint ECE.prog > Documents > Transport > LED Scenario > -# input files > lifetime-ldv-LED.xlsx as of 2025-03-18. -# -# Units: year -# -scenario, node_loc, technology, year_vtg, value -*, R12_AFR, *, 1990, 25 -*, R12_AFR, *, 2110, 25 -*, R12_CHN, *, 1990, 18 -*, R12_CHN, *, 2110, 18 -*, R12_EEU, *, 1990, 28 -*, R12_EEU, *, 2110, 28 -*, R12_FSU, *, 1990, 15 -*, R12_FSU, *, 2110, 15 -*, R12_LAM, *, 1990, 25 -*, R12_LAM, *, 2110, 25 -*, R12_MEA, *, 1990, 15 -*, R12_MEA, *, 2110, 15 -*, R12_NAM, *, 1990, 18 -*, R12_NAM, *, 2110, 18 -*, R12_PAO, *, 1990, 15 -*, R12_PAO, *, 2110, 15 -*, R12_PAS, *, 1990, 15 -*, R12_PAS, *, 2110, 15 -*, R12_RCPA, *, 1990, 15 -*, R12_RCPA, *, 2110, 15 -*, R12_SAS, *, 1990, 25 -*, R12_SAS, *, 2110, 25 -*, R12_WEU, *, 1990, 20 -*, R12_WEU, *, 2110, 20 - -LED, R12_AFR, *, 1990, 25 -LED, R12_AFR, *, 2050, 19.36 -LED, R12_AFR, *, 2110, 19.36 -LED, R12_CHN, *, 1990, 15 -LED, R12_CHN, *, 2050, 19.36 -LED, R12_CHN, *, 2110, 19.36 -LED, R12_EEU, *, 1990, 28 -LED, R12_EEU, *, 2050, 19.55 -LED, R12_EEU, *, 2110, 19.55 -LED, R12_FSU, *, 1990, 15 -LED, R12_FSU, *, 2050, 19.55 -LED, R12_FSU, *, 2110, 19.55 -LED, R12_LAM, *, 1990, 25 -LED, R12_LAM, *, 2050, 19.36 -LED, R12_LAM, *, 2110, 19.36 -LED, R12_MEA, *, 1990, 15 -LED, R12_MEA, *, 2050, 19.36 -LED, R12_MEA, *, 2110, 19.36 -LED, R12_NAM, *, 1990, 18 -LED, R12_NAM, *, 2050, 19.55 -LED, R12_NAM, *, 2110, 19.55 -LED, R12_PAO, *, 1990, 13 -LED, R12_PAO, *, 2050, 19.55 -LED, R12_PAO, *, 2110, 19.55 -LED, R12_PAS, *, 1990, 13 -LED, R12_PAS, *, 2050, 19.36 -LED, R12_PAS, *, 2110, 19.36 -LED, R12_RCPA, *, 1990, 15 -LED, R12_RCPA, *, 2050, 19.36 -LED, R12_RCPA, *, 2110, 19.36 -LED, R12_SAS, *, 1990, 25 -LED, R12_SAS, *, 2050, 19.36 -LED, R12_SAS, *, 2110, 19.36 -LED, R12_WEU, *, 1990, 20 -LED, R12_WEU, *, 2050, 19.55 -LED, R12_WEU, *, 2110, 19.55 diff --git a/message_ix_models/data/transport/R12/lifetime.csv b/message_ix_models/data/transport/R12/lifetime.csv new file mode 100644 index 0000000000..19388350c1 --- /dev/null +++ b/message_ix_models/data/transport/R12/lifetime.csv @@ -0,0 +1,82 @@ +# Technical lifetime (maximum age) of vehicles +# +# Sources +# - scenario=*: see https://github.com/iiasa/message-ix-models/pull/213 +# - scenario=LED: SharePoint ECE.prog > Documents > Transport > LED Scenario > +# input files > lifetime-ldv-LED.xlsx as of 2025-03-18. +# +# Units: year +# +scenario, technology, node_loc, year_vtg, value +*, LDV, R12_AFR, 1990, 25 +*, LDV, R12_AFR, 2110, 25 +*, LDV, R12_CHN, 1990, 18 +*, LDV, R12_CHN, 2110, 18 +*, LDV, R12_EEU, 1990, 28 +*, LDV, R12_EEU, 2110, 28 +*, LDV, R12_FSU, 1990, 15 +*, LDV, R12_FSU, 2110, 15 +*, LDV, R12_LAM, 1990, 25 +*, LDV, R12_LAM, 2110, 25 +*, LDV, R12_MEA, 1990, 15 +*, LDV, R12_MEA, 2110, 15 +*, LDV, R12_NAM, 1990, 18 +*, LDV, R12_NAM, 2110, 18 +*, LDV, R12_PAO, 1990, 15 +*, LDV, R12_PAO, 2110, 15 +*, LDV, R12_PAS, 1990, 15 +*, LDV, R12_PAS, 2110, 15 +*, LDV, R12_RCPA, 1990, 15 +*, LDV, R12_RCPA, 2110, 15 +*, LDV, R12_SAS, 1990, 25 +*, LDV, R12_SAS, 2110, 25 +*, LDV, R12_WEU, 1990, 20 +*, LDV, R12_WEU, 2110, 20 + +LED, LDV, R12_AFR, 1990, 25 +LED, LDV, R12_AFR, 2050, 19.36 +LED, LDV, R12_AFR, 2110, 19.36 +LED, LDV, R12_CHN, 1990, 15 +LED, LDV, R12_CHN, 2050, 19.36 +LED, LDV, R12_CHN, 2110, 19.36 +LED, LDV, R12_EEU, 1990, 28 +LED, LDV, R12_EEU, 2050, 19.55 +LED, LDV, R12_EEU, 2110, 19.55 +LED, LDV, R12_FSU, 1990, 15 +LED, LDV, R12_FSU, 2050, 19.55 +LED, LDV, R12_FSU, 2110, 19.55 +LED, LDV, R12_LAM, 1990, 25 +LED, LDV, R12_LAM, 2050, 19.36 +LED, LDV, R12_LAM, 2110, 19.36 +LED, LDV, R12_MEA, 1990, 15 +LED, LDV, R12_MEA, 2050, 19.36 +LED, LDV, R12_MEA, 2110, 19.36 +LED, LDV, R12_NAM, 1990, 18 +LED, LDV, R12_NAM, 2050, 19.55 +LED, LDV, R12_NAM, 2110, 19.55 +LED, LDV, R12_PAO, 1990, 13 +LED, LDV, R12_PAO, 2050, 19.55 +LED, LDV, R12_PAO, 2110, 19.55 +LED, LDV, R12_PAS, 1990, 13 +LED, LDV, R12_PAS, 2050, 19.36 +LED, LDV, R12_PAS, 2110, 19.36 +LED, LDV, R12_RCPA, 1990, 15 +LED, LDV, R12_RCPA, 2050, 19.36 +LED, LDV, R12_RCPA, 2110, 19.36 +LED, LDV, R12_SAS, 1990, 25 +LED, LDV, R12_SAS, 2050, 19.36 +LED, LDV, R12_SAS, 2110, 19.36 +LED, LDV, R12_WEU, 1990, 20 +LED, LDV, R12_WEU, 2050, 19.55 +LED, LDV, R12_WEU, 2110, 19.55 + +*, 2W, *, 1990, 15 +*, 2W, *, 2110, 15 +*, AIR, *, 1990, 15 +*, AIR, *, 2110, 15 +*, BUS, *, 1990, 15 +*, BUS, *, 2110, 15 +*, F RAIL, *, 1990, 15 +*, F RAIL, *, 2110, 15 +*, F ROAD, *, 1990, 15 +*, F ROAD, *, 2110, 15 diff --git a/message_ix_models/data/transport/lifetime-ldv.csv b/message_ix_models/data/transport/lifetime-ldv.csv deleted file mode 100644 index e0d4a339ff..0000000000 --- a/message_ix_models/data/transport/lifetime-ldv.csv +++ /dev/null @@ -1,7 +0,0 @@ -# Technical lifetime (maximum age) of LDVs -# -# Units: year -# -scenario, node_loc, technology, year_vtg, value -*, *, *, 1960, 15 -*, *, *, 2110, 15 diff --git a/message_ix_models/data/transport/lifetime.csv b/message_ix_models/data/transport/lifetime.csv new file mode 100644 index 0000000000..177ba0bdb8 --- /dev/null +++ b/message_ix_models/data/transport/lifetime.csv @@ -0,0 +1,7 @@ +# Technical lifetime (maximum age) of vehicles +# +# Units: year +# +scenario, technology, node_loc, year_vtg, value +*, *, *, 1960, 15 +*, *, *, 2110, 15 From 316f9a2d1e6512831ed04c2cc06cc95feb00df44 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Tue, 10 Mar 2026 00:19:57 +0100 Subject: [PATCH 38/73] Add .report.operator.broadcast_wildcard2() --- message_ix_models/report/operator.py | 28 +++++++++++++++++++++++++++- message_ix_models/util/common.py | 3 +++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/message_ix_models/report/operator.py b/message_ix_models/report/operator.py index ee9015ec63..d0a01f0854 100644 --- a/message_ix_models/report/operator.py +++ b/message_ix_models/report/operator.py @@ -24,7 +24,12 @@ from iam_units.emissions import SPECIES from message_ix_models.model.structure import get_codelist -from message_ix_models.util import MappingAdapter, add_par_data, nodes_ex_world +from message_ix_models.util import ( + MappingAdapter, + WildcardAdapter, + add_par_data, + nodes_ex_world, +) from message_ix_models.util.sdmx import leaf_ids if TYPE_CHECKING: @@ -47,6 +52,7 @@ def __lt__(self, __other: Any) -> bool: ... __all__ = [ "add_par_data", "broadcast_wildcard", + "broadcast_wildcard2", "call", "codelist_to_groups", "compound_growth", @@ -118,6 +124,26 @@ def broadcast_wildcard( return MappingAdapter(mapping)(qty) +def broadcast_wildcard2( + qty: "TQuantity", *coords: Sequence[str], dim: Hashable | Sequence[Hashable] = "n" +) -> "TQuantity": + """Like :func:`broadcast_wildcard`, but using :class:`.WildcardAdapter`.""" + if isinstance(dim, Hashable) and not isinstance(dim, tuple): + dim = (dim,) + if len(dim) != len(coords): + raise ValueError( + f"Must provide same number of dim (got |{dim}| = {len(dim)}) as coords " + f"(got {len(coords)})" + ) + + # Iterate over dimensions `d` and respective coords `c` + result = qty + for d, c in zip(dim, coords): + result = WildcardAdapter(d, c)(result) + + return result + + def call(callable, *args, **kwargs): """Invoke a callable on other arguments.""" return callable(*args, **kwargs) diff --git a/message_ix_models/util/common.py b/message_ix_models/util/common.py index f19740c887..60b3f9f324 100644 --- a/message_ix_models/util/common.py +++ b/message_ix_models/util/common.py @@ -191,7 +191,10 @@ def adapt(self, qty: "TQuantity") -> "TQuantity": class WildcardAdapter(Adapter): """Adapt data using by broadcasting wildcard ("*") entries for 1 dimension.""" + #: Dimension on which to expand wildcard. dim: str + + #: Expected full list of coords along :attr:`dim`. coords: set[str] def __init__(self, dim: str, coords: Sequence[str]) -> None: From 70526c6dd8c85fa6a41c82d99cfb51e049cd5838 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Tue, 10 Mar 2026 00:28:04 +0100 Subject: [PATCH 39/73] Add .transport.data.ActivityVehicle - Read and transform data from activity-vehicle.csv; mirrors code formerly in .transport.ldv.prepare_computer(). - Adjust usage, docs. --- doc/transport/input.rst | 4 +- doc/transport/output.rst | 4 +- doc/whatsnew.rst | 5 +- message_ix_models/model/transport/build.py | 9 +-- message_ix_models/model/transport/data.py | 56 ++++++++++++++++--- .../model/transport/disutility.py | 4 +- message_ix_models/model/transport/key.py | 10 ++-- 7 files changed, 67 insertions(+), 25 deletions(-) diff --git a/doc/transport/input.rst b/doc/transport/input.rst index 5ed0ec810f..cd38cffc1f 100644 --- a/doc/transport/input.rst +++ b/doc/transport/input.rst @@ -113,7 +113,7 @@ The :program:`git` history of files, or the GitHub "blame" view can also be used Quick links to each of the data flows: :data:`~.data.act_non_ldv` :data:`~.data.activity_freight` -:data:`~.data.activity_ldv` +:class:`~.data.ActivityVehicle` :data:`~.data.age_ldv` :data:`~.data.cap_new_ldv` :data:`~.data.class_ldv` @@ -153,7 +153,7 @@ Quick links to each of the data flows: .. autodata:: message_ix_models.model.transport.data.act_non_ldv .. autodata:: message_ix_models.model.transport.data.activity_freight -.. autodata:: message_ix_models.model.transport.data.activity_ldv +.. autoclass:: message_ix_models.model.transport.data.ActivityVehicle node = R12_AFR [1]_ Obtained from literature, based on estimates from South Africa. The reported value for South Africa is lower (18000 km/year, `source `__) than the one for Kenya (22000 km/year, `source `__). diff --git a/doc/transport/output.rst b/doc/transport/output.rst index 3cadc30f50..444123d40f 100644 --- a/doc/transport/output.rst +++ b/doc/transport/output.rst @@ -20,13 +20,13 @@ Data flows Quick links to each of the data flows: :data:`~.data.activity_passenger` -:data:`~.data.activity_vehicle` +:data:`~.data.activity_vehicle_out` :data:`~.data.fe_transport` :data:`~.data.gdp_in` :data:`~.data.population_in` .. autodata:: message_ix_models.model.transport.data.activity_passenger -.. autodata:: message_ix_models.model.transport.data.activity_vehicle +.. autodata:: message_ix_models.model.transport.data.activity_vehicle_out .. autodata:: message_ix_models.model.transport.data.fe_transport .. autodata:: message_ix_models.model.transport.data.gdp_in .. autodata:: message_ix_models.model.transport.data.population_in diff --git a/doc/whatsnew.rst b/doc/whatsnew.rst index 179d3ab75b..b697560e01 100644 --- a/doc/whatsnew.rst +++ b/doc/whatsnew.rst @@ -408,7 +408,7 @@ Update :doc:`/transport/index` (:pull:`259`, :pull:`289`, :pull:`300`, :pull:`32 :data:`.mode_share_freight`, :data:`.pdt_cap_ref`, and :data:`.speed`. -- Add LED-specific parametrization for :data:`.activity_ldv`, +- Add LED-specific parametrization for :class:`activity_ldv <.ActivityVehicle>`, :data:`.lifetime_ldv`, :py:`load_factor_ldv`, and :data:`.pdt_cap_proj`. @@ -416,7 +416,8 @@ Update :doc:`/transport/index` (:pull:`259`, :pull:`289`, :pull:`300`, :pull:`32 - Generate SDMX-ML structural metadata, including data flow definitions, and SDMX-{CSV,ML} data outputs for certain reported quantities. - New input data flow :data:`.input_share`. - - Add :py:`scenario` dimension to :data:`.activity_ldv`, :data:`.lifetime_ldv`, input data flow and files. + - Add :py:`scenario` dimension to :class:`activity_ldv <.ActivityVehicle>`, + :data:`.lifetime_ldv`, input data flow and files. - Expand use of fixed/shared keys from :mod:`.transport.key`. - Improve documentation: diff --git a/message_ix_models/model/transport/build.py b/message_ix_models/model/transport/build.py index 481da014ea..9c2df37f48 100644 --- a/message_ix_models/model/transport/build.py +++ b/message_ix_models/model/transport/build.py @@ -170,6 +170,11 @@ def add_exogenous_data(c: Computer, info: ScenarioInfo) -> None: for kw in source_kw: keys[kw["measure"]] = cls.add_tasks(c, source=config.ssp.urn, **kw, **c_s) + # Miscellaneous data + kw = dict(nodes=context.model.regions, config=config) + data.ActivityVehicle.add_tasks(c, **kw, **c_s) + data.LoadFactorLDV.add_tasks(c, **kw, **c_s) + # Add data for MERtoPPP kw = dict(measure="MERtoPPP", nodes=context.model.regions) data.MERtoPPP.add_tasks(c, **kw, **c_s) @@ -236,10 +241,6 @@ def add_exogenous_data(c: Computer, info: ScenarioInfo) -> None: for _, f in filter(lambda x: x[1].intent & Dataflow.FLAG.IN, data.iter_files()): c.add("", f, context=context) - data.LoadFactorLDV.add_tasks( - c, context=context, strict=False, nodes=context.model.regions, config=config - ) - #: :mod:`genno` tasks for model structure information that are 'static'—that is, do not #: change based on :class:`~.transport.config.Config` settings. See diff --git a/message_ix_models/model/transport/data.py b/message_ix_models/model/transport/data.py index bc5281557a..3a873f85ef 100644 --- a/message_ix_models/model/transport/data.py +++ b/message_ix_models/model/transport/data.py @@ -35,7 +35,7 @@ ) from message_ix_models.util.sdmx import DATAFLOW, STORE, Dataflow -from .util import EXTRAPOLATE +from .util import EXTRAPOLATE, region_path_fallback if TYPE_CHECKING: import sdmx.message @@ -61,6 +61,52 @@ ] +class ActivityVehicle(ExoDataSource): + """Activity (distance) per vehicle per year.""" + + @dataclass + class Options(BaseOptions): + #: Transport configuration. + config: "Config | None" = None + + #: ID of the node code list. + nodes: str = "" + + options: Options + + filename = "activity-vehicle.csv" + key = Key("activity:n-t-y:vehicle") + + def __init__(self, *args, **kwargs) -> None: + self.options = self.Options.from_args(self, *args, **kwargs) + self.path = region_path_fallback(self.options.nodes, self.filename) + + def get(self) -> "AnyQuantity": + from genno.operator import load_file + + return load_file(self.path, dims=RENAME_DIMS | dict(scenario="scenario")) + + def transform(self, c: "Computer", base_key: Key) -> Key: + k = base_key + + # Convert units + c.add(k[0], "convert_units", base_key, units="Mm/year") + + # Broadcast to all scenarios and nodes + coords = ["scenario::all", "n::ex world"] + dim = ("scenario", "n") + c.add(k[1], "broadcast_wildcard2", k[0], *coords, dim=dim) + + # Select values for the current scenario; drop the 'scenario' dimension + c.add(k[2], "select", k[1], "indexers:scenario:LED") + + # Interpolate on "y" dimension + c.add(self.key, "interpolate", k[2], "y::coords", **EXTRAPOLATE) + + # TODO Broadcast technology groups → individual technology IDs + return self.key + + class IEA_Future_of_Trucks(ExoDataSource): """Retrieve IEA “Future of Trucks” data. @@ -651,12 +697,6 @@ def _input_dataflow(**kwargs) -> "Dataflow": units="Gt / km", ) -activity_ldv = _input_dataflow( - key="ldv activity:scenario-n-y:exo", - name="Activity (driving distance) per light duty vehicle", - units="km / year", -) - age_ldv = _input_dataflow( path="ldv-age", key="age:n-t-y:ldv+exo", @@ -955,7 +995,7 @@ def _output_dataflow(**kwargs) -> "Dataflow": key="pdt:n-y-t", units="dimensionless", ) -activity_vehicle = _output_dataflow( +activity_vehicle_out = _output_dataflow( id="ACTIVITY_VEHICLE", name="Vehicle activity", description='Same as the IAMC ‘variable’ code "Energy Service|Transportation".', diff --git a/message_ix_models/model/transport/disutility.py b/message_ix_models/model/transport/disutility.py index c617721fe7..24b305674b 100644 --- a/message_ix_models/model/transport/disutility.py +++ b/message_ix_models/model/transport/disutility.py @@ -3,7 +3,7 @@ from genno import Key, Quantity, quote from . import util -from .key import activity_ldv_full, exo +from .key import exo from .util import EXTRAPOLATE if TYPE_CHECKING: @@ -34,7 +34,7 @@ def prepare_computer(c: "Computer") -> None: # Divide disutility per vehicle by annual driving distance per vehicle → disutility # per vehicle-km; convert to preferred units # TODO add "cg" dimension to ldv activity - k2 = c.add(k[2], "div", k[1], activity_ldv_full) + k2 = c.add(k[2], "div", k[1], (exo.activity_vehicle + "LDV") / "t") k3 = c.add(k[3], "mul", k2, Quantity(1.0, units="vehicle / year")) k4 = c.add(k[4], "convert_units", k3, units="USD / km") diff --git a/message_ix_models/model/transport/key.py b/message_ix_models/model/transport/key.py index b808753503..55523f5084 100644 --- a/message_ix_models/model/transport/key.py +++ b/message_ix_models/model/transport/key.py @@ -7,10 +7,9 @@ from message_ix_models.report.key import GDP, PRICE_COMMODITY from message_ix_models.util.genno import Keys -from .data import LoadFactorLDV, iter_files +from .data import ActivityVehicle, LoadFactorLDV, iter_files __all__ = [ - "activity_ldv_full", "cg", "cost", "exo", @@ -144,9 +143,10 @@ #: >>> from message_ix_models.model.transport.key import exo #: >>> exo.act_non_ldv #: -exo = Keys(load_factor_ldv=LoadFactorLDV.key) +exo = Keys( + activity_vehicle=ActivityVehicle.key, + load_factor_ldv=LoadFactorLDV.key, +) for name, df in iter_files(): setattr(exo, name, df.key) - -activity_ldv_full = exo.activity_ldv / "scenario" + "full" From f27f36c78d41f3f31c48c50e275082c2d2a7a0e1 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Tue, 10 Mar 2026 14:53:55 +0100 Subject: [PATCH 40/73] Add .transport.data.Lifetime - Reads data from lifetime.csv; mirrors and generalizes code formerly in .transport.ldv.prepare_computer() - Adjust usage, docs. --- doc/transport/input.rst | 4 +- message_ix_models/model/transport/build.py | 2 +- message_ix_models/model/transport/data.py | 70 ++++++++++++++++------ message_ix_models/model/transport/key.py | 3 +- 4 files changed, 58 insertions(+), 21 deletions(-) diff --git a/doc/transport/input.rst b/doc/transport/input.rst index cd38cffc1f..7c0e32251e 100644 --- a/doc/transport/input.rst +++ b/doc/transport/input.rst @@ -136,7 +136,7 @@ Quick links to each of the data flows: :data:`~.data.input_cap_new` :data:`~.data.input_ref_ldv` :data:`~.data.input_share` -:data:`~.data.lifetime_ldv` +:class:`~.data.Lifetime` :data:`~.data.load_factor_ldv` :data:`~.data.load_factor_nonldv` :data:`~.data.mer_to_ppp` @@ -232,7 +232,7 @@ Quick links to each of the data flows: .. autodata:: message_ix_models.model.transport.data.input_cap_new .. autodata:: message_ix_models.model.transport.data.input_ref_ldv .. autodata:: message_ix_models.model.transport.data.input_share -.. autodata:: message_ix_models.model.transport.data.lifetime_ldv +.. autoclass:: message_ix_models.model.transport.data.Lifetime .. autodata:: message_ix_models.model.transport.data.load_factor_ldv The code that handles this file interpolates on the |y| dimension. diff --git a/message_ix_models/model/transport/build.py b/message_ix_models/model/transport/build.py index 9c2df37f48..4453d1e2c3 100644 --- a/message_ix_models/model/transport/build.py +++ b/message_ix_models/model/transport/build.py @@ -135,7 +135,6 @@ def add_exogenous_data(c: Computer, info: ScenarioInfo) -> None: from message_ix_models.tools.iea.web import IEA_EWEB, TRANSFORM from message_ix_models.util.sdmx import Dataflow - # Ensure that the MERtoPPP data provider is available from . import data # Added keys @@ -173,6 +172,7 @@ def add_exogenous_data(c: Computer, info: ScenarioInfo) -> None: # Miscellaneous data kw = dict(nodes=context.model.regions, config=config) data.ActivityVehicle.add_tasks(c, **kw, **c_s) + data.Lifetime.add_tasks(c, **kw, **c_s) data.LoadFactorLDV.add_tasks(c, **kw, **c_s) # Add data for MERtoPPP diff --git a/message_ix_models/model/transport/data.py b/message_ix_models/model/transport/data.py index 3a873f85ef..d86f722f78 100644 --- a/message_ix_models/model/transport/data.py +++ b/message_ix_models/model/transport/data.py @@ -17,6 +17,7 @@ import pandas as pd from genno import Computer, Key from genno.core.key import single_key +from genno.operator import load_file from ixmp.report.common import RENAME_DIMS from message_ix import make_df @@ -82,8 +83,6 @@ def __init__(self, *args, **kwargs) -> None: self.path = region_path_fallback(self.options.nodes, self.filename) def get(self) -> "AnyQuantity": - from genno.operator import load_file - return load_file(self.path, dims=RENAME_DIMS | dict(scenario="scenario")) def transform(self, c: "Computer", base_key: Key) -> Key: @@ -140,8 +139,6 @@ def __init__(self, *args, **kwargs) -> None: super().__init__() def get(self) -> "AnyQuantity": - from genno.operator import load_file - return load_file(self.path, dims=RENAME_DIMS) def transform(self, c: "Computer", base_key: Key) -> Key: @@ -188,6 +185,58 @@ def transform(self, c: "Computer", base_key: Key) -> Key: return single_key(result) +class Lifetime(ExoDataSource): + """Technical lifetime (maximum age) of vehicles. + + Values are interpolated across the model horizon. In MESSAGE(V)-Transport, this + quantity had the additional dimension of driver_type, and values for t=LDV were 20 + years for driver_type='average', 15 y for 'moderate', and 10 y for 'frequent'. + """ + + @dataclass + class Options(BaseOptions): + #: Transport configuration. + config: "Config | None" = None + + #: ID of the node code list. + nodes: str = "" + + options: Options + + filename = "lifetime.csv" + key = Key("lifetime:nl-t-yv:exo") + + def __init__(self, *args, **kwargs) -> None: + self.options = self.Options.from_args(self, *args, **kwargs) + self.path = region_path_fallback(self.options.nodes, self.filename) + + def get(self) -> "AnyQuantity": + return load_file(self.path, dims=RENAME_DIMS | dict(scenario="scenario")) + + def transform(self, c: "Computer", base_key: Key) -> Key: + k = base_key + + # Interpolate on "y" dimension + c.add(k[0], "interpolate", base_key, "yv::coords", **EXTRAPOLATE) + + # Broadcast to all scenarios and nodes + coords = ["scenario::all", "n::ex world"] + c.add(k[1], "broadcast_wildcard2", k[0], *coords, dim=("scenario", "nl")) + + # Select values for the current scenario; drop the 'scenario' dimension + c.add(k[2], "select", k[1], "indexers:scenario:LED") + + # Expand from "t" modes to all actual technologies + c.add(k[3], "call", "t::transport map", k[2]) + + # Convert to integer + # NB This is required because the MESSAGEix GAMS implementation cannot handle + # non-integer values. + c.add(self.key, lambda qty: qty.astype(int), k[3]) + + return self.key + + class MaybeAdaptR11Source(ExoDataSource): """Source of transport data, possibly adapted from R11 for other node code lists. @@ -247,8 +296,6 @@ def __init__(self, *args, **kwargs) -> None: raise NotImplementedError(msg) def get(self) -> "AnyQuantity": - from genno.operator import load_file - return load_file(self.path, dims=self.dims, name=self.options.measure) def __repr__(self) -> str: @@ -319,8 +366,6 @@ def __init__(self, *args, **kwargs) -> None: raise FileNotFoundError(msg) def get(self) -> "AnyQuantity": - from genno.operator import load_file - return load_file( self.path, dims=RENAME_DIMS, name=self.key.name, units=self.units ) @@ -872,15 +917,6 @@ def _input_dataflow(**kwargs) -> "Dataflow": units="dimensionless", ) -lifetime_ldv = _input_dataflow( - key="lifetime:scenario-nl-t-yv:ldv+exo", - path="lifetime-ldv", - name="Technical lifetime (maximum age) of LDVs", - description="""Values are interpolated across the model horizon. In MESSAGE(V)- -Transport, this quantity had the additional dimension of driver_type, and values were 20 -years for driver_type='average', 15 y for 'moderate', and 10 y for 'frequent'.""", - units="year", -) load_factor_nonldv = _input_dataflow( key="load factor nonldv:t:exo", diff --git a/message_ix_models/model/transport/key.py b/message_ix_models/model/transport/key.py index 55523f5084..fd645f94cc 100644 --- a/message_ix_models/model/transport/key.py +++ b/message_ix_models/model/transport/key.py @@ -7,7 +7,7 @@ from message_ix_models.report.key import GDP, PRICE_COMMODITY from message_ix_models.util.genno import Keys -from .data import ActivityVehicle, LoadFactorLDV, iter_files +from .data import ActivityVehicle, Lifetime, LoadFactorLDV, iter_files __all__ = [ "cg", @@ -145,6 +145,7 @@ #: exo = Keys( activity_vehicle=ActivityVehicle.key, + lifetime=Lifetime.key, load_factor_ldv=LoadFactorLDV.key, ) From 661ec9da2936a296794f85d27436238ad84a56d9 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Tue, 10 Mar 2026 00:38:32 +0100 Subject: [PATCH 41/73] Add .transport.data.load_factor_[fp] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Rename load_factor_nonldv → load_factor_p. - Adjust usage, docs. --- doc/transport/input.rst | 12 +++++++----- message_ix_models/data/transport/load-factor-f.csv | 9 +++++++++ .../{load-factor-nonldv.csv => load-factor-p.csv} | 12 ++++++------ message_ix_models/model/transport/data.py | 14 +++++++++++--- message_ix_models/model/transport/passenger.py | 2 +- 5 files changed, 34 insertions(+), 15 deletions(-) create mode 100644 message_ix_models/data/transport/load-factor-f.csv rename message_ix_models/data/transport/{load-factor-nonldv.csv => load-factor-p.csv} (59%) diff --git a/doc/transport/input.rst b/doc/transport/input.rst index 7c0e32251e..ea47f5745a 100644 --- a/doc/transport/input.rst +++ b/doc/transport/input.rst @@ -137,8 +137,9 @@ Quick links to each of the data flows: :data:`~.data.input_ref_ldv` :data:`~.data.input_share` :class:`~.data.Lifetime` -:data:`~.data.load_factor_ldv` -:data:`~.data.load_factor_nonldv` +:data:`~.data.load_factor_f` +:data:`~.data.load_factor_p` +:class:`~.data.LoadFactorLDV` :data:`~.data.mer_to_ppp` :data:`~.data.mode_share_freight` :data:`~.data.pdt_cap_proj` @@ -233,7 +234,9 @@ Quick links to each of the data flows: .. autodata:: message_ix_models.model.transport.data.input_ref_ldv .. autodata:: message_ix_models.model.transport.data.input_share .. autoclass:: message_ix_models.model.transport.data.Lifetime -.. autodata:: message_ix_models.model.transport.data.load_factor_ldv +.. autodata:: message_ix_models.model.transport.data.load_factor_f +.. autodata:: message_ix_models.model.transport.data.load_factor_p +.. autoclass:: message_ix_models.model.transport.data.LoadFactorLDV The code that handles this file interpolates on the |y| dimension. @@ -243,8 +246,7 @@ Quick links to each of the data flows: .. todo:: Transcribe the method into this document. -.. autodata:: message_ix_models.model.transport.data.load_factor_nonldv -.. autodata:: message_ix_models.model.transport.data.mer_to_ppp + .. autodata:: message_ix_models.model.transport.data.mer_to_ppp .. autodata:: message_ix_models.model.transport.data.mode_share_freight .. _transport-pdt-cap-proj: diff --git a/message_ix_models/data/transport/load-factor-f.csv b/message_ix_models/data/transport/load-factor-f.csv new file mode 100644 index 0000000000..31ced11610 --- /dev/null +++ b/message_ix_models/data/transport/load-factor-f.csv @@ -0,0 +1,9 @@ +# Load factor of freight vehicles +# +# Units: tonne / vehicle +# +# Source: placeholder +# +technology, value +F RAIL, 1.0 +F ROAD, 1.0 diff --git a/message_ix_models/data/transport/load-factor-nonldv.csv b/message_ix_models/data/transport/load-factor-p.csv similarity index 59% rename from message_ix_models/data/transport/load-factor-nonldv.csv rename to message_ix_models/data/transport/load-factor-p.csv index f515cb530f..1ce93ba8d5 100644 --- a/message_ix_models/data/transport/load-factor-nonldv.csv +++ b/message_ix_models/data/transport/load-factor-p.csv @@ -1,4 +1,4 @@ -# Load factor (occupancy) of non-LDV vehicles +# Load factor (occupancy) of passenger vehicles except LDVs # # Source: transcribed from MESSAGE (V) Transport .chn files # Original source unknown. @@ -7,8 +7,8 @@ # technology, value # Urban public rail transport (agg. of metro, trams, regional trains, etc.) -# rail_pub,80 -2W,1.0 -RAIL,200 -AIR,115 -BUS,20.9 +# rail_pub, 80 +2W, 1.0 +RAIL, 200 +AIR, 115 +BUS, 20.9 diff --git a/message_ix_models/model/transport/data.py b/message_ix_models/model/transport/data.py index d86f722f78..d33c175414 100644 --- a/message_ix_models/model/transport/data.py +++ b/message_ix_models/model/transport/data.py @@ -918,9 +918,17 @@ def _input_dataflow(**kwargs) -> "Dataflow": ) -load_factor_nonldv = _input_dataflow( - key="load factor nonldv:t:exo", - name="Load factor (occupancy) of non-LDV passenger vehicles", +load_factor_f = _input_dataflow( + key="load factor:t:F+exo", + name="Load factor of freight vehicles", + path="load-factor-f.csv", + units="tonne / vehicle", +) + +load_factor_p = _input_dataflow( + key="load factor:t:P+exo", + name="Load factor (occupancy) of passenger vehicles ex LDV", + path="load-factor-p.csv", units="passenger / vehicle", ) diff --git a/message_ix_models/model/transport/passenger.py b/message_ix_models/model/transport/passenger.py index 75584dcf14..0be6541080 100644 --- a/message_ix_models/model/transport/passenger.py +++ b/message_ix_models/model/transport/passenger.py @@ -92,7 +92,7 @@ def prepare_computer(c: Computer): # keys.append(k + "emi") # Data for usage pseudo-technologies - collect("usage", usage_data, exo.load_factor_nonldv, t_modes, n, y) + collect("usage", usage_data, exo.load_factor_p, t_modes, n, y) #### NB lines below duplicated from .transport.base e_iea = Key("energy:n-y-product-flow:iea") From 7d9e7346bfa1220ef085aae9932a480b3963942b Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Tue, 10 Mar 2026 20:20:58 +0100 Subject: [PATCH 42/73] Use units "passenger / vehicle" in load-factor-ldv --- .../data/transport/R11/load-factor-ldv/SSP_2024_2.csv | 2 ++ .../data/transport/R12/load-factor-ldv/DIGSY-BEST-C.csv | 3 +-- .../data/transport/R12/load-factor-ldv/DIGSY-BEST-S.csv | 3 +-- .../data/transport/R12/load-factor-ldv/DIGSY-WORST-S.csv | 3 +-- .../data/transport/R12/load-factor-ldv/EDITS-CA.csv | 3 +-- .../data/transport/R12/load-factor-ldv/EDITS-HA.csv | 3 +-- message_ix_models/data/transport/R12/load-factor-ldv/LED.csv | 3 +-- .../data/transport/R12/load-factor-ldv/SSP_2024_1.csv | 3 +-- .../data/transport/R12/load-factor-ldv/SSP_2024_2.csv | 3 +-- .../data/transport/R12/load-factor-ldv/SSP_2024_3.csv | 3 +-- .../data/transport/R12/load-factor-ldv/SSP_2024_4.csv | 3 +-- .../data/transport/R12/load-factor-ldv/SSP_2024_5.csv | 3 +-- .../data/transport/R14/load-factor-ldv/SSP_2024_2.csv | 2 ++ message_ix_models/model/transport/data.py | 4 +--- 14 files changed, 16 insertions(+), 25 deletions(-) diff --git a/message_ix_models/data/transport/R11/load-factor-ldv/SSP_2024_2.csv b/message_ix_models/data/transport/R11/load-factor-ldv/SSP_2024_2.csv index 713cce77a5..9e37d193bd 100644 --- a/message_ix_models/data/transport/R11/load-factor-ldv/SSP_2024_2.csv +++ b/message_ix_models/data/transport/R11/load-factor-ldv/SSP_2024_2.csv @@ -4,6 +4,8 @@ # Original source unknown. The values appear to assume similarity # between certain regions. # +# Units: passenger / vehicle +# scenario, node, year, value SSP(2024).2, R11_AFR, 2020, 1.807 SSP(2024).2, R11_CPA, 2020, 1.892 diff --git a/message_ix_models/data/transport/R12/load-factor-ldv/DIGSY-BEST-C.csv b/message_ix_models/data/transport/R12/load-factor-ldv/DIGSY-BEST-C.csv index b91f8852c9..d94f20f82a 100644 --- a/message_ix_models/data/transport/R12/load-factor-ldv/DIGSY-BEST-C.csv +++ b/message_ix_models/data/transport/R12/load-factor-ldv/DIGSY-BEST-C.csv @@ -2,8 +2,7 @@ # # Source: Constructed by @r-aneeque # -# Units: dimensionless -# (Implicitly passengers per vehicle.) +# Units: passenger / vehicle # node, year, value R12_AFR, 2020, 2.10 diff --git a/message_ix_models/data/transport/R12/load-factor-ldv/DIGSY-BEST-S.csv b/message_ix_models/data/transport/R12/load-factor-ldv/DIGSY-BEST-S.csv index 7012c14115..790439373a 100644 --- a/message_ix_models/data/transport/R12/load-factor-ldv/DIGSY-BEST-S.csv +++ b/message_ix_models/data/transport/R12/load-factor-ldv/DIGSY-BEST-S.csv @@ -2,8 +2,7 @@ # # Source: Constructed by @r-aneeque # -# Units: dimensionless -# (Implicitly passengers per vehicle.) +# Units: passenger / vehicle # node, year, value R12_AFR, 2020, 2.10 diff --git a/message_ix_models/data/transport/R12/load-factor-ldv/DIGSY-WORST-S.csv b/message_ix_models/data/transport/R12/load-factor-ldv/DIGSY-WORST-S.csv index 8306a2f26a..bae0ad540b 100644 --- a/message_ix_models/data/transport/R12/load-factor-ldv/DIGSY-WORST-S.csv +++ b/message_ix_models/data/transport/R12/load-factor-ldv/DIGSY-WORST-S.csv @@ -2,8 +2,7 @@ # # Source: Constructed by @r-aneeque # -# Units: dimensionless -# (Implicitly passengers per vehicle.) +# Units: passenger / vehicle # node, year, value R12_AFR, 2020, 2.1 diff --git a/message_ix_models/data/transport/R12/load-factor-ldv/EDITS-CA.csv b/message_ix_models/data/transport/R12/load-factor-ldv/EDITS-CA.csv index 99b145584e..a5b3427ec1 100644 --- a/message_ix_models/data/transport/R12/load-factor-ldv/EDITS-CA.csv +++ b/message_ix_models/data/transport/R12/load-factor-ldv/EDITS-CA.csv @@ -5,8 +5,7 @@ # > PASTA data-20250822T114700Z-1-001 > PASTA data # > load-factor-ldv.csv, rows with scenario="EDITS_BAU" # -# Units: dimensionless -# (Implicitly passengers per vehicle.) +# Units: passenger / vehicle # node, year, value R12_AFR, 2015, 2.206028607 diff --git a/message_ix_models/data/transport/R12/load-factor-ldv/EDITS-HA.csv b/message_ix_models/data/transport/R12/load-factor-ldv/EDITS-HA.csv index 6a6f417cb7..58ad6c1317 100644 --- a/message_ix_models/data/transport/R12/load-factor-ldv/EDITS-HA.csv +++ b/message_ix_models/data/transport/R12/load-factor-ldv/EDITS-HA.csv @@ -5,8 +5,7 @@ # > PASTA data-20250822T114700Z-1-001 > PASTA data # > load-factor-ldv.csv, rows with scenario="EDITS_HWL_v_0.01" # -# Units: dimensionless -# (Implicitly passengers per vehicle.) +# Units: passenger / vehicle # node, year, value R12_AFR, 2015, 2.206012863 diff --git a/message_ix_models/data/transport/R12/load-factor-ldv/LED.csv b/message_ix_models/data/transport/R12/load-factor-ldv/LED.csv index a1ed781ba9..3a58b28a36 100644 --- a/message_ix_models/data/transport/R12/load-factor-ldv/LED.csv +++ b/message_ix_models/data/transport/R12/load-factor-ldv/LED.csv @@ -3,8 +3,7 @@ # Source: Duplicate of R11/load-factor-ldv.csv; R12_CHN and R12_RCPA values # filled from R11_CPA. # -# Units: dimensionless -# (Implicitly passengers per vehicle.) +# Units: passenger / vehicle # node, year, value # “Global South” diff --git a/message_ix_models/data/transport/R12/load-factor-ldv/SSP_2024_1.csv b/message_ix_models/data/transport/R12/load-factor-ldv/SSP_2024_1.csv index 1c75249ec8..d98a5b828d 100644 --- a/message_ix_models/data/transport/R12/load-factor-ldv/SSP_2024_1.csv +++ b/message_ix_models/data/transport/R12/load-factor-ldv/SSP_2024_1.csv @@ -3,8 +3,7 @@ # Source: Duplicate of R11/load-factor-ldv.csv; R12_CHN and R12_RCPA values # filled from R11_CPA. # -# Units: dimensionless -# (Implicitly passengers per vehicle.) +# Units: passenger / vehicle # node, year, value R12_AFR, 2020, 2.1 diff --git a/message_ix_models/data/transport/R12/load-factor-ldv/SSP_2024_2.csv b/message_ix_models/data/transport/R12/load-factor-ldv/SSP_2024_2.csv index f6c902a02b..0f09c53ec8 100644 --- a/message_ix_models/data/transport/R12/load-factor-ldv/SSP_2024_2.csv +++ b/message_ix_models/data/transport/R12/load-factor-ldv/SSP_2024_2.csv @@ -3,8 +3,7 @@ # Source: Duplicate of R11/load-factor-ldv.csv; R12_CHN and R12_RCPA values # filled from R11_CPA. # -# Units: dimensionless -# (Implicitly passengers per vehicle.) +# Units: passenger / vehicle # node, year, value R12_AFR, 2020, 2.10 diff --git a/message_ix_models/data/transport/R12/load-factor-ldv/SSP_2024_3.csv b/message_ix_models/data/transport/R12/load-factor-ldv/SSP_2024_3.csv index db6bb7d4c3..d62a804dfe 100644 --- a/message_ix_models/data/transport/R12/load-factor-ldv/SSP_2024_3.csv +++ b/message_ix_models/data/transport/R12/load-factor-ldv/SSP_2024_3.csv @@ -3,8 +3,7 @@ # Source: Duplicate of R11/load-factor-ldv.csv; R12_CHN and R12_RCPA values # filled from R11_CPA. # -# Units: dimensionless -# (Implicitly passengers per vehicle.) +# Units: passenger / vehicle # node, year, value R12_AFR, 2020, 2.1 diff --git a/message_ix_models/data/transport/R12/load-factor-ldv/SSP_2024_4.csv b/message_ix_models/data/transport/R12/load-factor-ldv/SSP_2024_4.csv index dcc5cb64a2..14ee3a469d 100644 --- a/message_ix_models/data/transport/R12/load-factor-ldv/SSP_2024_4.csv +++ b/message_ix_models/data/transport/R12/load-factor-ldv/SSP_2024_4.csv @@ -3,8 +3,7 @@ # Source: Duplicate of R11/load-factor-ldv.csv; R12_CHN and R12_RCPA values # filled from R11_CPA. # -# Units: dimensionless -# (Implicitly passengers per vehicle.) +# Units: passenger / vehicle # node, year, value R12_AFR, 2020, 2.1 diff --git a/message_ix_models/data/transport/R12/load-factor-ldv/SSP_2024_5.csv b/message_ix_models/data/transport/R12/load-factor-ldv/SSP_2024_5.csv index 35509239b1..833482ee04 100644 --- a/message_ix_models/data/transport/R12/load-factor-ldv/SSP_2024_5.csv +++ b/message_ix_models/data/transport/R12/load-factor-ldv/SSP_2024_5.csv @@ -3,8 +3,7 @@ # Source: Duplicate of R11/load-factor-ldv.csv; R12_CHN and R12_RCPA values # filled from R11_CPA. # -# Units: dimensionless -# (Implicitly passengers per vehicle.) +# Units: passenger / vehicle # node, year, value R12_AFR, 2020, 2.1 diff --git a/message_ix_models/data/transport/R14/load-factor-ldv/SSP_2024_2.csv b/message_ix_models/data/transport/R14/load-factor-ldv/SSP_2024_2.csv index 0530ef8294..d297b5d8a5 100644 --- a/message_ix_models/data/transport/R14/load-factor-ldv/SSP_2024_2.csv +++ b/message_ix_models/data/transport/R14/load-factor-ldv/SSP_2024_2.csv @@ -5,6 +5,8 @@ # - Duplicated manually from the corresponding R11 file. # - Data for R11_FSU duplicated for R14_{CAS,RUS,SCS,UBM}. # +# Units: passenger / vehicle +# scenario, node, year, value SSP(2024).2, R14_AFR, 2020, 1.807 SSP(2024).2, R14_CAS, 2020, 1.807 diff --git a/message_ix_models/model/transport/data.py b/message_ix_models/model/transport/data.py index d33c175414..555f04363b 100644 --- a/message_ix_models/model/transport/data.py +++ b/message_ix_models/model/transport/data.py @@ -385,14 +385,12 @@ class LoadFactorLDV(MultiFile): This source locates data in files named, for instance, :file:`message_ix_models/data/transport/{nodes}/load-factor-ldv/{scenario}.csv`. - - Units are implicitly passengers per vehicle. """ key = Key("load factor ldv:n-y:exo") dirname = "load-factor-ldv" - units = "dimensionless" + units = "passenger / vehicle" @property def filename(self) -> str: From eb1d47e7a4cd6ba35ab758fe77ff211e343eb263 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Tue, 10 Mar 2026 20:21:56 +0100 Subject: [PATCH 43/73] Use units "Gt * km / a" for freight activity - Add to transport/set.yaml. - Adjust checks. --- message_ix_models/data/transport/R11/freight-activity.csv | 2 +- message_ix_models/data/transport/R12/freight-activity.csv | 2 +- message_ix_models/data/transport/R14/freight-activity.csv | 2 +- message_ix_models/data/transport/set.yaml | 1 + message_ix_models/model/transport/check.py | 2 +- message_ix_models/model/transport/data.py | 2 +- 6 files changed, 6 insertions(+), 5 deletions(-) diff --git a/message_ix_models/data/transport/R11/freight-activity.csv b/message_ix_models/data/transport/R11/freight-activity.csv index b883b80b41..7af6dbef53 100644 --- a/message_ix_models/data/transport/R11/freight-activity.csv +++ b/message_ix_models/data/transport/R11/freight-activity.csv @@ -2,7 +2,7 @@ # # Source: placeholder; extracted from ADVANCE database # -# Units: Gt km +# Units: Gt km / a # node, value R11_AFR, 1210.1 diff --git a/message_ix_models/data/transport/R12/freight-activity.csv b/message_ix_models/data/transport/R12/freight-activity.csv index 55603b581b..f0e4011c0c 100644 --- a/message_ix_models/data/transport/R12/freight-activity.csv +++ b/message_ix_models/data/transport/R12/freight-activity.csv @@ -7,7 +7,7 @@ # to get estimate of R12_CHN freight demand.” # - All others: manually adapted from R11/freight-activity.csv. # -# Units: Gt km +# Units: Gt km / a # node, value R12_AFR, 730 diff --git a/message_ix_models/data/transport/R14/freight-activity.csv b/message_ix_models/data/transport/R14/freight-activity.csv index 8cd66594a2..2948b8d576 100644 --- a/message_ix_models/data/transport/R14/freight-activity.csv +++ b/message_ix_models/data/transport/R14/freight-activity.csv @@ -5,7 +5,7 @@ # - Duplicated manually from the corresponding R11 file. # - Data for R11_FSU split evenly across R14_{CAS,RUS,SCS,UBM}. # -# Units: Gt km +# Units: Gt km / a # node, value R14_AFR, 1210.1 diff --git a/message_ix_models/data/transport/set.yaml b/message_ix_models/data/transport/set.yaml index c6bbf0a7e2..898b274669 100644 --- a/message_ix_models/data/transport/set.yaml +++ b/message_ix_models/data/transport/set.yaml @@ -226,6 +226,7 @@ unit: Gp / Gv: passengers per vehicle Gt km: 10⁹ tonne-kilometre Gt * km: 10⁹ tonne-kilometre + Gt * km / a: 10⁹ tonne-kilometre per year Gv km: 10⁹ vehicle kilometre Gv * km: 10⁹ vehicle kilometre Mm / a: 10³ kilometre per year diff --git a/message_ix_models/model/transport/check.py b/message_ix_models/model/transport/check.py index d06492918d..9cfec53247 100644 --- a/message_ix_models/model/transport/check.py +++ b/message_ix_models/model/transport/check.py @@ -191,7 +191,7 @@ def run(self, obj): "pdt factor:n-y-t": (HasUnits(""),), # "fv factor:n-y": (HasUnits(""),), # Fails: this key no longer exists # "fv:n:advance": (HasUnits(""),), # Fails: only fuzzed data in message-ix-models - key.fv_cny: (HasUnits("Gt km"),), + key.fv_cny: (HasUnits("Gt km / a"),), # # Exogenous demand calculation succeeds "transport demand::ixmp": ( diff --git a/message_ix_models/model/transport/data.py b/message_ix_models/model/transport/data.py index 555f04363b..14bd8e3dc4 100644 --- a/message_ix_models/model/transport/data.py +++ b/message_ix_models/model/transport/data.py @@ -737,7 +737,7 @@ def _input_dataflow(**kwargs) -> "Dataflow": activity_freight = _input_dataflow( key="freight activity:n:exo", name="Freight transport activity", - units="Gt / km", + units="Gt km / a", ) age_ldv = _input_dataflow( From 635f3d1e1a552ce4bf1b7b174188f79ac302ea6b Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Tue, 10 Mar 2026 18:00:12 +0100 Subject: [PATCH 44/73] Use "passenger", not "capita" in stock_cap units --- message_ix_models/model/transport/data.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/message_ix_models/model/transport/data.py b/message_ix_models/model/transport/data.py index 14bd8e3dc4..bd4528ebe8 100644 --- a/message_ix_models/model/transport/data.py +++ b/message_ix_models/model/transport/data.py @@ -998,7 +998,7 @@ def _input_dataflow(**kwargs) -> "Dataflow": path="stock-cap", name="Vehicle stock per capita", description="", - units="vehicle/capita", + units="vehicle / passenger", ) t_share_ldv = _input_dataflow( From a91c3e0f2dd823ba3107527f35560236d9be443b Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Tue, 10 Mar 2026 01:47:58 +0100 Subject: [PATCH 45/73] Add 5 additional keys via .build.add_structure() --- message_ix_models/model/transport/build.py | 22 ++++++++++++++++++++++ message_ix_models/model/transport/key.py | 8 ++++++++ 2 files changed, 30 insertions(+) diff --git a/message_ix_models/model/transport/build.py b/message_ix_models/model/transport/build.py index 4453d1e2c3..942e1d160f 100644 --- a/message_ix_models/model/transport/build.py +++ b/message_ix_models/model/transport/build.py @@ -468,6 +468,28 @@ def add_structure(c: Computer) -> None: on_missing="raise", ) + # Identify the subset of periods up to and including y0 + c.add( + key.y_.historical, + lambda periods, y0: list(filter(lambda y: y < y0, periods)), + "y", + "y0", + ) + c.add( + key.y_.to_y0, + lambda periods, y0: dict(y=list(filter(lambda y: y <= y0, periods))), + "y", + "y0", + ) + # Convert duration_period to Quantity + c.add("duration_period:y", "duration_period", "info") + # Duration_period up to and including y0 + c.add("duration_period:y:to y0", "select", "duration_period:y", key.y_.to_y0) + # Groups for aggregating annual to period data + c.add(key.y_.annual_agg, "groups_y_annual", "duration_period:y") + # Indexers + c.add(key.yv.historical_idx, lambda periods: dict(yv=periods), key.y_.historical) + @minimum_version("genno 1.28") def get_computer( diff --git a/message_ix_models/model/transport/key.py b/message_ix_models/model/transport/key.py index fd645f94cc..ab1b33aa4d 100644 --- a/message_ix_models/model/transport/key.py +++ b/message_ix_models/model/transport/key.py @@ -134,6 +134,14 @@ #: Model periods. y = "y::model" +y_ = Keys( + annual_agg="y::annual agg", + historical="y::historical", + to_y0="y::to y0", +) + +yv = Keys(historical_idx="indexers:yv:historical") + #: Keys referring to loaded input data flows (exogenous data loaded from files). #: Attributes correspond to the members of :mod:`.transport.data`; see #: :doc:`/transport/input` for a complete list. From 74f2792ffe4ffccad1ff4599e7d13bb0b63f9ef8 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Tue, 10 Mar 2026 20:23:53 +0100 Subject: [PATCH 46/73] Adjust key usage in .freight.demand() - Ensure total freight demand appears at .key.fv. --- message_ix_models/model/transport/freight.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/message_ix_models/model/transport/freight.py b/message_ix_models/model/transport/freight.py index 5faaa9f77f..0441ea3aa8 100644 --- a/message_ix_models/model/transport/freight.py +++ b/message_ix_models/model/transport/freight.py @@ -91,18 +91,18 @@ def demand(c: "Computer") -> None: # Select certain modes. NB Do not drop so 't' labels can be used for 'c', next. freight_techs = ["F RAIL", "F ROAD"] - c.add(fv[5], "select", fv[4], indexers=dict(t=freight_techs)) + c.add(fv, "select", fv[4], indexers=dict(t=freight_techs)) # Relabel - c.add(fv_cny, "relabel2", fv[5], new_dims={"c": "transport {t}"}) + c.add(fv_cny, "relabel2", fv, new_dims={"c": "transport {t}"}) # Convert to ixmp format collect("demand", "as_message_df", fv_cny, **_DEMAND_KW) # Compute indices, e.g. for use in .other.prepare_computer() for t in freight_techs: - c.add(fv[5][t], "select", fv[5], indexers=dict(t=t)) - c.add(fv[f"{t} index"], "index_to", fv[5][t], literal("y"), "y0") + c.add(fv[t], "select", fv, indexers=dict(t=t)) + c.add(fv[f"{t} index"], "index_to", fv[t], literal("y"), "y0") def prepare_computer(c: "Computer") -> None: From 245007485e2843cb13b3cb3fc29ee010529f1aee Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Tue, 10 Mar 2026 01:50:44 +0100 Subject: [PATCH 47/73] Generalize code for vehicle stocks and operation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Rename .transport.stock → .transport.vehicle. - Migrate code from .ldv to .vehicle; expand and generalize. - Adjust reference in Config.modules. - Expand checks. - Adjust tests. --- message_ix_models/model/transport/check.py | 24 ++- message_ix_models/model/transport/config.py | 4 +- message_ix_models/model/transport/ldv.py | 143 +-------------- message_ix_models/model/transport/stock.py | 39 ---- message_ix_models/model/transport/testing.py | 2 +- message_ix_models/model/transport/vehicle.py | 167 ++++++++++++++++++ .../tests/model/transport/test_ldv.py | 13 +- 7 files changed, 197 insertions(+), 195 deletions(-) delete mode 100644 message_ix_models/model/transport/stock.py create mode 100644 message_ix_models/model/transport/vehicle.py diff --git a/message_ix_models/model/transport/check.py b/message_ix_models/model/transport/check.py index 9cfec53247..fe02f0597f 100644 --- a/message_ix_models/model/transport/check.py +++ b/message_ix_models/model/transport/check.py @@ -13,6 +13,7 @@ other, passenger, policy, + vehicle, ) from message_ix_models.model.transport.testing import assert_units from message_ix_models.testing.check import ( @@ -210,8 +211,6 @@ def run(self, obj): # .disutility.prepare_computer() "disutility:n-cg-t-y": (Size(dict(cg=27 * 12)),), disutility.TARGET: (ContainsDataForParameters({"input"}),), - # - "historical_new_capacity::LDV+ixmp": (HasUnits("million * v / a"),), # The following partly replicates .test_ldv.test_get_ldv_data() # NB Cannot use NoDuplicates here yet due to: # - inv_cost: 50076 duplicated keys @@ -220,17 +219,13 @@ def run(self, obj): ldv.TARGET: ( ContainsDataForParameters( { - "bound_new_capacity_lo", - "bound_new_capacity_up", "capacity_factor", "emission_factor", "fix_cost", - "historical_new_capacity", "input", "inv_cost", "output", "relation_activity", - "technical_lifetime", "var_cost", } ), @@ -263,6 +258,23 @@ def run(self, obj): # No structure in base scenarios to accommodate these values → discard HasCoords({"type_emission": ["CO2_shipping_IMO"]}, inverse=True), ), + vehicle.TARGET: ( + ContainsDataForParameters( + { + "bound_new_capacity_lo", + "bound_new_capacity_up", + "historical_new_capacity", + "capacity_factor", + "technical_lifetime", + } + ), + ), + "capacity_factor::P ex LDV+ixmp": (HasCoords({"technology": ["ICE_H_bus"]}),), + "capacity_factor::F+ixmp": (HasCoords({"technology": ["f rail electr"]}),), + "historical_new_capacity::LDV+ixmp": (HasUnits("million * v / a"),), + "technical_lifetime::vehicle+ixmp": ( + HasCoords({"technology": ["ICE_H_bus", "f rail electr"]}), + ), } CHECKS_CONDITIONAL: dict[str, dict["KeyLike", tuple[Check, ...]]] = { diff --git a/message_ix_models/model/transport/config.py b/message_ix_models/model/transport/config.py index 22d83d55d8..c450460bf2 100644 --- a/message_ix_models/model/transport/config.py +++ b/message_ix_models/model/transport/config.py @@ -188,8 +188,8 @@ class Config(ConfigHelper): #: List of modules containing model-building calculations. modules: list[str] = field( default_factory=lambda: ( - "groups demand constraint freight ikarus ldv disutility other passenger " - "data stock policy" + "data groups demand constraint freight ikarus ldv other passenger vehicle " + "disutility policy" ).split() ) diff --git a/message_ix_models/model/transport/ldv.py b/message_ix_models/model/transport/ldv.py index 01f9fd5b79..f6823c9a15 100644 --- a/message_ix_models/model/transport/ldv.py +++ b/message_ix_models/model/transport/ldv.py @@ -3,11 +3,10 @@ import logging from collections.abc import Mapping from operator import itemgetter -from typing import TYPE_CHECKING, Any, cast +from typing import TYPE_CHECKING, cast import genno from genno import Computer, Key, Keys -from genno.core.key import single_key from message_ix import make_df from sdmx.model.common import Code @@ -25,8 +24,8 @@ from . import util from .data import MaybeAdaptR11Source from .emission import ef_for_input -from .key import activity_ldv_full, bcast_tcl, bcast_y, exo -from .util import COMMON, EXTRAPOLATE, wildcard +from .key import bcast_tcl, bcast_y, exo +from .util import COMMON, wildcard if TYPE_CHECKING: from genno.types import AnyQuantity @@ -92,11 +91,12 @@ def prepare_computer(c: Computer): from . import factor + # Collect data in `TARGET` and connect to the "add transport data" key collect.computer = c + c.add("transport_data", __name__, key=TARGET) context = c.graph["context"] config: "Config" = context.transport - info = config.base_model_info # Some keys/shorthand k = Keys( @@ -144,47 +144,6 @@ def prepare_computer(c: Computer): "usage", usage_data, exo.load_factor_ldv, "cg", "n::ex world", t_ldv, "y::model" ) - ### Technical lifetime - tl, k_tl = "technical_lifetime", exo.lifetime_ldv - - # Interpolate on "yv" dimension - c.add(k_tl[0], "interpolate", k_tl, "yv::coords", **EXTRAPOLATE) - - # Broadcast to all nodes, scenarios, and LDV technologies - coords = ["scenario::all", "n::ex world", "t::LDV"] - c.add(k_tl[1], "broadcast_wildcard", k_tl[0], *coords, dim=("scenario", "nl", "t")) - - # Select values for the current scenario - c.add(k_tl[2] / "scenario", "select", k_tl[1], "indexers:scenario:LED") - - # Convert to integer - # NB This is required because the MESSAGEix GAMS implementation cannot handle non- - # integer values - c.add(k_tl[3] / "scenario", lambda qty: qty.astype(int), k_tl[2] / "scenario") - - # Convert to MESSAGE data structure - dims = dict(node_loc="nl", technology="t", year_vtg="yv") - collect(tl, "as_message_df", k_tl[3] / "scenario", name=tl, dims=dims, common={}) - - ### Capacity factor - cf, k_cf_s = "capacity_factor", exo.activity_ldv - k_cf = k_cf_s / "scenario" - # Convert units - c.add(k_cf_s[0], "convert_units", k_cf_s, units="Mm/year") - # Broadcast to all scenarios - c.add(k_cf_s[1], "broadcast_wildcard", k_cf_s[0], "scenario::all", dim="scenario") - # Select values for the current scenario - c.add(k_cf[2], "select", k_cf_s[1], "indexers:scenario:LED") - # Interpolate on "y" dimension - c.add(k_cf["full"], "interpolate", k_cf[2], "y::coords", **EXTRAPOLATE) - assert k_cf["full"] == activity_ldv_full - # Add dimension "t" indexing all LDV technologies - prev = c.add(k_cf[4] * "t", "expand_dims", k_cf["full"], "t::transport LDV") - # Broadcast y → (yV, yA) - prev = c.add(k_cf[5], "mul", prev, bcast_y.all) - # Convert to MESSAGE data structure - collect(cf, "as_message_df", prev, name=cf, dims=DIMS, common=COMMON) - # Add further keys for MESSAGE-structured data # Techno-economic attributes # Select a task for the final step that computes "tech::LDV+ixmp" @@ -206,37 +165,8 @@ def prepare_computer(c: Computer): except KeyError: k.stock = Key("") # No such file in this configuration elif config.ldv_stock_method == "B": - k.stock = single_key(c.apply(stock)) - - if k.stock: - # Convert units - c.add(k.stock[0], "convert_units", k.stock, units="million * vehicle / year") - - # historical_new_capacity: select only data prior to y₀ - kw1: dict[str, Any] = dict( - common={}, - dims=dict(node_loc="nl", technology="t", year_vtg="yv"), - name="historical_new_capacity", - ) - y_historical = list(filter(lambda y: y < info.y0, info.set["year"])) - c.add(k.stock[1], "select", k.stock[0], indexers=dict(yv=y_historical)) - collect(kw1["name"], "as_message_df", k.stock[1], **kw1) - - # CAP_NEW/bound_new_capacity_{lo,up} - # - Select only data from y₀ and later. - # - Discard values for ICE_conv. - # TODO Do not hard code this label; instead, identify the technology with the - # largest share and avoid setting constraints on it. - # - Add both upper and lower constraints to ensure the solution contains exactly - # the given value. - c.add(k.stock[2], "select", k.stock[0], indexers=dict(yv=info.Y)) - indexers = dict(t=["ICE_conv"]) - c.add(k.stock[3], "select", k.stock[2], indexers=indexers, inverse=True) - for kw1["name"] in map("bound_new_capacity_{}".format, ("lo", "up")): - collect(kw1["name"], "as_message_df", k.stock[3], **kw1) - - # Add the data to the target scenario - c.add("transport_data", __name__, key=TARGET) + # Now handled in .vehicle + pass def prepare_tech_econ( @@ -348,65 +278,6 @@ def get_dummy(context) -> "ParameterData": return data -def stock(c: Computer, *, margin: float = 0.2) -> Key: - """Prepare `c` to compute base-period stock and historical sales. - - Parameters - ---------- - margin : - Fractional margin by which to increase the resulting sales values. Because these - values are used to compute ``historical_new_capacity`` and - ``bound_new_capacity_{lo,up}``, this relaxes the resulting constraints on LDV - technologies in the first model period. - """ - from .key import ldv_ny - - k = Keys(stock="stock:n-y:LDV", sales="sales:n-t-y:LDV", result="sales:nl-t-yv:LDV") - - # - Divide total LDV activity by (1) annual driving distance per vehicle and (2) - # load factor (occupancy) to obtain implied stock. - # - Correct units: "load factor ldv:n-y" is dimensionless, should be - # passenger/vehicle - # - Select only the base-period value. - c.add(k.stock[0], "div", ldv_ny + "total", activity_ldv_full) - c.add(k.stock[1], "div", k.stock[0], exo.load_factor_ldv / "scenario") - c.add(k.stock[2], "div", k.stock[1], genno.Quantity(1.0, units="passenger/vehicle")) - c.add(k.stock[3] / "y", "select", k.stock[2], "y0::coord") - - # Multiply by exogenous technology shares to obtain stock with (n, t) dimensions - c.add(k.stock, "mul", k.stock[3] / "y", exo.t_share_ldv) - - # TODO Move the following 4 calls to .build.add_structure() or similar - # Identify the subset of periods up to and including y0 - c.add( - "y::to y0", - lambda periods, y0: dict(y=list(filter(lambda y: y <= y0, periods))), - "y", - "y0", - ) - # Convert duration_period to Quantity - c.add("duration_period:y", "duration_period", "info") - # Duration_period up to and including y0 - c.add("duration_period:y:to y0", "select", "duration_period:y", "y::to y0") - # Groups for aggregating annual to period data - c.add("y::annual agg", "groups_y_annual", "duration_period:y") - - # Fraction of sales in preceding years (annual, not MESSAGE 'year' referring to - # multi-year periods) - c.add(k.sales["fraction"], "sales_fraction_annual", exo.age_ldv) - # Absolute sales in preceding years - c.add(k.sales["annual"], "mul", k.stock, k.sales["fraction"], 1.0 + margin) - # Aggregate to model periods; total sales across the period - c.add(k.sales["total"], "aggregate", k.sales["annual"], "y::annual agg", keep=False) - # Divide by duration_period for the equivalent of CAP_NEW/historical_new_capacity - c.add(k.sales, "div", k.sales["total"], "duration_period:y") - - # Rename dimensions to match those expected in prepare_computer(), above - c.add(k.result, "rename_dims", k.sales, name_dict={"n": "nl", "y": "yv"}) - - return k.result - - def usage_data( load_factor: "AnyQuantity", cg: list["Code"], diff --git a/message_ix_models/model/transport/stock.py b/message_ix_models/model/transport/stock.py deleted file mode 100644 index 16681d76ce..0000000000 --- a/message_ix_models/model/transport/stock.py +++ /dev/null @@ -1,39 +0,0 @@ -"""First-period stock of non-LDV modes.""" - -import logging -from typing import TYPE_CHECKING - -from genno import Key - -from . import util -from .key import exo, pop - -if TYPE_CHECKING: - from genno import Computer - -log = logging.getLogger(__name__) - -Si = "stock+ixmp" -TARGET = f"transport::{Si}" - - -def prepare_computer(c: "Computer") -> None: - # total stock = stock per capita × total population - stock_total = exo.stock_cap - "cap" - c[stock_total] = "mul", exo.stock_cap, pop - - # Convert to data for MESSAGE parameters "bound_total_capacity_{lo,up}" - keys = [] - kw = dict(dims=util.DIMS | dict(node_loc="n", year_act="y"), common=util.COMMON) - for par_name in "bound_total_capacity_lo", "bound_total_capacity_up": - keys.append(Key(par_name, (), Si)) - c[keys[-1]] = "as_message_df", stock_total, dict(name=par_name) | kw - - # Merge parameter data - c[TARGET] = "merge_data", *keys - - log.warning(f"Disabled: add {__name__} data") - return - - # Connect `TARGET` to the "add transport data" key - c.add("transport_data", __name__, key=TARGET) diff --git a/message_ix_models/model/transport/testing.py b/message_ix_models/model/transport/testing.py index 7a27e8eb29..de2a170abe 100644 --- a/message_ix_models/model/transport/testing.py +++ b/message_ix_models/model/transport/testing.py @@ -41,7 +41,7 @@ reason="Currently only possible with regions=R12 input data/config", ), 3: pytest.mark.xfail( - raises=NotImplementedError, + raises=FileNotFoundError, reason="Missing ISR/mer-to-ppp.csv + not supported by MaybeAdaptR11Source", ), 4: pytest.mark.xfail(reason="Currently unsupported"), diff --git a/message_ix_models/model/transport/vehicle.py b/message_ix_models/model/transport/vehicle.py new file mode 100644 index 0000000000..b53728e6fb --- /dev/null +++ b/message_ix_models/model/transport/vehicle.py @@ -0,0 +1,167 @@ +"""Operational parameters (capacity factor, technical lifetime) and stock of vehicles. + +Some calculations for LDVs are more complex, and are handled in :mod:`.transport.ldv`. +""" + +import logging +from typing import TYPE_CHECKING, Any + +from genno import Key, Keys + +from message_ix_models.util.genno import Collector + +from .key import bcast_y, exo, fv, ldv_ny, pdt_nyt, y_, yv +from .util import COMMON, DIMS + +if TYPE_CHECKING: + from genno import Computer + + from message_ix_models.model.transport import Config + +log = logging.getLogger(__name__) + +# Shorthand +Vi = "vehicle+ixmp" + +#: Target key that collects all data generated in this module. +TARGET = f"transport::{Vi}" + + +collect = Collector(TARGET, "{}+ixmp".format) + + +def prepare_computer(c: "Computer") -> None: + # Collect data in `TARGET` and connect to the "add transport data" key + collect.computer = c + c.add("transport_data", __name__, key=TARGET) + + context = c.graph["context"] + techs = context.transport.spec.add.set["technology"] + k = exo.activity_vehicle + + for mode in "F", "P ex LDV", "LDV": + # Select only the "t" dimension coords according to `mode` + mode_code = techs[techs.index(mode)] + modes = ["LDV"] if mode == "LDV" else list(map(str, mode_code.child)) + + # One of the sums is used in .disutility.prepare_computer() + c.add(k[mode], "select", k, indexers={"t": modes}, sums=True) + + # Further operations based on k[mode] + capacity_factor(c, mode) + stock(c, mode) + + # Add data for MESSAGE parameter ``technical_lifetime`` + tl = "technical_lifetime" + # Convert to MESSAGE data structure + collect( + f"{tl}::vehicle", "as_message_df", exo.lifetime, name=tl, dims=DIMS, common={} + ) + + # # total stock = stock per capita × total population + # stock_total = exo.stock_cap - "cap" + # c[stock_total] = "mul", exo.stock_cap, pop + # + # # Convert to data for MESSAGE parameters "bound_total_capacity_{lo,up}" + # keys = [] + # kw = dict(dims=util.DIMS | dict(node_loc="n", year_act="y"), common=util.COMMON) + # for par_name in "bound_total_capacity_lo", "bound_total_capacity_up": + # keys.append(Key(par_name, (), Vi)) + # c[keys[-1]] = "as_message_df", stock_total, dict(name=par_name) | kw + + +def capacity_factor(c: "Computer", mode: str) -> None: + """Add data for MESSAGE parameter ``capacity_factor``.""" + cf = "capacity_factor" + k = Key(cf, exo.activity_vehicle.dims, mode) + + # Expand from "t" modes to all actual technologies + c.add(k[0], "call", "t::transport map", exo.activity_vehicle[mode]) + + # Broadcast y → (yV, yA) + prev = c.add(k[1], "mul", k[0], bcast_y.all) + + # Convert to MESSAGE data structure + dims = DIMS | dict(node_loc="n") + collect(f"{cf}::{mode}", "as_message_df", prev, name=cf, dims=dims, common=COMMON) + + +def stock(c: "Computer", mode: str, *, margin: float = 0.2) -> None: + """Prepare `c` to compute base-period stock and historical sales for `mode`. + + Parameters + ---------- + margin : + Fractional margin by which to increase the resulting sales values. Because these + values are used to compute ``historical_new_capacity`` and + ``bound_new_capacity_{lo,up}``, this relaxes the resulting constraints on LDV + technologies in the first model period. + """ + context = c.graph["context"] + config: "Config" = context.transport + info = config.base_model_info + + k = Keys( + stock=f"stock:n-t-y:{mode}", + sales_nty=f"sales:n-t-y:{mode}", + sales=f"sales:nl-t-yv:{mode}", + ) + + k_total_activity, k_load_factor = { + "F": (fv, exo.load_factor_f), + "P ex LDV": (pdt_nyt, exo.load_factor_p), + "LDV": (ldv_ny + "total", exo.load_factor_ldv), + }[mode] + + # - Divide total activity by (1) annual driving distance per vehicle and (2) load + # factor (occupancy) to obtain implied stock. + # - Correct units: "load factor ldv:n-y" is dimensionless, should be + # passenger/vehicle + # - Select only the base-period value. + c.add(k.stock[0], "div", k_total_activity, exo.activity_vehicle[mode]) + c.add(k.stock[1], "div", k.stock[0], k_load_factor) + c.add(k.stock[2] / "y", "select", k.stock[1], "y0::coord", sums=True) + + if mode != "LDV": + return + + # Multiply by exogenous technology shares to obtain stock with (n, t) dimensions + c.add(k.stock, "mul", k.stock[2] / ("t", "y"), exo.t_share_ldv) + + # Fraction of sales in preceding years (annual, not MESSAGE 'year' referring to + # multi-year periods) + c.add(k.sales_nty[0], "sales_fraction_annual", exo.age_ldv) + # Absolute sales in preceding years + c.add(k.sales_nty[1], "mul", k.stock, k.sales_nty[0], 1.0 + margin) + # Aggregate to model periods; total sales across the period + c.add(k.sales_nty[2], "aggregate", k.sales_nty[1], y_.annual_agg, keep=False) + # Divide by duration_period for the equivalent of CAP_NEW/historical_new_capacity + c.add(k.sales_nty, "div", k.sales_nty[2], "duration_period:y") + + # Rename dimensions to match those expected in prepare_computer(), above + c.add(k.sales, "rename_dims", k.sales_nty, name_dict={"n": "nl", "y": "yv"}) + + # Convert units + c.add(k.sales[0], "convert_units", k.sales, units="million * vehicle / year") + + # historical_new_capacity: select only data prior to y₀ + kw: dict[str, Any] = dict( + common={}, + dims=dict(node_loc="nl", technology="t", year_vtg="yv"), + name="historical_new_capacity", + ) + c.add(k.sales[1], "select", k.sales[0], yv.historical_idx) + collect(f"{kw['name']}::{mode}", "as_message_df", k.sales[1], **kw) + + # CAP_NEW/bound_new_capacity_{lo,up} + # - Select only data from y₀ and later. + # - Discard values for ICE_conv. + # TODO Do not hard code this label; instead, identify the technology with the + # largest share and avoid setting constraints on it. + # - Add both upper and lower constraints to ensure the solution contains exactly + # the given value. + c.add(k.sales[2], "select", k.sales[0], indexers=dict(yv=info.Y)) + indexers = dict(t=["ICE_conv"]) + c.add(k.sales[3], "select", k.sales[2], indexers=indexers, inverse=True) + for kw["name"] in map("bound_new_capacity_{}".format, ("lo", "up")): + collect(f"{kw['name']}::{mode}", "as_message_df", k.sales[3], **kw) diff --git a/message_ix_models/tests/model/transport/test_ldv.py b/message_ix_models/tests/model/transport/test_ldv.py index 0656b2a1fe..fb75a7c047 100644 --- a/message_ix_models/tests/model/transport/test_ldv.py +++ b/message_ix_models/tests/model/transport/test_ldv.py @@ -54,16 +54,7 @@ def test_get_ldv_data(tmp_path, test_context, dummy_LDV, regions, years) -> None # TODO Merge the following with test_build.test_debug() using Check objects # Data are returned for the following parameters - exp_pars = { - "bound_new_capacity_lo", - "bound_new_capacity_up", - "capacity_factor", - "historical_new_capacity", - "input", - "output", - "technical_lifetime", - "var_cost", - } + exp_pars = {"capacity_factor", "input", "output", "var_cost"} if not dummy_LDV: exp_pars |= { "emission_factor", @@ -139,7 +130,7 @@ def include(arg): # No missing entries assert not df.isna().any(axis=None), df.tostring() - if "year_vtg" not in df.columns: + if "year_vtg" not in df.columns or par_name == "capacity_factor": continue # Data covers at least these periods From 43fa630c08b2067ef43a442476c725e88e5de955 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Tue, 10 Mar 2026 20:48:35 +0100 Subject: [PATCH 48/73] =?UTF-8?q?Mark=20.transport.material=20for=20messag?= =?UTF-8?q?e-ix=20=E2=89=A53.12?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also mark tests. --- message_ix_models/model/transport/material.py | 2 ++ message_ix_models/testing/__init__.py | 6 ++++++ message_ix_models/tests/model/transport/test_build.py | 4 +++- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/message_ix_models/model/transport/material.py b/message_ix_models/model/transport/material.py index f716fa1c06..5bb2df770f 100644 --- a/message_ix_models/model/transport/material.py +++ b/message_ix_models/model/transport/material.py @@ -17,6 +17,7 @@ from genno import Key, Keys from genno.core.key import single_key +from message_ix_models.util import minimum_version from message_ix_models.util.genno import Collector from . import key, util @@ -110,6 +111,7 @@ def get_groups(config: "Config") -> dict[str, dict[str, list[str]]]: return dict(c=c_groups, t=t_groups) +@minimum_version("message_ix 3.11.2.dev0") # NB Actually 3.12 def prepare_computer(c: "Computer") -> None: """Prepare `c` to calculate and add data for materiality of transport.""" # Retrieve transport configuration diff --git a/message_ix_models/testing/__init__.py b/message_ix_models/testing/__init__.py index 18a779d4b8..3432950d6f 100644 --- a/message_ix_models/testing/__init__.py +++ b/message_ix_models/testing/__init__.py @@ -20,6 +20,7 @@ import pytest import sdmx.exceptions from ixmp import config as ixmp_config +from packaging.version import Version from message_ix_models import util from message_ix_models.model import snapshot @@ -78,6 +79,11 @@ # 11: pytest.mark.timeout( # 600, method="thread" if platform.system() == "Windows" else "thread" # ), + 12: pytest.mark.xfail( + Version(version("message_ix")) < Version("3.12"), + reason="Requires MESSAGE cap-comm parameters, only available in message-ix " + ">=3.12", + ), "#375": pytest.mark.flaky( reruns=3, rerun_delay=2, diff --git a/message_ix_models/tests/model/transport/test_build.py b/message_ix_models/tests/model/transport/test_build.py index 1a3b8fcdad..974615a635 100644 --- a/message_ix_models/tests/model/transport/test_build.py +++ b/message_ix_models/tests/model/transport/test_build.py @@ -143,7 +143,9 @@ def test_bare_res( ("R12", "B", dict(code="LED-SSP2")), ("R12", "B", dict(code="EDITS-CA")), ("R12", "B", dict(code="DIGSY-BEST-C")), - pytest.param("R12", "B", dict(code="SSP2", extra_modules=["material"])), + pytest.param( + "R12", "B", dict(code="SSP2", extra_modules=["material"]), marks=MARK[12] + ), # param("R14", "B", {}, marks=MARK[9]), # param("ISR", "A", {}, marks=MARK[3]), ), From efe66d3af75b947a9f11909da4adda0a16d598f8 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Tue, 10 Mar 2026 20:59:12 +0100 Subject: [PATCH 49/73] Adjust test marks for #471 --- message_ix_models/model/transport/testing.py | 3 +-- message_ix_models/tests/model/transport/test_build.py | 2 +- message_ix_models/tests/model/transport/test_demand.py | 1 + message_ix_models/tests/model/transport/test_report.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/message_ix_models/model/transport/testing.py b/message_ix_models/model/transport/testing.py index de2a170abe..1b22ac86f1 100644 --- a/message_ix_models/model/transport/testing.py +++ b/message_ix_models/model/transport/testing.py @@ -62,8 +62,7 @@ ), "gh": lambda f: pytest.mark.xfail( condition=GHA, - reason=f"Temporary, for https://github.com/iiasa/message-ix-models/pull/{f}:" - " fails on GHA, but not locally", + reason=f"Temporary, for https://github.com/iiasa/message-ix-models/pull/{f}", ), } diff --git a/message_ix_models/tests/model/transport/test_build.py b/message_ix_models/tests/model/transport/test_build.py index 974615a635..ffbb92d315 100644 --- a/message_ix_models/tests/model/transport/test_build.py +++ b/message_ix_models/tests/model/transport/test_build.py @@ -81,7 +81,7 @@ def scenario_code() -> Iterator["Code"]: False, "IKARUS", False, - marks=[mark.slow, make_mark[2](genno.ComputationError)], + marks=[mark.slow, make_mark[2](RuntimeError)], ), # Pending iiasa/message_data#190 param("ISR", "A", True, None, False, marks=MARK[3]), diff --git a/message_ix_models/tests/model/transport/test_demand.py b/message_ix_models/tests/model/transport/test_demand.py index 0c0720ef17..424441d1db 100644 --- a/message_ix_models/tests/model/transport/test_demand.py +++ b/message_ix_models/tests/model/transport/test_demand.py @@ -234,6 +234,7 @@ def test_urban_rural_shares(test_context, tmp_path, regions, years, pop_scen): assert set(["UR+SU", "RU"]) == set(result.coords["area_type"].values) +@make_mark["gh"](471) @MARK["#375"] @build.get_computer.minimum_version @workflow.generate.minimum_version diff --git a/message_ix_models/tests/model/transport/test_report.py b/message_ix_models/tests/model/transport/test_report.py index 561d2727d2..8822fba3ee 100644 --- a/message_ix_models/tests/model/transport/test_report.py +++ b/message_ix_models/tests/model/transport/test_report.py @@ -136,7 +136,7 @@ def test_debug( @pytest.mark.parametrize( "regions, years", ( - param("R11", "A", marks=make_mark[2](ValueError)), + param("R11", "A", marks=make_mark[2](RuntimeError)), ("R12", "B"), param("R14", "A", marks=MARK[9]), param("ISR", "A", marks=MARK[3]), From 1567034dc3320948c9074bea3fd8d4a426b232c6 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Wed, 1 Apr 2026 11:04:33 +0200 Subject: [PATCH 50/73] Improve ConfigHelper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Omit non-dataclass members of __dict__, such as "__weakref__", from ._fields() - Rename ._munge_dict() → ._canonicalize(). - Accept an Exception subclass instead of fail="raise" string. - Add __iter__ as a helper for .update(). - Use ._canonicalize() in .update(). - Accept a single positional arg to .update(). - Drop unused .read_file(…, fail=…) kwarg. - Adjust, simplify, and type hint tests. --- .../tests/model/transport/test_config.py | 8 +- message_ix_models/tests/util/test_config.py | 102 +++++++++--------- message_ix_models/util/config.py | 55 ++++++---- 3 files changed, 91 insertions(+), 74 deletions(-) diff --git a/message_ix_models/tests/model/transport/test_config.py b/message_ix_models/tests/model/transport/test_config.py index b468fc42b1..0fa51e4670 100644 --- a/message_ix_models/tests/model/transport/test_config.py +++ b/message_ix_models/tests/model/transport/test_config.py @@ -1,3 +1,5 @@ +from collections.abc import Iterator + import pytest from message_ix_models import Context @@ -39,9 +41,13 @@ class TestConfig: @pytest.fixture - def c(self): + def c(self) -> Iterator[Config]: yield Config() + def test_fields(self, c: Config) -> None: + """Settable class property included in :meth:`.ConfigHelper._fields`.""" + assert {"code"} & c._fields() + @pytest.mark.parametrize("input, expected", SSP) def test_ssp0(self, input, expected): """Set SSP through the constructor.""" diff --git a/message_ix_models/tests/util/test_config.py b/message_ix_models/tests/util/test_config.py index 0d77cf21fb..f883652243 100644 --- a/message_ix_models/tests/util/test_config.py +++ b/message_ix_models/tests/util/test_config.py @@ -1,68 +1,70 @@ from dataclasses import dataclass, field +from pathlib import Path import pytest from message_ix_models.util.config import ConfigHelper -class TestConfigHelper: - @pytest.fixture - def cls(self) -> type: - """A class which inherits from ConfigHelper.""" +@dataclass +class C1(ConfigHelper): + """A class which inherits from ConfigHelper.""" - @dataclass - class Config(ConfigHelper): - foo_1: int = 1 - foo_2: str = "" - foo_3: bool = True + foo_1: int = 1 + foo_2: str = "" + foo_3: bool = True - return Config - @pytest.fixture - def cls2(self, cls) -> type: - """A class with an attribute.""" +@dataclass +class C2: + """NOT a ConfigHelper subclass.""" + + baz_1: int = 1 + baz_2: int = 2 - @dataclass - class Config3: - """NOT a ConfigHelper subclass.""" - baz_1: int = 1 - baz_2: int = 2 +@dataclass +class C3(ConfigHelper): + """A class with a plain attribute and 2 instances of classes.""" - @dataclass - class Config2(ConfigHelper): - bar_1: float = 0.01 - subconfig_a: cls = field(default_factory=cls) # type: ignore [valid-type] - subconfig_b: Config3 = field(default_factory=Config3) + bar_1: float = 0.01 + subconfig_a: C1 = field(default_factory=C1) + subconfig_b: C2 = field(default_factory=C2) - return Config2 +class TestConfigHelper: @pytest.fixture - def c(self, cls): - return cls(foo_1=99, foo_2="bar", foo_3=False) + def c(self) -> C1: + return C1(foo_1=99, foo_2="bar", foo_3=False) @pytest.fixture - def c2(self, cls, cls2): - result = cls2(bar_1=3.14, subconfig_a=cls(foo_1=99, foo_2="bar", foo_3=False)) + def c2(self) -> C3: + result = C3(bar_1=3.14, subconfig_a=C1(foo_1=99, foo_2="bar", foo_3=False)) result.subconfig_b.baz_1 = 2 result.subconfig_b.baz_2 = 1 return result - def test_canonical_name(self, cls): - assert "foo_1" == cls._canonical_name("foo 1") - assert "foo_2" == cls._canonical_name("foo-2") - assert "foo_3" == cls._canonical_name("foo_3") - assert None is cls._canonical_name("foo 4") + def test_canonical_name(self) -> None: + assert "foo_1" == C1._canonical_name("foo 1") + assert "foo_2" == C1._canonical_name("foo-2") + assert "foo_3" == C1._canonical_name("foo_3") + assert None is C1._canonical_name("foo 4") - def test_from_dict(self, cls, c): + def test_from_dict(self, c: C1) -> None: values = {"foo 1": 99, "foo-2": "bar", "foo_3": False} - assert c == cls.from_dict({"foo 1": 99, "foo-2": "bar", "foo_3": False}) + assert c == C1.from_dict({"foo 1": 99, "foo-2": "bar", "foo_3": False}) values.update(foo_4=3.14) with pytest.raises(ValueError): - cls.from_dict(values) - - def test_read_file(self, caplog, tmp_path, cls, cls2, c, c2): + C1.from_dict(values) + + def test_read_file( + self, + caplog: pytest.LogCaptureFixture, + tmp_path: Path, + c: C1, + c2: C3, + ) -> None: # Write a YAML snippet to file yaml_path = tmp_path.joinpath("config.yaml") yaml_path.write_text( @@ -77,16 +79,10 @@ def test_read_file(self, caplog, tmp_path, cls, cls2, c, c2): """ ) - obj1 = cls() + obj1 = C1() # Method runs - obj1.read_file(yaml_path, fail=False) - # Values are read - assert c == obj1, obj1 - # Messages are logged - assert [ - "Config has no attribute for file section 'foo_4'; ignored" - ] == caplog.messages - caplog.clear() + with pytest.raises(ValueError, match="no attribute for file section 'foo_4'"): + obj1.read_file(yaml_path) yaml_path.write_text( """ @@ -101,9 +97,9 @@ def test_read_file(self, caplog, tmp_path, cls, cls2, c, c2): """ ) - obj2 = cls2() + obj2 = C3() # Method runs - obj2.read_file(yaml_path, fail=False) + obj2.read_file(yaml_path) # Values are read assert c2 == obj2, obj2 @@ -116,22 +112,22 @@ def test_read_file(self, caplog, tmp_path, cls, cls2, c, c2): } """ ) - obj3 = cls() + obj3 = C1() # Method runs obj3.read_file(json_path) # Values are read assert c == obj3, obj3 - obj4 = cls() + obj4 = C1() with pytest.raises(NotImplementedError): obj4.read_file(yaml_path.with_suffix(".xlsx")) - def test_replace(self, c): + def test_replace(self, c: C1) -> None: result = c.replace(foo_2="baz") assert result is not c assert "baz" == result.foo_2 - def test_update(self, c): + def test_update(self, c: C1) -> None: """:meth:`.ConfigHelper.update` raises AttributeError.""" with pytest.raises(AttributeError): c.update(foo_4="") diff --git a/message_ix_models/util/config.py b/message_ix_models/util/config.py index a57e3b5ed8..446e255c8e 100644 --- a/message_ix_models/util/config.py +++ b/message_ix_models/util/config.py @@ -1,7 +1,7 @@ import logging import os import pickle -from collections.abc import Mapping, MutableMapping, Sequence +from collections.abc import Iterator, Mapping, MutableMapping, Sequence from dataclasses import dataclass, field, fields, is_dataclass, replace from hashlib import blake2s from pathlib import Path @@ -67,13 +67,13 @@ class ConfigHelper: legible ways—e.g. "attribute name" or “attribute-name” instead of "attribute_name"— in configuration files and/or code. - It also add :meth:`hexdigest`. + It also adds :meth:`hexdigest`. """ @classmethod def _fields(cls) -> set[str]: """Names of fields in `cls`.""" - result = set(dir(cls)) + result = set(filter(lambda n: not n.startswith("_"), dir(cls))) if is_dataclass(cls): result |= set(map(lambda f: f.name, fields(cls))) return result @@ -85,20 +85,35 @@ def _canonical_name(cls, name: Hashable) -> str | None: return _name if _name in cls._fields() else None @classmethod - def _munge_dict(cls, data: Mapping[Hashable, Any], fail: str, kind: str): - for key, value in data.items(): - name = cls._canonical_name(key) + def _canonicalize( + cls, + data: Mapping[str, Any] | Mapping[Hashable, Any], + kind: str, + fail: type[Exception] | None = None, + ) -> Iterator[tuple[str, Any]]: + """Modify `data` by passing keys through :meth:`_canonical_name`. - if name: + Parameters + ---------- + kind + Used to format exception or log message. + """ + for key, value in data.items(): + if name := cls._canonical_name(key): yield name, value else: msg = f"{cls.__name__} has no attribute for {kind} {key!r}" - if fail == "raise": - raise ValueError(msg) + if fail is None: + log.info(msg) else: - log.info(f"{msg}; ignored") + raise fail(msg) + + def __iter__(self) -> Iterator[tuple[str, Any]]: + """Iterate over (field, value) pairs.""" + for f in self._fields(): + yield f, getattr(self, f) - def read_file(self, path: Path, fail="raise") -> None: + def read_file(self, path: Path) -> None: """Update configuration from file. Parameters @@ -110,11 +125,13 @@ def read_file(self, path: Path, fail="raise") -> None: of the dataclass raise a ValueError. Otherwise, a message is logged. """ if path.suffix == ".yaml": + # Read data from YAML import yaml with open(path, encoding="utf-8") as f: data = yaml.safe_load(f) elif path.suffix == ".json": + # Read data from JSON import json with open(path) as f: @@ -122,7 +139,7 @@ def read_file(self, path: Path, fail="raise") -> None: else: raise NotImplementedError(f"Read from {path.suffix}") - for key, value in self._munge_dict(data, fail, "file section"): + for key, value in self._canonicalize(data, "file section", ValueError): existing = getattr(self, key, None) if is_dataclass(existing) and not isinstance(existing, type): # Attribute value is also a dataclass; update it recursively @@ -138,11 +155,10 @@ def read_file(self, path: Path, fail="raise") -> None: def replace(self, **kwargs): """Like :func:`dataclasses.replace` with name manipulation.""" return replace( - self, - **{k: v for k, v in self._munge_dict(kwargs, "raise", "keyword argument")}, + self, **dict(self._canonicalize(kwargs, "keyword argument", ValueError)) ) - def update(self, **kwargs): + def update(self, arg: Mapping | None = None, **kwargs) -> None: """Update attributes in-place. Raises @@ -150,16 +166,15 @@ def update(self, **kwargs): AttributeError Any of the `kwargs` are not fields in the data class. """ - # TODO use _munge_dict(); allow a positional argument - for k, v in kwargs.items(): - if not hasattr(self, k): - raise AttributeError(k) + # Merge a positional argument and keyword arguments + data = dict(arg or {}) | kwargs + for k, v in self._canonicalize(data, "value", AttributeError): setattr(self, k, v) @classmethod def from_dict(cls, data: Mapping): """Construct an instance from `data` with name manipulation.""" - return cls(**{k: v for k, v in cls._munge_dict(data, "raise", "mapping key")}) + return cls(**dict(cls._canonicalize(data, "mapping key", ValueError))) def hexdigest(self, length: int = -1) -> str: """Return a hex digest that is unique for distinct settings on the instance. From eb5d7aea0b7c1c01f94320335c0c7e6f10175151 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Wed, 1 Apr 2026 11:07:44 +0200 Subject: [PATCH 51/73] Use ConfigHelper.update in Context.update() --- message_ix_models/util/context.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/message_ix_models/util/context.py b/message_ix_models/util/context.py index 334999cc73..e460aedb8d 100644 --- a/message_ix_models/util/context.py +++ b/message_ix_models/util/context.py @@ -235,10 +235,18 @@ def pop(self, name, default=_Missing): def setdefault(self, name, value): return self._values.setdefault(name, value) - def update(self, arg=None, **kwargs): - # Force update() to use set(), above + def update(self, arg: Any = None, **kwargs) -> None: + """Update the Context. + + `arg` may be a :class:`dict` or nested :class:`dict`. + """ for k, v in dict(*filter(None, [arg]), **kwargs).items(): - self.set(k, v) + if k in self and hasattr(self[k], "update"): + # Use ConfigHelper.update(), e.g. .transport.Config.update() + self[k].update(v) + else: + # Force update() to use dealiasing via set(), above + self.set(k, v) def __deepcopy__(self, memo): result = Context() # Create a new instance; this also updates _CONTEXTS From c7de67375f492946f2ee6e5c4576d6f643e592d6 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Wed, 1 Apr 2026 11:29:58 +0200 Subject: [PATCH 52/73] =?UTF-8?q?Update=20context=20with=20any=20report(?= =?UTF-8?q?=E2=80=A6,=20**kwargs)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- message_ix_models/report/__init__.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/message_ix_models/report/__init__.py b/message_ix_models/report/__init__.py index ec57b001c3..b170f0dffb 100644 --- a/message_ix_models/report/__init__.py +++ b/message_ix_models/report/__init__.py @@ -271,6 +271,9 @@ def report(context: Context, *args, **kwargs): if context.report.legacy["use"]: return _invoke_legacy_reporting(context) + # Update `context` using any remaining `kwargs` + context.update(kwargs) + with ( nullcontext() if context.core.verbose From 3369d64cc7e79a285cc8dac471c9ed3a7d4cd0f5 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Wed, 1 Apr 2026 11:13:03 +0200 Subject: [PATCH 53/73] Use transport code for report in .from_codelist() --- message_ix_models/model/workflow.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/message_ix_models/model/workflow.py b/message_ix_models/model/workflow.py index f7f9ebc0b6..c2ea55d5b2 100644 --- a/message_ix_models/model/workflow.py +++ b/message_ix_models/model/workflow.py @@ -121,7 +121,9 @@ def from_codelist(context: "Context", cl: type["StructureFactory"]) -> "Workflow # Report reported.append(f"{label} reported") - wf.add_step(reported[-1], f"{label} solved", report) + wf.add_step( + reported[-1], f"{label} solved", report, transport={"code": scenario_code} + ) # Report all the scenarios wf.add("all reported", reported) From 29814fe759613495b1ca4fbd25f4d12e48cb120b Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Wed, 1 Apr 2026 11:08:16 +0200 Subject: [PATCH 54/73] Reduce verbosity in .workflow.make_click_command() - Adjust tests. --- message_ix_models/tests/project/test_navigate.py | 2 +- message_ix_models/workflow.py | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/message_ix_models/tests/project/test_navigate.py b/message_ix_models/tests/project/test_navigate.py index ae1939ab23..e077203246 100644 --- a/message_ix_models/tests/project/test_navigate.py +++ b/message_ix_models/tests/project/test_navigate.py @@ -48,7 +48,7 @@ def test_generate_workflow(test_context: "Context") -> None: # displays "MT solved" and its subtree may vary. _context = r"'context' \(above\)" BLOCKS = [ - "Truncate workflow at 'M T3.5 built'", + "Truncate workflow at 1 point matching 'M T3.5 built'", rf""" (\s+)- 'MT NPi-ref solved': \1- diff --git a/message_ix_models/workflow.py b/message_ix_models/workflow.py index 641811ca5f..6d44122649 100644 --- a/message_ix_models/workflow.py +++ b/message_ix_models/workflow.py @@ -206,7 +206,7 @@ def run(self, name_or_names: str | list[str]): """ return self.get(name_or_names) - def truncate(self, name: str): + def truncate(self, name: str) -> None: """Truncate the workflow at the step `name`. The step `name` is replaced with a new :class:`WorkflowStep` that simply loads @@ -336,9 +336,15 @@ def _func(context, go, truncate_step, target_step, **kwargs): except AttributeError: pass # truncate_step is None else: + N_truncate = 0 for step in filter(expr.fullmatch, wf.keys()): - log.info(f"Truncate workflow at {step!r}") wf.truncate(step) + N_truncate += 1 + log.info( + f"Truncate workflow at {N_truncate} point" + + ("s" if N_truncate != 1 else "") + + f" matching {truncate_step!r}" + ) # Identify the target step if target_step: From 37950cda4a73c8b8a049d283b608e22bfa6a8cbb Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Wed, 1 Apr 2026 11:12:27 +0200 Subject: [PATCH 55/73] Don't auto-visualize large workflows on CLI - Adjust test. --- message_ix_models/tests/test_workflow.py | 2 +- message_ix_models/workflow.py | 15 ++++++--------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/message_ix_models/tests/test_workflow.py b/message_ix_models/tests/test_workflow.py index 581c99d0b5..5cb39a6ac4 100644 --- a/message_ix_models/tests/test_workflow.py +++ b/message_ix_models/tests/test_workflow.py @@ -113,7 +113,7 @@ def test_make_click_command( # Invoke the command with various parameters for params, output in ( (["--go", "B"], "nothing returned, workflow will continue with"), - (["B"], "Workflow diagram written to"), + (["B"], "Write workflow diagram to"), ): # Command runs and exits with 0 result = mix_models_cli.assert_exit_0(["_test", "run"] + params) diff --git a/message_ix_models/workflow.py b/message_ix_models/workflow.py index 6d44122649..678cbfacce 100644 --- a/message_ix_models/workflow.py +++ b/message_ix_models/workflow.py @@ -306,8 +306,8 @@ def make_click_command(wf_callback: str, name: str, slug: str, **kwargs) -> "Com help_arg = f"""Run the {name} workflow up to step TARGET. - Unless --go is given, the workflow is only displayed. - --from is interpreted as a regular expression. + Unless --go is given, the workflow is only displayed, and a visualization written + to a file. --from is interpreted as a regular expression. """ @click.command(name="run", help=help_arg, **kwargs) @@ -317,7 +317,7 @@ def make_click_command(wf_callback: str, name: str, slug: str, **kwargs) -> "Com ) @click.argument("target_step", metavar="TARGET", required=False) @click.pass_obj - def _func(context, go, truncate_step, target_step, **kwargs): + def _func(context, go, truncate_step, target_step: str | None, **kwargs): from importlib import import_module from message_ix_models.util import show_versions @@ -374,12 +374,9 @@ def _func(context, go, truncate_step, target_step, **kwargs): if not go: path = context.get_local_path(f"{slug}-workflow.svg") - wf.visualize( - str(path), - # key=target_step, # DEBUG Uncomment to show only a subset of steps - rankdir="LR", - ) - log.info(f"Workflow diagram written to {path}") + log.info(f"Write workflow diagram to {path}") + # If target_step is given, show only this step + wf.visualize(path, key=target_step, rankdir="LR") return wf.run(target_step) From d64fa1ec31b681b20c5c5943162ff5ce0e46c68b Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Wed, 1 Apr 2026 11:31:11 +0200 Subject: [PATCH 56/73] Use operator.summarize() for transport report --- message_ix_models/model/transport/base.py | 9 ++++--- message_ix_models/model/transport/build.py | 2 +- message_ix_models/model/transport/report.py | 27 +++++++++------------ 3 files changed, 18 insertions(+), 20 deletions(-) diff --git a/message_ix_models/model/transport/base.py b/message_ix_models/model/transport/base.py index ccf77173f0..28c28c1472 100644 --- a/message_ix_models/model/transport/base.py +++ b/message_ix_models/model/transport/base.py @@ -13,8 +13,7 @@ from message_ix_models.util import minimum_version -from .key import gdp_exo -from .key import report as k_report +from . import key as K from .util import EXTRAPOLATE if TYPE_CHECKING: @@ -203,7 +202,7 @@ def prepare_reporter(rep: "message_ix.Reporter") -> str: # below added to the list rep.add(TARGET, []) # Add this result key to the list of all reporting keys - rep.graph[k_report.all].append(TARGET) + rep.graph[K.report.all] += (TARGET,) # Create output subdirectory for base model files rep.graph["config"]["output_dir"].joinpath("base").mkdir( @@ -302,7 +301,9 @@ def prepare_reporter(rep: "message_ix.Reporter") -> str: ) # Compute for file and plot: transport final energy intensity of GDP PPP - k_gdp = rep.add("gdp:nl-ya", "rename_dims", gdp_exo, quote({"n": "nl", "y": "ya"})) + k_gdp = rep.add( + "gdp:nl-ya", "rename_dims", K.gdp_exo, name_dict={"n": "nl", "y": "ya"} + ) k_fei = single_key(rep.add("fe intensity", "div", k["s2"] / tuple("chlt"), k_gdp)) rep.add(k_fei + "units", "convert_units", k_fei, units="MJ / USD") rep.apply(to_csv, k_fei + "units", name="fe intensity") diff --git a/message_ix_models/model/transport/build.py b/message_ix_models/model/transport/build.py index 942e1d160f..0bab54168e 100644 --- a/message_ix_models/model/transport/build.py +++ b/message_ix_models/model/transport/build.py @@ -271,7 +271,7 @@ def add_exogenous_data(c: Computer, info: ScenarioInfo) -> None: #: See :func:`.nodes_world_agg`. STRUCTURE_STATIC: tuple[tuple, ...] = ( ("add transport data", []), - (key.report.all, []), + (key.report.all, "summarize"), ("info", lambda c: c.transport.base_model_info, "context"), ( "transport info", diff --git a/message_ix_models/model/transport/report.py b/message_ix_models/model/transport/report.py index 2b69f66672..0ce4343d8a 100644 --- a/message_ix_models/model/transport/report.py +++ b/message_ix_models/model/transport/report.py @@ -14,7 +14,8 @@ from message_ix_models.report import STAGE, add_plots from message_ix_models.report.util import add_replacements -from . import Config, key, plot +from . import Config, plot +from . import key as K if TYPE_CHECKING: from message_ix_models import Spec @@ -221,7 +222,7 @@ def callback(rep: Reporter, context: Context) -> None: misc(rep) convert_iamc(rep) # Adds to key.report.all convert_sdmx(rep) # Adds to key.report.all - add_plots(rep, plot, key.report.plot) + add_plots(rep, plot, K.report.plot) base.prepare_reporter(rep) # Tasks that prepare data to parametrize the base model log.info(f"Added {len(rep.graph) - N_keys} keys") @@ -306,8 +307,6 @@ def convert_iamc(c: "Computer") -> None: from message_ix_models.report import iamc as handle_iamc from message_ix_models.report import util - from .key import report as k_report - util.REPLACE_VARS.update({r"^CAP\|(Transport)": r"\1"}) keys = [] @@ -322,12 +321,11 @@ def convert_iamc(c: "Computer") -> None: # Add tasks for writing IAMC-structured data to file and storing on the scenario c.apply(add_iamc_store_write, k) - c.graph[k_report.all].append( - # Use ths line to both store and write to file IAMC structured-data - k + "all" - # Use this line for "transport::iamc+file" instead of "transport::iamc+all" - # k + " file" - ) + # Use this line to both store and write to file IAMC structured-data + c.graph[K.report.all] += (k + "all",) + # Use this line for "transport::iamc+file" instead of "transport::iamc+all", i.e. to + # write IAMC-structured data to file but *not* store on scenario + # c.graph[K.report.all] += (k + "file",) def convert_sdmx(c: "Computer") -> None: @@ -336,7 +334,6 @@ def convert_sdmx(c: "Computer") -> None: from message_ix_models.util.sdmx import DATAFLOW, Dataflow - from .key import report as k_report from .operator import write_sdmx_data # Directory for SDMX output @@ -354,10 +351,10 @@ def convert_sdmx(c: "Computer") -> None: c.add(keys[-1], write_sdmx_data, df.key, sm, "scenario", dir_, df_urn=df.df.urn) # Collect all the keys *then* write the collected structures to file - c.add(k_report.sdmx, "write_sdmx_structures", sm, dir_, *keys) + c.add(K.report.sdmx, "write_sdmx_structures", sm, dir_, *keys) # Connect to the main report key - c.graph[k_report.all].append(k_report.sdmx) + c.graph[K.report.all] += (K.report.sdmx,) def misc(c: "Computer") -> None: @@ -377,7 +374,7 @@ def misc(c: "Computer") -> None: c.add("distance:nl:non-ldv", "distance_nonldv", "config") # Demand per capita - c.add("demand::capita", "divdemand:n-c-y", key.pop) + c.add("demand::capita", "divdemand:n-c-y", K.pop) # Adjustment factor for LDV calibration: fuel economy ratio k_num = Key("in:nl-t-ya-c:transport+units") / "c" # As in CONVERT_IAMC @@ -392,7 +389,7 @@ def misc(c: "Computer") -> None: ) k_ratio = single_key( - c.add("fuel economy::ratio", "div", key.exo.input_ref_ldv, k_check + "sel") + c.add("fuel economy::ratio", "div", K.exo.input_ref_ldv, k_check + "sel") ) c.add("calibrate fe path", "make_output_path", "config", name="calibrate-fe.csv") hc = "\n\n".join( From 56f5ce7a34571b925c4ea952c924217d104d6939 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Tue, 7 Apr 2026 18:53:20 +0200 Subject: [PATCH 57/73] Add "CAP{,_NEW}::transport all" to reapply_units() --- message_ix_models/model/transport/report.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/message_ix_models/model/transport/report.py b/message_ix_models/model/transport/report.py index 0ce4343d8a..925c8835ef 100644 --- a/message_ix_models/model/transport/report.py +++ b/message_ix_models/model/transport/report.py @@ -470,7 +470,9 @@ def reapply_units(c: "Computer") -> None: # FIXME should not need the extra [vehicle] in the numerator "CAP:nl-t-ya:non-ldv": ("apply", "v**2 Tm / a"), "CAP:*:ldv": ("apply", "Mv"), + "CAP:*:transport all": ("apply", "Mv"), "CAP_NEW:*:ldv": ("apply", "Mv"), + "CAP_NEW:*:transport all": ("apply", "Mv"), # NB these units are correct for final energy only "in:*:transport": ("apply", "GWa / a"), "in:*:ldv": ("apply", "GWa / a"), From fe07b61c456c8e284397036f50039d0115150be3 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Tue, 7 Apr 2026 18:54:01 +0200 Subject: [PATCH 58/73] Strip "CAP{,_NEW}" prefix from 'variable' string - Move IAMC-related configuration into convert_iamc() setup function. --- message_ix_models/model/transport/report.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/message_ix_models/model/transport/report.py b/message_ix_models/model/transport/report.py index 925c8835ef..4204a8b017 100644 --- a/message_ix_models/model/transport/report.py +++ b/message_ix_models/model/transport/report.py @@ -212,9 +212,6 @@ def callback(rep: Reporter, context: Context) -> None: rep.set_filters(t=sorted(t_filter)) - # Configure replacements for conversion to IAMC data structure - add_replacements("t", context.transport.spec.add.set["technology"]) - # Apply some functions that prepare further tasks. Order matters here. aggregate(rep) select_transport_techs(rep) @@ -307,7 +304,14 @@ def convert_iamc(c: "Computer") -> None: from message_ix_models.report import iamc as handle_iamc from message_ix_models.report import util - util.REPLACE_VARS.update({r"^CAP\|(Transport)": r"\1"}) + # Configure replacements for technology IDs in conversion to IAMC data structure + cfg: Config = c.graph["context"].transport + add_replacements("t", cfg.spec.add.set["technology"]) + + # Update replacements for fully-constructed IAMC variable codes + # - Quantity.name is prepended automatically; this occurs with quantities derived + # from CAP and CAP_NEW. Remove the prefix. + util.REPLACE_VARS.update({r"^CAP(_NEW)?\|(S(ale|tock)s\|Transportation)": r"\2"}) keys = [] for info in CONVERT_IAMC: From e21851f56f4cf93f53741b1f00133e9375d8b361 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Wed, 8 Apr 2026 12:07:08 +0200 Subject: [PATCH 59/73] Use Code.name in .report.util.add_replacements() --- message_ix_models/report/util.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/message_ix_models/report/util.py b/message_ix_models/report/util.py index c91bc3b2cc..1e8658b56e 100644 --- a/message_ix_models/report/util.py +++ b/message_ix_models/report/util.py @@ -10,7 +10,7 @@ from genno.compat.pyam.util import collapse as genno_collapse from genno.core.key import single_key from message_ix import Reporter -from sdmx.model.v21 import Code +from sdmx.model.common import Code if TYPE_CHECKING: from genno import Computer @@ -334,13 +334,20 @@ def add_replacements(dim: str, codes: Iterable[Code]) -> None: qux: {} # No "report" annotation → no mapping - …results in entries :py:`{"foo": "fOO", "bar": "Baz"}` added to :data:`REPLACE_DIMS` + …results in entries :py:`{"Foo": "fOO", "Bar": "Baz"}` added to :data:`REPLACE_DIMS` and used by :func:`collapse`. """ for code in codes: + # List of candidates + candidates = [code.id, code.name] try: - label = str(code.get_annotation(id="report").text) + # Append the value of the "report" annotation, if any + candidates.append(code.get_annotation(id="report").text) except KeyError: pass - else: + + # Final entry in the list with a non-empty string representation + label = next(filter(None, map(str, reversed(candidates)))) + + if label != code.id: REPLACE_DIMS[dim][f"{code.id.title()}$"] = label From 01f95bfef3abda1af2e7da32a9c559f66b099bdf Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Wed, 15 Apr 2026 00:34:34 +0200 Subject: [PATCH 60/73] Add "report:" annotation for commodity "gas" - Preserve expected output per test_report.test_compare(). --- message_ix_models/data/commodity.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/message_ix_models/data/commodity.yaml b/message_ix_models/data/commodity.yaml index 965ee26d2d..cdf53a7a57 100644 --- a/message_ix_models/data/commodity.yaml +++ b/message_ix_models/data/commodity.yaml @@ -112,7 +112,8 @@ fueloil: iea-eweb-product: [BITUMEN, PARWAX, PETCOKE, RESFUEL] gas: - name: Natural Gas + name: Natural gas + report: Gas units: GWa ipcc-1996-name: "Natural Gas (Dry)" iea-eweb-product: [NATGAS] From 13f6ca4eba65944abc1abf5f6cca2b6dbd1aa840 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Wed, 8 Apr 2026 12:04:57 +0200 Subject: [PATCH 61/73] Improve transport/technology.yaml for #471 - Rename some old "report" annotations to "message-v-id:". - Add names and "report" annotations for many more technologies. - Include mode prefixes. --- .../data/transport/technology.yaml | 193 ++++++++++++------ 1 file changed, 129 insertions(+), 64 deletions(-) diff --git a/message_ix_models/data/transport/technology.yaml b/message_ix_models/data/transport/technology.yaml index e2dc20f506..bb56c0a643 100644 --- a/message_ix_models/data/transport/technology.yaml +++ b/message_ix_models/data/transport/technology.yaml @@ -21,7 +21,7 @@ # # - 'input': same as in message-ix-models: mapping including 'commodity' and/or # 'level' keys indicating the technology's inputs. -# - 'message-v-report': these appeared in the US-TIMES–MA³T input data, but were +# - 'message-v-id': these appeared in the US-TIMES–MA³T input data, but were # apparently not used in MESSAGE-(V)-Transport. # - 'report': are picked up by add_replacements() for reporting. @@ -30,187 +30,220 @@ ELC_100: description: >- Battery-electric light-duty vehicle using electricity only (100-mile all-electric range) - report: BEV input: {commodity: electr} - message-v-report: LDV_ELE + report: Light-Duty Vehicle|Battery-Electric + message-v-id: LDV_ELE ntnu-vmi-technology: BEV gfei-2017-technology: Electric HFC_ptrp: - report: FCEV + name: Hydrogen fuel cell LDV description: Hybridized fuel cell light-duty vehicle using hydrogen input: {commodity: hydrogen} - message-v-report: LDV_HFC + report: Light-Duty Vehicle|Fuel-Cell-Electric + message-v-id: LDV_HFC ntnu-vmi-technology: ICE gfei-2017-technology: Hydrogen IAHe_ptrp: - report: Biofuel hybrid + name: Biofuel hybrid LDV description: >- Hybridized internal combustion engine light-duty vehicle using biofuels input: {commodity: ethanol} - message-v-report: LDV_EHYB + report: Light-Duty Vehicle|Biofuel hybrid + message-v-id: LDV_EHYB ntnu-vmi-technology: ICE IAHm_ptrp: - report: Methanol hybrid + name: Methanol hybrid LDV description: >- Hybridized internal combustion engine light-duty vehicle using methanol/ synthetic fossil liquids input: {commodity: methanol} - message-v-report: LDV_MHYB + report: Light-Duty Vehicle|Methanol hybrid + message-v-id: LDV_MHYB ntnu-vmi-technology: ICE ICAe_ffv: - report: Biofuel ICEV + name: Biofuel ICE LDV description: >- Internal combustion engine light-duty vehicle using biofuels. Although real-world flex-fuel vehicles are run on varying mix of ethanol and lightoil, this technology uses only ethanol. input: {commodity: ethanol} - message-v-report: LDV_ffv + report: Light-Duty Vehicle|Biofuel + message-v-id: LDV_ffv ntnu-vmi-technology: ICE gfei-2017-technology: Diesel ICAm_ptrp: - report: Synfuel ICEV + name: Synfuel ICE LDV description: >- Internal combustion engine light-duty vehicle using methanol/synthetic fossil liquids input: {commodity: methanol} - message-v-report: LDV_meth + report: Light-Duty Vehicle|Synfuel + message-v-id: LDV_meth ntnu-vmi-technology: ICE gfei-2017-technology: Flexfuel ICE_conv: - report: ICEV + report: ICE LDV description: >- Future (2005 and after) medium/high-efficiency internal combustion engine light-duty vehicle using gasoline/diesel input: {commodity: lightoil} - message-v-report: LDV_conv + report: Light-Duty Vehicle|Light oil combustion + message-v-id: LDV_conv ntnu-vmi-technology: ICE gfei-2017-technology: Petrol ICE_L_ptrp: - report: ICEV (pre-2005) + name: ICE LDV (pre-2005) description: >- Historical (2005 and before) Low-efficiency internal combustion engine light-duty vehicle using gasoline/diesel input: {commodity: lightoil} + report: Light-Duty Vehicle|Light oil combustion (2005 and before) historical-only: True - message-v-report: LDV_ICE_L + message-v-id: LDV_ICE_L ntnu-vmi-technology: ICE ICE_nga: - report: Gas ICEV + name: Gas ICE LDVV description: >- Internal combustion engine light-duty vehicle using natural gas input: {commodity: gas} - message-v-report: LDV_NGA + report: Light-Duty Vehicle|Gas combustion + message-v-id: LDV_NGA gfei-2017-technology: [CNG, LPG] ntnu-vmi-technology: ICE ICH_chyb: - report: Hybrid + name: Hybrid LDV description: >- Hybridized internal combustion engine light-duty vehicle using gasoline/diesel input: {commodity: lightoil} - message-v-report: LDV_CHYB + report: Light-Duty Vehicle|Light-oil hybrid + message-v-id: LDV_CHYB ntnu-vmi-technology: ICE gfei-2017-technology: Hybrid IGH_ghyb: - report: Gas hybrid + name: Gas hybrid LDV description: >- Hybridized internal combustion engine light-duty vehicle using natural gas input: {commodity: gas} - message-v-report: LDV_GHYB + report: Light-Duty Vehicle|Gas hybrid + message-v-id: LDV_GHYB ntnu-vmi-technology: ICE PHEV_ptrp: - report: PHEV + report: PHE LDV description: >- Plug-in hybrid-electric light-duty vehicle using gasoline/diesel (40-mile all-electric range) input: {commodity: [electr, lightoil]} - message-v-report: LDV_PHEV + report: Light-Duty Vehicle|Plug-in Hybrid + message-v-id: LDV_PHEV ntnu-vmi-technology: PHEV gfei-2017-technology: Plug-in ICE_H_moto: - report: ICEV + name: ICE 2- and 3-wheeler description: >- High-efficiency internal combustion engine two-wheeler/motorcycle using gasoline/diesel input: {commodity: lightoil} - report: 2W_ICE_H + report: 2W|Combustion + message-v-id: 2W_ICE_H ELE_moto: - report: BEV + name: Battery-electric 2- and 3-wheeler description: >- Battery-electric two-wheeler/motorcycle using electricity-only input: {commodity: electr} - report: 2W_ELE + report: 2W|Battery-electric + message-v-id: 2W_ELE ICE_H_bus: + name: High-efficiency internal combustion bus description: High-efficiency internal combustion engine bus using gasoline/diesel input: {commodity: lightoil} - report: BUS_ICE_H + report: Bus|Combustion light oil high efficiency + message-v-id: BUS_ICE_H ICE_M_bus: + name: Medium-efficiency internal combustion bus description: >- Medium-efficiency internal combustion engine bus using gasoline/diesel input: {commodity: lightoil} - report: BUS_ICE_M + report: Bus|Combustion light oil + message-v-id: BUS_ICE_M ICG_bus: + name: Natural gas bus description: Internal combustion engine bus using natural gas input: {commodity: gas} - report: BUS_ICG + report: Bus|Combustion gas + message-v-id: BUS_ICG ICAe_bus: + name: Biofuel bus description: Internal combustion engine bus using biofuels input: {commodity: ethanol} - report: BUS_ICAe + report: Bus|Combustion biofuel + message-v-id: BUS_ICAe ICH_bus: + name: Hybridized internal combustion bus description: >- Hybridized internal combustion engine bus using gasoline/diesel input: {commodity: lightoil} # hybridized, but not plug-in, so only oil input - report: BUS_ICH + report: Bus|Hybrid combustion + message-v-id: BUS_ICH FC_bus: + name: Hybridized hydrogen fuel cell bus description: Hybridized fuel cell bus using hydrogen input: {commodity: hydrogen} - report: BUS_HFC + report: Bus|Hybrid fuel cell hydrogen + message-v-id: BUS_HFC FCg_bus: + name: Hybridized natural gas fuel cell bus description: >- Hybridized fuel cell bus using natural gas via steam reformation input: {commodity: gas} - report: BUS_GFC + report: Bus|Hybrid fuel cell gas + message-v-id: BUS_GFC FCm_bus: + name: Hybridized synfuel cell bus description: >- Hybridized fuel cell bus using methanol/synthetic fossil liquids via steam reformation input: {commodity: methanol} - report: BUS_MFC + report: Bus|Hybrid fuel cell synfuel + message-v-id: BUS_MFC Trolley_bus: + name: Electric trolley-bus description: Electric trolleybus connected to power cables input: {commodity: electr} - report: BUS_ELEtr + report: Bus|Trolley + message-v-id: BUS_ELEtr PHEV_bus: + name: Plug-in hybrid-electric bus description: Plug-in hybrid-electric bus using gasoline/diesel input: commodity: [electr, lightoil] - report: BUS_PHEV + report: Bus|Plug-in Hybrid + message-v-id: BUS_PHEV # BEV_bus: # description: Battery-electric bus using electricity only @@ -218,102 +251,126 @@ PHEV_bus: # report: BUS_BEV con_ar: + name: Kerosene aircraft description: >- Conventional jet engine passenger aircraft using light oil petroleum products (kerosene jet fuel) input: {commodity: lightoil} - report: AIRp_JF + report: Air|Kerosene + message-v-id: AIRp_JF conh_ar: + name: Hydrogen aircraft description: Conventional jet engine passenger aircraft using hydrogen input: {commodity: hydrogen} - report: AIRp_H2 + report: Air|Hydrogen + message-v-id: AIRp_H2 conm_ar: + name: Synfuel aircraft description: >- Conventional jet engine passenger aircraft using methanol/synthetic fossil liquids input: {commodity: methanol} - report: AIRp_MET + report: Air|Synfuel + message-v-id: AIRp_MET conE_ar: + name: Biofuel aircraft description: Conventional jet engine passenger aircraft using biofuels input: {commodity: ethanol} - report: AIRp_BIO + report: Air|Biofuel + message-v-id: AIRp_BIO FR_ICE_H: + name: High-efficiency light oil truck description: >- High-efficiency internal combustion engine freight truck using gasoline/diesel input: {commodity: lightoil, level: final} - report: FRT_ICE_H + report: Truck|Combustion light oil high efficiency + message-v-id: FRT_ICE_H FR_ICE_M: + name: Medium-efficiency light oil truck description: >- Medium-efficiency internal combustion engine freight truck using gasoline/diesel input: {commodity: lightoil} - report: FRT_ICE_M + report: Truck|Combustion light oil medium efficiency + message-v-id: FRT_ICE_M FR_ICE_L: + name: Low-efficiency light oil truck description: >- Low-efficiency internal combustion engine freight truck using gasoline/diesel input: {commodity: lightoil} - report: FRT_ICE_L + report: Truck|Combustion light oil low efficiency + message-v-id: FRT_ICE_L FR_ICAe: + name: Biofuel truck description: Internal combustion engine freight truck using biofuels input: {commodity: ethanol} - report: FRT_ICAe + report: Truck|Biofuel + message-v-id: FRT_ICAe FR_ICH: + name: Hybrid ICE truck description: >- Hybridized internal combustion engine freight truck using gasoline/diesel input: {commodity: lightoil} - report: FRT_ICH + report: Truck|Hybrid combustion + message-v-id: FRT_ICH FR_FCH: + name: Fuel cell truck description: Hybridized fuel cell freight truck using hydrogen input: {commodity: hydrogen} - report: FRT_HFC + report: Truck|Fuel cell hydrogen + message-v-id: FRT_HFC f road electr: name: Freight road vehicle powered by electricity input: {commodity: electr} + report: Truck|Battery-Electric f road gas fc: + name: Gas fuel cell truck description: >- Hybridized fuel cell freight truck using natural gas via steam reformation. Previous ID: FR_FCg. input: {commodity: gas} - report: FRT_GFC + report: Truck|Fuel cell gas + message-v-id: FRT_GFC f road gas ic: - description: >- - Internal combustion engine freight truck using natural gas. - - Previous ID: FR_ICG. + name: Gas combustion truck + description: Internal combustion engine freight truck using natural gas. input: {commodity: gas} - report: FRT_ICG + report: Truck|Gas combustion + message-v-id: [FR_ICG, FRT_ICG] f road methanol: + name: Synfuel truck description: >- Hybridized fuel cell freight truck using methanol/synthetic fossil liquids via steam reformation. - - Previous ID: FR_FCm input: {commodity: methanol} - report: FRT_MFC + report: Truck|Fuel cell synfuel + message-v-id: [FR_FCm, FRT_MFC] f rail electr: name: Freight rail powered by electricity input: {commodity: electr} + report: Rail|Freight|Electric f rail lightoil: name: Freight rail powered by light oil input: {commodity: lightoil} + report: Rail|Freight|Combustion F RAIL: name: Freight rail @@ -322,40 +379,47 @@ F RAIL: - f rail lightoil units: Gv km output: {commodity: transport F RAIL vehicle, level: useful} + report: Rail|Freight iea-eweb-flow: [RAIL] crail_pub: + name: Coal train description: >- Coal-powered urban public rail transport: aggregate of metro/underground, streetcars/trams, commuter trains, and regional trains - report: RAIL_urban_COAL + name: Passenger|Rail|Coal dMspeed_rai: + name: Diesel train description: Diesel-powered long-distance medium-speed rail transport input: {commodity: lightoil} - report: RAIL_ldm_DSL + report: Passenger|Rail|Diesel drail_pub: + name: Diesel urban train description: Diesel-powered urban public rail transport input: {commodity: lightoil} - report: RAIL_urban_DSL + report: Passenger|Rail|Diesel urban Hspeed_rai: + name: Electric high-speed train description: Electrically-powered long-distance high-speed rail transport input: {commodity: electr} - report: RAIL_ldh_ELE + report: Passenger|Rail|Electric high-speed Mspeed_rai: + name: Electric train description: Electrically-powered long-distance medium-speed rail transport input: {commodity: electr} - report: RAIL_ldm_ELE + report: Passenger|Rail|Electric rail_pub: + name: Electric urban train description: >- Electrically-powered urban public rail transport: aggregate of metro/ underground, streetcars/trams, commuter trains, and regional trains input: {commodity: electr} - report: RAIL_urban_ELE + report: Passenger|Rail|Electric urban transport F RAIL usage: description: >- @@ -500,6 +564,7 @@ AIR: BUS: name: Urban public transit + report: Bus description: >- Buses and other forms of urban public transit. From e8e6e65b70a506371f1db6122879fb25fc6efdff Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Tue, 7 Apr 2026 18:55:12 +0200 Subject: [PATCH 62/73] Output sales, stocks for non-LDV transport - Change "Transport|Stock|" variable prefix to "Stocks|Transportation|", likewise sales. - Adjust test. --- message_ix_models/model/transport/report.py | 18 +++++++++--------- .../tests/model/transport/test_report.py | 12 ++++++++---- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/message_ix_models/model/transport/report.py b/message_ix_models/model/transport/report.py index 4204a8b017..011b1719e0 100644 --- a/message_ix_models/model/transport/report.py +++ b/message_ix_models/model/transport/report.py @@ -33,20 +33,20 @@ # NGFS project dict( variable="transport activity", - base="out:nl-t-ya-c:transport+units", + base="out:nl-t-ya-c:transport all+units", var=["Energy Service|Transportation", "t", "c"], sums=["c", "t", "c-t"], ), dict( - variable="transport stock", - base="CAP:nl-t-ya:ldv+units", - var=["Transport|Stock|Road|Passenger|LDV", "t"], + variable="T stock", + base="CAP:nl-t-ya:transport all+units", + var=["Stocks|Transportation", "t"], unit="Mvehicle", ), dict( - variable="transport sales", - base="CAP_NEW:nl-t-yv:ldv+units", - var=["Transport|Sales|Road|Passenger|LDV", "t"], + variable="T sales", + base="CAP_NEW:nl-t-yv:transport all+units", + var=["Sales|Transportation", "t"], unit="Mvehicle", ), # Final energy @@ -55,7 +55,7 @@ # individual technologies are already aggregated to modes dict( variable="transport fe", - base="in:nl-t-ya-c:transport+units", + base="in:nl-t-ya-c:transport all+units", var=["Final Energy|Transportation", "t", "c"], sums=["c", "t", "c-t"], unit=_FE_UNIT, @@ -63,7 +63,7 @@ dict( variable="transport fe ldv", base="in:nl-t-ya-c:ldv+units", - var=["Final Energy|Transportation|Road|Passenger|LDV", "t", "c"], + var=["Final Energy|Transportation", "t", "c"], unit="EJ/yr", ), # Emissions using MESSAGEix emission_factor parameter diff --git a/message_ix_models/tests/model/transport/test_report.py b/message_ix_models/tests/model/transport/test_report.py index 8822fba3ee..f62fe84ada 100644 --- a/message_ix_models/tests/model/transport/test_report.py +++ b/message_ix_models/tests/model/transport/test_report.py @@ -226,7 +226,7 @@ def test_simulated( rep.get(k) # A quantity for message_ix_models.model.transport can be computed - k = "transport stock::iamc" + k = "T stock::iamc" result = rep.get(k) assert 0 < len(result) @@ -287,14 +287,18 @@ def test_simulated_iamc( # Retrieve time series data stored on the scenario object ts = s.timeseries() - # print(ts, ts["variable"].unique(), sep="\n") # DEBUG + # print( # DEBUG + # ts.head().to_string(), + # ts.tail().to_string(), + # "\n".join(sorted(ts["variable"].unique())), + # sep="\n", + # ) # The reported data was stored on the scenario, and has expected variable names - # print("\n".join(sorted(ts["variable"].unique()))) # DEBUG assert { "Energy Service|Transportation|Domestic Aviation", "Final Energy|Transportation|Bus", - "Transport|Stock|Road|Passenger|LDV|BEV", + "Stocks|Transportation|Light-Duty Vehicle|Battery-Electric", } <= set(ts["variable"].unique()) del result From bc9f7507b676fcae6219382d6d26b6e62ccde3bc Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Tue, 7 Apr 2026 19:49:53 +0200 Subject: [PATCH 63/73] Add CLI command "transport export-price" --- message_ix_models/model/transport/cli.py | 48 ++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/message_ix_models/model/transport/cli.py b/message_ix_models/model/transport/cli.py index b4ebdc5aab..711fadb60a 100644 --- a/message_ix_models/model/transport/cli.py +++ b/message_ix_models/model/transport/cli.py @@ -8,6 +8,7 @@ import logging from pathlib import Path +from typing import TYPE_CHECKING import click @@ -16,6 +17,9 @@ from message_ix_models.util.click import PARAMS, common_params, exec_cb from message_ix_models.workflow import make_click_command +if TYPE_CHECKING: + from message_ix_models import Context + log = logging.getLogger(__name__) @@ -109,6 +113,50 @@ def export_emissions_factors(context, path_stem): df.to_csv(path, mode="a", index=False) +@cli.command("export-price") +@click.pass_obj +def export_price_emission(context: "Context") -> None: # pragma: no cover + """Export PRICE_EMISSION values from base model scenarios. + + The --url option MUST be given. Values are exported to a CSV file at a path like: + + message_ix_models/data/transport/{nodes}/price-emission/{B}.csv + + …where {nodes} is the ID of the node codelist, and {B} is derived from the --url. + """ + # TODO Add a test; requires a solved scenario on the platform used by the + # mix_models_cli fixture + from datetime import datetime + + from message_ix_models.util import identify_nodes, package_data_path + + # Load the targeted scenario + scenario = context.get_scenario() + + # Identify the node codelist + nodes = identify_nodes(scenario) + + # Output path. + # NB Cannot use .with_suffix() here, as this replaces from the first "." in the file + # name, not the last. + info = ScenarioInfo.from_url(scenario.url) + path = package_data_path("transport", nodes, "price-emission", f"{info.path}.csv") + path.parent.mkdir(exist_ok=True, parents=True) + + df = scenario.var("PRICE_EMISSION") + log.info(f"Write {len(df)} rows to {path}") + + # Write header + path.write_text(f"""# Exported using: +# mix-models --url="{context.url}" transport export-price +# at {datetime.today().isoformat()} +# +""") + + # Write data + df.to_csv(path, mode="a", index=False) + + @cli.command() @common_params("dest") @click.option( From 54dc130c2329513f937de776bce7f20cff1dbbe3 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Tue, 7 Apr 2026 19:51:32 +0200 Subject: [PATCH 64/73] Add transport price-emission data for 17 scenarios - Update test expectations. --- .../SSP_LED_v6.5_LED - High Emissions_v3.csv | 10 ++ ..._LED_v6.5_SSP2 - Very Low Emissions_v3.csv | 16 ++ ...SSP_SSP1_v6.5_SSP1 - High Emissions_v1.csv | 12 ++ .../SSP_SSP1_v6.5_SSP1 - Low Emissions_v2.csv | 148 ++++++++++++++++++ ...SSP1_v6.5_SSP1 - Very Low Emissions_v2.csv | 16 ++ ...SSP_SSP2_v6.5_SSP2 - High Emissions_v1.csv | 8 + .../SSP_SSP2_v6.5_SSP2 - Low Emissions_v2.csv | 148 ++++++++++++++++++ .../SSP_SSP2_v6.5_SSP2 - Low Overshoot_v2.csv | 15 ++ ...P2_v6.5_SSP2 - Medium-Low Emissions_v2.csv | 14 ++ ...P_SSP2_v6.6_SSP2 - Medium Emissions_v1.csv | 104 ++++++++++++ ...SSP_SSP3_v6.5_SSP3 - High Emissions_v2.csv | 5 + ..._v6.5_SSP3 - Medium-Low Emissions_a_v1.csv | 10 ++ ...SSP_SSP4_v6.5_SSP4 - High Emissions_v1.csv | 5 + .../SSP_SSP4_v6.5_SSP4 - Low Overshoot_v2.csv | 15 ++ ...SSP_SSP5_v6.5_SSP5 - High Emissions_v2.csv | 5 + .../SSP_SSP5_v6.5_SSP5 - Low Overshoot_v2.csv | 15 ++ ..._v6.5_SSP5 - Medium-Low Emissions_a_v1.csv | 10 ++ .../tests/model/transport/test_config.py | 10 +- 18 files changed, 561 insertions(+), 5 deletions(-) create mode 100644 message_ix_models/data/transport/R12/price-emission/SSP_LED_v6.5_LED - High Emissions_v3.csv create mode 100644 message_ix_models/data/transport/R12/price-emission/SSP_LED_v6.5_SSP2 - Very Low Emissions_v3.csv create mode 100644 message_ix_models/data/transport/R12/price-emission/SSP_SSP1_v6.5_SSP1 - High Emissions_v1.csv create mode 100644 message_ix_models/data/transport/R12/price-emission/SSP_SSP1_v6.5_SSP1 - Low Emissions_v2.csv create mode 100644 message_ix_models/data/transport/R12/price-emission/SSP_SSP1_v6.5_SSP1 - Very Low Emissions_v2.csv create mode 100644 message_ix_models/data/transport/R12/price-emission/SSP_SSP2_v6.5_SSP2 - High Emissions_v1.csv create mode 100644 message_ix_models/data/transport/R12/price-emission/SSP_SSP2_v6.5_SSP2 - Low Emissions_v2.csv create mode 100644 message_ix_models/data/transport/R12/price-emission/SSP_SSP2_v6.5_SSP2 - Low Overshoot_v2.csv create mode 100644 message_ix_models/data/transport/R12/price-emission/SSP_SSP2_v6.5_SSP2 - Medium-Low Emissions_v2.csv create mode 100644 message_ix_models/data/transport/R12/price-emission/SSP_SSP2_v6.6_SSP2 - Medium Emissions_v1.csv create mode 100644 message_ix_models/data/transport/R12/price-emission/SSP_SSP3_v6.5_SSP3 - High Emissions_v2.csv create mode 100644 message_ix_models/data/transport/R12/price-emission/SSP_SSP3_v6.5_SSP3 - Medium-Low Emissions_a_v1.csv create mode 100644 message_ix_models/data/transport/R12/price-emission/SSP_SSP4_v6.5_SSP4 - High Emissions_v1.csv create mode 100644 message_ix_models/data/transport/R12/price-emission/SSP_SSP4_v6.5_SSP4 - Low Overshoot_v2.csv create mode 100644 message_ix_models/data/transport/R12/price-emission/SSP_SSP5_v6.5_SSP5 - High Emissions_v2.csv create mode 100644 message_ix_models/data/transport/R12/price-emission/SSP_SSP5_v6.5_SSP5 - Low Overshoot_v2.csv create mode 100644 message_ix_models/data/transport/R12/price-emission/SSP_SSP5_v6.5_SSP5 - Medium-Low Emissions_a_v1.csv diff --git a/message_ix_models/data/transport/R12/price-emission/SSP_LED_v6.5_LED - High Emissions_v3.csv b/message_ix_models/data/transport/R12/price-emission/SSP_LED_v6.5_LED - High Emissions_v3.csv new file mode 100644 index 0000000000..987bb5bb0f --- /dev/null +++ b/message_ix_models/data/transport/R12/price-emission/SSP_LED_v6.5_LED - High Emissions_v3.csv @@ -0,0 +1,10 @@ +# Exported using: +# mix-models --url="ixmp://ixmp-dev/SSP_LED_v6.5/LED - High Emissions" transport export-price +# at 2026-04-07T19:24:22.872482 +# +node,type_emission,type_tec,year,lvl,mrg +R12_GLB,CO2_shipping_IMO,bunkers,2060,5492.357908799743,0.0 +R12_GLB,CO2_shipping_IMO,bunkers,2070,269.0486426257295,0.0 +R12_GLB,CO2_shipping_IMO,bunkers,2080,313.2632000474355,0.0 +R12_GLB,CO2_shipping_IMO,bunkers,2090,490.8628883500824,0.0 +R12_GLB,CO2_shipping_IMO,bunkers,2110,219.3127211855239,0.0 diff --git a/message_ix_models/data/transport/R12/price-emission/SSP_LED_v6.5_SSP2 - Very Low Emissions_v3.csv b/message_ix_models/data/transport/R12/price-emission/SSP_LED_v6.5_SSP2 - Very Low Emissions_v3.csv new file mode 100644 index 0000000000..560f7f5164 --- /dev/null +++ b/message_ix_models/data/transport/R12/price-emission/SSP_LED_v6.5_SSP2 - Very Low Emissions_v3.csv @@ -0,0 +1,16 @@ +# Exported using: +# mix-models --url="ixmp://ixmp-dev/SSP_LED_v6.5/SSP2 - Very Low Emissions" transport export-price +# at 2026-04-07T19:26:21.921651 +# +node,type_emission,type_tec,year,lvl,mrg +World,TCE,all,2035,365.61880670519434,0.0 +World,TCE,all,2040,423.596572648762,0.0 +World,TCE,all,2045,491.20695234454087,0.0 +World,TCE,all,2050,569.261963287646,0.0 +World,TCE,all,2055,660.0400992843945,0.0 +World,TCE,all,2060,765.2859275753157,0.0 +World,TCE,all,2070,765.2859275753157,0.0 +World,TCE,all,2080,765.2859275753157,0.0 +World,TCE,all,2090,765.2859275753158,0.0 +World,TCE,all,2100,765.2859275753157,0.0 +World,TCE,all,2110,765.2859275753157,0.0 diff --git a/message_ix_models/data/transport/R12/price-emission/SSP_SSP1_v6.5_SSP1 - High Emissions_v1.csv b/message_ix_models/data/transport/R12/price-emission/SSP_SSP1_v6.5_SSP1 - High Emissions_v1.csv new file mode 100644 index 0000000000..c499ce3de7 --- /dev/null +++ b/message_ix_models/data/transport/R12/price-emission/SSP_SSP1_v6.5_SSP1 - High Emissions_v1.csv @@ -0,0 +1,12 @@ +# Exported using: +# mix-models --url="ixmp://ixmp-dev/SSP_SSP1_v6.5/SSP1 - High Emissions" transport export-price +# at 2026-04-07T19:27:11.494219 +# +node,type_emission,type_tec,year,lvl,mrg +R12_GLB,CO2_shipping_IMO,bunkers,2055,5284.612225974673,0.0 +R12_GLB,CO2_shipping_IMO,bunkers,2060,330.82231727551,0.0 +R12_GLB,CO2_shipping_IMO,bunkers,2070,332.1572884799681,0.0 +R12_GLB,CO2_shipping_IMO,bunkers,2080,337.9294736703953,0.0 +R12_GLB,CO2_shipping_IMO,bunkers,2090,392.2513710834383,0.0 +R12_GLB,CO2_shipping_IMO,bunkers,2100,342.0181312146865,0.0 +R12_GLB,CO2_shipping_IMO,bunkers,2110,326.3373130149824,0.0 diff --git a/message_ix_models/data/transport/R12/price-emission/SSP_SSP1_v6.5_SSP1 - Low Emissions_v2.csv b/message_ix_models/data/transport/R12/price-emission/SSP_SSP1_v6.5_SSP1 - Low Emissions_v2.csv new file mode 100644 index 0000000000..336186fbe1 --- /dev/null +++ b/message_ix_models/data/transport/R12/price-emission/SSP_SSP1_v6.5_SSP1 - Low Emissions_v2.csv @@ -0,0 +1,148 @@ +# Exported using: +# mix-models --url="ixmp://ixmp-dev/SSP_SSP1_v6.5/SSP1 - Low Emissions" transport export-price +# at 2026-04-07T19:28:01.143829 +# +node,type_emission,type_tec,year,lvl,mrg +R12_AFR,TCE,all,2035,27.986206720799046,0.0 +R12_AFR,TCE,all,2040,467.35267961138027,0.0 +R12_AFR,TCE,all,2045,444.5070441895579,0.0 +R12_AFR,TCE,all,2050,311.55643015397334,0.0 +R12_AFR,TCE,all,2055,422.78661070120506,0.0 +R12_AFR,TCE,all,2060,501.2019227503621,0.0 +R12_AFR,TCE,all,2070,322.69109219078086,0.0 +R12_AFR,TCE,all,2080,813.7065004041036,0.0 +R12_AFR,TCE,all,2090,283.2237440386424,0.0 +R12_AFR,TCE,all,2100,349.3235759372356,0.0 +R12_AFR,TCE,all,2110,391.42089075696026,0.0 +R12_EEU,TCE,all,2035,511.6312835286653,0.0 +R12_EEU,TCE,all,2040,425.5848369045436,0.0 +R12_EEU,TCE,all,2045,409.51882625905307,0.0 +R12_EEU,TCE,all,2050,1845.882528017128,0.0 +R12_EEU,TCE,all,2055,717.774921366223,0.0 +R12_EEU,TCE,all,2060,800.3242158967148,0.0 +R12_EEU,TCE,all,2070,1030.9060814821876,0.0 +R12_EEU,TCE,all,2080,1651.924312788974,0.0 +R12_EEU,TCE,all,2090,536.0220701273116,0.0 +R12_EEU,TCE,all,2100,461.2192537455781,0.0 +R12_EEU,TCE,all,2110,501.6761418755649,0.0 +R12_GLB,TCE,all,2035,340.239213661948,0.0 +R12_GLB,TCE,all,2040,450.6053842655253,0.0 +R12_GLB,TCE,all,2045,657.7941953375512,0.0 +R12_GLB,TCE,all,2050,1570.8502759050039,0.0 +R12_GLB,TCE,all,2055,4676.034426542131,0.0 +R12_GLB,TCE,all,2060,3343.2100489082222,0.0 +R12_GLB,TCE,all,2070,1194.9656610391576,0.0 +R12_GLB,TCE,all,2080,1404.7128455811344,0.0 +R12_GLB,TCE,all,2090,1546.0219248138126,0.0 +R12_GLB,TCE,all,2100,1187.178727613958,0.0 +R12_GLB,TCE,all,2110,1057.595474936114,0.0 +R12_LAM,TCE,all,2035,104.35956921758698,0.0 +R12_LAM,TCE,all,2040,34.36530431101274,0.0 +R12_LAM,TCE,all,2045,150.41146248532553,0.0 +R12_LAM,TCE,all,2050,70.66413911022997,0.0 +R12_LAM,TCE,all,2055,215.70938549273615,0.0 +R12_LAM,TCE,all,2060,500.78316716420227,0.0 +R12_LAM,TCE,all,2070,322.12831969990657,0.0 +R12_LAM,TCE,all,2080,571.0962259015375,0.0 +R12_LAM,TCE,all,2090,282.2073143203114,0.0 +R12_LAM,TCE,all,2100,347.9575793903185,0.0 +R12_LAM,TCE,all,2110,389.5851056234308,0.0 +R12_MEA,TCE,all,2035,42.44930741342586,0.0 +R12_MEA,TCE,all,2040,119.73946308509876,0.0 +R12_MEA,TCE,all,2045,163.2261479931304,0.0 +R12_MEA,TCE,all,2050,113.03373822668294,0.0 +R12_MEA,TCE,all,2055,216.07060773967356,0.0 +R12_MEA,TCE,all,2060,501.2019227503621,0.0 +R12_MEA,TCE,all,2070,366.9391983609653,0.0 +R12_MEA,TCE,all,2080,1064.9362568410152,0.0 +R12_MEA,TCE,all,2090,615.1496227361866,0.0 +R12_MEA,TCE,all,2100,614.2603491656861,0.0 +R12_MEA,TCE,all,2110,608.2140472193071,0.0 +R12_NAM,TCE,all,2035,23.874635191993924,0.0 +R12_NAM,TCE,all,2040,32.00111496722509,0.0 +R12_NAM,TCE,all,2045,56.87145993746946,0.0 +R12_NAM,TCE,all,2050,70.35254562690982,0.0 +R12_NAM,TCE,all,2055,227.00659759331748,0.0 +R12_NAM,TCE,all,2060,3931.161318243292,0.0 +R12_NAM,TCE,all,2070,337.2331939361697,0.0 +R12_NAM,TCE,all,2080,571.0962259015375,0.0 +R12_NAM,TCE,all,2090,283.22374403864103,0.0 +R12_NAM,TCE,all,2100,347.95757939031864,0.0 +R12_NAM,TCE,all,2110,389.5851056234308,0.0 +R12_SAS,TCE,all,2035,23.874635191993924,0.0 +R12_SAS,TCE,all,2040,52.07247934280867,0.0 +R12_SAS,TCE,all,2045,170.91923438721378,0.0 +R12_SAS,TCE,all,2050,111.37291032814153,0.0 +R12_SAS,TCE,all,2055,216.07060773967,0.0 +R12_SAS,TCE,all,2060,501.20192275035924,0.0 +R12_SAS,TCE,all,2070,1260.297844016243,0.0 +R12_SAS,TCE,all,2080,1113.4385863813409,0.0 +R12_SAS,TCE,all,2090,1651.184594654968,0.0 +R12_SAS,TCE,all,2100,1610.6891276473384,0.0 +R12_SAS,TCE,all,2110,1606.5989398789113,0.0 +R12_WEU,TCE,all,2035,23.874635191993907,0.0 +R12_WEU,TCE,all,2040,32.00111496722509,0.0 +R12_WEU,TCE,all,2045,56.87145993746946,0.0 +R12_WEU,TCE,all,2050,286.6994115472846,0.0 +R12_WEU,TCE,all,2055,13431.39375424236,0.0 +R12_WEU,TCE,all,2060,994.5939086303134,0.0 +R12_WEU,TCE,all,2070,586.7812874955271,0.0 +R12_WEU,TCE,all,2080,804.8925400764435,0.0 +R12_WEU,TCE,all,2090,662.4936285403586,0.0 +R12_WEU,TCE,all,2100,777.222047152305,0.0 +R12_WEU,TCE,all,2110,834.6102275908969,0.0 +R12_FSU,TCE,all,2035,23.874635191993953,0.0 +R12_FSU,TCE,all,2040,32.00111496722509,0.0 +R12_FSU,TCE,all,2045,56.87145993746946,0.0 +R12_FSU,TCE,all,2050,70.35254562690982,0.0 +R12_FSU,TCE,all,2055,215.70938549273615,0.0 +R12_FSU,TCE,all,2060,500.78316716443123,0.0 +R12_FSU,TCE,all,2070,322.12831969990657,0.0 +R12_FSU,TCE,all,2080,571.8525450698678,0.0 +R12_FSU,TCE,all,2090,283.2237440386422,0.0 +R12_FSU,TCE,all,2100,349.3235759372356,0.0 +R12_FSU,TCE,all,2110,389.58510562343093,0.0 +R12_PAO,TCE,all,2035,23.87463519199389,0.0 +R12_PAO,TCE,all,2040,32.00111496722509,0.0 +R12_PAO,TCE,all,2045,56.87145993746946,0.0 +R12_PAO,TCE,all,2050,592.7504895208199,0.0 +R12_PAO,TCE,all,2055,215.70938549273615,0.0 +R12_PAO,TCE,all,2060,500.78316716443123,0.0 +R12_PAO,TCE,all,2070,322.12831969990657,0.0 +R12_PAO,TCE,all,2080,571.0962259015375,0.0 +R12_PAO,TCE,all,2090,282.2073143203114,0.0 +R12_PAO,TCE,all,2100,347.9575793903185,0.0 +R12_PAO,TCE,all,2110,389.5851056234308,0.0 +R12_PAS,TCE,all,2035,31.567995869449643,0.0 +R12_PAS,TCE,all,2040,37.70276442682179,0.0 +R12_PAS,TCE,all,2045,57.14024321333827,0.0 +R12_PAS,TCE,all,2050,70.66413911022997,0.0 +R12_PAS,TCE,all,2055,215.70938549273615,0.0 +R12_PAS,TCE,all,2060,500.78316716443123,0.0 +R12_PAS,TCE,all,2070,322.69109219078086,0.0 +R12_PAS,TCE,all,2080,571.8525450698676,0.0 +R12_PAS,TCE,all,2090,393.7592109608249,0.0 +R12_PAS,TCE,all,2100,375.01031923432356,0.0 +R12_PAS,TCE,all,2110,391.42089075696026,0.0 +R12_CHN,TCE,all,2035,24.074635191993888,0.0 +R12_CHN,TCE,all,2040,32.23296978208509,0.0 +R12_CHN,TCE,all,2045,56.87145993746946,0.0 +R12_CHN,TCE,all,2050,70.35254562690982,0.0 +R12_CHN,TCE,all,2055,215.70938549273615,0.0 +R12_CHN,TCE,all,2060,4492.830710061616,0.0 +R12_CHN,TCE,all,2070,539.9303935721902,0.0 +R12_CHN,TCE,all,2080,785.1300410703798,0.0 +R12_CHN,TCE,all,2090,865.6317437515081,0.0 +R12_CHN,TCE,all,2100,873.1148049803113,0.0 +R12_CHN,TCE,all,2110,710.2662085157774,0.0 +R12_RCPA,TCE,all,2035,31.75083275873066,0.0 +R12_RCPA,TCE,all,2040,34.42431290638738,0.0 +R12_RCPA,TCE,all,2045,102.03817912206848,0.0 +R12_RCPA,TCE,all,2050,1497.8216676998738,0.0 +R12_RCPA,TCE,all,2055,516.4112167054008,0.0 +R12_RCPA,TCE,all,2060,501.2019227503621,0.0 +R12_RCPA,TCE,all,2070,381.76557244749864,0.0 +R12_RCPA,TCE,all,2080,571.8525450698678,0.0 +R12_RCPA,TCE,all,2090,531.8782459029042,0.0 +R12_RCPA,TCE,all,2100,558.544335266056,0.0 +R12_RCPA,TCE,all,2110,503.2742296147667,0.0 diff --git a/message_ix_models/data/transport/R12/price-emission/SSP_SSP1_v6.5_SSP1 - Very Low Emissions_v2.csv b/message_ix_models/data/transport/R12/price-emission/SSP_SSP1_v6.5_SSP1 - Very Low Emissions_v2.csv new file mode 100644 index 0000000000..de39d9d033 --- /dev/null +++ b/message_ix_models/data/transport/R12/price-emission/SSP_SSP1_v6.5_SSP1 - Very Low Emissions_v2.csv @@ -0,0 +1,16 @@ +# Exported using: +# mix-models --url="ixmp://ixmp-dev/SSP_SSP1_v6.5/SSP1 - Very Low Emissions" transport export-price +# at 2026-04-07T19:28:51.651269 +# +node,type_emission,type_tec,year,lvl,mrg +World,TCE,all,2035,309.12822607474226,0.0 +World,TCE,all,2040,358.290036725829,0.0 +World,TCE,all,2045,415.1807800485379,0.0 +World,TCE,all,2050,481.71096641354427,0.0 +World,TCE,all,2055,558.3300109638068,0.0 +World,TCE,all,2060,647.4038454754583,0.0 +World,TCE,all,2070,720.7009669862907,0.0 +World,TCE,all,2080,720.7009669862907,0.0 +World,TCE,all,2090,720.7009669862908,0.0 +World,TCE,all,2100,720.7009669862907,0.0 +World,TCE,all,2110,720.7009669862907,0.0 diff --git a/message_ix_models/data/transport/R12/price-emission/SSP_SSP2_v6.5_SSP2 - High Emissions_v1.csv b/message_ix_models/data/transport/R12/price-emission/SSP_SSP2_v6.5_SSP2 - High Emissions_v1.csv new file mode 100644 index 0000000000..65bd79f00c --- /dev/null +++ b/message_ix_models/data/transport/R12/price-emission/SSP_SSP2_v6.5_SSP2 - High Emissions_v1.csv @@ -0,0 +1,8 @@ +# Exported using: +# mix-models --url="ixmp://ixmp-dev/SSP_SSP2_v6.5/SSP2 - High Emissions" transport export-price +# at 2026-04-07T19:29:46.255758 +# +node,type_emission,type_tec,year,lvl,mrg +R12_GLB,CO2_shipping_IMO,bunkers,2090,4537.274658706932,0.0 +R12_GLB,CO2_shipping_IMO,bunkers,2100,384.621641518828,0.0 +R12_GLB,CO2_shipping_IMO,bunkers,2110,390.60386370178253,0.0 diff --git a/message_ix_models/data/transport/R12/price-emission/SSP_SSP2_v6.5_SSP2 - Low Emissions_v2.csv b/message_ix_models/data/transport/R12/price-emission/SSP_SSP2_v6.5_SSP2 - Low Emissions_v2.csv new file mode 100644 index 0000000000..a5d0296935 --- /dev/null +++ b/message_ix_models/data/transport/R12/price-emission/SSP_SSP2_v6.5_SSP2 - Low Emissions_v2.csv @@ -0,0 +1,148 @@ +# Exported using: +# mix-models --url="ixmp://ixmp-dev/SSP_SSP2_v6.5/SSP2 - Low Emissions" transport export-price +# at 2026-04-07T19:33:08.711752 +# +node,type_emission,type_tec,year,lvl,mrg +R12_AFR,TCE,all,2035,457.4718018905821,0.0 +R12_AFR,TCE,all,2040,1044.2424970470915,0.0 +R12_AFR,TCE,all,2045,695.5933085573403,0.0 +R12_AFR,TCE,all,2050,783.485558888148,0.0 +R12_AFR,TCE,all,2055,375.8835799422166,0.0 +R12_AFR,TCE,all,2060,352.01143511147194,0.0 +R12_AFR,TCE,all,2070,558.7541010289455,0.0 +R12_AFR,TCE,all,2080,595.4158550412619,0.0 +R12_AFR,TCE,all,2090,659.1544278579487,0.0 +R12_AFR,TCE,all,2100,682.859274139953,0.0 +R12_AFR,TCE,all,2110,652.2118201954781,0.0 +R12_EEU,TCE,all,2035,300.0334677026974,0.0 +R12_EEU,TCE,all,2040,366.74658162955154,0.0 +R12_EEU,TCE,all,2045,212.21698441945432,0.0 +R12_EEU,TCE,all,2050,256.4056702374348,0.0 +R12_EEU,TCE,all,2055,1143.849996386085,0.0 +R12_EEU,TCE,all,2060,467.8707189112857,0.0 +R12_EEU,TCE,all,2070,558.7541010289457,0.0 +R12_EEU,TCE,all,2080,669.8040049823541,0.0 +R12_EEU,TCE,all,2090,889.0274687223167,0.0 +R12_EEU,TCE,all,2100,982.3986012814297,0.0 +R12_EEU,TCE,all,2110,930.9318059536477,0.0 +R12_GLB,TCE,all,2035,310.5034931815895,0.0 +R12_GLB,TCE,all,2040,991.6928453698773,0.0 +R12_GLB,TCE,all,2045,760.7612037990809,0.0 +R12_GLB,TCE,all,2050,611.7080234700634,0.0 +R12_GLB,TCE,all,2055,948.9114976202475,0.0 +R12_GLB,TCE,all,2060,2091.890133993212,0.0 +R12_GLB,TCE,all,2070,1193.5900053210642,0.0 +R12_GLB,TCE,all,2080,971.2704678188609,0.0 +R12_GLB,TCE,all,2090,1054.3769427258392,0.0 +R12_GLB,TCE,all,2100,1052.4556650577229,0.0 +R12_GLB,TCE,all,2110,1683.0420876986182,0.0 +R12_LAM,TCE,all,2035,117.59794753271454,0.0 +R12_LAM,TCE,all,2040,118.56464338118082,0.0 +R12_LAM,TCE,all,2045,179.28964325264167,0.0 +R12_LAM,TCE,all,2050,156.97212996773533,0.0 +R12_LAM,TCE,all,2055,249.8309221925368,0.0 +R12_LAM,TCE,all,2060,351.33416412329206,0.0 +R12_LAM,TCE,all,2070,557.6508979554274,0.0 +R12_LAM,TCE,all,2080,595.4158550412619,0.0 +R12_LAM,TCE,all,2090,656.2273016746739,0.0 +R12_LAM,TCE,all,2100,678.0912940281173,0.0 +R12_LAM,TCE,all,2110,644.4452830107269,0.0 +R12_MEA,TCE,all,2035,309.42983118891175,0.0 +R12_MEA,TCE,all,2040,361.3070734143141,0.0 +R12_MEA,TCE,all,2045,321.0407879795653,0.0 +R12_MEA,TCE,all,2050,237.6450606752094,0.0 +R12_MEA,TCE,all,2055,281.4562451715461,0.0 +R12_MEA,TCE,all,2060,352.01143511147194,0.0 +R12_MEA,TCE,all,2070,558.7541010289457,0.0 +R12_MEA,TCE,all,2080,597.2128565999604,0.0 +R12_MEA,TCE,all,2090,659.1544278579487,0.0 +R12_MEA,TCE,all,2100,682.8592741399534,0.0 +R12_MEA,TCE,all,2110,652.3648186916367,0.0 +R12_NAM,TCE,all,2035,71.16954123913058,0.0 +R12_NAM,TCE,all,2040,118.3093870686808,0.0 +R12_NAM,TCE,all,2045,178.96386432728616,0.0 +R12_NAM,TCE,all,2050,156.5563443318546,0.0 +R12_NAM,TCE,all,2055,249.30026265150792,0.0 +R12_NAM,TCE,all,2060,351.33416412329206,0.0 +R12_NAM,TCE,all,2070,557.6508979554274,0.0 +R12_NAM,TCE,all,2080,597.2128565999604,0.0 +R12_NAM,TCE,all,2090,656.2273016746739,0.0 +R12_NAM,TCE,all,2100,678.0912940281165,0.0 +R12_NAM,TCE,all,2110,644.4452830107269,0.0 +R12_SAS,TCE,all,2035,71.36954123913078,0.0 +R12_SAS,TCE,all,2040,138.2277592568608,0.0 +R12_SAS,TCE,all,2045,224.30853917988748,0.0 +R12_SAS,TCE,all,2050,225.69010500899475,0.0 +R12_SAS,TCE,all,2055,249.8309221925368,0.0 +R12_SAS,TCE,all,2060,417.97376140399297,0.0 +R12_SAS,TCE,all,2070,760.8381096764655,0.0 +R12_SAS,TCE,all,2080,964.027671622367,0.0 +R12_SAS,TCE,all,2090,1084.3589254739054,0.0 +R12_SAS,TCE,all,2100,1740.103999191822,0.0 +R12_SAS,TCE,all,2110,2326.3640771163823,0.0 +R12_WEU,TCE,all,2035,287.6514158052839,0.0 +R12_WEU,TCE,all,2040,271.36257339335805,0.0 +R12_WEU,TCE,all,2045,258.00450553757776,0.0 +R12_WEU,TCE,all,2050,419.6670915739226,0.0 +R12_WEU,TCE,all,2055,626.1066150566011,0.0 +R12_WEU,TCE,all,2060,2391.9047516645705,0.0 +R12_WEU,TCE,all,2070,558.7541010289457,0.0 +R12_WEU,TCE,all,2080,599.8063903388241,0.0 +R12_WEU,TCE,all,2090,779.6384436171959,0.0 +R12_WEU,TCE,all,2100,932.626312881825,0.0 +R12_WEU,TCE,all,2110,1483.7206832583656,0.0 +R12_FSU,TCE,all,2035,71.16954123913064,0.0 +R12_FSU,TCE,all,2040,118.3093870686808,0.0 +R12_FSU,TCE,all,2045,178.96386432728616,0.0 +R12_FSU,TCE,all,2050,156.5563443318546,0.0 +R12_FSU,TCE,all,2055,249.30026265150792,0.0 +R12_FSU,TCE,all,2060,351.33416412329206,0.0 +R12_FSU,TCE,all,2070,557.6508979554274,0.0 +R12_FSU,TCE,all,2080,595.4158550412619,0.0 +R12_FSU,TCE,all,2090,656.2273016746739,0.0 +R12_FSU,TCE,all,2100,678.0912940281171,0.0 +R12_FSU,TCE,all,2110,644.4452830107269,0.0 +R12_PAO,TCE,all,2035,71.16954123913064,0.0 +R12_PAO,TCE,all,2040,118.3093870686808,0.0 +R12_PAO,TCE,all,2045,178.96386432728667,0.0 +R12_PAO,TCE,all,2050,156.9721299677369,0.0 +R12_PAO,TCE,all,2055,508.6297430534355,0.0 +R12_PAO,TCE,all,2060,352.01143511147194,0.0 +R12_PAO,TCE,all,2070,557.6508979554274,0.0 +R12_PAO,TCE,all,2080,595.4158550412619,0.0 +R12_PAO,TCE,all,2090,656.2273016746739,0.0 +R12_PAO,TCE,all,2100,678.0912940281171,0.0 +R12_PAO,TCE,all,2110,644.4452830107269,0.0 +R12_PAS,TCE,all,2035,71.16954123913064,0.0 +R12_PAS,TCE,all,2040,118.3093870686808,0.0 +R12_PAS,TCE,all,2045,178.96386432728616,0.0 +R12_PAS,TCE,all,2050,156.5563443318546,0.0 +R12_PAS,TCE,all,2055,249.30026265150792,0.0 +R12_PAS,TCE,all,2060,351.33416412329206,0.0 +R12_PAS,TCE,all,2070,557.6508979554274,0.0 +R12_PAS,TCE,all,2080,595.4158550412619,0.0 +R12_PAS,TCE,all,2090,656.2273016746735,0.0 +R12_PAS,TCE,all,2100,678.0912940281171,0.0 +R12_PAS,TCE,all,2110,644.4452830107269,0.0 +R12_CHN,TCE,all,2035,71.16954123913064,0.0 +R12_CHN,TCE,all,2040,118.3093870686808,0.0 +R12_CHN,TCE,all,2045,178.96386432728616,0.0 +R12_CHN,TCE,all,2050,156.5563443318546,0.0 +R12_CHN,TCE,all,2055,249.30026265150792,0.0 +R12_CHN,TCE,all,2060,351.33416412329206,0.0 +R12_CHN,TCE,all,2070,1256.6719938689396,0.0 +R12_CHN,TCE,all,2080,681.8576121660878,0.0 +R12_CHN,TCE,all,2090,832.090471658559,0.0 +R12_CHN,TCE,all,2100,1197.0993274910345,0.0 +R12_CHN,TCE,all,2110,1854.000470201083,0.0 +R12_RCPA,TCE,all,2035,86.05404913960399,0.0 +R12_RCPA,TCE,all,2040,141.2604436642539,0.0 +R12_RCPA,TCE,all,2045,217.34103674073936,0.0 +R12_RCPA,TCE,all,2050,306.72494481145304,0.0 +R12_RCPA,TCE,all,2055,588.4447013776846,0.0 +R12_RCPA,TCE,all,2060,352.01143511147194,0.0 +R12_RCPA,TCE,all,2070,558.7541010289457,0.0 +R12_RCPA,TCE,all,2080,597.2128565999604,0.0 +R12_RCPA,TCE,all,2090,659.1544278579487,0.0 +R12_RCPA,TCE,all,2100,707.5196545267625,0.0 +R12_RCPA,TCE,all,2110,1150.2790547291677,0.0 diff --git a/message_ix_models/data/transport/R12/price-emission/SSP_SSP2_v6.5_SSP2 - Low Overshoot_v2.csv b/message_ix_models/data/transport/R12/price-emission/SSP_SSP2_v6.5_SSP2 - Low Overshoot_v2.csv new file mode 100644 index 0000000000..d0badf1173 --- /dev/null +++ b/message_ix_models/data/transport/R12/price-emission/SSP_SSP2_v6.5_SSP2 - Low Overshoot_v2.csv @@ -0,0 +1,15 @@ +# Exported using: +# mix-models --url="ixmp://ixmp-dev/SSP_SSP2_v6.5/SSP2 - Low Overshoot" transport export-price +# at 2026-04-07T19:30:36.614016 +# +node,type_emission,type_tec,year,lvl,mrg +World,TCE,all,2040,217.81660994945733,0.0 +World,TCE,all,2045,277.9953232847465,0.0 +World,TCE,all,2050,354.8003055695489,0.0 +World,TCE,all,2055,452.82508836778146,0.0 +World,TCE,all,2060,577.9323113212328,0.0 +World,TCE,all,2070,827.1303972767862,0.0 +World,TCE,all,2080,1347.3082597684481,0.0 +World,TCE,all,2090,2194.6231849496917,0.0 +World,TCE,all,2100,3574.809913765749,0.0 +World,TCE,all,2110,5822.98866028376,0.0 diff --git a/message_ix_models/data/transport/R12/price-emission/SSP_SSP2_v6.5_SSP2 - Medium-Low Emissions_v2.csv b/message_ix_models/data/transport/R12/price-emission/SSP_SSP2_v6.5_SSP2 - Medium-Low Emissions_v2.csv new file mode 100644 index 0000000000..038a16ac1b --- /dev/null +++ b/message_ix_models/data/transport/R12/price-emission/SSP_SSP2_v6.5_SSP2 - Medium-Low Emissions_v2.csv @@ -0,0 +1,14 @@ +# Exported using: +# mix-models --url="ixmp://ixmp-dev/SSP_SSP2_v6.5/SSP2 - Medium-Low Emissions" transport export-price +# at 2026-04-07T19:32:18.075825 +# +node,type_emission,type_tec,year,lvl,mrg +World,TCE,all,2045,38.849018814864,0.0 +World,TCE,all,2050,49.58228643462654,0.0 +World,TCE,all,2055,63.28095800310772,0.0 +World,TCE,all,2060,80.76431995670322,0.0 +World,TCE,all,2070,115.58901058647753,0.0 +World,TCE,all,2080,188.28231825883412,0.0 +World,TCE,all,2090,306.6920565290152,0.0 +World,TCE,all,2100,499.5690429554364,0.0 +World,TCE,all,2110,813.7453297744595,0.0 diff --git a/message_ix_models/data/transport/R12/price-emission/SSP_SSP2_v6.6_SSP2 - Medium Emissions_v1.csv b/message_ix_models/data/transport/R12/price-emission/SSP_SSP2_v6.6_SSP2 - Medium Emissions_v1.csv new file mode 100644 index 0000000000..ca1be2aff3 --- /dev/null +++ b/message_ix_models/data/transport/R12/price-emission/SSP_SSP2_v6.6_SSP2 - Medium Emissions_v1.csv @@ -0,0 +1,104 @@ +# Exported using: +# mix-models --url="ixmp://ixmp-dev/SSP_SSP2_v6.6/SSP2 - Medium Emissions" transport export-price +# at 2026-04-07T19:31:26.682604 +# +node,type_emission,type_tec,year,lvl,mrg +R12_AFR,TCE,all,2035,1.116,0.0 +R12_AFR,TCE,all,2040,1.116,0.0 +R12_AFR,TCE,all,2045,1.116,0.0 +R12_AFR,TCE,all,2050,1.116,0.0 +R12_AFR,TCE,all,2055,1.116,0.0 +R12_AFR,TCE,all,2060,1.116,0.0 +R12_AFR,TCE,all,2070,1.116,0.0 +R12_AFR,TCE,all,2080,1.116,0.0 +R12_AFR,TCE,all,2090,1.116,0.0 +R12_AFR,TCE,all,2100,1.116,0.0 +R12_AFR,TCE,all,2110,1.116,0.0 +R12_EEU,TCE,all,2035,200.162,0.0 +R12_EEU,TCE,all,2040,200.162,0.0 +R12_EEU,TCE,all,2045,200.162,0.0 +R12_EEU,TCE,all,2050,200.16199999999998,0.0 +R12_EEU,TCE,all,2055,200.162,0.0 +R12_EEU,TCE,all,2060,200.162,0.0 +R12_EEU,TCE,all,2070,200.162,0.0 +R12_EEU,TCE,all,2080,200.162,0.0 +R12_EEU,TCE,all,2090,200.162,0.0 +R12_EEU,TCE,all,2100,200.162,0.0 +R12_EEU,TCE,all,2110,200.162,0.0 +R12_LAM,TCE,all,2035,29.212,0.0 +R12_LAM,TCE,all,2040,29.212,0.0 +R12_LAM,TCE,all,2045,29.212,0.0 +R12_LAM,TCE,all,2050,29.212000000000003,0.0 +R12_LAM,TCE,all,2055,29.212,0.0 +R12_LAM,TCE,all,2060,29.212,0.0 +R12_LAM,TCE,all,2070,29.212,0.0 +R12_LAM,TCE,all,2080,29.212,0.0 +R12_LAM,TCE,all,2090,29.212,0.0 +R12_LAM,TCE,all,2100,29.212,0.0 +R12_LAM,TCE,all,2110,29.212,0.0 +R12_NAM,TCE,all,2035,155.91,0.0 +R12_NAM,TCE,all,2040,155.91,0.0 +R12_NAM,TCE,all,2045,155.91,0.0 +R12_NAM,TCE,all,2050,155.91,0.0 +R12_NAM,TCE,all,2055,155.91,0.0 +R12_NAM,TCE,all,2060,155.91,0.0 +R12_NAM,TCE,all,2070,155.91,0.0 +R12_NAM,TCE,all,2080,155.91,0.0 +R12_NAM,TCE,all,2090,155.91,0.0 +R12_NAM,TCE,all,2100,155.91,0.0 +R12_NAM,TCE,all,2110,155.91,0.0 +R12_SAS,TCE,all,2035,0.045,0.0 +R12_SAS,TCE,all,2040,0.045,0.0 +R12_SAS,TCE,all,2045,0.045,0.0 +R12_SAS,TCE,all,2050,0.045,0.0 +R12_SAS,TCE,all,2055,0.045,0.0 +R12_SAS,TCE,all,2060,0.045,0.0 +R12_SAS,TCE,all,2070,0.045,0.0 +R12_SAS,TCE,all,2080,0.045,0.0 +R12_SAS,TCE,all,2090,0.045000000000000005,0.0 +R12_SAS,TCE,all,2100,0.045,0.0 +R12_SAS,TCE,all,2110,0.045,0.0 +R12_WEU,TCE,all,2035,252.422,0.0 +R12_WEU,TCE,all,2040,252.42199999999997,0.0 +R12_WEU,TCE,all,2045,252.422,0.0 +R12_WEU,TCE,all,2050,252.422,0.0 +R12_WEU,TCE,all,2055,252.422,0.0 +R12_WEU,TCE,all,2060,252.422,0.0 +R12_WEU,TCE,all,2070,252.422,0.0 +R12_WEU,TCE,all,2080,252.422,0.0 +R12_WEU,TCE,all,2090,252.422,0.0 +R12_WEU,TCE,all,2100,252.422,0.0 +R12_WEU,TCE,all,2110,252.42199999999997,0.0 +R12_PAO,TCE,all,2035,0.094,0.0 +R12_PAO,TCE,all,2040,0.094,0.0 +R12_PAO,TCE,all,2045,0.094,0.0 +R12_PAO,TCE,all,2050,0.09399999999999999,0.0 +R12_PAO,TCE,all,2055,0.094,0.0 +R12_PAO,TCE,all,2060,0.094,0.0 +R12_PAO,TCE,all,2070,0.094,0.0 +R12_PAO,TCE,all,2080,0.094,0.0 +R12_PAO,TCE,all,2090,0.094,0.0 +R12_PAO,TCE,all,2100,0.094,0.0 +R12_PAO,TCE,all,2110,0.094,0.0 +R12_PAS,TCE,all,2035,14.101,0.0 +R12_PAS,TCE,all,2040,14.101,0.0 +R12_PAS,TCE,all,2045,14.101,0.0 +R12_PAS,TCE,all,2050,14.101,0.0 +R12_PAS,TCE,all,2055,14.101,0.0 +R12_PAS,TCE,all,2060,14.101000000000003,0.0 +R12_PAS,TCE,all,2070,14.101,0.0 +R12_PAS,TCE,all,2080,14.101,0.0 +R12_PAS,TCE,all,2090,14.101,0.0 +R12_PAS,TCE,all,2100,14.101,0.0 +R12_PAS,TCE,all,2110,14.100999999999999,0.0 +R12_RCPA,TCE,all,2035,0.023,0.0 +R12_RCPA,TCE,all,2040,0.023,0.0 +R12_RCPA,TCE,all,2045,0.023,0.0 +R12_RCPA,TCE,all,2050,0.023,0.0 +R12_RCPA,TCE,all,2055,0.023,0.0 +R12_RCPA,TCE,all,2060,0.022999999999999996,0.0 +R12_RCPA,TCE,all,2070,0.023,0.0 +R12_RCPA,TCE,all,2080,0.023,0.0 +R12_RCPA,TCE,all,2090,0.023,0.0 +R12_RCPA,TCE,all,2100,0.023,0.0 +R12_RCPA,TCE,all,2110,0.023,0.0 diff --git a/message_ix_models/data/transport/R12/price-emission/SSP_SSP3_v6.5_SSP3 - High Emissions_v2.csv b/message_ix_models/data/transport/R12/price-emission/SSP_SSP3_v6.5_SSP3 - High Emissions_v2.csv new file mode 100644 index 0000000000..de1b880ba9 --- /dev/null +++ b/message_ix_models/data/transport/R12/price-emission/SSP_SSP3_v6.5_SSP3 - High Emissions_v2.csv @@ -0,0 +1,5 @@ +# Exported using: +# mix-models --url="ixmp://ixmp-dev/SSP_SSP3_v6.5/SSP3 - High Emissions" transport export-price +# at 2026-04-07T19:33:58.993258 +# +node,type_emission,type_tec,year,lvl,mrg diff --git a/message_ix_models/data/transport/R12/price-emission/SSP_SSP3_v6.5_SSP3 - Medium-Low Emissions_a_v1.csv b/message_ix_models/data/transport/R12/price-emission/SSP_SSP3_v6.5_SSP3 - Medium-Low Emissions_a_v1.csv new file mode 100644 index 0000000000..5dde1edb59 --- /dev/null +++ b/message_ix_models/data/transport/R12/price-emission/SSP_SSP3_v6.5_SSP3 - Medium-Low Emissions_a_v1.csv @@ -0,0 +1,10 @@ +# Exported using: +# mix-models --url="ixmp://ixmp-dev/SSP_SSP3_v6.5/SSP3 - Medium-Low Emissions_a" transport export-price +# at 2026-04-07T19:34:51.945187 +# +node,type_emission,type_tec,year,lvl,mrg +World,TCE,all,2070,1682.0469667125099,0.0 +World,TCE,all,2080,2739.877266065302,0.0 +World,TCE,all,2090,4462.971356723439,0.0 +World,TCE,all,2100,7269.71006242844,0.0 +World,TCE,all,2110,11841.591658919591,0.0 diff --git a/message_ix_models/data/transport/R12/price-emission/SSP_SSP4_v6.5_SSP4 - High Emissions_v1.csv b/message_ix_models/data/transport/R12/price-emission/SSP_SSP4_v6.5_SSP4 - High Emissions_v1.csv new file mode 100644 index 0000000000..d6e3ff464a --- /dev/null +++ b/message_ix_models/data/transport/R12/price-emission/SSP_SSP4_v6.5_SSP4 - High Emissions_v1.csv @@ -0,0 +1,5 @@ +# Exported using: +# mix-models --url="ixmp://ixmp-dev/SSP_SSP4_v6.5/SSP4 - High Emissions" transport export-price +# at 2026-04-07T19:35:43.226663 +# +node,type_emission,type_tec,year,lvl,mrg diff --git a/message_ix_models/data/transport/R12/price-emission/SSP_SSP4_v6.5_SSP4 - Low Overshoot_v2.csv b/message_ix_models/data/transport/R12/price-emission/SSP_SSP4_v6.5_SSP4 - Low Overshoot_v2.csv new file mode 100644 index 0000000000..dc4599e71a --- /dev/null +++ b/message_ix_models/data/transport/R12/price-emission/SSP_SSP4_v6.5_SSP4 - Low Overshoot_v2.csv @@ -0,0 +1,15 @@ +# Exported using: +# mix-models --url="ixmp://ixmp-dev/SSP_SSP4_v6.5/SSP4 - Low Overshoot" transport export-price +# at 2026-04-07T19:36:33.741874 +# +node,type_emission,type_tec,year,lvl,mrg +World,TCE,all,2040,146.23157631247022,0.0 +World,TCE,all,2045,186.6326647029175,0.0 +World,TCE,all,2050,238.1958289205782,0.0 +World,TCE,all,2055,304.0049447157383,0.0 +World,TCE,all,2060,387.99590584952864,0.0 +World,TCE,all,2070,555.2954930196108,0.0 +World,TCE,all,2080,904.5178448533748,0.0 +World,TCE,all,2090,1473.3642573059742,0.0 +World,TCE,all,2100,2399.9551220116377,0.0 +World,TCE,all,2110,3909.2740027517575,0.0 diff --git a/message_ix_models/data/transport/R12/price-emission/SSP_SSP5_v6.5_SSP5 - High Emissions_v2.csv b/message_ix_models/data/transport/R12/price-emission/SSP_SSP5_v6.5_SSP5 - High Emissions_v2.csv new file mode 100644 index 0000000000..6fba054c16 --- /dev/null +++ b/message_ix_models/data/transport/R12/price-emission/SSP_SSP5_v6.5_SSP5 - High Emissions_v2.csv @@ -0,0 +1,5 @@ +# Exported using: +# mix-models --url="ixmp://ixmp-dev/SSP_SSP5_v6.5/SSP5 - High Emissions" transport export-price +# at 2026-04-07T19:37:23.616510 +# +node,type_emission,type_tec,year,lvl,mrg diff --git a/message_ix_models/data/transport/R12/price-emission/SSP_SSP5_v6.5_SSP5 - Low Overshoot_v2.csv b/message_ix_models/data/transport/R12/price-emission/SSP_SSP5_v6.5_SSP5 - Low Overshoot_v2.csv new file mode 100644 index 0000000000..7a51983e76 --- /dev/null +++ b/message_ix_models/data/transport/R12/price-emission/SSP_SSP5_v6.5_SSP5 - Low Overshoot_v2.csv @@ -0,0 +1,15 @@ +# Exported using: +# mix-models --url="ixmp://ixmp-dev/SSP_SSP5_v6.5/SSP5 - Low Overshoot" transport export-price +# at 2026-04-07T19:38:15.358906 +# +node,type_emission,type_tec,year,lvl,mrg +World,TCE,all,2040,671.1788403289141,0.0 +World,TCE,all,2045,856.6131790519247,0.0 +World,TCE,all,2050,1093.2796066184828,0.0 +World,TCE,all,2055,1395.332604584423,0.0 +World,TCE,all,2060,1780.8372767862022,0.0 +World,TCE,all,2070,2548.7148155223163,0.0 +World,TCE,all,2080,4151.5878681923605,0.0 +World,TCE,all,2090,6762.499171092952,0.0 +World,TCE,all,2100,11015.398563380215,0.0 +World,TCE,all,2110,17942.92353170199,0.0 diff --git a/message_ix_models/data/transport/R12/price-emission/SSP_SSP5_v6.5_SSP5 - Medium-Low Emissions_a_v1.csv b/message_ix_models/data/transport/R12/price-emission/SSP_SSP5_v6.5_SSP5 - Medium-Low Emissions_a_v1.csv new file mode 100644 index 0000000000..2a513d992d --- /dev/null +++ b/message_ix_models/data/transport/R12/price-emission/SSP_SSP5_v6.5_SSP5 - Medium-Low Emissions_a_v1.csv @@ -0,0 +1,10 @@ +# Exported using: +# mix-models --url="ixmp://ixmp-dev/SSP_SSP5_v6.5/SSP5 - Medium-Low Emissions_a" transport export-price +# at 2026-04-07T19:39:06.461627 +# +node,type_emission,type_tec,year,lvl,mrg +World,TCE,all,2070,157.05140601954372,0.0 +World,TCE,all,2080,255.8201913930772,0.0 +World,TCE,all,2090,416.7041351813603,0.0 +World,TCE,all,2100,678.7671267528586,0.0 +World,TCE,all,2110,1105.6401256008944,0.0 diff --git a/message_ix_models/tests/model/transport/test_config.py b/message_ix_models/tests/model/transport/test_config.py index 0fa51e4670..7320cd1d1b 100644 --- a/message_ix_models/tests/model/transport/test_config.py +++ b/message_ix_models/tests/model/transport/test_config.py @@ -144,11 +144,11 @@ def test_get(self, test_context: Context) -> None: @pytest.mark.parametrize( "ssp_or_led, N_exp", ( - ("SSP1", 7), - ("SSP2", 22), - ("SSP3", 1), - ("SSP4", 5), - ("SSP5", 7), + ("SSP1", 10), + ("SSP2", 27), + ("SSP3", 3), + ("SSP4", 7), + ("SSP5", 10), ), ) def test_iter_price_emission(ssp_or_led: str, N_exp: int, regions="R12") -> None: From 764eca33c92b311f0bd073cee8b2a635fc652e48 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Tue, 7 Apr 2026 20:02:47 +0200 Subject: [PATCH 65/73] =?UTF-8?q?Bump=20CL=5FTRANSPORT=5FSCENARIO=201.3.0?= =?UTF-8?q?=20=E2=86=92=201.4.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Increase base model version from v6.1 to v6.5 or v6.6. - Add additional "exo price" cases for #271. - Simplify _append_codes() helper. - Improve docstrings. - Update test expectation of code count. --- ...IIASA_ECE_CL_TRANSPORT_SCENARIO(1.4.0).xml | 9532 +++++++++++++++++ message_ix_models/model/transport/config.py | 72 +- .../tests/model/transport/test_config.py | 2 +- 3 files changed, 9576 insertions(+), 30 deletions(-) create mode 100644 message_ix_models/data/sdmx/IIASA_ECE_CL_TRANSPORT_SCENARIO(1.4.0).xml diff --git a/message_ix_models/data/sdmx/IIASA_ECE_CL_TRANSPORT_SCENARIO(1.4.0).xml b/message_ix_models/data/sdmx/IIASA_ECE_CL_TRANSPORT_SCENARIO(1.4.0).xml new file mode 100644 index 0000000000..ea946d7cbd --- /dev/null +++ b/message_ix_models/data/sdmx/IIASA_ECE_CL_TRANSPORT_SCENARIO(1.4.0).xml @@ -0,0 +1,9532 @@ + + + + none + false + 2026-04-07T19:56:16.015127 + + Generated by message_ix_models 2026.1.16.dev379+g9cf763f5f + + + + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).1' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP1_v6.5/baseline_DEFAULT_step_13' + + + None + + + [] + + + SSP1 baseline + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).1' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP1_v6.5/baseline_DEFAULT_step_13' + + + None + + + ['material'] + + + SSP1 baseline with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).1' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP1_v6.5/baseline_DEFAULT_step_13' + + + TaxEmission(value=1000.0) + + + [] + + + SSP1 with tax + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).1' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP1_v6.5/baseline_DEFAULT_step_13' + + + TaxEmission(value=1000.0) + + + ['material'] + + + SSP1 with tax with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).1' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP1_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP1_v5.3.1/INDC2030i_SSP1 - Low Emissions_a#1') + + + [] + + + SSP1 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).1' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP1_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP1_v5.3.1/INDC2030i_SSP1 - Low Emissions_a#1') + + + ['material'] + + + SSP1 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).1' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP1_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP1_v5.3.1/INDC2030i_SSP1 - Very Low Emissions#1') + + + [] + + + SSP1 with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).1' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP1_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP1_v5.3.1/INDC2030i_SSP1 - Very Low Emissions#1') + + + ['material'] + + + SSP1 with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).1' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP1_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP1_v5.3.1/SSP1 - Low Emissions#2') + + + [] + + + SSP1 with exogenous price with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).1' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP1_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP1_v5.3.1/SSP1 - Low Emissions#2') + + + ['material'] + + + SSP1 with exogenous price with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).1' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP1_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP1_v5.3.1/SSP1 - Very Low Emissions#2') + + + [] + + + SSP1 with exogenous price with exogenous price with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).1' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP1_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP1_v5.3.1/SSP1 - Very Low Emissions#2') + + + ['material'] + + + SSP1 with exogenous price with exogenous price with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).1' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP1_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP1_v5.3.1/INDC2030i_SSP1 - Low Emissions#1') + + + [] + + + SSP1 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).1' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP1_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP1_v5.3.1/INDC2030i_SSP1 - Low Emissions#1') + + + ['material'] + + + SSP1 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).1' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP1_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP1_v6.5/SSP1 - Very Low Emissions#2') + + + [] + + + SSP1 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).1' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP1_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP1_v6.5/SSP1 - Very Low Emissions#2') + + + ['material'] + + + SSP1 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).1' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP1_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP1_v6.5/SSP1 - Low Emissions#2') + + + [] + + + SSP1 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).1' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP1_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP1_v6.5/SSP1 - Low Emissions#2') + + + ['material'] + + + SSP1 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).1' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP1_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP1_v5.3.1/SSP1 - Low Emissions_a#2') + + + [] + + + SSP1 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).1' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP1_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP1_v5.3.1/SSP1 - Low Emissions_a#2') + + + ['material'] + + + SSP1 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).1' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP1_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP1_v6.5/SSP1 - High Emissions#1') + + + [] + + + SSP1 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).1' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP1_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP1_v6.5/SSP1 - High Emissions#1') + + + ['material'] + + + SSP1 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).1' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP1_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP1_v5.3.1/baseline_1000f#1') + + + [] + + + SSP1 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).1' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP1_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP1_v5.3.1/baseline_1000f#1') + + + ['material'] + + + SSP1 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + None + + + [] + + + SSP2 baseline + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + None + + + ['material'] + + + SSP2 baseline with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + TaxEmission(value=1000.0) + + + [] + + + SSP2 with tax + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + TaxEmission(value=1000.0) + + + ['material'] + + + SSP2 with tax with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_5#3') + + + [] + + + SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_5#3') + + + ['material'] + + + SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v6.5/SSP2 - Low Overshoot#2') + + + [] + + + SSP2 with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v6.5/SSP2 - Low Overshoot#2') + + + ['material'] + + + SSP2 with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/NPiREF_SSP2 - Low Overshootf#3') + + + [] + + + SSP2 with exogenous price with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/NPiREF_SSP2 - Low Overshootf#3') + + + ['material'] + + + SSP2 with exogenous price with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/INDC2030i_SSP2 - Low Emissions_a#1') + + + [] + + + SSP2 with exogenous price with exogenous price with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/INDC2030i_SSP2 - Low Emissions_a#1') + + + ['material'] + + + SSP2 with exogenous price with exogenous price with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/npiref2035_low_dem_scen2#1') + + + [] + + + SSP2 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/npiref2035_low_dem_scen2#1') + + + ['material'] + + + SSP2 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_50#1') + + + [] + + + SSP2 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_50#1') + + + ['material'] + + + SSP2 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/INDC2030i_SSP2 - Low Emissions#1') + + + [] + + + SSP2 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/INDC2030i_SSP2 - Low Emissions#1') + + + ['material'] + + + SSP2 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/NPiREF_SSP2 - Medium-Low Emissionsf#1') + + + [] + + + SSP2 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/NPiREF_SSP2 - Medium-Low Emissionsf#1') + + + ['material'] + + + SSP2 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Medium Emissions#2') + + + [] + + + SSP2 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Medium Emissions#2') + + + ['material'] + + + SSP2 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/NPIREF_price_cap_5$_bkp#1') + + + [] + + + SSP2 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/NPIREF_price_cap_5$_bkp#1') + + + ['material'] + + + SSP2 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/NPiREF#10') + + + [] + + + SSP2 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/NPiREF#10') + + + ['material'] + + + SSP2 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Low Overshoot#2') + + + [] + + + SSP2 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Low Overshoot#2') + + + ['material'] + + + SSP2 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baseline_1000f#2') + + + [] + + + SSP2 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baseline_1000f#2') + + + ['material'] + + + SSP2 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_15#1') + + + [] + + + SSP2 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_15#1') + + + ['material'] + + + SSP2 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_20#1') + + + [] + + + SSP2 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_20#1') + + + ['material'] + + + SSP2 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v6.6/SSP2 - Medium Emissions#1') + + + [] + + + SSP2 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v6.6/SSP2 - Medium Emissions#1') + + + ['material'] + + + SSP2 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v6.5/SSP2 - Low Emissions#2') + + + [] + + + SSP2 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v6.5/SSP2 - Low Emissions#2') + + + ['material'] + + + SSP2 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Low Emissions#2') + + + [] + + + SSP2 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Low Emissions#2') + + + ['material'] + + + SSP2 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_110#1') + + + [] + + + SSP2 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_110#1') + + + ['material'] + + + SSP2 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v6.5/SSP2 - High Emissions#1') + + + [] + + + SSP2 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v6.5/SSP2 - High Emissions#1') + + + ['material'] + + + SSP2 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Medium-Low Emissions#2') + + + [] + + + SSP2 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Medium-Low Emissions#2') + + + ['material'] + + + SSP2 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_25#1') + + + [] + + + SSP2 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_25#1') + + + ['material'] + + + SSP2 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/NPiREF_SSP2 - Low Overshootf_price_cap_5$_bkp#1') + + + [] + + + SSP2 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/NPiREF_SSP2 - Low Overshootf_price_cap_5$_bkp#1') + + + ['material'] + + + SSP2 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v6.5/SSP2 - Medium-Low Emissions#2') + + + [] + + + SSP2 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v6.5/SSP2 - Medium-Low Emissions#2') + + + ['material'] + + + SSP2 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Low Emissions_a#2') + + + [] + + + SSP2 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Low Emissions_a#2') + + + ['material'] + + + SSP2 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_10#1') + + + [] + + + SSP2 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_10#1') + + + ['material'] + + + SSP2 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Medium Emissions_a#2') + + + [] + + + SSP2 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Medium Emissions_a#2') + + + ['material'] + + + SSP2 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).3' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP3_v6.5/baseline_DEFAULT_step_13' + + + None + + + [] + + + SSP3 baseline + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).3' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP3_v6.5/baseline_DEFAULT_step_13' + + + None + + + ['material'] + + + SSP3 baseline with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).3' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP3_v6.5/baseline_DEFAULT_step_13' + + + TaxEmission(value=1000.0) + + + [] + + + SSP3 with tax + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).3' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP3_v6.5/baseline_DEFAULT_step_13' + + + TaxEmission(value=1000.0) + + + ['material'] + + + SSP3 with tax with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).3' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP3_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP3_v6.5/SSP3 - High Emissions#2') + + + [] + + + SSP3 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).3' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP3_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP3_v6.5/SSP3 - High Emissions#2') + + + ['material'] + + + SSP3 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).3' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP3_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP3_v6.5/SSP3 - Medium-Low Emissions_a#1') + + + [] + + + SSP3 with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).3' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP3_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP3_v6.5/SSP3 - Medium-Low Emissions_a#1') + + + ['material'] + + + SSP3 with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).3' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP3_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP3_v5.3.1/baseline_1000f#1') + + + [] + + + SSP3 with exogenous price with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).3' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP3_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP3_v5.3.1/baseline_1000f#1') + + + ['material'] + + + SSP3 with exogenous price with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).4' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP4_v6.5/baseline_DEFAULT_step_13' + + + None + + + [] + + + SSP4 baseline + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).4' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP4_v6.5/baseline_DEFAULT_step_13' + + + None + + + ['material'] + + + SSP4 baseline with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).4' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP4_v6.5/baseline_DEFAULT_step_13' + + + TaxEmission(value=1000.0) + + + [] + + + SSP4 with tax + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).4' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP4_v6.5/baseline_DEFAULT_step_13' + + + TaxEmission(value=1000.0) + + + ['material'] + + + SSP4 with tax with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).4' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP4_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP4_v6.5/SSP4 - High Emissions#1') + + + [] + + + SSP4 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).4' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP4_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP4_v6.5/SSP4 - High Emissions#1') + + + ['material'] + + + SSP4 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).4' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP4_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP4_v5.3.1/baseline_1000f#1') + + + [] + + + SSP4 with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).4' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP4_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP4_v5.3.1/baseline_1000f#1') + + + ['material'] + + + SSP4 with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).4' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP4_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP4_v6.5/SSP4 - Low Overshoot#2') + + + [] + + + SSP4 with exogenous price with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).4' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP4_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP4_v6.5/SSP4 - Low Overshoot#2') + + + ['material'] + + + SSP4 with exogenous price with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).4' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP4_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP4_v5.3.1/SSP4 - Low Overshoot#2') + + + [] + + + SSP4 with exogenous price with exogenous price with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).4' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP4_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP4_v5.3.1/SSP4 - Low Overshoot#2') + + + ['material'] + + + SSP4 with exogenous price with exogenous price with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).4' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP4_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP4_v5.3.1/NPi2030#1') + + + [] + + + SSP4 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).4' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP4_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP4_v5.3.1/NPi2030#1') + + + ['material'] + + + SSP4 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).4' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP4_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP4_v5.3.1/NPiREF_SSP4 - Low Overshootf#1') + + + [] + + + SSP4 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).4' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP4_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP4_v5.3.1/NPiREF_SSP4 - Low Overshootf#1') + + + ['material'] + + + SSP4 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).4' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP4_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP4_v5.3.1/NPiREF#1') + + + [] + + + SSP4 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).4' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP4_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP4_v5.3.1/NPiREF#1') + + + ['material'] + + + SSP4 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).5' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP5_v6.5/baseline_DEFAULT_step_13' + + + None + + + [] + + + SSP5 baseline + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).5' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP5_v6.5/baseline_DEFAULT_step_13' + + + None + + + ['material'] + + + SSP5 baseline with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).5' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP5_v6.5/baseline_DEFAULT_step_13' + + + TaxEmission(value=1000.0) + + + [] + + + SSP5 with tax + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).5' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP5_v6.5/baseline_DEFAULT_step_13' + + + TaxEmission(value=1000.0) + + + ['material'] + + + SSP5 with tax with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).5' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP5_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP5_v6.5/SSP5 - High Emissions#2') + + + [] + + + SSP5 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).5' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP5_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP5_v6.5/SSP5 - High Emissions#2') + + + ['material'] + + + SSP5 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).5' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP5_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP5_v6.5/SSP5 - Medium-Low Emissions_a#1') + + + [] + + + SSP5 with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).5' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP5_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP5_v6.5/SSP5 - Medium-Low Emissions_a#1') + + + ['material'] + + + SSP5 with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).5' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP5_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP5_v5.3.1/baseline_1000f#2') + + + [] + + + SSP5 with exogenous price with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).5' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP5_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP5_v5.3.1/baseline_1000f#2') + + + ['material'] + + + SSP5 with exogenous price with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).5' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP5_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP5_v5.3.1/NPiREF#1') + + + [] + + + SSP5 with exogenous price with exogenous price with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).5' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP5_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP5_v5.3.1/NPiREF#1') + + + ['material'] + + + SSP5 with exogenous price with exogenous price with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).5' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP5_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP5_v5.3.1/baseline2060_low_dem_scen#2') + + + [] + + + SSP5 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).5' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP5_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP5_v5.3.1/baseline2060_low_dem_scen#2') + + + ['material'] + + + SSP5 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).5' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP5_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP5_v5.3.1/baseline2055_low_dem_scen#1') + + + [] + + + SSP5 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).5' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP5_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP5_v5.3.1/baseline2055_low_dem_scen#1') + + + ['material'] + + + SSP5 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).5' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP5_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP5_v5.3.1/NPiREF_SSP5 - Low Overshootf#1') + + + [] + + + SSP5 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).5' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP5_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP5_v5.3.1/NPiREF_SSP5 - Low Overshootf#1') + + + ['material'] + + + SSP5 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).5' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP5_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP5_v5.3.1/NPi2030#1') + + + [] + + + SSP5 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).5' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP5_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP5_v5.3.1/NPi2030#1') + + + ['material'] + + + SSP5 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).5' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP5_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP5_v6.5/SSP5 - Low Overshoot#2') + + + [] + + + SSP5 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).5' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP5_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP5_v6.5/SSP5 - Low Overshoot#2') + + + ['material'] + + + SSP5 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).5' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP5_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP5_v5.3.1/SSP5 - Low Overshoot#2') + + + [] + + + SSP5 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).5' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP5_v6.5/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP5_v5.3.1/SSP5 - Low Overshoot#2') + + + ['material'] + + + SSP5 with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).1' + + + True + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP1_v6.5/baseline_DEFAULT_step_13' + + + None + + + [] + + + Low Energy Demand/High-with-Low scenario with SSP1 demographics + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).1' + + + True + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP1_v6.5/baseline_DEFAULT_step_13' + + + None + + + ['material'] + + + Low Energy Demand/High-with-Low scenario with SSP1 demographics with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + True + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + None + + + [] + + + Low Energy Demand/High-with-Low scenario with SSP2 demographics + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + True + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + None + + + ['material'] + + + Low Energy Demand/High-with-Low scenario with SSP2 demographics with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2).BEST-C' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + None + + + [] + + + DIGSY 'BEST-C' scenario with SSP2 + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2).BEST-C' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + None + + + ['material'] + + + DIGSY 'BEST-C' scenario with SSP2 with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_5#3') + + + [] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_5#3') + + + ['material'] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v6.5/SSP2 - Low Overshoot#2') + + + [] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v6.5/SSP2 - Low Overshoot#2') + + + ['material'] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/NPiREF_SSP2 - Low Overshootf#3') + + + [] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/NPiREF_SSP2 - Low Overshootf#3') + + + ['material'] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/INDC2030i_SSP2 - Low Emissions_a#1') + + + [] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/INDC2030i_SSP2 - Low Emissions_a#1') + + + ['material'] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/npiref2035_low_dem_scen2#1') + + + [] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/npiref2035_low_dem_scen2#1') + + + ['material'] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_50#1') + + + [] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_50#1') + + + ['material'] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/INDC2030i_SSP2 - Low Emissions#1') + + + [] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/INDC2030i_SSP2 - Low Emissions#1') + + + ['material'] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/NPiREF_SSP2 - Medium-Low Emissionsf#1') + + + [] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/NPiREF_SSP2 - Medium-Low Emissionsf#1') + + + ['material'] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Medium Emissions#2') + + + [] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Medium Emissions#2') + + + ['material'] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/NPIREF_price_cap_5$_bkp#1') + + + [] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/NPIREF_price_cap_5$_bkp#1') + + + ['material'] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/NPiREF#10') + + + [] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/NPiREF#10') + + + ['material'] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Low Overshoot#2') + + + [] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Low Overshoot#2') + + + ['material'] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baseline_1000f#2') + + + [] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baseline_1000f#2') + + + ['material'] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_15#1') + + + [] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_15#1') + + + ['material'] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_20#1') + + + [] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_20#1') + + + ['material'] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v6.6/SSP2 - Medium Emissions#1') + + + [] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v6.6/SSP2 - Medium Emissions#1') + + + ['material'] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v6.5/SSP2 - Low Emissions#2') + + + [] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v6.5/SSP2 - Low Emissions#2') + + + ['material'] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Low Emissions#2') + + + [] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Low Emissions#2') + + + ['material'] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_110#1') + + + [] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_110#1') + + + ['material'] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v6.5/SSP2 - High Emissions#1') + + + [] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v6.5/SSP2 - High Emissions#1') + + + ['material'] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Medium-Low Emissions#2') + + + [] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Medium-Low Emissions#2') + + + ['material'] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_25#1') + + + [] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_25#1') + + + ['material'] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/NPiREF_SSP2 - Low Overshootf_price_cap_5$_bkp#1') + + + [] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/NPiREF_SSP2 - Low Overshootf_price_cap_5$_bkp#1') + + + ['material'] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v6.5/SSP2 - Medium-Low Emissions#2') + + + [] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v6.5/SSP2 - Medium-Low Emissions#2') + + + ['material'] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Low Emissions_a#2') + + + [] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Low Emissions_a#2') + + + ['material'] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_10#1') + + + [] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_10#1') + + + ['material'] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Medium Emissions_a#2') + + + [] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Medium Emissions_a#2') + + + ['material'] + + + DIGSY 'BEST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2).BEST-S' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + None + + + [] + + + DIGSY 'BEST-S' scenario with SSP2 + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2).BEST-S' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + None + + + ['material'] + + + DIGSY 'BEST-S' scenario with SSP2 with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_5#3') + + + [] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_5#3') + + + ['material'] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v6.5/SSP2 - Low Overshoot#2') + + + [] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v6.5/SSP2 - Low Overshoot#2') + + + ['material'] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/NPiREF_SSP2 - Low Overshootf#3') + + + [] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/NPiREF_SSP2 - Low Overshootf#3') + + + ['material'] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/INDC2030i_SSP2 - Low Emissions_a#1') + + + [] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/INDC2030i_SSP2 - Low Emissions_a#1') + + + ['material'] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/npiref2035_low_dem_scen2#1') + + + [] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/npiref2035_low_dem_scen2#1') + + + ['material'] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_50#1') + + + [] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_50#1') + + + ['material'] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/INDC2030i_SSP2 - Low Emissions#1') + + + [] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/INDC2030i_SSP2 - Low Emissions#1') + + + ['material'] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/NPiREF_SSP2 - Medium-Low Emissionsf#1') + + + [] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/NPiREF_SSP2 - Medium-Low Emissionsf#1') + + + ['material'] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Medium Emissions#2') + + + [] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Medium Emissions#2') + + + ['material'] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/NPIREF_price_cap_5$_bkp#1') + + + [] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/NPIREF_price_cap_5$_bkp#1') + + + ['material'] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/NPiREF#10') + + + [] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/NPiREF#10') + + + ['material'] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Low Overshoot#2') + + + [] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Low Overshoot#2') + + + ['material'] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baseline_1000f#2') + + + [] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baseline_1000f#2') + + + ['material'] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_15#1') + + + [] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_15#1') + + + ['material'] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_20#1') + + + [] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_20#1') + + + ['material'] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v6.6/SSP2 - Medium Emissions#1') + + + [] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v6.6/SSP2 - Medium Emissions#1') + + + ['material'] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v6.5/SSP2 - Low Emissions#2') + + + [] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v6.5/SSP2 - Low Emissions#2') + + + ['material'] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Low Emissions#2') + + + [] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Low Emissions#2') + + + ['material'] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_110#1') + + + [] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_110#1') + + + ['material'] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v6.5/SSP2 - High Emissions#1') + + + [] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v6.5/SSP2 - High Emissions#1') + + + ['material'] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Medium-Low Emissions#2') + + + [] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Medium-Low Emissions#2') + + + ['material'] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_25#1') + + + [] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_25#1') + + + ['material'] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/NPiREF_SSP2 - Low Overshootf_price_cap_5$_bkp#1') + + + [] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/NPiREF_SSP2 - Low Overshootf_price_cap_5$_bkp#1') + + + ['material'] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v6.5/SSP2 - Medium-Low Emissions#2') + + + [] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v6.5/SSP2 - Medium-Low Emissions#2') + + + ['material'] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Low Emissions_a#2') + + + [] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Low Emissions_a#2') + + + ['material'] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_10#1') + + + [] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_10#1') + + + ['material'] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Medium Emissions_a#2') + + + [] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Medium Emissions_a#2') + + + ['material'] + + + DIGSY 'BEST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2).WORST-C' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + None + + + [] + + + DIGSY 'WORST-C' scenario with SSP2 + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2).WORST-C' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + None + + + ['material'] + + + DIGSY 'WORST-C' scenario with SSP2 with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_5#3') + + + [] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_5#3') + + + ['material'] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v6.5/SSP2 - Low Overshoot#2') + + + [] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v6.5/SSP2 - Low Overshoot#2') + + + ['material'] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/NPiREF_SSP2 - Low Overshootf#3') + + + [] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/NPiREF_SSP2 - Low Overshootf#3') + + + ['material'] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/INDC2030i_SSP2 - Low Emissions_a#1') + + + [] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/INDC2030i_SSP2 - Low Emissions_a#1') + + + ['material'] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/npiref2035_low_dem_scen2#1') + + + [] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/npiref2035_low_dem_scen2#1') + + + ['material'] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_50#1') + + + [] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_50#1') + + + ['material'] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/INDC2030i_SSP2 - Low Emissions#1') + + + [] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/INDC2030i_SSP2 - Low Emissions#1') + + + ['material'] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/NPiREF_SSP2 - Medium-Low Emissionsf#1') + + + [] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/NPiREF_SSP2 - Medium-Low Emissionsf#1') + + + ['material'] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Medium Emissions#2') + + + [] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Medium Emissions#2') + + + ['material'] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/NPIREF_price_cap_5$_bkp#1') + + + [] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/NPIREF_price_cap_5$_bkp#1') + + + ['material'] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/NPiREF#10') + + + [] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/NPiREF#10') + + + ['material'] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Low Overshoot#2') + + + [] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Low Overshoot#2') + + + ['material'] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baseline_1000f#2') + + + [] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baseline_1000f#2') + + + ['material'] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_15#1') + + + [] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_15#1') + + + ['material'] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_20#1') + + + [] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_20#1') + + + ['material'] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v6.6/SSP2 - Medium Emissions#1') + + + [] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v6.6/SSP2 - Medium Emissions#1') + + + ['material'] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v6.5/SSP2 - Low Emissions#2') + + + [] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v6.5/SSP2 - Low Emissions#2') + + + ['material'] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Low Emissions#2') + + + [] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Low Emissions#2') + + + ['material'] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_110#1') + + + [] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_110#1') + + + ['material'] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v6.5/SSP2 - High Emissions#1') + + + [] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v6.5/SSP2 - High Emissions#1') + + + ['material'] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Medium-Low Emissions#2') + + + [] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Medium-Low Emissions#2') + + + ['material'] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_25#1') + + + [] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_25#1') + + + ['material'] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/NPiREF_SSP2 - Low Overshootf_price_cap_5$_bkp#1') + + + [] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/NPiREF_SSP2 - Low Overshootf_price_cap_5$_bkp#1') + + + ['material'] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v6.5/SSP2 - Medium-Low Emissions#2') + + + [] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v6.5/SSP2 - Medium-Low Emissions#2') + + + ['material'] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Low Emissions_a#2') + + + [] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Low Emissions_a#2') + + + ['material'] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_10#1') + + + [] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_10#1') + + + ['material'] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Medium Emissions_a#2') + + + [] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Medium Emissions_a#2') + + + ['material'] + + + DIGSY 'WORST-C' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2).WORST-S' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + None + + + [] + + + DIGSY 'WORST-S' scenario with SSP2 + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2).WORST-S' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + None + + + ['material'] + + + DIGSY 'WORST-S' scenario with SSP2 with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_5#3') + + + [] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_5#3') + + + ['material'] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v6.5/SSP2 - Low Overshoot#2') + + + [] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v6.5/SSP2 - Low Overshoot#2') + + + ['material'] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/NPiREF_SSP2 - Low Overshootf#3') + + + [] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/NPiREF_SSP2 - Low Overshootf#3') + + + ['material'] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/INDC2030i_SSP2 - Low Emissions_a#1') + + + [] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/INDC2030i_SSP2 - Low Emissions_a#1') + + + ['material'] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/npiref2035_low_dem_scen2#1') + + + [] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/npiref2035_low_dem_scen2#1') + + + ['material'] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_50#1') + + + [] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_50#1') + + + ['material'] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/INDC2030i_SSP2 - Low Emissions#1') + + + [] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/INDC2030i_SSP2 - Low Emissions#1') + + + ['material'] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/NPiREF_SSP2 - Medium-Low Emissionsf#1') + + + [] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/NPiREF_SSP2 - Medium-Low Emissionsf#1') + + + ['material'] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Medium Emissions#2') + + + [] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Medium Emissions#2') + + + ['material'] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/NPIREF_price_cap_5$_bkp#1') + + + [] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/NPIREF_price_cap_5$_bkp#1') + + + ['material'] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/NPiREF#10') + + + [] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/NPiREF#10') + + + ['material'] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Low Overshoot#2') + + + [] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Low Overshoot#2') + + + ['material'] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baseline_1000f#2') + + + [] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baseline_1000f#2') + + + ['material'] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_15#1') + + + [] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_15#1') + + + ['material'] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_20#1') + + + [] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_20#1') + + + ['material'] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v6.6/SSP2 - Medium Emissions#1') + + + [] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v6.6/SSP2 - Medium Emissions#1') + + + ['material'] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v6.5/SSP2 - Low Emissions#2') + + + [] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v6.5/SSP2 - Low Emissions#2') + + + ['material'] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Low Emissions#2') + + + [] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Low Emissions#2') + + + ['material'] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_110#1') + + + [] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_110#1') + + + ['material'] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v6.5/SSP2 - High Emissions#1') + + + [] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v6.5/SSP2 - High Emissions#1') + + + ['material'] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Medium-Low Emissions#2') + + + [] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Medium-Low Emissions#2') + + + ['material'] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_25#1') + + + [] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_25#1') + + + ['material'] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/NPiREF_SSP2 - Low Overshootf_price_cap_5$_bkp#1') + + + [] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/NPiREF_SSP2 - Low Overshootf_price_cap_5$_bkp#1') + + + ['material'] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v6.5/SSP2 - Medium-Low Emissions#2') + + + [] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v6.5/SSP2 - Medium-Low Emissions#2') + + + ['material'] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Low Emissions_a#2') + + + [] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Low Emissions_a#2') + + + ['material'] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_10#1') + + + [] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/baselineS_10#1') + + + ['material'] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Medium Emissions_a#2') + + + [] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1)._Z' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + ExogenousEmissionPrice(source_url='ixmp://ixmp-dev/SSP_SSP2_v5.3.1/SSP2 - Medium Emissions_a#2') + + + ['material'] + + + DIGSY 'WORST-S' scenario with SSP2 with exogenous price with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1).CA' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + None + + + [] + + + EDITS scenario with ITF PASTA 'CA' activity + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1).CA' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + None + + + ['material'] + + + EDITS scenario with ITF PASTA 'CA' activity with materials + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1).HA' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + None + + + [] + + + EDITS scenario with ITF PASTA 'HA' activity + + + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=ICONICS:SSP(2024).2' + + + False + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:DIGSY_SCENARIO(0.2)._Z' + + + 'urn:sdmx:org.sdmx.infomodel.codelist.Code=IIASA_ECE:EDITS_MCE_SCENARIO(0.1).HA' + + + 'ixmp://ixmp-dev/SSP_SSP2_v6.6/baseline_DEFAULT_step_13' + + + None + + + ['material'] + + + EDITS scenario with ITF PASTA 'HA' activity with materials + + + + + diff --git a/message_ix_models/model/transport/config.py b/message_ix_models/model/transport/config.py index c450460bf2..b39f7d6a01 100644 --- a/message_ix_models/model/transport/config.py +++ b/message_ix_models/model/transport/config.py @@ -530,18 +530,23 @@ class CL_SCENARIO(StructureFactory["common.Codelist"]): """ urn = "IIASA_ECE:CL_TRANSPORT_SCENARIO" - version = "1.3.0" + version = "1.4.0" - #: - Model name: + #: Base scenario URL, including model name and scenario name. + #: + #: - **Model name**: + #: #: - 2024-11-25: use _v1.1 per a Microsoft Teams message. #: - 2025-02-20: update to _v2.1 per discussion with OF. At this point _v2.3 is #: the latest appearing in the database. #: - 2025-05-05: update to _v5.0. #: - 2025-06-24: update to _v6.1. - #: - The scenario names appear to form a sequence from "baseline_DEFAULT" to + #: - 2026-04-07: update to _v6.5. See also _append_code() for a special override. + #: + #: - The **scenario names** appear to form a sequence from "baseline_DEFAULT" to #: "baseline_DEFAULT_step_15" and finally "baseline". The one used below is the #: latest in this sequence for which y₀=2020, rather than 2030. - base_url = "ixmp://ixmp-dev/SSP_SSP{}_v6.1/baseline_DEFAULT_step_13" + base_url = "ixmp://ixmp-dev/SSP_SSP{}_v6.5/baseline_DEFAULT_step_13" @classmethod def create(cls) -> "common.Codelist": @@ -557,6 +562,7 @@ def create(cls) -> "common.Codelist": cl_edits = message_ix_models.project.edits.structure.get_cl_scenario() cl_digsy = message_ix_models.project.digsy.structure.get_cl_scenario() + # Create an empty code list cl: "common.Codelist" = common.Codelist( id="CL_TRANSPORT_SCENARIO", maintainer=IIASA_ECE, @@ -565,63 +571,71 @@ def create(cls) -> "common.Codelist": is_final=True, ) - def _append_code( + def _append_codes( id: str, name: str, ssp: str, led: bool = False, edits: str = "_Z", digsy: str = "_Z", - policy=None, + policy: "Policy | None" = None, ) -> None: - """Shorthand for creating a code.""" - for modules, id_prefix, name_suffix in ( + """Shorthand to append Codes to `cl` with the given setttings. + + For each call, 2 codes are appended. One has the ID ``"M {id}"``, and + includes settings for using :mod:`.transport.material`. + """ + # Construct an SCA instance to transform settings to SDMX Annotations + sca = ScenarioCodeAnnotations( + cl_ssp_2024[ssp].urn, # Expand e.g. "1" to a full URN + led, + cl_digsy[digsy].urn, + cl_edits[edits].urn, + # Format base scenario URL + # - For SSP2 only, use v6.6 in the base model name + cls.base_url.format(ssp).replace( + "v6.5", "v6.6" if ssp == "2" else "v6.5" + ), + policy, + ) + + for sca.extra_modules, id_prefix, name_suffix in ( ([], "", ""), (["material"], "M ", " with materials"), ): - sca = ScenarioCodeAnnotations( - cl_ssp_2024[ssp].urn, # Expand e.g. "1" to a full URN - led, - cl_digsy[digsy].urn, - cl_edits[edits].urn, - cls.base_url.format(ssp), # Format base scenario URL - policy, - modules, - ) - code = common.Code( - id=id_prefix + id, - name=name + name_suffix, - **sca.get_annotations(dict), - ) + # Prepare annotations + anno = sca.get_annotations(dict) + # Construct and store a code + code = common.Code(id=id_prefix + id, name=name + name_suffix, **anno) cl.append(code) # Baselines and policy scenarios for each SSP te = TaxEmission(1000.0) for ssp in "12345": id_ = name = f"SSP{ssp}" - _append_code(id_, name + " baseline", ssp) + _append_codes(id_, name + " baseline", ssp) # Simple carbon tax - _append_code(id_ + " tax", name + " with tax", ssp, policy=te) + _append_codes(id_ + " tax", name + " with tax", ssp, policy=te) # PRICE_EMISSION from exogenous data file for eep, hash in iter_price_emission("R12", f"SSP{ssp}"): name += " with exogenous price" - _append_code(f"{id_} exo price {hash}", name, ssp, policy=eep) + _append_codes(f"{id_} exo price {hash}", name, ssp, policy=eep) # LED name = "Low Energy Demand/High-with-Low scenario with SSP{} demographics" for ssp in "12": - _append_code(f"LED-SSP{ssp}", name.format(ssp), ssp, led=True) + _append_codes(f"LED-SSP{ssp}", name.format(ssp), ssp, led=True) # DIGSY ssp, name = "2", "DIGSY {!r} scenario with SSP2" for id_ in ("BEST-C", "BEST-S", "WORST-C", "WORST-S"): - _append_code(f"DIGSY-{id_}", name.format(id_), ssp, digsy=id_) + _append_codes(f"DIGSY-{id_}", name.format(id_), ssp, digsy=id_) # PRICE_EMISSION from exogenous data file for eep, hash in iter_price_emission("R12", f"SSP{ssp}"): - _append_code( + _append_codes( f"DIGSY-{id_} exo price {hash}", name.format(id_) + " with exogenous price", ssp, @@ -631,7 +645,7 @@ def _append_code( # EDITS ssp, name = "2", "EDITS scenario with ITF PASTA {!r} activity" for id_ in ("CA", "HA"): - _append_code(f"EDITS-{id_}", name.format(id_), ssp, edits=id_) + _append_codes(f"EDITS-{id_}", name.format(id_), ssp, edits=id_) return cl diff --git a/message_ix_models/tests/model/transport/test_config.py b/message_ix_models/tests/model/transport/test_config.py index 7320cd1d1b..06c3a6da58 100644 --- a/message_ix_models/tests/model/transport/test_config.py +++ b/message_ix_models/tests/model/transport/test_config.py @@ -102,7 +102,7 @@ def test_get(self, test_context: Context) -> None: result = CL_SCENARIO.get(force=True) # Code list has the expected length - assert 296 == len(result) + assert 366 == len(result) # Code list contains codes with the expected IDs assert { From aeb6099d3f3f4d1fa0f92fab2fd2490399af5b03 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Tue, 14 Apr 2026 11:25:31 +0200 Subject: [PATCH 66/73] Add .report.util.store_write_ts() - Migrate and generalize from .transport.report.add_iamc_store_write(). - Adjust usage. --- message_ix_models/model/transport/report.py | 45 +------------ message_ix_models/report/util.py | 73 +++++++++++++++++++-- 2 files changed, 69 insertions(+), 49 deletions(-) diff --git a/message_ix_models/model/transport/report.py b/message_ix_models/model/transport/report.py index 011b1719e0..28b4c64344 100644 --- a/message_ix_models/model/transport/report.py +++ b/message_ix_models/model/transport/report.py @@ -112,49 +112,6 @@ ] -# TODO Type c as (string) "Computer" once genno supports this -def add_iamc_store_write(c: Computer, base_key) -> "Key": - """Write `base_key` to CSV, XLSX, and/or both; and/or store on "scenario". - - If `base_key` is, for instance, "foo::iamc", this function adds the following keys: - - - "foo::iamc+all": both of: - - - "foo::iamc+file": both of: - - - "foo::iamc+csv": write the data in `base_key` to a file named :file:`foo.csv`. - - "foo::iamc+xlsx": write the data in `base_key` to a file named - :file:`foo.xlsx`. - - The files are created in a subdirectory using :func:`make_output_path`—that is, - including a path component given by the scenario URL. - - - "foo::iamc+store" store the data in `base_key` as time series data on the - scenario identified by the key "scenario". - - .. todo:: Move upstream, to :mod:`message_ix_models`. - """ - k = Key(base_key) - - file_keys = [] - for suffix in ("csv", "xlsx"): - # Create the path - path = c.add( - k[f"{suffix} path"], "make_output_path", "config", name=f"{k.name}.{suffix}" - ) - # Write `key` to the path - file_keys.append(c.add(k[suffix], "write_report", base_key, path)) - - # Write all files - c.add(k["file"], file_keys) - - # Store data on "scenario" - c.add(k["store"], "store_ts", "scenario", base_key) - - # Both write and store - return single_key(c.add(k["all"], [k["file"], k["store"]])) - - def aggregate(c: "Computer") -> None: """Aggregate individual transport technologies to modes.""" from genno.operator import aggregate as func @@ -323,7 +280,7 @@ def convert_iamc(c: "Computer") -> None: c.add(k, "concat", *keys) # Add tasks for writing IAMC-structured data to file and storing on the scenario - c.apply(add_iamc_store_write, k) + c.apply(util.store_write_ts, k) # Use this line to both store and write to file IAMC structured-data c.graph[K.report.all] += (k + "all",) diff --git a/message_ix_models/report/util.py b/message_ix_models/report/util.py index 1e8658b56e..a887f728ea 100644 --- a/message_ix_models/report/util.py +++ b/message_ix_models/report/util.py @@ -2,19 +2,15 @@ from collections.abc import Iterable from dataclasses import dataclass, field from itertools import count -from typing import TYPE_CHECKING import pandas as pd from dask.core import quote -from genno import Key, Keys +from genno import Computer, Key, Keys from genno.compat.pyam.util import collapse as genno_collapse from genno.core.key import single_key from message_ix import Reporter from sdmx.model.common import Code -if TYPE_CHECKING: - from genno import Computer - log = logging.getLogger(__name__) @@ -351,3 +347,70 @@ def add_replacements(dim: str, codes: Iterable[Code]) -> None: if label != code.id: REPLACE_DIMS[dim][f"{code.id.title()}$"] = label + + +# FIXME Type as "Computer" str alias, when supported by genno.Computer.apply() +def store_write_ts(c: Computer, base_key: Key) -> Key: + """Add tasks to store and write files with time-series data from `base_key`. + + `base_key` **should** refer to a task that returns time-series data in the IAMC + structure; that is, the format used by :meth:`ixmp.TimeSeries.add_timeseries`. + + If `base_key` is for instance "foo::iamc", this function adds the following keys: + + "foo::iamc+all" + Both of: + + "foo::iamc+file" + Both of: + + "foo::iamc+csv" + Write data in `base_key` to a file named :file:`foo.csv` in CSV format, + wherein the file stem is the same as the :attr:`.Key.name` of `base_key`. + "foo::iamc+xlsx" + Write the data in `base_key` to a file named :file:`foo.xlsx` in Excel + format. + + The two files are created in a subdirectory created with + :func:`make_output_path`, including a path component constructed from the + scenario URL. + + "foo::iamc+store" + Store the data in `base_key` as time series data on the + :class:`.Scenario` identified by the key "scenario", using + :func:`ixmp.report.operator.store_ts`. + + Other code **may** then :meth:`~.Reporter.get` one of the 3 keys, as needed, to + perform some or all of these tasks. + + Returns + ------- + Key + the "+all" key described above. + + Example + ------- + >>> rep = Reporter(...) + >>> result = rep.apply(store_write_ts, "foo::iamc") + >>> result + + """ + k = Key(base_key) + + file_keys = [] + for suffix in ("csv", "xlsx"): + # Create the path + name = f"{k.name}.{suffix}" + path = c.add(k[f"{suffix} path"], "make_output_path", "config", name=name) + # Write `key` to the path + file_keys.append(c.add(k[suffix], "write_report", base_key, path)) + + # Write all files + c.add(k["file"], "summarize", *file_keys) + + # Store data on "scenario" + c.add(k["store"], "store_ts", "scenario", base_key) + + # Both write and store + c.add(k["all"], "summarize", k["store"], *file_keys) + return k["all"] From 3463af1c54aa03e60932b5cd7a23cc246eb8cf54 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Tue, 14 Apr 2026 13:40:17 +0200 Subject: [PATCH 67/73] Add .transport.structure.get_commodity_groups() - Align and share code with get_technology_groups(). - Update docstrings. - Add tests. --- message_ix_models/model/transport/groups.py | 2 +- .../model/transport/structure.py | 107 ++++++++++++++---- .../tests/model/transport/test_structure.py | 45 ++++++++ 3 files changed, 130 insertions(+), 24 deletions(-) create mode 100644 message_ix_models/tests/model/transport/test_structure.py diff --git a/message_ix_models/model/transport/groups.py b/message_ix_models/model/transport/groups.py index 0f0bdb7869..1069b93496 100644 --- a/message_ix_models/model/transport/groups.py +++ b/message_ix_models/model/transport/groups.py @@ -1,4 +1,4 @@ -"""Consumer groups data.""" +"""Consumer groups.""" import logging from copy import deepcopy diff --git a/message_ix_models/model/transport/structure.py b/message_ix_models/model/transport/structure.py index 95914d1dd1..45ff2c18a2 100644 --- a/message_ix_models/model/transport/structure.py +++ b/message_ix_models/model/transport/structure.py @@ -1,3 +1,4 @@ +from collections import defaultdict from collections.abc import Sequence from copy import deepcopy from typing import Any @@ -39,6 +40,63 @@ ) +def _code_list( + key: str, data: Spec | ScenarioInfo | Sequence["Code"] +) -> Sequence["Code"]: + """Handle input for :func:`get_commodity_groups`, :func:`get_technology_groups`.""" + match data: + case Spec(): + return data.add.set[key] + case ScenarioInfo(): + return data.set[key] + case _: + return data + + +def get_commodity_groups( + commodities: Spec | ScenarioInfo | Sequence["Code"], +) -> dict[str, list[str]]: + """Subsets of transport commodities for aggregation, mapping, and filtering. + + Returns + ------- + dict + Values are lists of transport commodities (|c|) that appear in the model. + Keys include: + + - "activity F": commodities measuring freight activity. + - "activity P": commodities measuring passenger activity. + - "disutility": the disutility commodity. + - "vehicle activity": commodities measuring vehicle activity + - "_T": total or all; union of the above 4 groups. + """ + result: dict[str, list[str]] = defaultdict(list) + + for c in _code_list("commodity", commodities): + result["_T"].append(c.id) + if c.id == "disutility": + result["disutility"].append(c.id) + continue + + match c.id.split()[1:]: + case ("vehicle", *_) | (*_, "vehicle"): + result["vehicle activity"].append(c.id) + case ("pax", *_): + result["activity P"].append(c.id) + case ("F", *_): + result["activity F"].append(c.id) + case _: + raise ValueError(c) + + # Check consistency + assert {"activity F", "activity P", "disutility", "vehicle activity", "_T"} == set( + result + ) + + # Convert to a non-defaultdict, so incorrect lookups fail + return dict(result) + + def get_technology_groups( technologies: Spec | ScenarioInfo | Sequence["Code"], ) -> dict[str, list[str]]: @@ -50,34 +108,37 @@ def get_technology_groups( Values are lists of transport technologies (|t|) that appear in the model. Keys include: - - Codes from :file:`transport/technology.yaml` with children. These can be - modes, services, groups of either, or other groups of technologies. Children - are processed recursively to obtain |t| elements. - - "historical-only": includes technologies where this annotation exists and - is set to :any:`True`. - - "LDV usage": includes the technologies generated using :data:`TEMPLATE`. - See :func:`make_spec`. + - Codes from :file:`transport/technology.yaml` with children. These can be + modes, services, groups of either, or other groups of technologies. Children + are processed recursively to obtain |t| elements. + - "historical-only": includes technologies where this annotation exists and is + set to :any:`True`. + - "usage": all 'usage' pseudo-technologies that transform vehicle activity into + freight or passenger activity. + - "usage LDV": includes the technologies generated using :data:`TEMPLATE`. See + :func:`make_spec`. + - "vehicle": all vehicle technologies that transform energy inputs into vehicle + activity. + - "_T": total or all; the list of all technologies. """ - if isinstance(technologies, Spec): - t_list: Sequence["Code"] = technologies.add.set["technology"] - elif isinstance(technologies, ScenarioInfo): - t_list = technologies.set["technology"] - else: - t_list = technologies - - result: dict[str, list[str]] = {"historical-only": [], "LDV usage": []} + result: dict[str, list[str]] = defaultdict(list) - for tech in t_list: - if len(tech.child): + for t in _code_list("technology", technologies): + if len(t.child): # Code with child codes → a group of technologies → store all the leaf IDs - result[tech.id] = leaf_ids(tech) - elif tech.eval_annotation(id="historical-only") is True: + techs = result[t.id] = leaf_ids(t) + # Add to either "usage" or "vehicle" group + result["usage" if "usage" in t.id else "vehicle"].extend(techs) + # Add to catch-all group + result["_T"].extend(techs) + elif t.eval_annotation(id="historical-only") is True: # Code without children = an individual technology → add to certain groups - result["historical-only"].append(tech.id) - elif tech.eval_annotation(id="is-disutility") is True: - result["LDV usage"].append(tech.id) + result["historical-only"].append(t.id) + elif t.eval_annotation(id="is-disutility") is True: + result["usage LDV"].append(t.id) - return result + # Convert to a non-defaultdict, so incorrect lookups fail + return dict(result) def make_spec(regions: str) -> Spec: diff --git a/message_ix_models/tests/model/transport/test_structure.py b/message_ix_models/tests/model/transport/test_structure.py new file mode 100644 index 0000000000..36c40dd529 --- /dev/null +++ b/message_ix_models/tests/model/transport/test_structure.py @@ -0,0 +1,45 @@ +from message_ix_models import Context +from message_ix_models.model.transport import Config +from message_ix_models.model.transport.structure import ( + get_commodity_groups, + get_technology_groups, +) + + +def test_get_commodity_groups(test_context: Context) -> None: + config = Config.from_context(test_context) + + # Function runs + c = get_commodity_groups(config.spec) + + # The "_T" groups is equal to the union of all others + assert set( + c["activity P"] + c["activity F"] + c["disutility"] + c["vehicle activity"] + ) == set(c["_T"]) + + +def test_get_technology_groups(test_context: Context) -> None: + config = Config.from_context(test_context) + + # Function runs + t = get_technology_groups(config.spec) + + # Vehicle technologies for each mode are present + assert {"2W", "AIR", "BUS", "F RAIL", "F ROAD", "LDV", "RAIL"} < set(t) + + # Vehicle technologies for each service are present + assert {"F", "P"} < set(t) + + # Service groups aggregate vehicle technologies for related modes + assert set(t["2W"] + t["AIR"] + t["BUS"] + t["LDV"] + t["RAIL"]) == set(t["P"]) + assert set(t["F RAIL"] + t["F ROAD"]) == set(t["F"]) + + # All vehicle technologies + assert not any(" usage" in tech for tech in t["vehicle"]), t["vehicle"] + assert set(t["F"] + t["P"] + t["OTHER"]) == set(t["vehicle"]) + + # # of LDV usage technologies: 27 consumer groups × # of LDV technologies + assert 27 * len(t["LDV"]) == len(t["usage LDV"]) + + # Vehicle and usage technologies + assert set(t["vehicle"] + t["usage"]) == set(t["_T"]) From b39c8a84b331dc2c65476f2945e168f1af10580e Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Tue, 14 Apr 2026 22:44:39 +0200 Subject: [PATCH 68/73] Add 4 entries to .transport.key .agg, .c, .coord, .t --- .../data/transport/constraint-dynamic.csv | 4 +-- message_ix_models/model/transport/key.py | 30 ++++++++++++++++++- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/message_ix_models/data/transport/constraint-dynamic.csv b/message_ix_models/data/transport/constraint-dynamic.csv index 112bef7ef7..c35c9ffc5a 100644 --- a/message_ix_models/data/transport/constraint-dynamic.csv +++ b/message_ix_models/data/transport/constraint-dynamic.csv @@ -49,8 +49,8 @@ ICE_L_ptrp, *, growth_new_capacity_up, 0.0192 # mode. LDV, *, initial_new_capacity_up, 10.0 -LDV usage, *, growth_activity_up, 0.0539 -LDV usage, *, initial_activity_up, 1000000 +usage LDV, *, growth_activity_up, 0.0539 +usage LDV, *, initial_activity_up, 1000000 P ex LDV, *, growth_activity_lo, -0.0192 P ex LDV, electr, growth_activity_lo, 0.0 diff --git a/message_ix_models/model/transport/key.py b/message_ix_models/model/transport/key.py index ab1b33aa4d..feed1eaaa6 100644 --- a/message_ix_models/model/transport/key.py +++ b/message_ix_models/model/transport/key.py @@ -10,7 +10,10 @@ from .data import ActivityVehicle, Lifetime, LoadFactorLDV, iter_files __all__ = [ + "agg", + "c", "cg", + "coord", "cost", "exo", "fv_cny", @@ -32,6 +35,7 @@ "pop", "price", "sw", + "t", "t_modes", "y", ] @@ -42,6 +46,15 @@ # Keys for new quantities +#: Structures for aggregation. Each refers to a :py:`dict[str, dict[str, list[str]]]`. +#: Top-level keys are dimension IDs. Second-level keys are coordinates along the +#: respective dimension to be created by aggregation. Second-level values are lists of +#: coordinates to be aggregated. +agg = Keys( + c="agg:c:T", + t="agg:t:T", +) + #: Quantities for broadcasting (t) to (t, c, l). See :func:`.broadcast_t_c_l`. #: #: - :py:`.input`: Quantity for broadcasting (all values 1) from every transport |t| @@ -66,9 +79,21 @@ no_vintage="broadcast:y-yv-ya:no vintage", ) +#: List of all transport commodities. +c = Key("c::T") + #: Shares of population with consumer group (`cg`) dimension. cg = Key("cg share:n-y-cg") +#: Coordinates for indexing and selecting. Each refers to a :py:`dict[str, list[str]`. +#: Keys are dimension IDs. Values are lists of coordinates along the respective +#: dimension to index or select. +coord = Keys( + c="coords:c:T", + t="coords:t:T", + yv_hist="coords:yv:T+historical", +) + cost = Key("cost", "nyct") debug = Key("transport debug") @@ -125,9 +150,12 @@ # Keys for (partial or full) sets or indexers -#: List of nodes excepting "World" or "*_GLB". +#: List of nodes, excepting "World" or "*_GLB". n = "n::ex world" +#: List of all transport technologies. +t = Key("t::T") + #: List of transport modes. t_modes = "t::transport modes" From 3bfbee63d054f30d36e6fe32fe8669ebc8f86dee Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Tue, 14 Apr 2026 22:54:59 +0200 Subject: [PATCH 69/73] Improve .transport.build - Add .structure.get_commodity_groups(). - Harmonize addition of structural information for groups, including keys; apply to both commodity and technology. - Use "from . import key as K" style consistently. --- message_ix_models/model/transport/build.py | 124 +++++++++++---------- 1 file changed, 68 insertions(+), 56 deletions(-) diff --git a/message_ix_models/model/transport/build.py b/message_ix_models/model/transport/build.py index 0bab54168e..7f658465a4 100644 --- a/message_ix_models/model/transport/build.py +++ b/message_ix_models/model/transport/build.py @@ -27,9 +27,10 @@ from message_ix_models.util._logging import mark_time from message_ix_models.util.graphviz import HAS_GRAPHVIZ -from . import Config, key, plot +from . import Config, plot +from . import key as K from .operator import indexer_scenario -from .structure import get_technology_groups +from .structure import get_commodity_groups, get_technology_groups if TYPE_CHECKING: from typing import TypedDict @@ -72,13 +73,13 @@ def add_debug(c: Computer) -> None: c.add(e.cnlt, "rename_dims", e.fnp[1], quote(dict(flow="t", n="nl", product="c"))) # Write some intermediate calculations from the build process to file - k_debug = copy(key.debug) # Make a copy so the original does not collect .generated + k_debug = copy(K.debug) # Make a copy so the original does not collect .generated for i, (k, stem) in enumerate( ( - (key.gdp_cap, "gdp-ppp-cap"), - (key.pdt_nyt, "pdt"), - (key.pdt_nyt + "capita+post", "pdt-cap"), - (key.ms, "mode-share"), + (K.gdp_cap, "gdp-ppp-cap"), + (K.pdt_nyt, "pdt"), + (K.pdt_nyt + "capita+post", "pdt-cap"), + (K.ms, "mode-share"), (e.fnp[0], "energy-iea-0"), (e.cnlt, "energy-iea-1"), ) @@ -210,10 +211,10 @@ def add_exogenous_data(c: Computer, info: ScenarioInfo) -> None: if False: pass # Solved scenario that already has this key else: - c.add(key.GDP, keys["GDP"][0]) + c.add(K.GDP, keys["GDP"][0]) # Ensure correct units - c.add(key.pop, "mul", "pop:n-y", genno.Quantity(1.0, units="passenger")) + c.add(K.pop, "mul", "pop:n-y", genno.Quantity(1.0, units="passenger")) # FIXME Adjust to derive PRICE_COMMODITY c=transport from solved scenario with # MESSAGEix-Transport detail, then uncomment the following line @@ -221,10 +222,10 @@ def add_exogenous_data(c: Computer, info: ScenarioInfo) -> None: if False: # Alias PRICE_COMMODITY:… to PRICE_COMMODITY:*:transport, e.g. solved scenario # that already has this key - c.add(key.price[0], key.price.base - "transport") + c.add(K.price[0], K.price.base - "transport") else: # Not solved scenario → dummy prices - c.add(key.price[0], "dummy_prices", keys["GDP"][0], sums=True) + c.add(K.price[0], "dummy_prices", keys["GDP"][0], sums=True) # Data from files @@ -271,7 +272,7 @@ def add_exogenous_data(c: Computer, info: ScenarioInfo) -> None: #: See :func:`.nodes_world_agg`. STRUCTURE_STATIC: tuple[tuple, ...] = ( ("add transport data", []), - (key.report.all, "summarize"), + (K.report.all, "summarize"), ("info", lambda c: c.transport.base_model_info, "context"), ( "transport info", @@ -279,26 +280,22 @@ def add_exogenous_data(c: Computer, info: ScenarioInfo) -> None: "context", ), ( - key.demand_base, + K.demand_base, partial(data_for_quantity, "par", "demand", "value"), "scenario", "config", ), ("dry_run", lambda c: c.core.dry_run, "context"), ("e::codelist", partial(get_codelist, "emission")), - ("groups::iea eweb", "groups_iea_eweb", "t::transport"), + ("groups::iea eweb", "groups_iea_eweb", K.t), ("groups::iea to transport", itemgetter(0), "groups::iea eweb"), ("groups::transport to iea", itemgetter(1), "groups::iea eweb"), ("indexers::iea to transport", itemgetter(2), "groups::iea eweb"), ("indexers:scenario", partial(indexer_scenario, with_LED=False), "config"), ("indexers:scenario:LED", partial(indexer_scenario, with_LED=True), "config"), - ("indexers::usage", "indexers_usage", "t::transport"), - ("n::ex world", "nodes_ex_world", "n"), - ( - "n:n:ex world", - lambda n: genno.Quantity([1.0] * len(n), coords={"n": n}), - "n::ex world", - ), + ("indexers::usage", "indexers_usage", K.t), + (K.n, "nodes_ex_world", "n"), + ("n:n:ex world", lambda n: genno.Quantity([1.0] * len(n), coords={"n": n}), K.n), ("n::ex world+code", "nodes_ex_world", "nodes"), ("nl::world agg", "nodes_world_agg", "config"), ("scenario::all", "scenario_codes"), @@ -360,6 +357,7 @@ def add_structure(c: Computer) -> None: config: "Config" = c.graph["context"].transport # .model.transport.Config object info = config.base_model_info # ScenarioInfo describing the base scenario spec = config.spec # Specification for MESSAGEix-Transport structure to be built + c_groups = get_commodity_groups(spec) # Commodity groups/hierarchy t_groups = get_technology_groups(spec) # Technology groups/hierarchy # Update RENAME_DIMS with transport-specific concepts/dimensions. This allows to use @@ -385,7 +383,7 @@ def add_structure(c: Computer) -> None: "cat_year", pd.DataFrame([["firstmodelyear", info.y0]], columns=["type_year", "year"]), ), - (key.y, "model_periods", "y", "cat_year"), + (K.y, "model_periods", "y", "cat_year"), ("y0", itemgetter(0), "y::model"), ("y::y0", lambda v: dict(y=v[0]), "y::model"), ): @@ -395,12 +393,38 @@ def add_structure(c: Computer) -> None: # log.debug(f"Use existing {c.describe(task[0])}") pass - # Assemble a queue of tasks - # - `Static` tasks - # - Single 'dynamic' tasks based on config, info, spec, and/or t_groups - # - Multiple static and dynamic tasks generated in loops etc. - tasks: list[tuple] = list(STRUCTURE_STATIC) + [ - ("c::transport", quote(spec.add.set["commodity"])), + # Assemble a queue of tasks; first, `static` tasks + tasks: list[tuple] = list(STRUCTURE_STATIC) + + # Commodity and technology coordinates + for name, groups in ("commodity", c_groups), ("technology", t_groups): + dim = name[0] # Dimension short ID ← first letter of set name + # Reference existing keys from .key module + k0 = Keys( + list=getattr(K, dim), agg=getattr(K.agg, dim), coord=getattr(K.coord, dim) + ) + + # 1. Flat list of all Codes. + # 2. Coordinates: dimension ID as the top-level key, then list of str. + # 3. Aggregator: dimension ID as the top-level key, then all groups. + # 4. Groups as top-level keys. + tasks += [ + (k0.list, quote(spec.add.set[name])), + (k0.coord, quote({dim: groups["_T"]})), + (k0.agg, quote({dim: groups})), + (f"groups:{dim}:T", quote(groups)), + ] + + # Each group individually + for group_id, members in groups.items(): + # Flat list of members as Codes + codes = sorted(filter(members.__contains__, spec.add.set[name])) + tasks.append((k0.list[group_id], quote(codes))) + # Coordinates + tasks.append((k0.coord[group_id], quote({dim: members}))) + + # Single 'dynamic' tasks based on config, info, spec, and/or t_groups + tasks += [ # Convert to str to avoid TypeError in broadcast_wildcard → sorted() # TODO Remove once sdmx.model.common.Code is sortable with str ( @@ -415,10 +439,7 @@ def add_structure(c: Computer) -> None: ("cg", quote(spec.add.set["consumer_group"])), ("indexers:cg", spec.add.set["consumer_group indexers"]), ("nodes", quote(info.set["node"])), - ("t::transport", quote(spec.add.set["technology"])), - ("t::transport agg", quote(dict(t=t_groups))), - ("t::transport all", quote(dict(t=spec.add.set["technology"]))), - (key.t_modes, quote(config.demand_modes)), + (K.t_modes, quote(config.demand_modes)), ("t::transport modes 0", quote(dict(t=list(t_groups.keys())))), ( "t::transport modes 1", @@ -426,34 +447,25 @@ def add_structure(c: Computer) -> None: ), ] + # Multiple static and dynamic tasks generated in loops etc. # Quantities for broadcasting (t,) to (t, c, l) dimensions tasks.extend( ( - getattr(key.bcast_tcl, kind), + getattr(K.bcast_tcl, kind), partial(broadcast_t_c_l, kind=kind, default_level="final"), - "t::transport", + K.t, "c::transport+base", ) for kind in ("input", "output") ) # Quantities for broadcasting y to (yv, ya) - for k, base, method in ( - (key.bcast_y.all, "y", "product"), # All periods - (key.bcast_y.model, "y::model", "product"), # Model periods only - (key.bcast_y.no_vintage, "y::model", "zip"), # Model periods with no vintaging + for k1, base, method in ( + (K.bcast_y.all, "y", "product"), # All periods + (K.bcast_y.model, K.y, "product"), # Model periods only + (K.bcast_y.no_vintage, K.y, "zip"), # Model periods with no vintaging ): - tasks.append((k, partial(broadcast_y_yv_ya, method=method), base, base)) - - # Groups of technologies and indexers - tasks.append(("t::transport groups", quote(t_groups))) - - # FIXME Combine or disambiguate these keys - for id, techs in t_groups.items(): - # Indexer-form of technology groups - tasks.append((f"t::transport {id}", quote(dict(t=techs)))) - # List form of technology groups - tasks.append((f"t::{id}", quote(techs))) + tasks.append((k1, partial(broadcast_y_yv_ya, method=method), base, base)) # - Change each task from single-tuple form to (args, kwargs) with strict=True. # - Add all to the Computer, making 2 passes. @@ -463,20 +475,20 @@ def add_structure(c: Computer) -> None: c.add( "t::transport map", MappingAdapter.from_dicts, - "t::transport groups", + "groups:t:T", dims=("t",), on_missing="raise", ) # Identify the subset of periods up to and including y0 c.add( - key.y_.historical, + K.y_.historical, lambda periods, y0: list(filter(lambda y: y < y0, periods)), "y", "y0", ) c.add( - key.y_.to_y0, + K.y_.to_y0, lambda periods, y0: dict(y=list(filter(lambda y: y <= y0, periods))), "y", "y0", @@ -484,11 +496,11 @@ def add_structure(c: Computer) -> None: # Convert duration_period to Quantity c.add("duration_period:y", "duration_period", "info") # Duration_period up to and including y0 - c.add("duration_period:y:to y0", "select", "duration_period:y", key.y_.to_y0) + c.add("duration_period:y:to y0", "select", "duration_period:y", K.y_.to_y0) # Groups for aggregating annual to period data - c.add(key.y_.annual_agg, "groups_y_annual", "duration_period:y") + c.add(K.y_.annual_agg, "groups_y_annual", "duration_period:y") # Indexers - c.add(key.yv.historical_idx, lambda periods: dict(yv=periods), key.y_.historical) + c.add(K.coord.yv_hist, lambda periods: dict(yv=periods), K.y_.historical) @minimum_version("genno 1.28") @@ -657,7 +669,7 @@ def _add_data(s, **kw): log.info(f"Added {sum_numeric(result)} total obs") if context.core.dry_run: - return c.get(key.debug) + return c.get(K.debug) # First strip existing emissions data strip_emissions_data(scenario, context) From 36a41b4bf5435ea9175cfba1cc8793c8bd002c76 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Tue, 14 Apr 2026 23:13:19 +0200 Subject: [PATCH 70/73] Use consistent style to import .transport.key --- .../model/transport/constraint.py | 8 +- message_ix_models/model/transport/data.py | 16 ++- message_ix_models/model/transport/demand.py | 101 ++++++++---------- .../model/transport/disutility.py | 6 +- message_ix_models/model/transport/factor.py | 10 +- message_ix_models/model/transport/freight.py | 59 +++++----- message_ix_models/model/transport/groups.py | 14 +-- message_ix_models/model/transport/ikarus.py | 12 +-- message_ix_models/model/transport/key.py | 2 - message_ix_models/model/transport/ldv.py | 45 +++----- message_ix_models/model/transport/other.py | 8 +- .../model/transport/passenger.py | 10 +- message_ix_models/model/transport/plot.py | 10 +- message_ix_models/model/transport/vehicle.py | 28 ++--- 14 files changed, 143 insertions(+), 186 deletions(-) diff --git a/message_ix_models/model/transport/constraint.py b/message_ix_models/model/transport/constraint.py index 0858b77360..c91120b3df 100644 --- a/message_ix_models/model/transport/constraint.py +++ b/message_ix_models/model/transport/constraint.py @@ -41,24 +41,24 @@ def prepare_computer(c: "Computer") -> None: from message_ix_models.util.genno import Collector - from .key import bcast_tcl, exo + from . import key as K collect = Collector(TARGET, "{}::constraint+ixmp".format) collect.computer = c c.add("transport_data", __name__, key=TARGET) - k = Keys(a=Key("constraints", exo.constraint_dynamic.dims, "transport")) + k = Keys(a=Key("constraints", K.exo.constraint_dynamic.dims, "transport")) k.b = k.a * tuple("lny") # 't'echnology dimension: broadcast labels like "F ROAD" to full lists of techs - c.add(k.a[0], "call", "t::transport map", exo.constraint_dynamic) + c.add(k.a[0], "call", "t::transport map", K.exo.constraint_dynamic) # 'c'ommodity dimension: broadcast "*" values to full lists of transport commodities c.add(k.a[1], "call", "c::transport wildcard", k.a[0]) # Keep only the (t, c) combinations which are actual inputs to specific transport # techs - c.add(k.a[2] * "l", "mul", k.a[1], bcast_tcl.input) + c.add(k.a[2] * "l", "mul", k.a[1], K.bcast_tcl.input) # Add and broadcast over: # - 'n'ode dimension including all nodes diff --git a/message_ix_models/model/transport/data.py b/message_ix_models/model/transport/data.py index bd4528ebe8..2a081f7ba2 100644 --- a/message_ix_models/model/transport/data.py +++ b/message_ix_models/model/transport/data.py @@ -36,6 +36,7 @@ ) from message_ix_models.util.sdmx import DATAFLOW, STORE, Dataflow +from . import key as K from .util import EXTRAPOLATE, region_path_fallback if TYPE_CHECKING: @@ -440,13 +441,11 @@ def filename(self) -> str: return re.sub("^(LED)-SSP.$", r"\1", self.options.config.label) + ".csv" def transform(self, c: "Computer", base_key: Key) -> Key: - from .key import pdt_nyt, pop - # This is the key used by subsequent steps in demand.py - target = pdt_nyt[0] + target = K.pdt_nyt[0] # Multiply by population for the total - c.add(target, "mul", base_key, pop) + c.add(target, "mul", base_key, K.pop) return target @@ -687,12 +686,11 @@ def navigate_ele( def prepare_computer(c: Computer): """Add miscellaneous transport data.""" # Data-generating calculations - n, y = "n::ex world", "y::model" for comp in ( - (conversion, n, y, "config"), - (misc, "info", n, y), - (dummy_supply, "t::transport", "info", "config"), - (navigate_ele, n, "t::transport", "t::transport agg", y, "config"), + (conversion, K.n, K.y, "config"), + (misc, "info", K.n, K.y), + (dummy_supply, K.t, "info", "config"), + (navigate_ele, K.n, K.t, K.agg.t, K.y, "config"), ): # Add 2 computations: one to generate the data name = getattr(comp[0], "__name__") diff --git a/message_ix_models/model/transport/demand.py b/message_ix_models/model/transport/demand.py index 593fece99b..5ce156260e 100644 --- a/message_ix_models/model/transport/demand.py +++ b/message_ix_models/model/transport/demand.py @@ -13,28 +13,8 @@ from message_ix_models.util import broadcast from . import factor +from . import key as K from .data import PDT_CAP -from .key import ( - cg, - cost, - exo, - gdp_cap, - gdp_ppp, - ldv_cny, - ldv_ny, - ldv_nycg, - ms, - n, - pdt_cap, - pdt_cny, - pdt_ny, - pdt_nyt, - pop, - price, - sw, - t_modes, - y, -) from .util import EXTRAPOLATE if TYPE_CHECKING: @@ -96,60 +76,60 @@ def dummy( (("lambda:", "quantity_from_config", "config"), dict(name="lamda")), (("y::conv", "quantity_from_config", "config"), dict(name="year_convergence")), # Base passenger mode share (exogenous/reference data) - (ms + "base", "base_shares", "mode share:n-t:exo", n, t_modes, y), + (K.ms + "base", "base_shares", "mode share:n-t:exo", K.n, K.t_modes, K.y), # GDP expressed in PPP. The in the SSP(2024) input files, this conversion is already # applied, so no need to multiply by a mer_to_ppp factor here → simple alias. - (gdp_ppp, GDP), + (K.gdp_ppp, GDP), # GDP PPP per capita - (gdp_cap, "div", gdp_ppp, pop), + (K.gdp_cap, "div", K.gdp_ppp, K.pop), # # Total PDT (n, y) = product of PDT / capita and population. See pdt_per_capita() # that sets up the calculation of `pdt_cap + "adj"` - (pdt_ny, "mul", pdt_cap + "adj", pop), + (K.pdt_ny, "mul", K.pdt_cap + "adj", K.pop), # Value-of-time multiplier # ("votm:n-y", "votm", gdp_cap + "adj"), # use the original GDP path for votm calculations - ("votm:n-y", "votm", gdp_cap), + ("votm:n-y", "votm", K.gdp_cap), # Select only the price of transport services # FIXME should be the full set of prices - ((price[1], "select", price[0]), dict(indexers=dict(c="transport"), drop=True)), - (price[2], "price_units", price[1]), + ((K.price[1], "select", K.price[0]), dict(indexers=dict(c="transport"), drop=True)), + (K.price[2], "price_units", K.price[1]), # Smooth prices to avoid zig-zag in share projections - (price, "smooth", price[2]), + (K.price, "smooth", K.price[2]), # Interpolate speed data - (("speed:scenario-n-t-y:0", "interpolate", exo.speed, "y::coords"), EXTRAPOLATE), + (("speed:scenario-n-t-y:0", "interpolate", K.exo.speed, "y::coords"), EXTRAPOLATE), # Select speed data ("speed:n-t-y", "select", "speed:scenario-n-t-y:0", "indexers:scenario"), # Cost of transport (n, t, y) - (cost, "cost", price, gdp_cap, "whour:", "speed:n-t-y", "votm:n-y", y), + (K.cost, "cost", K.price, K.gdp_cap, "whour:", "speed:n-t-y", "votm:n-y", K.y), # Share weights (n, t, y) ( - sw, + K.sw, "share_weight", - ms + "base", - gdp_cap, - cost, + K.ms + "base", + K.gdp_cap, + K.cost, "lambda:", - t_modes, - y, + K.t_modes, + K.y, "config", ), # Mode shares - ((ms, "logit", cost, sw, "lambda:", y), dict(dim="t")), + ((K.ms, "logit", K.cost, K.sw, "lambda:", K.y), dict(dim="t")), # Total PDT (n, t, y), with modes for the 't' dimension - (pdt_nyt[0], "mul", pdt_ny, ms), + (K.pdt_nyt[0], "mul", K.pdt_ny, K.ms), # Scenario-specific adjustment factors - ("pdt factor:n-y-t", "factor_pdt", n, y, t_modes, "config"), + ("pdt factor:n-y-t", "factor_pdt", K.n, K.y, K.t_modes, "config"), # Only the LDV values ( ("ldv pdt factor:n-y", "select", "pdt factor:n-y-t"), dict(indexers=dict(t="LDV"), drop=True), ), - (pdt_nyt, "mul", pdt_nyt[0], "pdt factor:n-y-t"), + (K.pdt_nyt, "mul", K.pdt_nyt[0], "pdt factor:n-y-t"), # Per capita (for validation) - (pdt_nyt + "capita+post", "div", pdt_nyt, pop), + (K.pdt_nyt + "capita+post", "div", K.pdt_nyt, K.pop), # LDV PDT only (n, y) - ((ldv_ny + "ref", "select", pdt_nyt), dict(indexers=dict(t="LDV"), drop=True)), + ((K.ldv_ny + "ref", "select", K.pdt_nyt), dict(indexers=dict(t="LDV"), drop=True)), # commented: The following computes LDV PDT as base-year values from the ADVANCE # database × an index of the top-down (Schäfer) LDV PDT versus base-year values # # Indexed to base year @@ -160,25 +140,28 @@ def dummy( # (ldv_ny + "total", "mul", ldv_ny + "total+0", "ldv pdt factor:n-y"), # # Apply the scenario-specific adjustment factor - (ldv_ny + "total", "mul", ldv_ny + "ref", "ldv pdt factor:n-y"), + (K.ldv_ny + "total", "mul", K.ldv_ny + "ref", "ldv pdt factor:n-y"), # LDV PDT shared out by consumer group (cg, n, y) - (ldv_nycg, "mul", ldv_ny + "total", cg), + (K.ldv_nycg, "mul", K.ldv_ny + "total", K.cg), # Select only non-LDV PDT - ((pdt_nyt[1], "select", pdt_nyt), dict(indexers=dict(t=["LDV"]), inverse=True)), + ((K.pdt_nyt[1], "select", K.pdt_nyt), dict(indexers=dict(t=["LDV"]), inverse=True)), # Relabel PDT ( - (pdt_cny[0], "relabel2", pdt_nyt[1]), + (K.pdt_cny[0], "relabel2", K.pdt_nyt[1]), dict(new_dims={"c": "transport pax {t.lower()}"}), ), - (pdt_cny, "convert_units", pdt_cny[0], "Gp km / a"), + (K.pdt_cny, "convert_units", K.pdt_cny[0], "Gp km / a"), # Convert to ixmp format - (("demand::P+ixmp", "as_message_df", pdt_cny), _DEMAND_KW), + (("demand::P+ixmp", "as_message_df", K.pdt_cny), _DEMAND_KW), # Relabel ldv pdt:n-y-cg - ((ldv_cny[0], "relabel2", ldv_nycg), dict(new_dims={"c": "transport pax {cg}"})), - (ldv_cny, "convert_units", ldv_cny[0], "Gp km / a"), - (("demand::LDV+ixmp", "as_message_df", ldv_cny), _DEMAND_KW), + ( + (K.ldv_cny[0], "relabel2", K.ldv_nycg), + dict(new_dims={"c": "transport pax {cg}"}), + ), + (K.ldv_cny, "convert_units", K.ldv_cny[0], "Gp km / a"), + (("demand::LDV+ixmp", "as_message_df", K.ldv_cny), _DEMAND_KW), # Dummy demands, if these are configured - ("demand::dummy+ixmp", dummy, "c::transport", "nodes::ex world", y, "config"), + ("demand::dummy+ixmp", dummy, "c::transport", "nodes::ex world", K.y, "config"), # Merge all data together ( "transport demand::ixmp", @@ -211,7 +194,7 @@ def pdt_per_capita(c: "Computer") -> None: c.add(gdp["PPP"], gdp) # GDP PPP per capita - c.add(gdp["capita"], "div", gdp["PPP"], pop) + c.add(gdp["capita"], "div", gdp["PPP"], K.pop) # Add `y` dimension. Here for the future fixed point we use y=2 * max(y), e.g. # 4220 for y=2110. The value doesn't matter, we just need to avoid overlap with y @@ -254,8 +237,8 @@ def _delta(qty: "AnyQuantity", y0: int) -> "AnyQuantity": c.add("pdt slope:n", "div", pdt["delta"] / "y", gdp["delta"] / "y") # Select 'elasticity' from "elasticity:scenario-n-y:P+exo" - k_e = genno.Key(exo.elasticity_p.name, "ny") - c.add(k_e[0], "select", exo.elasticity_p, "indexers:scenario") + k_e = genno.Key(K.exo.elasticity_p.name, "ny") + c.add(k_e[0], "select", K.exo.elasticity_p, "indexers:scenario") # Interpolate on "y" dimension c.add(k_e[1], "interpolate", k_e[0], "y::coords", **EXTRAPOLATE) @@ -281,10 +264,10 @@ def _delta(qty: "AnyQuantity", y0: int) -> "AnyQuantity": c.add(x[6], "assign_units", x[5], units=units) # Alias the last step to the target key - c.add(pdt_cap, pdt[6]) + c.add(K.pdt_cap, pdt[6]) # Provide a key for the adjusted GDP - c.add(gdp_cap + "adj", gdp[6]) + c.add(K.gdp_cap + "adj", gdp[6]) def prepare_computer(c: "Computer") -> None: @@ -301,7 +284,7 @@ def prepare_computer(c: "Computer") -> None: c.apply(pdt_per_capita) # Insert a scaling factor that varies according to SSP setting - c.apply(factor.insert, pdt_cap, name="pdt non-active", target=pdt_cap + "adj") + c.apply(factor.insert, K.pdt_cap, name="pdt non-active", target=K.pdt_cap + "adj") # Add other tasks for demand calculation c.add_queue(TASKS) diff --git a/message_ix_models/model/transport/disutility.py b/message_ix_models/model/transport/disutility.py index 24b305674b..8f64c6f49a 100644 --- a/message_ix_models/model/transport/disutility.py +++ b/message_ix_models/model/transport/disutility.py @@ -2,8 +2,8 @@ from genno import Key, Quantity, quote +from . import key as K from . import util -from .key import exo from .util import EXTRAPOLATE if TYPE_CHECKING: @@ -29,12 +29,12 @@ def prepare_computer(c: "Computer") -> None: # Interpolate to ensure all y::model are covered # NB "y::coords" is not equivalent here; includes all y, not just y::model c.add("y::model+coords", lambda years: dict(y=years), "y::model") - c.add(k[1], "interpolate", exo.disutility, "y::model+coords", **EXTRAPOLATE) + c.add(k[1], "interpolate", K.exo.disutility, "y::model+coords", **EXTRAPOLATE) # Divide disutility per vehicle by annual driving distance per vehicle → disutility # per vehicle-km; convert to preferred units # TODO add "cg" dimension to ldv activity - k2 = c.add(k[2], "div", k[1], (exo.activity_vehicle + "LDV") / "t") + k2 = c.add(k[2], "div", k[1], (K.exo.activity_vehicle + "LDV") / "t") k3 = c.add(k[3], "mul", k2, Quantity(1.0, units="vehicle / year")) k4 = c.add(k[4], "convert_units", k3, units="USD / km") diff --git a/message_ix_models/model/transport/factor.py b/message_ix_models/model/transport/factor.py index 2adcf6a514..1591975d28 100644 --- a/message_ix_models/model/transport/factor.py +++ b/message_ix_models/model/transport/factor.py @@ -462,14 +462,10 @@ def insert(c: Computer, key, *, name: str, target: Key, dims: str = "ny"): Use via :meth:`genno.Computer.apply`. """ - k_target = Key(target) + from . import key as K - dim_coord = { - "n": "n::ex world", - "t": "t::transport", - "y": "y::model", - } - coords = [dim_coord[d] for d in dims] + k_target = Key(target) + coords = [{"n": K.n, "t": K.t, "y": K.y}[d] for d in dims] se = "config['transport'].ssp" # Quantify the factor diff --git a/message_ix_models/model/transport/freight.py b/message_ix_models/model/transport/freight.py index 0441ea3aa8..4a1a426842 100644 --- a/message_ix_models/model/transport/freight.py +++ b/message_ix_models/model/transport/freight.py @@ -13,9 +13,9 @@ from message_ix_models.util import convert_units, make_matched_dfs, same_node, same_time from message_ix_models.util.genno import Collector +from . import key as K from . import util from .demand import _DEMAND_KW -from .key import bcast_tcl, bcast_y, exo, fv, fv_cny, n, y from .util import COMMON, EXTRAPOLATE, wildcard if TYPE_CHECKING: @@ -40,8 +40,8 @@ def demand(c: "Computer") -> None: # commented: Base freight activity from IEA EEI # c.add("iea_eei_fv", "fv:n-y:historical", quote("tonne-kilometres"), "config") # Base year freight activity from file (n, t), with modes for the 't' dimension - c.add("fv:n-t:historical", "mul", exo.mode_share_freight, exo.activity_freight) - c.add(fv["log y0"], np.log, "fv:n-t:historical") + c.add("fv:n-t:historical", "mul", K.exo.mode_share_freight, K.exo.activity_freight) + c.add(K.fv["log y0"], np.log, "fv:n-t:historical") ### Apply pseudo 'elasticity' of freight activity @@ -57,12 +57,13 @@ def demand(c: "Computer") -> None: c.add(gdp[1], "sub", gdp[0], genno.Quantity(1.0)) ### Prepare exo.elasticity_f - k_e = Key(exo.elasticity_f.name, "ny", "F") + k_e = Key(K.exo.elasticity_f.name, "ny", "F") # Broadcast elasticity to all (node, technology, scenario) - coords = ["scenario::all", "n::ex world", quote(["F RAIL", "F ROAD"])] + freight_modes = ["F RAIL", "F ROAD"] + coords = ["scenario::all", K.n, quote(freight_modes)] dim = ("scenario", "n", "t") - c.add(k_e[0], "broadcast_wildcard", exo.elasticity_f, *coords, dim=dim) + c.add(k_e[0], "broadcast_wildcard", K.exo.elasticity_f, *coords, dim=dim) # Select values for the current scenario c.add(k_e[1], "select", k_e[0], "indexers:scenario:LED") @@ -76,33 +77,32 @@ def demand(c: "Computer") -> None: c.add(gdp[2], "mul", gdp[1], k_e[2]) # Projected delta log freight activity is exactly the same - c.add(fv[0], gdp[2]) + c.add(K.fv[0], gdp[2]) # Reverse the transformation - c.add(fv[1], "add", fv[0], genno.Quantity(1.0)) - c.add(fv[2], "mul", fv[1], fv["log y0"]) - c.add(fv[3], np.exp, fv[2]) + c.add(K.fv[1], "add", K.fv[0], genno.Quantity(1.0)) + c.add(K.fv[2], "mul", K.fv[1], K.fv["log y0"]) + c.add(K.fv[3], np.exp, K.fv[2]) # (NAVIGATE) Scenario-specific adjustment factor for freight activity - c.add("fv factor:n-t-y", "factor_fv", n, y, "config") + c.add("fv factor:n-t-y", "factor_fv", K.n, K.y, "config") # Apply the adjustment factor - c.add(fv[4], "mul", fv[3], "fv factor:n-t-y") + c.add(K.fv[4], "mul", K.fv[3], "fv factor:n-t-y") # Select certain modes. NB Do not drop so 't' labels can be used for 'c', next. - freight_techs = ["F RAIL", "F ROAD"] - c.add(fv, "select", fv[4], indexers=dict(t=freight_techs)) + c.add(K.fv, "select", K.fv[4], indexers=dict(t=freight_modes)) # Relabel - c.add(fv_cny, "relabel2", fv, new_dims={"c": "transport {t}"}) + c.add(K.fv_cny, "relabel2", K.fv, new_dims={"c": "transport {t}"}) # Convert to ixmp format - collect("demand", "as_message_df", fv_cny, **_DEMAND_KW) + collect("demand", "as_message_df", K.fv_cny, **_DEMAND_KW) # Compute indices, e.g. for use in .other.prepare_computer() - for t in freight_techs: - c.add(fv[t], "select", fv, indexers=dict(t=t)) - c.add(fv[f"{t} index"], "index_to", fv[t], literal("y"), "y0") + for t in freight_modes: + c.add(K.fv[t], "select", K.fv, indexers=dict(t=t)) + c.add(K.fv[f"{t} index"], "index_to", K.fv[t], literal("y"), "y0") def prepare_computer(c: "Computer") -> None: @@ -125,10 +125,9 @@ def tech_econ(c: "Computer") -> None: # Add a technology dimension with certain labels to the energy intensity of VDT # NB "energy intensity of VDT" actually has dimension (n,) only - t_F_ROAD = "t::transport F ROAD" - c.add(k[0], "expand_dims", "energy intensity of VDT:n-y", t_F_ROAD) + c.add(k[0], "expand_dims", "energy intensity of VDT:n-y", K.coord.t["F ROAD"]) # Broadcast over dimensions (c, l, y, yv, ya) - prev = c.add(k[1], "mul", k[0], bcast_tcl.input, bcast_y.model) + prev = c.add(k[1], "mul", k[0], K.bcast_tcl.input, K.bcast_y.model) # Convert MESSAGE data structure c.add(k[2], "as_message_df", prev, name="input", dims=DIMS, common=COMMON) # Convert units; add to `TARGET` @@ -139,10 +138,9 @@ def tech_econ(c: "Computer") -> None: # Create base quantity c.add(k[0], wildcard(1.0, "dimensionless", NTY)) - coords = ["n::ex world", "t::F", "y::model"] - c.add(k[1], "broadcast_wildcard", k[0], *coords, dim=NTY) + c.add(k[1], "broadcast_wildcard", k[0], K.n, K.t["F"], K.y, dim=NTY) # Broadcast over dimensions (c, l, y, yv, ya) - prev = c.add(k[2], "mul", k[1], bcast_tcl.output, bcast_y.all) + prev = c.add(k[2], "mul", k[1], K.bcast_tcl.output, K.bcast_y.all) # Convert to MESSAGE data structure prev = c.add(k[3], "as_message_df", prev, name="output", dims=DIMS, common=COMMON) # Convert units; add to `TARGET` @@ -176,14 +174,13 @@ def usage(c: "Computer") -> None: # Base values c.add(k[0], "freight_usage_output", "context") # Broadcast from (t,) → (t, c, l) dimensions - prev = c.add(k[1], "mul", k[0], bcast_tcl.output) + prev = c.add(k[1], "mul", k[0], K.bcast_tcl.output) # Broadcast over the (n, yv, ya) dimensions - d = bcast_tcl.output.dims + tuple("ny") + d = K.bcast_tcl.output.dims + tuple("ny") prev = c.add(k[2] * d, "expand_dims", prev, dim=dict(n=["*"], y=["*"])) - coords = ["n::ex world", "y::model"] - prev = c.add(k[3] * d, "broadcast_wildcard", prev, *coords, dim=tuple("ny")) - prev = c.add(k[4], "mul", prev, bcast_y.no_vintage) + prev = c.add(k[3] * d, "broadcast_wildcard", prev, K.n, K.y, dim=tuple("ny")) + prev = c.add(k[4], "mul", prev, K.bcast_y.no_vintage) # Convert to MESSAGE data structure c.add(k[5], "as_message_df", prev, name="output", dims=DIMS, common=COMMON) # Fill node_dest, time_dest key values @@ -196,7 +193,7 @@ def usage(c: "Computer") -> None: coords = ["n::ex world", "t::F usage", "y::model"] c.add(k[1], "broadcast_wildcard", k[0], *coords, dim=NTY) # Broadcast (t,) → (t, c, l) and (y,) → (yv, ya) dimensions - prev = c.add(k[2], "mul", k[1], bcast_tcl.input, bcast_y.no_vintage) + prev = c.add(k[2], "mul", k[1], K.bcast_tcl.input, K.bcast_y.no_vintage) # Convert to MESSAGE data structure collect( "usage input", "as_message_df", prev, name="input", dims=DIMS, common=COMMON diff --git a/message_ix_models/model/transport/groups.py b/message_ix_models/model/transport/groups.py index 1069b93496..374a0ea439 100644 --- a/message_ix_models/model/transport/groups.py +++ b/message_ix_models/model/transport/groups.py @@ -16,19 +16,19 @@ def prepare_computer(c: "Computer") -> None: """Prepare `rep` for calculating transport consumer groups.""" - from .key import cg, exo, pop, pop_at + from . import key as K c.add("indexers:n-cd", "indexers_n_cd", "config") # Population shares by area_type - c.add(pop_at, urban_rural_shares, pop, "config") + c.add(K.pop_at, urban_rural_shares, K.pop, "config") # Exogenous data for consumer group sizes keys = [ - exo.population_suburb_share, - exo.pop_share_attitude, - exo.pop_share_driver, - exo.pop_share_cd_at, + K.exo.population_suburb_share, + K.exo.pop_share_attitude, + K.exo.pop_share_driver, + K.exo.pop_share_cd_at, ] - c.add(cg, cg_shares, pop_at, *keys, "indexers:n-cd", "indexers:cg") + c.add(K.cg, cg_shares, K.pop_at, *keys, "indexers:n-cd", "indexers:cg") def cg_shares( diff --git a/message_ix_models/model/transport/ikarus.py b/message_ix_models/model/transport/ikarus.py index 9ee5ceb725..f6e68a5023 100644 --- a/message_ix_models/model/transport/ikarus.py +++ b/message_ix_models/model/transport/ikarus.py @@ -22,7 +22,7 @@ same_time, ) -from .key import bcast_tcl, bcast_y +from . import key as K from .passenger import UNITS if TYPE_CHECKING: @@ -245,7 +245,7 @@ def prepare_computer(c: Computer): # NB this (harmlessly) duplicates an addition in .ldv.prepare_computer() # TODO deduplicate k_fi = Key("transport input factor:t-y") - c.add(k_fi, "factor_input", "y", "t::transport", "t::transport agg", "config") + c.add(k_fi, "factor_input", "y", K.t, K.agg.t, "config") parameters = ["fix_cost", "input", "inv_cost", "technical_lifetime", "var_cost"] @@ -296,7 +296,7 @@ def prepare_computer(c: Computer): # Drop existing "c" dimension prev = c.add(prev / "c", "drop_vars", prev, quote("c")) # Fill (c, l) dimensions based on t - prev = c.add(k[6], "mul", prev, bcast_tcl.input) + prev = c.add(k[6], "mul", prev, K.bcast_tcl.input) elif name == "technical_lifetime": # Round up technical_lifetime values due to incompatibility in handling # non-integer values in the GAMS code @@ -307,7 +307,7 @@ def prepare_computer(c: Computer): if name in ("fix_cost", "input", "var_cost"): # Broadcast across valid (yv, ya) pairs - prev = c.add(k[8], "mul", prev, bcast_y.model) + prev = c.add(k[8], "mul", prev, K.bcast_y.model) # Convert to target units try: @@ -344,9 +344,7 @@ def prepare_computer(c: Computer): # Derive "output" data from "input" prev = "transport nonldv output::ixmp" - final["output"] = c.add( - prev, make_output, "transport nonldv input::ixmp", "t::transport" - ) + final["output"] = c.add(prev, make_output, "transport nonldv input::ixmp", K.t) # Merge all data together c.add(TARGET, "merge_data", *final.values()) diff --git a/message_ix_models/model/transport/key.py b/message_ix_models/model/transport/key.py index feed1eaaa6..4e099d0b5c 100644 --- a/message_ix_models/model/transport/key.py +++ b/message_ix_models/model/transport/key.py @@ -168,8 +168,6 @@ to_y0="y::to y0", ) -yv = Keys(historical_idx="indexers:yv:historical") - #: Keys referring to loaded input data flows (exogenous data loaded from files). #: Attributes correspond to the members of :mod:`.transport.data`; see #: :doc:`/transport/input` for a complete list. diff --git a/message_ix_models/model/transport/ldv.py b/message_ix_models/model/transport/ldv.py index f6823c9a15..813bfe8d3a 100644 --- a/message_ix_models/model/transport/ldv.py +++ b/message_ix_models/model/transport/ldv.py @@ -21,10 +21,10 @@ ) from message_ix_models.util.genno import Collector +from . import key as K from . import util from .data import MaybeAdaptR11Source from .emission import ef_for_input -from .key import bcast_tcl, bcast_y, exo from .util import COMMON, wildcard if TYPE_CHECKING: @@ -100,11 +100,10 @@ def prepare_computer(c: Computer): # Some keys/shorthand k = Keys( - fe=Key("fuel economy:n-t-y:LDV"), - eff=Key("efficiency:t-y-n:LDV"), - factor_input=Key("input:t-y:LDV+factor"), + fe="fuel economy:n-t-y:LDV", + eff="efficiency:t-y-n:LDV", + factor_input="input:t-y:LDV+factor", ) - t_ldv = "t::transport LDV" # Use .tools.exo_data.prepare_computer() to add tasks that load, adapt, and select # the appropriate data @@ -114,7 +113,7 @@ def prepare_computer(c: Computer): # Insert a scaling factor that varies according to SSP c.apply( - factor.insert, k.fe + "exo", name="ldv fuel economy", target=k.fe, dims="nty" + factor.insert, k.fe["exo"], name="ldv fuel economy", target=k.fe, dims="nty" ) # Reciprocal value, i.e. from Gv km / GW a → GW a / Gv km @@ -122,27 +121,18 @@ def prepare_computer(c: Computer): # Compute the input efficiency adjustment factor for the NAVIGATE project # TODO Move this to project-specific code - c.add( - k.factor_input, - "factor_input", - "y", - "t::transport", - "t::transport agg", - "config", - ) + c.add(k.factor_input, "factor_input", "y", K.t, K.agg.t, "config") # Product of NAVIGATE input efficiency factor and LDV efficiency c.add(k.eff[1], "mul", k.factor_input, k.eff[0]) # Multiply by values from ldv-input-adj.csv. See file comment. Drop the 'scenario' # dimension; there is only one value in the file per 'n'. - c.add("input:n:LDV+adj", "sum", exo.input_adj_ldv, dimensions=["scenario"]) + c.add("input:n:LDV+adj", "sum", K.exo.input_adj_ldv, dimensions=["scenario"]) c.add(k.eff[2], "mul", k.eff[1], "input:n:LDV+adj") # Apply the function usage_data() for further processing - collect( - "usage", usage_data, exo.load_factor_ldv, "cg", "n::ex world", t_ldv, "y::model" - ) + collect("usage", usage_data, K.exo.load_factor_ldv, "cg", K.n, K.t["LDV"], K.y) # Add further keys for MESSAGE-structured data # Techno-economic attributes @@ -186,24 +176,23 @@ def prepare_tech_econ( c.add(k[0], wildcard(1.0, "Gv km", k.dims)) # Broadcast over (n, t, y) dimensions - coords = ["n::ex world", "t::LDV", "y::model"] - c.add(k[1], "broadcast_wildcard", k[0], *coords, dim=k.dims) + c.add(k[1], "broadcast_wildcard", k[0], K.n, K.t["LDV"], K.y, dim=k.dims) # Broadcast `exo.input_share` over (c, t) dimensions. This produces a large Quantity # with 1.0 everywhere except explicit entries in the input data file. # NB Order matters here - k = exo.input_share - coords = ["t::LDV", "c::transport+base", "y"] # NB include historical periods + k = K.exo.input_share + coords = [K.t["LDV"], "c::transport+base", "y"] # NB include historical periods c.add(k[0], "broadcast_wildcard", k, *coords, dim=k.dims) # Multiply by `bcast_tcl.input` to keep only the entries that correspond to actual # input commodities of particular technologies. - input_bcast = c.add("input broadcast::LDV", "mul", k[0], bcast_tcl.input) + input_bcast = c.add("input broadcast::LDV", "mul", k[0], K.bcast_tcl.input) ### Convert input and output to MESSAGE data structure for par_name, base, bcast in ( ("input", efficiency, input_bcast), - ("output", output_base[1], bcast_tcl.output), + ("output", output_base[1], K.bcast_tcl.output), ): k = Key(par_name, base.dims, "LDV") @@ -212,7 +201,7 @@ def prepare_tech_econ( # Broadcast from (y) to (yv, ya) dims to produce the full quantity for # input/output efficiency - prev = c.add(k[1], "mul", k[0], bcast, bcast_y.all) + prev = c.add(k[1], "mul", k[0], bcast, K.bcast_y.all) # Convert to ixmp/MESSAGEix-structured pd.DataFrame c.add(k[2], "as_message_df", prev, name=par_name, dims=DIMS, common=COMMON) @@ -224,7 +213,7 @@ def prepare_tech_econ( kw = dict(fill_value="extrapolate") for name, base in (("fix_cost", fix_cost), ("inv_cost", inv_cost)): prev = c.add(f"{name}::LDV+0", "interpolate", base, "y::coords", kwargs=kw) - prev = c.add(f"{name}::LDV+1", "mul", prev, bcast_y.all) + prev = c.add(f"{name}::LDV+1", "mul", prev, K.bcast_y.all) collect(name, "as_message_df", prev, name=name, dims=DIMS, common=COMMON) ### Compute CO₂ emissions factors @@ -282,7 +271,7 @@ def usage_data( load_factor: "AnyQuantity", cg: list["Code"], nodes: list[str], - t_ldv: Mapping[str, list], + technologies: list["Code"], years: list, ) -> "ParameterData": """Generate data for LDV “usage pseudo-technologies”. @@ -299,7 +288,7 @@ def usage_data( info = ScenarioInfo(set={"node": nodes, "year": years}) # Regenerate the Spec for the disutility formulation - spec = disutility.get_spec(groups=cg, technologies=t_ldv["t"], template=TEMPLATE) + spec = disutility.get_spec(groups=cg, technologies=technologies, template=TEMPLATE) data = disutility.data_conversion(info, spec) diff --git a/message_ix_models/model/transport/other.py b/message_ix_models/model/transport/other.py index 89036f2297..33809a00b0 100644 --- a/message_ix_models/model/transport/other.py +++ b/message_ix_models/model/transport/other.py @@ -7,8 +7,8 @@ import pandas as pd from genno import Key, quote +from . import key as K from . import util -from .key import exo, fv if TYPE_CHECKING: from genno import Computer @@ -34,7 +34,7 @@ def prepare_computer(c: "Computer") -> None: """Generate MESSAGE parameter data for ``transport other *`` technologies.""" # Keys - base = exo.energy_other + base = K.exo.energy_other assert {"c", "n"} == set(base.dims) bcast = Key("broadcast:c-t:other transport") k_cnt = (base + "0") * "t" # with added dimension "t" @@ -61,11 +61,11 @@ def broadcast_other_transport(technologies) -> "AnyQuantity": pd.DataFrame(rows, columns=cols).set_index(cols[:-1])[cols[-1]] ) - c.add(bcast, broadcast_other_transport, "t::transport") + c.add(bcast, broadcast_other_transport, K.t) c.add(k_cnt, "mul", base, bcast) # Project values across y using same trajectory as road freight activity - c.add(k_cnty[0], "mul", k_cnt, fv["F ROAD index"]) + c.add(k_cnty[0], "mul", k_cnt, K.fv["F ROAD index"]) # Convert units to GWa c.add(k_cnty[1], "convert_units", k_cnty[0], units="GWa") diff --git a/message_ix_models/model/transport/passenger.py b/message_ix_models/model/transport/passenger.py index 0be6541080..0b3f31236c 100644 --- a/message_ix_models/model/transport/passenger.py +++ b/message_ix_models/model/transport/passenger.py @@ -21,7 +21,7 @@ ) from message_ix_models.util.genno import Collector -from .key import exo +from . import key as K if TYPE_CHECKING: from message_ix_models import Context @@ -63,8 +63,6 @@ def prepare_computer(c: Computer): - from .key import n, t_modes, y - context: "Context" = c.graph["context"] # Collect data in `TARGET` and connect to the "add transport data" key @@ -92,7 +90,7 @@ def prepare_computer(c: Computer): # keys.append(k + "emi") # Data for usage pseudo-technologies - collect("usage", usage_data, exo.load_factor_p, t_modes, n, y) + collect("usage", usage_data, K.exo.load_factor_p, K.t_modes, K.n, K.y) #### NB lines below duplicated from .transport.base e_iea = Key("energy:n-y-product-flow:iea") @@ -171,7 +169,7 @@ def get_2w_dummies(context) -> "ParameterData": def bound_activity(c: "Computer") -> None: """Constrain activity of non-LDV technologies based on :file:`act-non_ldv.csv`.""" - base = exo.act_non_ldv + base = K.exo.act_non_ldv # Produce MESSAGE parameters bound_activity_{lo,up}:nl-t-ya-m-h kw = dict( @@ -220,7 +218,7 @@ def _(nodes, technologies, y0, config: dict) -> Quantity: ) k = Key("bound_activity_lo:n-t-y:transport minimum") - c.add(next(k), _, "n::ex world", "t::transport", "y0", "config") + c.add(next(k), _, K.n, K.t, "y0", "config") # Produce MESSAGE parameter bound_activity_lo:nl-t-ya-m-h kw = dict( diff --git a/message_ix_models/model/transport/plot.py b/message_ix_models/model/transport/plot.py index f88a76e01a..bcc93e927d 100644 --- a/message_ix_models/model/transport/plot.py +++ b/message_ix_models/model/transport/plot.py @@ -10,7 +10,7 @@ from message_ix_models.model.workflow import STAGE from message_ix_models.report.plot import COMMON, LabelFirst, Plot, PlotFromIAMC -from . import key +from . import key as K #: Common, static settings STATIC = [ @@ -403,7 +403,7 @@ class DemandCap(Plot): """Transport demand per capita [km / a].""" basename = "demand-capita" - inputs = ["demand:n-c-y:capita", "c::transport", "cg"] + inputs = ["demand:n-c-y:capita", K.c, "cg"] static = STATIC + [ p9.aes(x="y", y="value", fill="c"), p9.geom_bar(stat="identity", width=4), @@ -434,7 +434,7 @@ class DemandExo(Plot): basename = "demand-exo" stage = STAGE.BUILD - inputs = [key.pdt_nyt] + inputs = [K.pdt_nyt] static = STATIC + [ p9.aes(x="y", y="value", fill="t"), p9.geom_bar(stat="identity", width=4), @@ -456,7 +456,7 @@ class DemandExoCap0(Plot): basename = "demand-exo-capita" stage = STAGE.BUILD - inputs = [key.pdt_nyt + "capita+post"] + inputs = [K.pdt_nyt + "capita+post"] static = STATIC + [ p9.aes(x="y", y="value", fill="t"), p9.geom_bar(stat="identity", width=4), @@ -481,7 +481,7 @@ class DemandExoCap1(DemandExoCap0): basename = "demand-exo-capita-gdp" stage = STAGE.BUILD - inputs = [key.pdt_nyt + "capita+post", key.gdp_cap] + inputs = [K.pdt_nyt + "capita+post", K.gdp_cap] static = PDT_CAP_GDP_STATIC def generate(self, df_pdt, df_gdp): diff --git a/message_ix_models/model/transport/vehicle.py b/message_ix_models/model/transport/vehicle.py index b53728e6fb..24dfe1abf9 100644 --- a/message_ix_models/model/transport/vehicle.py +++ b/message_ix_models/model/transport/vehicle.py @@ -10,7 +10,7 @@ from message_ix_models.util.genno import Collector -from .key import bcast_y, exo, fv, ldv_ny, pdt_nyt, y_, yv +from . import key as K from .util import COMMON, DIMS if TYPE_CHECKING: @@ -37,7 +37,7 @@ def prepare_computer(c: "Computer") -> None: context = c.graph["context"] techs = context.transport.spec.add.set["technology"] - k = exo.activity_vehicle + k = K.exo.activity_vehicle for mode in "F", "P ex LDV", "LDV": # Select only the "t" dimension coords according to `mode` @@ -55,7 +55,7 @@ def prepare_computer(c: "Computer") -> None: tl = "technical_lifetime" # Convert to MESSAGE data structure collect( - f"{tl}::vehicle", "as_message_df", exo.lifetime, name=tl, dims=DIMS, common={} + f"{tl}::vehicle", "as_message_df", K.exo.lifetime, name=tl, dims=DIMS, common={} ) # # total stock = stock per capita × total population @@ -73,13 +73,13 @@ def prepare_computer(c: "Computer") -> None: def capacity_factor(c: "Computer", mode: str) -> None: """Add data for MESSAGE parameter ``capacity_factor``.""" cf = "capacity_factor" - k = Key(cf, exo.activity_vehicle.dims, mode) + k = Key(cf, K.exo.activity_vehicle.dims, mode) # Expand from "t" modes to all actual technologies - c.add(k[0], "call", "t::transport map", exo.activity_vehicle[mode]) + c.add(k[0], "call", "t::transport map", K.exo.activity_vehicle[mode]) # Broadcast y → (yV, yA) - prev = c.add(k[1], "mul", k[0], bcast_y.all) + prev = c.add(k[1], "mul", k[0], K.bcast_y.all) # Convert to MESSAGE data structure dims = DIMS | dict(node_loc="n") @@ -108,9 +108,9 @@ def stock(c: "Computer", mode: str, *, margin: float = 0.2) -> None: ) k_total_activity, k_load_factor = { - "F": (fv, exo.load_factor_f), - "P ex LDV": (pdt_nyt, exo.load_factor_p), - "LDV": (ldv_ny + "total", exo.load_factor_ldv), + "F": (K.fv, K.exo.load_factor_f), + "P ex LDV": (K.pdt_nyt, K.exo.load_factor_p), + "LDV": (K.ldv_ny + "total", K.exo.load_factor_ldv), }[mode] # - Divide total activity by (1) annual driving distance per vehicle and (2) load @@ -118,7 +118,7 @@ def stock(c: "Computer", mode: str, *, margin: float = 0.2) -> None: # - Correct units: "load factor ldv:n-y" is dimensionless, should be # passenger/vehicle # - Select only the base-period value. - c.add(k.stock[0], "div", k_total_activity, exo.activity_vehicle[mode]) + c.add(k.stock[0], "div", k_total_activity, K.exo.activity_vehicle[mode]) c.add(k.stock[1], "div", k.stock[0], k_load_factor) c.add(k.stock[2] / "y", "select", k.stock[1], "y0::coord", sums=True) @@ -126,15 +126,15 @@ def stock(c: "Computer", mode: str, *, margin: float = 0.2) -> None: return # Multiply by exogenous technology shares to obtain stock with (n, t) dimensions - c.add(k.stock, "mul", k.stock[2] / ("t", "y"), exo.t_share_ldv) + c.add(k.stock, "mul", k.stock[2] / ("t", "y"), K.exo.t_share_ldv) # Fraction of sales in preceding years (annual, not MESSAGE 'year' referring to # multi-year periods) - c.add(k.sales_nty[0], "sales_fraction_annual", exo.age_ldv) + c.add(k.sales_nty[0], "sales_fraction_annual", K.exo.age_ldv) # Absolute sales in preceding years c.add(k.sales_nty[1], "mul", k.stock, k.sales_nty[0], 1.0 + margin) # Aggregate to model periods; total sales across the period - c.add(k.sales_nty[2], "aggregate", k.sales_nty[1], y_.annual_agg, keep=False) + c.add(k.sales_nty[2], "aggregate", k.sales_nty[1], K.y_.annual_agg, keep=False) # Divide by duration_period for the equivalent of CAP_NEW/historical_new_capacity c.add(k.sales_nty, "div", k.sales_nty[2], "duration_period:y") @@ -150,7 +150,7 @@ def stock(c: "Computer", mode: str, *, margin: float = 0.2) -> None: dims=dict(node_loc="nl", technology="t", year_vtg="yv"), name="historical_new_capacity", ) - c.add(k.sales[1], "select", k.sales[0], yv.historical_idx) + c.add(k.sales[1], "select", k.sales[0], K.coord.yv_hist) collect(f"{kw['name']}::{mode}", "as_message_df", k.sales[1], **kw) # CAP_NEW/bound_new_capacity_{lo,up} From 86da9cc6bef77fa59166d9133d4d0ddcf0d98ba6 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Tue, 14 Apr 2026 23:25:15 +0200 Subject: [PATCH 71/73] Consolidate .transport.report.callback() - Remove separate functions aggregate(), reapply_units(), select_transport_techs() in favour of fewer/generalized tasks. - Rename SELECT to QUANTITY. - Apply operations consistently to all QUANTITY. - Add UNIT global. - Adjust key references in .transport.{base,data}. - Improve docstrings. --- message_ix_models/model/transport/base.py | 2 +- message_ix_models/model/transport/data.py | 4 +- message_ix_models/model/transport/report.py | 216 +++++++++----------- 3 files changed, 101 insertions(+), 121 deletions(-) diff --git a/message_ix_models/model/transport/base.py b/message_ix_models/model/transport/base.py index 28c28c1472..d2d6371e69 100644 --- a/message_ix_models/model/transport/base.py +++ b/message_ix_models/model/transport/base.py @@ -213,7 +213,7 @@ def prepare_reporter(rep: "message_ix.Reporter") -> str: e_iea = Key("energy:n-y-product-flow:iea") e_fnp = Key(e_iea.drop("y")) e_cnlt = Key("energy:c-nl-t:iea+0") - k = Key("in:nl-t-ya-c-l-h:transport+units") # MESSAGE solution values + k = Key("in:nl-t-ya-c-l-h:T") # MESSAGE solution values # First period y0 = rep.get("y0") diff --git a/message_ix_models/model/transport/data.py b/message_ix_models/model/transport/data.py index 2a081f7ba2..0494a7e18d 100644 --- a/message_ix_models/model/transport/data.py +++ b/message_ix_models/model/transport/data.py @@ -1039,13 +1039,13 @@ def _output_dataflow(**kwargs) -> "Dataflow": id="ACTIVITY_VEHICLE", name="Vehicle activity", description='Same as the IAMC ‘variable’ code "Energy Service|Transportation".', - key="out:nl-t-ya-c:transport+units", + key="out:nl-t-ya-c:T", ) fe_transport = _output_dataflow( id="FE_TRANSPORT", name="Final energy", description='Same as the IAMC ‘variable’ code "Final Energy|Transportation".', - key="in:nl-t-ya-c:transport+units", + key="in:nl-t-ya-c:T", ) gdp_in = _output_dataflow( id="GDP_IN", diff --git a/message_ix_models/model/transport/report.py b/message_ix_models/model/transport/report.py index 28b4c64344..291a13e3d3 100644 --- a/message_ix_models/model/transport/report.py +++ b/message_ix_models/model/transport/report.py @@ -6,7 +6,7 @@ from typing import TYPE_CHECKING import pandas as pd -from genno import Computer, Key, Keys, MissingKeyError +from genno import Computer, Key, Keys from genno.core.key import single_key from message_ix import Reporter @@ -18,6 +18,8 @@ from . import key as K if TYPE_CHECKING: + from message_ix import Scenario + from message_ix_models import Spec log = logging.getLogger(__name__) @@ -27,25 +29,25 @@ #: the legacy reporting to properly handle the result. _FE_UNIT = "EJ/yr" - +#: Quantities to convert to IAMC. See :func:`convert_iamc`. CONVERT_IAMC = ( # NB these are currently tailored to produce the variable names expected for the # NGFS project dict( - variable="transport activity", - base="out:nl-t-ya-c:transport all+units", + variable="T activity", + base="out:nl-t-ya-c:T", var=["Energy Service|Transportation", "t", "c"], - sums=["c", "t", "c-t"], + sums=["c"], ), dict( variable="T stock", - base="CAP:nl-t-ya:transport all+units", + base="CAP:nl-t-ya:T", var=["Stocks|Transportation", "t"], unit="Mvehicle", ), dict( variable="T sales", - base="CAP_NEW:nl-t-yv:transport all+units", + base="CAP_NEW:nl-t-yv:T", var=["Sales|Transportation", "t"], unit="Mvehicle", ), @@ -54,18 +56,12 @@ # The following are 4 different partial sums of in::transport, in which # individual technologies are already aggregated to modes dict( - variable="transport fe", - base="in:nl-t-ya-c:transport all+units", + variable="T final energy", + base="in:nl-t-ya-c:T", var=["Final Energy|Transportation", "t", "c"], - sums=["c", "t", "c-t"], + sums=["c"], unit=_FE_UNIT, ), - dict( - variable="transport fe ldv", - base="in:nl-t-ya-c:ldv+units", - var=["Final Energy|Transportation", "t", "c"], - unit="EJ/yr", - ), # Emissions using MESSAGEix emission_factor parameter # base: auto-sum over dimensions yv, m, h # var: Same as in data/report/global.yaml @@ -97,11 +93,11 @@ ) -#: Quantities in which to select transport technologies only. See -#: :func:`select_transport_techs`. -SELECT = [ +#: Quantities in which to select transport technologies only. See :func:`callback`. +QUANTITY = [ "CAP_NEW", "CAP", + "emi", "fix_cost", "historical_new_capacity", "in", @@ -111,68 +107,101 @@ "var_cost", ] - -def aggregate(c: "Computer") -> None: - """Aggregate individual transport technologies to modes.""" - from genno.operator import aggregate as func - - config: Config = c.graph["config"]["transport"] - - for k in map(lambda s: Key(c.infer_keys(s)), "emi in out".split()): - try: - # Reference the function to avoid the genno magic which would treat as sum() - # NB aggregation on the nl dimension *could* come first, but this can use a - # lot of memory when applied to e.g. out:*: for a full global model. - c.add(k[0], func, k, "t::transport agg", keep=False) - c.add(k[1], func, k[0], "nl::world agg", keep=False) - c.add(k["transport"], "select", k[1], "t::transport modes 1", sums=True) - except MissingKeyError: - if config.with_solution: - raise +#: Units to apply or assign to specific quantities. See :func:`callback`. +#: +#: - Previously ``CAP:nl-t-ya:non-ldv`` was converted to "v**2 Tm / a". +#: - For ``emi``, units of ``ACT`` are not carried, so a correction is needed: +#: +#: - Add [time]: -1 +#: - Remove [vehicle]: -1, [distance]: -1 +#: +#: When run together with global.yaml reporting, emi:* is assigned units of +#: "Mt / year". Using apply_units() causes these to be *converted* to kt/a, i.e. +#: increasing the magnitude; so use assign_units() instead. +UNITS = { + "CAP": ("apply", "Mv"), + "CAP_NEW": ("apply", "Mv"), + "emi": ("assign", "kt / a"), + "in": ("apply", "GWa / a"), + "out": ("apply", "Tm / a"), +} def callback(rep: Reporter, context: Context) -> None: """:meth:`.prepare_reporter` callback for MESSAGEix-Transport. - Among others, adds: - - - ``{in,out}::transport``: with outputs aggregated by technology group or - "mode". - - ``transport plots``: the plots from :mod:`.transport.plot`. - - If the scenario to be reported is not solved, only a subset of plots are added. - - :data:`.key.report.all`: all of the above. + `rep` is extended with tasks for transport reporting. Among others, these include: + + 1. Select subsets of transport technologies. For each input quantity in + :data:`SELECT`, for example ``CAP_NEW:*``, tasks are added to compute: + + - ``CAP_NEW:*:transport all`` —selects only the technologies in + ``t::transport all``. + - ``CAP_NEW:*:ldv`` —selects only the technologies in ``t::transport LDV``. + - ``CAP_NEW:*:non-ldv`` —selects only the technologies in + ``t::transport P ex LDV``. + + 2. (Re) apply units. :func:`.ixmp.report.operator.data_for_quantity` drops units for + most data extracted from a MESSAGEix-GLOBIOM :class:`.Scenario`, because the data + contain a mix of inconsistent units. + + For every item in :data:`UNITS`, add a task to apply or assign units to selected + subsets of data that are guaranteed to have those units. + + 3. Aggregate in 3 stages, using :data:`key.agg.t <.transport.key.agg>` and + ``nl::world agg``, ``t::transport modes 1``, producing keys like ``emi:*:T``. + These values are aggregated by technology group and/or mode. + 4. Invoke :func:`misc`. + 5. Invoke :func:`convert_iamc`. + 6. Invoke :func:`convert_sdmx`. + 7. Add plots from :mod:`.transport.plot` using :func:`.report.add_plots`. These + appear at :data:`key.report.plot <.transport.key.report>`. If the scenario to be + reported is not solved, only a subset of plots are added. + 8. Invoke :func:`.transport.base.prepare_reporter`. + 9. :data:`key.report.all <.transport.key.report>` which includes all of the above. """ + from genno.operator import aggregate + from . import base, build - N_keys = len(rep.graph) + N_keys = len(rep.graph) # Number of keys prior to additions - # - Configure MESSAGEix-Transport. - # - Add structure and other information. + # - Configure MESSAGEix-Transport, if not already configured. + # - Add structure and other information from `scenario`. # - Call, inter alia: # - demand.prepare_computer() for ex-post mode and demand calculations. - check = build.get_computer( - context, obj=rep, visualize=False, scenario=rep.graph.get("scenario") - ) - - assert check is rep # Same `rep` was returned - - if False: - log.info("Filter out non-transport technologies") + # - Check that the same Reporter object is returned. + s: "Scenario | None" = rep.graph.get("scenario") + assert build.get_computer(context, obj=rep, visualize=False, scenario=s) is rep + + # Apply common steps for each of QUANTITY + # - Infer the full dimensionality of each key to be selected + for k_base in rep.infer_keys(QUANTITY): + k = k_base["T"] # Target key + + # 1. Select all transport technologies + rep.add(k[0], "select", k_base, K.coord.t, sums=True) + + # 2. Apply units + if k.name in UNITS: + op, units = UNITS[k.name] + rep.add(k[1], f"{op}_units", k[0], units=units, sums=True) + else: + rep.add(k[1], k[0]) # Simple alias / no-op - # Plain "transport" from the base model, for e.g. prices - t_filter = {"transport"} - # MESSAGEix-Transport -specific technologies - t_filter.update(map(str, rep.get("t::transport").copy())) - # # Required commodities (e.g. fuel) from the base model - # t_filter.update(spec.require.set["commodity"]) + # 1. Select further subsets of transport technologies. + rep.add(k["ldv"], "select", k[1], K.coord.t["LDV"], sums=True) + rep.add(k["non-ldv"], "select", k[1], K.coord.t["P ex LDV"], sums=True) - rep.set_filters(t=sorted(t_filter)) + # 3. Aggregate according to groups + # Reference the function to avoid the genno magic which would treat as sum() + # NB aggregation on the nl dimension *could* come first, but this can use a + # lot of memory when applied to e.g. out:*: for a full global model. + rep.add(k[2], aggregate, k[1], K.agg.t, keep=True) + rep.add(k, aggregate, k[2], "nl::world agg", keep=False, sums=True) + rep.add(k["modes"], "select", k, "t::transport modes 1", sums=True) # Apply some functions that prepare further tasks. Order matters here. - aggregate(rep) - select_transport_techs(rep) - reapply_units(rep) misc(rep) convert_iamc(rep) # Adds to key.report.all convert_sdmx(rep) # Adds to key.report.all @@ -180,7 +209,6 @@ def callback(rep: Reporter, context: Context) -> None: base.prepare_reporter(rep) # Tasks that prepare data to parametrize the base model log.info(f"Added {len(rep.graph) - N_keys} keys") - # TODO Write an SVG visualization of reporting calculations def check(scenario): @@ -329,6 +357,7 @@ def misc(c: "Computer") -> None: # Configuration for :func:`check`. Adds a single key, 'transport check', that # depends on others and returns a :class:`pandas.Series` of :class:`bool`. + # TODO Replace with use of message_ix_models.testing.check c.add("transport check", "transport_check", "scenario", "ACT:nl-t-yv-va-m-h") # Exogenous data @@ -338,8 +367,8 @@ def misc(c: "Computer") -> None: c.add("demand::capita", "divdemand:n-c-y", K.pop) # Adjustment factor for LDV calibration: fuel economy ratio - k_num = Key("in:nl-t-ya-c:transport+units") / "c" # As in CONVERT_IAMC - k_denom = Key("out:nl-t-ya-c:transport+units") / "c" # As in CONVERT_IAMC + k_num = Key("in:nl-t-ya-c:T") / "c" # As in CONVERT_IAMC + k_denom = Key("out:nl-t-ya-c:T") / "c" # As in CONVERT_IAMC k_check = single_key(c.add("fuel economy::check", "div", k_num, k_denom)) c.add( k_check + "sel", @@ -413,52 +442,3 @@ def multi(context: Context, targets: list[str], *, use_platform: bool = False) - add_plots(c, plot, "multi", stage=STAGE.REPORT, single=False) return c.get("multi") - - -def reapply_units(c: "Computer") -> None: - """Apply units to transport quantities. - - :func:`.ixmp.report.operator.data_for_quantity` drops units for most data extracted - from a MESSAGEix-GLOBIOM :class:`.Scenario`, because the data contain a mix of - inconsistent units. - - Here, add tasks to reapply units to selected subsets of data that are guaranteed to - have certain units. - """ - # TODO Infer these values from technology.yaml etc. - for base, (op, units) in { - # Vehicle stocks - # FIXME should not need the extra [vehicle] in the numerator - "CAP:nl-t-ya:non-ldv": ("apply", "v**2 Tm / a"), - "CAP:*:ldv": ("apply", "Mv"), - "CAP:*:transport all": ("apply", "Mv"), - "CAP_NEW:*:ldv": ("apply", "Mv"), - "CAP_NEW:*:transport all": ("apply", "Mv"), - # NB these units are correct for final energy only - "in:*:transport": ("apply", "GWa / a"), - "in:*:ldv": ("apply", "GWa / a"), - "out:*:transport": ("apply", "Tm / a"), - "out:*:ldv": ("apply", "Tm / a"), - # Units of ACT are not carried, so must correct here: - # - Add [time]: -1 - # - Remove [vehicle]: -1, [distance]: -1 - # - # When run together with global.yaml reporting, emi:* is assigned units of - # "Mt / year". Using apply_units() causes these to be *converted* to kt/a, i.e. - # increasing the magnitude; so use assign_units() instead. - "emi:*:transport": ("assign", "kt / a"), - }.items(): - key = c.infer_keys(base) - c.add(key + "units", f"{op}_units", key, units=units, sums=True) - - -def select_transport_techs(c: "Computer") -> None: - """Select subsets of transport technologies. - - Applied to the quantities in :data:`SELECT`. - """ - # Infer the full dimensionality of each key to be selected - for k in map(lambda name: c.infer_keys(f"{name}:*"), SELECT): - c.add(k + "transport all", "select", k, "t::transport all", sums=True) - c.add(k + "ldv", "select", k, "t::transport LDV", sums=True) - c.add(k + "non-ldv", "select", k, "t::transport P ex LDV", sums=True) From 5b4e32a08331acee2702885c0bc2a594e5cdfe24 Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Tue, 14 Apr 2026 23:14:23 +0200 Subject: [PATCH 72/73] Update docs for #471 --- message_ix_models/model/transport/operator.py | 5 ++++- message_ix_models/report/operator.py | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/message_ix_models/model/transport/operator.py b/message_ix_models/model/transport/operator.py index 3095ca8f0a..195b765e57 100644 --- a/message_ix_models/model/transport/operator.py +++ b/message_ix_models/model/transport/operator.py @@ -1121,7 +1121,10 @@ def transport_data(*args): def transport_check(scenario: "Scenario", ACT: "AnyQuantity") -> pd.Series: - """Reporting operator for :func:`.check`.""" + """Reporting operator for :func:`.check`. + + .. todo:: Replace with use of :mod:`.testing.check`. + """ info = ScenarioInfo(scenario) # Mapping from check name → bool diff --git a/message_ix_models/report/operator.py b/message_ix_models/report/operator.py index d0a01f0854..3e69ee749f 100644 --- a/message_ix_models/report/operator.py +++ b/message_ix_models/report/operator.py @@ -436,7 +436,8 @@ def nodes_world_agg( """Mapping to aggregate e.g. nl="World" from values for child nodes of "World". This mapping should be used with :func:`.genno.operator.aggregate`, giving the - argument ``keep=False``. It includes 1:1 mapping from each region name to itself. + argument :py:`keep=False`, because it includes 1:1 mapping from each region name to + itself. """ from message_ix_models.model.structure import get_codelist From eb278bc8a4b20559ccd3529bad204bb02284aadc Mon Sep 17 00:00:00 2001 From: Paul Natsuo Kishimoto Date: Wed, 15 Apr 2026 11:06:54 +0200 Subject: [PATCH 73/73] Add #471 to doc/whatsnew --- doc/whatsnew.rst | 95 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 83 insertions(+), 12 deletions(-) diff --git a/doc/whatsnew.rst b/doc/whatsnew.rst index b697560e01..08e57cd53b 100644 --- a/doc/whatsnew.rst +++ b/doc/whatsnew.rst @@ -4,18 +4,89 @@ What's new Next release ============ -- :mod:`message_ix_models` supports and is tested against `Pandas 3.0.0 `_, +- :mod:`message_ix_models` supports and is tested against + `Pandas 3.0.0 `_, released 2026-01-21 (:pull:`470`). -- New module :mod:`tools.bilateralize ` +- New module :mod:`.tools.bilateralize` to change scenarios to a bilateral representation of trade (:pull:`438`). - -- Add reduced basin filtering for water module with ``--reduced-basin`` and - demand/supply stress-based selection via ``--basin-selection stress`` - (:pull:`432`, :issue:`414`). - -- Fix water module parameter bugs and refactor cooling (:pull:`405`): - infrastructure M1/Mf mode fixes, regional average shares for cooling allocation, - water supply level hierarchy corrections, and test suite improvements. +- New function :func:`.workflow.from_codelist` (:pull:`471`) + to generate a :class:`.Workflow` from a list of SDMX codes + by inspection of their IDs and annotations. +- Improve :mod:`~message_ix_models.report` (:pull:`471`): + + - :func:`~.report.report` updates the :class:`.Context` + with additional keyword arguments. + - New reporting operator :func:`.broadcast_wildcard2`. + - New utility :func:`.report.util.store_write_ts`, + generalized from :py:`transport.report.add_iamc_store_write()`. + +- New class :class:`.testing.check.InRange` (:pull:`471`). +- :meth:`.ConfigHelper.update` canonicalizes arguments; + accepts an optional ConfigHelper or dict as first positional argument (:pull:`471`). +- :meth:`.Context.update` invokes :meth:`.ConfigHelper.update` on sub-instances (:pull:`471`). +- Improve :doc:`/transport/index` (:pull:`471`): + + - Update data flows: + + - :class:`.ActivityVehicle`: new :class:`.ExoDataSource` class + inclusive of all modes and technologies; + replaces :py:`ldv_activity` that was specific to LDVs. + - :data:`.activity_vehicle_out`: rename from :py:`activity_vehicle`. + - :class:`.Lifetime`: new :class:`.ExoDataSource` class, + replaces :py:`lifetime_Ldv` that was specific to LDVs. + - :data:`.load_factor_f`: new. + This data flow is kept separate from :data:`.load_factor_p` because the units + of activity/service differ (tonne- vs. passenger-kilometre). + - :class:`.LoadFactorLDV`: add units "passenger / vehicle". + - :data:`.load_factor_p`: rename from :py:`load_factor_non_ldv`. + - :data:`.freight_activity`: change units Gt km → Gt km / year. + + - Expand transport technology code list: + + - Distinguish names and reporting aliases for all vehicle technologies. + - Add ``ntnu-vmi-technology`` annotations for :mod:`.transport.material`. + + - New functions and methods: + + :meth:`.transport.config.Config.get_target_url` + replacing :py:`transport.workflow.scenario_url()`, + + :func:`.transport.material.get_groups`, and + + :func:`~.transport.structure.get_commodity_groups`. + + - Harmonize :mod:`genno` keys used for structural information, + coordinates, etc. during build and reporting in :mod:`.transport.key`. + - New CLI command :program:`mix-models transport export-price`. + - Bump Codelist=IIASA_ECE:CL_TRANSPORT_SCENARIO to version 1.4.0. + + - Add additional exogenous price trajectories. + - Bump :attr:`.CL_SCENARIO.base_url` to v6.5 of the ScenarioMIP scenarios. + + - Add and apply :data:`.transport.material.OUTPUT_SHARE`. + - Improve reporting output (:mod:`.transport.report`): + align IAMC ‘variable’ codes with common definitions. + - New module :mod:`.transport.vehicle` for operational parameters + (capacity factor, technical lifetime) and stock of vehicles, + both passenger and freight. + + - Transfer and generalize stock-related calculations from :mod:`.transport.ldv`. + - Remove module :py:`transport.stock`. + + - New function :func:`.transport.workflow.add_steps` adds + transport-related steps to any Workflow + given a Code with :class:`.ScenarioCodeAnnotations`. + +- Improve :doc:`/water/index`: + + - Add reduced basin filtering with :program:`--reduced-basin` + and demand/supply stress-based selection via :program:`--basin-selection stress` + (:pull:`432`, :issue:`414`). + - Fix parameter bugs and refactor cooling (:pull:`405`): + infrastructure M1/Mf mode fixes, + regional average shares for cooling allocation, + water supply level hierarchy corrections, + and test suite improvements. v2026.1.15 ========== @@ -75,7 +146,7 @@ Projects and model variants --------------------------- - Add :doc:`/project/circeular` code list :class:`~.circeular.structure.CL_TRANSPORT_SCENARIO` (:pull:`447`). -- Improve :mod:`.model.transport` (:pull:`447`). +- Improve :doc:`/transport/index` (:pull:`447`). - Add :meth:`Config.use_modules <.transport.config.Config.use_modules>`. - Bump Codelist=IIASA_ECE:CL_TRANSPORT_SCENARIO to version 1.3.0. @@ -119,7 +190,7 @@ v2025.10.31 to read input data from distinct files according to scenario label. - New :class:`LoadFactorLDV`, replacing :py:`load_factor_ldv` and allowing a distinct file according to scenario label. - - New submodule :mod:`~.transport.stock` and input data flow :data:`.stock_cap`. + - New submodule :py:`transport.stock` and input data flow :data:`.stock_cap`. - Add technology dimension to :data:`.elasticity_f`. - Document :class:`.ScenarioCodeAnnotations`.