Python中的数值ODE求解

时间:2013-04-10 14:31:39

标签: python plot numerical-methods differential-equations

如何在Python中用数字方式解决ODE?

考虑

equation to solve

\ddot{u}(\phi) = -u + \sqrt{u}

具有以下条件

u(0) = 1.49907

\dot{u}(0) = 0

带约束

0 <= \phi <= 7\pi.

最后,我想制作一个参数图,其中x和y坐标是u的函数。

问题是,我需要运行两次odeint,因为这是二阶微分方程。 我试过让它在第一次运行后再次运行,但它回来时出现雅可比错误。必须有一种方法可以同时运行它两次。

这是错误:

  

odepack.error:该函数及其雅可比行列式必须是可调用函数

以下代码生成的代码。有问题的行是sol = odeint。

import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
from numpy import linspace


def f(u, t):
    return -u + np.sqrt(u)


times = linspace(0.0001, 7 * np.pi, 1000)
y0 = 1.49907
yprime0 = 0
yvals = odeint(f, yprime0, times)

sol = odeint(yvals, y0, times)

x = 1 / sol * np.cos(times)
y = 1 / sol * np.sin(times)

plot(x,y)

plt.show()

修改

我正在尝试构建第9页的情节

Classical Mechanics Taylor

以下是Mathematica的情节

mathematica plot

In[27]:= sol = 
 NDSolve[{y''[t] == -y[t] + Sqrt[y[t]], y[0] == 1/.66707928, 
   y'[0] == 0}, y, {t, 0, 10*\[Pi]}];

In[28]:= ysol = y[t] /. sol[[1]];

In[30]:= ParametricPlot[{1/ysol*Cos[t], 1/ysol*Sin[t]}, {t, 0, 
  7 \[Pi]}, PlotRange -> {{-2, 2}, {-2.5, 2.5}}]

4 个答案:

答案 0 :(得分:23)

import scipy.integrate as integrate
import matplotlib.pyplot as plt
import numpy as np

pi = np.pi
sqrt = np.sqrt
cos = np.cos
sin = np.sin

def deriv_z(z, phi):
    u, udot = z
    return [udot, -u + sqrt(u)]

phi = np.linspace(0, 7.0*pi, 2000)
zinit = [1.49907, 0]
z = integrate.odeint(deriv_z, zinit, phi)
u, udot = z.T
# plt.plot(phi, u)
fig, ax = plt.subplots()
ax.plot(1/u*cos(phi), 1/u*sin(phi))
ax.set_aspect('equal')
plt.grid(True)
plt.show()

enter image description here

答案 1 :(得分:4)

您的其他question的代码非常接近您想要的代码。需要进行两项更改:

  • 您正在解决另一个ODE(因为您更改了函数deriv内的两个符号)
  • 您所需绘图的y分量来自解决方案值,而不是解决方案的一阶导数的值,因此您需要替换{{1}的u[:,0](函数值) (衍生物)。

这是最终结果:

u[:, 1]

但是,我建议您使用unutbu答案中的代码,因为它是自我记录(import numpy as np import matplotlib.pyplot as plt from scipy.integrate import odeint def deriv(u, t): return np.array([u[1], -u[0] + np.sqrt(u[0])]) time = np.arange(0.01, 7 * np.pi, 0.0001) uinit = np.array([1.49907, 0]) u = odeint(deriv, uinit, time) x = 1 / u[:, 0] * np.cos(time) y = 1 / u[:, 0] * np.sin(time) plt.plot(x, y) plt.show() )并使用u, udot = z而不是np.linspace。然后,运行它以获得您想要的数字:

np.arange

答案 2 :(得分:3)

您可以使用scipy.integrate.ode。要解决dy / dt = f(t,y),初始条件为y(t0)= y0,在时间= t1时使用4阶Runge-Kutta,你可以这样做:

from scipy.integrate import ode
solver = ode(f).set_integrator('dopri5')
solver.set_initial_value(y0, t0)
dt = 0.1
while t < t1:
    y = solver.integrate(t+dt)
    t += dt

编辑:你必须得到你的衍生物到第一个订单才能使用数值积分。这可以通过设置例如z1 = u和z2 = du / dt,之后你有dz1 / dt = z2和dz2 / dt = d ^ 2u / dt ^ 2。将这些替换为原始等式,并简单地迭代向量dZ / dt,这是第一阶。

编辑2:这是整个事情的示例代码:

import numpy as np
import matplotlib.pyplot as plt

from numpy import sqrt, pi, sin, cos
from scipy.integrate import ode

# use z = [z1, z2] = [u, u']
# and then f = z' = [u', u''] = [z2, -z1+sqrt(z1)]
def f(phi, z):
    return [z[1], -z[0]+sqrt(z[0])]


# initialize the 4th order Runge-Kutta solver
solver = ode(f).set_integrator('dopri5')

# initial value
z0 = [1.49907, 0.]
solver.set_initial_value(z0)

values = 1000
phi = np.linspace(0.0001, 7.*pi, values)
u = np.zeros(values)

for ii in range(values):
    u[ii] = solver.integrate(phi[ii])[0] #z[0]=u

x = 1. / u * cos(phi)
y = 1. / u * sin(phi)

plt.figure()
plt.plot(x,y)
plt.grid()
plt.show()

答案 3 :(得分:2)

scipy.integrate()进行ODE整合。那是你在找什么?