我正在尝试在每个空间网格单元应用常微分方程(ODE)系统。因此,每个景观单元具有相关的ODE模型。在每个时间步骤更新易感蚊子(Sv
),暴露的蚊子(Se
)和受感染的蚊子(St
)的数量,并且ODE模型与基于离散的代理相结合动物运动模型。以下是运行ODE模型的示例:
library(deSolve)
mod1 <- function(out_tab, time_step, var){
Sv <- out_tab[time_step,c("Sv")]
Ev <- out_tab[time_step,c("Ev")]
Iv <- out_tab[time_step,c("Iv")]
Nh <- out_tab[time_step,c("Nh")]
Ih <- out_tab[time_step,c("Ih")]
bv <- 100
dv <- 0.07
betav <- 0.33
av <- 0.5
muv <- 0.1
mod <- function(times, states, parameters) {
with(as.list(c(states, parameters)), {
dSv <- bv - dv*Sv - betav*av*(Ih/Nh)*Sv
dEv <- betav*av*(Ih/Nh)*Sv - dv*Ev - muv*Ev
dIv <- muv*Ev - dv*Iv
return(list(c(dSv, dEv, dIv)))
})
}
states <- c(Sv = Sv, Ev = Ev, Iv = Iv)
input_parameters <- c(bv = bv, dv = dv, betav = betav, av = av, muv = muv)
## Solve ODEs
out <- ode(func=mod, y=states, times=seq(time_step, time_step + 1, by=1), parms=input_parameters, method="iteration")
out <- as.data.frame(out)
out_tab[time_step + 1, c("Sv", "Ev", "Iv")] <- out[dim(out)[1], c("Sv", "Ev", "Iv")]
# out_tab[time_step + 1, c("Nh")] <- var
# out_tab[time_step + 1, c("Ih")] <- var
return(out_tab)
}
out_tab <- data.frame(Sv = 10, Ev = 3, Iv = 2, Nh = 2, Ih = 1)
Nh <- c(5, 1, 8, 0, 5)
Ih <- c(2, 0, 4, 0, 1)
for(time in 1:2){
out_tab <- mod1(out_tab = out_tab, time_step = time)
## print(out_tab)
out_tab[time + 1, c("Nh")] <- Nh[time + 1]
out_tab[time + 1, c("Ih")] <- Ih[time + 1]
}
在time = 2
(以天为单位),Ih
(单元格中的动物数量)等于0,因此Ev
的值为负数。有没有办法防止ODE的负面价值?我使用方法"iteration"
,因为ODE模型包含在基于代理的离散模型中。
答案 0 :(得分:7)
这里有一些主要问题;长话短说你已经错误地定义了你的模型系统与method = "iteration"
一起使用,所以没有多少光线修补就会得到明智的结果。我会在答案的第二部分谈到这一点,但首先,我会回答你原来的问题。
您可以使用事件强制deSolve
中的非负人口规模。我建议您进一步阅读deSolve
文档,因为有很多方法可以触发事件,但我们会将一个方法集成到您在每个时间步骤中触发的代码中。因为它是基于时间的,所以它需要某种最大时间来引用,因此我创建了一个maxtime
值,您也可以在for循环中使用它。您应该在其他函数可访问的位置定义此值;我只是把它放在你的mod1
函数声明之前。
# Here we declare the maximum time to which your system will evaluate
maxtime <- 2
# This is where we define your event function
# Add this directly above your call to ode()
posfun <- function(t, y, parms){
with(as.list(y), {
y[which(y<0)] <- 0
return(y)
})
}
# Here's your original call to ode(), with a small addition
# Notice that we added events; iteration is missing, more on that later
out <- ode(func=mod,
y=states,
times=seq(time_step, time_step + 1, by=1),
parms=input_parameters,
events=list(func = posfun, time = c(0:maxtime)))
out <- as.data.frame(out)
# Don't forget to add maxtime to your for-loop
for(time in 1:maxtime){
out_tab <- mod1(out_tab = out_tab, time_step = time)
## print(out_tab)
out_tab[time + 1, c("Nh")] <- Nh[time + 1]
out_tab[time + 1, c("Ih")] <- Ih[time + 1]
查看posfun
,我们看到它只是在每个时间步检查每个状态变量,并将任何负值设置为零。如果我们检查输出,我们会看到它给出了非负人口密度:
out_tab
Sv Ev Iv Nh Ih
1 10.0000 3.00000 2.000000 2 1
3 179.7493 16.67784 3.244288 1 0
4 416.2958 10.01499 6.133576 8 4
很好,对吗?嗯,不太好。不幸的是,目前无法在method = iteration
时使用事件。鉴于到目前为止您已经分享了关于模型的内容,我们肯定会在连续时间内对其进行建模。仅仅因为分散事件被离散化并不一定意味着出生,死亡和感染事件也必须是离散的。重要的是要概念化这些现象在现实生活中发生的不同时间尺度,并问问自己是否使用模型准确捕捉它们。但是,这已经超出了StackOverflow的范围,所以在第二部分:
查看iteration
中deSolve
方法的文档,我们看到:&#34; Method&#34; iteration&#34;特别之处在于函数func应该返回状态变量的新值而不是变化率。&#34;
您已经在连续时间模型中清楚地编码,该模型返回衍生物的值,而不是返回状态变量的值的离散时间模型。你dSv
中的出生成分是一个常数,所以你使用的是一个内在的出生率;在一个离散时间模型中,你的出生成分将是后代的一些常数数(几乎总是一个整数)乘以&#34;父母的数量&#34;从上一个时间步。
观察你的方程组,我们可以看出这是如何产生问题的:你不是每个Sv
个人在每个时间步产生100个人,而是设置< / em> Sv
到100。 Sv
不可避免地会在你快速累积净亏损时直线下跌。
示例离散时间模型如下所示:
# discrete-time host-parasite model
Parasite <- function(t, y, ks) {
P <- y[1]
H <- y[2]
f <- A * P / (ks + H)
Pnew <- H * (1 - exp(-f))
Hnew <- H * exp(rH * (1 - H) - f)
list (c(Pnew, Hnew))
}
请注意我们如何不断提及&#34;现在&#34;为了计算下一时间步的种群动态,P和H的值。我希望这对你有所帮助,祝你在模特冒险中好运!