2015-11-04 6 views
4

У меня есть решатель, который может обмениваться между scipy.integrate.ode и scipy.integrate.odeint. Вот код.Переключение между различными scipy ode solvers

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) 

Проблема, которую я испытываю, следующая. Если я решаю использовать решатель от scipy.integrate.odeint, тогда параметры f должны быть указаны в порядке, указанном в коде. Тем не менее, если я решу использовать решатель из scipy.integrate.ode я должен изменить порядок параметров функции f(y,s,C,u,v) к f(s,y,C,u,v), в противном случае я получаю ошибку

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

Если я это сделаю, то scipy.integrate.odeint порождает ту же ошибку для f определяется как f(s,y,C,u,v). Как я могу работать с унифицированным f независимо от порядка параметров?

Edit:

Обобщая проблему до:

scipy.integrate.ode решателей работать, если функция F определяется как f(s,y,C,u,v) и scipy.integrate.odeint решатель работает, если функция F определяется как f(y,s,C,u,v). Почему это происходит, и как я могу это исправить?

Edit:

SciPy - версия 0.16.0

+0

Если бы я поменяться с и Y параметров решателя пытается получить доступ к float, как если бы это был список. Это вызывает сообщение об ошибке выше. – imranal

+1

Но зачем вам вообще '' odeint'''? '' 'Odeint''' использует' '' lsoda''' решатель, который доступен в '' 'ode'''. –

+0

Извините за поздний ответ. Первоначально я использовал odeint, но потом я хотел добавить возможность использовать и других решателей (кроме Lsoda). Код, показанный в этом примере, является лишь частью всего кода. Наверное, я ленился, не желая менять код. Но я также думал, что вопрос представляется актуальным, поскольку было странно, что у этих двух решателей были разные переменные карты. – imranal

ответ

5

Почему это происходит, и как я могу это исправить?

Это происходит из-за неудачного решения по дизайну API, сделанного много лет назад. odeint и класс ode требуют разных сигнатур для системы, подлежащей разрешению.

Вы можете исправить это, добавив оболочку, которая изменяет порядок первых двух аргументов, когда вы используете, скажем, класс ode. Например, вы могли бы изменить это:

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

в

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

лучшая документация этого несоответствия в ходе: https://github.com/scipy/scipy/pull/5151

+0

Спасибо! Это работало как шарм. Таким образом, я все еще могу использовать одну и ту же функцию f без необходимости физически изменять порядок параметров или создавать новую функцию. – imranal