簡體   English   中英

使用 Runge-Kutta 求解耦合微分方程

[英]Using Runge-Kutta to solve coupled differential equations

我有一個耦合方程組:流體靜力平衡方程、質量連續性方程和理想氣體狀態方程。 這些是,在數學語法中,

  1. \\frac{dP}{dr}=- \\rho*g ,

其中\\rho是密度, g是重力加速度。

  1. \\frac{dM}{dr}=4*pi* r^2*\\rho

  1. p=\\rho* k_B* T/(\\mu *m_p) ,

其中k_Bm_p常數, \\mu是平均分子量, m_p是質子質量。

我想使用 Runge-Kutta 數值技術求解這些耦合方程,並在此展示我為解決此問題而設計的 python 代碼:

from scipy.constants import m_p,G,k,pi
from pylab import *

#mu may be changed for different molecular composition:
mu=2
def g(r_atm, p_atm):
    T=165
    return 4*pi*r_atm**2*mu*m_p*p_atm/(k*T)

def f(r_atm,p_atm, m_atm):
    T=165
    return -mu*m_p*p_atm*G*m_atm/(k*T*r_atm**2)

def rk4_1(g,f, r0, p0,m0, r1, n):
    r_atm = [0]*(n + 1)
    p_atm = [0]*(n + 1)
    m_atm=[0]*(n + 1)
    h = (r1 - r0)/n
#    h=-20
    r_atm[0]=r0
    p_atm[0]=p0
    m_atm[0]=m0

    for i in range(0,10000000):
        if p_atm[i]<100000:

            k0 = h*g(r_atm[i], p_atm[i])

            l0 = h*f(r_atm[i], p_atm[i], m_atm[i])

            k1 = h*g(r_atm[i] + 0.5*h, p_atm[i] + 0.5*k0)

            l1 = h*f(r_atm[i] + 0.5*h, p_atm[i] + 0.5*l0, m_atm[i]+0.5*k0)

            k2 = h*g(r_atm[i] + 0.5*h, p_atm[i] + 0.5*k1)

            l2 = h*f(r_atm[i] + 0.5*h, p_atm[i] + 0.5*l1, m_atm[i]+0.5*k1)

            k3 = h*g(r_atm[i] + h, p_atm[i] + k2)

            l3 = h*f(r_atm[i] + h, p_atm[i] + l2,  m_atm[i]+k2)

            r_atm[i+1] = r0 + (i+1)*h
            p_atm[i+1] = p_atm[i] + (l0 + 2*l1 + 2*l2 + l3)/6
            m_atm[i+1] = m_atm[i] + (k0 + 2*k1 + 2*k2 + k3)/6

            else:
                break

        return h, r_atm, p_atm, m_atm

h, r_atm, p_atm, m_atm = rk4_1(g,f, 6.991e7, 1e-6*1e5, 1.898e27, 2.0e7,10000000) #bar to pascals (*1e5)

對於壓力p_atm 、半徑r_atm和質量m_atm初始條件,我使用我在h, r_atm, p_atm, m_atm = rk4_1(g,f, 6.991e7, 1e-6*1e5, 1.898e27, 2.0e7,10000000) 請注意,我正在從高層大氣(給出初始條件)並在大氣中向下推進(注意 h 為負)來解決這個邊界值問題。 我的目的是評估這個從10^-1帕斯卡到100000帕斯卡的數值積分。 我從運行這段代碼中得到的結果是,壓力在三個步驟中簡單地上升到~1e+123 ,所以顯然有一些非常錯誤的流媒體,但是換個角度或視角會有所幫助,因為這是第一個時間我正在執行 Runga-Kutta 方法。

正如沃爾夫所說,除以n可能只是給你h=0 ,這取決於你使用的 Python 版本。 如果您使用的是 2.x,您應該在開頭包含from __future__ import division ,或者以其他方式處理除法(例如,除以float(n) )。 (哦,我想也許您還打算在循環中使用n ,而不是硬編碼range(0,10000000) ?代碼中存在一些縮進錯誤,但我想這只是來自貼在這里。)

不過,這似乎不是主要問題。 你說你很早就有高壓; 當我運行它時,它變得非常低? 即使有適當的划分,我p_atm[3] = -2.27e+97得到p_atm[3] = -2.27e+97 ,然后我開始得到無窮大( inf-inf )和nan s。

在不更好地了解具體問題的情況下,很難查看您的實現中是否存在錯誤,或者這是否僅僅是數值不穩定的問題。 對我來說看起來不錯,但我很可能漏掉了一些東西(有點難以閱讀。)如果這是您第一次使用 Runge-Kutta,我強烈建議您使用現有的實現,而不是自己嘗試把它弄好. 數值計算和避免浮點問題可能非常具有挑戰性。 您已經在使用scipy — 為什么不使用他們實現的 R-K 方法或相關的數值積分解決方案? 例如,看看scipy.integrate 如果不出scipy ,如果scipy集成商無法解決您的問題,至少您更了解您的挑戰是什么。

這是一個使用小數的版本順便說一句,它似乎工作得稍微好一點:

from decimal import Decimal as D
from scipy.constants import m_p,G,k,pi

m_p = D(m_p)
G = D(G)
k = D(k)
pi = D(pi)

# mu may be changed for different molecular composition:
mu = D(2)

def g(r_atm, p_atm):
    T = D(165)
    return D(4) * pi * r_atm ** D(2) * mu * m_p * p_atm/(k * T)


def f(r_atm,p_atm, m_atm):
    T = D(165)
    return -mu * m_p * p_atm * G * m_atm/(k * T * r_atm ** D(2))


def rk4_1(g,f, r0, p0,m0, r1, n):
    r_atm = [D(0)] * (n + 1)
    p_atm = [D(0)] * (n + 1)
    m_atm = [D(0)] * (n + 1)
    h = (r1 - r0) / n
    # h = -20
    r_atm[0] = r0
    p_atm[0] = p0
    m_atm[0] = m0

    for i in range(0, 10000000):
        if p_atm[i] < 100000:
            k0 = h * g(r_atm[i], p_atm[i])
            l0 = h * f(r_atm[i], p_atm[i], m_atm[i])
            k1 = h * g(r_atm[i] + D('0.5') * h, p_atm[i] + D('0.5') * k0)
            l1 = h * f(r_atm[i] + D('0.5') * h, p_atm[i] + D('0.5') * l0,
                       m_atm[i]+D('0.5') * k0)
            k2 = h * g(r_atm[i] + D('0.5') * h, p_atm[i] + D('0.5') * k1)
            l2 = h * f(r_atm[i] + D('0.5') * h, p_atm[i] + D('0.5') * l1,
                       m_atm[i]+D('0.5') * k1)
            k3 = h * g(r_atm[i] + h, p_atm[i] + k2)
            l3 = h * f(r_atm[i] + h, p_atm[i] + l2,  m_atm[i]+k2)

            r_atm[i + 1] = r0 + (i + 1) * h
            p_atm[i + 1] = p_atm[i]  +  (l0  +  D('2') * l1  +  D('2') * l2  +
                                         l3)/D('6')
            m_atm[i + 1] = m_atm[i]  +  (k0  +  D('2') * k1  +  D('2') * k2  +  k3)/D('6')

        else:
            break

    return h, r_atm, p_atm, m_atm

h, r_atm, p_atm, m_atm = rk4_1(
    g,
    f,
    D('6.991e7'),
    D('1e-6') * D('1e5'),
    D('1.898e27'),
    D('2.0e7'),
    10000000,
)  # bar to pascals (*1e5)

print 'h', h

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM