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)
也许不是最复杂的方法,但快速而肮脏的方法是将与时间相关的强制变量保留为外部(全局)变量。
我用来pmax(1,ceiling(t))从时间索引转换为数据帧的行索引(pmax如果你想从0开始,这是必要的t=0,ceiling(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)
