Skip to content

Effort-sharing

Back to general structure

Effort-sharing regimes can be used to enforce the redistribution of mitigation effort and damage costs among regions following pre-defined equity principles. By default, in MIMOSA, no effort-sharing regime is imposed.

Besides no regime at all, there are five effort-sharing regimes implemented in MIMOSA. The regime can be selected using the effortsharing module parameter.

Usage:

params = load_params()
params["model structure"]["effortsharing module"] = "noregime"
model = MIMOSA(params)

By default, no effort-sharing regime is imposed.

Source code in mimosa/components/effortsharing/noregime.py
def get_constraints(
    m: AbstractModel, context: ModelContext
) -> Sequence[GeneralConstraint]:
    """
    Usage:
    ```python hl_lines="2"
    params = load_params()
    params["model structure"]["effortsharing module"] = "noregime"
    model = MIMOSA(params)
    ```

    By default, no effort-sharing regime is imposed.

    """

    return []

Usage:

params = load_params()
params["model structure"]["effortsharing module"] = "equal_mitigation_costs"
model = MIMOSA(params)

Equal mitigation costs implies that the attributed mitigation costs in every year (in terms of percentage of GDP) should be the same for every region:

\[ \text{mitigation costs}_{t,r} = \text{common level}_t, \]

where the variable \(\text{common level}_t\) can have arbitrary values and is purely used as a common value accross all the regions1.


  1. Implementing every regional condition as an exact equality can give IPOPT too many or redundant equality equations relative to the available variables. The condition is therefore implemented as an "almost-equality" (a soft-equality constraint), allowing a difference of at most 0.5%. See Soft-equality constraints.

    \[ 0.995 \cdot \text{RHS} \leq \text{LHS} \leq 1.005 \cdot \text{RHS}. \]

Source code in mimosa/components/effortsharing/equal_mitigation_costs.py
def get_constraints(
    m: AbstractModel, context: ModelContext
) -> Sequence[GeneralConstraint]:
    """
    Usage:
    ```python hl_lines="2"
    params = load_params()
    params["model structure"]["effortsharing module"] = "equal_mitigation_costs"
    model = MIMOSA(params)
    ```

    Equal mitigation costs implies that the attributed mitigation costs in every year (in terms of
    percentage of GDP) should be the same for every region:

    $$
    \\text{mitigation costs}_{t,r} = \\text{common level}_t,
    $$

    where the variable $\\text{common level}_t$ can have arbitrary values and is purely used as a common
    value accross all the regions[^1].

    [^1]: Implementing every regional condition as an exact equality can give IPOPT too many or
        redundant equality equations relative to the available variables. The condition is therefore
        implemented as an "almost-equality" (a soft-equality constraint), allowing a difference of at
        most 0.5%. See [Soft-equality constraints](../extending/variables_constraints.md#soft-equality-constraints).

        $$
        0.995 \\cdot \\text{RHS} \\leq \\text{LHS} \\leq 1.005 \\cdot \\text{RHS}.
        $$

    """

    m.effort_sharing_common_level = Var(m.t, units=quant.unit("fraction_of_GDP"))

    return [
        RegionalSoftEqualityConstraint(
            lambda m, t, r: m.mitigation_costs[t, r],
            lambda m, t, r: m.effort_sharing_common_level[t],
            "effort_sharing_regime_mitigation_costs",
        ),
    ]

Usage:

params = load_params()
params["model structure"]["effortsharing module"] = "equal_total_costs"
model = MIMOSA(params)

In this effort-sharing regime, the damages are also taken into account when equalising the costs among regions:

\[ \text{mitigation costs}_{t,r} + \text{damage costs}_{t,r}\ (+ \text{financial transfer}_{t,r}) = \text{common level}_t, \]

where the variable \(\text{common level}_t\) can have arbitrary values and is purely used as a common value accross all the regions1. Note that the variable \(\text{damages}_{t,r}\) is already expressed as percentage of GDP (see Damages).

For feasibility reasons, this constraint is only enforced until 2100.

Compared to the equal mitigation cost regime, this regime might be infeasible, especially for regions with very high damages, unless:

  • (a) the mitigation costs can be negative (for regions with very high damages). This can be achieved with the parameter rel_mitigation_costs_min_level.

  • or (b) if financial transfers are allowed between regions, that go beyond emission trading. See Financial transfers.


  1. Implementing every regional condition as an exact equality can give IPOPT too many or redundant equality equations relative to the available variables. The condition is therefore implemented as an "almost-equality" (a soft-equality constraint), allowing a difference of at most 0.5%. See Soft-equality constraints.

    \[ 0.995 \cdot \text{RHS} \leq \text{LHS} \leq 1.005 \cdot \text{RHS}. \]

Source code in mimosa/components/effortsharing/equal_total_costs.py
def get_constraints(
    m: AbstractModel, context: ModelContext
) -> Sequence[GeneralConstraint]:
    """
    Usage:
    ```python hl_lines="2"
    params = load_params()
    params["model structure"]["effortsharing module"] = "equal_total_costs"
    model = MIMOSA(params)
    ```

    In this effort-sharing regime, the damages are also taken into account when equalising the costs among regions:

    $$
    \\text{mitigation costs}_{t,r} + \\text{damage costs}_{t,r}\\ (+ \\text{financial transfer}_{t,r}) = \\text{common level}_t,
    $$

    where the variable $\\text{common level}_t$ can have arbitrary values and is purely used as a common
    value accross all the regions[^1]. Note that the variable $\\text{damages}_{t,r}$ is already expressed as percentage of GDP (see [Damages](damages.md)).

    For feasibility reasons, this constraint is only enforced until 2100.

    Compared to the equal mitigation cost regime, this regime might be infeasible, especially for regions with very high damages, unless:

    * (a) the mitigation costs can be negative (for regions with very high damages). This can be achieved with the
        parameter [`rel_mitigation_costs_min_level`](../parameters.md#economics.MAC.rel_mitigation_costs_min_level).

    * or (b) if financial transfers are allowed between regions, that go beyond emission trading. See [Financial transfers](financialtransfers.md).

    [^1]: Implementing every regional condition as an exact equality can give IPOPT too many or
        redundant equality equations relative to the available variables. The condition is therefore
        implemented as an "almost-equality" (a soft-equality constraint), allowing a difference of at
        most 0.5%. See [Soft-equality constraints](../extending/variables_constraints.md#soft-equality-constraints).

        $$
        0.995 \\cdot \\text{RHS} \\leq \\text{LHS} \\leq 1.005 \\cdot \\text{RHS}.
        $$
    """

    m.effort_sharing_common_level = Var(m.t, units=quant.unit("fraction_of_GDP"))

    return [
        # Total costs: mitigation + damage costs should be equal among regions as % GDP
        RegionalSoftEqualityConstraint(
            lambda m, t, r: m.mitigation_costs[t, r]
            + m.damage_costs[t, r]
            + m.financial_transfer[t, r],
            lambda m, t, r: m.effort_sharing_common_level[t],
            "effort_sharing_regime_total_costs",
            ignore_if=lambda m, t, r: m.year(t) > 2100,
        ),
    ]

Usage:

params = load_params()
params["model structure"]["effortsharing module"] = "per_cap_convergence"
params["effort sharing"]["percapconv_year"] = 2050

# Per-capita convergence needs emission trading to avoid infeasibility
params["model structure"]["emissiontrade module"] = "emissiontrade"
# And financial transfers higher than just emission trading need to be enabled
# (therefore allowing for negative mitigation costs)
params["economics"]["MAC"]["rel_mitigation_costs_min_level"] = -0.5
model = MIMOSA(params)

The per capita convergence regime allocates equal per capita emission rights to each region, starting from a given year (called the convergence year). The convergence year can be set with the parameter percapconv_year and is set to 2050 by default. Before this convergence year, the allowances are interpolated between grandfathering (the emission distribution in the first model year) and equal per capita emission rights in the convergence year.

Therefore, two functions are needed. First, the allowances for equal per capita emissions (EPC):

\[ \text{allowances}_{\text{EPC}, t, r} = \frac{\text{population}_{t,r}}{\sum_{s} \text{population}_{t,s}} \cdot \text{global emissions}_{t}, \]

and second the allowances for grandfathering (GF):

\[ \text{allowances}_{\text{GF}, t, r} = \frac{\text{baseline emissions}_{0,r}}{\sum_{s} \text{baseline emissions}_{0,s}} \cdot \text{global emissions}_{t}, \]

