Python API

The application programming interface (API) for MESSAGEix model developers is implemented in Python. The full API is also available from R; see Usage in R via reticulate.

ixmp package

ixmp provides three classes. These are fully described by the ixmp documentation, which is cross-linked from many places in the MESSAGEix documentation.

Platform([name, backend])

Instance of the modeling platform.

TimeSeries(mp, model, scenario[, version, ...])

Collection of data in time series format.

Scenario(mp, model, scenario[, version, ...])

Collection of model-related data.

ixmp also provides some utility classes and methods:

ixmp.config

Configuration for ixmp.

ixmp.model.MODELS

Mapping from names to available models.

ixmp.model.get_model(name, **model_options)

Return a model for name (or the default) with model_options.

message_ix package

MESSAGEix models are created using the message_ix.Scenario class. Several utility methods are also provided in the module message_ix.util.

class message_ix.Scenario(mp, model, scenario=None, version=None, annotation=None, scheme=None, **kwargs)[source]

Bases: Scenario

MESSAGEix Scenario.

See ixmp.TimeSeries for the meaning of arguments mp, model, scenario, version, and annotation. The scheme of a newly-created Scenario is always “MESSAGE”.

This class extends ixmp.Scenario and ixmp.TimeSeries and inherits of the methods of those classes, shown below. message_ix.Scenario adds or overrides the following methods specific to MESSAGEix:

add_cat(name, cat, keys[, is_unique])

Map elements from keys to category cat within set name.

add_horizon([year, firstmodelyear, data])

Set the scenario time horizon via year and related categories.

add_macro(data[, scenario, check_convergence])

Add MACRO parametrization to the Scenario and calibrate.

add_spatial_sets(data)

Add sets related to spatial dimensions of the model.

cat(name, cat)

Return a list of all set elements mapped to a category.

cat_list(name)

Return a list of all categories for a mapping set.

clone(*args, **kwargs)

Clone the current scenario and return the clone.

equ(name[, filters])

Return equation data.

firstmodelyear

The first model year of the scenario.

par(name[, filters])

Return parameter data.

rename(name, mapping[, keep])

Rename elements in the set name and transform data indexed by old name(s).

set(name[, filters])

Return elements of a set.

solve([model, solve_options])

Solve MESSAGE or MESSAGE-MACRO for the Scenario.

var(name[, filters])

Return variable data.

vintage_and_active_years([ya_args, tl_only])

Return matched pairs of vintage and active periods for use in data input.

y0

Alias for firstmodelyear.

years_active(node, tec, yr_vtg)

Return periods in which tec hnology of yr_vtg can be active in node.

ya(node, tec, yr_vtg)

Alias for years_active().

yv_ya([ya_args, tl_only])

Alias for vintage_and_active_years().

Inherited from ixmp.Scenario:

Changed in version 3.0: read_excel() and to_excel() are now methods of ixmp.Scenario, but continue to work with message_ix.Scenario.

add_par(name[, key_or_data, value, unit, ...])

Set the values of a parameter.

add_set(name, key[, comment])

Add elements to an existing set.

change_scalar(name, val, unit[, comment])

Set the value and unit of a scalar.

has_item(name[, item_type])

Check whether the Scenario has an item name of item_type.

has_solution()

Return True if the Scenario contains model solution data.

idx_names(name)

Return the list of index names for an item (set, par, var, equ).

idx_sets(name)

Return the list of index sets for an item (set, par, var, equ).

init_item(item_type, name[, idx_sets, idx_names])

Initialize a new item name of type item_type.

init_scalar(name, val, unit[, comment])

Initialize a new scalar and set its value.

items([type, filters, indexed_by, par_data])

Iterate over model data items.

list_items(item_type[, indexed_by])

List all defined items of type item_type.

load_scenario_data()

Load all Scenario data into memory.

read_excel(path[, add_units, init_items, ...])

Read a Microsoft Excel file into the Scenario.

remove_par(name[, key])

Remove parameter values or an entire parameter.

remove_set(name[, key])

Delete set elements or an entire set.

remove_solution([first_model_year])

Remove the solution from the scenario.

scalar(name)

Return the value and unit of a scalar.

to_excel(path[, items, filters, max_row])

Write Scenario to a Microsoft Excel file.

Inherited from ixmp.TimeSeries:

add_geodata(df)

Add geodata.

add_timeseries(df[, meta, year_lim])

Add time series data.

check_out([timeseries_only])

Check out the Scenario.

commit(comment)

Commit all changed data to the database.

discard_changes()

Discard all changes and reload from the database.

get_geodata()

Fetch geodata and return it as dataframe.

get_meta([name])

Get Metadata for this object.

is_default()

Return True if the version is the default version.

last_update()

Get the timestamp of the last update/edit of this TimeSeries.

preload_timeseries()

Preload timeseries data to in-memory cache.

read_file(path[, firstyear, lastyear])

Read time series data from a CSV or Microsoft Excel file.

remove_geodata(df)

Remove geodata from the TimeSeries instance.

remove_timeseries(df)

Remove time series data.

run_id()

Get the run id of this TimeSeries.

set_as_default()

Set the current version as the default.

set_meta(name_or_dict[, value])

Set Metadata for this object.

timeseries([region, variable, unit, year, ...])

Retrieve time series data.

transact([message, condition, discard_on_error])

Context manager to wrap code in a 'transaction'.

url

URL fragment for the TimeSeries.

add_macro(data: Mapping | PathLike, scenario=None, check_convergence=True, **kwargs)[source]

Add MACRO parametrization to the Scenario and calibrate.

Note

