【问题标题】:Solve a system of differential equations using Euler's method使用欧拉法求解微分方程组
【发布时间】:2015-04-25 20:16:03
【问题描述】:

我正在尝试使用欧拉方法求解一个常微分方程组,但是当我尝试打印速度时,我得到了

RuntimeWarning: overflow encountered in double_scalars

我得到的是nan(不是数字),而不是打印数字。我认为问题可能出在定义加速度时,但我不确定,如果有人能帮助我,我将不胜感激。

from numpy import *
from math import pi,exp

d=0.0005*10**-6
a=[]

while d<1.0*10**-6 :
    d=d*2
    a.append(d)

D=array(a)

def a_particula (D,x, v, t):
    cc=((1.00+((2.00*lam)/D))*(1.257+(0.400*exp((-1.10*D)/(2.00*lam)))))
    return (g-((densaire*g)/densparticula)-((mu*18.0*v)/(cc*densparticula*  (D**2.00))))

def euler (acel,D, x, v, tv, n=15):
    nv, xv, vv = tv.size, zeros_like(tv), zeros_like(tv)
    xv[0], vv[0] = x, v
    for k in range(1, nv):
        t, Dt = tv[k-1], (tv[k]-tv[k-1])/float(n)
        for i in range(n):
            a = acel(D,x, v, t)
            t, v = t+Dt, v+a*Dt
            x = x+v*Dt
        xv[k], vv[k] = x, v
    return (xv, vv)

g=(9.80)    
densaire= 1.225         
lam=0.70*10**-6         
densparticula=1000.00
mu=(1.785*10**-5)       
tv = linspace(0, 5, 50)
x, v = 0, 0 #initial conditions


for j in range(len(D)):

    xx, vv = euler(a_particula, D[j], x, v, tv)

    print(D[j],xx,vv)

【问题讨论】:

  • 请注意,您使用的是辛欧拉,尽管它是一个非保守系统。用t,x,v = t+Dt, x+v*Dt, v+a*Dt 替换欧拉步骤以实现正确的数值方法。再次检查方程的物理特性,其他力项应以重力项为主。第二个(浮力?)更小,第三个(摩擦力)更大,导致速度演化中的正反馈(带有负因素,因此振荡)。如果找不到错误,请说明用于推导力项的物理定律。
  • 或者使用与 Lipschitz 常数(倒数)相称的时间步长。这意味着Dt=1e-8 或更小。 tv=linspace(0,5e-4,50)n=1000 有效。使用刚性系统的方法(梯形方法,其他隐式方法)能够使用更大的时间步长。

标签: python numpy floating-point differential-equations


【解决方案1】:

将来,如果您在问题中包含完整的警告消息会很有帮助 - 它将包含出现问题的行:

tmp/untitled.py:15: RuntimeWarning: overflow encountered in double_scalars
  return (g-((densaire*g)/densparticula)-((mu*18.0*v)/(cc*densparticula*  (D**2.00))))

Overflow 发生在变量的大小超过可以表示的最大值时。在这种情况下,double_scalars 指的是一个 64 位浮点数,其最大值为:

print(np.finfo(float).max)
# 1.79769313486e+308

所以表达式中有一个标量值:

(g-((densaire*g)/densparticula)-((mu*18.0*v)/(cc*densparticula*  (D**2.00))))

超过 ~1.79e308。要找出是哪一个,您可以在发生这种情况时使用np.errstate 引发FloatingPointError,然后抓住它并启动Python debugger

    ... 
    with errstate(over='raise'):
        try:
            ret = (g-((densaire*g)/densparticula)-((mu*18.0*v)/(cc*densparticula*  (D**2.00))))
        except FloatingPointError:
            import pdb
            pdb.set_trace()
        return ret
    ...

然后,您可以在调试器中检查此表达式各个部分的值。溢出似乎发生在:

(mu*18.0*v)/(cc*densparticula*  (D**2.00))

第一次出现警告时,(cc*densparticula* (D**2.00) 的计算结果为 2.3210168586496022e-12,而 (mu*18.0*v) 的计算结果为 -9.9984582297025182e+299。

基本上,您将一个非常大的数字除以一个非常小的数字,结果的大小超过了可以表示的最大值。这可能是您的数学问题,也可能是您对函数的输入没有合理缩放。

【讨论】:

    【解决方案2】:

    你的系统减少到

    dv/dt = a = K - L*v
    

    K 大约在10L 之间,乍一看是1e+51e+10。使用的实际系数证实:

    D=1.0000e-09        K= 9.787995      L=1.3843070e+08
    D=3.2000e-08        K= 9.787995      L=4.2570244e+06
    D=1.0240e-06        K= 9.787995      L=9.0146813e+04
    

    速度的欧拉步长是

    v[j+1]=v[j]+(K-L*v[j])*dt =(1-L*dt)*v[j] + K*dt
    

    对于任何类似于预期摩擦效果的东西,即速度下降到K/L,需要abs(1-L*dt)&lt;1,如果可能的话,需要0&lt;1-L*dt&lt;1,即dt &lt; 1/L。这意味着这里dt &lt; 1e-10

    为了能够使用更大的时间步,您需要使用刚性微分方程的方法,这意味着隐式方法。最简单的有隐式欧拉法、中点法和梯形法。

    由于线性关系,中点法和梯形法等于同一个公式

    v[j+1] = v[j] + dt * ( K - L*(v[j]+v[j+1])/2 )
    

    v[j+1] = ( (1-L*dt/2)*v[j] + K*dt ) / (1+L*dt/2)
    

    当然,最简单的方法就是完全集成ODE

    (-L*v')/(K-L*v)=-L  =>  K-L*v(t)=C*exp(-L*t), C=K-L*v(0)
    
    v(t)=K/L + exp(-L*t)*(v(0)-K/L)
    

    集成到

    x(t)=x(0)+K/L*t+(1-exp(-L*t))/L*(v(0)-K/L).
    

    或者您可能在将物理定律转换为公式时犯了一个错误,因此常数的大小都是错误的。

    【讨论】:

      猜你喜欢
      • 2014-07-03
      • 2015-08-22
      • 1970-01-01
      • 2019-01-19
      • 2022-01-04
      • 1970-01-01
      • 2021-04-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多