Finally, the allowances for each region are calculated as a linear interpolation between the two before the convergence year. After the convergence year, only the equal per capita emissions are used:

\[ \text{allowances}_{t, r} = \begin{cases} x \cdot \text{allowances}_{\text{GF}, t, r} + (1-x) \cdot (\text{allowances}_{\text{EPC}, t, r}), & \text{if } t < \text{convergence year}, \\ \text{allowances}_{\text{EPC}, t, r}, & \text{if } t \geq \text{convergence year},\\ \text{allowances}_{\text{GF},t,r}, & \text{if } \text{convergence year} = \text{false}. \end{cases} \]

where \(x\) is the linear interpolation factor, which is 1 in the first year and 0 in the convergence year:

\[ x = \frac{t - t_0}{\text{convergence year} - t_0}. \]
Immediate per capita convergence

If the convergence year is set to the first year, the per capita convergence is applied immediately:

params = load_params()
params["model structure"]["effortsharing module"] = "per_cap_convergence"
params["effort sharing"]["percapconv_year"] = params["time"]["start"]
Grandfathering

If the convergence year is set to false, the grandfathering allowance distribution is used all the time.

params = load_params()
params["model structure"]["effortsharing module"] = "per_cap_convergence"
params["effort sharing"]["percapconv_year"] = False  # Grandfathering all the time
Source code in mimosa/components/effortsharing/per_cap_convergence.py
def percapconv_share_rule(m, t, r):
    """
    Finally, the allowances for each region are calculated as a linear interpolation between the two before the convergence year. After the convergence year,
    only the equal per capita emissions are used:

    $$
    \\text{allowances}_{t, r} = \\begin{cases}
    x \\cdot \\text{allowances}_{\\text{GF}, t, r} + (1-x) \\cdot (\\text{allowances}_{\\text{EPC}, t, r}), & \\text{if } t < \\text{convergence year}, \\\\
    \\text{allowances}_{\\text{EPC}, t, r}, & \\text{if } t \\geq \\text{convergence year},\\\\
    \\text{allowances}_{\\text{GF},t,r}, & \\text{if } \\text{convergence year} = \\text{false}.
    \\end{cases}
    $$

    where $x$ is the linear interpolation factor, which is 1 in the first year and 0 in the convergence year:

    $$
    x = \\frac{t - t_0}{\\text{convergence year} - t_0}.
    $$

    #### Immediate per capita convergence

    If the convergence year is set to the first year, the per capita convergence is applied immediately:

    ```python hl_lines="3"
    params = load_params()
    params["model structure"]["effortsharing module"] = "per_cap_convergence"
    params["effort sharing"]["percapconv_year"] = params["time"]["start"]
    ```

    #### Grandfathering

    If the convergence year is set to `false`, the grandfathering allowance distribution is used all the time.

    ```python hl_lines="3"
    params = load_params()
    params["model structure"]["effortsharing module"] = "per_cap_convergence"
    params["effort sharing"]["percapconv_year"] = False  # Grandfathering all the time
    ```
    """

    year_0, year_t = m.year(0), m.year(t)
    year_conv = m.percapconv_year

    if year_conv is False:
        # If it is false, use grandfathering all the time
        return m.percapconv_share_init[r]
    if year_conv == year_0:
        # If it is equal to first year, use immediate per capita convergence
        return m.percapconv_share_pop[t, r]

    year_linear_part = (year_t - year_0) / (year_conv - year_0)

    return (
        min(year_linear_part, 1) * m.percapconv_share_pop[t, r]
        + max(1 - year_linear_part, 0) * m.percapconv_share_init[r]
    )

Finally, the calculated allowances are imposed on each region's regional_emission_allowances. Since this regime needs emission trading to avoid infeasibility, allowances are calculated from the reductions attributed to a region. These can differ from the physical reductions within that region because reductions can be traded:

\[ \text{allowances}_{t,r} = \text{baseline emissions}_{t,r} - \text{attributed emission reductions}_{t,r} \]
Source code in mimosa/components/effortsharing/per_cap_convergence.py
def get_constraints(
    m: AbstractModel, context: ModelContext
) -> Sequence[GeneralConstraint]:
    """
    Usage:
    ```python hl_lines="2-9"
    params = load_params()
    params["model structure"]["effortsharing module"] = "per_cap_convergence"
    params["effort sharing"]["percapconv_year"] = 2050

    # Per-capita convergence needs emission trading to avoid infeasibility
    params["model structure"]["emissiontrade module"] = "emissiontrade"
    # And financial transfers higher than just emission trading need to be enabled
    # (therefore allowing for negative mitigation costs)
    params["economics"]["MAC"]["rel_mitigation_costs_min_level"] = -0.5
    model = MIMOSA(params)
    ```

    The per capita convergence regime allocates equal per capita emission rights to each region, starting
    from a given year (called the convergence year). The convergence year can be set with the parameter
    [`percapconv_year`](../parameters.md#effort sharing.percapconv_year) and is
    set to 2050 by default. Before this convergence year, the allowances are interpolated
    between grandfathering (the emission distribution in the first model year) and equal per capita
    emission rights in the convergence year.


    Therefore, two functions are needed. First, the allowances for equal per capita emissions (EPC):

    $$
    \\text{allowances}_{\\text{EPC}, t, r} = \\frac{\\text{population}_{t,r}}{\\sum_{s} \\text{population}_{t,s}} \\cdot \\text{global emissions}_{t},
    $$

    and second the allowances for grandfathering (GF):

    $$
    \\text{allowances}_{\\text{GF}, t, r} = \\frac{\\text{baseline emissions}_{0,r}}{\\sum_{s} \\text{baseline emissions}_{0,s}} \\cdot \\text{global emissions}_{t},
    $$

    :::mimosa.components.effortsharing.per_cap_convergence.percapconv_share_rule

    Finally, the calculated allowances are imposed on each region's `regional_emission_allowances`.
    Since this regime needs [emission trading](emissiontrading.md) to avoid infeasibility, allowances
    are calculated from the reductions attributed to a region. These can differ from the physical
    reductions within that region because reductions can be traded:

    $$
    \\text{allowances}_{t,r} = \\text{baseline emissions}_{t,r} - \\text{attributed emission reductions}_{t,r}
    $$


    """
    ## Per capita convergence:
    # m.regional_per_cap_emissions = Var(
    #     m.t, m.regions, units=quant.unit("emissionsrate_unit/population_unit")
    # )
    m.percapconv_share_init = Param(
        m.regions,
        initialize=lambda m, r: m.ssp_baseline_emissions[0, r]
        / sum(m.ssp_baseline_emissions[0, s] for s in m.regions),
    )
    m.percapconv_year = Param(initialize=2050, doc="::effort sharing.percapconv_year")
    m.percapconv_share_pop = Param(
        m.t,
        m.regions,
        initialize=lambda m, t, r: m.population[t, r] / m.global_population[t],
    )

    m.percapconv_share = Param(m.t, m.regions, initialize=percapconv_share_rule)

    return [
        RegionalSoftEqualityConstraint(
            lambda m, t, r: m.percapconv_share[t, r] * m.global_emissions[t],
            lambda m, t, r: m.regional_emission_allowances[t, r],
            epsilon=None,
            absolute_epsilon=0.001,
            ignore_if=lambda m, t, r: t == 0,
            name="percapconv_rule",
        ),
    ]

Usage:

params = load_params()
params["model structure"]["effortsharing module"] = "ability_to_pay"
model = MIMOSA(params)

In this effort-sharing regime, emission allowances are allocated based on per-capita GDP (see van den Berg et al. (2020)).

There are three steps in the calculation of the allowances: (1) the main reduction calculation based on per-capita GDP, (2) a global correction factor to make sure that the total reductions match the global target, and (3) the final allowances calculation.

Step 1: Reductions before correction factor
\[ \text{reductions}_{\text{AP}; t,r} = \sqrt[3]{\frac{\text{per cap. GDP}_{t,r}}{\text{global per cap. GDP}_{t}}} \cdot \text{glob. fract. of baseline emissions}_{t} \cdot \text{baseline emissions}_{t,r}, \]

with

\[ \text{glob. frac. of baseline emissions}_{t} = \frac{\text{global baseline emissions}_{t} - \text{global emissions}_{t}}{\text{global baseline emissions}_{t}}. \]

