Skip to content Skip to sidebar Skip to footer

Stiff Ode-solver

I need an ODE-solver for a stiff problem similar to MATLAB ode15s. For my problem I need to check how many steps (calculations) is needed for different initial values and compare t

Solution 1:

I'm seeing something similar; with the 'vode' solver, changing methods between 'adams' and 'bdf' doesn't change the number of steps by very much. (By the way, there is no point in using order=15; the maximum order of the 'bdf' method of the 'vode' solver is 5 (and the maximum order of the 'adams' solver is 12). If you leave the argument out, it should use the maximum by default.)

odeint is a wrapper of LSODA. ode also provides a wrapper of LSODA: change 'vode' to 'lsoda'. Unfortunately the 'lsoda' solver ignores the step=True argument of the integrate method.

The 'lsoda' solver does much better than 'vode' with method='bdf'. You can get an upper bound on the number of steps that were used by initializing tvals = [], and in func, do tvals.append(t). When the solver completes, set tvals = np.unique(tvals). The length of tvals tells you the number of time values at which your function was evaluated. This is not exactly what you want, but it does show a huge difference between using the 'lsoda' solver and the 'vode' solver with method 'bdf'. The number of steps used by the 'lsoda' solver is on the same order as you quoted for matlab in your comment. (I used mu=10000, tf = 10.)

Update: It turns out that, at least for a stiff problem, it make a huge difference for the 'vode' solver if you provide a function to compute the Jacobian matrix.

The script below runs the 'vode' solver with both methods, and it runs the 'lsoda' solver. In each case, it runs the solver with and without the Jacobian function. Here's the output it generates:

vode   adams    jac=Nonelen(tvals) = 517992
vode   adams    jac=jac   len(tvals) = 195
vode   bdf      jac=Nonelen(tvals) = 516284
vode   bdf      jac=jac   len(tvals) = 55
lsoda           jac=Nonelen(tvals) = 49
lsoda           jac=jac   len(tvals) = 49

The script:

from __future__ import print_function

import numpy as np
from scipy.integrate import ode


deffunc(t, u, mu):
    tvals.append(t)
    u1 = u[1]
    u2 = mu*(1 - u[0]*u[0])*u[1] - u[0]
    return np.array([u1, u2])


defjac(t, u, mu):
    j = np.empty((2, 2))
    j[0, 0] = 0.0
    j[0, 1] = 1.0
    j[1, 0] = -mu*2*u[0]*u[1] - 1
    j[1, 1] = mu*(1 - u[0]*u[0])
    return j


mu = 10000.0
u0 = [2, 0]
t0 = 0.0
tf = 10for name, kwargs in [('vode', dict(method='adams')),
                     ('vode', dict(method='bdf')),
                     ('lsoda', {})]:
    for j in [None, jac]:
        solver = ode(func, jac=j)
        solver.set_integrator(name, atol=1e-8, rtol=1e-6, **kwargs)
        solver.set_f_params(mu)
        solver.set_jac_params(mu)
        solver.set_initial_value(u0, t0)

        tvals = []
        i = 0while solver.successful() and solver.t < tf:
            solver.integrate(tf, step=True)
            i += 1print("%-6s %-8s jac=%-5s " %
              (name, kwargs.get('method', ''), j.func_name if j elseNone),
              end='')

        tvals = np.unique(tvals)
        print("len(tvals) =", len(tvals))

Post a Comment for "Stiff Ode-solver"