Skip to content

LULUC modules

Currently only one module (SoilC) is included here, but additional modules are to be added to account for all land use and land use change related emissions associated with different scenarios.

SoilC

Module for estimating soil organic carbon stocks in mineral soils

The SoilC module uses the Introductory Carbon Balance Model (ICBM; Kätterer & Andrén, 2001) to estimate changes in soil organic carbon (SOC) stocks in mineral soils. This module is run after running the main model and data has been stored in the Session database.

SoilC implements the step-wise ICBM equations for the young (\(Y\)) and old (\(O\)) soil carbon pools as presented in Menichetti et al. (2024)

\[ Y_{t+1} = (Y_t + I_t) e^{-k_y re_t} \]
\[ O_{t+1} = (O_t - h \frac{k_y (Y_t+I_t)}{k_o - k_y}) e^{-k_o re_t} + h \frac{k_y (Y_t+I_t)}{k_o - k_y} e^{-k_y re_t} \]

where \(I_t\) is carbon input to the soil at year \(t\), \(h\) is the humification coefficient for the present carbon input, \(k_y\) and \(k_o\) are the decay rates for the young and old carbon pool respectively, and \(re_t\) is the environmental modifier at year \(t\).

The starting values (i.e. at \(t = 0\)) for the young and old pool (\(Y_0\) and \(O_0\)) are found by analytically solving the steady states (\(Y^*\) and \(O^*\)) assuming constant \(I=I_0\) and \(r=re_0\) equal to the the first year in the modelled scenario.

\[ Y^* = \frac{I_0 \times e^{-k_y re_0}}{1 - e^{-k_y * re_0}} \]
\[ O^* = h \frac{k_y \times I_0}{(k_o - k_y) (1 - e^{-k_y * re_0})} \times \frac{e^{-k_y * re_0} - e^{-k_o re_0}}{1 - e^{-k_o re_0}} \]

The SoilC module is instantiated with a ParameterRetriever and a Session object containing the scenarios to be modelled. The ICBM calculations are performed by first calling the .make_input() method, which gathers all the required inputs from the Session object (i.e. cropland areas and carbon inputs), followed by the .run_ICBM() method.

soil = cm.SoilC(
    par = cm.ParameterRetriever('SoilC'),
    session = my_session
)
soil.make_input()
soil.run_ICBM()

ICBM is run for each region and input separately on a per-hectare basis. Results are retrieved with the .get_data() method, where SOC stocks can be retrieved for separate inputs or aggregated to regional or national totals. The module can also calculate the CO2 flux associated with changes in SOC stocks via the .get_flux() method.

View Docstring
Signature:
SoilC(par: ParameterRetriever, session: Session)

Docstring:
Module that estimates soil organic carbon stock changes by collecting
soil carbon inputs from a Session object, calculating the environmental
modifier (re) and humification coefficients (h), and running the ICBM
model for each input source.
It also provides utilities to retrieve aggregated soil carbon stocks
and fluxes.

Parameters
----------
par : ParameterRetriever
session : Session

Attributes
----------
inputs : dict[str, str]
    Mapping from user-facing input names to session attribute keys.
agg_cols : list[str]
    Column levels used as the aggregation dimensions.
    Default is ["region"], and should likely not be changed.
lu : str
    Land-use category used throughout the class.
    Default is "cropland". May be changed if calculations are to
    be performed for another land-use category.
data_attr : DataAttr
    Container for derived model inputs and outputs.
par : ParameterRetriever
    Parameter access helper.
session : Session
    Session/database interface for retrieving source data.
crop_areas : pd.DataFrame
    Cropland area by aggregation dimensions and crop. Created by
    `.make_input()`.
total_area : pd.DataFrame
    Total cropland area aggregated over regions. Created by
    `.make_input()`.

File: CIBUSmod/LULUC_modules/soil_C.py

.make_input()

View Docstring
Signature:
SoilC.make_input(
    crop_residue_method: Literal['Bolinder', 'CIBUSmod']
)

Docstring:
Prepare ICBM input data in terms of re-values, C input and humification coefficients
for all input sources.

This method computes:

- crop areas and total land-use area
- aggregated environmental modifiers ``re``
- annual carbon inputs per hectare for each configured input source
- humification coefficients ``h`` for each input source

All generated datasets are stored in ``self.data_attr``.

Parameters
----------
crop_residue_method
    Method used to derive crop residue inputs. Must be either
    ``"Bolinder"`` or ``"CIBUSmod"``.

Returns
-------
None

File: CIBUSmod/LULUC_modules/soil_C.py

.run_ICBM()

View Docstring
Signature:
SoilC.run_ICBM(extend: int)

Docstring:
Run the ICBM model for all configured carbon input sources.

For each input source and scenario, this method simulates the young pool
``Y``, old pool ``O``, and total stock ``C = Y + O``. Results are stored
in ``.data_attr`` and can be retrieved with the methods ``.get_data()``
and ``.get_flux()``.

Parameters
----------
extend
    Number of additional years to append to the simulation using
    forward-filled input data. Defaults to ``0``.

Returns
-------
None

File: CIBUSmod/LULUC_modules/soil_C.py

.get_data()

View Docstring
Signature:
SoilC.get_data(
    pool: Literal['Y', 'O', 'C', 'C_in'],
    input_name: str,
    groupby: str | list[str] | dict[str, str | None] | None
)

Docstring:
Return per-hectare (kg C/ha) soil carbon stocks or inputs.

If ``"region"`` is supplied to ``groupby``, stocks or inputs are expressed
per hectare of total land use in each region. If region is not used to
group, stocks or inputs represent the area-weighted national value. As such,
the area-weighted national stock can increase even if all regional stocks
decrease if land use in regions with high stocks increase, and vice versa.
If other ``groupby`` levels are used, those represent the fraction of regional
or national stocks/inputs derived from that source.


Parameters
----------
pool
    Carbon pool to retrieve. Must be one of ``"Y"``, ``"O"``, ``"C"``,
    or ``"C_in"`` to retrieve carbon inputs to soils
input_name
    Input source to retrieve. Use ``"all"`` to aggregate across all
    configured input sources, or pass one of ``self.inputs``.
groupby
    Grouping specification for output aggregation.

    Supported forms are:

    - ``"none"`` or ``None``: return a total area-weighted Series
    - ``str``: group by one column level
    - ``list[str]``: group by multiple column levels
    - ``dict[str, str | None]``: group and optionally remap levels
      before aggregation; values of ``None`` mean no remapping

Returns
-------
pd.Series | pd.DataFrame
    Per-hectare Soil carbon stocks or inputs. A Series is returned
    when no grouping is requested; otherwise a DataFrame is returned.
    Results are expressed as kg C/ha of total land-use.

File: CIBUSmod/LULUC_modules/soil_C.py

.get_flux()

The flux (\(E\)) is calculated based on year-to-year changes in per-hectare SOC stock in each region multiplied by the total (crop)land use in the region to get the total flux of CO2 to and from the atmosphere

\[ E_{i,t} = -(SOC_{i,t} - SOC_{i,t-1})A_{i,t} \times (\frac{44}{12}) \]

where \(E_{i,t}\) is the flux of CO2 (kg CO2) for region \(i\) in year \(t\), \(SOC\) is the per-hectare SOC stock (kg C/ha), and \(A\) is the (crop)land area. The total national flux can then be obtain by summing all regional fluxes.

Note

Since the flux is calculated from per-hectare changes in SOC stocks in each region, and only after that multiplied by the area in each region, the flux will always be zero if per-hectare stocks are steady even if the national average SOC stock may change due to changes in regional areas (i.e. if area increase in a region with a high SOC stock, the national SOC stock will increase even if per-hectare stocks are constant across all regions).

View Docstring
Signature:
SoilC.get_flux(
    pool: Literal['Y', 'O', 'C'],
    input_name: str,
    groupby: str | list[str] | dict[str, str | None] | None,
    as_CO2: bool
)

Docstring:
Return flux derived from year-to-year changes in per-hectare stocks.

Flux is defined as the year-to-year change in stock density (kg C/ha)
within each region multiplied by the total land-use area in the same
region.

This means that pure changes in area do not create flux when per-hectare
stocks are constant.

Parameters
----------
pool
    Carbon pool to use. Must be one of ``"Y"``, ``"O"``, or ``"C"``.
input_name
    Input source to retrieve. Use ``"all"`` to aggregate across all
    configured input sources, or pass one of ``.inputs``.
groupby
    Grouping specification, interpreted in the same way as in
    `.get_data()`.

    Important:
    - flux is always computed at least at ``region`` level
    - if ``region`` is not included in the requested output grouping,
      regional fluxes are summed
as_CO2
    If ``True`` convert from kg C/year to kg CO2/year using ``44/12``.

Returns
-------
pd.Series | pd.DataFrame
    Flux time series. A Series is returned when no grouping is
    requested; otherwise a DataFrame is returned.

    Units are:
    - kg C/year if ``as_CO2=False``
    - kg CO2/year if ``as_CO2=True``

File: CIBUSmod/LULUC_modules/soil_C.py