| steady.1D {rootSolve} | R Documentation |
Estimates the steady-state condition for a system of ordinary differential equations that result from 1-Dimensional partial differential equation models that have been converted to ODEs by numerical differencing.
It is assumed that exchange occurs only between adjacent layers.
steady.1D(y, time=0, func, parms=NULL, nspec=NULL, dimens=NULL, names=NULL, method = "stode", cyclicBnd = NULL, ...)
y |
the initial guess of (state) values for the ODE system, a vector. |
time |
time for which steady-state is wanted; the default is time=0. |
func |
either an R-function that computes the values of the
derivatives in the ode system (the model defininition) at time time,
or a character string giving the name of a compiled function in a
dynamically loaded shared library.
If func is an R-function, it must be defined as:
yprime = func(t, y, parms,...). t is the current time point
in the integration, y is the current estimate of the variables
in the ODE system. If the initial values y has a names
attribute, the names will be available inside func. parms is
a vector or list of parameters; ... (optional) are any other arguments
passed to the function.
The return value of func should be a list, whose first element is a
vector containing the derivatives of y with respect to
time, and whose next elements are global values whose steady-state
value is also required.
The derivatives should be specified in the same order as the state variables y.
|
parms |
parameters passed to func.
|
nspec |
the number of *species* (components) in the model.
If NULL, then dimens should be specified.
|
dimens |
the number of *boxes* in the model. If NULL, then
nspec should be specified.
|
names |
the names of the components; used to label the output, which will be written as a matrix. |
method |
the solution method, one of "stode", "stodes" or "runsteady". |
cyclicBnd |
if a cyclic boundary exists, a value of 1 else
NULL; see details.
|
... |
additional arguments passed to the solver function as defined
by method.
|
This is the method of choice for multi-species 1-dimensional models, that are only subjected to transport between adjacent layers
More specifically, this method is to be used if the state variables are arranged per species:
A[1],A[2],A[3],....B[1],B[2],B[3],.... (for species A, B))
Two methods are implemented.
stode solves the banded problem.
stodes. Based on the
dimension of the problem, the method first calculates the sparsity pattern
of the Jacobian, under the assumption that transport is only occurring
between adjacent layers. Then stodes is called to solve the problem.
As stodes is used to estimate steady-state, it may be necessary to
specify the length of the real work array, lrw.
Although a reasonable guess of lrw is made, it is possible that
this will be too low.
In this case, steady.1D will return with an error message telling
the size of the work array actually needed. In the second try then,
set lrw equal to this number.
For single-species 1-D models, use steady.band.
If state variables are arranged as (e.g. A[1],B[1],A[2],B[2],A[3],B[3],...
then the model should be solved with steady.band
In some cases, a cyclic boundary condition exists. This is when the first
box interacts with the last box and vice versa. In this case, there
will be extra non-zero fringes in the Jacobian which need to be taken
into account. The occurrence of cyclic boundaries can be
toggled on by specifying argument cyclicBnd=1. If this is the
case, then the steady-state will be estimated using stodes.
The default is no cyclic boundaries.
A list containing
y |
if names is not given: a vector with the state variable
values from the last iteration during estimation of steady-state condition
of the system of equations.
if names is given, a matrix with one column for every steady-state
*component*.
|
... |
the number of "global" values returned. |
The output will have the attribute steady, which returns TRUE, if
steady-state has been reached and the attribute
precis with the precision attained during each iteration.
It is advisable though not mandatory to specify BOTH nspec and
dimens.
In this case, the solver can check whether the input makes sense
(i.e. if nspec*dimens = length(y))
Karline Soetaert <k.soetaert@nioo.knaw.nl>
steady, for a general interface to most of the steady-state
solvers
steady.band, to find the steady-state of ODE models with a
banded Jacobian
steady.2D,
steady.3D, steady-state solvers for 2-D and 3-D
partial differential equations.
stode, iterative steady-state solver for ODEs with full
or banded Jacobian.
stodes, iterative steady-state solver for ODEs with arbitrary
sparse Jacobian.
runsteady, steady-state solver by dynamically running to
steady-state
##################################################################
###### EXAMPLE 1: BOD + O2 ######
##################################################################
# Biochemical Oxygen Demand (BOD) and oxygen (O2) dynamics
# in a river
#==================#
# Model equations #
#==================#
O2BOD <- function(t,state,pars)
{
BOD <- state[1:N]
O2 <- state[(N+1):(2*N)]
# BOD dynamics
FluxBOD <- v*c(BOD_0,BOD) # fluxes due to water transport
FluxO2 <- v*c(O2_0,O2)
BODrate <- r*BOD*O2/(O2+10) # 1-st order consumption, Monod in oxygen
#rate of change = flux gradient - consumption + reaeration (O2)
dBOD <- -diff(FluxBOD)/dx - BODrate
dO2 <- -diff(FluxO2)/dx - BODrate + p*(O2sat-O2)
return(list(c(dBOD=dBOD,dO2=dO2),BODrate=BODrate))
} # END O2BOD
#==================#
# Model application#
#==================#
# parameters
dx <- 100 # grid size, meters
v <- 1e2 # velocity, m/day
x <- seq(dx/2,10000,by=dx) # m, distance from river
N <- length(x)
r <- 0.1 # /day, first-order decay of BOD
p <- 0.1 # /day, air-sea exchange rate
O2sat <- 300 # mmol/m3 saturated oxygen conc
O2_0 <- 50 # mmol/m3 riverine oxygen conc
BOD_0 <- 1500 # mmol/m3 riverine BOD concentration
# initial guess:
state <- c(rep(200,N),rep(200,N))
# running the model
print(system.time(
out <- steady.1D (y=state,func=O2BOD,parms=NULL,
nspec=2,pos=TRUE,names=c("BOD","O2"))))
#==================#
# Plotting output #
#==================#
mf <- par(mfrow=c(2,2))
plot(x,out$y[,"O2"],xlab= "Distance from river",
ylab="mmol/m3",main="Oxygen",type="l")
plot(x,out$y[,"BOD"],xlab= "Distance from river",
ylab="mmol/m3",main="BOD",type="l")
plot(x,out$BODrate,xlab= "Distance from river",
ylab="mmol/m3/d",main="BOD decay rate",type="l")
par(mfrow=mf)
# same, but now running dynamically to steady-state
print(system.time(
out2 <- steady.1D (y=state,func=O2BOD,parms=NULL, nspec=2,
time=c(0,1000),method="runsteady")))
##################################################################
###### EXAMPLE 2: Silicate diagenesis ######
##################################################################
# Example from the book:
# Soetaert and Herman (2009).
# a practical guide to ecological modelling -
# using R as a simulation platform.
# Springer
#====================#
# Model equations #
#====================#
SiDIAmodel <- function (time=0, # time, not used here
Conc, # concentrations: BSi, DSi
parms=NULL) # parameter values; not used
{
BSi<- Conc[1:N]
DSi<- Conc[(N+1):(2*N)]
# transport
# diffusive fluxes at upper interface of each layer
# upper concentration imposed (bwDSi), lower: zero gradient
DSiFlux <- -SedDisp * IntPor *diff(c(bwDSi ,DSi,DSi[N]))/thick
BSiFlux <- -Db *(1-IntPor)*diff(c(BSi[1],BSi,BSi[N]))/thick
BSiFlux[1] <- BSidepo # upper boundary flux is imposed
# BSi dissolution
Dissolution <- rDissSi * BSi*(1.- DSi/EquilSi )^pow
Dissolution <- pmax(0,Dissolution)
# Rate of change= Flux gradient, corrected for porosity + dissolution
dDSi <- -diff(DSiFlux)/thick/Porosity + # transport
Dissolution * (1-Porosity)/Porosity # biogeochemistry
dBSi <- -diff(BSiFlux)/thick/(1-Porosity) - Dissolution
return(list(c(dBSi=dBSi,dDSi=dDSi), # Rates of changes
Dissolution=Dissolution, # Profile of dissolution rates
DSiSurfFlux =DSiFlux[1], # DSi sediment-water exchange rate
DSIDeepFlux =DSiFlux[N+1], # DSi deep-water (burial) flux
BSiDeepFlux =BSiFlux[N+1])) # BSi deep-water (burial) flux
}
#====================#
# Model run #
#====================#
# sediment parameters
thick <- 0.1 # thickness of sediment layers (cm)
Intdepth <- seq(0,10,by=thick) # depth at upper interface of layers
Nint <- length(Intdepth) # number of interfaces
Depth <- 0.5*(Intdepth[-Nint] +Intdepth[-1]) # depth at middle of layers
N <- length(Depth) # number of layers
por0 <- 0.9 # surface porosity (-)
pordeep <- 0.7 # deep porosity (-)
porcoef <- 2 # porosity decay coefficient (/cm)
# porosity profile, middle of layers
Porosity <- pordeep + (por0-pordeep)*exp(-Depth*porcoef)
# porosity profile, upper interface
IntPor <- pordeep + (por0-pordeep)*exp(-Intdepth*porcoef)
dB0 <- 1/365 # cm2/day - bioturbation coefficient
dBcoeff <- 2
mixdepth <- 5 # cm
Db <- pmin(dB0,dB0*exp(-(Intdepth-mixdepth)*dBcoeff))
# biogeochemical parameters
SedDisp <- 0.4 # diffusion coefficient, cm2/d
rDissSi <- 0.005 # dissolution rate, /day
EquilSi <- 800 # equilibrium concentration
pow <- 1
BSidepo <- 0.2*100 # nmol/cm2/day
bwDSi <- 150 # mmol/m3
# initial guess of state variables-just random numbers between 0,1
Conc <- runif(2*N)
# three runs with different deposition rates
BSidepo <- 0.2*100 # nmol/cm2/day
sol <- steady.1D (Conc, func=SiDIAmodel, parms=NULL, nspec=2)
CONC <- sol$y
BSidepo <- 2*100 # nmol/cm2/day
sol2 <- steady.1D (Conc, func=SiDIAmodel, parms=NULL, nspec=2)
CONC <- cbind(CONC,sol2$y)
BSidepo <- 3*100 # nmol/cm2/day
sol3 <- steady.1D (Conc, func=SiDIAmodel, parms=NULL, nspec=2)
CONC <- cbind(CONC,sol3$y)
DSi <- CONC[(N+1):(2*N),]
BSi <- CONC[1:N,]
#====================#
# plotting output #
#====================#
par(mfrow=c(2,2))
matplot(DSi,Depth,ylim=c(10,0),xlab="mmolSi/m3 Liquid",
main="DSi",type="l",lwd=c(1,2,1),col="black")
matplot(BSi,Depth,ylim=c(10,0),xlab="mmolSi/m3 Solid" ,
main="BSi",type="l",lwd=c(1,2,1),col="black")
legend("right",c("0.2","2","3"),title="mmol/m2/d",
lwd=c(1,2,1),lty=1:3)
plot(Porosity,Depth,ylim=c(10,0),xlab="-" ,
main="Porosity", type="l",lwd=2)
plot(Db,Intdepth,ylim=c(10,0),xlab="cm2/d",
main="Bioturbation",type="l",lwd=2)
mtext(outer=TRUE,side=3,line=-2,cex=1.5,"SiDIAmodel")