有没有一种方法可以强制ode()[deSolve-R包]在ode函数的每个集成步骤中提供输出

时间:2019-03-31 17:42:38

标签: r ode

我想在数值方案的每个步骤中提取状态变量的值。

deSolve R软件包中的ode()函数使用已实现的ODE求解器之一对常微分方程组进行数值求解。为此,它使用动态调整的集成步骤,该步骤基于每次集成结束时本地截断错误的值。用户基本上可以指定所需的输出时间,以定义时间步长网格,该步长可以等于或小于输出时间。

如果我们以Lotka Volterra Predator-Prey模型(带有物流猎物)为例:

LVmod <- function(Time, State, Pars) {
  with(as.list(c(State, Pars)), {
    Ingestion    <- rIng  * Prey * Predator
    GrowthPrey   <- rGrow * Prey * (1 - Prey/K)
    MortPredator <- rMort * Predator

    dPrey        <- GrowthPrey - Ingestion
    dPredator    <- Ingestion * assEff - MortPredator

    return(list(c(dPrey, dPredator)))
  })
}

参数和状态变量定义为:


pars  <- c(rIng   = 0.2,    # /day, rate of ingestion
           rGrow  = 1.0,    # /day, growth rate of prey
           rMort  = 0.2 ,   # /day, mortality rate of predator
           assEff = 0.5,    # -, assimilation efficiency
           K      = 10)     # mmol/m3, carrying capacity



yini  <- c(Prey = 1, Predator = 2)

并按每天的时间要求输出:

times <- seq(0, 200, by = 1)

out   <- ode(yini, times, LVmod, pars)
diagnostics(out)

查看诊断信息,可以看到求解器总共使用282步,而生成的输出为200步(在times对象中设置)。

对于我正在运行的模型,这种差异要大得多,并且要对系统的稳定性进行完整的分析,我需要每个集成步骤的输出以及步骤的大小。有没有办法从ode中提取此信息?

2 个答案:

答案 0 :(得分:1)

可以通过在模型函数中放置印刷品或猫来观察积分器的工作方式:

library("deSolve")

LVmod <- function(Time, State, Pars) {
  with(as.list(c(State, Pars)), {
    Ingestion    <- rIng  * Prey * Predator
    GrowthPrey   <- rGrow * Prey * (1 - Prey/K)
    MortPredator <- rMort * Predator

    dPrey        <- GrowthPrey - Ingestion
    dPredator    <- Ingestion * assEff - MortPredator
    cat("Time=", Time, "dPrey"=dPrey, "dPredator=", dPredator, "\n")
    return(list(c(dPrey, dPredator)))
  })
}

这适用于自动和固定步长求解器。但是请注意,自动步进器有时可能会放弃步骤并重试,因此时间并不总是单调的。如果要保存数据以备后用,请使用<<-将数据保存到列表中,最好是在模拟周围构造一个闭包。

答案 1 :(得分:0)

因此,经过一些研究[1,2]:

有两种不适合时间步长的显式方法:euler方法和rk4方法。它们有两种实现方式:

  1. 作为一般rk解算器的rkMethod。在这种情况下,可以通过设置参数hini来独立于times参数指定所使用的时间步长。功能ode使用此通用代码
  2. 作为特殊的求解器代码euler和rk4。这些实施方式得到了简化,并且具有较少的选择以避免开销。使用的时间步长由times参数中的时间增量确定。

在LV示例中,接下来的两个语句都触发Euler方法,第一个语句使用“特殊”代码,时间步长= 1(由times参数施加),第二个语句使用带有时间的广义方法hini设置的步骤。


    out.euler  <- euler(y = state, times = times, func = LVmod, parms = parameters)
    out.rk <- ode(y = state, times = times, func = LVmod, parms = parameters,
                 method = "euler", hini = 0.01)

在这个非常简单的系统中,使用显式Euler方案可能有意义,但是对于更复杂的系统,尽管rk4仍然是显式方案,还是建议的。

总结:

  • 似乎没有办法在每个步骤中提取状态值 在ode()函数中使用动态时间步长时。
  • 您可以为两个显式方案设置恒定步长:Euler和rk4。

[1] Soetaert,K. E. R.,Petzoldt,T.,&Setzer,R. W.(2010)。在R:包deSolve中求解微分方程。统计软件杂志,33。

[p] [2] Soetaert,K.,Petzoldt,T.,&Setzer,R. W.(2010)。 Package deSolve:在R. J Stat Softw,33(9),1-25中求解初值微分方程。