LoginSignup
11
9

More than 3 years have passed since last update.

1次元波動方程式を差分法で解く(python)

Last updated at Posted at 2020-06-14

シンプルな波動方程式

 \frac{\partial^2 u}{\partial t^2} = c^2 \frac{\partial^2 u}{\partial x^2} \\
0<x<l,0<t

これを解きたい

境界条件

u(0)=0,\frac{\partial u}{\partial x}\Big|_{x=l} = 0

左端は境界での$u$の値を指定するディリクレ境界条件で、右端は境界値の微分値を指定するノイマン境界条件

左は固定端、右は自由端という境界条件になっている。

初期条件

u(x,0) = f(x)\\
\frac{\partial u}{\partial t}=0

弦の振動や縦棒の振動であれば、初速は0ということ。

離散式

x_i = i\Delta x\\
t^n = n\Delta t\\
u_{i}^n = u(x_i,t^n)\\
(i = 1\cdots m, \Delta x = \frac{l}{m})

と置く。ただし$m$は空間分割数とする。

初期条件 境界条件

まず初期解を設定する。

u_{i}^0 = f(x_i)\\
u_{i}^1 = u_{i}^0

時間の一階微分が0なので$u_{i}^1 = u_{i}^0$となっている。

次に境界条件を設定する。
しかし、困ったことに右端のノイマン境界条件は空間微分で表されるため、表現するためには2要素使わなければならない。そのため、右端の境界にもう一つ偽の要素を加える。つまり、

u_{m+1}^n = u_{m}^n

とすれば、一階の空間微分が0であるという、右端のノイマン境界条件が満たされる。
そして、左端のディリクレ境界条件は、以下のように表せる。

u_1^n = 0

いよいよ方程式そのものを離散化していく。

空間微分の離散化

\frac{\partial^2 u}{\partial x^2}\Big|_{x=x_i}=\frac{u_{i+1}-2u_{i}+u_{i-1}}{\Delta x^2}

$u_{i+1}$と$u_{i-1}$を$x=x_i$でテーラー展開して求めるとこれを導けます。

時間発展の離散化

空間微分と同様に考えると,

\frac{\partial^2 u}{\partial t^2} =\frac{u^{n+1}-2u^{n}+u^{n-1}}{\Delta t^2}

であるから,

\begin{align}
u^{n+1}_i &= 2u^{n}_i-u^{n-1}_i + \Delta t^2 \frac{\partial^2 u}{\partial t^2}\Big|_{x=x_i}\\
&= 2u^{n}_i-u^{n-1}_i + c^2 \Delta t^2 \frac{u_{i+1}-2u_{i}+u_{i-1}}{\Delta x^2}
\end{align}

コードを書こう

サンプルクソコード

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from copy import deepcopy


fig, ax = plt.subplots()

c = 1.
x_left = 0.
x_right = 1.
t = 0.
# 101個の点で離散化を行うという意味
num_points = 101
dx = (x_right-x_left)/(num_points-1)
# ノイマン境界のために余分に一つ確保
x = np.linspace(x_left, x_right+dx, num_points+1)
# u = x/1000 で初期化
u = 1e-3*x
# ノイマン境界条件
u[-1] = u[-2]

u_before = deepcopy(u)
u_next = deepcopy(u)

# 一定時間ごとのuの値をここに積んでいく
u_at_t = [deepcopy(u)]


dt = 0.1 * dx/c

count = 0


while t < 0.5:
    print(np.diff(u,2))
    u_next[1:num_points] = 2.*u[1:num_points] - u_before[1:num_points] + c*c*dt*dt/(dx*dx) * np.diff(u, 2)

    # ノイマン境界条件
    u_next[-1] = u_next[-2]
    u_next[0] = 0.
    u_before = deepcopy(u)
    u = deepcopy(u_next)
    u_next = np.zeros(u.shape)
    t += dt
    count += 1
    # 16ステップに一回
    if count == 16:
        u_at_t.append(deepcopy(u))
        count = 0


def update(u, x):
    plt.clf()
    plt.xlim(x_left, x_right)
    plt.ylim(-1e-3, 1e-3)
    plt.plot(x, u)


# アニメーション表示するための関数
anim = FuncAnimation(fig, update, fargs=(
    x,), frames=u_at_t, interval=10)

plt.show()

# anim.save("foo.mp4", writer="ffmpeg",fps=10)

動画を保存するのは重たい作業になるので注意

続く

参考

動画作成のためのテクニック
https://qiita.com/msrks/items/e264872efa062c7d6955
差分式
https://qiita.com/Ushio/items/0249fd7a5363ccd914dd

11
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
9