This method causes existing MACRO calibration data to be overwritten.

Parameters:
  • data (dict or os.PathLike) – Dictionary of required data for MACRO calibration (mapping str to pandas.DataFrame) or path to a file containing the data.

  • scenario (str, optional) – Scenario name for calibrated Scenario. If not given, the name of scenario with “ macro” appended.

  • check_convergence (bool, optional) – Confirm that the calibrated scenario solves in one iteration.

  • kwargs – Solve options when solving the calibrated scenario.

Returns:

A clone of scenario with MACRO calibrated.

Return type:

Scenario

Warning

MACRO support via add_macro() is experimental in message_ix 3.0 and may not function as expected on all possible MESSAGEix models. See a list of known and pending issues on GitHub.

add_cat(name, cat, keys, is_unique=False)[source]

Map elements from keys to category cat within set name.

Parameters:
  • name (str) – Name of the set.

  • cat (str) – Name of the category.

  • keys (str or list of str) – Element keys to be added to the category mapping.

  • is_unique (bool, optional) – If True, then cat must have only one element. An exception is raised if cat already has an element, or if len(keys) > 1.

add_geodata(df: DataFrame) None[source]

Add geodata.

Parameters:

df (pandas.DataFrame) –

Data to add. df must have the following columns:

  • region

  • variable

  • subannual

  • unit

  • year

  • value

  • meta

add_horizon(year: Iterable[int] = [], firstmodelyear: int | None = None, data: dict | None = None) None[source]

Set the scenario time horizon via year and related categories.

add_horizon() acts like add_set("year", ...), except with additional conveniences:

  • The firstmodelyear argument can be used to set the first period handled by the MESSAGE optimization. This is equivalent to:

    scenario.add_cat("year", "firstmodelyear", ..., is_unique=True)
    
  • Parameter duration_period is assigned values based on year: The duration of periods is calculated as the interval between successive year elements, and the duration of the first period is set to value that appears most frequently.

See Years, periods, and time slices for a detailed terminology of years and periods in message_ix.

Parameters:
  • year (list of int) – The set of periods.

  • firstmodelyear (int, optional) – First period for the model solution. If not given, the first entry of year is used.

  • data (dict) –

    Deprecated since version 3.1: The “year” key corresponds to year and is required. A “firstmodelyear” key corresponds to firstmodelyear and is optional.

Raises:

ValueError – If the year set of the Scenario is already populated. Changing the time periods of an existing Scenario can entail complex adjustments to data. For this purpose, adjust each set and parameter individually, or see tools.add_year.

Examples

>>> s = message_ix.Scenario()
# The following are equivalent
>>> s.add_horizon(year=[2020, 2030, 2040], firstmodelyear=2020)
>>> s.add_horizon([2020, 2030, 2040], 2020)
>>> s.add_horizon([2020, 2030, 2040])
add_par(name: str, key_or_data: int | str | Sequence[int | str] | Dict | DataFrame | None = None, value=None, unit: str | None = None, comment: str | None = None) None[source]

Set the values of a parameter.

Parameters:
add_set(name: str, key: int | str | Sequence[int | str] | Dict | DataFrame, comment: str | Sequence[str] | None = None) None[source]

Add elements to an existing set.

Parameters:
Raises:
add_spatial_sets(data)[source]

Add sets related to spatial dimensions of the model.

Parameters:

data (dict) –

Mapping of levelmember. Each member may be:

  • A single label for elements.

  • An iterable of labels for elements.

  • A recursive dict following the same convention, defining sub-levels and their members.

Examples

>>> s = message_ix.Scenario()
>>> s.add_spatial_sets({'country': 'Austria'})
>>> s.add_spatial_sets({'country': ['Austria', 'Germany']})
>>> s.add_spatial_sets({'country': {
...     'Austria': {'state': ['Vienna', 'Lower Austria']}}})
add_timeseries(df: DataFrame, meta: bool = False, year_lim: Tuple[int | None, int | None] = (None, None)) None[source]

Add time series data.

Parameters:
  • df (pandas.DataFrame) –

    Data to add. df must have the following columns:

    • region or node

    • variable

    • unit

    Additional column names may be either of:

    • year and value—long, or ‘tabular’, format.

    • one or more specific years—wide, or ‘IAMC’ format.

    To support subannual temporal resolution of timeseries data, a column subannual is optional in df. The entries in this column must have been defined in the Platform instance using add_timeslice() beforehand. If no column subannual is included in df, the data is assumed to contain yearly values. See timeslices() for a detailed description of the feature.

  • meta (bool, optional) – If True, store df as metadata. Metadata is treated specially when Scenario.clone() is called for Scenarios created with scheme='MESSAGE'.

  • year_lim (tuple, optional) – Respectively, earliest and latest years to add from df; data for other years is ignored.

cat(name, cat)[source]

Return a list of all set elements mapped to a category.

Parameters:
  • name (str) – Name of the set.

  • cat (str) – Name of the category.

Returns:

int is returned if name is ‘year’.

Return type:

list of str or list of int

cat_list(name)[source]

Return a list of all categories for a mapping set.

Parameters:

name (str) – Name of the set.

change_scalar(name: str, val: Real, unit: str, comment: str | None = None) None[source]

Set the value and unit of a scalar.

Parameters:
  • name (str) – Name of the scalar.

  • val (float or int) – New value of the scalar.

  • unit (str) – New unit of the scalar.

  • comment (str, optional) – Description of the change.

check_out(timeseries_only: bool = False) None[source]

Check out the Scenario.

Raises:

ValueError – If has_solution() is True.

See also