Note: The per-capita GDP can be calculated in two ways: either from the baseline GDP variable or from the net GDP variable. For numerical stability, we use the baseline GDP variable, even though it would be slightly more accurate to use the net GDP variable.

Source code in mimosa/components/effortsharing/ability_to_pay.py
def ability_to_pay_rule(m, t, r):
    """
    #### Step 1: Reductions before correction factor

    $$
    \\text{reductions}_{\\text{AP}; t,r} = \\sqrt[3]{\\frac{\\text{per cap. GDP}_{t,r}}{\\text{global per cap. GDP}_{t}}} \\cdot \\text{glob. fract. of baseline emissions}_{t} \\cdot \\text{baseline emissions}_{t,r},
    $$

    with

    $$
    \\text{glob. frac. of baseline emissions}_{t} = \\frac{\\text{global baseline emissions}_{t} - \\text{global emissions}_{t}}{\\text{global baseline emissions}_{t}}.
    $$

    *Note: The per-capita GDP can be calculated in two ways: either from the baseline GDP variable or from the net GDP variable. For numerical stability, we use the baseline GDP variable, even though it would be slightly more accurate to use the net GDP variable.*


    """
    gdp_var = m.baseline_GDP  # or: m.GDP_net
    per_cap_gdp = gdp_var[t, r] / m.population[t, r]
    global_per_cap_gdp = sum(gdp_var[t, s] for s in m.regions) / m.global_population[t]
    global_baseline_emissions = sum(m.baseline_emissions[t, s] for s in m.regions)

    reductions_before_correction = (
        (per_cap_gdp / global_per_cap_gdp) ** (1 / 3)
        * (global_baseline_emissions - m.global_emissions[t])
        / global_baseline_emissions
        * m.baseline_emissions[t, r]
    )

    return reductions_before_correction
Step 2: Global correction factor

The reduction factors from step 1 do not fully add up to the global emissions. There is typically a gap of a few percent. To correct this, a global correction factor is applied to the reductions:

\[ \text{correction factor}_{t} = \frac{\text{global baseline emissions}_{t} - \text{global emissions}_{t}}{\sum_{r} \text{reductions}_{\text{AP}; t,r}}. \]
Step 3: Final allowances calculation

Finally, the allowances are calculated by subtracting the reductions from the baseline emissions, multiplied by the correction factor:

\[ \text{allowances}_{\text{AP}; t,r} = \text{baseline emissions}_{t,r} - \text{reductions}_{\text{AP}; t,r} \cdot \text{correction factor}_{t}. \]
Source code in mimosa/components/effortsharing/ability_to_pay.py
def get_constraints(
    m: AbstractModel, context: ModelContext
) -> Sequence[GeneralConstraint]:
    """
    Usage:
    ```python hl_lines="2"
    params = load_params()
    params["model structure"]["effortsharing module"] = "ability_to_pay"
    model = MIMOSA(params)
    ```

    In this effort-sharing regime, emission allowances are allocated based on per-capita GDP (see [van den Berg et al. (2020)](https://doi.org/10.1007/s10584-019-02368-y)).

    There are three steps in the calculation of the allowances: (1) the main reduction calculation based on per-capita GDP,
    (2) a global correction factor to make sure that the total reductions match the global target, and (3) the final allowances calculation.


    :::mimosa.components.effortsharing.ability_to_pay.ability_to_pay_rule

    #### Step 2: Global correction factor

    The reduction factors from step 1 do not fully add up to the global emissions. There is typically a gap of a few percent. To correct this, a global correction factor is applied to the reductions:

    $$
    \\text{correction factor}_{t} = \\frac{\\text{global baseline emissions}_{t} - \\text{global emissions}_{t}}{\\sum_{r} \\text{reductions}_{\\text{AP}; t,r}}.
    $$

    #### Step 3: Final allowances calculation

    Finally, the allowances are calculated by subtracting the reductions from the baseline emissions, multiplied by the correction factor:

    $$
    \\text{allowances}_{\\text{AP}; t,r} = \\text{baseline emissions}_{t,r} - \\text{reductions}_{\\text{AP}; t,r} \\cdot \\text{correction factor}_{t}.
    $$


    """

    m.effortsharing_AP_reductions_before_correction = Var(m.t, m.regions)
    m.effortsharing_AP_inv_correction_factor = Var(m.t)
    m.effortsharing_AP_allowances = Var(m.t, m.regions)

    return [
        RegionalEquation(
            m.effortsharing_AP_reductions_before_correction, ability_to_pay_rule
        ),
        GlobalEquation(
            m.effortsharing_AP_inv_correction_factor,
            lambda m, t: (
                (
                    sum(m.baseline_emissions[t, r] for r in m.regions)
                    - m.global_emissions[t]
                )
                / soft_min(
                    sum(
                        m.effortsharing_AP_reductions_before_correction[t, r]
                        for r in m.regions
                    )
                )
                if t > 0
                else 1
            ),
        ),
        RegionalEquation(
            m.effortsharing_AP_allowances,
            lambda m, t, r: (
                m.baseline_emissions[t, r]
                - m.effortsharing_AP_reductions_before_correction[t, r]
                * m.effortsharing_AP_inv_correction_factor[t]
            ),
        ),
        RegionalSoftEqualityConstraint(
            lambda m, t, r: m.effortsharing_AP_allowances[t, r],
            lambda m, t, r: m.regional_emission_allowances[t, r],
            epsilon=None,
            absolute_epsilon=0.001,
            ignore_if=lambda m, t, r: t == 0,
            name="effortsharing_AP_rule",
        ),
    ]

Usage:

params = load_params()
params["model structure"]["effortsharing module"] = "equal_cumulative_per_cap"
model = MIMOSA(params)

In the equal cumulative per capita (ECPC) regime, emission allowances are allocated based on an equal per capita distribution of emissions, combining both historical and future emissions per capita. The historical emission debt is then spread out over the future time steps, going linearly down to zero in the repayment end year (default: 2050).

First, a historical debt is calculated for each region: how much more, or less, emissions did a region emit compared to its fair share of cumulative emissions per capita since a start year (by default 1850).

Step 1: historical debt calculation

The historical debt is calculated as the cumulative difference between the historical fair share (based on equal per capita emissions) and the actual emissions, starting from a given start year (default: 1850) and using all historical observations available up to the first model year. The debt is discounted to that first model year, denoted by \(t_0\) (2025 by default). If \(t_{\mathrm{hist}}\) is the final available historical observation:

\[ \text{debt}_{r} = \sum_{t=\text{start year}}^{t_{\mathrm{hist}}} \left(\text{emissions}_{r,t} - \frac{\text{population}_{r,t}}{\text{global population}_{t}} \cdot \text{global emissions}_{t}\right) \cdot e^{-\text{discount rate} \cdot (t_0 - t)}. \]

where you can set the following parameters:

The historical debt is therefore positive for regions that emitted more than their fair share of cumulative emissions per capita, and negative for regions that emitted less than their fair share:

Source code in mimosa/components/effortsharing/equal_cumulative_per_cap.py
def _calc_debt(m, r, all_emissions, all_population):
    """

    #### Step 1: historical debt calculation

    The historical debt is calculated as the cumulative difference between the historical
    fair share (based on equal per capita emissions) and the actual emissions, starting from
    a given start year (default: 1850) and using all historical observations available up to
    the first model year. The debt is discounted to that first model year, denoted by $t_0$
    (2025 by default). If $t_{\\mathrm{hist}}$ is the final available historical observation:

    $$
    \\text{debt}_{r} = \\sum_{t=\\text{start year}}^{t_{\\mathrm{hist}}} \\left(\\text{emissions}_{r,t} - \\frac{\\text{population}_{r,t}}{\\text{global population}_{t}} \\cdot \\text{global emissions}_{t}\\right) \\cdot e^{-\\text{discount rate} \\cdot (t_0 - t)}.
    $$

    where you can set the following parameters:

    * $\\text{start year}$ using [`params["effort sharing"]["ecpc_start_year"]`](../parameters.md#effort sharing.ecpc_start_year) (default: 1850),
    * $\\text{discount rate}$ using [`params["effort sharing"]["ecpc_discount_rate"]`](../parameters.md#effort sharing.ecpc_discount_rate) (default: 3%/yr).

    The historical debt is therefore positive for regions that emitted more than their fair share of cumulative emissions per capita, and negative for regions that emitted less than their fair share:

    ``` plotly
    {"file_path": "./assets/plots/ecpc_debt.json"}
    ```
    """
    start_year = value(m.effortsharing_ecpc_start_year)
    base_year = value(m.beginyear)

    emissions = all_emissions.loc[start_year:base_year]
    population = all_population.loc[start_year:base_year]
    global_emissions = emissions.sum(axis=1)
    global_population = population.sum(axis=1)

    years = global_population.index
    discount_factor = pd.Series(
        np.exp(-m.effortsharing_ecpc_discount_rate * (base_year - years)),
        index=years,
    )

    fair_share = population[r] / global_population * global_emissions
    cumulative_discounted_debt = ((emissions[r] - fair_share) * discount_factor).sum()

    return float(cumulative_discounted_debt)
