| [ 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.