Nothing
########################
## Class definition
########################
# Lemna model class (Schmitt et al. 2013)
#' @export
#' @include man-lemna.R
setClass("LemnaSchmitt", contains="Lemna")
# for backwards compatibility
#' @export
setClass("LemnaSchmittScenario", contains="LemnaSchmitt")
########################
## Constructor
########################
#' Lemna model (Schmitt et al. 2013)
#'
#' The model is a mechanistic combined toxicokinetic-toxicodynamic (TK/TD) and
#' growth model for the aquatic macrophytes *Lemna spp.*
#' The model simulates the development of *Lemna* biomass under laboratory and
#' environmental conditions and was developed by Schmitt *et al.* (2013). Growth
#' of the *Lemna* population is simulated on basis of photosynthesis and respiration
#' rates which are functions of environmental conditions.
#' The toxicodynamic sub-model describes the effects of growth-inhibiting
#' substances by a respective reduction in the photosynthesis rate based on
#' internal concentrations. This is the historical version of the Lemna model.
#' For current uses, we recommend the Lemna (SETAC) model, which is a more recent
#' version of the Schmitt model.
#'
#' Constructors to ease creation of scenarios based on the *Lemna* model by
#' Schmitt *et al.* (2013).
#' A variant of this *Lemna* model, `Lemna_SchmittThold()`, provides an additional
#' cumulative exposure threshold parameter. The Lemna biomass stops growing
#' if the integral of exposure over time exceeds the threshold. The integral
#' of exposure is internally accounted for by an additional state variable
#' `AUC` (Area Under Curve).
#'
#' @section State variables:
#' The following list describes the default names and standard units of the model's
#' state variables:
#' * BM, g_dw/m2, dry weight biomass per square meter
#' * E, -, effect \[0,1\]
#' * M_int, ug, internal toxicant mass
#' * AUC, ug/L, cumulative exposure (**only** for `LemnaThreshold` model)
#'
#' Biomass (BM) and internal toxicant mass (M_int) are initialized to zero by
#' default. See [set_init()] on how to set the initial states.
#'
#' @section Model parameters:
#' The following model parameters are required:
#' * Fate and biomass
#' * `k_phot_fix`, logical, TRUE then k_phot_max is not changed by environmental factors, else FALSE
#' * `k_phot_max`, 1/d, maximum photosynthesis rate
#' * `k_resp`, 1/d, respiration rate
#' * `k_loss`, 1/d, rate of loss (e.g. flow rate)
#' * `mass_per_frond`, g_dw/frond, dry weight per frond
#' * `BMw2BMd`, g_fw/g_dw, Fresh weight/dry weight
#' * Effect
#' * `Emax`, -, maximum effect \[0,1\]
#' * `EC50`, ug/L, midpoint of effect curve
#' * `b`, -, slope of effect curve
#' * Toxicokinetics
#' * `P_up`, cm/d, Permeability for uptake
#' * `AperBM`, cm2/g_dw, A_leaf / d_leaf = 1/d_leaf (for circular disc, d=0.05 cm)
#' * `Kbm`, -, Biomass(fw) : water partition coefficient
#' * `P_Temp`, logical, TRUE to enable temperature dependence of cuticle permeability, else FALSE
#' * `MolWeight`, g/mol, Molmass of molecule (determines Q10_permeability)
#' * Temperature dependence
#' * `Tmin`, deg C, minimum temperature for growth
#' * `Tmax`, deg C, maximum temperature for growth
#' * `Topt`, deg C, optimal temperature for growth
#' * `t_ref`, deg C, reference temperature for respiration rate
#' * `Q10`, -, temperature dependence factor for respiration rate
#' * Light dependence
#' * `k_0`, 1/d, light dependence: intercept of linear part
#' * `a_k`, (1/d)/(kJ/m2.d), light dependence: slope of linear part
#' * Phosphorus dependence (Hill like dep.)
#' * `C_P`, mg/L, phosphorus concentration in water
#' * `CP50`, mg/L, phosphorus conc. where growth rate is halfed
#' * `a_p`, -, Hill coefficient
#' * `KiP`, mg/L, p-inhibition constant for very high p-conc.
#' * Nitrogen dependence (Hill like dep.)
#' * `C_N`, mg/L, nitrogen concentration in water
#' * `CN50`, mg/L, n-conc. where growth rate is halfed
#' * `a_N`, -, Hill coefficient
#' * `KiN`, mg/L, n-inhibition constant for very high p-conc.
#' * Density dependence
#' * `BM50`, g_dw/m2, cut off BM
#'
#' The `Lemna_SchmittThold` model requires the following additional parameter:
#' * `threshold`, ug/L, cumulative exposure threshold
#'
#' @section Forcings:
#' Besides exposure, the model requires four environmental properties as
#' time-series input:
#' - `temp`, temperature (°C)
#' - `rad`, global irradiation (kJ m-2 d-1)
#'
#' The following constant default values are used for these properties:
#' - `temp` = 12 °C
#' - `rad` = 15,000 kJ m-2 d-1
#'
#' Forcings time-series are represented by `data.frame` objects consisting of two
#' columns. The first for time and the second for the environmental factor in question.
#'
#' Entries of the `data.frame` need to be ordered chronologically. A time-series
#' can consist of only a single row; in this case it will represent constant
#' environmental conditions. See [scenarios] for more details.
#'
#' @section Effects:
#' Supported effect endpoints include *BM* (biomass) and *r* (average
#' growth rate during simulation). The effect on biomass is calculated from
#' the last state of a simulation. Be aware that endpoint *r* is incompatible
#' with frond transfers.
#'
#' @section Parameter boundaries:
#' Default values for parameter boundaries are set for all parameters by expert
#' judgement, for calibration purposes. Values can be access from the object, and
#' defaults overwritten.
#'
#' @section Simulation output:
#' Simulation results will contain two additional columns besides state variables:
#' * `C_int`, ug/L, internal concentration of toxicant
#' * `FrondNo`, -, number of fronds
#'
#' It is possible to amend the output of [simulate()] with additional model
#' quantities that are not state variables, for e.g. debugging purposes or to
#' analyze model behavior. To enable or disable additional outputs, use the
#' optional argument `nout` of [simulate()], see examples below. `nout=1`
#' enables reporting of internal concentration (C_int), `nout=14` enables all
#' additional outputs, and `nout=0` will disable additional outputs.
#'
#' The available output levels are as follows:
#' * `nout >= 1`: `C_int`, internal concentration (ug/L)
#' * `nout >= 2`: `FrondNo`, number of fronds (-)
#' * `nout >= 3`: `C_int_u`, unbound internal concentration (ug/l)
#' * Growth and TK/TD
#' * `nout >= 4`: `BM_fresh`, fresh weight biomass (g_fw/m2)
#' * `nout >= 5`: `k_photo_eff`, current photosynthesis rate (1/d)
#' * `nout >= 6`: `k_resp_eff`, current respiration rate (1/d)
#' * `nout >= 7`: `f_Eff`, toxic effect factor (-)
#' * `nout >= 8`: `P_up_eff`, current permeability for uptake (cm/d)
#' * Environmental variables
#' * `nout >= 9`: `actConc`, current toxicant concentration in surrounding medium (ug/L)
#' * `nout >= 10`: `actTemp`, current environmental temperature (deg C)
#' * `nout >= 11`: `actRad`, current environmental radiation (kJ/m2.d)
#' * Derivatives
#' * `nout >= 12`: `d BM/dt`, current change in state variable BM
#' * `nout >= 13`: `d E/dt`, current change in effect
#' * `nout >= 14`: `d M_int/dt`, current change in internal toxicant mass
#'
#' @section Solver settings:
#' The arguments to ODE solver [deSolve::ode()] control how model equations
#' are numerically integrated. The settings influence stability of the numerical
#' integration scheme as well as numerical precision of model outputs. Generally, the
#' default settings as defined by *deSolve* are used, but all *deSolve* settings
#' can be modified in *cvasi* workflows by the user, if needed. Please refer
#' to e.g. [simulate()] on how to pass arguments to *deSolve* in *cvasi*
#' workflows.
#'
#' Some default settings of *deSolve* were adapted for this model by expert
#' judgement to enable precise, but also computationally efficient, simulations
#' for most model parameters. These settings can be modified by the user,
#' if needed:
#'
#' - `hmax = 0.1`<br>
#' Maximum step length in time suitable for most simulations.
#'
#' @inheritSection Transferable Biomass transfer
#'
#' @param param optional named `list` or `vector` of model parameters
#' @param init optional named numeric `vector` of initial state values
#'
#' @return an S4 object of type [LemnaSchmitt-class]
#' @seealso [Lemna-models], [Macrophyte-models], [Transferable], [Scenarios]
#' @references
#' Schmitt W., Bruns E., Dollinger M., and Sowig P., 2013:
#' *Mechanistic TK/TD-model simulating the effect of growth inhibitors on
#' Lemna populations*. Ecol Model 255, pp. 1-10. \doi{10.1016/j.ecolmodel.2013.01.017}
#'
#' @family Lemna models
#' @family macrophyte models
#' @aliases LemnaSchmitt-class LemnaSchmittScenario-class
#' @export
Lemna_Schmitt <- function(param, init) {
new("LemnaSchmitt",
name="Lemna_Schmitt",
param.req=c("Emax", "EC50", "b", "P_up", "AperBM", "Kbm", "P_Temp",
"MolWeight", "k_phot_fix", "k_phot_max", "k_resp", "k_loss",
"Tmin", "Tmax", "Topt", "t_ref", "Q10", "k_0", "a_k", "C_P",
"CP50", "a_P", "KiP", "C_N", "CN50", "a_N", "KiN", "BM50",
"mass_per_frond", "BMw2BMd"),
# default values as defined by Schmitt et al. (2013)
param=list(Emax=1, AperBM=1000, Kbm=1, P_Temp=FALSE,
MolWeight=390.4, k_phot_fix=TRUE, k_phot_max=0.47, k_resp=0.05, k_loss=0.0,
Tmin=8.0, Tmax=40.5, Topt=26.7, t_ref=25, Q10=2, k_0=3, a_k=5E-5, C_P=0.3,
CP50=0.0043, a_P=1, KiP=101, C_N=0.6, CN50=0.034, a_N=1, KiN=604, BM50=176,
mass_per_frond=0.0001, BMw2BMd=16.7),
# boundary presets defined by expert judgement
param.bounds=list(Emax=c(0, 1), EC50=c(0, 1e6), b=c(0.1, 20), P_up=c(0, 100),
k_phot_max=c(0,1)),
endpoints=c("BM","r"),
forcings.req=c("temp", "rad"),
forcings=list(temp=data.frame(time=0, tmp=12),
rad=data.frame(time=0, irr=15000)),
control.req=TRUE,
init=c(BM=0.0012, E=1, M_int=0),
transfer.interval=-1,
transfer.biomass=0.0012,
transfer.comp.biomass="BM",
transfer.comp.scaled="M_int"
) %>% set_noexposure() -> o
if(!missing(param))
o <- set_param(o, param)
if(!missing(init))
o <- set_init(o, init)
o
}
#' @describeIn Lemna_Schmitt model variant with cumulative exposure threshold
#' @export
Lemna_SchmittThold <- function(param, init) {
o <- Lemna_Schmitt()
o@name <- "Lemna_SchmittThold"
o@param.req <- c(o@param.req, "threshold")
o@init <- c(o@init, AUC=0)
if(!missing(param))
o <- set_param(o, param)
if(!missing(init))
o <- set_init(o, init)
o
}
########################
## Simulation
########################
# @param scenario Scenario object
# @param nout `numeric`, number of additional output variables, `nout=1` appends
# the internal concentration `C_int`, the maximum number is 13
# @param method string, numerical solver used by [deSolve::ode()]
# @param hmax numeric, maximum step length in time, see [deSolve::ode()]
# @param ... additional arguments passed to [deSolve::ode()]
#' @importFrom deSolve ode
solver_lemna_schmitt <- function(scenario, nout=2, method="lsoda", hmax=0.1, ...) {
params <- scenario@param
if(is.list(params))
params <- unlist(params)
# make sure that parameters are present and in required order
params.req <- c("Emax","EC50","b","P_up","AperBM","Kbm","P_Temp","MolWeight",
"k_phot_fix","k_phot_max","k_resp","k_loss","Tmin","Tmax",
"Topt","t_ref","Q10","k_0","a_k","C_P","CP50","a_P","KiP",
"C_N","CN50","a_N","KiN","BM50","mass_per_frond","BMw2BMd")
# additional output variables
outnames <- c("C_int","FrondNo","C_int_u","BM_fresh","k_phot_eff","k_resp_eff","f_Eff",
"P_up_eff","actConc","actTemp","actRad","dBMdt","dEdt","dM_intdt")
# check for missing parameters
params.missing <- setdiff(params.req, names(params))
if(length(params.missing)>0)
stop(paste("missing parameters:",paste(params.missing,sep=",",collapse=",")))
# make sure exposure AUC parameter exists
# magic value: -1 denotes that threshold is not considered
if(!("threshold" %in% names(params))) {
params["threshold"] <- -1
}
# disable threshold for scenarios were effects were disabled
if(params["Emax"] <= 0 | params["threshold"] <= 0) {
params["threshold"] <- -1
}
# reorder parameters for deSolve
params <- params[c(params.req, "threshold")]
# check if any parameter is negative apart from threshold
if(any(head(params,-1)<0)) {
stop(paste("parameter out of bounds: ",paste(names(params)[which(head(params,-1)<0)], collapse=",")))
}
# create forcings list
# TODO check if it can be activated without issues
#if(params["k_phot_fix"]==FALSE)
forcings <- list(scenario@exposure@series, scenario@forcings$temp, scenario@forcings$rad)
#else # temp and radiation are not required by model if k_phot_fix==TRUE
# forcings <- list(exposure, data.frame(t=0,temp=-1), data.frame(t=0,rad=-1))
# run solver
ode(y=scenario@init, times=scenario@times, parms=params, dllname="cvasi",
initfunc="lemna_schmitt_init", func="lemna_schmitt_func", initforc="lemna_schmitt_forc",
forcings=forcings, nout=nout, outnames=outnames, method=method,
hmax=hmax, ...)
}
#' @include solver.R
#' @describeIn solver Numerically integrates Lemna_Schmitt scenarios
setMethod("solver", "LemnaSchmitt", function(scenario, ...) solver_lemna_schmitt(scenario, ...) )
########################
## Effects
########################
# effects are calculated them same way as for `LemnaSetac`, see
# model-lemna_setac.R for details
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.