-
Notifications
You must be signed in to change notification settings - Fork 35
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'nexus-upd' of https://github.com/iiasa/message-ix-models …
…into nexus-upd
- Loading branch information
Showing
12 changed files
with
327 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,13 @@ | ||
comment: | ||
layout: "diff, files" | ||
behavior: once | ||
|
||
coverage: | ||
precision: 1 | ||
status: | ||
project: | ||
default: | ||
if_ci_failed: success | ||
patch: | ||
default: | ||
if_ci_failed: success |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
# Converted from P:/ene.model/MACRO/python/R12-CHN-5y_macro_data_NGFS_w_rc_ind_adj_mat.xlsx | ||
# | ||
# Units: dimensionless | ||
node,value | ||
R12_AFR,3.0 | ||
R12_RCPA,3.0 | ||
R12_EEU,3.0 | ||
R12_FSU,3.0 | ||
R12_LAM,3.0 | ||
R12_MEA,3.0 | ||
R12_NAM,2.4 | ||
R12_PAO,2.8 | ||
R12_PAS,3.0 | ||
R12_SAS,3.0 | ||
R12_WEU,2.8 | ||
R12_CHN,3.0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
"""Tools for calibrating MACRO for MESSAGEix-GLOBIOM. | ||
See :doc:`message-ix:macro` for *general* documentation on MACRO and MESSAGE-MACRO. This | ||
module contains tools specifically for using these models with MESSAGEix-GLOBIOM. | ||
""" | ||
import logging | ||
from functools import lru_cache | ||
from itertools import product | ||
from pathlib import Path | ||
from typing import TYPE_CHECKING, List, Literal, Mapping, Optional, Union | ||
|
||
import pandas as pd | ||
|
||
from message_ix_models.model.bare import get_spec | ||
from message_ix_models.util import nodes_ex_world | ||
|
||
if TYPE_CHECKING: # pragma: no cover | ||
from sdmx.model.v21 import Code | ||
|
||
from message_ix_models import Context | ||
|
||
log = logging.getLogger(__name__) | ||
|
||
#: Default set of commodities to include in :func:`generate`. | ||
COMMODITY = ["i_therm", "i_spec", "rc_spec", "rc_therm", "transport"] | ||
|
||
|
||
def generate( | ||
parameter: Literal["aeei", "config", "depr", "drate", "lotol"], | ||
context: "Context", | ||
commodities: Union[List[str], List["Code"]] = COMMODITY, | ||
value: Optional[float] = None, | ||
) -> pd.DataFrame: | ||
"""Generate uniform data for one :mod:`message_ix.macro` `parameter`. | ||
:meth:`message_ix.Scenario.add_macro` expects as its `data` parameter a | ||
:class:`dict` that maps certain MACRO parameter names (or the special name "config") | ||
to :class:`.pandas.DataFrame`. This function generates data for those data frames. | ||
For the particular dimensions, generate automatically includes: | ||
- "node": All nodes in the node code list given by :func:`.nodes_ex_world`, for the | ||
node list indicated by :attr:`.model.Config.regions`. | ||
- "year": All periods from the period *before* the first model year. | ||
- "commodity": The elements of `commodities`. | ||
- "sector": If each entry of `commodities` is a :class:`.Code` and has an annotation | ||
with id="macro-sector", the value of that annotation. Otherwise, the same as | ||
`commodity`. | ||
`value` supplies the parameter value, which is the same for all observations. | ||
The labels level="useful" and unit="-" are fixed. | ||
Parameters | ||
---------- | ||
parameter : str | ||
MACRO parameter for which to generate data. | ||
context | ||
Used with :func:`.bare.get_spec`. | ||
commodities : list of str or Code | ||
Commodities to include in the MESSAGE-MACRO linkage. | ||
value : float | ||
Parameter value. | ||
Returns | ||
------- | ||
pandas.DataFrame | ||
The columns vary according to `parameter`: | ||
- "aeei": node, sector, year, value, unit. | ||
- "depr", "drate", or "lotol": node, value, unit. | ||
- "config": node, sector, commodity, level, year. | ||
""" | ||
spec = get_spec(context) | ||
|
||
if isinstance(commodities[0], str): | ||
c_codes = spec.add.set["commodity"] | ||
else: | ||
c_codes = commodities | ||
|
||
@lru_cache | ||
def _sector(commodity: str) -> str: | ||
try: | ||
idx = c_codes.index(commodity) | ||
return str(c_codes[idx].get_annotation(id="macro-sector").text) | ||
except (KeyError, ValueError) as e: | ||
log.info(e) | ||
return str(commodity) | ||
|
||
# AEEI data must begin from the period before the first model period | ||
y0_index = spec.add.set["year"].index(spec.add.y0) | ||
iterables = dict( | ||
c_s=zip( # Paired commodity and sector | ||
map(str, commodities), map(_sector, commodities) | ||
), | ||
level=["useful"], | ||
node=nodes_ex_world(spec.add.N), | ||
sector=map(_sector, commodities), | ||
year=spec.add.set["year"][y0_index:], | ||
) | ||
|
||
if parameter == "aeei": | ||
dims = ["node", "year", "sector"] | ||
iterables.update(year=spec.add.set["year"][y0_index - 1 :]) | ||
elif parameter == "config": | ||
dims = ["node", "c_s", "level", "year"] | ||
assert value is None | ||
elif parameter in ("depr", "drate", "lotol"): | ||
dims = ["node"] | ||
else: | ||
raise NotImplementedError(f"generate(…) for MACRO parameter {parameter!r}") | ||
|
||
result = pd.DataFrame( | ||
[tuple(values) for values in product(*[iterables[d] for d in dims])], | ||
columns=dims, | ||
) | ||
|
||
if parameter == "config": | ||
return pd.concat( | ||
[ | ||
result.drop("c_s", axis=1), | ||
pd.DataFrame(result["c_s"].tolist(), columns=["commodity", "sector"]), | ||
], | ||
axis=1, | ||
) | ||
else: | ||
return result.assign(value=value, unit="-") | ||
|
||
|
||
def load(base_path: Path) -> Mapping[str, pd.DataFrame]: | ||
"""Load MACRO data from CSV files. | ||
The function reads files in the simple/long CSV format understood by | ||
:func:`genno.computations.load_file`. For use with | ||
:meth:`~message_ix.Scenario.add_macro`, the dimension names should be given in full, | ||
for instance "node" or "sector". | ||
Parameters | ||
---------- | ||
base_path : pathlib.Path | ||
Directory containing zero or more CSV files. | ||
Returns | ||
------- | ||
dict of (str -> pandas.DataFrame) | ||
Mapping from MACRO calibration parameter names to data; one entry for each file | ||
in `base_path`. | ||
""" | ||
from genno.computations import load_file | ||
|
||
result = {} | ||
for filename in base_path.glob("*.csv"): | ||
name = filename.stem | ||
|
||
q = load_file(filename, name=name) | ||
|
||
result[name] = ( | ||
q.to_frame() | ||
.reset_index() | ||
.rename(columns={name: "value"}) | ||
.assign(unit=f"{q.units:~}" or "-") | ||
) | ||
|
||
return result |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import pandas as pd | ||
import pandas.testing as pdt | ||
import pytest | ||
from sdmx.model import Annotation, Code | ||
|
||
from message_ix_models.model.macro import generate, load | ||
from message_ix_models.util import package_data_path | ||
|
||
|
||
@pytest.mark.parametrize( | ||
"parameter, value", | ||
[ | ||
("aeei", 1.0), | ||
("config", None), | ||
("depr", 1.0), | ||
("drate", 1.0), | ||
("lotol", 1.0), | ||
pytest.param("foo", 1.0, marks=pytest.mark.xfail(raises=NotImplementedError)), | ||
], | ||
) | ||
def test_generate0(test_context, parameter, value): | ||
result = generate(parameter, test_context, value=value) | ||
|
||
assert not result.isna().any(axis=None) | ||
|
||
|
||
def test_generate1(test_context): | ||
commodities = [ | ||
Code(id="foo", annotations=[Annotation(id="macro-sector", text="BAR")]), | ||
Code(id="baz", annotations=[Annotation(id="macro-sector", text="QUX")]), | ||
] | ||
|
||
result = generate("config", test_context, commodities) | ||
|
||
assert {"foo", "baz"} == set(result["commodity"].unique()) | ||
|
||
# Only the identified sectors appear | ||
assert {"BAR", "QUX"} == set(result["sector"].unique()) | ||
|
||
# Only 2 unique (commodity, sector) combinations appear | ||
assert 2 == len(result[["commodity", "sector"]].drop_duplicates()) | ||
|
||
|
||
def test_load(test_context): | ||
result = load(package_data_path("test", "macro")) | ||
assert {"kgdp"} == set(result.keys()) | ||
pdt.assert_index_equal(pd.Index(["node", "value", "unit"]), result["kgdp"].columns) | ||
assert not result["kgdp"].isna().any(axis=None) |
Oops, something went wrong.