Consumer disutility (model.disutility)

This module provides a generalized consumer disutility formulation, currently used by message_data.model.transport. The formulation rests on the concept of “consumer groups”; each consumer group may have a distinct disutility associated with using the outputs of each technology. A set of ‘pseudo-’/‘virtual’/non-physical “usage technologies” converts the outputs of the actual technologies into the commodities demanded by each group, while also requiring input of a costly “disutility” commodity.

Method & usage

Use this code by calling add(), which takes arguments that describe the concrete usage:

Consumer groups

This is a list of Code objects describing the consumer groups. The list must be 1-dimensional, but can be composed (as in message_data.model.transport) from multiple dimensions.

Technologies

This is a list of Code objects describing the technologies for which the consumers in the different groups experience disutility. Each object must be have ‘input’ and ‘output’ annotations (annotations); each of these is a dict with the keys ‘commodity’, ‘input’, and ‘unit’, describing the source or sink for the technology.

Template

This is also a Code object, similar to those in technologies; see below.

The code creates a source technology for the “disutility” commodity. The code does not perform the following step(s) needed to completely parametrize the formulation:

  • Set consumer group-specific demand parameter values for new commodities.

  • Set the amounts of “disutility” commodities used as input to the new usage technologies.

These must be parametrized based on the particular application.

Detailed example

This example is similar to the one used in test_disutility.test_minimal():

# Two consumer groups
groups = [Code(id="g0"), Code(id="g1")]

# Two technologies, for which groups may have different disutilities.
techs = [Code(id="t0"), Code(id="t1")]

# Add generalized disutility formulation to some technologies
disutility.add(
    scenario,
    groups=groups,
    technologies=techs,

    template=Code(
        # Template for IDs of conversion technologies
        id="usage of {technology} by {group}",

        # Templates for inputs of conversion technologies
        input=dict(
            # Technology-specific output commodity
            commodity="output of {technology}",
            level="useful",
            unit="kg",
        ),

        # Templates for outputs of conversion technologies
        output=dict(
            # Consumer-group–specific demand commodity
            commodity="demand of group {group}",
            level="useful",
            unit="kg",
        ),
    ),
    **options,
)

add() uses get_spec() to generate a specification that adds the following:

  • For the set commodity:

    • The single element “disutility”.

    • One element per technologies, using the template “input” annotation, e.g. “output of t0” generated from output of {technology} and the id “t0”. These may already be present in the scenario; if not, the spec causes them to be added.

    • One elements per groups, using the template “output” annotation, e.g. “demand of group g1” generated from demand of group {group} and the id “g1”. These may already be present in the scenario; if not, the spec causes them to be added.

  • For the set technology:

    • The single element “disutility source”.

    • One element per each combination of disutility-affected technology (technologies) and consumer group (groups). For example, “usage of t0 by g1” generated from usage of {technology} by {group}, and the ids “t0” and “g1”.

The spec is applied to the target scenario using model.build.apply_spec(). If the arguments produce a spec that is inconsistent with the target scenario, an exception will by raised at this point.

Next, add() uses data_conversion() and data_source() to generate:

  • output and var_cost parameter data for “disutility source”. This technology outputs the unitless commodity “disutility” at a cost of 1.0 per unit.

  • input and output parameter data for the new usage technologies. For example, the new technology “usage of t0 by g1”…

    • …takes input from the technology-specific commodity “output of t0”.

    • …takes input from the common commodity “disutility”, in an amount specific to group “g1”.

    • …outputs to a group-specific commodity “demand of group g1”.

Note that the technologies towards which the groups have disutility are assumed to already be configured to output to the corresponding commodities. For example, the technology “t0” outputs to the commodity “output of t0”; the output values for this technology are not added/introduced by add().

(Dis)utility is generally dimensionless. In pint and thus also message_ix_models, this should be represented by "". However, to work around iiasa/ixmp#425, data_conversion() and data_source() return data with "-" as units. See GH #45 for more information.

Code reference

See also message_ix_models.tests.model.test_disutility.

message_ix_models.model.disutility.add(scenario: Scenario, groups: Sequence[Code], technologies: Sequence[Code], template: Code, **options) Spec[source]

Add disutility formulation to scenario.

message_ix_models.model.disutility.data_conversion(info, spec: Spec) MutableMapping[str, DataFrame][source]

Generate input and output data for disutility conversion technologies.

message_ix_models.model.disutility.data_source(info, spec) Mapping[str, DataFrame][source]

Generate data for a technology that emits the “disutility” commodity.

message_ix_models.model.disutility.dp_for(col_name: str, info: ScenarioInfo) Series[source]

pandas.DataFrame.assign() helper for duration_period.

Returns a callable to be passed to pandas.DataFrame.assign(). The callable takes a data frame as the first argument, and returns a pandas.Series based on the duration_period parameter in info, aligned to col_name in the data frame.

Currently (2021-04-07) unused.

message_ix_models.model.disutility.get_data(scenario, spec, **kwargs) Mapping[str, DataFrame][source]

Get data for disutility formulation.

Calls data_conversion() and data_source().

Parameters:

spec (dict) – The output of get_spec().

message_ix_models.model.disutility.get_spec(groups: Sequence[Code], technologies: Sequence[Code], template: Code) Spec[source]

Get a spec for a disutility formulation.

Parameters:
  • groups (list of Code) – Identities of the consumer groups with distinct disutilities.

  • technologies (list of Code) – The technologies to which the disutilities are applied.

  • template (Code)