[ Home ] | Integration of Ordinary Differential Equations | Numerical Methods. Note « 3 » |
Runge-Kutta methods are one-step methods where the solution y is advanced by one step h as y1=y0+hk, where k is a cleverly chosen constant. The first order Runge-Kutta method is simply the Euler's method k=k0, k0=f(x0,y0). Second order Runge-Kutta method advances the solution by an auxiliary evaluation of the derivative, fx the half-step method
k=k1/2 : k0=f(x0, y0), y1/2=y0 + h/2 k0, k1/2 = f(x1/2 , y1/2), y1 = y0 + hk1/2 |
k=1/2(k0+k1) : k1 = f(x1, y0+hk0), y1 = y0 + h 1/2 (k0+k1). |
k= 1/6 k0 + 4/6 k1/2 + 1/6 k1. |
Bulirsch-Stoer methods. The idea is to evaluate y1 with several (ever smaller) step-sizes and then make an extrapolation to step-size zero.
Multi-step and predictor-corrector methods. Multi-step methods try to use the information about the function gathered at previous steps. For example the sought function y can be approximated as
yp(x)=y1+y'1⋅(x-x1)+c(x-x1)2, |
c = [y0-y1-y'1⋅(x0-x1)]/(x0-x1)2. |
yc(x)=y1+y'1(x-x1)+c(x-x1)2+d(x-x1)2(x-x0). |
d=[ f2-y'1-2c(x2-x1) ]/[2(x2-x1)(x2-x0)+(x2-x1)2] , |
Step-size control.
Tolerance tol
is the maximal accepted error consistent with the
required absolute acc
and relative eps
accuracies
tol=(eps*|y|+acc)*√[h/b-a] .
|
err
is e.g. estimated from comparing the solution for a
full-step and two half-steps (the Runge principle):
err=|yfull-step - ytwo-half-steps|/(2n-1), |
hnext=hprevious*(tol/err)power*Safety, |
Problems
rkstep
wich advances
the solution by a step h
and estimates the error (for a single
first order ODE): function rkstep(f,x0,y0,h){ k0=f(x0,y0); x12=x0+h/2; y12=y0+k0*h/2; k12=f(x12,y12); y1=y0+k12*h; err=Math.abs( (k0-k12)*h/2 ); return [y1, err] }Here is a Haskell example.
rkstep
with appropriate step-sizes) keeping the specified relative, eps
,
and absolute, acc
, precision:
function driver(f,a,b,y0,acc,eps,h){ if(a>=b) return y0; if(a+h>b) h=b-a; trial=rkstep(f,a,y0,h); y1=trial[0]; err=trial[1]; tol=(eps*Math.abs(y1)+acc)*Math.sqrt(h/(b-a)); if(err>0) newh=h*Math.pow((tol/err),0.2)*0.95; else newh=2*h; if(err<tol) { a=a+h; return driver(f,a,b,y1,acc,eps,newh); } else { return driver(f,a,b,y0,acc,eps,newh); } }Here is a Haskell example.