TimeSeries.check_out, util.maybe_check_out

clone(*args, **kwargs)[source]

Clone the current scenario and return the clone.

See ixmp.Scenario.clone() for other parameters.

Parameters:
  • keep_solution (bool, optional) – If True, include all time series and model solution (variable and equation) data from the current Scenario in the clone. Otherwise, only time series data marked as meta=True (see ixmp.TimeSeries.add_timeseries()) or prior to first_model_year (see ixmp.TimeSeries.add_timeseries()) are cloned.

  • shift_first_model_year (int, optional) – If given, certain values of the model solution are transferred to correspondin gparameters historical_*, parameter resource_volume is updated, and the first_model_year is shifted. The solution is then discarded (remove_solution()).

commit(comment: str) None[source]

Commit all changed data to the database.

If the TimeSeries was newly created (with version='new'), version is updated with a new version number assigned by the backend. Otherwise, commit() does not change the version.

Parameters:

comment (str) – Description of the changes being committed.

See also

util.maybe_commit

delete_meta(*args, **kwargs) None[source]

Remove Metadata for this object.

Deprecated since version 3.1: Use remove_meta().

Parameters:

name (str or list of str) – Either single metadata name/identifier, or list of names.

discard_changes() None[source]

Discard all changes and reload from the database.

equ(name, filters=None)[source]

Return equation data.

Same as ixmp.Scenario.equ(), except columns indexed by the MESSAGEix set year are returned with int dtype.

Parameters:
  • name (str) – Name of the equation.

  • filters (dict, optional) – Filters for the dimensions of the equation. See ixmp.Scenario.equ().

Returns:

Filtered elements of the equation.

Return type:

pandas.DataFrame

equ_list(indexed_by: str | None = None) List[str][source]
property firstmodelyear[source]

The first model year of the scenario.

Return type:

int

classmethod from_url(url: str, errors: Literal['warn', 'raise'] = 'warn') Tuple[TimeSeries | None, Platform][source]

Instantiate a TimeSeries (or Scenario) given an ixmp:// URL.

The following are equivalent:

from ixmp import Platform, TimeSeries
mp = Platform(name='example')
scen = TimeSeries(mp 'model', 'scenario', version=42)

and:

from ixmp import TimeSeries
scen, mp = TimeSeries.from_url('ixmp://example/model/scenario#42')
Parameters:
  • url (str) – See parse_url.

  • errors ('warn' or 'raise') – If ‘warn’, a failure to load the TimeSeries is logged as a warning, and the platform is still returned. If ‘raise’, the exception is raised.

Returns:

with 2 elements:

  • The TimeSeries referenced by the url.

  • The Platform referenced by the url, on which the first element is stored.

Return type:

tuple

get_geodata() DataFrame[source]

Fetch geodata and return it as dataframe.

Returns:

Specified data.

Return type:

pandas.DataFrame

get_meta(name: str | None = None)[source]

Get Metadata for this object.

Metadata with the given name, attached to this (model name, scenario name, version), is retrieved.

Parameters:

name (str, optional) – Metadata name/identifier.

has_equ(name: str, *, item_type=<ItemType.EQU: 16>) bool[source]
has_item(name: str, item_type=<ItemType.MODEL: 30>) bool[source]

Check whether the Scenario has an item name of item_type.

In general, user code should call one of has_equ(), has_par(), has_set(), or has_var() instead of calling this method directly.

Returns:

  • True – if the Scenario contains an item of item_type with name name.

  • False – otherwise

See also

items

has_par(name: str, *, item_type=<ItemType.PAR: 4>) bool[source]
has_set(name: str, *, item_type=<ItemType.SET: 2>) bool[source]
has_solution() bool[source]

Return True if the Scenario contains model solution data.

has_var(name: str, *, item_type=<ItemType.VAR: 8>) bool[source]
idx_names(name: str) List[str][source]

Return the list of index names for an item (set, par, var, equ).

Parameters:

name (str) – name of the item

idx_sets(name: str) List[str][source]

Return the list of index sets for an item (set, par, var, equ).

Parameters:

name (str) – name of the item

init_equ(name: str, idx_sets: Sequence[str] | None = None, idx_names: Sequence[str] | None = None)[source]
init_item(item_type: ItemType, name: str, idx_sets: Sequence[str] | None = None, idx_names: Sequence[str] | None = None)[source]

Initialize a new item name of type item_type.

In general, user code should call one of init_set(), init_par(), init_var(), or init_equ() instead of calling this method directly.

Parameters:
  • item_type (ItemType) – The type of the item.

  • name (str) – Name of the item.

  • idx_sets (collections.abc.Sequence of str or str, optional) – Name(s) of index sets for a 1+-dimensional item. If none are given, the item is scalar (zero dimensional).

  • idx_names (collections.abc.Sequence of str or str, optional) – Names of the dimensions indexed by idx_sets. If given, they must be the same length as idx_sets.

Raises:
  • ValueError

    • if idx_names are given but do not match the length of idx_sets. - if an item with the same name, of any item_type, already exists.

  • RuntimeError – if the Scenario is not checked out (see check_out()).

init_par(name: str, idx_sets: Sequence[str] | None = None, idx_names: Sequence[str] | None = None)[source]
init_scalar(name: str, val: Real, unit: str, comment=None) None[source]

Initialize a new scalar and set its value.

Parameters:
  • name (str) – Name of the scalar

  • val (float or int) – Initial value of the scalar.

  • unit (str) – Unit of the scalar.

  • comment (str, optional) – Description of the scalar.

init_set(name: str, idx_sets: Sequence[str] | None = None, idx_names: Sequence[str] | None = None)[source]
init_var(name: str, idx_sets: Sequence[str] | None = None, idx_names: Sequence[str] | None = None)[source]
is_default() bool[source]

Return True if the version is the default version.

items(type: ~ixmp.backend.ItemType = <ItemType.PAR: 4>, filters: ~typing.Dict[str, ~typing.Sequence[str]] | None = None, *, indexed_by: str | None = None, par_data: bool | None = None) Iterable[str][source]

Iterate over model data items.

Parameters:
  • type (ItemType, optional) – Types of items to iterate, for instance ItemType.PAR for parameters.

  • filters (dict, optional) – Filters for values along dimensions; same as the filters argument to par(). Only value for ItemType.PAR.

  • indexed_by (str, optional) – If given, only iterate over items where one of the item dimensions is indexed_by the set of this name.

  • par_data (bool, optional) – If True (the default) and type is ItemType.PAR, also iterate over data for each parameter.

Yields:
last_update() str[source]

Get the timestamp of the last update/edit of this TimeSeries.

list_items(item_type: ItemType, indexed_by: str | None = None) List[str][source]

List all defined items of type item_type.

See also

items

load_scenario_data() None[source]

Load all Scenario data into memory.

Raises:

ValueError – If the Scenario was instantiated with cache=False.

model: str[source]

Name of the model associated with the TimeSeries.

par(name, filters=None)[source]

Return parameter data.

Same as ixmp.Scenario.par(), except columns indexed by the MESSAGEix set year are returned with int dtype.

Parameters:
  • name (str) – Name of the parameter.

  • filters (dict, optional) – Filters for the dimensions of the parameter. See ixmp.Scenario.par().

Returns:

Filtered elements of the parameter.

Return type:

pandas.DataFrame

par_list(indexed_by: str | None = None) List[str][source]
preload_timeseries() None[source]

Preload timeseries data to in-memory cache. Useful for bulk updates.

read_excel(path: PathLike, add_units: bool = False, init_items: bool = False, commit_steps: bool = False) None[source]

Read a Microsoft Excel file into the Scenario.

Parameters:
  • path (os.PathLike) – File to read. Must have suffix ‘.xlsx’.

  • add_units (bool, optional) – Add missing units, if any, to the Platform instance.

  • init_items (bool, optional) – Initialize sets and parameters that do not already exist in the Scenario.

  • commit_steps (bool, optional) – Commit changes after every data addition.

read_file(path: PathLike, firstyear: int | None = None, lastyear: int | None = None) None[source]

Read time series data from a CSV or Microsoft Excel file.

Parameters:
  • path (os.PathLike) – File to read. Must have suffix ‘.csv’ or ‘.xlsx’.

  • firstyear (int, optional) – Only read data from years equal to or later than this year.

  • lastyear (int, optional) – Only read data from years equal to or earlier than this year.

remove_geodata(df: DataFrame) None[source]

Remove geodata from the TimeSeries instance.

Parameters:

df (pandas.DataFrame) –

Data to remove. df must have the following columns:

  • region

  • variable

  • unit

  • subannual

  • year

remove_meta(name: str | Sequence[str]) None[source]

Remove Metadata for this object.

Parameters:

name (str or list of str) – Either single metadata name/identifier, or list of names.

remove_par(name: str, key=None) None[source]

Remove parameter values or an entire parameter.

Parameters:
  • name (str) – Name of the parameter.

  • key (pandas.DataFrame or list or str, optional) – Elements to be removed. If a pandas.DataFrame, must contain the same columns (indices/dimensions) as the parameter. If a list, a single key for a single data point; the individual elements must correspond to the indices/dimensions of the parameter.

remove_set(name: str, key: str | Sequence[str] | Dict | DataFrame | None = None) None[source]

Delete set elements or an entire set.

Parameters:
  • name (str) – Name of the set to remove (if key is None) or from which to remove elements.

  • key (pandas.DataFrame or list of str, optional) – Elements to be removed from set name.

remove_solution(first_model_year: int | None = None) None[source]

Remove the solution from the scenario.

This function removes the solution (variables and equations) and timeseries data marked as meta=False from the scenario (see add_timeseries()).

Parameters:

first_model_year (int, optional) – If given, timeseries data marked as meta=False is removed only for years from first_model_year onwards.

Raises:

ValueError – If Scenario has no solution or if first_model_year is not int.

remove_timeseries(df: DataFrame) None[source]

Remove time series data.

Parameters:

df (pandas.DataFrame) –

Data to remove. df must have the following columns:

  • region or node

  • variable

  • unit

  • year

rename(name: str, mapping: Mapping[str, str], keep: bool = False) None[source]

Rename elements in the set name and transform data indexed by old name(s).

  • All new set element names per mapping are added to the set name, if not already present.

  • Data in all sets and parameters indexed by the set name is also either duplicated (if keep=True) or replaced (if keep=False) with mapped keys.

Parameters:
  • name (str) – Name of the set to change, for instance "technology". Note that renaming the “year” set may require further adjustments for a feasible scenario.

  • mapping (dict) – Mapping from old/current to new set element names.

  • keep (bool, optional) – If False (the default), old/current set element names are removed entirely from the Scenario. If True, old/current set elements and all parameter data indexed by them is retained.

Raises:
  • KeyError – if name is the name of a different kind of item (for instance, a parameter) or of no known item.

  • ValueError – if name is a set indexed by 1 or more others.

run_id() int[source]

Get the run id of this TimeSeries.

scalar(name: str) Dict[str, Real | str][source]

Return the value and unit of a scalar.

