用于简单重力模拟的Python scipy.integrate.odeint失败

时间:2019-03-03 22:04:36

标签: python scipy differential-equations

我正在尝试编写一个非常简单的绕原点运行的质量的重力模拟。我已经使用scipy.integrate.odeint积分了微分方程。

问题是我收到以下错误消息:

ODEintWarning: Excess work done on this call (perhaps wrong Dfun type). Run with full_output = 1 to get quantitative information.
  warnings.warn(warning_msg, ODEintWarning)

此外,这显然是有问题的-方程未正确积分并且运动不正确。下面是初始条件下的运动图,应给出绕原点的圆周运动:

image

这是代码:

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

G=1
m=1
def f_grav(y, t):
    x1, x2, v1, v2 = y
    m = t
    dydt = [v1, v2, -x1*G*m/(x1**2+x2**2)**(3/2), -x2*G*m/(x1**2+x2**2)**(3/2)]
    return dydt

t = np.linspace(0, 100, 1001)
init = [0, 1, 1, 0]
ans = odeint(f_grav, init, t)
print(ans)

x = []
y = []
for i in range (100):
    x.append(ans[i][0])
    y.append(ans[i][1])
plt.plot(x, y)
plt.show()

请注意,我之前使用过此函数,并且为SHM微分方程编写几乎相同的代码可获得正确的结果。更改t中的数字无济于事。有谁知道为什么这种失败如此严重?

3 个答案:

答案 0 :(得分:1)

根据odeint的文档,无论哪种方式,错误的运动都可能是数值不稳定:

  

注意:对于新代码,请使用scipy.integrate.solve_ivp来求解微分方程。

solve_ivp实际上仅取边界并确定点的数量,因此积分方法对于方程式是稳定的。您还可以选择集成方法。

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

G=1
m=1
def f_grav(t, y):
    x1, x2, v1, v2 = y
    m = t
    dydt = [v1, v2, -x1*G*m/(x1**2+x2**2)**(3/2), -x2*G*m/(x1**2+x2**2)**(3/2)]
    return dydt

domain = (0, 100)
init = [0, 1, 1, 0]
ans = solve_ivp(fun=f_grav, t_span=domain, y0=init)

plt.plot(ans['y'][0], ans['y'][1])
plt.show()

我没有收到任何警告,并且模拟看起来更好(请注意,该函数必须按(t, y)的顺序排列参数)。

答案 1 :(得分:0)

可能有两个主要问题:输入参数为整数而不是双精度;另外,您没有设置积分精度的公差,并且输出不是“密集”的。像这样:

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


G=1.
m=1.
def f_grav(t, w):
    x, y, z, vx, vy, vz = w
    fg = -G*m/(x**2.+y**2.+z**2.)**(1.5)
    dwdt = [vx, vy, vz, fg*x, fg*y, fg*z]
    return dwdt

n=100 # total number of orbits
tmin = 0.
tmax = float(n)*6.283185

domain = (tmin, tmax)
t_eval = np.linspace(tmin, tmax, int(tmax*1000))
init = [0., 1., 0., 1., 0., 0.]
ans = solve_ivp(fun=f_grav, t_span=domain, t_eval =t_eval, y0=init,dense_output=True, rtol=1.e-10)


fig = plt.figure(figsize=(10,10))
ax = fig.add_subplot(111)
plt.plot(ans['y'][0], ans['y'][1])
plt.show()

应该可以正常工作,至少在我的笔记本电脑上可以。 我希望这会有所帮助。

答案 2 :(得分:0)

正如评论中已经得出的那样,错误是质量被设定为时间,这种不断增长的质量与情况的物理学相矛盾,但是,另一方面,它解释了随着能量的增长而螺旋下降的趋势。和动量得以保留。

经过更正和简化的代码

G=1
m=1
def f_grav(y, t):
    x1, x2, v1, v2 = y
    r = np.hypot(x1,x2); 
    F = G*m/r**3;
    return [v1, v2, -x1*F, -x2*F];

t = np.linspace(0, 100, 1001)
init = [0, 1, 1, 0]
ans = odeint(f_grav, init, t)
print(ans)

x,y,_,_ = ans.T

plt.plot(0,0,'oy', ms=8)
plt.plot(x, y); plt.axis('equal');
plt.show()

(在vx=1中以(vx,0)为初始速度)将一个视觉上完美的圆作为轨道。

enter image description here