2

我有一个耦合方程组:流体静力平衡方程、质量连续性方程和理想气体的状态方程。这些是,在数学语法中,

  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_B是玻尔兹曼常数,\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 方法。

4

2 回答 2

1

正如 Wolph 所说,除以n可能只是给你h=0,这取决于你使用的 Python 版本。如果您使用的是 2.x,则应from __future__ import division在开头包含,或以其他方式处理除法(例如,除以float(n))。(哦,我想也许您还打算n在循环中使用,而不是硬编码range(0,10000000)?而且代码中存在一些缩进错误,但我想这只是在这里发布的。)

不过,这似乎不是主要问题。你说你很早就得到了高压;当我运行它时,它真的很低吗?即使有适当的划分,我也会得到p_atm[3] = -2.27e+97,并且由此开始得到无穷大 (inf-inf) 和nans。

在不更好地了解具体问题的情况下,很难确定您的实现中是否存在错误,或者这是否只是数值不稳定的问题。在我看来它是正确的,但我很可能遗漏了一些东西(有点难以阅读。)如果这是您第一次使用 Runge–Kutta,我强烈建议您使用现有的实现,而不是尝试自己做对. 数值计算和避免浮点问题可能非常具有挑战性。您已经在使用scipy— 为什么不使用他们的 R-K 方法或相关数值积分解决方案的实现?例如,看看scipy.integrate。如果不出意外,如果scipy集成商不能解决你的问题,至少你更了解你的挑战是什么。

于 2015-06-30T13:45:21.670 回答
1

这是一个使用小数的版本,顺便说一句,它似乎工作得更好:

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
于 2015-07-01T09:35:28.810 回答