[英]Using Runge-Kutta to solve coupled differential equations
I have a system of coupled equations: the hydrostatic equilibrium equation, the mass continuity equation, and an equation of state of the ideal gas.我有一个耦合方程组:流体静力平衡方程、质量连续性方程和理想气体状态方程。 These are, in mathematical grammer,
这些是,在数学语法中,
\\frac{dP}{dr}=- \\rho*g
, \\frac{dP}{dr}=- \\rho*g
, where \\rho
is the density and g
is the gravitational acceleration.其中
\\rho
是密度, g
是重力加速度。
\\frac{dM}{dr}=4*pi* r^2*\\rho
and和
p=\\rho* k_B* T/(\\mu *m_p)
, p=\\rho* k_B* T/(\\mu *m_p)
, where k_B
is boltzmann's constant, \\mu
is the mean molecular weight, and m_p
is the proton mass.其中
k_B
是m_p
常数, \\mu
是平均分子量, m_p
是质子质量。
I want to solve these coupled equations using the Runge-Kutta numerical technique, and I herein show the python code I have devised to solve this problem:我想使用 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)
for intial conditions for the pressure, p_atm
, radius, r_atm
, and mass, m_atm
, I use the values I have shown in h, r_atm, p_atm, m_atm = rk4_1(g,f, 6.991e7, 1e-6*1e5, 1.898e27, 2.0e7,10000000)
.对于压力
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)
。 Notice that I am approaching this boundary-value problem from the upper atmosphere (where the initial conditions are given) and progressing downward in the atmosphere (notice that h is negative).请注意,我正在从高层大气(给出初始条件)并在大气中向下推进(注意 h 为负)来解决这个边界值问题。 My intention is to evaluate this numerical integration from
10^-1
Pascals to 100000
Pascals.我的目的是评估这个从
10^-1
帕斯卡到100000
帕斯卡的数值积分。 The result I get from running this code is that the pressure simply blows up to ~1e+123
in three steps, so there is obviously something terribly wrong streaming about, but it would help to have another eye or perspective, for this is the first time I am performing Runga-Kutta methodology.我从运行这段代码中得到的结果是,压力在三个步骤中简单地上升到
~1e+123
,所以显然有一些非常错误的流媒体,但是换个角度或视角会有所帮助,因为这是第一个时间我正在执行 Runga-Kutta 方法。
As Wolph says, dividing by n
might simply give you h=0
, depending on which version of Python you're using.正如沃尔夫所说,除以
n
可能只是给你h=0
,这取决于你使用的 Python 版本。 If you're using 2.x, you should include from __future__ import division
in the beginning, or handle the division in some other way (eg, divide by float(n)
).如果您使用的是 2.x,您应该在开头包含
from __future__ import division
,或者以其他方式处理除法(例如,除以float(n)
)。 (Oh, and I guess perhaps you also intended to use n
in your loop, rather than hard-coding range(0,10000000)
? And there are a couple of indentation errors in the code as it stands, but I guess that's just from posting it here.) (哦,我想也许您还打算在循环中使用
n
,而不是硬编码range(0,10000000)
?代码中存在一些缩进错误,但我想这只是来自贴在这里。)
This doesn't seem to be the main problem, though.不过,这似乎不是主要问题。 You say you get a high pressure early;
你说你很早就有高压; when I run it, it gets really low?
当我运行它时,它变得非常低? Even with proper divisions, I get
p_atm[3] = -2.27e+97
, and from that, I start getting infinities ( inf
and -inf
) and nan
s.即使有适当的划分,我
p_atm[3] = -2.27e+97
得到p_atm[3] = -2.27e+97
,然后我开始得到无穷大( inf
和-inf
)和nan
s。
It's hard, without knowing the specific problem better, to see if there's an error in your implementation, or if this is simply a matter of numerical instability.在不更好地了解具体问题的情况下,很难查看您的实现中是否存在错误,或者这是否仅仅是数值不稳定的问题。 It looks right to me, but I may very well have missed something (sort of hard to read.) If this is your first time with Runge–Kutta, I'd strongly suggest using an existing implementation rather than trying to get it right yourself.
对我来说看起来不错,但我很可能漏掉了一些东西(有点难以阅读。)如果这是您第一次使用 Runge-Kutta,我强烈建议您使用现有的实现,而不是自己尝试把它弄好. Numerical computation and avoiding floating-point issues can be quite challenging.
数值计算和避免浮点问题可能非常具有挑战性。 You're already using
scipy
— why not use their implementation of the R–K method, or related numerical integration solutions?您已经在使用
scipy
— 为什么不使用他们实现的 R-K 方法或相关的数值积分解决方案? have a look at scipy.integrate , for example.例如,看看scipy.integrate 。 If nothing else, if the
scipy
integrators can't solve your problem, at least you know more about what your challenges are.如果不出
scipy
,如果scipy
集成商无法解决您的问题,至少您更了解您的挑战是什么。
Here's a version that uses decimals btw, it seems to work slightly better:这是一个使用小数的版本顺便说一句,它似乎工作得稍微好一点:
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.