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 three types of effort-sharing regimes implemented in MIMOSA. This can be set using the effort_sharing_regime parameter.

Usage:

params = load_params()
params["effort sharing"]["regime"] = "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) -> Sequence[GeneralConstraint]:
    """
    Usage:
    ```python hl_lines="2"
    params = load_params()
    params["effort sharing"]["regime"] = "noregime"
    model = MIMOSA(params)
    ```

    By default, no effort-sharing regime is imposed.

    """

    return []

Usage:

params = load_params()
params["effort sharing"]["regime"] = "equal_mitigation_costs"
model = MIMOSA(params)

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

\[ \frac{\text{mitig. costs}_{t,r}}{\text{GDP}_{\text{gross},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. Note that for numerical stability, the constraint is not implemented as an equality constraint, but as an "almost-equality" constraint (called soft-equality constraint). This means that it is enough if the left-hand side (LHS) and right-hand side (RHS) are very close to each other (less than 0.5%):

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

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

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

    $$
    \\frac{\\text{mitig. costs}_{t,r}}{\\text{GDP}_{\\text{gross},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]: Note that for numerical stability, the constraint is not implemented as an equality constraint,
        but as an "almost-equality" constraint (called soft-equality constraint). This means that it is enough
        if the left-hand side (LHS) and right-hand side (RHS) are very close to each other (less than 0.5%):

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

    """

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

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

Usage:

params = load_params()
params["effort sharing"]["regime"] = "equal_total_costs"
model = MIMOSA(params)

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

\[ \frac{\text{mitig. costs}_{t,r}}{\text{GDP}_{\text{gross},t,r}} + \text{damages}_{t,r}\ (+ \text{rel. financial transf.}_{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. Note that for numerical stability, the constraint is not implemented as an equality constraint, but as an "almost-equality" constraint (called soft-equality constraint). This means that it is enough if the left-hand side (LHS) and right-hand side (RHS) are very close to each other (less than 0.5%):

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

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

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

    $$
    \\frac{\\text{mitig. costs}_{t,r}}{\\text{GDP}_{\\text{gross},t,r}} + \\text{damages}_{t,r}\\ (+ \\text{rel. financial transf.}_{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]: Note that for numerical stability, the constraint is not implemented as an equality constraint,
        but as an "almost-equality" constraint (called soft-equality constraint). This means that it is enough
        if the left-hand side (LHS) and right-hand side (RHS) are very close to each other (less than 0.5%):

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

    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.rel_mitigation_costs[t, r]
            + m.damage_costs[t, r]
            + m.rel_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["effort sharing"]["regime"] = "per_cap_convergence"
params["effort sharing"]["percapconv_year"] = 2050

# Per-capita convergence needs emission trading to avoid infeasibility
params["model"]["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 (current emission distribution) in 2020 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["effort sharing"]["regime"] = "per_cap_convergence"
params["effort sharing"]["percapconv_year"] = 2020  # Immediate per capita convergence
Grandfathering

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

params = load_params()
params["effort sharing"]["regime"] = "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["effort sharing"]["regime"] = "per_cap_convergence"
    params["effort sharing"]["percapconv_year"] = 2020  # Immediate per capita convergence
    ```

    #### 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["effort sharing"]["regime"] = "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 allowances per region are added as constraint on the regional emissions. Since this regime needs emission trading to avoid infeasibility, the regional emissions can be expressed as the baseline emissions minus the reductions that this region needs to pay for (this is not necessarily equal to the regional emissions in physical terms, as the region can buy or sell allowances from other regions):

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

    # Per-capita convergence needs emission trading to avoid infeasibility
    params["model"]["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 (current emission distribution) in 2020 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 allowances per region are added as constraint on the regional emissions. Since this regime needs
    [emission trading](emissiontrading.md) to avoid infeasibility, the regional emissions can be expressed as the baseline emissions
    minus the reductions that this region needs to pay for (this is not necessarily equal to the regional emissions
    in physical terms, as the region can buy or sell allowances from other regions):

    $$
    \\text{allowances}_{t,r} = \\text{baseline emissions}_{t,r} - \\text{paid for 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.baseline_emissions[0, r]
        / sum(m.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["effort sharing"]["regime"] = "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[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[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) -> Sequence[GeneralConstraint]:
    """
    Usage:
    ```python hl_lines="2"
    params = load_params()
    params["effort sharing"]["regime"] = "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[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[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["effort sharing"]["regime"] = "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) until the base year (default: 2020), and then discounted by a given rate:

\[ \text{debt}_{r} = \sum_{t=\text{start year}}^{2020} \left(\text{emissions}_{r,t} - \frac{\text{population}_{r,t}}{\text{emissions}_{r,t}\text{global population}_{t}} \cdot \text{global emissions}_{t}\right) \cdot e^{-\text{discount rate} \cdot (2020 - 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) until the base year (default: 2020), and then
    discounted by a given rate:

    $$
    \\text{debt}_{r} = \\sum_{t=\\text{start year}}^{2020} \\left(\\text{emissions}_{r,t} - \\frac{\\text{population}_{r,t}}{\\text{emissions}_{r,t}\\text{global population}_{t}} \\cdot \\text{global emissions}_{t}\\right) \\cdot e^{-\\text{discount rate} \\cdot (2020 - 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_start_year"]`](../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) -> Sequence[GeneralConstraint]:
    """
    Usage:
    ```python hl_lines="2"
    params = load_params()
    params["effort sharing"]["regime"] = "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",
        ),
    ]