Parameters:

name (str) – Name of the scalar.

Returns:

with the keys “value” and “unit”.

Return type:

dict

scenario: str[source]

Name of the scenario associated with the TimeSeries.

scheme = None[source]

Scheme of the Scenario.

set(name, filters=None)[source]

Return elements of a set.

Same as ixmp.Scenario.set(), except columns for multi-dimensional sets indexed by the MESSAGEix set year are returned with int dtype.

Parameters:
  • name (str) – Name of the set.

  • filters (dict, optional) – Mapping of dimension_nameelements, where dimension_name is one of the idx_names given when the set was initialized (see init_set()), and elements is an iterable of labels to include in the return value.

Returns:

set_as_default() None[source]

Set the current version as the default.

set_list(indexed_by: str | None = None) List[str][source]
set_meta(name_or_dict: str | Dict[str, Any], value=None) None[source]

Set Metadata for this object.

Parameters:
  • name_or_dict (str or dict) – If dict, a mapping of names/identifiers to values. Otherwise, use the metadata identifier.

  • value (str or float or int or bool, optional) – Metadata value.

solve(model='MESSAGE', solve_options={}, **kwargs)[source]

Solve MESSAGE or MESSAGE-MACRO for the Scenario.

By default, ixmp.Scenario.solve() is called with ‘MESSAGE’ as the model argument. model may also be overwritten, e.g.:

>>> s.solve(model='MESSAGE-MACRO')
Parameters:
  • model ('MESSAGE' or 'MACRO' or 'MESSAGE-MACRO', optional) – Model to solve.

  • solve_options (dict, optional) – Mapping of (optionvalue) to use for GAMS CPLEX solver options file. See the MESSAGE class and DEFAULT_CPLEX_OPTIONS.

  • kwargs – Other options control the execution of the underlying GAMS code; see the MESSAGE_MACRO class and GAMSModel.

timeseries(region: str | Sequence[str] | None = None, variable: str | Sequence[str] | None = None, unit: str | Sequence[str] | None = None, year: int | Sequence[int] | None = None, iamc: bool = False, subannual: bool | str = 'auto') DataFrame[source]

Retrieve time series data.

Parameters:
  • iamc (bool, optional) – Return data in wide/’IAMC’ format. If False, return data in long format; see add_timeseries().

  • region (str or list of str, optional) – Regions to include in returned data.

  • variable (str or list of str, optional) – Variables to include in returned data.

  • unit (str or list of str, optional) – Units to include in returned data.

  • year (int or list of int, optional) – Years to include in returned data.

  • subannual (bool or 'auto', optional) – Whether to include column for sub-annual specification (if bool); if ‘auto’, include column if sub-annual data (other than ‘Year’) exists in returned data frame.

Raises:

ValueError – If subannual is False but Scenario has (filtered) sub-annual data.

Returns:

Specified data.

Return type:

pandas.DataFrame

to_excel(path: ~os.PathLike, items: ~ixmp.backend.ItemType = <ItemType.SET|PAR: 6>, filters: ~typing.Dict[str, ~typing.Sequence[str] | ~ixmp.core.scenario.Scenario] | None = None, max_row: int | None = None) None[source]

Write Scenario to a Microsoft Excel file.

Parameters:
  • path (os.PathLike) – File to write. Must have suffix .xlsx.

  • items (ItemType, optional) – Types of items to write. Either SET | PAR (i.e. only sets and parameters), or MODEL (also variables and equations, i.e. model solution data).

  • filters (dict, optional) – Filters for values along dimensions; same as the filters argument to par().

  • max_row (int, optional) – Maximum number of rows in each sheet. If the number of elements in an item exceeds this number or EXCEL_MAX_ROWS, then an item is written to multiple sheets named, e.g. ‘foo’, ‘foo(2)’, ‘foo(3)’, etc.

transact(message: str = '', condition: bool = True, discard_on_error: bool = False)[source]

Context manager to wrap code in a ‘transaction’.

Parameters:
  • message (str) – Commit message to use, if any commit is performed.

  • condition (bool) –

    If True (the default):

    • Before entering the code block, the TimeSeries (or Scenario) is checked out.

    • On exiting the code block normally (without an exception), changes are committed with message.

    If False, nothing occurs on entry or exit.

  • discard_on_error (bool) – If True (default False), then the anti-locking behaviour of discard_on_error() also applies to any exception raised in the block.

Example

>>> # `ts` is currently checked in/locked
>>> with ts.transact(message="replace 'foo' with 'bar' in set x"):
>>>    # `ts` is checked out and may be modified
>>>    ts.remove_set("x", "foo")
>>>    ts.add_set("x", "bar")
>>> # Changes to `ts` have been committed
property url: str[source]

URL fragment for the TimeSeries.

This has the format {model name}/{scenario name}#{version}, with the same values passed when creating the TimeSeries instance.

Examples

To form a complete URL (e.g. to use with from_url()), use a configured ixmp.Platform name:

>>> platform_name = "my-ixmp-platform"
>>> mp = Platform(platform_name)
>>> ts = TimeSeries(mp, "foo", "bar", 34)
>>> ts.url
"foo/bar#34"
>>> f"ixmp://{platform_name}/{ts.url}"
"ixmp://platform_name/foo/bar#34"

Note

Use caution: because Platform configuration is system-specific, other systems must have the same configuration for platform_name in order for the URL to refer to the same TimeSeries/Scenario.

var(name, filters=None)[source]

Return variable data.

Same as ixmp.Scenario.var(), except columns indexed by the MESSAGEix set year are returned with int dtype.

