ERSEM module index
Module name: ersem_primary_producer
Include:
"fabm_driver.h"
Class inheritance:
type_ersem_pelagic_base
- Description:
Silicate use (P1) is optional - it is activated by setting the “use_Si” flag in the run-time configuration.
Calcification (P2) is optional - it is activated by setting the “calcify” flag in the run-time configuration. Preprocessor symbol CALC is no longer used.
The model can be switched from a constant ratio between labile and semi- labile dissolved organic matter production to a dynamic ratio by setting the “docdyn” flag in the run-time configuration. Preprocessor symbol DOCDYN is no longer used.
Iron use is controlled by use_iron defined in ersem/shared.F90.
Functions:
function get_sinking_rate(self,e__arguments_local_e) result (sd) real(kind=rk) :: sd
Module name: ersem_benthic_bacteria
Include:
"fabm_driver.h"
Class inheritance:
type_ersem_benthic_baseDescription:
Module name: ersem_carbonate
Include:
"fabm_driver.h"
Class inheritance:
type_base_modelDescription:
Functions:
function approximate_alkalinity(iswtalk,t,s) result (ta) integer, intent(in) :: iswtalk real(kind=rk), intent(in) :: t real(kind=rk), intent(in) :: s real(kind=rk) :: ta
Module name: ersem_light
Include:
"fabm_driver.h"
Class inheritance:
type_base_modelDescription:
Module name: ersem_mesozooplankton
Include:
"fabm_driver.h"
Class inheritance:
type_ersem_pelagic_baseDescription:
Module name: ersem_benthic_carbonate
Include:
"fabm_driver.h"
Class inheritance:
type_base_modelDescription:
Module name: ersem_benthic_erosion
Include:
"fabm_driver.h"
Class inheritance:
type_base_model
- Description:
type_ersem_benthic_erosion
This model estimates sediment erosion in m/d from the bottom shear stress.
Module name: ersem_bacteria_docdyn
Include:
"fabm_driver.h"
Class inheritance:
type_ersem_pelagic_baseDescription:
Module name: ersem_benthic_calcite
Include:
"fabm_driver.h"
Class inheritance:
type_ersem_benthic_base
- Description:
Benthic variable that supports resuspension and remineralization. Both processes return material to the pelagic.
default: all is private.
Module name: ersem_benthic_column
Include:
"fabm_driver.h"
Class inheritance:
type_base_model
- Description:
type_ersem_benthic_column
This model specifies the structure of the three-layer sediment column.
This model also computes the diffusivity of solutes in the different layers, and a “particulate diffusivity” that represents bioturbation. These variables account for variable bioturbation and bioirrigation activity, respectively.
Module name: ersem_light_iop
Include:
"fabm_driver.h"
Class inheritance:
type_base_modelDescription:
Module name: ersem_calcification
Include:
"fabm_driver.h"
Class inheritance:
type_ersem_pelagic_baseDescription:
Module name: ersem_microzooplankton
Include:
"fabm_driver.h"
Class inheritance:
type_ersem_pelagic_baseDescription:
Module name: ersem_benthic_nitrogen_cycle
Include:
"fabm_driver.h"
Class inheritance:
type_base_model
- Description:
Model for nitrogen cycle
Module name: ersem_benthic_base
Include:
"fabm_driver.h"
Class inheritance:
type_particle_model
- Description:
Benthic variable that supports resuspension and remineralization. Both processes return material to the pelagic.
default: all is private.
Module name: ersem_pelagic_base
Include:
"fabm_driver.h"
Class inheritance:
type_particle_model
- Description:
default: all is private.
Functions:
function get_sinking_rate(self,e__arguments_local_e) result (rm) real(kind=rk) :: rm
Module name: ersem_light_iop_ady
Include:
"fabm_driver.h"
Class inheritance:
type_base_modelDescription:
Module name: ersem_benthic_column_particulate_matter
Include:
"fabm_driver.h" surface flux $-D C0 z/z_mean d/dz exp(-z/z_mean) = 0$, as well as non-zero bottom fluxClass inheritance:
type_ersem_benthic_base
- Description:
Particulate organic matter with idealized [exponential] profile.
The concentration of matter, in mass per unit sediment volume, is assumed to be an exponential function of depth $z$:
C(z) = C0*exp(-b*z)
What value do constants $C0$ and $b$ take?
Let’s define the mean depth of matter within entire sediment column (depth range $0$ to $infty$):
z_mean = int_0^infty z C(z) dz / int_0^infty C(z) dz
When we insert the exponential distribution of $C(z)$, $C0$ drops out and we obtain
z_mean = int_0^infty z exp(-b*z) dz / int_0^infty exp(-b*z) dz
For the denominator of z_mean (concentration integrated from surface to infinite depth) we find through standard integration:
int_0^infty exp(-b*z) dz = [-1/b exp(-b*z)]_0^infty = 1/b
Numerator $int_0^infty z exp(-b*z) dz$ can be found through integration by parts: General rule: $int u v dz = u int v dz - int (u’ int v dz) dz$ We can apply this to find the antiderivative of $z exp(-b*z)$:
int z exp(-b*z) dz = -z/b exp(-b*z) - 1/b^2 exp(-b*z) = -(z+1/b)/b exp(-b*z)
Verify by differentiation (apply chain rule):
-1/b exp(-b*z) + z exp(-b*z) + 1/b exp(-b*z) = z exp(-b*z) [OK]
Integrating from $0$ to $intfy$ while assuming $b>0$ we obtain
int_0^infty z exp(-b*z) dz = [-(z+1/b)/b exp(-b*z)]_0^infty = 1/b^2
Combining the expressions for the numerator and denominator of $z_mean$:
z_mean = (1/b^2)/(1/b) = 1/b
Thus, the exponential decay constant $b$ is equal to $1/z_mean$, and
C(z) = C0*exp(-z/z_mean)
NB this is a standard result (mean of the exponential distribution); the above derivation is given simply for completeness.
The integral of C(z) from 0 to the bottom of the modelled column, z_bot, should equal the modelled density of mass:
int_0^z_bot C(z) dz = [-z_mean*C0*exp(-z/z_mean)]_0^z_bot = z_mean*C0*(1-exp(-z_bot/z_mean)) = C_int
Thus, surface concentration $C0$ can be rewritten in terms of the depth-integrated concentration $C_int$, (integrated up to $z_bot$, not $infty$
C0 = C_int/z_mean/(1-exp(-z_bot/z_mean))
Note: Ebenhoeh et al. 1995 define the penetration depth as mean depth within the model domain, i.e., with lower boundary $z_bot$ rather than $infty$:
- z_mean’ = int_0^z_bot z C(z) dz / int_0^z_bot C(z) dz
= [-(z+1/b)/b exp(-b*z)]_0^z_bot / [-1/b exp(-b*z)]_0^z_bot = [1/b^2-(z_bot+1/b)/b exp(-b*z_bot)] / [1/b-1/b exp(-b*z_bot)] = 1/b [1-(z_bot/b+1) exp(-b*z_bot)] / [1-exp(-b*z_bot)] = 1/b [1-z_bot/b exp(-b*z_bot)/[1-exp(-b*z_bot)]
This will NOT produce an explicit expression for b as a function of z_mean’. Instead, Ebenhoeh et al. implicitly assume z_bot>>z_mean’, which leads to $b approx 1/z_mean’$. However, this approximation becomes invalid when z_mean becomes large, and that can happen in the model. To avoid this problem, we define penetration depth as the mean depth of mass between 0 and infty. Since our exponential function remains the same, expressions based on that (e.g., impact of bioturbation) are the same as in the Oldenburg model. Expressions based on the interpretation of penetration depth (the mean depth of mass between 0 and infty in our case, and between 0 and z_bot for the Oldenburg model) will differ slightly, as e.g. in the next section.
Sources and sinks change $C(z)$, and therefore also penetration depth
z_mean = int_0^infty z C(z) dz / int_0^infty C(z) dz
The time derivative of this expression is found by applying the chain rule
d/dt z_mean = [int_0^infty z d/dt C(z) dz - int_0^infty d/dt C(z) dz int_0^infty z C(z) dz / int_0^infty C(z) dz] / int_0^infty C(z) dz
Introducing depth-integrated concentration
C_int_infty = int_0^infty C(z) dz,
depth-integrated sources minus sinks
sms = int_0^infty d/dt C(z) dz,
and the mean depth of the sources minus sinks
z_sms = int_0^infty z d/dt C(z) dz / int_0^infty d/dt C(z) dz,
we can simplify this to
d/dt z_mean = (z_sms - z_mean) sms/C_int_infty
It is worth noting that the final division is by the concentration integrated from surface to infinite depth, $C_int_infty$:
$C_int_infty = z_mean C0
That is not the same as $C_int$, i.e., the concentration integrated over the modelled depth interval ($0$ to $z_bot$), which equals
C_int = z_mean C0 (1-exp(-z_bot/z_mean))
In the original Oldenburg implementation, penetration depth is defined as the mean depth of mass between 0 and z_bot (not 0 to infty). As a result, $C_int$ is substituted for $C_int_infty$. One consequence of this difference is that penetration depth in the Oldenburg model can “run away” (tend to infinity), while that is prevented in our expression due to the additional multiplication of the rate of change with 1-exp(-z_bot/z_mean).
It is worth noting that the resulting expression for d/dt z_mean does NOT depend on distribution $C(z)$. That is, it is valid for ANY vertical distribution, exponential or otherwise.
Modelled as a diffusion process, bioturbation changes $C(z)$, and therefore also penetration depth
z_mean = int_0^infty z C(z) dz / int_0^infty C(z) dz
Let us try this first for the denominator:
d/dt int_0^infty C(z) dz = int_0^infty d/dt C(z) dz
For d/dt C(z) we have the normal diffusion equation:
d/dt C(z) = d/dz(D d/dz C(z)) = d/dz(-D/z_mean C0 exp(-z/z_mean)) = D C0/z_mean^2 exp(-z/z_mean)
Inserting this expression we obtain for the change in depth-integrated mass:
- d/dt int_0^infty C(z) dz = int_0^infty D C0/z_mean^2 exp(-z/z_mean) dz
= [-D C0/z_mean exp(-z/z_mean)]_0^infty = D C0/z_mean
However, we KNOW that diffusion witin the column should not affect the mass integral. Why is this then non-zero? The reason for this is that we have not accounted for the no-flux boundary conditions. As a result, we are implicity using a non-zero inward flux at the surface that is determined by the gradient:
-D d/dz C(0) = D C0/z_mean exp(-z/z_mean) = D C0/z_mean
In other words, to close the column for mass, we need to subtract this surface flux. (NB the gradient is zero at infinite depth, i.e., the bottom flux is zero)
With this knowledge, we can revisit the numerator in the change in penetration depth $z_mean$. Its time derivative equals
d/dt int_0^infty z C(z) dz = int_0^infty z d/dt C(z) dz
From the diffusion equation for $C(z)$ we derived $d/dt C(z) = D C0/z_mean^2 exp(-z/z_mean)$. Inserting this in $d/dt z_mean$, while limiting bioturbation to maximum depth $z_tur$, we obtain
d/dt int_0^z_tur z C(z) dz = D C0/z_mean^2 int_0^z_tur z exp(-z/z_mean) dz
For the expression within the integral we previously found antiderivative $-(z+z_mean)z_mean exp(-z/z_mean)$. Thus,
- int_0^z_tur z exp(-z/z_mean) dz = [-(z+z_mean)z_mean exp(-z/z_mean)]_0^z_tur
= -(z_tur+z_mean)z_mean exp(-z_tur/z_mean) + z_mean^2
Using this antiderivative to solve the integral from $0$ to $z_tur$:
d/dt int_0^infty z C(z) dz = D C0 [1-(z_tur/z_mean+1)] exp(-z_tur/z_mean)
$-D C0 z_tur/z_mean exp(-z_tur/z_mean)$. Subtracting the latter we obtain:
d/dt int_0^infty z C(z) dz = D C0 [1 - exp(-z_tur/z_mean)]
Finally, $d/dt z_mean$ is given by the ratio of this expression to $int_0^infty C(z) dz = C0 z_mean$:
d/dt z_mean = D/z_mean [1 - exp(-z_tur/z_mean)]
This describes how the penetration depth $z_mean$ changes due to bioturbation up to depth $z_tur$, with the intensity of bioturbation described by diffusivity $D$. It is worth noting that $d/dt z_mean to infty$ when $z_mean to 0$. Thus, in the analytical solution of the model penetration depth cannot become negative as long as $D>0$.
A change in penetration depth without an associated change in total mass $C_int_infty$ will cause a change in the mass in the depth interval described by the model, i.e., int_0^z_bot C0 exp(-z/z_mean). Inserting $C0 = C_int_infty/z_mean$:
int_0^z_bot C0 exp(-z/z_mean) = C_int_infty/z_mean int_0^z_bot exp(-z/z_mean)
Taking the time derivative, with only z_mean depending on time (C_int_infty is constant
For the first term (first line), we have:
d/dt z_mean -C_int_infty/z_mean^2 int_0^z_bot exp(-z/z_mean) = - 1/z_mean d/dt z_mean C_int
with C_int being the concentration integrated from surface to model bottom [not infinite depth
We can rewrite the second term by moving constants outside the integral:
C_int_infty/z_mean^3 d/dt z_mean int_0^z_bot z exp(-z/z_mean) dz
Now we can solve the integral with our previously found antiderivative:
- int_0^z_bot z exp(-z/z_mean) dz = [-(z+z_mean)z_mean exp(-z/z_mean)]_0^z_bot
= -(z_bot+z_mean)z_mean exp(-z_bot/z_mean) + z_mean^2
Inserting this
Since $C_int = C_int_infty [1 - exp(-z_bot/z_mean)]$, we can rewrite this as
1/z_mean d/dt z_mean C_int - C_int_infty/z_mean d/dt z_mean z_bot/z_mean exp(-z_bot/z_mean)
Combining the two contributions to d/dt int_0^z_bot C0 exp(-z/z_mean), we are left with
d/dt int_0^z_bot C0 exp(-z/z_mean) = - C_int_infty z_bot/z_mean^2 exp(-z_bot/z_mean) d/dt z_mean
JB 28/11/2014: this solution was validated in Python with sympy, using the following code
C_int_infty,z_bot,z,t = sympy.symbols(‘C_int_infty,z_bot,z,t’,positive=True,real=True) z_mean = sympy.Function(‘z_mean’,positive=True,real=True)(t) C = C_int_infty/z_mean*sympy.exp(-z/z_mean) dC_dt = sympy.diff(C,t) print sympy.integrate(dC_dt,(z,0,z_bot),conds=’none’)
Inserting $C_int_infty = C_int/[1 - exp(-z_bot/z_mean)]$
d/dt int_0^z_bot C0 exp(-z/z_mean) = - C_int/[1 - exp(-z_bot/z_mean)] z_bot/z_mean^2 exp(-z_bot/z_mean) d/dt z_mean
Since $C0 = C_int/[1 - exp(-z_bot/z_mean)]/z_mean$, this is equivalent to
d/dt int_0^z_bot C0 exp(-z/z_mean) = C(z_bot) z_bot/z_mean d/dt z_mean
In the Oldenburg code, the final expression for the change in mass within model domain due to burial is
C_int/[1-exp(-z_bot/z_mean)] [exp(-(z_bot-d/dt z_mean)/z_mean-exp(-z_bot/z_mean)]
Both our expression and the Oldenburg one contain -C_int/[1-exp(-z_bot/z_mean)] exp(-z_bot/z_mean). A discrepancy remains in the scale factor applied to it:
our derivation: z_bot/z_mean^2 d/dt z_mean Oldenburg: exp(d/dt z_mean/z_mean) - 1
It’s worth noting that the Oldenburg model here has a unit problem: the factor in the exponential is not dimensionless, but has unit time^-1.
This file contains two modules that can be instantiated by the user (from fabm.yaml): type_ersem_benthic_column_particulate_matter: describes particulate organic matter in terms of column-integrated mass and penetration depth type_ersem_benthic_pom_layer: describes particulate organic matter within a user-specified depth interval
The idealized profile is defined only in terms of its density (quantity/m^2) and its penetration depth. By assuming an exponential distribution of matter (constant positive concentration at sediment surface, tending to zero at infinite depth), these two variables suffice to specify the concentration profile.
From the idealized concentration profile, we first compute densities (quantity/m^2) per layer. These layer-specific densities act as state variable: other modules can retrieve their value, but also provide their rate of change. We finally retrieve these rates of change, and convert them into a change in total depth-integrated matter and a change in penetration depth.
The “within a single depth interval” functionality is partitioned over two modules:
type_ersem_benthic_pom_layer computes the density of all constituents within the specified depth interval. This is the module that can be instantiated from fabm.yaml.
type_constituent_for_single_layer_change collects interval-specific sink-source terms for a single constituent and translates those into the change in column-integrated matter and penetration depth. It is created automatically as a submodel of type_ersem_benthic_pom_layer and does not interact with the user.
The split of functionality across two modules is needed because the mass within the interval must be known early, so all other modules can use it, while the change in column-integrated mass and penetration depth must be computed late, after all other individual modules have computed interval-specific rates of change. Thus we have the dependency chain:
1 mass within the desired depth interval (type_ersem_benthic_pom_layer)
-> 2 interval-specific sink-source terms (all other modules) -> 3 change in column-integrated mass and penetration depth (type_constituent_for_single_layer_change)
- Putting 1 and 3 in the same module creates a circular dependency [that’s BAD].
default: all is private.
Module for particulate organic matter class with idealized profile (e.g., Q6, Q7) Also handles the change in average penetration depth due to bioturbation, as well as burial in the form of organic matter moving beyond the bottom of the modelled column due to an increase in penetration depth. This module will always create a “surface” submodel for organic matter at the very surface of the sediment; this is typically used as target for sedimention/resuspension.
Functions:
function partq(d_pen,d_top,d_bot,d_max) real(kind=rk), intent(in) :: d_pen real(kind=rk), intent(in) :: d_top real(kind=rk), intent(in) :: d_bot real(kind=rk), intent(in) :: d_max
Module name: ersem_benthic_column_dissolved_matter
Include:
"fabm_driver.h"
Class inheritance:
type_base_model
- Description:
depth-integrated mass in the benthic column depth-integrated [negative] mass below the zero-concentration isocline concentration in bottom-most pelagic cell sources-sinks specified for layer-integrated variables (pore water and adsorbed) sources-sinks specified for layer-integrated pore water concentration pelagic-benthic flux Flag specifying whether constituent is non-negative Model for dissolved matter in sediment, using idealized equilibrium profiles to determine pelagic-benthic diffusive flux, and to determine equilibrium depths of all but the last layer (NB layer depth will be relaxed to equilibrium value).
Module name: ersem_nitrification
Include:
"fabm_driver.h"
Class inheritance:
type_ersem_pelagic_baseDescription:
Module name: ersem_oxygen
Include:
"fabm_driver.h" as part of utilization.Class inheritance:
type_base_model
- Description:
Computes oxygen saturation, apparent oxygen utilization and handles exchange of oxygen across the water surface. Note: negative oxygen concentrations are permitted. These reflect an oygen debt (e.g., presence of H2S) In this case, oxygen saturation will be zero (not negative while apparent oxygen utilization will still be the difference between saturation concentration and [negative] oxygen concentration.
Functions:
function oxygen_saturation_concentration(self,etw,x1x) result (osat) real(kind=rk), intent(in) :: etw real(kind=rk), intent(in) :: x1x real(kind=rk) :: osat
Module name: ersem_zenith_angle
Include:
"fabm_driver.h"
Class inheritance:
type_base_model
- Description:
This module calculates the solar zenith angle as a function of longitude, latitude, day of year, and time of day. The code that performs this calculation has been adapted from the General Ocean Turbulence Model (GOTM, http://www.gotm.net). Original GOTM source file: src/airsea/solar_zenith_angle.F90.
Module name: ersem_model_library
Include:
Class inheritance:
type_base_model_factoryDescription:
Module name: ersem_nitrous_oxide
Include:
"fabm_driver.h"
Class inheritance:
type_ersem_pelagic_base
- Description:
This module calculates saturation concentrations and air-sea exchange of nitrous oxide. Production of nitrous oxide is implemented in nitrification module (nitrification.F90). For implementation and validation of nitrous oxide on the North-West European Shelf see Lessin et al. (2020): doi.org/10.1029/2019JG005613 ———————————————————————–
Functions:
function n2o_transfer_coefficient(self,etw,x1x) result (kon2o) real(kind=rk), intent(in) :: etw real(kind=rk), intent(in) :: x1x real(kind=rk) :: kon2o
Module name: ersem_bacteria
Include:
"fabm_driver.h"
Class inheritance:
type_ersem_pelagic_baseDescription:
Module name: ersem_benthic_fauna
Include:
"fabm_driver.h"
Class inheritance:
type_ersem_benthic_base
- Description:
To achieve compatibility with legacy ERSEM, we need to be able to decouple the variable from which food availability is derived from the variable that absorbs the loss due to gross food uptake. The following variables absorb the loss due to food uptake - by default they are coupled to the same variable from which available food is derived.
Module name: ersem_fluff
Include:
"fabm_driver.h"
Class inheritance:
type_ersem_benthic_baseDescription:
Module name: ersem_fluff
Include:
"fabm_driver.h"
Class inheritance:
type_ersem_benthic_baseDescription: