solve_ivp
it is possible to provide extra functions, event-functions, that monitor mathematically
if any events occur. Each function must take the same input as the dydt
-function (the first
argument of solve_ivp
), and must return a float which is a continuous value being
a function of the independent and dependent variables in the problem. Given one or several such event-functions,
solve_ivp
will monitor if there are any sign-changes in the floats of the event-functions, while
it solves the differential equations.
If so, the precise times at which that happens will be evaluated and returned in the end. If the event-function
whose float is changing sign has an attribute, .terminal
set to True
, then
solve_ivp
will further stop at the time of the event.
%matplotlib inline from scipy.integrate import solve_ivp import numpy as np import matplotlib.pyplot as plt plt.rc('font', size=16) tinit = 0 tfinal = 10 trange = [tinit,tfinal] t_eval = np.linspace(tinit,tfinal,100) yinit = np.array([1]) # the event function requires it to be np.array dydt = lambda t, y: 0.9 * y**2 * np.cos(t) # define the event function with the # independent and dependent variable as input f = lambda t, y: y - 5 # supply it in a list as value for keyword "events": mysol = solve_ivp(dydt, trange, yinit, t_eval=t_eval, max_step=1e-2, events=[f]) ts = mysol.t ys = mysol.y[0] # now extract the times at which the events occurred t_events = mysol.t_events[0] # [0] because we want output from the # first (and only) event function print(t_events) fig,ax = plt.subplots(1,1) ax.plot(ts,ys) ax.grid() ax.set_ylim([0,11]) ax.set_xlabel('$t$') ax.set_ylabel('$y$') ax.scatter(t_events,5 * np.ones(t_events.shape)) fig.tight_layout() fig.savefig('ode_events_1.png')
[1.09491408 2.04667858 7.37809938 8.32986388]
%matplotlib inline from scipy.integrate import solve_ivp import numpy as np import matplotlib.pyplot as plt plt.rc('font', size=16) tinit = 0 tfinal = 10 trange = [tinit,tfinal] t_eval = np.linspace(tinit,tfinal,100) yinit = np.array([1]) dydt = lambda t, y: 0.9 * y**2 * np.cos(t) # define the event functions f = lambda t, y: y - 5 g = lambda t, y: y - t # supply it in a list as value for keyword "events": mysol = solve_ivp(dydt, trange, yinit, t_eval=t_eval, max_step=1e-2, events=[f,g]) # provide two event functions ts = mysol.t ys = mysol.y[0] t_events_f = mysol.t_events[0] # times for events with f t_events_g = mysol.t_events[1] # times for events with g fig,ax = plt.subplots(1,1) ax.plot(ts,ys) ax.grid() ax.set_ylim([0,11]) ax.set_xlabel('$t$') ax.set_ylabel('$y$') print(t_events) ax.scatter(t_events_f,5 * np.ones(t_events_f.shape)) ax.plot(t_events_g,t_events_g,marker='s',linestyle='dashed') fig.tight_layout() fig.savefig('ode_events_2.png')
def
, the
resulting function may be given any of the two attributes .direction
and .terminal
.
.direction
attribute is set to some
positive value, it means that solve_ivp
should
only consider an event to occur if the event function changes its
value in ascending direction (from negative to positive). Likewise, if
the .direction
attribute is set to some
negative value, it means that an event has only occured
whenever
the event function changes in descending direction (from positive to negative).
.terminal
attribute is set,
solve_ivp
should stop its integration whenever the
first event occurs according to this event function.
%matplotlib inline from scipy.integrate import solve_ivp import numpy as np import matplotlib.pyplot as plt plt.rc('font', size=16) tinit = 0 tfinal = 10 trange = [tinit,tfinal] yinit = np.array([1]) dydt = lambda t, y: 0.9 * y**2 * np.cos(t) # define an event function def f(t,y): return y - 5 f.direction = -1 # only event if f changes sign while decreasing f.terminal = True # solve_ivp should stop mysol = solve_ivp(dydt, trange, yinit, max_step=1e-2, events=[f]) ts = mysol.t ys = mysol.y[0] t_events = mysol.t_events[0] # times for events with f fig,ax = plt.subplots(1,1) ax.plot(ts,ys) ax.grid() ax.set_ylim([0,11]) ax.set_xlabel('$t$') ax.set_ylabel('$y$') print(t_events) ax.scatter(t_events,5 * np.ones(t_events.shape)) fig.tight_layout() fig.savefig('ode_events_3.png')
Choose which booklet to go to: