Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 109 additions & 0 deletions doc/api/tools-impacts.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
.. currentmodule:: message_ix_models.tools.impacts

Climate impact prediction toolkit (:mod:`.tools.impacts`)
**********************************************************

.. contents::
:local:

Overview
========

:mod:`.tools.impacts` provides GMT-to-impact prediction via RIME regional
emulators, with helpers for assembling GMT ensembles from MAGICC output and
resampling sparse calibration inputs onto MESSAGE model years.

The toolkit is domain-agnostic: it predicts at native emulator resolution and
returns NumPy arrays. Domain modules under :mod:`.model.buildings`,
:mod:`.model.water.data`, and :mod:`.project.sparccle` own the transformation
to MESSAGE-compatible parameters.

RIME prediction is an adapted reimplementation of the GWL-binned
nearest-neighbor lookup from Byers et al. (2025), *Environ. Res.: Climate*
**4** 035011, `doi:10.1088/2752-5295/adee3d
<https://doi.org/10.1088/2752-5295/adee3d>`_;
upstream code at `iiasa/rime <https://github.com/iiasa/rime>`_ (GPL-3.0).
See :mod:`.tools.impacts.rime` for full attribution.

Usage
=====

.. code-block:: python

import numpy as np

from message_ix_models.tools.impacts import (
GmtArray,
gmt_ensemble,
gmt_expectation,
load_magicc_gmt,
predict_rime,
)

# Read a MAGICC climate-assessment Excel run-ensemble
gmt = load_magicc_gmt("/path/to/magicc_output_dir", n_runs=600)
# gmt.values: (n_runs, n_years); gmt.years: (n_years,)

# Single-trajectory prediction (ensemble-mean GMT)
mean = gmt_expectation(gmt) # values shape (n_years,)
qtot_1d = predict_rime(
mean.values,
"rime_regionarray_qtot_mean_CWatM_annual_window11.nc",
"qtot_mean",
) # (157, n_years)

# Ensemble prediction with mean reduction
qtot_2d = predict_rime(
gmt.values,
"rime_regionarray_qtot_mean_CWatM_annual_window11.nc",
"qtot_mean",
aggregate="mean",
) # (157, n_years)

RIME emulators (:mod:`.tools.impacts.rime`)
===========================================

RIME datasets use GWL-binned nearest-neighbor lookup. Each emulator covers a
GMT range of 0.6–7.4 °C (ISIMIP3b-derived). Values outside this range return
NaN; values below the minimum are clipped with skewed Beta(2, 5) noise via
:func:`.clip_gmt`.

For ensemble input ``(n_runs, n_years)``, :func:`.predict_rime` returns a
Monte Carlo estimate of ``E_{P(GMT)}[f(GMT)]`` when called with
``aggregate="mean"``. This is meaningful only when the emulator response is
approximately linear over the GMT range present in the ensemble; for
single-run input on a non-linear emulator it raises. Use
:func:`.check_emulator_linearity` to probe a dataset before relying on
ensemble means. :func:`.open_rime_dataset` opens a packaged NetCDF by
filename and caches the result.

Climate inputs (:mod:`.tools.impacts.climate`)
===============================================

:func:`.load_magicc_gmt` reads a ``*_IAMC_climateassessment.xlsx`` file and
returns a :class:`.GmtArray` of per-run GSAT trajectories.
:func:`.gmt_ensemble` builds a :class:`.GmtArray` from any wide DataFrame with
year columns. :func:`.gmt_expectation` reduces an ensemble to its per-year
``nanmean``. :func:`.persist_gmt_mean` writes the ensemble-mean trajectory
onto a scenario as a ``Physical Climate Impact|Surface Temperature (GSAT)``
timeseries.

Temporal resampling (:mod:`.tools.impacts.temporal`)
=====================================================

:func:`.sample_to_model_years` maps annual or sparse calibration inputs to
MESSAGE model years via ``method="point"`` (lookup), ``"average"`` (period
mean), or ``"interpolate"`` (linear infill between sparse anchors with
forward-fill beyond the last input).

Code reference
==============

.. currentmodule:: message_ix_models.tools

.. autosummary::
:toctree: _autosummary
:template: autosummary-module.rst
:recursive:

impacts
1 change: 1 addition & 0 deletions doc/api/tools.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ On other pages:

- :doc:`tools-bilateralize`
- :doc:`tools-costs`
- :doc:`tools-impacts`

On this page:

Expand Down
125 changes: 125 additions & 0 deletions doc/impacts/index.rst
Comment thread
Wegatriespython marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
Physical impacts
****************

.. contents::
:local:

Architecture
============

Physical-impact support is split across three layers. Generic prediction
utilities live in :mod:`message_ix_models.tools.impacts`. They evaluate
packaged RIME emulators and return impact arrays at the emulator's native
resolution. The current file reader ingests MAGICC ensembles in the
``climate-assessment`` workbook format; the downstream prediction utilities
only require an ensemble realization of global mean temperature and can be
fed by other simple climate models through :class:`~message_ix_models.tools.impacts.GmtArray`.

