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_base

Description:

Module name: ersem_carbonate

Include:

"fabm_driver.h"

Class inheritance:

type_base_model

Description:

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_model

Description:

Module name: ersem_mesozooplankton

Include:

"fabm_driver.h"

Class inheritance:

type_ersem_pelagic_base

Description:

Module name: ersem_benthic_carbonate

Include:

"fabm_driver.h"

Class inheritance:

type_base_model

Description:

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_base

Description:

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_model

Description:

Module name: ersem_calcification

Include:

"fabm_driver.h"

Class inheritance:

type_ersem_pelagic_base

Description:

Module name: ersem_microzooplankton

Include:

"fabm_driver.h"

Class inheritance:

type_ersem_pelagic_base

Description:

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_model

Description:

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 flux

Class 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

d/dt int_0^z_bot C0 exp(-z/z_mean) = d/dt z_mean -C_int_infty/z_mean^2 int_0^z_bot exp(-z/z_mean)
  • C_int_infty/z_mean int_0^z_bot z/z_mean^2 d/dt z_mean exp(-z/z_mean) dz

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

C_int_infty/z_mean d/dt z_mean [-(z_bot/z_mean+1) exp(-z_bot/z_mean) + 1] = C_int_infty/z_mean d/dt z_mean [1 - exp(-z_bot/z_mean) - z_bot/z_mean exp(-z_bot/z_mean)]

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_base

Description:

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_factory

Description:

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_base

Description:

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_base

Description:

Module name: ersem_fluff

Include:

"fabm_driver.h"

Class inheritance:

type_ersem_benthic_base

Description: