lotkav
@lotkav

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

ルンゲクッタ法 ロトカ3種競争系

解決したいこと

ルンゲクッタ法のコードがうまく書けず困っています。
以下はロトカヴォルテラ3種競争系3すくみの関係のコードです。
ルンゲクッタ法でもシュミレーションを行い結果を比較したいと考えています。
ご教授いただければ幸いです。
よろしくお願いいたします。

該当するソースコード

import numpy as np
import matplotlib.pyplot as plt

dt = 0.05
t0 = 0
te = 1000

ts = np.arange(t0, te + dt, dt)

a = 2.6
b = 0.2
x = 0.3
y = 0.3
z = 0.3

xs, ys, zs = [], [], []

for t in ts:
    xs.append(x)
    ys.append(y)
    zs.append(z)

    x += (1. - xs[-1] - a * ys[-1] - b * zs[-1]) * xs[-1] * dt
    y += (1. - b * xs[-1] - ys[-1] - a * zs[-1]) * ys[-1] * dt
    z += (1. - a * xs[-1] - b * ys[-1] - zs[-1]) * zs[-1] * dt

    print(f"(x, y, z) = ({x:.3e}, {y:.3e}, {z:.3e}) ({t:.2e} sec)\r", end=" ")


fig, ax = plt.subplots()

ax.plot(ts, xs, label="x")
ax.plot(ts, ys, label="y")
ax.plot(ts, zs, label="z")

ax.set_xlabel("t")
ax.set_ylabel("x, y, z")
ax.legend()

plt.show()

自分で試したこと

改良しようとしたところぐちゃぐちゃになってしまいました...

import numpy as np
import matplotlib.pyplot as plt

dt = 0.05
t0 = 0
te = 1000

a = 2.6
b = 0.2
x = 0.3
y = 0.3
z = 0.3

ts = np.arange(t0, te + dt, dt)

def function(x,y,z):
    dxdt=(1 - x - a * y - b * z) * x
    dydt=(1 - b * x - y - a * z) * y
    dzdt=(1 - a * x - b * y - z) * z
    return [dxdt,dydt,dzdt]



x, y, z = [], [], []

for t in ts:

    k1=function(x,y,z)
    k2=function(x+k1[0]*(dt/2),y+k1[1]*(dt/2),z+k1[2]*(dt/2))
    k3=function(x+k2[0]*(dt/2),y+k2[1]*(dt/2),z+k2[2]*(dt/2))
    k4=function(x+k3[0]*(dt/2),y+k3[1]*(dt/2),z+k3[2]*(dt/2))

    x=x+(1/6)*(k1[0]+2*k2[0]+2*k3[0]+k4[0])*dt
    y=y+(1/6)*(k1[1]+2*k2[1]+2*k3[1]+k4[1])*dt
    z=z+(1/6)*(k1[2]+2*k2[2]+2*k3[2]+k4[2])*dt

    x.append(x)
    y.append(y)
    z.append(z)

fig, ax = plt.subplots()

ax.plot(ts, x, label="x")
ax.plot(ts, y, label="y")
ax.plot(ts, z, label="z")

ax.set_xlabel("t")
ax.set_ylabel("x, y, z")
ax.legend()

plt.show()
0

1Answer

こんなのでどうでしょうか?

import numpy as np
import matplotlib.pyplot as plt

# パラメータ
a = 2.9
b = 0.8

# 微分方程式の右辺
def func(t, Xs):
	x, y, z = Xs

	dxdt = (1 - x - a * y - b * z) * x
	dydt = (1 - b * x - y - a * z) * y
	dzdt = (1 - a * x - b * y - z) * z

	return np.array([dxdt,dydt,dzdt])

# 4次ルンゲクッタ
def rk4(dt, t, Xs, func):
	k1 = dt * func(t, Xs)
	k2 = dt * func(t + dt / 2, Xs + k1 / 2)
	k3 = dt * func(t + dt / 2, Xs + k2 / 2)
	k4 = dt * func(t + dt, Xs + k3)

	new_t = t + dt
	newXs = Xs + (k1 + 2 * k2 + 2 * k3 + k4) / 6

	return new_t, newXs

# 計算の実行
dt = 0.05
t0 = 0
te = 1000
ts = np.arange(t0, te + dt, dt)
Xs = np.array([0.3, 0.3, 0.3])

xs, ys, zs = [], [], []
for t in ts:
	x, y, z = Xs
	xs.append(x)
	ys.append(y)
	zs.append(z)

	_, Xs = rk4(dt, t, Xs, func)

# 描画
fig, ax = plt.subplots()

ax.plot(ts, xs, label="x")
ax.plot(ts, ys, label="y")
ax.plot(ts, zs, label="z")

ax.set_xlabel("t")
ax.set_ylabel("x, y, z")
ax.legend()

plt.show()
0Like

Comments

  1. @lotkav

    Questioner

    ご回答ありがとうございます!
    ルンゲクッタ法は初めてだったのでとても助かりました。
    精度を比較したところあまり差はなかったです。
    以前のコードはオイラー法を用いたものという認識で間違っていないでしょうか。
  2. > 精度を比較したところあまり差はなかったです。
    時間刻みを大きくすると差が出てくるかもしれません。

    > 以前のコードはオイラー法を用いたものという認識で間違っていないでしょうか。
    はい。間違いありません。
  3. @lotkav

    Questioner

    時間刻み幅大きくして試してみたところ差が生まれました!
    ルンゲクッタ法は精度がいいですね。

    確信が持ててよかったです。
    勉強になりました、ご回答ありがとうございました!

Your answer might help someone💌