Soil biogeochemistry
Soil biogeochemistry in Terrarium is still under active development. The one-pool soil carbon scheme is experimental and its interface may change.
Overview
Soils store more organic carbon than vegetation and the atmosphere combined. The size of this store is set by the balance between carbon inputs, mainly litterfall from vegetation, and losses through microbial decomposition, which releases carbon to the atmosphere as heterotrophic respiration. Both decomposition and vertical redistribution of carbon depend on the physical state of the soil, in particular its temperature and moisture.
In Terrarium, soil biogeochemistry processes describe the evolution of the soil organic carbon (SOC) density $\rho_{\text{soc}}$ (kg/m³), defined as the mass of organic material per unit bulk volume of soil. The main inputs are the litter carbon flux $I$ (kg/m²/s) at the soil surface and the soil temperature $T$ (°C) from the Soil energy balance. The main outputs are the SOC density and the respiration rate $R$ (kg/m³/s).
In one vertical dimension, conservation of SOC can be written as
\[\begin{equation} \label{eq:socconservation} \frac{\partial \rho_{\text{soc}}}{\partial t} = -\frac{\partial}{\partial z}\left(q_{\text{d}} + q_{\text{a}}\right) - R(\rho_{\text{soc}}, T)\,, \end{equation}\]
where $q_{\text{d}}$ is the diffusive flux (kg/m²/s) representing mixing by soil fauna (bioturbation) and cryoturbation, $q_{\text{a}}$ is an advective flux representing burial or upward transport, and $R$ is the decomposition rate. Litter inputs enter through the flux boundary condition at the soil surface, $q(z_{\text{top}}) = -I$, following the convention that fluxes are positive upward.
Coupling to soil physics
Soil organic carbon also changes the physical properties of the soil. Organic material has a much higher natural porosity and a lower thermal conductivity than mineral material. Terrarium therefore computes the organic fraction of the soil matrix from the SOC density,
\[\begin{equation} f_{\text{org}} = \frac{\rho_{\text{soc}}}{(1 - \phi_{\text{org}})\,\rho_{\text{org}}}\,, \end{equation}\]
where $\rho_{\text{org}}$ (kg/m³) is the density of pure organic material and $\phi_{\text{org}}$ is the natural porosity of organic soil. The denominator is the bulk density of a soil made entirely of organic material, so $f_{\text{org}}$ is dimensionless. The bulk porosity is then a mixture of the mineral and organic porosities,
\[\begin{equation} \phi = (1 - f_{\text{org}})\,\phi_{\text{min}} + f_{\text{org}}\,\phi_{\text{org}}\,, \end{equation}\]
which in turn determines the heat capacity, thermal conductivity, and hydraulic properties of the soil (see Soil stratigraphy). This relation is only physically meaningful for $0 \leq f_{\text{org}} \leq 1$, i.e. for $\rho_{\text{soc}} \leq (1 - \phi_{\text{org}})\,\rho_{\text{org}}$, which is about 130 kg/m³ with the default parameters.
\[\rho_{\text{soc}}\]
is used as the density of organic material when computing $f_{\text{org}}$. Organic matter is only about 50–58% carbon by mass, so if $\rho_{\text{soc}}$ is interpreted as a carbon density, the organic fraction is underestimated by roughly a factor of two.
All implementations should extend AbstractSoilBiogeochemistry and provide a method for density_soc, which the other soil processes use to compute the soil composition.
Terrarium.AbstractSoilBiogeochemistry — Type
abstract type AbstractSoilBiogeochemistry{NF} <: Terrarium.AbstractProcess{NF}Base type for soil biogeochemistry process implementations.
subtypes(Terrarium.AbstractSoilBiogeochemistry)2-element Vector{Any}:
ConstantSoilCarbonDensity
SinglePoolSoilCarbonImplementations
Constant soil carbon density
The simplest implementation prescribes a constant SOC density in all soil layers. It has no state variables and no tendencies and only affects the soil through the organic fraction described above. This is the default biogeochemistry scheme of SoilEnergyWaterCarbon, with $\rho_{\text{soc}} = 0$ (purely mineral soil).
Terrarium.ConstantSoilCarbonDensity — Type
struct ConstantSoilCarbonDensity{NF} <: Terrarium.AbstractSoilBiogeochemistry{NF}Naive implementation of soil biogeochemistry that just assumes there to be a constant organic content in all soil layers.
Properties:
ρ_soc::Any: Soil organic carbon densityρ_org::Any: Pure organic matter density
One-pool soil carbon
The one-pool scheme treats all soil organic carbon as a single pool with prognostic density $\rho_{\text{soc}}$ in each soil layer, which evolves according to $\eqref{eq:socconservation}$.
Decomposition. Decomposition follows first-order kinetics with a Q10 temperature sensitivity,
\[\begin{equation} R = k_{\text{ref}}\, Q_{10}^{(T - T_{\text{ref}})/10}\, \rho_{\text{soc}}\,, \end{equation}\]
where $k_{\text{ref}}$ (1/s) is the decomposition rate at the reference temperature $T_{\text{ref}}$ (°C) and $Q_{10}$ is the factor by which the rate increases for a 10 °C warming. The defaults are $k_{\text{ref}} = 0.1$ per year, $Q_{10} = 2$, and $T_{\text{ref}} = 10$ °C. The respiration rate is stored as the auxiliary variable respiration_rate. Moisture limitation of decomposition is not yet considered.
Terrarium.SoilCarbonRespiration — Type
struct SoilCarbonRespiration{NF}Soil Carbon Respiration component for the Soil Carbon Model.
Transport. Vertical transport consists of Fickian diffusion with constant diffusivity $D_b$ (m²/s) and advection with constant velocity $\omega$ (m/s),
\[\begin{equation} q_{\text{d}} = -D_b \frac{\partial \rho_{\text{soc}}}{\partial z}\,, \qquad q_{\text{a}} = \omega\, \rho_{\text{soc}}\,. \end{equation}\]
The defaults are $D_b = 1$ cm²/yr and $\omega = 0.002$ mm/yr.
Terrarium.SoilCarbonTransport — Type
struct SoilCarbonTransport{NF}Soil Carbon Transport component with Bioturbation (Diffusion) and Advection terms for the Soil Carbon Model.
Litter input. Litterfall enters the uppermost soil layer through a flux boundary condition on density_soc, which reads the litter input variable (kg/m²/s). The bottom boundary has no flux. This boundary condition must be passed explicitly when initializing the model; see LitterfallFlux below.
Terrarium.SinglePoolSoilCarbon — Type
struct SinglePoolSoilCarbon{NF} <: Terrarium.AbstractSoilBiogeochemistry{NF}Represents a simple one pool soil carbon model.
The following example sets up a soil model with one-pool soil carbon and a constant litter input of 0.5 kg/m²/yr:
grid = ColumnGrid(CPU(), Float64, UniformSpacing(N = 10))
biogeochem = SinglePoolSoilCarbon(eltype(grid))
soil = SoilEnergyWaterCarbon(eltype(grid); biogeochem)
model = SoilModel(grid; soil)
seconds_per_year = 365 * 24 * 3600.0
litter = FieldTimeSeries(grid, XY(), [0.0, 10 * seconds_per_year])
litter.data .= 0.5 / seconds_per_year
inputs = InputSources(InputSource(grid, litter; units = u"kg/m^2/s", name = :litter))
initializers = (; density_soc = 10.0, temperature = 5.0, saturation_water_ice = 1.0)
boundary_conditions = Terrarium.LitterfallFlux(biogeochem)
integrator = initialize(model; inputs, initializers, boundary_conditions)
timestep!(integrator)
integrator.state.density_soc1×1×10 Field{Center, Center, Center} on RectilinearGrid on CPU
├── grid: 1×1×10 RectilinearGrid{Float64, Periodic, Flat, Bounded} on CPU with 1×0×3 halo
├── boundary conditions: FieldBoundaryConditions
│ └── west: Periodic, east: Periodic, south: Nothing, north: Nothing, bottom: ZeroFlux, top: Flux, immersed: Nothing
└── data: 3×1×16 StaticStridesOffsetArray(::Array{Float64, 3}, 0:2, 1:1, -2:13) with eltype Float64 with indices 0:2×1:1×-2:13
└── max=10.0005, min=9.99992, mean=9.99998Process interface
Dispatches for SinglePoolSoilCarbon:
Terrarium.compute_auxiliary! — Method
compute_auxiliary!(
state,
grid,
soc::SinglePoolSoilCarbon,
soil::Terrarium.AbstractSoil,
args...
)Compute the soil organic carbon respiration rate in each soil layer.
Terrarium.compute_boundary_conditions! — Method
compute_boundary_conditions!(
state,
grid,
::SinglePoolSoilCarbon
)Fill the halo regions of density_soc and apply its boundary conditions (e.g. LitterfallFlux) to the soil organic carbon tendency.
Terrarium.compute_tendencies! — Method
compute_tendencies!(
state,
grid,
soc::SinglePoolSoilCarbon,
soil::Terrarium.AbstractSoil,
args...
)Compute the tendency of the soil organic carbon density in each soil layer.
Boundary conditions
Terrarium.LitterfallFlux — Function
Alias for FluxBoundaryCondition on density_soc with name litter representing litter fall inputs to top layer soil organic carbon.
Methods
Terrarium.density_pure_soc — Function
density_pure_soc(bgc::AbstractSoilBiogeochemistry)Return the assumed constant density of pure organic material. The default implementation assumes there to be a property ρ_org defined on the type of bgc.
Terrarium.compute_respiration_rate — Function
compute_respiration_rate(
resp::Terrarium.SoilCarbonRespiration{NF},
C,
T
) where NFCompute the decomposition (heterotrophic respiration) rate (kg/m³/s) of soil organic carbon with density C (kg/m³) at temperature T (°C), R = kref ⋅ Q10^((T - Tref) / 10) ⋅ C.
Kernel functions
Terrarium.density_soc — Function
density_soc(i, j, k, grid, fields, bgc::AbstractSoilBiogeochemistry{NF}) where {NF}Return the bulk soil organic carbon density ρsoc (kg/m³) at index i, j, k, i.e. the mass of organic material per unit volume of soil. The default implementation returns zero, corresponding to a purely mineral soil. Implementations of AbstractSoilBiogeochemistry should override this method; see `organicfraction` for how ρ_soc is converted to the organic fraction of the soil matrix.
Terrarium.compute_respiration! — Function
compute_respiration!(
out,
i,
j,
k,
grid,
fields,
soc::SinglePoolSoilCarbon{NF},
soil::Terrarium.AbstractSoil
) where NFCompute the respiration rate at index i, j, k and store it in out.respiration_rate.
Terrarium.compute_soc_tendency! — Function
compute_soc_tendency!(
tend,
i,
j,
k,
grid,
fields,
soc::SinglePoolSoilCarbon,
soil::Terrarium.AbstractSoil
)Compute the soil organic carbon tendency at index i, j, k and add it to tend.density_soc.
Terrarium.compute_soc_tendency — Function
compute_soc_tendency(
i,
j,
k,
grid,
fields,
soc::SinglePoolSoilCarbon,
soil::Terrarium.AbstractSoil
)Compute the soil organic carbon tendency (kg/m³/s) at index i, j, k, ∂C/∂t = -∂qd/∂z - ∂qa/∂z - R, where qd and qa are the diffusive and advective fluxes and R is the respiration rate. Litter inputs enter through the top boundary condition.
Terrarium.compute_soc_diffusive_flux — Function
compute_soc_diffusive_flux(
i,
j,
k,
grid,
fields,
transport::Terrarium.SoilCarbonTransport
)Compute the diffusive soil organic carbon flux qd = -Db ⋅ ∂C/∂z (kg/m²/s) at the lower cell face of index i, j, k.
Terrarium.compute_soc_advective_flux — Function
compute_soc_advective_flux(
i,
j,
k,
grid,
fields,
transport::Terrarium.SoilCarbonTransport
)Compute the advective soil organic carbon flux q_a = ω ⋅ C (kg/m²/s) at index i, j, k.
Terrarium.litterfall_bc — Function
litterfall_bc(i, j, grid, clock, fields)Discrete-form boundary-condition function (see LitterfallFlux), computes incoming litterfall carbon inputs to the soil. Note that module computes infiltration as positive downward, so it is negated here since fluxes are by convention positive upward.