Step 2: future fair share (excluding historical debt repayment)

The future fair share for every region (excluding the historical debt) is equal to the immediate per capita convergence regime: every year, a region gets allocated a share of the global emissions based on their population share.

Source code in mimosa/components/effortsharing/equal_cumulative_per_cap.py
def get_constraints(
    m: AbstractModel, context: ModelContext
) -> Sequence[GeneralConstraint]:
    """
    Usage:
    ```python hl_lines="2"
    params = load_params()
    params["model structure"]["effortsharing module"] = "equal_cumulative_per_cap"
    model = MIMOSA(params)
    ```

    In the equal cumulative per capita (ECPC) regime, emission allowances are allocated based on an equal
    per capita distribution of emissions, combining both *historical* and *future* emissions per capita.
    The historical emission debt is then spread out over the future time steps, going linearly down to
    zero in the repayment end year (default: 2050).

    First, a historical debt is calculated for each region: how much more, or less, emissions did a region emit
    compared to its fair share of cumulative emissions per capita since a start year (by default 1850).


    :::mimosa.components.effortsharing.equal_cumulative_per_cap._calc_debt

    #### Step 2: future fair share (excluding historical debt repayment)

    The future fair share for every region (excluding the historical debt) is equal to the immediate
    per capita convergence regime: every year, a region gets allocated a share of the global emissions
    based on their population share.

    ``` plotly
    {"file_path": "./assets/plots/ecpc_allowances.json"}
    ```


    """

    historical_emissions, historical_population = _load_data()
    m.effortsharing_ecpc_discount_rate = Param(
        doc="::effort sharing.ecpc_discount_rate"
    )
    m.effortsharing_ecpc_start_year = Param(doc="::effort sharing.ecpc_start_year")
    m.effortsharing_ecpc_historical_debt = Param(
        m.t,  # Constant over time
        m.regions,
        initialize=lambda m, t, r: _calc_debt(
            m, r, historical_emissions, historical_population
        ),
        units=quant.unit("emissions_unit"),
    )

    m.percapconv_share_pop = Param(
        m.t,
        m.regions,
        initialize=lambda m, t, r: m.population[t, r] / m.global_population[t],
    )

    m.effortsharing_ecpc_repayment_endyear = Param(
        doc="::effort sharing.ecpc_repayment_endyear"
    )

    m.effortsharing_ecpc_annual_debt_repayment = Param(
        m.t,
        m.regions,
        initialize=_calc_ecpc_annual_debt_repayment,
        units=quant.unit("emissionsrate_unit"),
    )

    return [
        RegionalSoftEqualityConstraint(
            lambda m, t, r: m.percapconv_share_pop[t, r] * m.global_emissions[t]
            - m.effortsharing_ecpc_annual_debt_repayment[t, r],
            lambda m, t, r: m.regional_emission_allowances[t, r],
            epsilon=None,
            absolute_epsilon=0.001,
            ignore_if=lambda m, t, r: t == 0,
            name="percapconv_rule",
        ),
    ]
Effort sharing in simulation mode

The example effort-sharing runs use optimisation. In simulation mode, the effort-sharing rules are not applied directly because they are constraints on calculated variables such as regional emission allowances and mitigation costs. A simulation can replay an optimised effort-sharing result when all underlying control values, including the relevant trading balances, are supplied, but it does not determine a new effort-sharing allocation itself.