Nothing
### ============================================================================
### lsodes -- solves ordinary differential equation systems with general
### sparse Jacobian matrix.
### The sparsity structure of the Jacobian is either specified
### by the user, estimated internally (default), or of a special type.
### To date, "1D", "2D", "3D" are supported as special types.
### These are the sparsity associated with 1- 2- and 3-Dimensional PDE models
###
### as from deSolve 1.9.1, lsode1 finds the root of at least one of a set
### of constraint functions g(i) of the independent and dependent variables.
### It finds only those roots for which some g(i), as a function
### of t, changes sign in the interval of integration.
### It then returns the solution at the root, if that occurs
### sooner than the specified stop condition, and otherwise returns
### the solution according the specified stop condition.
###
### Karline: version 1.10.4:
### added 2-D with mapping - still in testing phase, undocumented
### ============================================================================
lsodes <- function(y, times, func, parms, rtol = 1e-6, atol = 1e-6,
jacvec = NULL, sparsetype = "sparseint", nnz = NULL, inz = NULL,
rootfunc = NULL, verbose = FALSE, nroot = 0,
tcrit = NULL, hmin = 0, hmax = NULL, hini = 0, ynames = TRUE,
maxord = NULL, maxsteps = 5000, lrw = NULL, liw = NULL,
dllname = NULL, initfunc = dllname, initpar = parms,
rpar = NULL, ipar = NULL, nout = 0, outnames = NULL, forcings = NULL,
initforc = NULL, fcontrol = NULL, events = NULL, lags = NULL, ...) {
### check input
if (is.list(func)) { ### IF a list
if (!is.null(jacvec) & "jacvec" %in% names(func))
stop("If 'func' is a list that contains jacvec, argument 'jacvec' should be NULL")
if (!is.null(rootfunc) & "rootfunc" %in% names(func))
stop("If 'func' is a list that contains rootfunc, argument 'rootfunc' should be NULL")
if (!is.null(initfunc) & "initfunc" %in% names(func))
stop("If 'func' is a list that contains initfunc, argument 'initfunc' should be NULL")
if (!is.null(dllname) & "dllname" %in% names(func))
stop("If 'func' is a list that contains dllname, argument 'dllname' should be NULL")
if (!is.null(initforc) & "initforc" %in% names(func))
stop("If 'func' is a list that contains initforc, argument 'initforc' should be NULL")
if (!is.null(events$func) & "eventfunc" %in% names(func))
stop("If 'func' is a list that contains eventfunc, argument 'events$func' should be NULL")
if ("eventfunc" %in% names(func)) {
if (! is.null(events))
events$func <- func$eventfunc
else
events <- list(func = func$eventfunc)
}
if (!is.null(func$jacvec)) jacvec <- func$jacvec
if (!is.null(func$rootfunc)) rootfunc <- func$rootfunc
if (!is.null(func$initfunc)) initfunc <- func$initfunc
if (!is.null(func$dllname)) dllname <- func$dllname
if (!is.null(func$initforc)) initforc <- func$initforc
func <- func$func
}
hmax <- checkInput (y, times, func, rtol, atol,
jacvec, tcrit, hmin, hmax, hini, dllname,"jacvec")
n <- length(y)
if (is.null (maxord))
maxord <- 5
if (maxord > 5 )
stop ("'maxord' too large: should be <= 5")
if (maxord < 1 )
stop ("`maxord' must be >1")
### Sparsity type and Jacobian method flag imp
if (sparsetype=="sparseusr" && is.null(inz))
stop("'inz' must be specified if 'sparsetype' = 'sparseusr'")
if (sparsetype=="sparsejan" && is.null(inz))
stop("'inz' must be specified if 'sparsetype' = 'sparsejan'")
if (sparsetype=="1D" && ! is.null(jacvec))
stop("cannot combine 'sparsetype=1D' and 'jacvec'")
if (sparsetype %in% c("2D", "2Dmap") && ! is.null(jacvec))
stop("cannot combine 'sparsetype=2D' and 'jacvec'")
if (sparsetype %in% c("3D", "3Dmap") && ! is.null(jacvec))
stop("cannot combine 'sparsetype=3D' and 'jacvec'")
# imp = method flag as used in lsodes
if (! is.null(jacvec) && sparsetype %in% c("sparseusr", "sparsejan"))
imp <- 21 # inz supplied,jac supplied
else if (! is.null(jacvec) && !sparsetype=="sparseusr")
imp <- 121 # inz internally generated,jac supplied
else if (is.null(jacvec) && sparsetype%in%c("sparseusr","1D","2D","2Dmap","3D","3Dmap","sparsejan"))
imp <- 22 # inz supplied,jac not supplied
else
imp <- 222 # sparse Jacobian, calculated internally
## Special-purpose sparsity structures: 1-D and 2-D reaction-transport problems
## Typically these applications are called via ode.1D, ode.2D and ode.3D
## Here the sparsity is specified in the C-code; this needs extra input:
## the number of components *nspec* and the dimensionality of the problem
## (number of boxes in each direction).
## This information is passed by ode.1D, ode.2D and ode.3D in parameter
## nnz (a vector).
## nnz is altered to include the number of nonzero elements (element 1).
## 'Type' contains the type of sparsity + nspec + num boxes + cyclicBnd + bandwidth
if (sparsetype == "1D") {
nspec <- nnz[1]
bandwidth <- 1 # nnz[3]
Type <- c(2,nnz) #type=2
nnz <- n*(2+nspec*bandwidth)-2*nspec
} else if (sparsetype %in% c("2D","2Dmap")) {
nspec <- nnz[1]
dimens <- nnz[2:3]
bandwidth <- 1# nnz[6]
maxdim <- max(dimens)
if (sparsetype == "2D") {
Type <- c(3, nnz) #type=3
nnz <- n*(4+nspec*bandwidth)-2*nspec*(sum(dimens))
} else { ## Karline: changes for 2D map
Type <- c(30, nnz) #type=30 for 2Dmap
nnz <- (nspec*prod(dimens))*(4+nspec*bandwidth)-2*nspec*(sum(dimens))
}
if (Type[5]==1) { # cyclic boundary in x-direction
nnz <- nnz + 2*maxdim*nspec*bandwidth
}
if (Type[6] ==1) {# cyclic boundary in y-direction
nnz <- nnz + 2*maxdim*nspec*bandwidth
}
} else if (sparsetype %in% c("3D","3Dmap")) {
nspec <- nnz[1]
dimens <- nnz[2:4] #type=4
bandwidth <- 1# nnz[8]
if (sparsetype == "3D") {
Type <- c(4,nnz)
nnz <- n*(6+nspec*bandwidth)-2*nspec*(sum(dimens))
} else { ## Karline: changes for 3D map
Type <- c(40, nnz) #type=40 for 3Dmap
nnz <- (nspec*prod(dimens))*(6+nspec*bandwidth)-2*nspec*(sum(dimens))
}
if (Type[6]== 1) { # cyclic boundary in x-direction
nnz <- nnz + 2*dimens[2]*dimens[3]*nspec
}
if (Type[7] == 1) {# cyclic boundary in y-direction
nnz <- nnz + 2*dimens[1]*dimens[3]*nspec
}
if (Type[8] == 1) {# cyclic boundary in y-direction
nnz <- nnz + 2*dimens[1]*dimens[2]*nspec
}
} else if (sparsetype == "sparseusr") {
Type <- 0
nnz <- nrow(inz)
} else if (sparsetype == "sparsejan") { # ian and jan inputted, as a vector
Type <- 0
nnz <- length(inz) - n
} else {
Type <- 1
if (is.null(nnz)) nnz <- n*n
}
if (nnz < 1)
stop ("Jacobian should at least contain one non-zero value")
### model and Jacobian function
JacFunc <- NULL
Ynames <- attr(y,"names")
RootFunc <- NULL
flist <- list(fmat=0,tmat=0,imat=0,ModelForc=NULL)
ModelInit <- NULL
Eventfunc <- NULL
events <- checkevents(events, times, Ynames, dllname,TRUE)
if (! is.null(events$newTimes)) times <- events$newTimes
if (is.character(func) | inherits(func, "CFunc")) { # function specified in a DLL or inline compiled
DLL <- checkDLL(func,jacvec,dllname,
initfunc,verbose,nout, outnames, JT=2)
## Is there a root function?
if (!is.null(rootfunc)) {
if (!is.character(rootfunc) & !inherits(rootfunc, "CFunc"))
stop("If 'func' is dynloaded, so must 'rootfunc' be")
rootfuncname <- rootfunc
if (inherits(rootfunc, "CFunc"))
RootFunc <- body(rootfunc)[[2]]
else if (is.loaded(rootfuncname, PACKAGE = dllname)) {
RootFunc <- getNativeSymbolInfo(rootfuncname, PACKAGE = dllname)$address
} else
stop(paste("root function not loaded in DLL",rootfunc))
if (nroot == 0)
stop("if 'rootfunc' is specified in a DLL, then 'nroot' should be > 0")
}
ModelInit <- DLL$ModelInit
Func <- DLL$Func
JacFunc <- DLL$JacFunc
Nglobal <- DLL$Nglobal
Nmtot <- DLL$Nmtot
if (! is.null(forcings))
flist <- checkforcings(forcings,times,dllname,initforc,verbose,fcontrol)
if (is.null(ipar)) ipar<-0
if (is.null(rpar)) rpar<-0
Eventfunc <- events$func
if (is.function(Eventfunc))
rho <- environment(Eventfunc)
else
rho <- NULL
} else {
if(is.null(initfunc))
initpar <- NULL # parameter initialisation not needed if function is not a DLL
rho <- environment(func)
# func and jac are overruled, either including ynames, or not
# This allows to pass the "..." arguments and the parameters
if (ynames) {
Func <- function(time,state) {
attr(state,"names") <- Ynames
unlist(func (time,state,parms,...))
}
Func2 <- function(time,state) {
attr(state,"names") <- Ynames
func (time,state,parms,...)
}
JacFunc <- function(time,state,J){
attr(state,"names") <- Ynames
jacvec(time,state,J,parms,...)
}
RootFunc <- function(time,state) {
attr(state,"names") <- Ynames
rootfunc(time,state,parms,...)
}
if (! is.null(events$Type))
if (events$Type == 2)
Eventfunc <- function(time,state) {
attr(state,"names") <- Ynames
events$func(time,state,parms,...)
}
} else { # no ynames...
Func <- function(time,state)
unlist(func (time,state,parms,...))
Func2 <- function(time,state)
func (time,state,parms,...)
JacFunc <- function(time,state,J)
jacvec(time,state,J,parms,...)
RootFunc <- function(time,state)
rootfunc(time,state,parms,...)
if (! is.null(events$Type))
if (events$Type == 2)
Eventfunc <- function(time,state)
events$func(time,state,parms,...)
}
## Check function and return the number of output variables +name
FF <- checkFunc(Func2,times,y,rho)
Nglobal<-FF$Nglobal
Nmtot <- FF$Nmtot
## Check event function
if (! is.null(events$Type))
if (events$Type == 2)
checkEventFunc(Eventfunc,times,y,rho)
## and for rootfunc
if (! is.null(rootfunc)) {
tmp2 <- eval(rootfunc(times[1],y,parms,...), rho)
if (!is.vector(tmp2))
stop("root function 'rootfunc' must return a vector\n")
nroot <- length(tmp2)
} else nroot = 0
}
### work arrays iwork, rwork
# 1. Estimate length of rwork and iwork if not provided via arguments lrw, liw
moss <- imp%/%100 # method to be used to obtain sparsity
meth <- imp%%100%/%10 # basic linear multistep method
miter <- imp%%10 # corrector iteration method
lenr = 2 # real to integer wordlength ratio (2 due to double precision)
if (is.null(lrw)) { # make a guess of real work space needed
lrw = 20+n*(maxord+1)+3*n +20 #extra 20 to make sure
if(miter == 1) lrw = lrw + 2*nnz + 2*n + (nnz+9*n)/lenr
if(miter == 2) lrw = lrw + 2*nnz + 2*n + (nnz+10*n)/lenr
if(miter == 3) lrw = lrw + n + 2
if (sparsetype == "1D") lrw <- lrw*1.2 # increase to be sure it is enough...
}
# if (is.null(liw)) { # make a guess of integer work space needed KS->THOMAS: if not NULL, should be large enough!
if (moss == 0 && miter %in% c(1,2)) liw <- max(liw, 31+n+nnz +30) else # extra 30
liw <- max(liw, 30)
# }
lrw <- max(20, lrw) + 3*nroot
# 2. Allocate and set values
# only first 20 elements of rwork passed to solver;
# other elements will be allocated in C-code
# for iwork: only first 30 elements, except when sparsity imposed
rwork <- vector("double",20)
rwork[] <- 0.
# iwork will contain sparsity structure (ian,jan)
# See documentation of DLSODES how this is done
if(sparsetype=="sparseusr") {
iwork <- vector("integer",liw)
iwork[] <- 0
iw <- 32+n
iwork[31]<- iw
# input = 2-columned matrix inz; converted to ian,jan and put in iwork
# column indices should be sorted...
rr <- inz[,2]
if (min(rr[2:nnz]-rr[1:(nnz-1)])<0)
stop ("cannot proceed: column indices (2nd column of inz) should be sorted")
for(i in 1:n) {
ii <- which (rr==i)
il <- length(ii)
i1 <- iwork[i+30]
i2 <- iwork[i+30]+il-1
iwork[i+31] <- i2+1
if (il>0) iwork[i1:i2] <- inz[ii,1]
}
iwork[31:(31+n)] <- iwork[31:(31+n)]-31-n
} else if(sparsetype=="sparsejan") {
iwork <- vector("integer",liw)
iwork[] <- 0
iw <- 32+n
linz <- 30 + length(inz)
iwork[31:linz] <- inz
} else { # sparsity not imposed; only 30 element of iwork allocated.
iwork <- vector("integer",30)
iwork[] <- 0
}
# other elements of iwork, rwork
iwork[5] <- maxord
iwork[6] <- maxsteps
if(! is.null(tcrit)) rwork[1] <- tcrit
rwork[5] <- hini
rwork[6] <- hmax
rwork[7] <- hmin
# the task to be performed.
if (! is.null(times))
itask <- ifelse (is.null (tcrit), 1,4) else # times specified
itask <- ifelse (is.null (tcrit), 2,5) # only one step
if(is.null(times)) times <- c(0,1e8)
### print to screen...
if (verbose) {
printtask(itask,func,jacvec)
printM("\n--------------------")
printM("Integration method")
printM("--------------------\n")
txt <- "" # to avoid txt being not defined...
if (imp == 21)
txt <- " The user has supplied indices to nonzero elements of Jacobian,
and a Jacobian function" else
if (imp == 22) {
if (sparsetype %in% c("sparseusr","sparsejan"))
txt <-" The user has supplied indices to nonzero elements of Jacobian,
the Jacobian will be estimated internally, by differences"
if (sparsetype=="1D")
txt <-" The nonzero elements are according to a 1-D model,
the Jacobian will be estimated internally, by differences"
if (sparsetype %in% c("2D", "2Dmap"))
txt <-" The nonzero elements are according to a 2-D model,
the Jacobian will be estimated internally, by differences"
if (sparsetype %in% c("3D","3Dmap"))
txt <-" The nonzero elements are according to a 3-D model,
the Jacobian will be estimated internally, by differences"
} else
if (imp == 122)
txt <-" The user has supplied the Jacobian,
its structure (indices to nonzero elements) will be obtained from NEQ+1 calls to jacvec" else
if (imp == 222)
txt <-" The Jacobian will be generated internally,
its structure (indices to nonzero elements) will be obtained from NEQ+1 calls to func"
printM(txt)
}
### calling solver
storage.mode(y) <- storage.mode(times) <- "double"
IN <- 3
if (!is.null(rootfunc)) IN <- 7
lags <- checklags(lags, dllname)
on.exit(.C("unlock_solver"))
out <- .Call("call_lsoda",y,times,Func,initpar,
rtol, atol, rho, tcrit, JacFunc, ModelInit, Eventfunc,
as.integer(verbose), as.integer(itask), as.double(rwork),
as.integer(iwork), as.integer(imp),as.integer(Nglobal),
as.integer(lrw),as.integer(liw),as.integer(IN),
RootFunc, as.integer(nroot), as.double (rpar), as.integer(ipar),
as.integer(Type),flist, events, lags, PACKAGE="deSolve")
### saving results
if (nroot>0) iroot <- attr(out, "iroot")
out <- saveOut(out, y, n, Nglobal, Nmtot, func, Func2,
iin=c(1,12:20), iout=c(1:3,14,5:9,17))
if (nroot>0) attr(out, "iroot") <- iroot
attr(out, "type") <- "lsodes"
if (verbose) diagnostics(out)
out
}
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.