Skip to content

Pathway Allocation Functions

Pathway allocation functions generate annual emission allocation shares over time.

Overview

All pathway allocation approaches return a PathwayAllocationResult containing:

  • approach: Name of the allocation approach used
  • parameters: Dictionary of parameters used in the calculation
  • relative_shares_pathway_emissions: DataFrame of annual shares (sum to 1.0 each year)

Per Capita Pathways

equal_per_capita

fair_shares.library.allocations.pathways.per_capita.equal_per_capita

Python
equal_per_capita(
    population_ts: TimeseriesDataFrame,
    first_allocation_year: int,
    emission_category: str,
    preserve_first_allocation_year_shares: bool = False,
    group_level: str = "iso3c",
    unit_level: str = "unit",
    ur: PlainRegistry = get_default_unit_registry(),
) -> PathwayAllocationResult

Equal per capita pathway allocation based on population shares.

Allocates emissions in proportion to population, with no adjustments for historical responsibility or economic capability.

Mathematical Foundation

Mode 1: Dynamic shares (preserve_first_allocation_year_shares=False, default)

Population shares are calculated at each year from first_allocation_year onwards. This accounts for changes in relative population shares over time:

\[ A(g, t) = \frac{P(g, t)}{\sum_{g'} P(g', t)} \]

Where:

  • \(A(g, t)\): Allocation share for country \(g\) at year \(t\)
  • \(P(g, t)\): Population of country \(g\) at year \(t\)
  • \(\sum_{g'} P(g', t)\): Total world population at year \(t\)

Mode 2: Preserved shares (preserve_first_allocation_year_shares=True)

Population shares calculated at the first_allocation_year are preserved across all periods. This means the relative allocation between groups remains constant:

\[ A(g, t) = \frac{P(g, t_a)}{\sum_{g'} P(g', t_a)} \quad \forall t \geq t_a \]

Where:

  • \(A(g, t)\): Allocation share for country \(g\) at year \(t\) (constant for all \(t \geq t_a\))
  • \(P(g, t_a)\): Population of country \(g\) at first allocation year \(t_a\)
  • \(\sum_{g'} P(g', t_a)\): Total world population at first allocation year

Parameters:

Name Type Description Default
population_ts TimeseriesDataFrame

Population time series for each group of interest.

required
first_allocation_year int

First year that should be used for calculating the allocation. This must be a column in population_ts. See docs/science/parameter-effects.md#allocation_year for how this affects country shares

required
emission_category str

Emission category to include in the output.

required
preserve_first_allocation_year_shares bool

If False (default), shares are calculated at each year from first_allocation_year onwards. If True, shares calculated at the first_allocation_year are preserved across all periods.

False
group_level str

Index level name for grouping (typically 'iso3c'). Default: 'iso3c'

'iso3c'
unit_level str

Index level name for units. Default: 'unit'

'unit'
ur PlainRegistry

Pint unit registry for unit conversions.

get_default_unit_registry()

Returns:

Type Description
PathwayAllocationResult

Relative shares over time, summing to unity each year.

Notes

The equal per capita principle treats the atmosphere as a finite shared resource with equal claims per person. It serves as a widely used baseline in climate equity analysis.

When to Use

  • As a baseline to compare against adjusted approaches
  • When transparency and simplicity are priorities
  • As a reference point before applying responsibility or capability adjustments

See docs/science/allocations.md for theoretical grounding and limitations.

Examples:

Python Console Session
>>> from fair_shares.library.utils import create_example_data
>>> data = create_example_data()
>>> result = equal_per_capita(
...     population_ts=data["population"],
...     first_allocation_year=2020,
...     emission_category="co2-ffi",
... )
Converting units...
>>> # Check that shares sum to 1.0 at each year
>>> shares = result.relative_shares_pathway_emissions
>>> shares_2020 = shares["2020"]
>>> bool(abs(shares_2020.sum() - 1.0) < 1e-10)
True
>>> # China and India have similar populations, so similar shares
>>> bool(shares_2020.loc["CHN"].item() > 0.3)  # China has large population
True
>>> bool(shares_2020.loc["IND"].item() > 0.3)  # India has large population too
True
See Also

per_capita_adjusted : With pre-allocation responsibility/capability adjustments per_capita_adjusted_gini : With Gini-adjusted GDP

per_capita_adjusted

fair_shares.library.allocations.pathways.per_capita.per_capita_adjusted

Python
per_capita_adjusted(
    population_ts: TimeseriesDataFrame,
    first_allocation_year: int,
    emission_category: str,
    country_actual_emissions_ts: (
        TimeseriesDataFrame | None
    ) = None,
    gdp_ts: TimeseriesDataFrame | None = None,
    pre_allocation_responsibility_weight: float = 0.0,
    capability_weight: float = 0.0,
    pre_allocation_responsibility_year: int = 1990,
    pre_allocation_responsibility_per_capita: bool = True,
    pre_allocation_responsibility_exponent: float = 1.0,
    pre_allocation_responsibility_functional_form: str = "asinh",
    capability_per_capita: bool = True,
    capability_exponent: float = 1.0,
    capability_functional_form: str = "asinh",
    max_deviation_sigma: float | None = 2.0,
    preserve_first_allocation_year_shares: bool = False,
    historical_discount_rate: float = 0.0,
    group_level: str = "iso3c",
    unit_level: str = "unit",
    ur: PlainRegistry = get_default_unit_registry(),
) -> PathwayAllocationResult

Per capita pathway allocation with pre-allocation responsibility and capability adjustments.

Extends equal per capita by incorporating:

  • Responsibility adjustment: Countries with higher historical emissions receive smaller allocations
  • Capability adjustment: Countries with higher GDP (per capita or absolute) receive smaller allocations
Mathematical Foundation

Mode 1: Dynamic adjusted shares (preserve_first_allocation_year_shares=False, default)

Shares are computed by adjusting population at each year:

\[ A(g, t) = \frac{P_{\text{adj}}(g, t)}{\sum_{g'} P_{\text{adj}}(g', t)} \]

Where the adjusted population is:

\[ P_{\text{adj}}(g, t) = P(g, t) \times R(g) \times C(g, t) \]

Where:

  • \(A(g, t)\): Allocation share for country \(g\) at year \(t\)
  • \(P_{\text{adj}}(g, t)\): Adjusted population of country \(g\) at year \(t\)
  • \(P(g, t)\): Actual population of country \(g\) at year \(t\)
  • \(R(g)\): Responsibility adjustment factor (constant over time, equals 1.0 if not used)
  • \(C(g, t)\): Capability adjustment factor (time-varying, equals 1.0 if not used)

Mode 2: Preserved adjusted shares (preserve_first_allocation_year_shares=True)

Shares calculated at first_allocation_year are broadcast across all years.

Responsibility Adjustment

The responsibility metric is based on cumulative historical emissions from pre_allocation_responsibility_year to first_allocation_year.

For per capita responsibility (:code:pre_allocation_responsibility_per_capita=True, default):

\[ R(g) = \left(\frac{\sum_{t=t_h}^{t_a} E(g, t)}{\sum_{t=t_h}^{t_a} P(g, t)}\right)^{-w_r \times e_r} \]

Where:

  • \(R(g)\): Responsibility adjustment factor (inverse - higher emissions = lower allocation)
  • \(E(g, t)\): Emissions of country \(g\) in year \(t\)
  • \(t_h\): Historical responsibility start year
  • \(t_a\): First allocation year
  • \(w_r\): Normalized responsibility weight
  • \(e_r\): Responsibility exponent

For absolute responsibility (:code:pre_allocation_responsibility_per_capita=False):

\[ R(g) = \left(\sum_{t=t_h}^{t_a} E(g, t)\right)^{-w_r \times e_r} \]