Parameters:
  • name (str) – Name of the variable.

  • filters (dict, optional) – Filters for the dimensions of the variable. See ixmp.Scenario.var().

Returns:

Filtered elements of the variable.

Return type:

pandas.DataFrame

var_list(indexed_by: str | None = None) List[str][source]
version = None[source]

Version of the TimeSeries. Immutable for a specific instance.

vintage_and_active_years(ya_args: Tuple[str, str] | Tuple[str, str, int | str] | None = None, tl_only: bool = True, **kwargs) DataFrame[source]

Return matched pairs of vintage and active periods for use in data input.

Each returned pair of (vintage period \(y^V\), active period \(y\)) satisfies all of the following conditions:

  1. \(y^V, y \in Y\): both vintage and active period are in the year set of the Scenario.

  2. \(y^V \leq y\): a technology cannot be active before it is constructed.

  3. If ya_args (node \(n\), technology \(t\), and optionally \(y^V\)) are given:

    1. \(y^V\) is in the subset of \(Y\) for which \(\text{technical_lifetime}_{n,t,y^V}\) is defined (or the single, specified value).

    2. \(y - y^V + \text{duration_period}_{n,t,y^V} < \text{technical_lifetime}_{n,t,y^V}\): the active period is partly or fully within the technical lifetime defined for that technology, node, and vintage. This is the same condition as years_active().

  4. If ya_args are given and tl_only is True (the default): \(y\) is in the subset of \(Y\) for which \(\text{technical_lifetime}_{n,t,y}\) is defined. [1]

  5. (Deprecated) If in_horizon is True: \(y \geq y_0\), the firstmodelyear.

Parameters:
  • ya_args (tuple, optional) – Either length 2 (node, technology) or length 3 (node, technology, year_vtg). Supplied directly to years_active(). If the third element is omitted, years_active() is called repeatedly, once for each vintage for which a technical lifetime value is set (condition (3)).

  • tl_only (bool, optional) – Condition (4), above.

  • in_horizon (bool, optional) –

    Condition (5), above.

    Deprecated since version 3.6: In message_ix 4.0 or later, in_horizon will be removed, and the default behaviour of vintage_and_active_years() will change to the equivalent of in_horizon = False.

Returns:

with columns “year_vtg” and “year_act”, in which each row is a valid pair.

Return type:

pandas.DataFrame

Examples

pandas.DataFrame.query() can be used to further manipulate the data in the returned data frame. To limit the vintage periods included:

>>> base = s.vintage_and_active_years(("node", "tech"))
>>> df = base.query("2020 <= year_vtg")

Limit the active periods included:

>>> df = base.query("2040 < year_act")

Limit year_act to the first model year or later (same as deprecated in_horizon argument):

>>> df = base.query(f"{s.firstmodelyear} <= year_act")

More complex expressions and a chained pandas call:

>>> df = s.vintage_and_active_years(
...     ("node", "tech"), tl_only=False
... ).query("2025 <= year_act or year_vtg < 2010")
property y0[source]

Alias for firstmodelyear.

ya(node: str, tec: str, yr_vtg: int | str) List[int][source]

Alias for years_active().

years_active(node: str, tec: str, yr_vtg: int | str) List[int][source]

Return periods in which tec hnology of yr_vtg can be active in node.

The parameters duration_period and technical_lifetime are used to determine which periods are partly or fully within the lifetime of the technology.

Parameters:
  • node (str) – Node name.

  • tec (str) – Technology name.

  • yr_vtg (int or str) – Vintage year.

Return type:

list of int

yv_ya(ya_args: Tuple[str, str] | Tuple[str, str, int | str] | None = None, tl_only: bool = True, **kwargs) DataFrame[source]

Alias for vintage_and_active_years().

Model classes

MESSAGE([name])

Model class for MESSAGE.

MACRO(*args, **kwargs)

Model class for MACRO.

MESSAGE_MACRO(*args, **kwargs)

Model class for MESSAGE_MACRO.

GAMSModel([name])

Extended ixmp.model.gams.GAMSModel for MESSAGE & MACRO.

DEFAULT_CPLEX_OPTIONS

Solver options used by Scenario.solve().

Item(name, type, expr, coords, ...] =, dims, ...)

Description of an ixmp item: equation, parameter, set, or variable.

ItemType(value[, names, module, qualname, ...])

Type of data items in ixmp.TimeSeries and ixmp.Scenario.

message_ix.models.DEFAULT_CPLEX_OPTIONS = {'advind': 0, 'epopt': 1e-06, 'lpmethod': 4, 'threads': 4}

Solver options used by Scenario.solve().

These configure the GAMS CPLEX solver (or another solver, if selected); see the solver documentation for possible values.

class message_ix.models.GAMSModel(name=None, **model_options)[source]

Extended ixmp.model.gams.GAMSModel for MESSAGE & MACRO.

The MESSAGE, MACRO, and MESSAGE_MACRO child classes encapsulate the GAMS code for the core MESSAGE (or MACRO) mathematical formulation.

The class receives model_options via Scenario.solve(). Some of these are passed on to the parent class ixmp.model.gams.GAMSModel (see there for a list); others are handled as described below.

The “model_dir” option may be set in the user’s ixmp configuration file using the key “message model dir”. If not set, it defaults to “message_ix/model” below the directory where message_ix is installed.

The “solve_options” option may be set in the user’s ixmp configuration file using the key “message solve options”. If not set, it defaults to DEFAULT_CPLEX_OPTIONS.

For example, with the following configuration file:

