steady.1D {rootSolve} | R Documentation |
Estimates the steady-state condition for a system of ordinary differential equations that result from 1-Dimensional reaction-transport models that include transport only between adjacent layers and that model many species.
steady.1D(y, time=0, func, parms=NULL, nspec=NULL, dimens=NULL, names=NULL,method = "stode",...)
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. |
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" |
... |
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.
stodes
is used to estimate steady-state, it may be necessary to specify the length of the real work array, lrw
.
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
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>
stode
and stodes
for the additional options
steady
, for solving steady-state when the jacobian matrix is full
steady.2D
, for steady-state estimation of 2-D models
steady.band
, for steady-state solution, when the jacobian matrix is banded
################################################################## ###### 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 (2008). # 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")