← コード一覧に戻る

輸送方程式_中心差分2次精度近似.py ― 1次元移流方程式の中心差分法(2次精度)

目次

  1. 概要
  2. 使用ライブラリ
  3. 物理・数学的背景
  4. 計算手法
  5. コードの流れ
  6. 精度と安定性
  7. コード全文
  8. グラフ結果

概要

1次元移流方程式(輸送方程式)を中心差分(空間2次精度)+前進オイラー(時間1次精度)で数値的に解くプログラム。
初期条件としてステップ関数(左半分が1、右半分が0)を与え、時間発展とともに分布がどう変化するかをグラフで確認する。

使用ライブラリ

numpy格子配列・ゼロ配列の生成、配列演算
matplotlib各時間ステップの分布をプロット。偶数ステップのみ描画

物理・数学的背景

支配方程式

∂q/∂t + c ∂q/∂x = 0

解析解は初期分布 q₀ が速度 c で右方向に平行移動するだけ:

q(x, t) = q₀(x − ct)

パラメータ

c = 1移流速度 [m/s]
dt = 0.05時間刻み [s]
dx = 0.1空間刻み [m]
jmax = 21格子点数(x = 0 〜 2.0 m)
nmax = 6総時間ステップ数

計算手法

中心差分(空間2次精度)

空間微分を左右対称の差分で近似する:

∂q/∂x ≈ (q[j+1] − q[j−1]) / (2Δx)

前後2点を使うため、片側差分(1次精度)より精度が高い(2次精度)。

時間更新式(前進オイラー法・陽解法)

前進オイラー法は陽解法(explicit method)であり、次の時刻の値 q^(n+1) を現在時刻 n の値だけで直接計算できる。連立方程式を解く必要がなく実装が簡単だが、安定条件(CFL条件)を満たす必要がある。

q[j]^(n+1) = q[j]^n − c·Δt · (q[j+1]^n − q[j−1]^n) / (2Δx)

クーラン数

r = c·Δt / Δx = 1 × 0.05 / 0.1 = 0.5

コードの流れ

1
パラメータ・格子設定
c, dt, dx, jmax, nmax を定義。np.linspace で x 座標配列を生成
2
初期条件の設定
j < jmax/2(左半分)は q=1、それ以外は q=0 のステップ関数
3
初期分布をプロット(n=0)
4
時間ループ(n = 1 〜 nmax)
qold = q.copy() で更新前の値を保存し、中心差分で全格子点を更新。
偶数ステップ(n=2, 4, 6)のみグラフに追加
5
グラフ表示
各時刻の分布を重ねてプロット。凡例は n=0, 2, 4, 6

境界の扱い

空間ループは range(1, jmax-1) なので、両端 j=0 と j=jmax-1 は更新されない(固定境界)。

qold = q.copy() の役割

更新中に q[j] を書き換えると、隣の計算に新しい値が混入してしまう。copy() で旧値を保持することで、全格子点を同一時刻の値から計算できる。

精度と安定性

精度

空間差分中心差分 → 2次精度 O(Δx²)
時間差分前進オイラー(陽解法) → 1次精度 O(Δt)

安定性

中心差分+前進オイラーの組み合わせは無条件不安定(von Neumann 安定性解析より)。
クーラン数 r がいかなる値でも数値振動が成長し、時間が経つにつれて解が発散する。
グラフではステップの不連続部付近に振動(数値拡散ではなく数値分散)が現れる。

安定な手法との比較

手法空間精度安定条件
風上差分1次r ≤ 1(安定)
中心差分+前進オイラー2次無条件不安定
Lax-Wendroff法2次r ≤ 1(安定)

コード全文

import numpy as np import matplotlib.pyplot as plt c = 1 # 移流速度 dt = 0.05 # 時間刻み dx = 0.1 # 空間刻み jmax = 21 # 格子点数 nmax = 6 # 総時間ステップ数 x = np.linspace(0, dx*(jmax-1), jmax) # ── 初期条件(ステップ関数) ──────────────── q = np.zeros(jmax) for j in range(jmax): if(j < jmax/2): q[j] = 1 else: q[j] = 0 plt.figure(figsize=(7, 7), dpi=100) plt.rcParams["font.size"] = 25 plt.plot(x, q, marker='o', lw=2, label='n=0') # ── 時間ループ ────────────────────────────── for n in range(1, 1+nmax): qold = q.copy() for j in range(1, jmax-1): q[j] = qold[j] - dt*c*(qold[j+1]-qold[j-1])/(2*dx) # 中心差分 if n%2==0: plt.plot(x, q, marker='o', lw=2, label=f'n={n}') # ── グラフ装飾 ─────────────────────────────── plt.grid(color='black', linestyle='dashed', linewidth=0.5) plt.xlabel('x') plt.ylabel('q') plt.legend() plt.show()

グラフ結果

中心差分による輸送方程式の数値解

関連キーワード

移流方程式 中心差分 2次精度 前進オイラー法 数値不安定 CFL条件 ステップ関数 偏微分方程式 numpy matplotlib