I'm building predator-prey models based on Lotka-Volterra derivatives in R using package deSolve. I define parameters, initial state and timesteps and the model function. Then I solve everyting using ode() or dede() when using a time lag.
I noticed there's a big difference in output depending on how you define the parameters WITHIN the model function and I really don't understand why. You can extract the parameters either by calling them via the argument: parms['r'], or via the previously defined object I passed to the argument: parameters['r']. Same result in both cases.
This is different voor the initial state though: calling the argument: y[1] or y['N'], gives a totally different result than calling it via the object passed to the argument: init[1] or init['N'].
Also in the DDE: there's a difference in time - tau vs times - tau and ylag <- y vs ylag <- init.
Why is there a different result for argument vs object for the initial state and time and not for the parameters? I need to comprehend this well in order to use the FME package in a later stage, so I hope someone can explain this behaviour.
My code:
library(deSolve)
## Parameters
parameters <- c(r = 0.25, K = 200, a = 0.01, c = 0.01, m = 1, tau = 7)
init <- c(N = 20, P = 2)
time <- seq(0, 100, by = 0.01)
## Ordinary DE
PreyPred <- function(times, y, parms){ #chose same argument names as ode()
N <- y['N'] #y[1] works as well
P <- y['P']
#N <- init['N'] #(or init[1]) gives a totally different result!
#P <- init['P']
r <- parms['r'] #growth rate prey parameters['r'] gives same result
K <- parms['K'] #carrying capacity prey
a <- parms['a'] #attack rate predator
c <- parms['c'] #assimilation rate (?) predator
m <- parms['m'] #mortality predator
dN <- r * N * (1-N/K) - a * N * P
dP <- c * N * P - m * P
return(list(c(dN, dP)))
}
oderesult <- ode(func = PreyPred, parms = parameters, y = init, times = time)
plot(oderesult, lwd = 2, mfrow = c(1,2))
## Delayed DE
PreyPredLag <- function(times, y, parms){
N <- y['N']
P <- y['P']
#N <- init['N']
#P <- init['P']
r <- parms['r'] #growth rate prey
K <- parms['K'] #carrying capacity prey
a <- parms['a'] #attack rate predator
c <- parms['c'] #assimilation rate (?) predator
m <- parms['m'] #mortality predator
tau <- parms['tau'] #time lag
tlag <- times - tau
#tlag <- time - tau #different result
if (tlag < 0)
ylag <- y
#ylag <- init
else
ylag <- lagvalue(tlag)
# dede
dN <- r * N * (1-N/K) - a * N * P
dP <- c * ylag[1] * ylag[2] - m * P
return(list(c(dN, dP), lag = ylag))
}
dederesult <- dede(func = PreyPredLag, parms = parameters, y = init, times = time)
plot(dederesult, lwd = 2, mfrow = c(2,2))
The observed behavior is correct. A short explanation:
'parms' is the local variable in the model function, while 'parameters' the global variable in the workspace. This is nothing special for deSolve, it is the general way how R works. The in most cases preferred way is to use the local variable.
For the states, this is indeed different. here the outer value 'init' is the initial value at the beginning, while the local 'y' is the current value for the time step.
The dede parameters are analogous. init is the start, y the instantaneous value, times is the global vector of all time steps and time the actual time step.
Related
I want to estimate the basic reproductive number(R0) of Covid-19 using the next-generation matrix method. I have a complemental model as follows:
rm(list = ls())
library(deSolve)
library(rootSolve)
pars<- c( R0=8,inter.eff=0.75,
inter.start=1,e.dur=3,i.dur=10,cfr=0.0003)
tout <- seq(1, 2, by = 1)
derivs <- function(t, state, pars){
with(as.list(c(state, pars)),{
num <- S + E + I + R# Population size
# Effective contact rate and FOI from a rearrangement of Beta * c * D
ce <- R0 / i.dur
lambda <- ce * I/num
if (!is.null(inter.eff) && t >= inter.start) {
lambda <- lambda * (1 - inter.eff)
}
dS <- -lambda*S
dE <- lambda*S - (1/e.dur)*E
dI <- (1/e.dur)*E - (1 - cfr)*(1/i.dur)*I - cfr*(1/i.dur)*I
dR <- (1 - cfr)*(1/i.dur)*I
# Compartments and flows are part of the derivative vector
# Other calculations to be output are outside the vector, but within the containing list
list(c(dS, dE, dI, dR))
})
}
And consequently, an ordinary differential system as follows:
v<-as.data.frame( ode(y = c(S=64000000,
E=1000, I=5, R=3),
times = tout, func = derivs,
parms = pars,method = "euler"))
In the next step, I want to estimate the Jacobin matrix for each row of the v.The last code I wrote for this purpose was as follows, but unfortunately, I did not get the result. So that a matrix is estimated as a whole and not for each row of the v.Please help me if possible.
v<- v[,-c(1)]#Delete time column
for (i in 1:nrow(v) ){
r<-jacobian.full(y= c(S=v[i,1], E=v[i,2], I=v[i,3],
R=v[i,4]),
func=derivs,
parms =pars,
pert = 1e-8)
}
The solution is:
`product = function(x, output){
S=x[1]
E=x[2]
I= x[3]
R=x[4]
w<-jacobian.full(y= c(S, E, I,
R),
func=derivs,
parms =pars,
pert = 1e-8)
# return product
return(as.data.frame( w))
}
single <- apply(v,1,product )`
library(deSolve)
require(deSolve)
delta_conc <- function(time, current_state, params) {
with(as.list(c(current_state, params)),{
dX <- Y
dY <- X - X^3 - 0.25*Y + A * sin(t)
return(list(c(dX, dY)))
})
}
params <- c(
A <- 0.2645
)
initial_state <- c(
X <- 0.9,
Y <- 0.4
)
times <- 1:10
model <- ode(initial_state, times, delta_conc, params)
summary(model)
matplot(model, type="l",lty=1, main="Enzyme model", xlab="Time")
I get this error message when I try to run it:
Error in checkFunc(Func2, times, y, rho) :
The number of derivatives returned by func() (21) must equal the length of the initial conditions vector (2)
When I exclude the 'sin(t)' part it works, so the problem is with that part, but I'm very much a beginner so I have no idea how to approach this problem
You should consistently use einer t or time for the actual time step. In your case t is not defined as variable, so tis interpreted as transpose-function.
The following should work:
require(deSolve)
delta_conc <- function(time, current_state, params) {
with(as.list(c(current_state, params)),{
dX <- Y
dY <- X - X^3 - 0.25*Y + A * sin(time)
return(list(c(dX, dY)))
})
}
params <- c(
A = 0.2645
)
initial_state <- c(
X = 0.9,
Y = 0.4
)
times <- 1:10
model <- ode(initial_state, times, delta_conc, params)
summary(model)
matplot.0D(model, type="l",lty=1, main="Enzyme model", xlab="Time")
In addition, the code had also some other issues:
use either require or library and not both
use = within c(). It is parameter matching and not assignment
Two additional suggestions:
you can use the deSolve-built in plot function matplot.0D
I would recommend to use times <- seq(0, 10, length.out = 100) instead of 1:10. This way the plot will get smooth. Starting time with 1 (or another value) may be ok, but is often more convenient to start time with zero.
I'm attempting to solve a set of equations related to biological processes. One equation (of about 5) is for a pharmacokinetic (PK) curve of the form C = Co(exp(k1*t)-exp(k2*t). The need is to simultaneously solve the derivative of this equation along with some enzyme binding equations and initial results where not as expected. After troubleshooting, realized that the PK derivative doesn't numerically integrate by itself, if k is negative using the desolve ode function. I've attempted every method (lsode, lsoda, etc) in the ode function, with no success. I've tried adjusting rtol, it doesn't resolve.
Is there an alternative to the deSolve ode function I should investigate? Or another way to get at this problem?
Below is the code with a simplified equation to demonstrate the problem.
When k is negative, the integrated solution does not match the analytical result.
When k is positive, results are as expected.
First Image, result with k=0.2: Analytical and Integrated results match when k is positive
Second Image, result with k=-0.2: Integrated result does not match analytical when k is negative
library(deSolve)
abi <- function(t, state, parameters) {
with(as.list(c(state, parameters)), {
dI <- k*exp(k*t)
list(c(dI))
})
}
k <- c(-0.2)
times <- seq(0, 24, by = 1)
I_analytical <- exp(k*times)
parameters <- c(k)
state <- c(I = 0)
out <- ode(y = state, times = times, func = abi, parms = parameters)
plot(out)
points(I_analytical ~ times)
It was pointed out that the initial condition easily resolves the above example, which is very helpful. Here is the equation I can't accurately integrate, I've tried a few different initial conditions without real success.
library(deSolve)
## Chaos in the atmosphere
CYP <- function(t, state, parameters) {
with(as.list(c(state, parameters)), {
#dE <- ksyn - (kdeg * E) + (k2 * EI) - (k1 * E * I)
#dEI <- (k1 * E * I) - (k2 * EI) + (k4 * EIstar) - (k3 * EI)
#dEIstar <- (k3 * EI) - (k4 * EIstar)
#dOcc <- dEI + dEIstar
dI <- a*tau1*exp(tau1*t) + b*tau2*exp(tau2*t) + c*tau3*exp(tau3*t)
#list(c(dE, dEI, dEIstar, dOcc, dI))
list(c(dI))
})
}
ifit <- c(-0.956144311,0.82619445,0.024520276,-0.913499862,-0.407478829,-0.037174745)
a = ifit[1]
b = ifit[2]
c = ifit[3]
tau1 = ifit[4]
tau2 = ifit[5]
tau3 = ifit[6]
parameters <- c(ksyn = 0.82, kdeg = 0.02, k1 = 2808, k2 = 370.66, k3 = 2.12, k4 = 0.017, a, b, c, tau1, tau2, tau3)
#state <- c(E = 41, EI = 0, EIstar = 0, Occupancy = 0, I = 0.0)
state <- c(I=-0.01)
times <- seq(0, 24, by = .1)
out <- ode(y = state, times = times, func = CYP, parms = parameters)
I_analytical <- a*exp(tau1*times) + b*exp(tau2*times) + c*exp(tau3*times)
plot(out)
points(I_analytical ~ times)
Target curve and the ode solution line.
The initial value should be
state <- c(I= a + b + c)
#state <- c(I = 1)
The first script contains several issues. The most important two are that (1) the model function (abi) must contain the derivative, not an integrated function, while (2) the analytically integrated model missed I_0 that results from the integration constant.
Let's assume a first order decay model
dI/dt = k I
then analytical integration yields
I_t = I_0 exp(kt)
The code is then:
library(deSolve)
abi <- function(t, state, parameters) {
with(as.list(c(state, parameters)), {
# dI <- k*exp(k*t) # original
dI <- k * I # corrected, should be the dervivative
list(c(dI))
})
}
k <- -0.2 # simplified, c() was not necessary
times <- seq(0, 24, by = 1)
# correction: set I0 to a value > zero
I0 <- 10
# I_analytical <- exp(k*times) # original
I_analytical <- I0 * exp(k*times) # corrected, multiplied with I0
#state <- c(I = 0) # original
state <- c(I = I0) # corrected
parameters <- c(k = k)
out <- ode(y = state, times = times, func = abi, parms = parameters)
plot(out)
points(I_analytical ~ times)
This code can be further simplified if you want.
I'm doing Maximum Likelihood Estimation using maxLik, which requires specifying starting values. Instead of specifying a single value, is there any way that allows me to use all the values from a matrix as the start value?
My current code of maxLik is:
f12 <- function(param){
alpha <- param[1]
rho <- param[2]
lambda <- param[3]
u <- 0.5*(p12$v_50_1)^alpha + 0.5*lambda*(p12$v_50_2)^alpha
p <- 1/(1 + exp(-rho*u))
f <- sum(p12$gamble*log(p) + (1-p12$gamble)*log(1-p))}
ml <- maxLik(f12, start = c(alpha = 1, rho=2, lambda = 1), method = "NM")
I create a dataframe with the upper and lower bounds of potential start values:
st <- expand.grid(alpha = seq(0, 2, len = 100),rho = seq(0, 1, len = 100),lambda = seq(0,2, length(100))
There are 3 parameters in my function, and my goal is to loop all the values in the above dataframe st and select the best vector of start values after running the model from a variety of starting parameters.
Thanks!
Consider Map (wrapper to mapply) to pass the st columns elementwise through your methods. Here, Map will return a list of maxLik objects, specifically inherited maxim class objects containing a list of other components. The number of items in this list will be equal to rows of st.
Notice input parameters, a, r, and l being passed into start argument of maxLik() and no longer hard-coded integers. And f12 is left untouched.
maxLik_run <- function(a, r, l) {
tryCatch({
f12 <- function(param){
alpha <- param[1]
rho <- param[2]
lambda <- param[3]
u <- 0.5*(p12$v_50_1)^alpha + 0.5*lambda*(p12$v_50_2)^alpha
p <- 1/(1 + exp(-rho*u))
f <- sum(p12$gamble*log(p) + (1-p12$gamble)*log(1-p))
}
return(maxLik(f12, start = c(alpha = a, rho = r, lambda = l), method = "NM"))
}, error = function(e) return(NA))
}
st <- expand.grid(alpha = seq(0, 2, len = 100),
rho = seq(0, 1, len = 100),
lambda = seq(0, 2, length(100)))
maxLik_list <- Map(maxLik_run, st$alpha, st$rho, st$lambda)
And to answer the question --best vector of start values after running the model from a variety of starting parameters-- requires a particular definition of "best". Once you define this, you can use Filter() on your returned list of objects to select the one or more element that yields this "best".
Below is a demonstration to find the highest value across each maximum likelihood's maximum. Use estimate if needed. Do note, this returned list can have more than one if the highest value is shared by other list items:
highest_value <- max(sapply(maxLik_list, function(item) item$maximum))
maxLik_item_list <- Filter(function(i) i$maximum == highest_value, maxLik_list)
What you are doing in your logLik function is that you are calculating alpha,lambda,rho whereas your data already has them.Those are the lines with u,p and f12(that is also your function name!). Also it is possible to calculate log likelihood for one row as your log likelihood function has single indices. So you run the code using apply like this
#create a function to find mle estimate for first row
maxlike <- function(a) {
f12 <- function(param){
alpha <- param[1]
rho <- param[2]
lambda <- param[3]
#u <- 0.5*(p12$v_50_1)^alpha + 0.5*lambda*(p12$v_50_2)^alpha
#p <- 1/(1 + exp(-rho*u))
#f12 <- sum(p12$gamble*log(p) + (1-p12$gamble)*log(1-p))
}
ml <- maxLik(f12, start = c(alpha = 1, rho=2, lambda = 1), method = "NM")
}
#then using apply with data = st, 2 means rows and your mle function
mle <- apply(st,2,maxlike)
mle
I've written some code that has a logistic growth component (i.e. as N approaches the 'carrying capacity' it grows at a slower rate, until when it reaches the 'carrying capacity' it stops growing). However, when I run it in R it doesn't seem to be working. Some populations end up being larger than the carrying capacity. I've looked at the maths and its all OK. So I think that the problem is that dN/dt is only being calculated once for each population. Does anyone know how to fix this problem?
Any help would be greatly appreciated!
Example code below:
library('optimbase')
library('deSolve')
library('tidyverse')
K = 150000 #carrying capacity
deaths = 0.2567534 #death rate
treesize = 0.23523 #resource size
K_mat = K*ones(10, 1) #matrix of Ks
death_mat = deaths*ones(10, 1) #matrix of deathrates
tree_mat = treesize*ones(11, 1) #matrix of resources
for_mat <- matrix(rbinom(11 * 10, 1, 0.2), ncol = 11, nrow = 10) #connection
#matrix of foraging
parameters <- c(for_mat, tree_mat, death_mat, K_mat) #outline parameters
N <- runif(10,0,K)
state <- N #starting state
nestchange <- function(t, state, parameters){
with(as.list(c(state, parameters)),{
r = for_mat %*% tree_mat - death_mat
dNdt = r*N - r*N*(N/K_mat)
list(c(dNdt))
})
}
times <- seq(0,100)
out <- ode (y = state,
times = times,
func = nestchange,
parms = parameters)
results <- as.data.frame(out)
results <- gather(results, 'nest', 'N', 2:11)
ggplot(data=results,
aes(x=time, y=N, colour=nest)) +
geom_line() +
theme_bw()
Should your function actually be,
nestchange <- function(t, state, parameters){
with(as.list(c(state, parameters)),{
r <- for_mat %*% tree_mat - death_mat
dNdt <- r*state - r*state*(state/K_mat)
list(c(dNdt))
})
}
as the ODE solver is passing state to the function at each time step, yet the function is using the variable N for the calculations instead which isn't updated by the ODE solver.