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.
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 )`
I'm currently trying to calculate finite differences in R using the fderiv method from the pracma library. I've developed the method to identify the Lorenz derivatives below:
library(deSolve)
parameters <- c(s = 10, r = 28, b = 8/3) # Lorenz Parameters: sigma, rho, beta
state <- c(X = -8, Y = 7, Z = 27) # Initial State
# Lorenz Function used to generate Lorenz Derivatives
lorenz <- function(t, state, parameters) {
with(as.list(c(state, parameters)), {
dX <- s * (Y - X)
dY <- X * (r - Z) - Y
dZ <- X * Y - b * Z
list(c(dX, dY, dZ))
})
}
times <- seq(0.01, 100, by = 0.01)
# ODE45 used to determine Lorenz Matrix
out <- ode(y = state, times = times, func = lorenz, parms = parameters)
However, I'm struggling to develop the first or second order differences from this function. When I use fderiv(Vectorize(lorenz), state = state, parameters = parameters, x = times, n = 1, "forward") I get the error Error in eval(substitute(expr), data, enclos = parent.frame()) : object 'Y' not found. I was hoping for insight on how I can develop these finite differences with fderiv.
Thanks in advance.
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.
I am trying to solve a series of equations using deSolve in R. I wish to list the equations using for loop but having trouble doing so.
The system is as follows:
X_i' = a X_i+1 - (b+c) X_i
X_k' = 2c (X_1+ ... + X_k) - (b+c) X_k
This is how I tried to write it:
library(deSolve)
ode_func <- function(t, state, parms){
with(as.list(c(state, parms)),{
#rate of change
for (i in 1:k-1) {
dX[i] <- a * X[i+1] - (b + c) * X[i]
dX[k] <- 2 * c * sum(X[i]) - (b + c) * X[k]
#return the rate of change
list(c(dX[i], dX[k])) } }) }
k=10
#initial conditions
state <- c(rep(0, k-1), 1e4)
times=seq(0,500,1)
sol_ode <- ode(y= state, times=times, func = ode_func,
parms = list(a= 0.01, b= 0.01, alpha = 0.01))
I get and error saying that 'object X not found'. I have used deSolve many times successfully but had bever had to use for loop. Thanks in advance for the help.
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.