Domain application modules translate those predictions into MESSAGE scenario
edits. The current application modules are
:mod:`message_ix_models.model.buildings.impacts` for buildings demand and
:mod:`message_ix_models.model.water.data.cooling_impacts` for thermoelectric
cooling. Basin-level water transformations live in
:mod:`message_ix_models.model.water.data.impacts`.

Project workflows, such as :mod:`message_ix_models.project.sparccle`, choose
starter scenarios, input files, variants, and clone names. They do not define
the domain-specific MESSAGE parameters used for an impact.

Buildings
=========

Buildings impacts replace the climate-sensitive part of aggregate
``rc_spec`` and ``rc_therm`` demand. The replacement demand is calibrated in
three layers.

The correction-coefficient files contain archetype-level ``gamma`` terms.
STURM encodes stock turnover, access, cooling-area, and other internal
dynamics. RIME/CHILLED provides climate-responsive energy intensity. Energy
intensity multiplied by floor area does not by itself reproduce the STURM
time series, so ``gamma`` is constructed so the reference-temperature product
matches STURM baseline energy demand:

.. math::

\mathrm{raw}_{r,a,t} =
\gamma_{r,a,t} \cdot EI_{r,a}(GSAT_t) \cdot F_{r,a,t}

where ``F`` is STURM floor area. In the packaged CSV files, ``gamma`` is the
``correction_coeff`` column.

The ``theta`` files are a second calibration layer. The raw STURM trajectory
is not the same object as the calibrated residential/commercial demand that
enters MESSAGE. For each SSP, ``theta`` scales the node-year aggregate so the
Comment thread
Wegatriespython marked this conversation as resolved.
reference-GWL result matches the calibrated buildings heating and cooling
demand from the Shared Socioeconomic Pathways 2023 / WP-RC demand workflow.

The ``rc_sector_fractions`` files identify the residential and commercial
buildings components already present in aggregate ``rc_spec`` and
``rc_therm`` so they can be removed before the replacement demand is added.

Packaged SSP coverage differs across the calibration layers. ``theta`` and
``rc_sector_fractions`` ship for SSP1, SSP2, and SSP3. ``gamma`` (the
``correction_coefficients`` files) and the STURM floor-area projections are
SSP2-only, pending additional STURM runs. Buildings impacts under SSP1 or
SSP3 therefore use SSP-specific ``theta`` and ``rc_sector_fractions`` on top
of an SSP2 STURM baseline and SSP2 ``gamma``.

Thermoelectric cooling
======================

Thermoelectric cooling impacts use
:file:`message_ix_models/data/impacts/rime/r12_thermoelectric_gwl.nc`. The
file is R12-coded and has two cooling categories: ``wet`` for freshwater
once-through and closed-loop cooling, and ``dry`` for air cooling. Ratios are
computed relative to the 1.0 °C GWL capacity factor.

Wet and dry cooling use different MESSAGE-side levers. Wet cooling limits
freshwater-cooled activity, so the application writes relation bounds on
freshwater once-through and closed-loop cooling technologies. Dry cooling
reduces air-cooled plant performance, so the application derates
``capacity_factor`` rows for ``__air`` technologies. Saline cooling is not
represented in the packaged RIME cooling dataset and is left unchanged.

The wet-cooling relation is constructed so that, given the regional freshwater
share, total freshwater-cooled activity from a parent power technology cannot
exceed the warming-impaired capacity factor times that parent's activity.
Dry cooling is represented directly as a multiplicative derating of air-cooled
capacity factors.

The impact kernels are based on:

- Wet cooling: Li et al. (2025), "Global hydroclimatic risks and strategic
decommissioning pathways for thermal power units." *Nature Sustainability*.
doi:10.1038/s41893-025-01692-9
- Dry cooling: Qin et al. (2023), "Global assessment of the carbon-water
tradeoff of dry cooling for thermal power generation." *Nature Water*.
doi:10.1038/s44221-023-00120-6

Water availability
==================

Basin-level water impacts use RIME datasets at native 157-basin resolution.
The packaged water datasets store GWL-indexed conditional summaries for
``qtot_mean`` and ``qr`` from CWatM ISIMIP3b realizations. The stored
variables are the expected value plus selected spread summaries
(``std``, ``p10``, ``p50``, and ``p90``). The source realizations span five GCMs
(``gfdl-esm4``, ``ipsl-cm6a-lr``, ``mpi-esm1-2-hr``, ``mri-esm2-0``,
``ukesm1-0-ll``) and three SSP-RCP climate scenarios (``ssp126``,
``ssp370``, ``ssp585``). The future CWatM runs use
``2015soc-from-histsoc`` direct human forcing, so runs differ by climate
forcing rather than by changing socioeconomic water-use assumptions. The
RIME datasets are binned with an 11-year centered time window.

The water application expands those predictions to the MESSAGE basin-region
rows used by the water module, including transboundary basin splits. This is
also a domain application layer: :mod:`message_ix_models.tools.impacts`
predicts emulator values, while :mod:`message_ix_models.model.water.data.impacts`
owns the basin mapping and water-specific output shapes.

The current transform preserves the RIME prediction values while changing the
spatial index from native emulator basins to MESSAGE basin-region rows. Future
water-CID application work is expected to add the MESSAGE-side hydrology
semantics on top of that mapping, including groundwater-share construction,
km3-to-MCM conversion, and the sign convention needed when water availability
is represented through MESSAGE demand-like parameters.
2 changes: 2 additions & 0 deletions doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ Other submodules are documented on their respective pages:
api/tools
api/tools-bilateralize
api/tools-costs
api/tools-impacts
api/tools-messagev
api/data-sources
api/workflow
Expand All @@ -117,6 +118,7 @@ Other submodules are documented on their respective pages:
:caption: Model variants

buildings/index
impacts/index
material/index
transport/index
water/index
Expand Down
68 changes: 67 additions & 1 deletion doc/project/sparccle.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,73 @@
SPARCCLE
********

Socioeconomic Pathways, Adaptation and Resilience to Changing CLimate in Europe
"Socioeconomic Pathways, Adaptation and Resilience to Changing CLimate in Europe"

- Project lead: :gh-user:`byersiiasa`
- Lead modeler: :gh-user:`adrivinca`

Overview
========

The SPARCCLE protocol combines socioeconomic starter scenarios with
climate-impact variants and project-specific clone naming.

Economic impacts
================

Economic and GDP-based impacts are part of the broader SPARCCLE protocol.
They are not implemented by the physical-impact workflow described below.

Physical climate impacts
========================

The physical-impact workflow applies climate-impact damage drivers to solved
MESSAGE starter scenarios. It reads starter-specific GSAT ensembles, evaluates
the packaged RIME impact emulators, and writes buildings and cooling impacts
to project-side scenario clones.

Prerequisites
=============

Each starter needs a MAGICC ``*_IAMC_climateassessment.xlsx`` file in the
directory configured by
:file:`message_ix_models/project/sparccle/scenario_config.yaml`. Buildings
impacts operate on calibrated ``rc_spec`` and ``rc_therm`` demand. Cooling
impacts require the water-cooling module; the workflow builds this prep clone
before applying cooling CIDs.

SSP coverage
============

Buildings calibration data ships for SSP1, SSP2, and SSP3. Cooling impacts
do not depend on SSP-specific buildings calibration.

Running the pipeline
====================

The CLI builds a workflow graph from
:file:`message_ix_models/project/sparccle/scenario_config.yaml` and runs
the requested target step:

.. code-block:: bash

# Buildings only
mix-models sparccle run "<MODEL>/<SCENARIO> CI_b" --go

# Cooling only (wet + dry, on a cooling-built prep clone)
mix-models sparccle run "<MODEL>/<SCENARIO> CI_p" --go

# Combined buildings + cooling
mix-models sparccle run "<MODEL>/<SCENARIO> CI_bp" --go

Each target writes a suffixed clone:

- ``<scenario>_CI_b`` — buildings demand replaced under
``Final Energy|Residential and Commercial|{Cooling,Heating}``.
- ``<scenario>_cooling_CI_p`` — wet-cooling activity bounds and dry-cooling
capacity-factor derating applied; ratios persisted as
``Physical Climate Impact|Thermoelectric Cooling|*`` timeseries.
- ``<scenario>_cooling_CI_bp`` — both, in one workflow step.

See :doc:`/impacts/index` for the impact application modules and
:doc:`/api/tools-impacts` for the underlying GMT-to-impact toolkit.
2 changes: 2 additions & 0 deletions doc/whatsnew.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ Next release
- Adjust :mod:`.project.ssp.transport` (:pull:`485`):
- Add stub of :func:`.scenariomip.workflow.generate` (:pull:`394`).
- New guide on HOWTO :doc:`/howto/report` (:pull:`488`).
- New :mod:`.tools.impacts` library and :mod:`.project.sparccle` consumer
for SPARCCLE physical-impact scenarios (:pull:`479`).

v2026.4.17
==========
Expand Down
1 change: 1 addition & 0 deletions message_ix_models/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ def _log_threads(k: int, n: int):
"message_ix_models.project.circeular.cli",
"message_ix_models.project.edits.cli",
"message_ix_models.project.navigate.cli",
"message_ix_models.project.sparccle.cli",
"message_ix_models.project.ssp.cli",
"message_ix_models.report.cli",
"message_ix_models.model.material.cli",
Expand Down
Loading
Loading