I have opened PR #21741 to add callbacks in scipy.integrate.solve_ivp
for use cases such as progress tracking and dynamic max step size control. This callback is not currently intended to directly control the state or RHS of the integration as currently solve_ivp
is not equipped to handle this.
The current discussion has aligned on passing the callback an instance of class IntermediateOdeResult
(current naming) inheriting from _RichResult
It would contain attributes that have information about the integration, e.g. time, state, nsteps, etc.
In review, there was a desire to open a discussion on when the callback should be called and what information should be supplied to the callback in those cases. I am trying to distill a few different pieces of the conversation down, and the list is meant as a starting point for discussion.
First, some definitions used in the options related to timing/type of callback:
- after-step callback: callback that is called after every (successful) integration step of the algorithm.
- upon-event callback: callback that is called when any event occurs
- upon-event-type callback: callback that is called only when a specific event occurs
More definitions:
t_current
: current integration time after stepy_current
current integration state after stept
: history of time for all steps including last stepy
: history of state for all steps including last stept_events_current
: times of events that occured at last stepy_events_current
: states of system at times in above linet_events
history of times of events for all steps including last stepy_events
history of states of system at times in above lineevent_id
index of a specific event that occured over last stepevent_indices
indices of all events that occured over last stepcontext
what triggered the callback
Options:
-
Only use a single after-step callback with history: include
t
,y
,t_events
,y_events
,event_indices
. Thecurrent
values could also be passed for convenience. -
Only use a single after-step callback without history: include
t_current
,y_current
,t_events_current
,y_events_current
,event_indices
. -
Use a single callback, and call it after-step and upon-event without history.
- Using
context
to distinguish what triggered callback.
- Using
-
Use a single callback, and call it after-step and upon-event-type without history.
- Similar to 3, but it would be called per step type.
context
could be the same asevent_id
in this case.
- Similar to 3, but it would be called per step type.
-
Use different callbacks for after-step and upon-event without history.
- No need for
context
.
- No need for
-
Use different callbacks for after-step and upon-event-type without history.
- Need
event_id
and could be same ascontext
. - 1 callback per event type could also be considered.
event_id
/context
is possibly unneeded, but could be useful.
- Need
I chose to include with history for option 1, but it could potentially be considered for any option 3-6, particularly for the after-step context.
For options 3-6 we could choose to limit the information available to the different types of callback calls, e.g. only after step information in after-step context and only the state at the time of event in the upon-event context. Or we could chose to provide similar types of information to all contexts.