ODE Solvers¶
scikits.odes
contains two main routines for solving ODEs: the simpler
scikits.odes.odeint.odeint()
, and the more configurable
scikits.odes.ode.ode
. Both these routines allow selection of the
solver and solution method used. Additionally, it is also possible to directly
use the low level interface to individual solvers.
- scikits.odes.odeint.odeint(rhsfun, tout, y0, method='bdf', **options)[source]¶
Integrate a system of ordinary differential equations. odeint is a wrapper around the ode class, as a convenience function to quickly integrate a system of ode. Solves the initial value problem for stiff or non-stiff systems of first order ode’s:
rhs = dy/dt = fun(t, y)
where y can be a vector, then rhsfun must be a function computing rhs with signature:
rhsfun(t, y, rhs)
storing the computed dy/dt in the rhs array passed to the function
- Parameters:
rhsfun (callable(t, y, out)) – Computes the derivative at dy/dt in terms of t and y, and stores in out
y0 (array) – Initial condition on y (can be a vector).
t (array) – A sequence of time points for which to solve for y. The initial value point should be the first element of this sequence.
method (string, solution method to use.) –
Available are all the ode class solvers as well as some convenience shorthands:
Method
Meaning
bdf
This uses the ‘cvode’ solver in default from, which is a variable step, variable coefficient Backward Differentiation Formula solver, good for stiff ODE. Newton iterations are used to solve the nonlinear system.
admo
This uses the ‘cvode’ solver with option lmm_type=’ADAMS’, which is a variable step Adams-Moulton method (linear multistep method), good for non-stiff ODE. Functional iterations are used to solve the nonlinear system.
rk5
This uses the ‘dopri5’ solver, which is a variable step Runge-Kutta method of order (4)5 (use for non-stiff ODE)
rk8
This uses the ‘dop853’ solver, which is a variable step Runge-Kutta method of order 8(5,3)
For educational purposes, you can also access following methods:
Method
Meaning
beuler
This is the Implicit Euler (backward Euler) method (order 1), which is obtained via the ‘bdf’ method, setting the order option to 1, setting large tolerances, and fixing the stepsize. Use option ‘step’ to change stepsize, default: step=0.05. Use option ‘rtol’ and ‘atol’ to use more strict tolerances Note: this is not completely the backward Euler method, as the cvode solver has added control options!
trapz
This is the Trapezoidal Rule method (order 2), which is obtained via the ‘admo’ method, setting option order to 2, setting large tolerances and fixing the stepsize. Use option ‘step’ to change stepsize, default: step=0.05. Use option ‘rtol’ and ‘atol’ to use more strict tolerances Note: The cvode solver might change the order to 1 internally in which case this becomes beuler method. Set atol, rtol options as strict as possible.
You can also access the solvers of ode via their names:
Method
Meaning
cvode
This uses the ‘cvode’ solver
dopri5
This uses the ‘dopri5’ solver
dop853
This uses the ‘dop853’ solver
options (extra solver options, optional) – Every solver has it’s own extra options, see the ode class and the details of the solvers available there to know the options possible per solver
- Returns:
solution – A single named tuple is returned containing the result of the integration.
Field
Meaning
flag
An integer flag
values
Named tuple with fields t and y
errors
Named tuple with fields t and y
roots
Named tuple with fields t and y
tstop
Named tuple with fields t and y
message
String with message in case of an error
- Return type:
named tuple
See also
scikits.odes.ode.ode
a more object-oriented integrator
scikits.odes.dae.dae
a solver for differential-algebraic equations
scipy.integrate.quad
for finding the area under a curve
Examples
The second order differential equation for the angle theta of a pendulum acted on by gravity with friction can be written:
\[\theta''(t) + b \theta'(t) + c \sin(\theta(t)) = 0\]where b and c are positive constants, and a prime (’) denotes a derivative. To solve this equation with odeint, we must first convert it to a system of first order equations. By defining the angular velocity
omega(t) = theta'(t)
, we obtain the system:\[\theta'(t) = \omega(t) \omega'(t) = -b \omega(t) - c \sin(\theta(t))\]We assume the constants are b = 0.25 and c = 5.0:
>>> b = 0.25 >>> c = 5.0
Let y be the vector [theta, omega]. We implement this system in python as:
>>> def pend(t, y, out): ... theta, omega = y ... out[:] = [omega, -b*omega - c*np.sin(theta)] ...
In case you want b and c easily changable, make pend a class method, and consider attributes b and c accessible via self.b and self.c. For initial conditions, we assume the pendulum is nearly vertical with theta(0) = pi - 0.1, and it initially at rest, so omega(0) = 0. Then the vector of initial conditions is
>>> y0 = [np.pi - 0.1, 0.0]
We generate a solution 101 evenly spaced samples in the interval 0 <= t <= 10. So our array of times is
>>> t = np.linspace(0, 10, 101)
Call odeint to generate the solution.
>>> from scikits.odes.odeint import odeint >>> sol = odeint(pend, t, y0)
The solution is a named tuple sol. sol.values.y is an array with shape (101, 2). The first column is theta(t), and the second is omega(t). The following code plots both components.
>>> import matplotlib.pyplot as plt >>> plt.plot(sol.values.t, sol.values.y[:, 0], 'b', label='theta(t)') >>> plt.plot(sol.values.t, sol.values.y[:, 1], 'g', label='omega(t)') >>> plt.legend(loc='best') >>> plt.xlabel('t') >>> plt.grid() >>> plt.show()
- class scikits.odes.ode.ode(integrator_name, eqsrhs, **options)[source]¶
A generic interface class to differential equation solvers.
- Parameters:
integrator_name (
'cvode'
,'dopri5'
or'dop853'
) –The solver to use.
'cvode'
selects the CVODE solver from the SUNDIALS package. See py:class:scikits.odes.sundials.cvode.CVODE for solver specific options.'dopri5'
selects the Dormand & Prince Runge-Kutta order (4)5 solver from scipy.eqsrhs (right-hand-side function) –
Right-hand-side of a first order ode. Generally, you can assume the following signature to work:
eqsrhs(x, y, return_rhs)
with
x: independent variable, eg the time, float
y: array of n unknowns in x
return_rhs : array that must be updated with the value of the right-hand-side, so f(t,y). The dimension is equal to dim(y)
- return value: An integer, 0 for success, 1 for failure.
It is not guaranteed that a solver takes this status into account
Some solvers will allow userdata to be passed to eqsrhs, or optional formats that are more performant.
options (additional options of the solver) – See set_options method of the integrator_name you selected for details. Set option old_api=False to use the new API. In the future, this will become the default!
See also
scikits.odes.odeint.odeint
an ODE integrator with a simpler interface
scipy.integrate
Methods in scipy for ODE integration
Examples
ODE arise in many applications of dynamical systems, as well as in discritisations of PDE (eg moving mesh combined with method of lines). As an easy example, consider the simple oscillator,
>>> from __future__ import print_function >>> from numpy import cos, sin, sqrt >>> k = 4.0 >>> m = 1.0 >>> initx = [1, 0.1] >>> def rhseqn(t, x, xdot): # we create rhs equations for the problem xdot[0] = x[1] xdot[1] = - k/m * x[0]
>>> from scikits.odes import ode >>> solver = ode('cvode', rhseqn, old_api=False) >>> result = solver.solve([0., 1., 2.], initx) >>> print(' t Solution Exact') >>> print('------------------------------------') >>> for t, u in zip(result.values.t, result.values.y): print('%4.2f %15.6g %15.6g' % (t, u[0], initx[0]*cos(sqrt(k/m)*t)+initx[1]*sin(sqrt(k/m)*t)/sqrt(k/m)))
More examples in the Examples directory and IPython worksheets.
- get_info()[source]¶
Return additional information about the state of the integrator.
- Returns:
A dictionary filled with internal data as exposed by the integrator.
See the get_info method of your chosen integrator for details.
- init_step(t0, y0)[source]¶
Initializes the solver and allocates memory. It is not needed to call this method if solve is used to compute the solution. In the case step is used, init_step must be called first.
- Parameters:
t0 (number) – initial time
y0 (array) – initial condition for y (can be list or numpy array)
- Returns:
old_api is False (namedtuple) – namedtuple with the following attributes
Field
Meaning
flag
An integer flag (StatusEnum)
values
Named tuple with entries t and y
errors
Named tuple with entries t and y
roots
Named tuple with entries t and y
tstop
Named tuple with entries t and y
message
String with message in case of an error
old_api is True (tuple) – tuple with the following elements in order
Field
Meaning
flag
boolean status of the computation (successful or error occured)
t_out
inititial time
- set_options(**options)[source]¶
Set specific options for the solver. See the solver documentation for details.
Calling set_options a second time, is only possible for options that can change during runtime.
- set_tstop(tstop)[source]¶
Add a stop time to the integrator past which he is not allowed to integrate.
- Parameters:
tstop (float time) – Time point in the future where the integration must stop. You can indicate like this that integration past this point is not allowed, in order to avoid undefined behavior. You can achieve the same result with a call to set_options(tstop=tstop)
- solve(tspan, y0)[source]¶
Runs the solver.
- Parameters:
tspan (array (or similar)) – a list of times at which the computed value will be returned. Must contain the start time as first entry.
y0 (array (or similar)) – a list of initial values
- Returns:
old_api is False (namedtuple) – namedtuple with the following attributes
Field
Meaning
flag
An integer flag (StatusEnum)
values
Named tuple with entries t and y
errors
Named tuple with entries t and y
roots
Named tuple with entries t and y
tstop
Named tuple with entries t and y
message
String with message in case of an error
old_api is True (tuple) – tuple with the following elements in order
Field
Meaning
flag
indicating return status of the solver
t
numpy array of times at which the computations were successful
y
numpy array of values corresponding to times t (values of y[i, :] ~ t[i])
t_err
float or None - if recoverable error occured (for example reached maximum number of allowed iterations), this is the time at which it happened
y_err
numpy array of values corresponding to time t_err
- step(t, y_retn=None)[source]¶
Method for calling successive next step of the ODE solver to allow more precise control over the solver. The ‘init_step’ method has to be called before the ‘step’ method.
A step is done towards time t, and output at t returned. This time can be higher or lower than the previous time. If option ‘one_step_compute’==True, and the solver supports it, only one internal solver step is done in the direction of t starting at the current step.
If old_api=True, the old behavior is used: if t>0.0 then integration is performed until this time and results at this time are returned in y_retn if t<0.0 only one internal step is perfomed towards time abs(t) and results after this one time step are returned
- Parameters:
t (number)
y_retn (numpy vector (ndim = 1)) – in which the computed value will be stored (needs to be preallocated). If None y_retn is not used.
- Returns:
old_api is False (namedtuple) – namedtuple with the following attributes
Field
Meaning
flag
An integer flag (StatusEnum)
values
Named tuple with entries t and y
errors
Named tuple with entries t and y
roots
Named tuple with entries t and y
tstop
Named tuple with entries t and y
message
String with message in case of an error
old_api is True (tuple) – tuple with the following elements in order
Field
Meaning
flag
status of the computation (successful or error occured)
t_out
time, where the solver stopped (when no error occured, t_out == t)