As with integration, SciPy has some extremely accurate general-purpose solvers for systems of ordinary differential equations of first order:
For real-valued functions, we have basically two flavors: ode
(with options passed with the set_integrator
method) and odeint
(simpler interface). The syntax of ode
is as follows:
ode(f,jac=None)
The first parameter, f
, is the function to be integrated, and the second parameter, jac
, refers to the matrix of partial derivatives with respect to the dependent variables (the Jacobian). This creates an ode
object, with different methods to indicate the algorithm to solve the system (set_integrator
), the initial conditions (set_initial_value
), and different parameters to be sent to the function or its Jacobian.
The options for integration algorithm are 'vode'
for real-valued variable coefficient ODE solver, with fixed-leading-coefficient implementation (it provides Adam's method for non-stiff problems and BDF for stiff); 'zvode'
for complex-valued variable coefficient ODE solver, with similar options as the preceding option; 'dopri5'
for a Runge-Kutta method of order (4)5; 'dop853'
for a Runge-Kutta method of order 8(5, 3).
The next code snippet presents an example of usage of the scipy.integrate.ode
to solve the initial value problem using the following formula:
We compute each step sequentially and compare it with the actual solution, which is known. You will notice that virtually there is no difference:
>>> import numpy >>> from scipy.integrate import ode >>> f=lambda t,y: -20*y # The ODE >>> actual_solution=lambda t:numpy.exp(-20*t) # actual solution >>> dt=0.01 # time step >>> solver=ode(f).set_integrator('dop853') # solver >>> solver.set_initial_value(1,0) # initial value >>> while solver.successful() and solver.t<=1+dt: # solve the equation at succesive time steps, # until the time is greater than 1 # but make sure that the solution is successful print (solver.t, solver.y, actual_solution(solver.t)) # We compare each numerical solution with the actual # solution of the ODE solver.integrate(solver.t + dt) # solve next step
Once run, the preceding code gives us the following output:
<scipy.integrate._ode.ode at 0x10eac5e50> 0 [ 1.] 1.0 0.01 [ 0.81873075] 0.818730753078 0.02 [ 0.67032005] 0.670320046036 0.03 [ 0.54881164] 0.548811636094 0.04 [ 0.44932896] 0.449328964117 0.05 [ 0.36787944] 0.367879441171 0.06 [ 0.30119421] 0.301194211912 0.07 [ 0.24659696] 0.246596963942 0.08 [ 0.20189652] 0.201896517995 0.09 [ 0.16529889] 0.165298888222 0.1 [ 0.13533528] 0.135335283237 ... 0.9 [ 1.52299797e-08] 1.52299797447e-08 0.91 [ 1.24692528e-08] 1.24692527858e-08 0.92 [ 1.02089607e-08] 1.02089607236e-08 0.93 [ 8.35839010e-09] 8.35839010137e-09 0.94 [ 6.84327102e-09] 6.84327102222e-09 0.95 [ 5.60279644e-09] 5.60279643754e-09 0.96 [ 4.58718175e-09] 4.58718174665e-09 0.97 [ 3.75566677e-09] 3.75566676594e-09 0.98 [ 3.07487988e-09] 3.07487987959e-09 0.99 [ 2.51749872e-09] 2.51749871944e-09 1.0 [ 2.06115362e-09] 2.06115362244e-09
The full output is displayed on the corresponding section of the IPython Notebook for this chapter. For systems of differential equations of first order with complex-valued functions, we have a wrapper of ode
, which we call with the complex_ode
command. Syntax and usage are similar to those of ode
.
The syntax of odeint
is much more intuitive, and more Python friendly:
odeint(func, y0, t, args=(), Dfun=None, col_deriv=0, full_output=0, ml=None, mu=None, rtol=None, atol=None, tcrit=None, h0=0.0, hmax=0.0, hmin=0.0, ixpr=0, mxstep=0, mxhnil=0, mxordn=12, mxords=5, printmessg=0)
The most impressive part of this routine is that one is able to indicate not only the Jacobian, but also whether this is banded and how many nonzero diagonals are under or over the main diagonal we have (with the ml
and mu
options). This speeds up computations by a huge factor. Another amazing feature of odeint
is the possibility to indicate critical points for the integration (tcrit
).
We will now introduce an application to analyze Lorentz attractors with the routines presented in this section.
18.116.67.70