Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
437 views
in Technique[技术] by (71.8m points)

python - Interchanging between different scipy ode solvers

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

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...