見出し画像

Runge-Kutta法についてのちょっとした解説

常微分方程式の初期値問題の数値計算において、比較的実装ロジックが単純である割に高精度である4段4次精度陽的Runge-Kutta法(RK4)が使われるケースが多い。基礎的なEuler法から始め、2~4段の陽的Runnge-Kutta法について、一般的なパラメータの条件を導出までを行っている解説です。

画像1

下図は各解法での刻み幅と相対誤差の関係。これのソースはさらにその下(Python)。

画像2

import numpy as np
import matplotlib.pyplot as plt

# ordinary differential equation
f = lambda x, y : y

# calculation section
x_0 = 0
x_n = 1

# initial value
y_0 = 1

# max number of steps: 2**(m-1)
m = 16

# store
step = np.empty(m)
err_eul = np.empty(m)
err_heu = np.empty(m)
err_rk3 = np.empty(m)
err_rk4 = np.empty(m)

# exact value
exact = np.exp(1)

# relative error
rel_err = lambda y : np.abs(y - exact)/exact

for j in range(m):
    # number of steps
    n = 2**j

    # step-size
    h = (x_n - x_0) / n

    x = x_0
    y_eul = y_0
    y_heu = y_0
    y_rk3 = y_0
    y_rk4 = y_0

    for i in range(n):

        # Euler's method
        k_1 = f(x, y_eul)
        y_eul += h*k_1

        # Heun's method
        k_1 = f(x    , y_heu        )
        k_2 = f(x + h, y_heu + h*k_1)
        y_heu += h*(k_1 + k_2)/2

        # RK3 method
        k_1 = f(x      , y_rk3                    )
        k_2 = f(x + h/2, y_rk3 + h*k_1/2          )
        k_3 = f(x + h  , y_rk3 - h*k_1   + 2*h*k_2)
        y_rk3 += h*(k_1 + 4*k_2 + k_3)/6

        # RK4 method
        k_1 = f(x      , y_rk4                            )
        k_2 = f(x + h/2, y_rk4 + h*k_1/2                  )
        k_3 = f(x + h/2, y_rk4           + h*k_2/2        )
        k_4 = f(x + h  , y_rk4                     + h*k_3)
        y_rk4 += h*(k_1 + 2*(k_2 + k_3) + k_4)/6

        x += h

    step[j] = h
    err_eul[j] = rel_err(y_eul)
    err_heu[j] = rel_err(y_heu)
    err_rk3[j] = rel_err(y_rk3)
    err_rk4[j] = rel_err(y_rk4)

# graph
plt.xscale("log")
plt.yscale("log")
plt.xlabel("step-size")
plt.ylabel("relative error")
plt.plot(step, err_eul, label="Euler", marker=".")
plt.plot(step, err_heu, label="Heun", marker=".")
plt.plot(step, err_rk3, label="RK3", marker=".")
plt.plot(step, err_rk4, label="RK4", marker=".")
plt.grid()
plt.legend()
plt.show()

いいなと思ったら応援しよう!