Reputation: 2433
I am not sure if the event handling in scipy.integrate.solve_ivp is working correctly. In the example below, I integrated a derivative which should result in a cubic polynomial with three roots at x=-6, x=-2 and x=2. I set up an event function that returns y, which will be zero at those x-values. I expected to see three entries in the t_events attribute of the solution, but I only see one, even though it is clear the solution crosses the x-axis three times.
Am I doing something wrong here?
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])
The code above results in:
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. ]])
```
The problem is you can see from the sol.y array there should be three zeros (there are three sign changes), but only one event is recorded.
1.0.0 1.13.3 sys.version_info(major=3, minor=6, micro=0, releaselevel='final', serial=0)
[UPDATE]: if I use the optional max_step argument to solve_ivp, and make it small enough, then I see all three roots. It seems that the event functions are not called at the t_eval steps, but rather only on internal solver steps, which are far fewer than the t_eval steps, and which end up skipping some roots. That doesn't seem very useful, as you have to know how to set max_steps to avoid missing roots.
Upvotes: 16
Views: 16770
Reputation:
the event functions are not called at the
t_eval
steps, but rather only on internal solver steps
This is correct. After a new (t, y)
pair is found, the events are computed from them and passed to find_active_events
that will compare the signs of event-functions to the previous step.
t_eval
is not used by the event computation at all, it is dealt with later. So the sign changes that events see are those that you see in the output with t_eval=None
, of which there is just one.
y: array([[-120. , -110.49687882, -35.93785936, 94.46893375,
120. ]])
Seems worth raising an issue on SciPy tracker; there are a few open issues regarding solve_ivp
, which is still pretty new.
Upvotes: 5