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

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

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

问题

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

  1. library(deSolve)
  2. q <- 0
  3. # 定义ODE系统
  4. ode_fun <- function(t, y, parms) {
  5. dy_dt <- -y # y' = -y
  6. return(list(dy_dt))
  7. }
  8. # 定义事件函数
  9. event_fun <- function(t, y, parms) {
  10. print(t)
  11. q <<- q + 1
  12. y <- y + 1
  13. }
  14. # 设置初始条件和时间点
  15. y0 <- 0.5 # y的初始值
  16. times <- seq(0, 5, by = 0.1) # 用于解ODE的时间点
  17. # 设置ODE系统的参数
  18. parms <- NULL
  19. # 使用事件函数解ODE系统
  20. ode_sol <- ode(y = y0, times = times, func = ode_fun, parms = parms,
  21. events = list(func = event_fun, times = c(2)))
  22. # 绘制解的图形
  23. plot(ode_sol, xlab = "时间", ylab = "y")
  24. 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:

  1. library(deSolve)
  2. q &lt;- 0
  3. # Define the ODE system
  4. ode_fun &lt;- function(t, y, parms) {
  5. dy_dt &lt;- -y # y&#39; = -y
  6. return(list(dy_dt))
  7. }
  8. # Define the event function
  9. event_fun &lt;- function(t, y, parms) {
  10. print(t)
  11. q &lt;&lt;- q +1
  12. y &lt;- y + 1
  13. }
  14. # Set up initial conditions and time points
  15. y0 &lt;- 0.5 # initial value of y
  16. times &lt;- seq(0, 5, by = 0.1) # time points to solve ODEs
  17. # Set up the parameters for the ODE system
  18. parms &lt;- NULL
  19. # Solve the ODE system with the event function
  20. ode_sol &lt;- ode(y = y0, times = times, func = ode_fun, parms = parms,
  21. events = list(func = event_fun, times = c(2)))
  22. # Plot the solution
  23. plot(ode_sol, xlab = &quot;time&quot;, ylab = &quot;y&quot;)
  24. 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:

  1. event_fun &lt;- function(t, y, parms) {
  2. print(t)
  3. stop(&quot;test0&quot;)
  4. q &lt;&lt;- q +1
  5. y + 1
  6. }
  7. ode_sol &lt;- ode(y = y0, times = times, func = ode_fun, parms = parms,
  8. events = list(func = event_fun, time = c(2)))
  9. traceback()
  10. #7: stop(&quot;test0&quot;) at #3
  11. #6: events$func(time, state, parms, ...)
  12. #5: Func(times[1], y)
  13. #4: eval(Func(times[1], y), rho)
  14. #3: checkEventFunc(Eventfunc, times, y, rho)
  15. #2: lsoda(y, times, func, parms, ...)
  16. #1: ode(y = y0, times = times, func = ode_fun, parms = parms, events = list(func = #event_fun,
  17. # time = c(2)))

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

  1. deSolve:::checkEventFunc
  2. #function (Func, times, y, rho)
  3. #{
  4. # tmp &lt;- eval(Func(times[1], y), rho)
  5. # if (length(tmp) != length(y))
  6. # stop(paste(&quot;The number of values returned by events$func() (&quot;,
  7. # length(tmp), &quot;) must equal the length of the initial conditions vector #(&quot;,
  8. # length(y), &quot;)&quot;, sep = &quot;&quot;))
  9. # if (!is.vector(tmp))
  10. # stop(&quot;The event function &#39;events$func&#39; must return a vector\n&quot;)
  11. #}
  12. #&lt;bytecode: 0x00000173fc02a080&gt;
  13. #&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:

  1. event_fun &lt;- function(t, y, parms) {
  2. print(t)
  3. if (t &gt; 0) stop(&quot;test1&quot;)
  4. q &lt;&lt;- q +1
  5. y + 1
  6. }
  7. ode_sol &lt;- ode(y = y0, times = times, func = ode_fun, parms = parms,
  8. events = list(func = event_fun, time = c(2)))
  9. traceback()
  10. #5: stop(&quot;test1&quot;) at #3
  11. #4: events$func(time, state, parms, ...)
  12. #3: (function (time, state)
  13. # {
  14. # attr(state, &quot;names&quot;) &lt;- Ynames
  15. # events$func(time, state, parms, ...)
  16. # })(2, 0.0676677861933153)
  17. #2: lsoda(y, times, func, parms, ...)
  18. #1: ode(y = y0, times = times, func = ode_fun, parms = parms, events = list(func = event_fun,
  19. # 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:

  1. event_fun &lt;- function(t, y, parms) {
  2. y + 1
  3. }
  4. ode_sol_with &lt;- ode(y = y0, times = times, func = ode_fun, parms = parms,
  5. events = list(func = event_fun, time = c(2)))
  6. ode_sol_without &lt;- ode(y = y0, times = times, func = ode_fun, parms = parms)
  7. plot(ode_sol_with, xlab = &quot;time&quot;, ylab = &quot;y&quot;, ylim = c(0, 1))
  8. par(new = TRUE)
  9. 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:

确定