{
  "platform": {
    "default": "my-platform",
    "my-platform": {"backend": "jdbc", "etc": "etc"},
  },
  "message model dir": "/path/to/custom/gams/source/files",
  "message solve options": {"lpmethod": 4},
}

The following are equivalent:

# Model options given explicitly
scen.solve(
    model_dir="/path/to/custom/gams/source/files",
    solve_options=dict(lpmethod=4),
)

# Model options are read from configuration file
scen.solve()

GDX input and output files generated using this class will contain a 2-dimensional set named ixmp_version, wherein the first element of each member is a package name from the record_version_packages parameter, and the second is its version according to importlib.metadata.version(). If the package is not installed, the string “(not installed)” is stored.

The following tables list all model options:

Options in message_ix.models.GAMSModel or overridden from ixmp

Option

Usage

Default value

model_dir

Path to GAMS source files.

See above.

model_file

Path to GAMS source file.

"{model_dir}/{model_name}_run.gms"

in_file

Path to write GDX input file.

"{model_dir}/data/MsgData_{case}.gdx"

out_file

Path to read GDX output file.

"{model_dir}/output/MsgOutput_{case}.gdx"

solve_args

Arguments passed directly to GAMS.

[
    '--in="{in_file}"',
    '--out="{out_file}"',
    '--iter="{model_dir}/output/MsgIterationReport_{case}.gdx"'
]

solve_options

Options for the GAMS LP solver.

DEFAULT_CPLEX_OPTIONS

record_version_packages

Python package versions to record.

["message_ix", "ixmp"]

Option defaults inherited from ixmp.model.gams.GAMSModel

Option

Default value

case

"{scenario.model}_{scenario.scenario}"

gams_args

["LogOption=4"]

check_solution

True

comment

None

equ_list

None

var_list

None

items: Mapping[str, Item][source]

Mapping from model item (equation, parameter, set, or variable) names to Item describing the item.

run(scenario)[source]

Execute the model.

GAMSModel creates a file named cplex.opt in the model directory containing the “solve_options”, as described above.

Warning

GAMSModel can solve Scenarios in two or more Python processes simultaneously; but using different CPLEX options in each process may produce unexpected results.

class message_ix.models.MESSAGE(name=None, **model_options)[source]

Bases: GAMSModel

Model class for MESSAGE.

items: MutableMapping[str, Item][source]

All equations, parameters, sets, and variables in the MESSAGE formulation.

Keys are the names of items (sets, parameters, variables, and equations); values are Item instances. These include all items listed in the MESSAGE mathematical specification, i.e. Sets and mappings and Parameter definition.

classmethod initialize(scenario)[source]

Set up scenario with required sets and parameters for MESSAGE.

See also

items

class message_ix.models.MACRO(*args, **kwargs)[source]

Bases: GAMSModel

Model class for MACRO.

items: MutableMapping[str, Item][source]

All equations, parameters, sets, and variables in the MACRO formulation.

GAMS_min_version = '24.8.1'[source]

MACRO uses the GAMS break; statement, and thus requires GAMS 24.8.1 or later.

classmethod initialize(scenario, with_data=False)[source]

Initialize the model structure.

name: str = 'MACRO'[source]

Model name.

class message_ix.models.MESSAGE_MACRO(*args, **kwargs)[source]

Bases: MESSAGE, MACRO

Model class for MESSAGE_MACRO.

MESSAGE_MACRO solves the MESSAGE and MACRO models iteratively, connecting changes in technology activity and resource demands (from MESSAGE) to changes in final demands and prices (from MACRO). This iteration continues until the solution converges; i.e. the two models reach a stable point for the values of these parameters.

MESSAGE_MACRO accepts three additional model_options that control the behaviour of this iteration algorithm:

  • max_adjustment (float, default 0.2): the maximum absolute relative change in final demands between iterations. If MACRO returns demands that have changed by more than a factor outside the range (1 - max_adjustment, 1 + max_adjustment) since the previous iteration, then the change is confined to the limits of that range for the next run of MESSAGE.

  • convergence_criterion (float, default 0.01): threshold for model convergence. This option applies to the same value as max_adjustment: the relative change in final demands between two iterations. If the absolute relative change is less than convergence_criterion, the linked model run is complete.

  • max_iteration (int, default 50): the maximum number of iterations between the two models. If the solution does not converge after this many iterations, the linked model run fails and no valid result is produced.

items: MutableMapping[str, Item][source]

All equations, parameters, sets, and variables in the MESSAGE-MACRO formulation.

classmethod initialize(scenario, with_data=False)[source]

Set up scenario with required sets and parameters for MESSAGE.

See also

items

name: str = 'MESSAGE-MACRO'[source]

Model name.

message_ix.models.DIMS = {'c': ('commodity', 'commodity'), 'e': ('emission', 'emission'), 'g': ('grade', 'grade'), 'h': ('time', 'time'), 'hd': ('time', 'time_dest'), 'ho': ('time', 'time_origin'), 'l': ('level', 'level'), 'm': ('mode', 'mode'), 'ms': ('mode', 'storage_mode'), 'n': ('node', 'node'), 'nd': ('node', 'node_dest'), 'nl': ('node', 'node_loc'), 'no': ('node', 'node_origin'), 'node_parent': ('node', 'node_parent'), 'nr': ('node', 'node_rel'), 'ns': ('node', 'node_share'), 'q': ('rating', 'rating'), 'r': ('relation', 'relation'), 's': ('land_scenario', 'land_scenario'), 't': ('technology', 'technology'), 'ta': ('technology', 'technology_addon'), 'time_parent': ('time', 'time_parent'), 'tp': ('technology', 'technology_primary'), 'ts': ('technology', 'storage_tec'), 'u': ('land_type', 'land_type'), 'y': ('year', 'year'), 'ya': ('year', 'year_act'), 'yr': ('year', 'year_rel'), 'yv': ('year', 'year_vtg')}

