我目前正在使用 deSolve
解决一组普通微分方程组,想知道是否有任何方法可以防止微分变量值低于零。我看到了一些其他帖子关于在向量、数据框等中将负值设置为零,但由于这是生物模型(T细胞计数不可能为负),我需要阻止它发生,以便这些值不会影响结果,而不仅仅是在最终输出中替换负数。
我目前正在使用 deSolve
解决一组普通微分方程组,想知道是否有任何方法可以防止微分变量值低于零。我看到了一些其他帖子关于在向量、数据框等中将负值设置为零,但由于这是生物模型(T细胞计数不可能为负),我需要阻止它发生,以便这些值不会影响结果,而不仅仅是在最终输出中替换负数。
我的标准方法是将状态变量转换为不受限制的尺度。对于正变量来说,最明显/标准的做法是编写关于 log(x)
的动态方程,而不是 x
的动态方程。
例如,在传染病流行的易感-感染-康复(SIR)模型中,方程式为 dS/dt = -beta*S*I; dI/dt = beta*S*I-gamma*I; dR/dt = gamma*I
我们会天真地将梯度函数写成
gfun <- function(time, y, params) {
g <- with(as.list(c(y,params)),
c(-beta*S*I,
beta*S*I-gamma*I,
gamma*I)
)
return(list(g))
}
如果我们将状态变量设为log(I)
而不是I
(理论上,我们也可以使用S
,但在实践中,S
接近边界的可能性要小得多),那么我们就有了d(log(I))/dt = (dI/dt)/I = beta*S-gamma
;其余方程需要使用exp(logI)
来引用I
。 因此:
gfun_log <- function(time, y, params) {
g <- with(as.list(c(y,params)),
c(-beta*S*exp(logI),
beta*S-gamma,
gamma*exp(logI))
)
return(list(g))
}
计算 exp(logI)
一次并将结果存储/重复使用比两次计算更为高效...
如果一个值在现实中不会变成负数,但在您的模型中变成了负数,那么您应该更改您的模型或者等效地修改您的微分方程,使其不可能出现这种情况。换句话说:不要试图限制您的动态变量,而是限制它们的导数。其他任何方法都只会导致求解器出现问题,而它不应该关心微分方程的变化。
举个简单的例子,假设:
在这种情况下,y只有在f(0) < 0时才会变成负数。因此,您只需要修改f,使得f(0) ≥ 0(并且仍然平滑)即可。
为了证明这个原理,您可以将f与适当修改的sigmoid函数相乘(这允许您使用平滑函数组合每个逻辑操作)。这样,在大多数值y的情况下,没有任何改变,并且只有在y接近0时才更改微分方程,即当您要进行操作时。
但是,我不建议您在不考虑模型的情况下使用sigmoid。如果您的模型在y=0附近完全错误,那么它很可能已经对附近的值无用。如果您的模拟涉及到此地形,并且希望结果具有意义,则应修复此问题。
x[1]=max(x[1],0)
,然后即使需要后处理,动态也应该是正确的。 - goryh