[R-sig-dyn-mod] DeSolve Lagvalue Error: illegal input, lag too large

Thomas Petzoldt thom@@@petzo|dt @end|ng |rom tu-dre@den@de
Sat Mar 28 13:47:46 CET 2020


Hi,

your example was a little bit more than "minimal", so not many in this 
list may be motivated to answer quickly. Nevertheless, a possible reason 
of the error message was easily to spot:

If you use a large number of time steps (long simulatio  time and a very 
small time step), you need to increase the history buffer, for example:

yout <- as.data.frame(dede(y = yinit, times = times, func = derivs,
          parms = params,  control=list(mxhist = 1e6)))

.. but on the other hand, I would recommend to reduce the time step 
instead from:

times <- seq(0, 400, 0.003125)

just to:

times <- seq(0, 400, 1)

or even bigger than one, as lsoda, the default solver, adjusts its 
**internal** time step anyway. The automatic time step adjustment 
approaches the same precision with less computation effort, i.e. will be 
much faster and needs less memory.

A few additional suggestions:

1) use debugging techniques to see why your script fails, either by 
using the "traceback" function of RStudio or by adding print or cat 
statements to your model, e.g.

derivs <- function(t, y, parms) {
   cat(t, y, "\n")
   ......
}

2) be very careful with very small or big numbers! Precision of floating 
arithmetics is limited to 16 digits and standard tolerance of deSolve is 
1e-6, absolute and relative. One may consider to adjust 'rtol' to lower 
values and 'atol' to lower OR higher values, depending on the scale, but 
it is sometimes easier to re-scale the state variables to stay within 
reasonable limits of, say, 1e-4 to 10000.

3) You try to handle negative resp. extreme values of states and 
derivatives with if-clauses. This is a frequently seen approach, but I 
always argue that it is much better to modify the model such, that 
negative or extreme values are cannot occur, e.g. by transforming the 
model to log-scale or by using safeguard functions. This avoids mass 
balance issues, and makes life easier for automatic step-size solvers to 
maintain stability and speed.

See the following post for more information:

https://stackoverflow.com/questions/56614347/non-negative-ode-solutions-with-functools-in-r


Hope it helps

Thomas P.



On 20.03.2020 at 05:32 Mike Blazanin wrote:
> #Minimal reproduction of lag too large error
> library(deSolve)
> library(reshape2)
> library(ggplot2)
> 
> derivs <- function(t, y, parms) {
>    #The derivs function must return the derivative of all the variables at a
>    # given time, in a list
> 
>    #Issue warning about too small/negative yvals
>    if (any(y < 0)) {
>      warning(paste("pop(s)",
>                    paste(which(y < 0), collapse = ","),
>                    "below 0, treating as 0, returning dY = 0"))
>    }
> 
>    #Save "true" y values for future reference
>    ystart <- y
> 
>    #Set negative y values to 0 so they don't affect the dN's
>    y[y < 0] <- 0
> 
>    #Create output vector
>    dY <- c(S = 0, I = 0, P = 0)
> 
>    ##Calculate dS
> 
>    #Old (exponential dS/dt)
>    #dS/dt = rS - aSP
>    #dS <- parms["r"] * y["S"] - a * y["S"] * y["P"]
> 
>    #New (logistic dS/dt)
>    #dS/dt = rS((K-S/K)) - aSP
>    dY["S"] <- parms["r"] * y["S"] * ((parms["K"] - y["S"])/parms["K"]) -
>      parms["a"] * y["S"] * y["P"]
> 
>    ##Calculate dI
>    #dI/dt = aSP - aS(t-tau)P(t-tau)
>    if (t < parms["tau"]) {
>      dY["I"] <- parms["a"] * y["S"] * y["P"]
>    } else {
>      dY["I"] <- parms["a"] * y["S"]*y["P"] -
>        parms["a"] * lagvalue(t - parms["tau"], 1)*lagvalue(t - parms["tau"],
> 3)
>    }
> 
>    ##Calculate dP
>    #dP/dt = baS(t-tau)P(t-tau) - aSP
>    if (t < parms["tau"]) {
>      dY["P"] <- -parms["a"] * y["S"] * y["P"]
>    } else {
>      dY["P"] <- parms["b"] * parms["a"] *
>        lagvalue(t-parms["tau"], 1)*lagvalue(t-parms["tau"], 3) -
>        parms["a"]*y["S"]*y["P"]
>    }
> 
>    #Issue warning about too large pop
>    if (any(y > 10**100)) {
>      warning(paste("pop(s)",
>                    paste(which(y > 10**100), collapse = ","),
>                    "exceed max limit, 10^100, returning dY = 0"))
>      dY[y > 10**100] <- 0
>    }
> 
>    #Change dY for too small pops
>    dY[ystart < 0] <- 0
> 
>    #From documentation: The return value of func should be a list, whose
> first
>    #element is a vector containing the derivatives of y with respect to time
>    return(list(dY))
> }
> 
> yinit <- c(S = 10**6,
>             I = 0,
>             P = 10**5)
> 
> #First example
> params <- c(r = .04, a = 10**-12, b = 5, tau = 10, K = 10**7)
> times <- seq(0, 400, 0.003125)
> yout <- as.data.frame(
>    dede(y = yinit, times = times, func = derivs, parms = params))
> 
> #Second example
> params <- c(r = .04, a = 10**-12, b = 5, tau = 50, K = 10**8)
> times <- seq(0, 204800, 25.6)
> yout <- as.data.frame(
>    dede(y = yinit, times = times, func = derivs, parms = params))
> 
> times <- seq(0, 73190, 25.6)
> yout <- as.data.frame(
>    dede(y = yinit, times = times, func = derivs, parms = params))
> tail(yout)
> #All pops are still positive at 73141, when it says the lag is too large
> 
> #Third example
> params <- c(r = .04, a = 10**-8, b = 500, tau = 100, K = 10**8)
> times <- seq(0, 400, 2.5*10**-2)
> yout <- as.data.frame(
>    dede(y = yinit, times = times, func = derivs, parms = params))
> 
> times <- seq(0, 99, 2.5*10**-2)
> yout <- as.data.frame(
>    dede(y = yinit, times = times, func = derivs, parms = params))
> 
> 
> #Code for plotting population sizes over time
> ymelt <- reshape2::melt(data = as.data.frame(yout),
>                          id = c("time"),
>                          value.name = "Density",
>                          variable.name = "Pop")
> 
> ggplot(data = ymelt,
>         aes(x = time, y = Density+1, color = Pop)) +
>    geom_line(lwd = 1.5, alpha = 1) +
>    scale_y_continuous(trans = "log10") +
>    scale_x_continuous(breaks = seq(from = 0, to = max(ymelt$time),
>                                    by = round(max(ymelt$time)/10))) +
>    geom_hline(yintercept = 1, lty = 2) +
>    theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
>    NULL


-- 
Dr. Thomas Petzoldt
wiss. Mitarbeiter                     member of scientific staff

Technische Universität Dresden        Technische Universitaet Dresden
Fakultät Umweltwissenschaften         Faculty of Environmental Sciences
Institut für Hydrobiologie            Institute of Hydrobiology
Professur für Limnologie              Chair of Limnology
01062 Dresden                         01062 Dresden, Germany

Tel.: +49 351 463 34954
Fax:  +49 351 463 37108
E-Mail: thomas.petzoldt using tu-dresden.de
http://tu-dresden.de/Members/thomas.petzoldt



More information about the R-sig-dynamic-models mailing list