【问题标题】:Programming of 4th order Runge-Kutta in advection equation in pythonpython 平流方程中四阶龙格-库塔的编程
【发布时间】:2020-04-22 23:51:24
【问题描述】:
%matplotlib notebook
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from math import pi

# wave speed
c = 1
# spatial domain
xmin = 0
xmax = 1
#time domain
m=500; # num of time steps 
tmin=0
T = tmin + np.arange(m+1);
tmax=500

n = 50 # num of grid points

# x grid of n points
X, dx = np.linspace(xmin, xmax, n+1, retstep=True);
X = X[:-1] # remove last point, as u(x=1,t)=u(x=0,t)

# for CFL of 0.1
CFL = 0.3
dt = CFL*dx/c


# initial conditions
def initial_u(x):
    return np.sin(2*pi*x)

# each value of the U array contains the solution for all x values at each timestep
U = np.zeros((m+1,n),dtype=float)
U[0] = u = initial_u(X);




def derivatives(t,u,c,dx):
    uvals = [] # u values for this time step
    for j in range(len(X)):
        if j == 0: # left boundary
            uvals.append((-c/(2*dx))*(u[j+1]-u[n-1]))
        elif j == n-1: # right boundary
            uvals.append((-c/(2*dx))*(u[0]-u[j-1]))
        else:
            uvals.append((-c/(2*dx))*(u[j+1]-u[j-1]))
    return np.asarray(uvals)


# solve for 500 time steps
for k in range(m):
    t = T[k];
    k1 = derivatives(t,u,c,dx)*dt;
    k2 = derivatives(t+0.5*dt,u+0.5*k1,c,dx)*dt;
    k3 = derivatives(t+0.5*dt,u+0.5*k2,c,dx)*dt;
    k4 = derivatives(t+dt,u+k3,c,dx)*dt;
    U[k+1] = u = u + (k1+2*k2+2*k3+k4)/6;

# plot solution
plt.style.use('dark_background')
fig = plt.figure()
ax1 = fig.add_subplot(1,1,1)

line, = ax1.plot(X,U[0],color='cyan')
ax1.grid(True)
ax1.set_ylim([-2,2])
ax1.set_xlim([0,1])
def animate(i):
    line.set_ydata(U[i])
    return line,

我想用 Python 编写一个平流方程,它是 (∂u/∂t) +c (∂u/∂x) = 0。时间应该用 Runge-kutta 4 阶离散化。空间离散化是二阶有限差分。当我运行我的代码时,我得到了转换成正弦波的直线。但我给出了初始条件正弦波。为什么它以直线开始?我想让正弦波向前移动。您对如何使正弦波前进有任何想法吗?我感谢您的帮助。提前致谢!

【问题讨论】:

  • 首先,你需要使用更少的全局变量,尤其是。 U 数组。传递更多作为参数。请注意,对于 RK4,您将需要在距离上一个时间节点欧拉步长的状态下进行 3 次导数评估。此外,k 向量应该是导数函数的结果(此更改可能足以更正您的代码)。为了进一步简化代码,请考虑如何使用切片或卷积实现二阶导数。
  • 感谢您的回答。在从最后一个时间节点开始不是欧拉步的状态下的 3 个导数评估到底是什么意思?你能澄清一下吗?
  • 稍后再读,这里不相关。您只是使用一种非常非常规的方法来获取阶段值。然而,在那之后的点仍然存在,函数u 计算一个点/状态,而k 向量应该包含斜率/导数。
  • 我在 k 个向量中包含了导数函数。所以 k 值是使用导数函数计算的。但我现在得到了强烈的振荡。我编辑了我的代码。所以你可以看到它的新形式。
  • 您在除以(dx+deltax) 时做了一些非常奇怪的事情。通过它的使用,deltax 应该是deltat,并且在任何时候它都不会添加到dx

标签: python numerical-methods runge-kutta


【解决方案1】:

虽然表面上您的计算步骤与 RK4 方法有关,但它们与 RK4 方法和正确的空间离散化相差太多,不能一概而论。

应用 ODE 积分方法的传统方法是拥有一个函数 derivatives(t, state, params),然后应用它来计算 Euler 步或 RK4 步。在你的情况下,它会是

def derivatives(t,u,c,dx):
    du = np.zeros(len(u));
    p = c/(2*dx);
    du[0] = p*(u[1]-u[-1]);
    du[1:-1] = p*(u[2:]-u[:-2]);
    du[-1] = p*(u[0]-u[-2]);
    return du;

那你就可以了

X, dx = np.linspace(xmin, xmax, n+1, retstep=True);
X = X[:-1] # remove last point, as u(x=1,t)=u(x=0,t)

m=500; # number of time steps
T = tmin + np.arange(m+1);

U = np.zeros((m+1,n),dtype=float)
U[0] = u = initial_u(X);
for k in range(m):
    t = T[k];
    k1 = derivatives(t,u,c,dx)*dt;
    k2 = derivatives(t+0.5*dt,u+0.5*k1,c,dx)*dt;
    k3 = derivatives(t+0.5*dt,u+0.5*k2,c,dx)*dt;
    k4 = derivatives(t+dt,u+k3,c,dx)*dt;
    U[k+1] = u = u + (k1+2*k2+2*k3+k4)/6;

这使用dt 作为时间步长中的主变量计算,然后从tmin 构造算术序列,步长为dt。其他方式也是可行的,但必须使tmax 和时间步数兼容。

到此为止的计算现在应该是成功的并且可以在动画中使用。据我了解,您不会在每一帧中生成一个新图,您只需绘制一次图形,之后只需更改线条数据

# animate the time data
line, = ax1.plot(X,U[0],color='cyan')
ax1.grid(True)
ax1.set_ylim([-2,2])
ax1.set_xlim([0,1])

def animate(i):
    line.set_ydata(U[i])
    return line,

等等

【讨论】:

  • 感谢您的帮助!但我收到错误,因为 t+0.5dt 是浮点数。错误是“只有整数、切片 (:)、省略号 (...)、numpy.newaxis (None) 和整数或布尔数组是有效索引”,它出现在 k2 =导数(t+0.5*dt, u+0.5*k1,c,dx)*dt;
  • 使用通常暗示浮点变量作为整数索引的名称通常是一个坏主意。您还需要确保在函数调用中使用匹配的接口,以我的方式,实际上并没有使用时间。
  • 但是以您的方式,您使用了 t ,即 index 。当添加0.5dt时,它将以浮点数作为索引。我应该如何解决这个问题?你能澄清一下吗?
  • 感谢您编辑的代码。我现在在 k1 = 导数(t,u,c,dx)*dt; 行中得到一个错误。错误就是这样 - 不能将序列乘以“numpy.float64”类型的非整数
  • 我不确定你做了什么,我得到了一个非常流畅的动画。如果你使用你的衍生函数或类似的东西,你需要将构造的列表转换成一个numpy数组,return np.asarray(uvals)
猜你喜欢
  • 2016-02-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-19
  • 1970-01-01
  • 1970-01-01
  • 2018-12-09
相关资源
最近更新 更多