是否可以在ode中使用rk4和rootfun(package deSolve)

时间:2017-03-07 10:43:44

标签: r modeling ode

我正在尝试使用基于LV模型的微分方程对猎物 - 食饵 - 捕食者系统进行建模。为了精确,我需要使用runge-kutta4方法。 但考虑到这些方程式,一些人群很快变得消极。

所以我尝试使用ODE的事件/根系统,但似乎rk4和rootfun不兼容......

eventFunc <- function(t, y, p){
  if (y["N1"] < 0) { y["N1"] = 0 }
  if (y["N2"] < 0) { y["N2"] = 0 }
  if (y["P"] < 0) { y["P"] = 0 }
  return(y)
}

rootFunction <- function(t, y, p){
  if (y["P"] < 0) {y["P"] = 0}
  if (y["N1"] < 0) {y["N1"] = 0}
  if (y["N2"] < 0) {y["N2"] = 0}
  return(y)
}

out <- ode(func=Model_T2.2,
           method="rk4",
           y=state,
           parms=parameters,
           times=times,
           events = list(func = eventFunc,
                         root = TRUE),
           rootfun = rootFunction
           )

此代码给出了以下错误:

  

checkevents(事件,时间,Ynames,dllname)出错:     如果指定'events $ func'并且没有root函数或你的求解器不支持根函数,则应该给出'events $ time'并包含事件的时间

有没有解决方案使用rk4并禁止函数低于0?

提前致谢。

对于那些可能会问的人,这是有效的:

if(!require(ggplot2)) {
  install.packages("ggplot2"); require(ggplot2)}
if(!require(deSolve)) {
  install.packages("deSolve"); require(deSolve)}
Model_T2.2 <- function(t, state, par){
  with(as.list(c(state, par)), {

    response1 <- (a1 * N1)/(1+(a1*h1*N1)+(a2*h2*N2))
    response2 <- (a2 * N2)/(1+(a1*h1*N1)+(a2*h2*N2))

    dN1 = r1*N1 * (1 - ((N1 + A12 * N2)/K1)) - response1 * P
    dN2 = r2*N2 * (1 - ((N1 + A21 * N2)/K2)) - response2 * P
    dP = ((E1 * response1) + (E2 * response2)) * P - Mp

    return(list(c(dN1, dN2, dP)))
  })
}

parameters<-c(
  r1=1.42, r2=0.9,
  A12=0.6, A21=0.5,
  K1=50, K2=50,
  a1=0.77, a2=0.77,
  b1 = 1, b2=1,
  h1=1.04, h2=1.04,
  o1=0, o2=0,
  Mp=0.22,
  E1=0.36, E2=0.36
)

## inital states
state<-c(
  P=10,
  N1=30,
  N2=30
)

times <- seq(0, 30, by=0.5)

out <- ode(func=Model_T2.2,
           method="rk4",
           y=state,
           parms=parameters,
           times=times,
           events = list(func = eventFunc,
                         root = TRUE),
           rootfun = rootFunction
           )

md <- melt(as.data.frame(out), id.vars=1, measure.vars = c("N1", "N2", "P"))
pl <- ggplot(md, aes(x=time, y=value, colour=variable))
pl <- pl + geom_line() + geom_point() + scale_color_discrete(name="Population")
pl

图表中的结果: Evolution of prey1, prey2 and predator populations 正如你所看到的,掠食者的数量变为负数,这在现实世界中显然是不可能的。

编辑:缺少变量,对不起。

2 个答案:

答案 0 :(得分:1)

对于像rk4这样的所有显式求解器,这是一个问题。减少时间步骤将有助于达到一定程度。更好地使用具有隐式方法的求解器,lsoda似乎以一种或另一种形式普遍可用。

明确强制正值的另一种方法是将它们作为指数参数化。设置N1=exp(U1)N2=exp(U2)然后ODE功能代码转换为(dN = exp(U)*dU = N*dU

N1 <- exp(U1)
N2 <- exp(U2)
response1 <- (a1)/(1+(a1*h1*N1)+(a2*h2*N2))
response2 <- (a2)/(1+(a1*h1*N1)+(a2*h2*N2))

dU1 = r1 * (1 - ((N1 + A12 * N2)/K1)) - response1 * P
dU2 = r2 * (1 - ((N1 + A21 * N2)/K2)) - response2 * P
dP = ((E1 * response1*N1) + (E2 * response2*N2)) * P - Mp

对于输出,您当然可以从解决方案N1, N2重建U1, U2

答案 1 :(得分:1)

感谢J_F,我现在可以运行我的L-V模型了。

radau(你提到的不是randau)函数确实接受root函数和事件ans隐式实现了runge-kutta方法。

再次感谢,希望这将有助于将来的某个人。