name | unit | description | initial |
---|---|---|---|
P | g m-3 | phosphorus in water column | 0.1 |
Psed | g m-3 | sediment phosphorus | 1.0 |
Basics and the R package “rodeo”
Differential equations have derivatives on their left-hand side
\[\frac{dy}{dx} = \ldots\]
Expresses the rate of change of a state variable (\(y\)) with respect to another quantity (\(x\))
Derivatives in a single dimension \(\rightarrow\) ODE
\[\frac{dy}{dt} = \ldots\]
Derivatives in multiple dimensions \(\rightarrow\) PDE
\[\frac{\partial y}{\partial t} = \ldots \frac{\partial y}{\partial x} \ldots \]
\[\frac{dy}{dt} = f(y, p, t)\]
y | State variables (e.g. temperature, O2) |
\[\frac{dy}{dt} = f(y, p, t)\]
y | State variables (e.g. temperature, O2) |
p | Parameters (e.g. radiation, reflection, heat capacity, …) |
\[\frac{dy}{dt} = f(y, p, t)\]
y | State variables (e.g. temperature, O2) |
p | Parameters (e.g. radiation, reflection, heat capacity, …) |
t | Time; appears on right hand side if external forcing varies |
Prediction and simulation of hypothetical scenarios
Estimation of parameters from observations
Analysis of discrepancies between modeled and observed patterns
Aerobic bacteria (B) grow on organic substrate (S)
Well mixed culture
Oxygen (X) exchanged with atmosphere
Exponential growth
\[
\begin{align}
\frac{d}{dt} B & = \mu \cdot B
\end{align}
\]
B | Bacterial density (mmol C / L) |
µ | Growth rate constant (1 / h) |
Accounting for substrate limitation
\[
\begin{align}
\frac{d}{dt} B & = \mu \cdot B \cdot \left( \frac{S}{S+h_S} \right)
\end{align}
\]
S | Substrate (mmol C / L) |
hS | Monod parameter (mmol C / L) |
Accounting for oxygen limitation
\[
\begin{align}
\frac{d}{dt} B & = \mu \cdot B \cdot \left( \frac{S}{S+h_S} \right) \cdot \left( \frac{X}{X+h_X} \right)
\end{align}
\]
X | Oxygen (mmol O2 / L) |
hX | Monod parameter (mmol O2 / L) |
Equivalent for the second state variable
\[
\begin{align}
\frac{d}{dt} B & = & \mu \cdot B \cdot \left( \tfrac{S}{S+h_S} \right) \cdot \left( \tfrac{X}{X+h_X} \right) \\
\frac{d}{dt} S & = & \color{orange}{-\frac{1}{f}} \cdot \mu \cdot B \cdot \left( \tfrac{S}{S+h_S} \right) \cdot \left( \tfrac{X}{X+h_X} \right)
\end{align}
\]
f | Yield parameter (mmol B / mmol S) |
\[ \begin{align} \frac{d}{dt} B & = & \mu \cdot B \cdot \left( \tfrac{S}{S+h_S} \right) \cdot \left( \tfrac{X}{X+h_X} \right) \\ \frac{d}{dt} S & = & \color{orange}{-\tfrac{1}{f}} \cdot \mu \cdot B \cdot \left( \tfrac{S}{S+h_S} \right) \cdot \left( \tfrac{X}{X+h_X} \right) \\ \frac{d}{dt} X & = & \color{teal}{\left(1-\tfrac{1}{f} \right)} \cdot \mu \cdot B \cdot \left( \tfrac{S}{S+h_S} \right) \cdot \left( \tfrac{X}{X+h_X} \right) \\ & & + \color{magenta}{k \cdot \left(X_{sat} - X \right)} \end{align} \]
k | Exchange rate constant (1 / hour) |
Xsat | Oxygen saturation level (mmol / L) |
\[ \begin{align} \frac{d}{dt} B & = & \mu \cdot B \cdot \left( \tfrac{S}{S+h_S} \right) \cdot \left( \tfrac{X}{X+h_X} \right) \\ \frac{d}{dt} S & = & \color{orange}{-\tfrac{1}{f}} \cdot \mu \cdot B \cdot \left( \tfrac{S}{S+h_S} \right) \cdot \left( \tfrac{X}{X+h_X} \right) \\ \frac{d}{dt} X & = & \color{teal}{\left(1-\tfrac{1}{f} \right)} \cdot \mu \cdot B \cdot \left( \tfrac{S}{S+h_S} \right) \cdot \left( \tfrac{X}{X+h_X} \right) \\ & & + \color{magenta}{k \cdot \left(X_{sat} - X \right)} \end{align} \]
Terms heavily redundant
All variables on all RHS \(\rightarrow\) simultaneous solution
\[ \begin{align} \frac{d}{dt} \color{red}{y_1} & = f_1(\left[\color{red}{y_1}, \color{blue}{y_2}, \ldots, \color{green}{y_n}\right], p, t) \\ \frac{d}{dt} \color{blue}{y_2} & = f_2(\left[\color{red}{y_1}, \color{blue}{y_2}, \ldots, \color{green}{y_n}\right], p, t) \\ \ldots & \\ \frac{d}{dt} \color{green}{y_n} & = f_3(\left[\color{red}{y_1}, \color{blue}{y_2}, \ldots, \color{green}{y_n}\right], p, t) \end{align} \]
From a known initial state, we predict future states
“Initial Value Problem” (IVP)
Requires integration over time (e.g., R package “deSolve”)
Given constant forcings, systems may run into steady state
All fluxes are in perfect balance
Option 1: Set LHS to zero and solve for state variables (R package “rootSolve”): Elegant but “fragile”
Option 2: Long-term integration: Fail-proof but slow
Analytical solutions exist for simple cases only
Useful for testing accuracy of numerical algorithms
Widely used
Methods of Runge & Kutta
Fails on stiff systems
Recommended
LSODA from ODEPACK
Efficient on both well-behaved and stiff systems
Default of deSolve
\(P\) | Total P in water column (g m-3) |
\(P_{sed}\) | Total sediment P (g m-2) |
\[ \begin{align} \frac{d}{dt} P & = & ... \\ \frac{d}{dt} P_{sed} & = & ... \end{align} \]
Expressions for processes that link water and sediment would appear redundantly in both ODE
Chemical engineers invented a clever notation …
\[ \begin{align} \begin{bmatrix} \tfrac{d}{dt}y_1 \\ \tfrac{d}{dt}y_2 \\ \ldots \\ \tfrac{d}{dt}y_n \end{bmatrix} ^T & = & \begin{bmatrix} a \\ b \\ \ldots \\ z \end{bmatrix} ^T & \cdot & \begin{bmatrix} s_{a,1}, & \ldots, & s_{a,n} \\ s_{b,1}, & \ldots, & s_{b,n} \\ \ldots, & \ldots, & \ldots \\ s_{z,1}, & \ldots, & s_{z,n} \\ \end{bmatrix} \end{align} \]
Vector of derivatives
Vector of rate expressions (processes)
Stoichiometry matrix
\[ \begin{align} \begin{bmatrix} \color{blue}{\tfrac{d}{dt}y_1} \\ \tfrac{d}{dt}y_2 \\ \ldots \\ \tfrac{d}{dt}y_n \end{bmatrix} ^T & = & \begin{bmatrix} \color{teal}{a} \\ \color{orange}{b} \\ \ldots \\ \color{red}{z} \end{bmatrix} ^T & \cdot & \begin{bmatrix} \color{teal}{s_{a,1}}, & \ldots, & s_{a,n} \\ \color{orange}{s_{b,1}}, & \ldots, & s_{b,n} \\ \ldots, & \ldots, & \ldots \\ \color{red}{s_{z,1}}, & \ldots, & s_{z,n} \\ \end{bmatrix} \end{align} \]
\[ \color{blue}{\tfrac{d}{dt}y_1} = \color{teal}{a} \cdot \color{teal}{s_{a,1}} + \color{orange}{b} \cdot \color{orange}{s_{b,1}} + \ldots + \color{red}{z} \cdot \color{red}{s_{z,1}} \]
\[ \begin{align} \begin{bmatrix} \tfrac{d}{dt}\color{blue}{P} \\ \tfrac{d}{dt}\color{brown}{P_{sed}} \end{bmatrix} ^T = \begin{bmatrix} 1/\tau \cdot P_{in} \\ 1/\tau \cdot P \\ u/d \cdot P \\ k_B \cdot P_{sed} \\ k_R \cdot P_{sed} \end{bmatrix} ^T \cdot \begin{bmatrix} \color{blue}{1} & \color{brown}{0} \\ \color{blue}{-1} & \color{brown}{0} \\ \color{blue}{-1} & \color{brown}{d} \\ \color{blue}{0} & \color{brown}{-1} \\ \color{blue}{1/d} & \color{brown}{-1} \end{bmatrix} \end{align} \]
\(\tau\) | Residence time (y) |
\(d\) | Water depth (m) |
\(u\) | Settl. velocity (m y-1) |
\(P_{in}\) | P in inflow (g / m3) |
\(k_B\) | Burial rate const. (y-1) |
\(k_R\) | Remob. rate const. (y-1) |
\[ \begin{align} \begin{bmatrix} \color{red}{\tfrac{d}{dt}P} \\ \tfrac{d}{dt}P_{sed} \end{bmatrix} ^T = \begin{bmatrix} \color{blue}{1/\tau \cdot P_{in}} \\ \color{magenta}{1/\tau \cdot P} \\ \color{olive}{u/d \cdot P} \\ k_B \cdot P_{sed} \\ \color{teal}{k_R \cdot P_{sed}} \end{bmatrix} ^T \cdot \begin{bmatrix} \color{blue}{1} & 0 \\ \color{magenta}{-1} & 0 \\ \color{olive}{-1} & d \\ 0 & -1 \\ \color{teal}{1/d} & -1 \end{bmatrix} \end{align} \]
\[\color{red}{\tfrac{d}{dt}P} = \color{blue} {\tfrac{1}{\tau} \cdot P_{in}} \color{magenta}{- \tfrac{1}{\tau} \cdot P} \color{olive}{- \tfrac{u}{d} \cdot P} \color{teal}{+ k_R \cdot P_{sed} \cdot \tfrac{1}{d}}\]
Import, Export, Settling, Burial, Remobilization
\[ \begin{align} \begin{bmatrix} \tfrac{d}{dt}P \\ \tfrac{d}{dt}P_{sed} \end{bmatrix} ^T = \begin{bmatrix} 1/\tau \cdot P_{in} \\ 1/\tau \cdot P \\ u/d \cdot P \\ k_B \cdot P_{sed} \\ k_R \cdot P_{sed} \end{bmatrix} ^T \cdot \begin{bmatrix} 1 & 0 \\ -1 & 0 \\ -1 & d \\ 0 & -1 \\ 1/d & -1 \end{bmatrix} \end{align} \]
Process rate expression do not appear redundantly
\[ \begin{align} \begin{bmatrix} \tfrac{d}{dt}P \\ \tfrac{d}{dt}P_{sed} \end{bmatrix} ^T = \begin{bmatrix} 1/\tau \cdot P_{in} \\ 1/\tau \cdot P \\ u/d \cdot P \\ k_B \cdot P_{sed} \\ k_R \cdot P_{sed} \end{bmatrix} ^T \cdot \begin{bmatrix} 1 & 0 \\ -1 & 0 \\ -1 & d \\ 0 & -1 \\ 1/d & -1 \end{bmatrix} \end{align} \]
Straightforward modification
to add/drop a process, we add/drop a row
similar for state variables
\[ \begin{align} \begin{bmatrix} \tfrac{d}{dt}P \\ \tfrac{d}{dt}P_{sed} \end{bmatrix} ^T = \begin{bmatrix} 1/\tau \cdot P_{in} \\ 1/\tau \cdot P \\ u/d \cdot P \\ k_B \cdot P_{sed} \\ k_R \cdot P_{sed} \end{bmatrix} ^T \cdot \begin{bmatrix} 1 & 0 \\ -1 & 0 \\ -1 & d \\ 0 & -1 \\ 1/d & -1 \end{bmatrix} \end{align} \]
The stoichiometry matrix is extremely useful for communicating the model
Signs of coefficients can be translated to symbols
\[ \begin{align} \begin{matrix} & P & P_{sed} \\ \text{Import} & \color{red}{\uparrow} & \circ \\ \text{Export} & \color{blue}{\downarrow} & \circ \\ \text{Settling} & \color{blue}{\downarrow} & \color{red}{\uparrow} \\ \text{Burial} & \circ & \color{blue}{\downarrow} \\ \text{Remob.} & \color{red}{\uparrow} & \color{blue}{\downarrow} \end{matrix} \end{align} \]
\(\color{red}{\uparrow}\) increase, \(\color{blue}{\downarrow}\) decline, \(\circ\) no direct effect
Vectors and matrices can be stored in tables, alongside with documentation
Tables can be processed automatically to …
generate source code for simulation
perform sanity checks
create nicely formatted documentation
Available on CRAN since around 2017
Provides a code generator compliant with integration routines from deSolve
native R code
compiled Fortran 2000+
\[ \begin{align} \begin{bmatrix} \tfrac{d}{dt}P \\ \tfrac{d}{dt}P_{sed} \end{bmatrix} ^T = \begin{bmatrix} 1/\tau \cdot P_{in} \\ 1/\tau \cdot P \\ u/d \cdot P \\ k_B \cdot P_{sed} \\ k_R \cdot P_{sed} \end{bmatrix} ^T \cdot \begin{bmatrix} 1 & 0 \\ -1 & 0 \\ -1 & d \\ 0 & -1 \\ 1/d & -1 \end{bmatrix} \end{align} \]
\[ \begin{align} \begin{bmatrix} \tfrac{d}{dt}\color{red}{P} \\ \tfrac{d}{dt}\color{red}{P_{sed}} \end{bmatrix} ^T = \begin{bmatrix} 1/\color{teal}{\tau} \cdot \color{teal}{P_{in}} \\ 1/\color{teal}{\tau} \cdot \color{red}{P} \\ \color{teal}{u}/\color{teal}{d} \cdot \color{red}{P} \\ \color{teal}{k_B} \cdot \color{red}{P_{sed}} \\ \color{teal}{k_R} \cdot \color{red}{P_{sed}} \end{bmatrix} ^T \cdot \begin{bmatrix} 1 & 0 \\ -1 & 0 \\ -1 & \color{teal}{d} \\ 0 & -1 \\ 1/\color{teal}{d} & -1 \end{bmatrix} \end{align} \]
1st table | Math expressions of RHS |
2nd table | Declaration & doc. of state variables |
3rd table | Declaration & doc. of parameters |
name | unit | description | initial |
---|---|---|---|
P | g m-3 | phosphorus in water column | 0.1 |
Psed | g m-3 | sediment phosphorus | 1.0 |
name | unit | description | default |
---|---|---|---|
tau | years | residence time | 1.0 |
d | m | lake depth | 10.0 |
u | m y-1 | apparent settling velocity | 40.0 |
kB | y-1 | rate constant of burial | 0.1 |
kR | y-1 | remobilization rate const. | 0.3 |
Pin | g m-3 | inflow concentration | 0.1 |
name | unit | description | expression | P | Psed |
---|---|---|---|---|---|
imp | g m-3 y-1 | import | 1 / tau * Pin | 1 | 0 |
exp | g m-3 y-1 | export | 1 / tau * P | -1 | 0 |
set | g m-3 y-1 | settling | u / d * P | -1 | d |
bur | g m-2 y-1 | burial | kB * Psed | 0 | -1 |
rem | g m-2 y-1 | remobil. | kR * Psed | 1/d | -1 |
For cheap models, R code is sufficient
Compiled Fortran code is way faster
Needs “gfortran” (on Windows: “Rtools”)
Nature of simultaneous ODE
Numerical solutions: Dynamics or steady-state ?
Numerous advantages of a matrix-based notation (Petersen matrix)
\[ \begin{align} \begin{bmatrix} \tfrac{d}{dt}P \\ \tfrac{d}{dt}P_{sed} \end{bmatrix} ^T = \begin{bmatrix} 1/\tau \cdot P_{in} \\ 1/\tau \cdot P \\ u/d \cdot P \\ k_B \cdot P_{sed} \\ k_R \cdot P_{sed} \end{bmatrix} ^T \cdot \begin{bmatrix} 1 & 0 \\ -1 & 0 \\ -1 & d \\ 0 & -1 \\ 1/d & -1 \end{bmatrix} \end{align} \]
Adopts the matrix-based notation
ODEs held in tables with basic documentation
deSolve::lsoda( … )
Generated source code passed to numeric solver
Examples provided (workbook + R code)
Walk through examples
Learn by simple modifications
Introduction to solving PDE problems (MOL)
Web browser
Spreadsheet software, e.g., Libre Office “calc”
A version of R with these CRAN packages installed: deSolve, rodeo, readxl
The tools to compile source code in R packages (gfortran, “Rtools” on Windows)