Overview
This documentation is work in progress. Potential discrepancies and omissions may exist for the time being. If you find any, contact us here.
spadesCBM is a modular, transparent, and spatially explicit implementation of the logic, pools structure, equations, and default assumptions of the Carbon Budget Model of the Canadian Forest Sector (CBM). It applies the science presented in Kurz et al. (2009) in a similar way to the simulations in Boisvenue et al. (2016) and Boisvenue et al. (2022) but calls Python functions for annual processes (see libcbm_py/examples/cbm_exn). These functions and spadesCBM are, like much of modelling-based science, continuously under development.
The collection of SpaDES modules in spadesCBM was developed to enable R&D input to the Canadian Forest Service (CFS) forest carbon reporting system, NFCMARS. The CFS provides science backing for Canadian policies on national forest issues. spadesCBM is a nimble tool in which new science, data and algorithms can be tested and explored to serve policy purposes. spadesCBM development follows the PERFICT approach of McIntire et al. (2022) for ecological modelling systems. The SpaDES platform is the toolkit that enables this implementation of the PERFICT principle, a recipe to build nimble systems that help solve many ecological modelling issues.
0.1 Usage
Four modules need to be run in tandem for a spadesCBM simulation.
The first module, CBM_defaults, reads in defaults CBM parameters for Canada.
The second module, CBM_dataPrep_SK, is a data preparation SpaDES module, where input data and spatial layers are assembled and prepared for a specific study area. The CBM_dataPrep_SK module will be study-area and scenario specific.
Throughout this manual we use an example simulation of forest carbon dynamics for the managed forests of SK from 1985-2012 similarly to the simulations in Boisvenue et al. (2016), where the *_SK* indicates the study area.
In spadesCBM, as in CBM, growth curves (\(m^3/ha\)) are the main change-agent.
The CBM_vol2biomass module translates user-provided stand-level growth curves (\(m^3/ha\)) into increments for specific above ground carbon pools (metric tonnes of carbon/ha) using Boudewyn et al. (2007) models (leading species specific) to which we added a smoothing algorithm to fill-in the gap between age 0 and the age at which growth curves have data.
Note that CBM_vol2biomass is also study-area specific, as Boudewyn et al. (2007) parameters are dominant species and ecozone specific.
CBM_defaults, CBM_dataPrep_SK, and CBM_vol2biomass all have one event (init
), and need to be run only once (note that they will be cached in our example).
These three modules provide the inputs to the CBM_core module, where carbon-transfers between pools are applied on a specified time step (in our example, yearly).
This modularity enables users to access and change default parameters, change inputs, connect to external modules that modify the landscape, and assess the impact of these changes.
We are working on various implementations of this modelling system and making these available to the community in the Preditive Ecology GitHub repository.
We hope others will do the same.
A smaller study area extent simulation of spadesCBM is available in the SpaDES training manual.
Maybe we insert a moduleDiagram
?
Several core utilities to spadesCBM are provided by the CBMutils
package, available on GitHub. Active development in CBMutils
and all spadesCBM modules is underway.
0.2 The Carbon Budget Model in SpaDES
The Carbon Budget Model (CBM) was first developed in the early 1990s (Kurz et al. (1993)). Its implementation in a platform for model inter-operability and nimbleness such as SpaDES warrants an overview.
spadesCBM simulates forest carbon dynamics for a given study area based on Canadian-parameterization and user-provided growth and inventory information. Default Canadian parameters are read-in (CBM_defaults), matched to the user-provided information (CBM_dataPrep_SK and CBM_vol2biomass), and this information drives the carbon-transfers through the simulations (CBM_core).
0.2.1 Input requirements
spadesCBM simulations require study area information, age, and leading species of each stand or pixel to simulate on the landscape, and growth information for each stand or pixel. Users can provide this information in various format which is processed in CBM_dataPrep_SK and in CBM_vol2biomass. We suggest users modify the example provided to represent their study area and inventory information.
0.2.2 Pools
There are 19 carbon pools in spadesCBM (Table 1). The carbon transfers are dictated by matrices (available in the defaults information) which specify the proportion of carbon moving from one pool (“source_pool” - this needs to be in our lexicon) to (“sink_pools” - this too). Matrices for growth are populated with the user-provided growth information and are the main change agent in the system. Default parameters for biomass and dead organic mater (DOM) turnover, decay, and soil mixing are either at the provincial/territorial, ecozone (NEED TO DEFINE), or Canada-wide scale (see Kurz et al. (2009) Table 1). Note that parameters can easily be modified from their defaults in a spadesCBM simulation.
Table 1: Carbon pools in spadesCBM
Pool | Description |
---|---|
Input | is this input from atmosphere??? |
Merch | Live stemwood of merchantable size |
Foliage | Live foliage |
Other | Live branches, stumps, and small trees |
CoarseRoots | Live roots ≥5 mm diameter |
FineRoots | Live roots <5 mm diameter |
AboveGroundVeryFastSoil | The L horizon comprised of foliar litter plus dead fine roots <5 mm diameter |
BelowGroundVeryFastSoil | Dead fine roots in the mineral soil <5 mm diameter |
AboveGroundFastSoil | Fine and small woody debris plus dead coarse roots in the forest floor ≥5 and <75 mm diameter |
BelowGroundFastSoil | Dead coarse roots in the mineral soil ≥5 diameter |
MediumSoil | Coarse woody debris on the ground |
AboveGroundSlowSoil | F, H, and O horizons |
BelowGroundSlowSoil | Humified organic matter in the mineral soil |
StemSnag | Dead standing stemwood of merchantable size including bark |
BranchSnag | Dead branches, stumps, and small trees including bark |
CO2 | CO2 emitted to atmosphere |
CH4 | CH4 emitted to atmosphere |
CO | CO emitted to atmosphere |
NO2 | NO2 emitted to atmosphere |
0.2.3 Order of operations
In simulations, disturbances occur before any other carbon-transfer. After the disturbances, half of the growth (determined by increments in the user-provided growth curve) is applied followed by the transfers representing DOM turnover, live biomass turnover, an overmature decline compensation if applicable, the 2nd half of the growth, DOM decay, slow decay and slow soil mixing. Addition to the system only come from the atmosphere (amount determined by growth), and carbon exists the system to the atmosphere or to the forest products sector (ADD A FIGURE HERE MODIFICATION OF CBM_slide.ppt). Transfers are proportions of a source pool to sink pools and proportions add up to 1, so no carbon is lost.
MAKE A TABLE OF THESE disturbance half growth domturnover bioturnover overmaturedecline 2nd half of the growth domdecay slowdecay slowmixing
0.2.4 The spinup
function
The amount of carbon below ground in forests is extremely variable and consequently there are few data that can provide this information at scales greater then plot levels (REFS). To compensate for this gap in knowledge and data, prior to a simulation, CBM_core completes a process that populates below ground pools. This process is called a spinup and it is the first event in the CBM_core module. The procedure consists of growing and burning forest stand, according to the provided growth curves and default values for fire return intervals (provided in CBM_defaults) until the below ground carbon pool stabilize or reach a predefined number of simulations. The choice of a fire disturbance matche the historical forest disturbance for most forests in Canada. We consider this procedure a place holder until our knowledge of below ground carbon dynamics improves. Although it will likely be resulting in errors in absolute carbon stocks (see Boisvenue et al. (2022) Appendix 4), these should be systematic errors and we can at at least simulate the trends in carbon stocks and fluxes. Research has compared below ground stocks values ((shaw?)??) and work continues to improve parameters (Hararuk (2017) ?).
0.3 Setup
In this example, we setup the workflow using the
SpaDES.project
package and
current versions of the spadesCBM modules.
0.4 Google account needed for this example
To run the provided example, users need to access some of the data using the googledrive R package (part of the tidyverse familyof R packages). During the simInit() (or simInitAndSpades) call, a function to initialize or initialize and run SpaDES-based simulations, R will prompt you to either choose a previously authenticated account (if you have previously used googledrive) or to open a browser window and authenticate.
Make sure you give tidyverse read/write access to your files:

0.5 Python is required for this example
The CBM_core module, which is the simulation modules of spadesCBM requires Python >=3.9 and <=3.12.7.
If a suitable version of Python does not already exist on your computer,
SpaDES.project::setupProject will use the reticulate
package to install it using the pyenv or pyenv-win.
If you are using a Windows computer with Git installed, the pyenv-win tool will be acquired and managed directly by reticulate
. If you are using a Windows computer without Git installed, you will be prompted to allow the pyenv-win tool to be downloaded directly from Github to your local user application data directory (tools::R_user_dir("r-spadesCBM")
).
If the Python installation process fails or you would prefer to manually install Python, it can be downloaded directly from python.org/downloads. The calls to Python functions from a package called libcbm. Python functions are only used in the CBM_core module. Details on CBM_core module and the Python functions are provided in CBM_core chapter in this manual.
0.6 Run Example Simulation
Here is the R script to run the simulation of forest carbon dynamics in the managed forests of SK from 1985 to 2012, with disturbances as presented in Boisvenue et al. (2016). Depending on your computing capacity, this may take a while, particularly the first time you run it. Subsequent simulations are much faster because of the use of the reproducible::Cache function.
projectPath <- "~/GitHub/spadesCBM"
repos <- unique(c("predictiveecology.r-universe.dev", getOption("repos")))
install.packages("SpaDES.project",
repos = repos)
# start in 1985, and end in 2012
times <- list(start = 1985, end = 2012)
out <- SpaDES.project::setupProject(
Restart = TRUE,
useGit = "PredictiveEcology", # a developer sets and keeps this = TRUE
overwrite = TRUE, # a user who wants to get latest modules sets this to TRUE
paths = list(projectPath = projectPath),
options = options(
repos = c(repos = repos),
Require.cloneFrom = Sys.getenv("R_LIBS_USER"),
reproducible.destinationPath = "inputs",
## These are for speed
reproducible.useMemoise = TRUE,
# Require.offlineMode = TRUE,
spades.moduleCodeChecks = FALSE
),
modules = c("PredictiveEcology/CBM_defaults@development",
"PredictiveEcology/CBM_dataPrep_SK@development",
"PredictiveEcology/CBM_vol2biomass@development",
"PredictiveEcology/CBM_core@development"),
times = times,
require = c("SpaDES.core", "reticulate",
"PredictiveEcology/libcbmr", "data.table"),
params = list(
CBM_defaults = list(
.useCache = TRUE
),
CBM_dataPrep_SK = list(
.useCache = TRUE
),
CBM_vol2biomass = list(
.useCache = TRUE
)
),
functions = "PredictiveEcology/CBM_core@training/R/ReticulateFindPython.R",
ret = {
reticulate::virtualenv_create(
"r-spadesCBM",
python = if (!reticulate::virtualenv_exists("r-spadesCBM")){
ReticulateFindPython(
version = ">=3.9,<=3.12.7",
versionInstall = "3.10:latest",
pyenvRoot = tools::R_user_dir("r-spadesCBM")
)
},
packages = c(
"numpy<2",
"pandas>=1.1.5",
"scipy",
"numexpr>=2.8.7",
"numba",
"pyyaml",
"mock",
"openpyxl",
"libcbm"
)
)
reticulate::use_virtualenv("r-spadesCBM")
},
#### begin manually passed inputs #########################################
## define the study area.
masterRaster = {
mr <- reproducible::prepInputs(url = "https://drive.google.com/file/d/1zUyFH8k6Ef4c_GiWMInKbwAl6m6gvLJW/view?usp=drive_link",
destinationPath = "inputs")
mr[mr[] == 0] <- NA
mr
},
disturbanceRastersURL = "https://drive.google.com/file/d/12YnuQYytjcBej0_kdodLchPg7z9LygCt",
outputs = as.data.frame(expand.grid(objectName = c("cbmPools", "NPP"),
saveTime = sort(c(times$start,
times$start +
c(1:(times$end - times$start))
)))),
)
# Run
simPython <- SpaDES.core::simInitAndSpades2(out)