使用时间序列参数在 R 中求解 ODE

Ice*_*lim 5 r ode differential-equations

我正在尝试使用 deSolve 在 R 中解决一个简单的 ODE: dQ/dt = f(Q)*(P - E).整个过程是 Q 的时间序列。诀窍是 P 和 E 是数据本身的固定时间序列,因此 diff eq 仅在 Q 中有效。

用固定的时间步长迭代解决这个问题相对简单,但我试图找到一种在 R 中使用自适应时间步长的方法。因为 P 和 E 是离散的,连续的时间步长可能具有相同的 P 和 E 值,其中很好。我一直在玩 deSolve,但一直无法解决这个问题。理想情况下,我想使用标准的四阶 Runge-Kutta。

有任何想法吗?在 MATLAB 中做吗?

编辑可复制的例子。我希望能够使用可变时间步长 Runge-Kutta 4 方法进行此计算。我可以很容易地对固定时间步 rk4 进行编程,而不是自适应。

working <- structure(list(datetime = structure(c(1185915600, 1185919200, 
1185922800, 1185926400, 1185930000, 1185933600, 1185937200, 1185940800, 
1185944400, 1185948000, 1185951600), class = c("POSIXct", "POSIXt"
), tzone = "UTC"), p = c(0, 0, 0, 1.1, 0.5, 0.7, 0, 0, 1.3, 0, 
0), e = c(0.15, 0.14, 0.13, 0.21, 0.15, 0.1, 0.049, 0, 0, 0, 
0), qsim = c(-1.44604436552566, NA, NA, NA, NA, NA, NA, NA, NA, 
NA, NA)), .Names = c("datetime", "p", "e", "qsim"), row.names = c(NA, 11L), 
class = "data.frame")


# this is the derivative function dQ/dt = f(Q,p,e) where p and e are time series
dqdt <- function(qsim, pcp, pet) {
  dq <- (qsim ^ 2) * ((pcp - pet) / qsim) 
  return(dq)
}

# loops through and calculates the Q at each time step using the Euler method
for (i in 1:(nrow(working) - 1)) {
  dq <- dqdt(working$qsim[i], pcp = working$p[i], pet = working$e[i])
  working$qsim[i + 1] <- working$qsim[i] + dq
}
Run Code Online (Sandbox Code Playgroud)

Ben*_*ker 2

也许不是最复杂的方法,但快速而肮脏的方法是将与时间相关的强制变量保留为外部(全局)变量。

我用来pmax(1,ceiling(t))从时间索引转换为数据帧的行索引(pmax如果你想从0开始,这是必要的t=0ceiling(0)x[0]R中通常是一个空向量,然后它会破坏东西)。可能还有其他方法来进行索引。

library(deSolve)
gradfun <- function(t,y,parms) {
   pcp <- working$p[pmax(1,ceiling(t))]
   pet <- working$e[pmax(1,ceiling(t))]
   list(y^2*((pcp-pet)/y),NULL)
}

gradfun(0,working$qsim[1],1)   ## test
ode1 <- ode(y=c(qsim=working$qsim[1]),func=gradfun,
                time=seq(0,nrow(working),length.out=101),
                parms=NULL,method="rk4")
plot(ode1)
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述