4차 룽게-쿠타 메소드
📂수치해석4차 룽게-쿠타 메소드
메소드
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 지점의 데이터까지 사용한 것을 알 수 있다. 더 일반화된 설명은 같이보기를 참고하자.
직관적인 유도
위의 항들을 하나씩 풀어서 가장 간단한 오일러 메소드 yn+1=yn+hf(xn,yn) 를 통해 생각해보자. (편의상 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))
역시 백워드 오일러 메소드 yn+1=yn+hf(xn+1,yn+1) 에 의해 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]
은 한 스텝 h 를 진행시키기 위해 xn+21 지점의 데이터까지 사용하면서 특히 xn+21 지점에 가중치를 준 가중평균으로 볼 수 있다.
여기서 더 많은 계산을 추가할 순 있지만 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 플랏을 얻는다.

줄리아
다음은 위와 같은 내용의 코드를 줄리아로 구현한 것이다.
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)
같이보기