odeint()中的Sympy表达式给出了派生错误

时间:2016-08-07 00:06:41

标签: python scipy sympy ode derivative

我正在尝试自动化几个过程,比如使用Sympy从Lagrangians生成ODE,并使用Numpy和Scipy对它们进行数值积分。 最后的完整代码。作为使用solve()生成ODE的结果,我得到了一个包含Sympy表达式的字典,如下所示:

{Derivative(lambda1(t), t): (y(t) + 1)/(x(t)*y(t)),
 Derivative(z(t), t): x(t),
 Derivative(x(t), t): y(t)*z(t),
 Derivative(y(t), t): -x(t)*z(t)
 }

然后由此我想将微分方程系统与Scipy的odeint()结合起来。为此,我需要从lambdify内的字典中提取表达式(例如def Field(Q,t):),以odeint(Field,Q_0,t_array)引入。这是我遇到困难的地方:

我第一次尝试

def Equ2(nQ,t,Q,Field):
x1,y1,z1,lamb1 = nQ
dQ =[]
for f in Q:
    dQ.append(lambdify(Q, Field[f.diff(t)],'numpy' )(x1,y1,z1,lamb1))
return dQ[0:len(nQ)]

但它不能转到odeint(),因为它需要带有2个参数的字段,并且我尝试将其传递给arga=()的{​​{1}},并给我一个(长) )错误:

odeint()

所以我尝试的基本相同,但没有循环,

ValueError                   Traceback (most recent call last)
<ipython-input-20-63f086b8a252> in Equ2(nQ, t, Q, Field)
      20     dQ =[]
      21     for f in Q:
 ---> 22         dQ.append(lambdify(Q, Field[f.diff(t)],'numpy' )(x1,y1,z1,lamb1))
      23     return dQ[0:len(Q)-1]

[...]
ValueError: 
Can't calculate 1st derivative wrt 14.0430379424125.

并且(我认为)有同样的问题:

def Equ1(nQ,t):
x1,y1,z1,lamb1 = nQ
dx = lambdify((x,y,z,lam[0]), field[x.diff(t)],'numpy' )(x1,y1,z1,lamb1)
dy = lambdify((x,y,z,lam[0]), field[y.diff(t)],'numpy' )(x1,y1,z1,lamb1)
dz = lambdify((x,y,z,lam[0]), field[z.diff(t)],'numpy' )(x1,y1,z1,lamb1)
dlam = lambdify((x,y,z,lam[0]), field[lam[0].diff(t)],'numpy' )(x1,y1,z1,lamb1)
return [dx,dy,dz]

如果我只是尝试:

ValueError                                Traceback (most recent call last)
<ipython-input-20-63f086b8a252> in Equ1(nQ, t)
      9 def Equ1(nQ,t):
     10     x1,y1,z1,lamb1 = nQ
---> 11     dx = lambdify((x,y,z,lam[0]), field[x.diff(t)],'numpy' )(x1,y1,z1,lamb1)
     12     dy = lambdify((x,y,z,lam[0]), field[y.diff(t)],'numpy' )(x1,y1,z1,lamb1)
     13     dz = lambdify((x,y,z,lam[0]), field[z.diff(t)],'numpy' )(x1,y1,z1,lamb1)

[...]
ValueError: 
Can't calculate 1st derivative wrt 17.6326726993661.

集成工作正常。此外,如果我使用类似的参数调用def Equ0(nQ,t): x,y,z,lamb = nQ dx = y*z dy = -x*z dz = x dlam = (y+1.)/(x*y) return [dx,dy,dz] 函数,它们将在EquX()内调用,它们的工作正常。

完整代码

odeint()

最后是完整错误:

from sympy import *
from sympy.physics.mechanics import dynamicsymbols
from numpy import linspace, sin, cos
from scipy.integrate import odeint

t = Symbol('t')
x = Function('x')(t)
y = Function('y')(t)
z = Function('z')(t)

lam = dynamicsymbols('lambda1:{0}'.format(5))
f = x.diff(t)- y*z
eq = Matrix([x.diff(t) - lam[0].diff(t)*y*x*z+z,
         y.diff(t) +x*z,
         z.diff(t)-x
        ])

field = solve(list(eq)+[f],[x.diff(t),y.diff(t),z.diff(t),lam[0].diff(t)])


def Equ0(nQ,t):
    x,y,z,lamb = nQ
    dx = y*z
    dy = -x*z
    dz = x
    dlam = (y+1.)/(x*y)
    return [dx,dy,dz]

def Equ1(nQ,t):
    x1,y1,z1,lamb1 = nQ
    dx = lambdify((x,y,z,lam[0]), field[x.diff(t)],'numpy' )(x1,y1,z1,lamb1)
    dy = lambdify((x,y,z,lam[0]), field[y.diff(t)],'numpy' )(x1,y1,z1,lamb1)
    dz = lambdify((x,y,z,lam[0]), field[z.diff(t)],'numpy' )(x1,y1,z1,lamb1)
    dlam = lambdify((x,y,z,lam[0]), field[lam[0].diff(t)],'numpy' )(x1,y1,z1,lamb1)
    return [dx,dy,dz]


def Equ2(nQ,t,Q,Field):
    x1,y1,z1,lamb1 = nQ
    dQ =[]
    for f in Q:
        dQ.append(lambdify(Q, Field[f.diff(t)],'numpy' )(x1,y1,z1,lamb1))
    return dQ[0:len(Q)-1]

q = [x,y,z,lam[0]]
nq = [1,2,3,4]
time=linspace(0,10,10)

### This line works just fine:
print Equ0(nq,t), Equ1(nq,t), Equ2(nq,t,q,field) #They give the same output 

sol0 = odeint(Equ0,nq,time)
sol1 = odeint(Equ1,nq,time) #Errors here
sol2 = odeint(Equ2,nq,time,args=(q,field)) #And here

TL; DR odeint()中出现了一些派生错误,我无法使用自定义函数在odeint()外部重现。

1 个答案:

答案 0 :(得分:3)

如果要使用t作为符号,则应避免在函数声明中将t声明为浮点数。尝试使用其他名称ts替换浮点tt或...