Capability Adjustment

The capability metric is based on cumulative GDP per capita from first_allocation_year up to year :math:t.

For per capita capability (:code:capability_per_capita=True, default):

\[ C(g, t) = \left(\frac{\sum_{t'=t_a}^{t} \text{GDP}(g, t')}{\sum_{t'=t_a}^{t} P(g, t')}\right)^{-w_c \times e_c} \]

Where:

  • \(C(g, t)\): Capability adjustment factor (inverse - higher cumulative GDP per capita = lower allocation)
  • \(\text{GDP}(g, t')\): Gross domestic product of country \(g\) in year \(t'\)
  • \(w_c\): Normalized capability weight
  • \(e_c\): Capability exponent

For absolute capability (:code:capability_per_capita=False):

\[ C(g, t) = \left(\sum_{t'=t_a}^{t} \text{GDP}(g, t')\right)^{-w_c \times e_c} \]

Deviation Constraint

When :code:max_deviation_sigma is provided, shares are constrained to prevent extreme deviations from equal per capita. The constraint limits allocations to within :math:\sigma standard deviations of the equal per capita baseline.

Parameters:

Name Type Description Default
population_ts TimeseriesDataFrame

Population time series for per capita calculations.

required
first_allocation_year int

Starting year for the allocation. See docs/science/parameter-effects.md#allocation_year for how this affects country shares

required
emission_category str

The emission category (e.g., 'co2-ffi', 'all-ghg').

required
country_actual_emissions_ts TimeseriesDataFrame | None

Country emissions for responsibility calculation. Required if pre_allocation_responsibility_weight > 0.

None
gdp_ts TimeseriesDataFrame | None

GDP time series for capability adjustment. Required if capability_weight > 0.

None
pre_allocation_responsibility_weight float

Weight for responsibility adjustment (0-1). Higher historical emissions -> smaller allocation. Must satisfy: pre_allocation_responsibility_weight + capability_weight <= 1.0 See docs/science/parameter-effects.md#pre_allocation_responsibility_weight for real allocation examples showing how this affects country shares

0.0
capability_weight float

Weight for capability adjustment (0-1). Higher cumulative GDP per capita -> smaller allocation. Must satisfy: pre_allocation_responsibility_weight + capability_weight <= 1.0 See docs/science/parameter-effects.md#capability_weight for real allocation examples showing how this affects country shares

0.0
pre_allocation_responsibility_year int

First year of responsibility window [pre_allocation_responsibility_year, first_allocation_year]. Default: 1990

1990
pre_allocation_responsibility_per_capita bool

If True, use per capita emissions for responsibility. Default: True

True
pre_allocation_responsibility_exponent float

Exponent for responsibility adjustment calculation. Default: 1.0

1.0
pre_allocation_responsibility_functional_form str

Functional form for responsibility adjustment ('asinh', 'power', 'linear'). Default: 'asinh'

'asinh'
capability_exponent float

Exponent for capability adjustment calculation. Default: 1.0

1.0
capability_functional_form str

Functional form for capability adjustment ('asinh', 'power', 'linear'). Default: 'asinh'

'asinh'
max_deviation_sigma float | None

Maximum allowed deviation from equal per capita baseline. Constrains allocations to remain within a statistically reasonable range of the equal per capita baseline, preventing extreme adjustments. If None, no constraint is applied.

2.0
preserve_first_allocation_year_shares bool

If False (default), shares are calculated at each year. If True, shares calculated at first_allocation_year are preserved across all periods.

False
historical_discount_rate float

Discount rate for historical emissions (0.0 to <1.0). When > 0, earlier emissions are weighted less via (1 - rate)^(reference_year - t). Implements natural CO2 removal rationale (Dekker Eq. 5). Default: 0.0 (no discounting).

0.0
group_level str

Index level name for grouping (typically 'iso3c'). Default: 'iso3c'

'iso3c'
unit_level str

Index level name for units. Default: 'unit'

'unit'
ur PlainRegistry

Pint unit registry for unit conversions.

get_default_unit_registry()

Returns:

Type Description
PathwayAllocationResult

Relative shares over time, summing to unity each year.

Notes

This approach operationalizes Common But Differentiated Responsibilities and Respective Capabilities (CBDR-RC) by combining:

  • Historical Responsibility (Polluter Pays Principle): Adjusts allocations based on cumulative historical emissions — countries that contributed more to the problem bear greater obligations
  • Capability (Ability to Pay Principle): Adjusts based on economic resources — countries with greater capacity bear greater obligations

Parameter choices involve normative judgments that should be made transparently:

  • Choice of start year for historical responsibility
  • Whether to use per capita or absolute metrics
  • Choice of GDP indicator (PPP vs. MER)
  • Transformation of indicators onto allocation scales

See docs/science/allocations.md for theoretical grounding.

Examples:

Python Console Session
>>> from fair_shares.library.utils import create_example_data
>>> data = create_example_data()
>>> # Equal weights for responsibility and capability (50/50 split)
>>> result = per_capita_adjusted(
...     population_ts=data["population"],
...     country_actual_emissions_ts=data["emissions"],
...     gdp_ts=data["gdp"],
...     first_allocation_year=2020,
...     emission_category="co2-ffi",
...     pre_allocation_responsibility_weight=0.5,
...     capability_weight=0.5,
... )
Converting units...
>>> # Check that shares sum to 1.0
>>> shares = result.relative_shares_pathway_emissions
>>> shares_2020 = shares["2020"]
>>> bool(abs(shares_2020.sum() - 1.0) < 1e-10)
True
>>> # High emitters like USA should have smaller shares than equal per capita
>>> equal_pc_result = equal_per_capita(
...     population_ts=data["population"],
...     first_allocation_year=2020,
...     emission_category="co2-ffi",
... )
Converting units...
>>> equal_pc_shares = equal_pc_result.relative_shares_pathway_emissions["2020"]
>>> # USA has lower share with adjustments due to high historical emissions + GDP
>>> bool(shares_2020.loc["USA"].item() < equal_pc_shares.loc["USA"].item())
True
See Also

equal_per_capita : Without adjustments per_capita_adjusted_gini : With Gini-adjusted GDP

per_capita_adjusted_gini

fair_shares.library.allocations.pathways.per_capita.per_capita_adjusted_gini

Python
per_capita_adjusted_gini(
    population_ts: TimeseriesDataFrame,
    first_allocation_year: int,
    emission_category: str,
    country_actual_emissions_ts: (
        TimeseriesDataFrame | None
    ) = None,
    gdp_ts: TimeseriesDataFrame | None = None,
    gini_s: DataFrame | None = None,
    pre_allocation_responsibility_weight: float = 0.0,
    capability_weight: float = 0.0,
    pre_allocation_responsibility_year: int = 1990,
    pre_allocation_responsibility_per_capita: bool = True,
    pre_allocation_responsibility_exponent: float = 1.0,
    pre_allocation_responsibility_functional_form: str = "asinh",
    capability_per_capita: bool = True,
    capability_exponent: float = 1.0,
    capability_functional_form: str = "asinh",
    income_floor: float = 7500.0,
    max_gini_adjustment: float = 0.8,
    max_deviation_sigma: float | None = 2.0,
    preserve_first_allocation_year_shares: bool = False,
    historical_discount_rate: float = 0.0,
    group_level: str = "iso3c",
    unit_level: str = "unit",
    ur: PlainRegistry = get_default_unit_registry(),
) -> PathwayAllocationResult

Per capita pathway allocation with pre-allocation responsibility, capability, and Gini adjustments.

The most comprehensive variant, incorporating:

  • Responsibility adjustment: Countries with higher historical emissions receive smaller allocations
  • Capability adjustment: Countries with higher Gini-adjusted GDP (per capita or absolute) receive smaller allocations
  • Gini adjustment: GDP is adjusted for income inequality within countries
Mathematical Foundation

Similar to :func:per_capita_adjusted, but capability uses Gini-adjusted GDP to account for income inequality within countries.

Gini Adjustment Process

GDP is adjusted using an interpretation of the Greenhouse Development Rights (GDR) framework's capability metric (note: GDR was designed for burden-sharing; fair-shares adapts its capability calculation for entitlement allocation). Only income above a development threshold counts as capability. When combined with the income floor, higher inequality means more national income sits above the threshold — increasing measured capability. See :func:~fair_shares.library.utils.math.allocation.calculate_gini_adjusted_gdp for the full mathematical derivation.

Capability Adjustment with Gini-Adjusted GDP

For per capita capability (:code:capability_per_capita=True, default):

\[ C(g, t) = \left(\frac{\sum_{t'=t_a}^{t} \text{GDP}^{\text{adj}}(g, t')}{\sum_{t'=t_a}^{t} P(g, t')}\right)^{-w_c \times e_c} \]

Where:

  • \(C(g, t)\): Capability adjustment factor using Gini-adjusted GDP
  • \(\text{GDP}^{\text{adj}}(g, t')\): Gini-adjusted GDP in year \(t'\)
  • \(P(g, t')\): Population in year \(t'\)
  • \(t_a\): First allocation year
  • \(w_c\): Normalized capability weight
  • \(e_c\): Capability exponent

For absolute capability (:code:capability_per_capita=False):

\[ C(g, t) = \left(\sum_{t'=t_a}^{t} \text{GDP}^{\text{adj}}(g, t')\right)^{-w_c \times e_c} \]

Gini Adjustment Effect

When combined with the income floor, higher inequality means more national income sits above the development threshold, creating larger per-person excesses. Countries with high inequality and high GDP thus receive smaller emission allocations (higher measured capability = more ability to pay). See :func:~fair_shares.library.utils.math.allocation.calculate_gini_adjusted_gdp for worked examples.

Parameters:

Name Type Description Default
population_ts TimeseriesDataFrame

Population time series for per capita calculations.

required
first_allocation_year int

Starting year for the allocation. See docs/science/parameter-effects.md#allocation_year for how this affects country shares

required
emission_category str

The emission category (e.g., 'co2-ffi', 'all-ghg').

required
country_actual_emissions_ts TimeseriesDataFrame | None

Country emissions for responsibility calculation. Required if pre_allocation_responsibility_weight > 0.

None
gdp_ts TimeseriesDataFrame | None

GDP time series for capability adjustment. Required if capability_weight > 0 or gini_s provided.

None
gini_s DataFrame | None

Gini coefficients for GDP inequality adjustment. When provided, GDP is adjusted to reflect income distribution within countries.

None
pre_allocation_responsibility_weight float

Weight for responsibility adjustment (0-1). Must satisfy: pre_allocation_responsibility_weight + capability_weight <= 1.0

0.0
capability_weight float

Weight for capability adjustment (0-1). Must satisfy: pre_allocation_responsibility_weight + capability_weight <= 1.0

0.0
pre_allocation_responsibility_year int

First year of responsibility window. Default: 1990

1990
pre_allocation_responsibility_per_capita bool

If True, use per capita emissions for responsibility. Default: True

True
pre_allocation_responsibility_exponent float

Exponent for responsibility adjustment calculation. Default: 1.0

1.0
pre_allocation_responsibility_functional_form str

Functional form for responsibility adjustment. Default: 'asinh'

'asinh'
capability_exponent float

Exponent for capability adjustment calculation. Default: 1.0

1.0
capability_functional_form str

Functional form for capability adjustment. Default: 'asinh'

'asinh'
income_floor float

Income floor for Gini adjustment (in USD PPP per capita). Income below this threshold is excluded from capability calculations, adapted from the Greenhouse Development Rights (GDR) development threshold [Baer 2013] (GDR was designed for burden-sharing; fair-shares uses its capability metric in an entitlement allocation context). Default: 7500.0 See docs/science/parameter-effects.md#income_floor for real allocation examples showing how this affects country shares

7500.0
max_gini_adjustment float

Maximum reduction factor from GDR threshold adjustment (0-1). Limits how much the development threshold deduction can reduce effective GDP. Default: 0.8

0.8
max_deviation_sigma float | None

Maximum allowed deviation from equal per capita baseline. Constrains allocations to remain within a statistically reasonable range of the equal per capita baseline, preventing extreme adjustments. If None, no constraint is applied.

2.0
preserve_first_allocation_year_shares bool

If False (default), shares are calculated at each year. If True, shares calculated at first_allocation_year are preserved across all periods.

False
historical_discount_rate float

Discount rate for historical emissions (0.0 to <1.0). When > 0, earlier emissions are weighted less via (1 - rate)^(reference_year - t). Implements natural CO2 removal rationale (Dekker Eq. 5). Default: 0.0 (no discounting).

0.0
group_level str

Index level name for grouping (typically 'iso3c'). Default: 'iso3c'

'iso3c'
unit_level str

Index level name for units. Default: 'unit'

'unit'
ur PlainRegistry

Pint unit registry for unit conversions.

get_default_unit_registry()

Returns:

Type Description
PathwayAllocationResult

Relative shares over time, summing to unity each year.

Notes

This approach extends capability-based allocation by incorporating intra-national inequality via the GDR development threshold (adapted for entitlement allocation from GDR's burden-sharing context). Only income above the development threshold counts toward capability. When combined with the income floor, higher inequality means more national income sits above the threshold. See :func:~fair_shares.library.utils.math.allocation.calculate_gini_adjusted_gdp for the mathematical formulation.

When to Use

  • When capability assessment should account for income distribution within countries
  • When the development threshold (income floor) should affect capability measurement
  • For comprehensive allocation incorporating population, historical responsibility, and inequality-adjusted capability

See docs/science/allocations.md for theoretical grounding.

Examples:

Python Console Session
>>> from fair_shares.library.utils import create_example_data
>>> data = create_example_data()
>>> # Equal weights with Gini adjustment
>>> result = per_capita_adjusted_gini(
...     population_ts=data["population"],
...     country_actual_emissions_ts=data["emissions"],
...     gdp_ts=data["gdp"],
...     gini_s=data["gini"],
...     first_allocation_year=2020,
...     emission_category="co2-ffi",
...     pre_allocation_responsibility_weight=0.5,
...     capability_weight=0.5,
... )
Converting units...
>>> # Check that shares sum to 1.0
>>> shares = result.relative_shares_pathway_emissions
>>> shares_2020 = shares["2020"]
>>> bool(abs(shares_2020.sum() - 1.0) < 1e-10)
True
>>> # Verify approach is correctly identified
>>> result.approach
'per-capita-adjusted-gini'
>>> # Verify all countries have valid shares (between 0 and 1)
>>> bool((shares_2020 >= 0).all() and (shares_2020 <= 1).all())
True
>>> # Compare to non-Gini version - shares will differ due to inequality adjustment
>>> result_no_gini = per_capita_adjusted(
...     population_ts=data["population"],
...     country_actual_emissions_ts=data["emissions"],
...     gdp_ts=data["gdp"],
...     first_allocation_year=2020,
...     emission_category="co2-ffi",
...     pre_allocation_responsibility_weight=0.5,
...     capability_weight=0.5,
... )
Converting units...
>>> shares_no_gini = result_no_gini.relative_shares_pathway_emissions["2020"]
>>> # Gini adjustment changes the allocation pattern
>>> bool(not shares_2020.equals(shares_no_gini))
True
See Also

equal_per_capita : Without adjustments per_capita_adjusted : Without Gini adjustment

Convergence Pathways

per_capita_convergence

fair_shares.library.allocations.pathways.per_capita_convergence.per_capita_convergence

Python
per_capita_convergence(
    population_ts: TimeseriesDataFrame,
    country_actual_emissions_ts: TimeseriesDataFrame,
    first_allocation_year: int,
    convergence_year: int,
    emission_category: str,
    group_level: str = "iso3c",
    unit_level: str = "unit",
    ur: PlainRegistry = get_default_unit_registry(),
) -> PathwayAllocationResult

Per capita convergence pathway blending grandfathering and equal per capita.

This approach transitions from grandfathering (GF) to equal per capita (EPC) from allocation time, \(t_{a}\), to convergence time, \(t_{conv}\), using a linear weight \(M(t)\). It implements a variant of Contraction and Convergence [GCI 2003], where global emissions contract while per capita emissions converge to equality by a target date.

Mathematical Foundation

Baseline Shares at Allocation Time

Grandfathering and equal per capita shares at allocation time are calculated as:

\[ \mathrm{GF}(g) = \frac{E(g, t_{a})}{\sum_{g'} E(g', t_{a})} \]
\[ \mathrm{EPC}(g) = \frac{P(g, t_{a})}{\sum_{g'} P(g', t_{a})} \]

Where:

  • \(E(g, t_{a})\): Emissions of country \(g\) at first allocation year \(t_a\)
  • \(P(g, t_{a})\): Population of country \(g\) at first allocation year \(t_a\)

Time-Dependent Blending Weight

The transition weight \(M(t)\) controls the blend between grandfathering and equal per capita:

  • \(M(t) = 1\) for \(t \le t_{a}\) (full grandfathering at start)
  • \(M(t) = \frac{t_{conv} - t}{t_{conv} - t_{a}}\) for \(t_{a} < t < t_{conv}\)
  • \(M(t) = 0\) for \(t \ge t_{conv}\) (full equal per capita at convergence)

Blended Allocation

The final allocation blends the two principles:

\[ A(g, t) = M(t) \cdot \mathrm{GF}(g) + (1 - M(t)) \cdot \mathrm{EPC}(g) \]

Parameters:

Name Type Description Default
population_ts TimeseriesDataFrame

Timeseries of population for each group of interest.

required
country_actual_emissions_ts TimeseriesDataFrame

Timeseries of emissions for each group of interest.

required
first_allocation_year int

First year that should be used for calculating the allocation. This must be a column in both population and emissions.

required
convergence_year int

Year by which allocations fully converge to equal per capita.

required
emission_category str

Emission category to include in the output.

required
group_level str

Level in index specifying group information. Default: 'iso3c'

'iso3c'
unit_level str

Level in index specifying units. Default: 'unit'

'unit'
ur PlainRegistry

The unit registry to use for calculations.

get_default_unit_registry()

Returns:

Type Description
PathwayAllocationResult

Container with relative shares for pathway emissions allocation. The TimeseriesDataFrame contains all years from first_allocation_year onwards with shares that sum to 1 across groups for the specified emission category.

Notes

When to Use

  • Academic comparison with Contraction and Convergence scenarios
  • Exploring sensitivity of allocations to transition period length
  • When a gradual transition from status quo is explicitly desired

Limitations

  • Does not incorporate historical responsibility for past emissions
  • Does not incorporate capability/ability to pay
  • The grandfathering starting point lacks ethical basis (see referenced docs)

For allocations grounded in CBDR-RC principles, consider using per_capita_adjusted or cumulative_per_capita_convergence approaches.

Examples:

Calculate per capita convergence allocation transitioning from current emission shares to equal per capita shares over a 30-year period.

Python Console Session
>>> from fair_shares.library.utils import create_example_data
>>> data = create_example_data(
...     countries=["USA", "CHN", "IND"], years=[2020, 2030, 2050]
... )
>>> result = per_capita_convergence(
...     population_ts=data["population"],
...     country_actual_emissions_ts=data["emissions"],
...     first_allocation_year=2020,
...     convergence_year=2050,
...     emission_category="co2-ffi",
... )
>>> result.approach
'per-capita-convergence'
>>> result.parameters["convergence_year"]
2050
>>> # Result contains relative shares that blend from current emissions
>>> # (grandfathering) at 2020 to equal per capita at 2050
>>> result.relative_shares_pathway_emissions.sum(axis=0).round(3)
2020    1.000
2030    1.000
2050    1.000
dtype: float64
See Also

per_capita_adjusted : Equal per capita with pre-allocation responsibility/capability adjustments cumulative_per_capita_convergence : Convergence accounting for cumulative emissions

cumulative_per_capita_convergence

fair_shares.library.allocations.pathways.cumulative_per_capita_convergence.cumulative_per_capita_convergence

Python
cumulative_per_capita_convergence(
    population_ts: TimeseriesDataFrame,
    country_actual_emissions_ts: TimeseriesDataFrame,
    first_allocation_year: int,
    emission_category: str,
    world_scenario_emissions_ts: TimeseriesDataFrame,
    max_deviation_sigma: float | None = 2.0,
    max_convergence_speed: float = 0.9,
    strict: bool = True,
    historical_start_year: int | None = None,
    convergence_method: str = "minimum-speed",
    convergence_year: int | None = None,
    group_level: str = "iso3c",
    unit_level: str = "unit",
    ur: PlainRegistry = get_default_unit_registry(),
) -> PathwayAllocationResult

Pure cumulative per capita convergence allocation without adjustments.

Allocates emissions based on cumulative population shares, converging from initial emission shares to cumulative per capita targets over time.

Mathematical Foundation

Convergence Dynamics

The allocation shares evolve through exponential convergence:

\[ A(g, t+1) = A(g, t) + \lambda \big(A^{\infty}(g) - A(g, t)\big) \]

Where:

  • \(A(g, t)\): Allocation share for country \(g\) at year \(t\)
  • \(A^{\infty}(g)\): Long-run target share that each year converges toward
  • \(\lambda\): Convergence speed (automatically determined to be minimum feasible)

Initial Shares

Initial shares at first_allocation_year are based on actual emissions:

\[ A(g, t_a) = \frac{E(g, t_a)}{\sum_{g'} E(g', t_a)} \]

Where:

  • \(A(g, t_a)\): Initial allocation share for country \(g\) at first allocation year
  • \(E(g, t_a)\): Actual emissions of country \(g\) at year \(t_a\)
  • \(t_a\): First allocation year
  • \(\sum_{g'} E(g', t_a)\): Total world emissions at first allocation year

Cumulative Target Shares

The cumulative target shares are based on cumulative population:

\[ T_{\text{cum}}(g) = \frac{\sum_{t \geq t_a} P(g, t)}{\sum_{g'} \sum_{t \geq t_a} P(g', t)} \]

Where:

  • \(T_{\text{cum}}(g)\): Cumulative target share for country \(g\)
  • \(P(g, t)\): Population of country \(g\) at year \(t\)
  • \(\sum_{t \geq t_a} P(g, t)\): Cumulative population of country \(g\) from allocation year onwards
  • \(\sum_{g'} \sum_{t \geq t_a} P(g', t)\): Total cumulative world population from allocation year onwards

Convergence Speed Determination

The convergence speed \(\lambda\) is automatically determined to be the minimum speed that ensures cumulative allocations match targets:

\[ \sum_{t \geq t_a} w(t) \, A(g, t) = T_{\text{cum}}(g) \]

Where:

  • \(w(t)\): Year weight for year \(t\), defined as \(w(t) = \frac{W(t)}{\sum_{t' \geq t_a} W(t')}\)
  • \(W(t)\): World emissions in year \(t\) from the scenario pathway

Deviation Constraint

When :code:max_deviation_sigma is provided, cumulative target shares are constrained to prevent extreme deviations from equal cumulative per capita:

\[ T_{\text{equal}}(g) - \sigma \, s \leq T_{\text{cum}}(g) \leq T_{\text{equal}}(g) + \sigma \, s \]

Where:

  • \(T_{\text{equal}}(g)\): Equal cumulative per capita baseline share
  • \(\sigma\): Maximum deviation parameter (e.g., 2.0 standard deviations)
  • \(s\): Population-weighted standard deviation of unconstrained cumulative targets

Parameters:

Name Type Description Default
population_ts TimeseriesDataFrame

Population time series for calculating cumulative per capita shares.

required
country_actual_emissions_ts TimeseriesDataFrame

Country emissions for calculating initial shares at first_allocation_year.

required
world_scenario_emissions_ts TimeseriesDataFrame

World emissions pathway defining the time horizon and year weights.

required
first_allocation_year int

Starting year for the allocation.

required
emission_category str

The emission category (e.g., 'co2-ffi', 'all-ghg').

required
max_deviation_sigma float | None

Maximum allowed deviation from equal per capita baseline in terms of population-weighted standard deviations. If provided, constrains each group's share to be within ±max_deviation_sigma standard deviations from the baseline equal per capita share. If None, no constraint is applied.

2.0
max_convergence_speed float

Maximum allowed convergence speed (0 to 1.0). Lower values create smoother pathways but may become infeasible. Default: 0.9.

0.9
strict bool

If True (default), raise error for infeasible convergence. If False, use nearest feasible solution with warnings.

True
historical_start_year int | None

If provided, cumulative population for target shares is computed from this year instead of first_allocation_year. Must be <= first_allocation_year. Shifts entitlements toward historically populous countries (e.g. China, India pre-industrial) when early start years like 1850 are used. Default: None (use first_allocation_year).

None
convergence_method str

Convergence algorithm to use. "minimum-speed" (default): exponential convergence with binary-search for minimum feasible speed. "sine-deviation" (Dekker Eqs. 7-8): iterative sine-shaped correction from a PCC baseline; requires convergence_year.

'minimum-speed'
convergence_year int | None

Year by which allocations converge to equal per capita. Required when convergence_method='sine-deviation'. Must be > first_allocation_year. Default: None.

None
group_level str

Index level name for grouping (typically 'iso3c'). Default: 'iso3c'

'iso3c'
unit_level str

Index level name for units. Default: 'unit'

'unit'
ur PlainRegistry

Pint unit registry for unit conversions.

get_default_unit_registry()

Returns:

Type Description
PathwayAllocationResult

Relative shares over time, summing to unity each year.

See Also

cumulative_per_capita_convergence_adjusted : With pre-allocation responsibility/capability adjustments cumulative_per_capita_convergence_adjusted_gini : With Gini-adjusted GDP

Notes

Theoretical grounding:

For theoretical foundations, use cases, and limitations, see: docs/science/allocations.md#convergence-mechanism-theoretical-foundations

For translating the egalitarian tradition (which grounds the equal per capita principle) into pathway allocations, see: docs/science/principle-to-code.md#convergence-pathway-approaches

For CBDR-RC principles (responsibility and capability), use cumulative_per_capita_convergence_adjusted or cumulative_per_capita_convergence_adjusted_gini.

Convergence Speed

The convergence speed is automatically determined to be the minimum speed that ensures cumulative targets are met, creating the smoothest possible transition path while still achieving equity goals. The strict parameter controls whether an error is raised if exact targets cannot be achieved.

Examples:

Basic usage with default parameters:

Python Console Session
>>> from fair_shares.library.utils import create_example_data
>>> from fair_shares.library.allocations.pathways import (
...     cumulative_per_capita_convergence,
... )
>>> # Create example data
>>> data = create_example_data(
...     countries=["USA", "CHN", "IND"], years=[2020, 2030, 2050]
... )
>>> # Run allocation with strict=False for limited time horizon
>>> result = cumulative_per_capita_convergence(
...     population_ts=data["population"],
...     country_actual_emissions_ts=data["emissions"],
...     world_scenario_emissions_ts=data["world_emissions"],
...     first_allocation_year=2020,
...     emission_category="co2-ffi",
...     strict=False,  # Accept approximate targets with limited data
... )
Converting units...
>>> # Check approach is correct
>>> result.approach
'cumulative-per-capita-convergence'
>>> # Shares sum to 1.0 at each year
>>> shares = result.relative_shares_pathway_emissions
>>> bool(abs(shares["2020"].sum() - 1.0) < 1e-10)
True

Adjust convergence behavior with strict=False for approximate targets:

Python Console Session
>>> result_approx = cumulative_per_capita_convergence(
...     population_ts=data["population"],
...     country_actual_emissions_ts=data["emissions"],
...     world_scenario_emissions_ts=data["world_emissions"],
...     first_allocation_year=2020,
...     emission_category="co2-ffi",
...     strict=False,  # Accept approximate targets
...     max_convergence_speed=0.5,  # Slower, smoother convergence
... )
Converting units...
>>> # Check for warnings about deviations
>>> if result_approx.country_warnings:
...     print("Some targets approximate:", result_approx.country_warnings)

Remove deviation constraints for unconstrained targets:

Python Console Session
>>> result_unconstrained = cumulative_per_capita_convergence(
...     population_ts=data["population"],
...     country_actual_emissions_ts=data["emissions"],
...     world_scenario_emissions_ts=data["world_emissions"],
...     first_allocation_year=2020,
...     emission_category="co2-ffi",
...     max_deviation_sigma=None,  # No constraints on target shares
...     strict=False,  # Needed for limited data
... )
Converting units...

cumulative_per_capita_convergence_adjusted

fair_shares.library.allocations.pathways.cumulative_per_capita_convergence.cumulative_per_capita_convergence_adjusted

Python
cumulative_per_capita_convergence_adjusted(
    population_ts: TimeseriesDataFrame,
    country_actual_emissions_ts: TimeseriesDataFrame,
    first_allocation_year: int,
    emission_category: str,
    world_scenario_emissions_ts: TimeseriesDataFrame,
    gdp_ts: TimeseriesDataFrame | None = None,
    pre_allocation_responsibility_weight: float = 0.0,
    capability_weight: float = 0.0,
    pre_allocation_responsibility_year: int = 1990,
    pre_allocation_responsibility_per_capita: bool = True,
    pre_allocation_responsibility_exponent: float = 1.0,
    pre_allocation_responsibility_functional_form: str = "asinh",
    capability_per_capita: bool = True,
    capability_exponent: float = 1.0,
    capability_functional_form: str = "asinh",
    max_deviation_sigma: float | None = 2.0,
    max_convergence_speed: float = 0.9,
    strict: bool = True,
    historical_start_year: int | None = None,
    historical_discount_rate: float = 0.0,
    convergence_method: str = "minimum-speed",
    convergence_year: int | None = None,
    group_level: str = "iso3c",
    unit_level: str = "unit",
    ur: PlainRegistry = get_default_unit_registry(),
) -> PathwayAllocationResult

Cumulative per capita convergence with pre-allocation responsibility and capability adjustments.

Extends cumulative per capita convergence by incorporating:

  • Responsibility adjustment: Countries with higher historical emissions receive smaller allocations
  • Capability adjustment: Countries with higher GDP receive smaller allocations
Mathematical Foundation

Convergence Dynamics

The allocation shares evolve through exponential convergence (same as base approach):

\[ A(g, t+1) = A(g, t) + \lambda \big(A^{\infty}(g) - A(g, t)\big) \]

Where:

  • \(A(g, t)\): Allocation share for country \(g\) at year \(t\)
  • \(A^{\infty}(g)\): Long-run target share
  • \(\lambda\): Convergence speed (automatically determined)

Initial shares at first_allocation_year are based on actual emissions.

Cumulative Target Shares with Adjustments

Target shares are computed by adjusting cumulative population for historical responsibility and economic capability:

\[ T_{\text{cum}}(g) = \frac{P_{\text{adj}}(g)}{\sum_{g'} P_{\text{adj}}(g')} \]

Where the adjusted population is:

\[ P_{\text{adj}}(g) = P_{\text{cum}}(g) \times R(g) \times C(g) \]

Where:

  • \(T_{\text{cum}}(g)\): Cumulative target share for country \(g\)
  • \(P_{\text{adj}}(g)\): Adjusted cumulative population
  • \(P_{\text{cum}}(g) = \sum_{t \geq t_a} P(g, t)\): Cumulative population from allocation year onwards
  • \(R(g)\): Responsibility adjustment factor (equals 1.0 if not used)
  • \(C(g)\): Capability adjustment factor (equals 1.0 if not used)

Responsibility Adjustment

The responsibility metric is based on cumulative historical emissions from pre_allocation_responsibility_year to first_allocation_year.

For per capita responsibility (:code:pre_allocation_responsibility_per_capita=True, default):

\[ R(g) = \left(\frac{\sum_{t=t_h}^{t_a} E(g, t)}{\sum_{t=t_h}^{t_a} P(g, t)}\right)^{-w_r \times e_r} \]

Where:

  • \(R(g)\): Responsibility adjustment factor (inverse - higher emissions = lower allocation)
  • \(E(g, t)\): Emissions of country \(g\) in year \(t\)
  • \(t_h\): Historical responsibility start year
  • \(t_a\): First allocation year
  • \(w_r\): Normalized responsibility weight
  • \(e_r\): Responsibility exponent

For absolute responsibility (:code:pre_allocation_responsibility_per_capita=False):

\[ R(g) = \left(\sum_{t=t_h}^{t_a} E(g, t)\right)^{-w_r \times e_r} \]

Capability Adjustment

The capability metric is based on cumulative GDP from first_allocation_year onwards.

For per capita capability (:code:capability_per_capita=True, default):

\[ C(g) = \left(\frac{\sum_{t \geq t_a} \text{GDP}(g, t)}{\sum_{t \geq t_a} P(g, t)}\right)^{-w_c \times e_c} \]

Where:

  • \(C(g)\): Capability adjustment factor (inverse - higher cumulative GDP per capita = lower allocation)
  • \(\text{GDP}(g, t)\): Gross domestic product of country \(g\) in year \(t\)
  • \(w_c\): Normalized capability weight
  • \(e_c\): Capability exponent

For absolute capability (:code:capability_per_capita=False):

\[ C(g) = \left(\sum_{t \geq t_a} \text{GDP}(g, t)\right)^{-w_c \times e_c} \]

Deviation Constraint

When :code:max_deviation_sigma is provided, adjusted cumulative target shares are constrained to prevent extreme deviations from equal cumulative per capita.

Parameters:

Name Type Description Default
population_ts TimeseriesDataFrame

Population time series for per capita calculations and responsibility adjustment.

required
country_actual_emissions_ts TimeseriesDataFrame

Country emissions for initial shares and responsibility calculation.

required
world_scenario_emissions_ts TimeseriesDataFrame

World emissions pathway defining time horizon and year weights.

required
first_allocation_year int

Starting year for the allocation.

required
emission_category str

The emission category (e.g., 'co2-ffi', 'all-ghg').

required
gdp_ts TimeseriesDataFrame | None

GDP time series for capability adjustment. Required if capability_weight > 0.

None
pre_allocation_responsibility_weight float

Weight for responsibility adjustment (0-1). Higher historical emissions -> smaller allocation. Must satisfy: pre_allocation_responsibility_weight + capability_weight <= 1.0

0.0
capability_weight float

Weight for capability adjustment (0-1). Higher GDP -> smaller allocation. Applies from the first allocation year onwards (contrast with pre-allocation responsibility, which looks backward from it). Requires gdp_ts. Must satisfy: pre_allocation_responsibility_weight + capability_weight <= 1.0

0.0
pre_allocation_responsibility_year int

First year of responsibility window [pre_allocation_responsibility_year, first_allocation_year]. Default: 1990

1990
pre_allocation_responsibility_per_capita bool

If True, use per capita emissions for responsibility. Default: True

True
pre_allocation_responsibility_exponent float

Exponent for responsibility adjustment calculation. Default: 1.0

1.0
pre_allocation_responsibility_functional_form str

Functional form for responsibility adjustment ('asinh', 'power', 'linear'). Default: 'asinh'

'asinh'
capability_per_capita bool

If True, use per capita GDP for capability. Default: True

True
capability_exponent float

Exponent for capability adjustment calculation. Default: 1.0

1.0
capability_functional_form str

Functional form for capability adjustment ('asinh', 'power', 'linear'). Default: 'asinh'

'asinh'
max_deviation_sigma float | None

Maximum allowed deviation from equal per capita baseline in terms of population-weighted standard deviations. If None, no constraint is applied.

2.0
max_convergence_speed float

Maximum allowed convergence speed (0 to 1.0). Lower values create smoother pathways but may become infeasible. Default: 0.9

0.9
strict bool

If True (default), raise error for infeasible convergence. If False, use nearest feasible solution with warnings.

True
historical_start_year int | None

If provided, cumulative population for target shares is computed from this year instead of first_allocation_year. Must be <= first_allocation_year. Shifts entitlements toward historically populous countries. Default: None (use first_allocation_year).

None
historical_discount_rate float

Discount rate for historical emissions (0.0 to <1.0). When > 0, earlier emissions are weighted less via (1 - rate)^(reference_year - t). Implements natural CO2 removal rationale (Dekker Eq. 5). Default: 0.0 (no discounting).

0.0
convergence_method str

Convergence algorithm to use. "minimum-speed" (default): exponential convergence with binary-search for minimum feasible speed. "sine-deviation" (Dekker Eqs. 7-8): iterative sine-shaped correction from a PCC baseline; requires convergence_year.

'minimum-speed'
convergence_year int | None

Year by which allocations converge to equal per capita. Required when convergence_method='sine-deviation'. Must be > first_allocation_year. Default: None.

None
group_level str

Index level name for grouping (typically 'iso3c'). Default: 'iso3c'

'iso3c'
unit_level str

Index level name for units. Default: 'unit'

'unit'
ur PlainRegistry

Pint unit registry for unit conversions.

get_default_unit_registry()

Returns:

Type Description
PathwayAllocationResult

Relative shares over time, summing to unity each year.

See Also

cumulative_per_capita_convergence : Without adjustments cumulative_per_capita_convergence_adjusted_gini : With Gini-adjusted GDP

Notes

Theoretical grounding:

For theoretical foundations and CBDR-RC principles, see: docs/science/allocations.md#convergence-mechanism-theoretical-foundations docs/science/allocations.md#4-common-but-differentiated-responsibilities-cbdr-rc

For translating equity principles into pathway allocations, see: docs/science/principle-to-code.md#convergence-pathway-approaches docs/science/principle-to-code.md#cbdr-rc

This approach incorporates historical responsibility and capability adjustments to operationalize Common But Differentiated Responsibilities and Respective Capabilities (CBDR-RC). Higher past emissions and higher GDP -> smaller allocation.

Examples:

Basic usage with equal responsibility and capability weights:

Python Console Session
>>> from fair_shares.library.utils import create_example_data
>>> from fair_shares.library.allocations.pathways import (
...     cumulative_per_capita_convergence_adjusted,
... )
>>> # Create example data
>>> data = create_example_data(
...     countries=["USA", "CHN", "IND"], years=[2020, 2030, 2050]
... )
>>> # Run allocation with adjustments and strict=False for limited data
>>> result = cumulative_per_capita_convergence_adjusted(
...     population_ts=data["population"],
...     country_actual_emissions_ts=data["emissions"],
...     world_scenario_emissions_ts=data["world_emissions"],
...     gdp_ts=data["gdp"],
...     first_allocation_year=2020,
...     emission_category="co2-ffi",
...     pre_allocation_responsibility_weight=0.5,  # 50% adjustment for historical emissions
...     capability_weight=0.5,  # 50% adjustment for GDP
...     strict=False,  # Accept approximate targets with limited data
... )
Converting units...
>>> # Check results - high emitters get less than pure per-capita
>>> result.approach
'cumulative-per-capita-convergence-adjusted'
>>> # Shares sum to 1.0 at each year
>>> shares = result.relative_shares_pathway_emissions
>>> bool(abs(shares["2020"].sum() - 1.0) < 1e-10)
True

Adjust convergence speed for smoother pathways:

Python Console Session
>>> result_smooth = cumulative_per_capita_convergence_adjusted(
...     population_ts=data["population"],
...     country_actual_emissions_ts=data["emissions"],
...     world_scenario_emissions_ts=data["world_emissions"],
...     gdp_ts=data["gdp"],
...     first_allocation_year=2020,
...     emission_category="co2-ffi",
...     pre_allocation_responsibility_weight=0.3,
...     capability_weight=0.3,
...     max_convergence_speed=0.5,
...     strict=False,
... )
Converting units...
>>> # Check for warnings if targets couldn't be met exactly
>>> if result_smooth.country_warnings:
...     print("Approximate targets:", result_smooth.country_warnings)

Emphasize responsibility over capability:

Python Console Session
>>> result_responsibility = cumulative_per_capita_convergence_adjusted(
...     population_ts=data["population"],
...     country_actual_emissions_ts=data["emissions"],
...     world_scenario_emissions_ts=data["world_emissions"],
...     gdp_ts=data["gdp"],
...     first_allocation_year=2020,
...     emission_category="co2-ffi",
...     pre_allocation_responsibility_weight=0.7,
...     capability_weight=0.3,
...     strict=False,
... )
Converting units...
>>> # Historical emitters penalized more than in equal-weight case
>>> result_responsibility.parameters["pre_allocation_responsibility_weight"]
0.7

cumulative_per_capita_convergence_adjusted_gini

fair_shares.library.allocations.pathways.cumulative_per_capita_convergence.cumulative_per_capita_convergence_adjusted_gini

Python
cumulative_per_capita_convergence_adjusted_gini(
    population_ts: TimeseriesDataFrame,
    country_actual_emissions_ts: TimeseriesDataFrame,
    first_allocation_year: int,
    emission_category: str,
    world_scenario_emissions_ts: TimeseriesDataFrame,
    gdp_ts: TimeseriesDataFrame | None = None,
    gini_s: DataFrame | None = None,
    pre_allocation_responsibility_weight: float = 0.0,
    capability_weight: float = 0.0,
    pre_allocation_responsibility_year: int = 1990,
    pre_allocation_responsibility_per_capita: bool = True,
    pre_allocation_responsibility_exponent: float = 1.0,
    pre_allocation_responsibility_functional_form: str = "asinh",
    capability_per_capita: bool = True,
    capability_exponent: float = 1.0,
    capability_functional_form: str = "asinh",
    income_floor: float = 7500.0,
    max_gini_adjustment: float = 0.8,
    max_deviation_sigma: float | None = 2.0,
    max_convergence_speed: float = 0.9,
    strict: bool = True,
    historical_start_year: int | None = None,
    historical_discount_rate: float = 0.0,
    convergence_method: str = "minimum-speed",
    convergence_year: int | None = None,
    group_level: str = "iso3c",
    unit_level: str = "unit",
    ur: PlainRegistry = get_default_unit_registry(),
) -> PathwayAllocationResult

Cumulative per capita convergence with Gini-adjusted GDP and full adjustments.

The most comprehensive variant, incorporating:

  • Responsibility adjustment: Countries with higher historical emissions receive smaller allocations
  • Capability adjustment: Countries with higher GDP receive smaller allocations
  • Gini adjustment: GDP is adjusted for income inequality within countries
Mathematical Foundation

Convergence Dynamics

The allocation shares evolve through exponential convergence (same as base approach):

\[ A(g, t+1) = A(g, t) + \lambda \big(A^{\infty}(g) - A(g, t)\big) \]

Where:

  • \(A(g, t)\): Allocation share for country \(g\) at year \(t\)
  • \(A^{\infty}(g)\): Long-run target share
  • \(\lambda\): Convergence speed (automatically determined)

Initial shares at first_allocation_year are based on actual emissions.

Cumulative Target Shares with Adjustments

Target shares are computed by adjusting cumulative population for historical responsibility and Gini-adjusted economic capability:

\[ T_{\text{cum}}(g) = \frac{P_{\text{adj}}(g)}{\sum_{g'} P_{\text{adj}}(g')} \]

Where the adjusted population is:

\[ P_{\text{adj}}(g) = P_{\text{cum}}(g) \times R(g) \times C_{\text{Gini}}(g) \]

Where:

  • \(T_{\text{cum}}(g)\): Cumulative target share for country \(g\)
  • \(P_{\text{adj}}(g)\): Adjusted cumulative population
  • \(P_{\text{cum}}(g) = \sum_{t \geq t_a} P(g, t)\): Cumulative population from allocation year onwards
  • \(R(g)\): Responsibility adjustment factor (equals 1.0 if not used)
  • \(C_{\text{Gini}}(g)\): Gini-adjusted capability factor (equals 1.0 if not used)

Gini Adjustment Process

GDP is adjusted using an interpretation of the Greenhouse Development Rights (GDR) framework's capability metric (note: GDR was designed for burden-sharing; fair-shares adapts its capability calculation for entitlement allocation). Only income above a development threshold counts as capability. When combined with the income floor, higher inequality means more national income sits above the threshold — increasing measured capability. See :func:~fair_shares.library.utils.math.allocation.calculate_gini_adjusted_gdp for the full mathematical derivation.

Responsibility Adjustment

Identical to adjusted convergence (see that function for details).

For per capita responsibility (:code:pre_allocation_responsibility_per_capita=True, default):

\[ R(g) = \left(\frac{\sum_{t=t_h}^{t_a} E(g, t)}{\sum_{t=t_h}^{t_a} P(g, t)}\right)^{-w_r \times e_r} \]

Where:

  • \(E(g, t)\): Emissions of country \(g\) in year \(t\)
  • \(t_h\): Historical responsibility start year
  • \(t_a\): First allocation year
  • \(w_r\): Normalized responsibility weight
  • \(e_r\): Responsibility exponent

Capability Adjustment with Gini-Adjusted GDP

The capability metric uses Gini-adjusted GDP to account for income inequality.

For per capita capability (:code:capability_per_capita=True, default):

\[ C_{\text{Gini}}(g) = \left(\frac{\sum_{t \geq t_a} \text{GDP}^{\text{adj}}(g, t)}{\sum_{t \geq t_a} P(g, t)}\right)^{-w_c \times e_c} \]

Where:

  • \(C_{\text{Gini}}(g)\): Gini-adjusted capability factor (inverse - higher adjusted GDP = lower allocation)
  • \(\text{GDP}^{\text{adj}}(g, t)\): Gini-adjusted GDP in year \(t\)
  • \(w_c\): Normalized capability weight
  • \(e_c\): Capability exponent

For absolute capability (:code:capability_per_capita=False):

\[ C_{\text{Gini}}(g) = \left(\sum_{t \geq t_a} \text{GDP}^{\text{adj}}(g, t)\right)^{-w_c \times e_c} \]

Gini Adjustment Effect

When combined with the income floor, higher inequality means more national income sits above the development threshold, creating larger per-person excesses. Countries with high inequality and high GDP thus receive smaller emission allocations (higher measured capability = more ability to pay). See :func:~fair_shares.library.utils.math.allocation.calculate_gini_adjusted_gdp for worked examples.

Deviation Constraint

When :code:max_deviation_sigma is provided, adjusted cumulative target shares are constrained to prevent extreme deviations from equal cumulative per capita.

Parameters:

Name Type Description Default
population_ts TimeseriesDataFrame

Population time series for per capita calculations and responsibility adjustment.

required
country_actual_emissions_ts TimeseriesDataFrame

Country emissions for initial shares and responsibility calculation.

required
world_scenario_emissions_ts TimeseriesDataFrame

World emissions pathway defining time horizon and year weights.

required
first_allocation_year int

Starting year for the allocation.

required
emission_category str

The emission category (e.g., 'co2-ffi', 'all-ghg').

required
gdp_ts TimeseriesDataFrame | None

GDP time series for capability adjustment. Required if capability_weight > 0 or gini_s provided.

None
gini_s DataFrame | None

Gini coefficients for GDP inequality adjustment. When provided, GDP is adjusted to reflect income distribution within countries.

None
pre_allocation_responsibility_weight float

Weight for responsibility adjustment (0-1). Higher historical emissions -> smaller allocation. Must satisfy: pre_allocation_responsibility_weight + capability_weight <= 1.0

0.0
capability_weight float

Weight for capability adjustment (0-1). Higher GDP -> smaller allocation. Applies from the first allocation year onwards (contrast with pre-allocation responsibility, which looks backward from it). Requires gdp_ts. Must satisfy: pre_allocation_responsibility_weight + capability_weight <= 1.0

0.0
pre_allocation_responsibility_year int

First year of responsibility window [pre_allocation_responsibility_year, first_allocation_year]. Default: 1990

1990
pre_allocation_responsibility_per_capita bool

If True, use per capita emissions for responsibility. Default: True

True
pre_allocation_responsibility_exponent float

Exponent for responsibility adjustment calculation. Default: 1.0

1.0
pre_allocation_responsibility_functional_form str

Functional form for responsibility adjustment ('asinh', 'power', 'linear'). Default: 'asinh'

'asinh'
capability_per_capita bool

If True, use per capita GDP for capability. Default: True

True
capability_exponent float

Exponent for capability adjustment calculation. Default: 1.0

1.0
capability_functional_form str

Functional form for capability adjustment ('asinh', 'power', 'linear'). Default: 'asinh'

'asinh'
income_floor float

Income floor for Gini adjustment (in USD). Income below this threshold is excluded from capability calculations. Default: 7500.0

7500.0
max_gini_adjustment float

Maximum reduction factor from GDR threshold adjustment (0-1). Limits how much the development threshold deduction can reduce effective GDP. Default: 0.8

0.8
max_deviation_sigma float | None

Maximum allowed deviation from equal per capita baseline in terms of population-weighted standard deviations. If None, no constraint is applied.

2.0
max_convergence_speed float

Maximum allowed convergence speed (0 to 1.0). Lower values create smoother pathways but may become infeasible. Default: 0.9

0.9
strict bool

If True (default), raise error for infeasible convergence. If False, use nearest feasible solution with warnings.

True
historical_start_year int | None

If provided, cumulative population for target shares is computed from this year instead of first_allocation_year. Must be <= first_allocation_year. Shifts entitlements toward historically populous countries. Default: None (use first_allocation_year).

None
historical_discount_rate float

Discount rate for historical emissions (0.0 to <1.0). When > 0, earlier emissions are weighted less via (1 - rate)^(reference_year - t). Implements natural CO2 removal rationale (Dekker Eq. 5). Default: 0.0 (no discounting).

0.0
convergence_method str

Convergence algorithm to use. "minimum-speed" (default): exponential convergence with binary-search for minimum feasible speed. "sine-deviation" (Dekker Eqs. 7-8): iterative sine-shaped correction from a PCC baseline; requires convergence_year.

'minimum-speed'
convergence_year int | None

Year by which allocations converge to equal per capita. Required when convergence_method='sine-deviation'. Must be > first_allocation_year. Default: None.

None
group_level str

Index level name for grouping (typically 'iso3c'). Default: 'iso3c'

'iso3c'
unit_level str

Index level name for units. Default: 'unit'

'unit'
ur PlainRegistry

Pint unit registry for unit conversions.

get_default_unit_registry()

Returns:

Type Description
PathwayAllocationResult

Relative shares over time, summing to unity each year.

See Also

cumulative_per_capita_convergence : Without adjustments cumulative_per_capita_convergence_adjusted : Without Gini adjustment

Notes

Theoretical grounding:

For theoretical foundations, intra-national equity, and Gini adjustment rationale, see: docs/science/allocations.md#convergence-mechanism-theoretical-foundations docs/science/allocations.md#gini-adjustment-for-within-country-inequality

For translating equity principles into pathway allocations, see: docs/science/principle-to-code.md#convergence-pathway-approaches docs/science/principle-to-code.md#subsistence-protection

This approach extends the adjusted convergence method by incorporating Gini-adjusted GDP to account for income inequality within countries. The income_floor parameter implements the subsistence vs. luxury emissions distinction. When combined with the income floor, higher inequality means more national income sits above the threshold — increasing measured capability.

Examples:

Basic usage with Gini-adjusted GDP:

Python Console Session
>>> from fair_shares.library.utils import create_example_data
>>> from fair_shares.library.allocations.pathways import (
...     cumulative_per_capita_convergence_adjusted_gini,
... )
>>> # Create example data
>>> data = create_example_data(
...     countries=["USA", "CHN", "BRA"], years=[2020, 2030, 2050]
... )
>>> # Run allocation with Gini adjustment
>>> result = cumulative_per_capita_convergence_adjusted_gini(
...     population_ts=data["population"],
...     country_actual_emissions_ts=data["emissions"],
...     world_scenario_emissions_ts=data["world_emissions"],
...     gdp_ts=data["gdp"],
...     gini_s=data["gini"],
...     first_allocation_year=2020,
...     emission_category="co2-ffi",
...     pre_allocation_responsibility_weight=0.5,  # 50% adjustment for historical emissions
...     capability_weight=0.5,  # 50% adjustment for Gini-adjusted GDP
... )
Converting units...
>>> # Check results - Gini adjustment included
>>> result.approach
'cumulative-per-capita-convergence-gini-adjusted'

Adjust Gini parameters to control inequality weighting:

Python Console Session
>>> # Custom Gini parameters
>>> result_custom_gini = (
...     cumulative_per_capita_convergence_adjusted_gini(
...         population_ts=data["population"],
...         country_actual_emissions_ts=data["emissions"],
...         world_scenario_emissions_ts=data["world_emissions"],
...         gdp_ts=data["gdp"],
...         gini_s=data["gini"],
...         first_allocation_year=2020,
...         emission_category="co2-ffi",
...         pre_allocation_responsibility_weight=0.3,
...         capability_weight=0.3,
...         income_floor=5000.0,  # Lower income floor
...         max_gini_adjustment=0.9,  # Allow stronger inequality adjustment
...         max_convergence_speed=0.5,  # Slower convergence
...         strict=False,  # Accept approximate targets if exact infeasible
...     )
... )
Converting units...
>>> # With income floor, high inequality means more income above threshold
>>> result_custom_gini.approach
'cumulative-per-capita-convergence-gini-adjusted'

See Also