Common dimension name abbreviations mapped to tuples with:

  1. the respective coordinate/index set, and

  2. the full dimension name.

class message_ix.models.Item(name: str, type: ~ixmp.backend.ItemType, expr: dataclasses.InitVar[str] = '', coords: ~typing.Tuple[str, ...] = <factory>, dims: ~typing.Tuple[str, ...] = <factory>, description: str | None = None)[source]

Description of an ixmp item: equation, parameter, set, or variable.

Instances of this class carry only structural information, not data.

coords: Tuple[str, ...][source]

Coordinates of the item; that is, the names of sets that index its dimensions. The same set name may be repeated if it indexes multiple dimensions.

description: str | None = None[source]

Text description of the item.

dims: Tuple[str, ...][source]

Dimensions of the item.

expr: dataclasses.InitVar[str] = ''[source]

String expression for coords and dims. Split on spaces and parsed using DIMS so that, for instance, “nl yv” results in entries for for “node”, “year” in coords, and “node_loc”, “year_vtg” in dims.

property ix_type: str[source]

“equ”, “par”, “set”, or “var”.

Read-only.

Type:

Lower-case string form of type

name: str[source]

Name of the item.

to_dict() dict[source]

Return the dict representation used internally in ixmp.

This has the keys:

  • ix_type: same as ix_type.

  • idx_sets: same as coords.

  • idx_names: same as dims, but only included if these are (a) non-empty and (b) different from coords.

type: ItemType[source]

Type of the item, for instance ItemType.PAR.

Utility methods

message_ix.util.copy_model(path: Path, overwrite: bool = False, set_default: bool = False, quiet: bool = False) None[source]

Copy the MESSAGE GAMS files to a new path.

Parameters:
  • overwrite (bool) – If True, overwrite existing files.

  • set_default (bool) – If True, update the ixmp configuration setting “message model dir”.

  • quiet (bool) – If False, print actions to stdout; otherwise display nothing.

message_ix.util.expand_dims(scenario: Scenario, name, **data)[source]

Expand dimensions of parameter name on scenario, filling with data.

This function is for use when an existing parameter name has dimensions that are a subset of those that would be created by make_df(), i.e. those given by MESSAGE.items.

This can occur when the underlying structure of MESSAGE and the model core is enhanced by adding dimensions to existing parameters. Existing scenario data in users’ databases can not then be automatically updated.

expand_dims() helps users to update this data manually. It:

  1. Retrieves the existing parameter data for name.

  2. Passes this existing data, plus any data given as keyword arguments, to make_df(). The result must be a data frame with no empty values; in other words, data must include all the dimensions to be added to name.

  3. Re-initializes the parameter name on scenario, with the dimensions given by MESSAGE.items.

  4. Adds the expanded data.

The modifications (steps 3 and 4) are wrapped using transact().

message_ix.util.make_df(name, **data)[source]

Return a data frame for parameter or indexed set name filled with data.

make_df() always returns a data frame with the columns required by either:

  • add_par(): the dimensions of the parameter name, plus ‘value’ and ‘unit’.

  • add_set(): the dimensions of the indexed set name.

Columns not listed in data are left empty.

The data keyword arguments can be passed in many ways; see the Keyword Arguments and “Function Examples” sections of the Python introductory tutorial, or the examples below.

Examples

>>> make_df(
...    "demand", node=["foo", "bar"], commodity="baz", value=[1.2, 3.4]
... )
  node  commodity  level  year  time  value  unit
0  foo        baz   None  None  None    1.2  None
1  bar        baz   None  None  None    3.4  None

Pass some values as direct keyword arguments, and others by unpacking a dictionary:

>>> common = dict(
...    commodity="light",
...    level="useful",
...    time="year",
...    unit="GWa",
... )
>>> make_df(
...    "demand",
...    node=["Westeros", "Middle-earth"],
...    year=[680, 700],
...    value=[50, 80],
...    # Use values from `common` as additional keyword args:
...    **common,
... )
           node  commodity   level  year  time  value  unit
0      Westeros      light  useful   680  year     50   GWa
1  Middle-earth      light  useful   700  year     50   GWa

Code that uses the deprecated signature, such as:

>>> base = {"year": [2020, 2021, 2022]}
>>> make_df(base, value=1., unit="y")
   year  value  unit
0     1    1.0     y
1     2    1.0     y
2     3    1.0     y

or:

>>> base = dict(
...    node=["Westeros", "Middle-earth"],
...    year=[680, 700],
...    time="year",
...    unit="-",
... )
>>> make_df(base, mode="standard")
           node  year  time  unit      mode
0      Westeros   680  year     -  standard
1  Middle-earth   700  year     -  standard

…can either be adjusted to use the new signature:

>>> make_df("duration_period", **base, value=1., unit="y")

or, emulated using the pandas.DataFrame.assign() method:

>>> pd.DataFrame(base).assign(value=1., unit="y")

The former is recommended, because it will ensure the result has the correct columns for the parameter.

Parameters:
  • name (str) – Name of a parameter listed in MESSAGE.items or MACRO.items.

  • data (optional) – Contents for dimensions of the parameter, its ‘value’, or ‘unit’. Other keys are ignored.

Return type:

pandas.DataFrame

Raises:

ValueError – if name is not the name of a MESSAGE or MACRO parameter; if arrays in data have uneven lengths.

Testing utilities