The Runge-Kutta method attempts to improve the Euler’s method. Each Runge–Kutta method is derived from an appropriate Taylor method (In fact, Euler’s method can also be seen derived from a simple Taylor method). These methods can be constructed for any order. By far, the most often used method is the classical fourth-order Runge-Kutta method.
Suppose we want to solve the the following ODE
\[\left\{\begin{matrix} y'=f(t,y)\\ y(t_0)=y_0 \end{matrix}\right. \] For RK4 we will use the following recursive method to find the final solution
\[y_{n+1}=y_n+\frac{1}{6}(k_1+2k_2+2k_3+k_4)h\] where: \[y_n+\frac{1}{6}(k_1+2k_2+2k_3+k_4)h=\text{weighted average slope}\] \[\begin{array}{l} k_1 = f(t_n , y_n ), \\ k_2 = f\left( t_n + \frac{h}{2}, y_n + \frac{h}{2} k_1 \right) , \\ k_3 =f\left( t_n + \frac{h}{2}, y_n + \frac{h}{2} k_2 \right) , \\ k_4 = f( t_n + h, y_n + h k_3 ). \end{array}\]Other methods: Gill’s Algorithm RK4, Fifth order Butcher’s method, Runge–Kutta–Fehlberg Method (RKF45), et al
Example: R code to solve \[{{dy(t)} \over {dt}} + 2y(t) = 0\quad {\rm{or }} \quad {{dy(t)} \over {dt}} = - 2y(t)\] From: https://lpsa.swarthmore.edu/NumInt/NumIntFourth.html, I modified the Matlab code.
# Solve y'(t)=-2y(t) with y0=3, 4th order Runge Kutta
# Initial condition gives solution at t=0.
RK4_1<-function(h,t0,t_m,y0){
t = seq(t0,t_m,by=h)
nstep=(t_m-t0)/h+1
ystar<-c((1:nstep)*0)
ystar[1] = y0
for(i in 1:(length(t)-1)){
k1 = -2*ystar[i] # Approx for y gives approx for deriv
y1 = ystar[i]+k1*h/2 # Intermediate value (using k1)
k2 = -2*y1 # Approx deriv at intermediate value.
y2 = ystar[i]+k2*h/2 # Intermediate value (using k2)
k3 = -2*y2 # Another approx deriv at intermediate value.
y3 = ystar[i]+k3*h # Endpoint value (using k3)
k4 = -2*y3 # Approx deriv at endpoint value.
ystar[i+1] = ystar[i] + (k1+2*k2+2*k3+k4)*h/6 # Approx soln
}
return(list('ystar'=ystar,'t'=t))
}
y1<-RK4_1(0.2,0,2,3)
y2<-RK4_1(0.8,0,2,3)
t = seq(0,2,by=0.2) # t goes from 0 to 2 seconds.
yexact = 3*exp(-2*t)
plot(y1$t,y1$ystar,xlab='time',ylab='y')
lines(t,yexact,type='l')
lines(y2$t,y2$ystar,lty=3)
Another example solve \(\frac{dy}{dt}=y-t^2+1\) and \(y(0)=0.5\)
#f(t,y)=y-t^2+1
f_ty<-function(t,y){
f_ty<-y-t^2+1
return(f_ty)
}
RK4_2<-function(h,t0,t_m,y0){
t = seq(t0,t_m,by=h)
ystar<-c((1:length(t))*0)
ystar[1] = y0
for(i in 1:(length(t)-1)){
k1 = h*f_ty(t[i],ystar[i])
k2 = h*f_ty(t[i]+0.5*h,ystar[i]+k1/2)
k3 = h*f_ty(t[i]+0.5*h,ystar[i]+k2/2)
k4 = h*f_ty(t[i]+h,ystar[i]+k3)
ystar[i+1] = ystar[i] + (k1+2*k2+2*k3+k4)/6
}
return(ystar)
}
y<-RK4_2(0.5,0,2,0.5)
y
## [1] 0.500000 1.425130 2.639603 4.006819 5.301605
The exact solution of is \(y=t^2+2t+1-\frac{1}{2}e^t\)
t = seq(0,2,by=0.5)
y_exact<-t^2+2*t+1-0.5*exp(t)
y_exact
## [1] 0.500000 1.425639 2.640859 4.009155 5.305472
\[ \left\{\begin{array}{l} \frac{dy}{dx}=f(x,y(x),z(x)), & y(x_0)=y_0 \\ \frac{dz}{dx}=g(x, y(x), z(x)),& z(x_0)=z_0\\ \end{array} \right. \]
\[\begin{array}{l} k_1 = h · f(x_n, y_n, z_n)\\ l_1 = h · g(x_n, y_n, z_n)\\ k_2 = h · f(x_n + h/2, y_n + k_1/2, z_n + l_1/2)\\ l_2 = h · g(x_n + h/2, y_n + k_1/2, z_n + l_1/2)\\ k_3 = h · f(x_n + h/2, y_n + k_2/2, z_n + l_2/2)\\ l_3 = h · g(x_n + h/2, y_n + k_2/2, z_n + l_2/2)\\ k_4 = h · f(x_n + h, y_n + k_3, z_n + l_3)\\ l_4 = h · g(x_n + h, y_n + k_3, z_n + l_3)\\ k = 1/6 · (k_1 + 2 · k_2 + 2 · k_3 + k_4)\\ l = 1/6 · (l_1 + 2 · l_2 + 2 · l_3 + l_4)\\ x_n+1 = x_n + h\\ y_n+1 = y_n + k\\ z_n+1 = z_n + l\\ \end{array}\]Example
\[\left\{\begin{array}{l} \frac{dy}{dx} = z \\ \frac{dz}{dx} = 6y - z \end{array}\right. \]
With \(y(0)=3\) and \(z(0)=1\), for \(0\le t \le 1\)
R code for solving above system using RK4:
F_xyz<-function(x,y,z){
fxyz<-z
return(fxyz)
}
G_xyz<-function(x,y,z){
gxyz<-6*y-z
return(gxyz)
}
RK4_3<-function(h,t0,t_m,y0,z0){
t = seq(t0,t_m,by=h)
ystar<-c((1:length(t))*0)
zstar<-c((1:length(t))*0)
ystar[1] = y0
zstar[1] = z0
for(i in 1:(length(t)-1)){
k1 = h*F_xyz(t[i],ystar[i],zstar[i])
l1 = h*G_xyz(t[i],ystar[i],zstar[i])
k2 = h*F_xyz(t[i]+0.5*h,ystar[i]+k1/2,zstar[i]+l1/2)
l2 = h*G_xyz(t[i]+0.5*h,ystar[i]+k1/2,zstar[i]+l1/2)
k3 = h*F_xyz(t[i]+0.5*h,ystar[i]+k2/2,zstar[i]+l2/2)
l3 = h*G_xyz(t[i]+0.5*h,ystar[i]+k2/2,zstar[i]+l2/2)
k4 = h*F_xyz(t[i]+h,ystar[i]+k3,zstar[i]+l3)
l4 = h*G_xyz(t[i]+h,ystar[i]+k3,zstar[i]+l3)
ystar[i+1] = ystar[i] + (k1+2*k2+2*k3+k4)/6
zstar[i+1] = zstar[i] + (l1+2*l2+2*l3+l4)/6
}
return(list('ystar'=ystar,'zstar'=zstar))
}
RK4_3(0.1,0,1,3,1)
## $ystar
## [1] 3.000000 3.183638 3.532476 4.050814 4.752267 5.659661 6.805469
## [8] 8.232750 9.996623 12.166270 14.827579
##
## $zstar
## [1] 1.000000 2.663088 4.320751 6.068622 7.998407 10.203527 12.784314
## [8] 15.853107 19.539561 23.996434 29.406157
We also can use R deSolve package to solve the above ODE system
ODE_sys<-function(t,state,parameters){
with(as.list(c(state)),
{
dy <-z
dz <- 6*y-z
list(c(dy,dz))
})
}
### define parameters
state <- c(y=3,z=1)
times<-seq(0,1,by=0.1)
require(deSolve)
out <- as.data.frame(ode(y=state,times=times,func=ODE_sys))
out
## time y z
## 1 0.0 3.000000 1.000000
## 2 0.1 3.183624 2.663155
## 3 0.2 3.532461 4.320864
## 4 0.3 4.050808 6.068766
## 5 0.4 4.752278 7.998580
## 6 0.5 5.659696 10.203737
## 7 0.6 6.805536 12.784573
## 8 0.7 8.232863 15.853438
## 9 0.8 9.996792 19.539990
## 10 0.9 12.166514 23.996997
## 11 1.0 14.827920 29.406900
We see the two methods got exactly the same results.
Another example:
\[\left\{\begin{array}{l} \frac{dy}{dt} = -y+4x \\ \frac{dx}{dt} = -y+6x \end{array}\right. \] with With \(y(0)=-0.5\) and \(x(0)=0.5\), for \(0\le t \le 1\) for \(0\le t \le 0.7\)
1.https://www.cfm.brown.edu/people/dobrush/am33/Matlab/ch3/RK4.html
2.https://mathworld.wolfram.com/Runge-KuttaMethod.html
3.https://math.okstate.edu/people/yqwang/teaching/math4513_fall11/Notes/rungekutta.pdf