4 CBM_core
This documentation is work in progress. Potential discrepancies and omissions may exist for the time being. If you find any, please contact us here.
4.1 Overview
CBM_core is the central module of spadesCBM. This is where all the carbon transfers are calculated at every time step, where disturbances are applied, and stocks are tracked. It cannot run on its own and it needs parameters from either CBM_defaults, CBM_dataPrep_SK, and CBM_vol2biomass_SK (as per the provided example for managed forests of Saskatchewan) or the equivalent information from the user. In SpaDES-speak, this module has five events (Init
, spinup
, annual
, accumulateResults
, and plot
). Only in two of these events do carbon transactions occur: spinup
and annual
. The other events are tools to enable these transactions. All events are scheduled only once except for the annual
event, who schedules itself until the end of the simulation horizon. Only in this module are the Python functions from the libcbm package called. The functions used in this module are the libcbm cbm-exn functions exclusively, as these were designed to accept external biomass increments. These Python functions are used in the spinup
and in the annual
events only.
4.2 Background
In CBM_core, the approach described in our Overview section is applied. Parameters are easily accessible via normal R-functions, and the SpaDES toolkit enables a modular, repeatable continuous workflow. This brings the transparency and flexibility needed for scientists to modify, evaluate and test new inputs, new data, and new algorithms while permitting non-researcher users to also use the system.
4.3 Inputs
Name | Class | Description | Source |
---|---|---|---|
growth_increments | Data table | growth increment matrix | CBM_vol2biomass_SK |
standDT | Data table | Table of stand attributes. Stands can have 1 or more cohorts | CBM_dataPrep_SK |
cohortDT | Data table | Table of cohort attributes | CBM_dataPrep_SK |
masterRaster | SpatRaster | Raster of study area | User provided, for SK: Google Drive |
gcMeta | Data table | Growth curve metadata | CBM_dataPrep_SK |
pooldef | Character | Vector of pools | CBM_defaults |
spinupSQL | Data table | Parameters for CBM_core spinup event | CBM_defaults |
disturbanceEvents | Data table | Table with disturbance events for each simulation year | CBM_dataPrep_SK |
disturbanceMeta | Data table | Table defining disturbance event types | CBM_dataPrep_SK |
4.4 Module functioning
4.4.1 Events
There are 5 events in CBM_core. Each are run once, except for the annual
event, which is repeated for each simulation year.
4.4.1.1 Init
In this short event, the Python virtual environment is set up. If a suitable version of python is not available, it will be installed using the reticulate
package.
4.4.1.2 spinup
The main goal of this event is to initialize the landscape by performing the spinup function.
Cohort and stand data is prepared and passed to the cbmExnSpinup
function alongside growth curve data (from CBM_vol2biomass_SK) and spinup default data (from CBM_defaults). The cbmExnSpinup
function sets up inputs, calls the cbm_exn_get_default_parameters
python function that defines the model structure, and runs the carbon transfers necessary for the growth and burn cycle using cbm_exn_spinup
.
The spinup output data and cohort groups are then prepared for use in the annual
event.
4.4.1.3 annual
This event is where all the carbon transfers are applied for each simulation year. Disturbances are matched to the correct records, and the transfers listed here are applied. Details on transfer rates are found in the following section, below. While undisturbed cohorts will continue to grow by one time step according to their associated growth curve, disturbed cohorts will only begin growing again after a delay period. This delay is dictated by the default_delay_regen
parameter of the CBM_core module, and can be changed by the user. Only growth-related carbon transfers are affected by this delay. By default it is set to 0 years.
4.4.1.4 accumulateResults
This event is where outputs are saved. In the case of our example in Saskatchewan, we output and save cbmPools and Net Primary Production (NPP) for each simulation year. If paths are kept at default when running the global script, these outputs will be found here: ~/GitHub/spadesCBM/outputs
.
4.4.1.5 plot
This final event is where all plotting occurs. Plots will be saved as .png
files in the project’s outputs folder. Similar to in accumulateResults
, if paths are kept at default when running our example global script, these outputs will be found here:
~/GitHub/spadesCBM/outputs
. You can also view examples of these plots here.
4.4.2 Stands and Cohort Groups
Cohort groups are unique combinations of age, growth curve (which equates to species as there is one growth curve per leading species in CBM), spatial unit and ecozone. In spadesCBM, forested pixels are simulated and represent a stand. Each stand (or pixel) can have one or many cohorts. All cohorts across stands that share an identical age, growth curve, spatial unit, and ecozone will share one unique cohortGroupID
number.
The object allPixDT
is a large table with a row corresponding to every pixel in the masterRaster
. The cohortDT
object is a long-form table where each simulated pixel (or stand) has its own row (no NAs), and cohortGroups
lists only the cohort groups and their attributes. In our example there are 1 347 529 pixels simulated (i.e., 1 347 529 rows in cohortDT
) which are grouped in 739 cohortGroups
for processing (i.e. 739 rows in cohortGroups
).
4.4.3 Carbon Transfers
Default parameters for simulations are available mainly from default .csv
files with a few pieces of information such as mean_annual_temperature
used in decay rates calculations, return_interval
, min_rotations
and max_rotations
used in the spinup
or initialization process available in an SQLight database. There are 18 internal carbon pools in spadesCBM (see Table 1 in Overview), and two pools that take carbon out of the system, one for the atmosphere and one for harvested wood exiting the system. Disturbances are the first carbon transfer to be applied to each record. Half the annual increment is then added (transfer from the atmosphere to the three above ground biomass pools - Merch
, Foliage
, and Other
). Disturbance inputs are processed externally to CBM_core. In our example disturbances are processed in CBM_dataPrep_SK, leaving CBM_core free of spatial data manipulations. Disturbance matrices specify the proportion of carbon in each pool to be transferred to other pools or to be taken out of the system (via forest products (pool named Products
) or back to the atmosphere). Figure 1 gives an example of transfers during a fire in Saskatchewan.
Figure 1: Proportional carbon transfers between pools during a fire in Saskatchewan

The amount of carbon transferred from the atmosphere to the above ground biomass pools is determined from the growth curves, which were translated from \(m^3/ha\) to carbon increments in CBM_vol2biomass_SK and provided to CBM_core in carbon increments (in tonnes of carbon/ha). In our example the object simMngedSK$growth_increments
has the increments used for the simulation. Dead Organic Matter (DOM) turnover happens next and transfers carbon from the pools representing snags (StemSnags
and BranchSnags
), to the MediumSoil
, and AboveGroundFastSoil
pools. Biomass turnover follows with transfers from the Merch
, Foliage
, Other
, FineRoots
and CoarseRoots
, to the pools representing the snags (StemSnags
and BranchSnags
), AboveGroundVeryFastSoil
, BelowGroundFastSoil
, AboveGroundVeryFastSoil
and BelowGroundVeryFastSoil pools
. Carbon is never lost in the system, but increments are at times negative. To accommodate negative increment values, a carbon transfer labelled overmature_decline
, moves carbon between the Merch
, Other
, Foliage
, CoarseRoots
and FineRoots
to pools representing stem an branch snags, and the AboveGroundFastSoil
, AboveGroundVeryFastSoil
, BelowGroundFastSoil
, and BelowGroundVeryFastSoil
pools. The transfers are portioned in the same way as the annual turnover and the amount is equal to the loss of each individual biomass pool according to the negative increment. Following the overmature_decline
transfers, the second half of the growth is added to the three above ground biomass pools - Merch
, Foliage
, and Other
. Next, the transfers due to decay are performed. Applied decay rates (\(a_k\)) are calculated for each DOM pool(\(_k\)) as per Equation 1 (see Kurz et al. (2009)).
Equation 1. \(a_k = D_k * TempMod * StandMod\)
Where:
\(D_k\) is the base decay rate (yr−1) at a reference mean annual temperature (\(RefTemp\)).
\(TempMod\) is a temperature modifier, as per Equation 2, and \(StandMod\) is a stand modifier as per Equation 3 (Kurz & App (1999)).
Equation 2,
TempMod = \(e^{((MAT_i -RefTemp) * ln(Q_{10}) * 0.1)}\)
Where:
\(MAT_i\) is the mean annual temperature of each spatial analysis unit.
\(RefTemp\) is the reference mean annual temperature.
\(Q_{10}\) is a temperature coefficient.
Equation 3.
\(StandMod = 1+(max_r - 1) * e^{(-b * TotBio/MaxBio)}\)
Where:
\(max_r\) is the open canopy decay rate multiplier (default value of 1).
\(TotBio\) is the total aboveground biomass, \(MaxBio\) is the maximum aboveground biomass for the specified stand type, and
\(b\) is a reduction factor calculated such that at 10% of maximum biomass, decomposition rates are reduce by 50% (set at 6.93 see Kurz & App (1999)).
The default values for base decay rate (\(D_k\)), \(RefTemp\), \(Q_10\) and \(max_r\) for spadesCBM simulations are found here.
The final carbon transfers represents the physical transfer rate from the above- to belowground slow pool and is set at of 0.006 yr−1 (slowmixing
) is based on the transfer rate for dissolved organic C reported in the literature for some Canadian forest soils (Moore (2003)).
The amount of carbon in the CoarseRoots
and FineRoots
pools depends on the carbon in the three above ground pools that absorb carbon from the atmosphere, Merch
, Other
, and Foliage
. The total root biomass is estimated using empirical equations, one set of equations for hardwood (Equation 4, 6, 7, 9) and one for softwood species (Equation 5, 6, 8, 10) (Kurz et al. (2009), Li (2003)).
Equation 4.
\(T_{hw} = hw_a * ((Merch_{hw} + Foliage_{hw} + Other_{hw}) * 2)^{hw_b}\)
Equation 5.
\(T_{sw} = sw_a * ((Merch_{sw} + Foliage_{sw} + Other_{sw}) * 2)\)
Equation 6.
\(P_{fine} = frp_a + frp_b * e^{((-1/frp_c)*(T_{hw} + T_{sw}))}\)
Equation 7.
\(FineRoots_{hw} = T_{hw} * P_{fine}\)
Equation 8.
\(FineRoots_{sw} = T_{sw} * P_{fine}\)
Equation 9.
\(CoarseRoots_{hw} = T_{hw} * (1-P_{fine})\)
Equation 10.
\(CoarseRoots_{sw} = T_{sw} * (1-P_{fine})\)
On-going work to improve CBM is targeting all DOM related parameters. Hararuk (2017) used data assimilation methods which brought improvements to the turnover rates to the FineRoots
pool, but no change to the CoarseRoots
pool. The allocation of carbon between above ground biomass (Merch
, Foliage
, and Other
) to the roots (FineRoots
, CoarseRoots
) implemented in CBM dates from the model development (Kurz et al. (2009), Li (2003)). Other methods for estimating below ground biomass from above ground have been implement to estimate carbon elsewhere (example Harris (2021)), and a user would be justified in wanting to explore the effects of changing these parameters (Błońska (2022)). In this R-based environment implementation and improvement of CBM, a user is free to change any of the parameters provided to the cbm_exn_spinup()
and cbm_exn_step()
Python functions.
4.5 Outputs
CBM_core provides outputs as prescribed in the global script, the script that controls simulations. We make use of the function SpaDES.project::setupProject. While it is possible to develop a SpaDES project using different methods more familiar to the user, the SpaDES.project package streamlines this process, facilitating a clean, reproducible and reusable project setup for any project. In our example, we specify in the globalSK.R
script that we want NPP
and cbmPools
saved every year (lines 54-56). A user could specify outputs for any pools (see Table 1 in Overview). A user can also chose the outputs they would like to see from all objects in the simList. For example, a user my have interest in the quantity (in tonnes of carbon) of forest products and emissions existing the system. Our simList is named simMngedSK
(line 61 of our global script globalSK.R
), so the object of interest would be simMngedSK$emissionsProducts
.
Note that CBM, like CBM-CFS3, does not simulate photosynthesis or autotrophic respiration. Therefore, NPP is calculated as the sum of net growth (i.e., growth that results in positive increment) and growth that replaces material lost to biomass turnover during the year. In young, actively growing stands, a large proportion of NPP results in positive growth increment while in older, mature stands, a larger proportion of NPP is allocated to replacement of material lost to turnover.
Name | Class | Description |
---|---|---|
spinupInput | Data table | input parameters for the spinup functions |
spinupResults | Data frame | Pools post spinup in order of pixelGroup |
cbm_vars | List | List of 4 data tables: parameters, pools, flux, and state |
cohortGroupKeep | Data table | Key connecting ‘cohortID’ with current and previous cohortGroupID
|
cbmPools | Data table | Cohort groups and pools after each simulation year (or as prescribed if the simulations are very long) |
NPP | Data table | Net primary production per cohort group |
emissionsProducts | matrix | Total emissions and products for study area per simulation year |