为什么deSolve中的ode函数总是在时间t = 0时触发事件?

huangapple go评论134阅读模式
英文:

Why does the ode function in deSolve always have an event occur at time = 0?

问题

我正在编写一段更复杂的代码,但它的行为与我的预期不符,经过一些尝试,我已经弄清楚了问题出在哪里:在deSolve的ode函数中,'events'事件的发生次数比我预期的要多一次,特别是在时间t=0时,即使不应该有事件。我在这里创建了一个最小的示例:

library(deSolve)

q <- 0

# 定义ODE系统
ode_fun <- function(t, y, parms) {
  dy_dt <- -y # y' = -y
  return(list(dy_dt))
}

# 定义事件函数
event_fun <- function(t, y, parms) {
  print(t)
  q <<- q + 1
  y <- y + 1
}

# 设置初始条件和时间点
y0 <- 0.5 # y的初始值
times <- seq(0, 5, by = 0.1) # 用于解ODE的时间点

# 设置ODE系统的参数
parms <- NULL

# 使用事件函数解ODE系统
ode_sol <- ode(y = y0, times = times, func = ode_fun, parms = parms,
               events = list(func = event_fun, times = c(2)))

# 绘制解的图形
plot(ode_sol, xlab = "时间", ylab = "y")
print(q)

在这个示例中,事件应该只发生一次,所以最终q应该为1,但实际上是2!为什么会发生这种情况?有没有办法修复它?

英文:

I am writing a more complex bit of code that wasn't behaving as I expected and after some tinkering have worked out what I think is going wrong: the 'events' in the ode function of deSolve are occuring once more than I would have expected, specifically there is an event at time=0 even when there should not be. I have created a minimal example here:

library(deSolve)

q &lt;- 0

# Define the ODE system
ode_fun &lt;- function(t, y, parms) {
  dy_dt &lt;- -y # y&#39; = -y
  return(list(dy_dt))
}

# Define the event function
event_fun &lt;- function(t, y, parms) {
  print(t)
  q &lt;&lt;- q +1
  y &lt;- y + 1
}

# Set up initial conditions and time points
y0 &lt;- 0.5 # initial value of y
times &lt;- seq(0, 5, by = 0.1) # time points to solve ODEs

# Set up the parameters for the ODE system
parms &lt;- NULL

# Solve the ODE system with the event function
ode_sol &lt;- ode(y = y0, times = times, func = ode_fun, parms = parms,
               events = list(func = event_fun, times = c(2)))

# Plot the solution
plot(ode_sol, xlab = &quot;time&quot;, ylab = &quot;y&quot;)
print(q)

In the example, the event should only happen once, so q should be 1 at the end, but it is actually 2!
Why does this happen? Is there a way to fix it?

答案1

得分: 2

这部分代码是一个R语言的代码示例,用于模拟ODE(常微分方程)的行为,特别是与事件相关的情况。在代码中,有两个事件函数,分别命名为event_fun,它们在不同的时间点触发。

代码中的第一个event_fun函数在时间点2处抛出错误"test0",并且会打印时间t。第二个event_fun函数在时间点2处抛出错误"test1",也会打印时间t。这两个事件函数被用于ODE求解中,以观察它们对求解的影响。

最后,代码展示了两个ODE的解,一个包含事件(ode_sol_with),一个不包含事件(ode_sol_without),并使用plot函数可视化它们的行为。在事件发生前,两个解是相同的。

如果您需要进一步的帮助或解释,请随时提问。

英文:

This is nothing to be concerned about. Let's investigate what happens. First I let the event function throw an error to be able to see the call stack:

event_fun &lt;- function(t, y, parms) {
  print(t)
  stop(&quot;test0&quot;)
  q &lt;&lt;- q +1
  y + 1
}

ode_sol &lt;- ode(y = y0, times = times, func = ode_fun, parms = parms,
               events = list(func = event_fun, time = c(2)))
traceback()
#7: stop(&quot;test0&quot;) at #3
#6: events$func(time, state, parms, ...)
#5: Func(times[1], y)
#4: eval(Func(times[1], y), rho)
#3: checkEventFunc(Eventfunc, times, y, rho)
#2: lsoda(y, times, func, parms, ...)
#1: ode(y = y0, times = times, func = ode_fun, parms = parms, events = list(func = #event_fun, 
#       time = c(2)))

We see that the function was called within a call to checkEventFunc. Let's take a look at that function:

deSolve:::checkEventFunc
#function (Func, times, y, rho) 
#{
#    tmp &lt;- eval(Func(times[1], y), rho)
#    if (length(tmp) != length(y)) 
#        stop(paste(&quot;The number of values returned by events$func() (&quot;, 
#            length(tmp), &quot;) must equal the length of the initial conditions vector #(&quot;, 
#            length(y), &quot;)&quot;, sep = &quot;&quot;))
#    if (!is.vector(tmp)) 
#        stop(&quot;The event function &#39;events$func&#39; must return a vector\n&quot;)
#}
#&lt;bytecode: 0x00000173fc02a080&gt;
#&lt;environment: namespace:deSolve&gt;

It is obvious (also from its name) that the only purpose of this function is to check that the event function was defined properly.

Now let's check the other call:

event_fun &lt;- function(t, y, parms) {
  print(t)
  if (t &gt; 0) stop(&quot;test1&quot;)
  q &lt;&lt;- q +1
  y + 1
}

ode_sol &lt;- ode(y = y0, times = times, func = ode_fun, parms = parms,
               events = list(func = event_fun, time = c(2)))
traceback()
#5: stop(&quot;test1&quot;) at #3
#4: events$func(time, state, parms, ...)
#3: (function (time, state) 
#   {
#       attr(state, &quot;names&quot;) &lt;- Ynames
#       events$func(time, state, parms, ...)
#   })(2, 0.0676677861933153)
#2: lsoda(y, times, func, parms, ...)
#1: ode(y = y0, times = times, func = ode_fun, parms = parms, events = list(func = event_fun, 
#       time = c(2)))

We can see that this is a call to the event function that is actually used by the solver.

You can also compare the solutions with and without event:

event_fun &lt;- function(t, y, parms) {
  y + 1
}
ode_sol_with &lt;- ode(y = y0, times = times, func = ode_fun, parms = parms,
               events = list(func = event_fun, time = c(2)))
ode_sol_without &lt;- ode(y = y0, times = times, func = ode_fun, parms = parms)

plot(ode_sol_with, xlab = &quot;time&quot;, ylab = &quot;y&quot;, ylim = c(0, 1))
par(new = TRUE)
plot(ode_sol_without, xlab = &quot;time&quot;, ylab = &quot;y&quot;, ylim = c(0, 1), col = &quot;red&quot;, lty = 2)

为什么deSolve中的ode函数总是在时间t = 0时触发事件?

Clearly, both solutions are identical before the event time.

huangapple
  • 本文由 发表于 2023年3月23日 07:59:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/75818222.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定