我不确定scipy.integrate.solve_ivp中的事件处理是否正常工作。在下面的示例中,我对一个导数进行了积分,该导数将导致三次多项式具有x = -6,x = -2和x = 2的三个根。我设置了一个事件函数,该函数返回y,在这些x值处将为零。我希望在解决方案的t_events属性中看到三个条目,但是即使解决方案跨过x轴三遍,我也只能看到一个条目。
我在这里做错什么了吗?
def fprime(x, y):
return 3 * x**2 + 12 * x - 4
def event(x, y):
return y
import numpy as np
from scipy.integrate import solve_ivp
sol = solve_ivp(fprime, (-8, 4), np.array([-120]), t_eval=np.linspace(-8, 4, 10), events=[event])
上面的代码导致:
message: 'The solver successfully reached the interval end.'
nfev: 26
njev: 0
nlu: 0
sol: None
status: 0
success: True
t: array([-8. , -6.66666667, -5.33333333, -4. , -2.66666667,
-1.33333333, 0. , 1.33333333, 2.66666667, 4. ])
t_events: [array([-6.])]
y: array([[-120. , -26.96296296, 16.2962963 , 24. ,
10.37037037, -10.37037037, -24. , -16.2962963 ,
26.96296296, 120. ]])
```
问题是,您可以从sol.y数组中看到三个零(三个符号变化),但是只记录了一个事件。
1.0.0 1.13.3 sys.version_info(major=3, minor=6, micro=0, releaselevel='final', serial=0)
[更新]:如果我对resolve_ivp使用可选的max_step参数,并使其足够小,则可以看到所有三个根。似乎事件函数不是在t_eval步骤中调用的,而是仅在内部求解器步骤中调用的,内部求解器步骤比t_eval步骤少得多,并且最终会跳过一些根。这似乎不太有用,因为您必须知道如何设置max_steps以避免丢失根。
答案 0 :(得分:2)
事件函数不是在
t_eval
步骤中调用,而是仅在内部求解器步骤中调用
这是正确的。在一对新的(t, y)
对is found之后,从事件and passed到find_active_events
计算事件,这会将事件功能的符号与上一步进行比较。
t_eval
完全不被事件计算使用,它由later处理。因此,事件看到的符号更改就是您在输出中看到的带有t_eval=None
的符号更改,其中只有一个。
y: array([[-120. , -110.49687882, -35.93785936, 94.46893375,
120. ]])
似乎值得在SciPy追踪器上提出问题;有a few open issues regarding solve_ivp
,仍然很新。