四次のルンゲ=クッタ法
📂数値解析四次のルンゲ=クッタ法
メソッド
D⊂R2 で定義された連続関数 f に対する初期値問題 {y′=f(x,y)y(x0)=Y0 が与えられている。区間 (a,b) を a≤x0<x1<⋯<xn<⋯xN≤b のようなノードポイントで分けたとする。特に充分に小さい h>0 に対して xj=x0+jh とすると、初期値 y0=Y0 に対して
yn+1=yn+hj=1∑pγjVj
説明
ルンゲ=クッタ法は、アダムス法のように、多様な形式を持ち、複雑な代数的操作を通じて γj と Vj を決定する。その中でも特に人気があるのが4次のルンゲ=クッタ法で、通常 RK4 と略される。
4次のルンゲ=クッタ法:
yn+1=V1=V2=V3=V4=yn+6h[V1+2V2+2V3+V4]f(xn,yn)f(xn+2h,yn+2hV1)f(xn+2h,yn+2hV2)f(xn+h,yn+hV3)
この式を見ると、ステップ h を進めるために 2h 地点のデータまで使ったことがわかる。もっと一般化した説明は関連項目を参照してほしい。
直感的な導入
上記の項を一つずつ解いて、最も単純なオイラー法を使って考えてみよう。 (便宜上 xn+21:=xn+2h、yn+21≈Y(xn+2h) とする。)
V1=f(xn,yn)
は、xn 地点での微分係数 yn′ になる。
V2==f(xn+2h,yn+2hf(xn,yn))f(xn+21,yn+21)
は、xn+21 地点での微分係数 yn+21′ になる。
V3=f(xn+2h,yn+2hf(xn+21,yn+21))
また、バックワードオイラー法により V3=f(xn+21,yn+21) で、xn+21 地点での微分係数 yn+21′ になる。
V4===f(xn+h,yn+hV3)f(xn+2h+2h,yn+2hV3+2hV3)f(xn+2h+2h,yn+2h+2hV3)
さらに、バックワードオイラー法により、xn+1 地点での微分係数 yn+1′ になる。
6h[V1+2V2+2V3+V4]
特に、xn+21 地点のデータまで使いながら、特に xn+21 地点に重みをつけた加重平均と見ることができるステップ h を進めるためのものと考えられる。
ここで更に計算を加えることは可能だが、RK4からは収束次数が計算量だけで上がってくれない。別にもっと上げなくても、問題がスティフでなければ、RK4だけで十分であり、コーディングも比較的簡単で広く使われている。
実装
R
以下は、RでRK4を実装し、ローレンツアトラクタを3Dで描画するコードである。
library(rgl)
RK4<-function(ODE,v,h=10^(-2)){
V1 = ODE(v)
V2 = ODE(v + (h/2)*V1)
V3 = ODE(v + (h/2)*V2)
V4 = ODE(v + h*V3)
v = v + (h/6)*(V1 + 2*V2 + 2*V3 + V4)
return(v)
}
lorenz<-function(v,rho=28,sigma=10,beta=8/3){
dvdt = v
dvdt[1] = sigma*(v[2]-v[1])
dvdt[2] = v[1]*(rho-v[3])-v[2]
dvdt[3] = v[1]*v[2] - beta*v[3]
return(dvdt)
}
traj<-numeric(0)
v=c(1,1,1)
for(i in 1:10000){
traj<-rbind(traj,v)
v=RK4(lorenz,v)
}
plot3d(traj,type='l')
plot(traj[,1],traj[,3],type='l')
このコードを実行すると、次のような3Dプロットを得られる。

ジュリア
../../categories/줄리아
以下は、上記と同じ内容のコードをジュリアで実装したものである。
using Plots
function RK4(ODE::Function,v::Array{Float64,1},h=10^(-2))
V1 = ODE(v)
V2 = ODE(v .+ (h/2)*V1)
V3 = ODE(v .+ (h/2)*V2)
V4 = ODE(v .+ h*V3)
return @. v + (h/6)*(V1 + 2*V2 + 2*V3 + V4)
end
function lorenz(v::Array{Float64,1}; ρ=28.,σ=10.,β=8/3)
dvdt = deepcopy(v)
dvdt[1] = σ*(v[2]-v[1])
dvdt[2] = v[1]*(ρ-v[3])-v[2]
dvdt[3] = v[1]*v[2] - β*v[3]
return dvdt
end
function lorenz_attracter(v::Array{Float64,1}, endtime = 10000)
x,y,z = [v[1]], [v[2]], [v[3]]
for t in 1:endtime
newx,newy,newz = RK4(lorenz,[x[end], y[end], z[end]])
push!(x, newx)
push!(y, newy)
push!(z, newz)
end
return x,y,z
end
result = lorenz_attracter([1.,1.,1.])
plot(result)
関連項目