Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Interchanging between different scipy ode solvers

Tags:

python

scipy

I have a made a solver which can interchange between scipy.integrate.ode and scipy.integrate.odeint. Here is the code.

def f(y,s,C,u,v):
    y0 = y[0] # u
    y1 = y[1] # u'
    y2 = y[2] # v
    y3 = y[3] # v'
    dy = np.zeros_like(y)
    dy[0] = y1
    dy[2] = y3

    C = C.subs({u:y0,v:y2})
    dy[1] = -C[0,0][0]*dy[0]**2\
            -2*C[0,0][1]*dy[0]*dy[2]\
            -C[0,1][1]*dy[2]**2
    dy[3] = -C[1,0][0]*dy[0]**2\
            -2*C[1,0][1]*dy[0]*dy[2]\
            -C[1,1][1]*dy[2]**2
    return dy

def solve(C,u0,s0,s1,ds,solver=None):
    from sympy.abc import u,v
    if solver == None: # use lsoda from scipy.integrate.odeint
        s = np.arange(s0,s1+ds,ds)
        print 'Running solver ...'
        return sc.odeint(f,u0,s,args=(C,u,v))
    else: # use any other solver from scipy.integrate.ode
        r = sc.ode(f).set_integrator(solver) # vode,zvode,lsoda,dopri5,dop853
        r.set_f_params(C,u,v)
        r.set_initial_value(u0)
        #t = []
        y = []
        print 'Running solver ...'
        while r.successful() and r.t <= s1:
            r.integrate(r.t + ds)
            y.append(r.y)#; t.append(r.t)
        return np.array(y)

The problem I experience is as following. If I decide to use the solver from scipy.integrate.odeint then the parameters of f have to be specified in the order as they are in the code. However, if I decide to use the solvers from scipy.integrate.ode I have to change the order of the parameters of the function f(y,s,C,u,v) to f(s,y,C,u,v), otherwise I get the error

TypeError: 'float' object has no attribute '__getitem__'

If I do this, then scipy.integrate.odeint generates the same error for f defined as f(s,y,C,u,v). How can I operate with a unified f regardless of the order of the parameters ?

Edit :

To sum the problem up :

scipy.integrate.ode solvers work if the function f is defined as f(s,y,C,u,v), and scipy.integrate.odeint solver works if the function f is defined as f(y,s,C,u,v). Why is this occurring, and how I can I fix this?

Edit :

Scipy -- version 0.16.0

like image 685
imranal Avatar asked Nov 04 '15 13:11

imranal


1 Answers

Why is this occurring, and how I can I fix this?

It is occurring because of an unfortunate API design decision made years ago. odeint and the ode class require different signatures for the system to be solved.

You can fix it by adding a wrapper that changes the order of the first two arguments when you use, say, the ode class. For example, you could change this:

    r = sc.ode(f).set_integrator(solver)

to

    r = sc.ode(lambda t, x, *args: f(x, t, *args)).set_integrator(solver)

Update: In SciPy 1.1.0, the argument tfirst was added to scipy.integrate.odeint. The default, tfirst=False, maintains the old behavior. With tfirst=True, odeint expects the first argument of func to be t (i.e. the independent variable). By using tfirst=True, the same func can be used with ode, odeint and the newer solver_ivp.

like image 181
Warren Weckesser Avatar answered Oct 19 '22 09:10

Warren Weckesser