The Runge-Kutta Method
The Runge-Kutta Method
(1)
where F is any arbitrary combination of the unknown function and the independent variable. We
saw that a unique solution of (1) could be obtained numerically provided that we were given the
subsidiary initial condition: y ( x 0 ) = y 0 , i.e., the value of the unknown function, y 0 , at some initial value of the independent variable, x 0 . We obtained our numerical solution of (1) by applying
the iterative Euler method algorithm:
y i + 1 = y i + xF ( y i, x i )
x i = x 0 + ix
(2)
When F is algebraic (i.e., simple polynomials) the large x solution of (1) generally has exponential behavior (c.f., the population growth and coffee cooling problems). In such cases we could
obtain fairly accurate numerical solutions of (1) with a modest x size.
(3)
-2-
where F is some arbitrary function of y' ( x ) , y ( x ) and x. y'' ( x ) is the notation we use for the
second derivative of the function y ( x ) .
How do equations that have the form of (3) arise in nature? For mechanical systems, Newtons
second law of motion is just such an equation. Newtons second law states that the acceleration of
an object is proportional to the sum of all the forces acting on the object and inversely proportional to its mass:
F
a = ---- ,
(4)
m
where a is the acceleration, F is the net force and m is the mass. For motion in two- and three-dimensions, a and F are really vector quantities, but lets not worry about that yet. Equation (4) is a
second-order differential equation because the acceleration is the rate of change of the velocity
(the derivative of the velocity with respect to time, a ( t ) = v' ( t ) ), and the velocity, in turn, is the
rate of change of the position (the derivative of the position with respect to time, v ( t ) = x' ( t ) ).
Therefore the acceleration is the rate of change of the rate of change of the position (the second
derivative of the position with respect to time, a ( t ) = x'' ( t ) ). Therefore, we can rewrite (4) as:
F ( v, x, t )
x'' ( t ) = --------------------- .
(5)
m
For complete generality, Ive explicitly indicated in (5) the possible dependence of the net force
on velocity, position and time. As a simple example, consider a mass m connected to a spring that
is free to slide on a frictionless horizontal surface:
k
m
+x
x=0
The zigzag line is the spring that has a stiffness k. When the mass is at x = 0 the spring is completely relaxed (i.e., neither stretched nor compressed). When the mass is moved to the left or to
the right it experiences a restoring force due to the spring that is directed towards the right or left,
respectively. The magnitude of the force is proportional to the displacement of the mass, the proportionality constant being the stiffness of the spring, k. This is known as Hookes Law:
. For now well restrict our discussion to one-dimensional systems, i.e., motion along a straight line. Later
in the semester well discuss the Kepler problem (motion of the planets) and electron-electron scattering,
both two-dimensional systems. Well see then that equation (4) becomes a system of two second-order differential equations which must be solved simultaneously.
-3-
F = kx .
Substituting (6) into (5) gives the second-order differential equation describing the motion:
x'' ( t ) = ( k m ) x ( t ) .
(6)
(7)
We know that a first-order differential equation has a unique solution only when a subsidiary
initial condition is supplied. In the case of a second-order differential equation, we must provide
two initial conditions to obtain a unique solution. For Newtons second law of motion, we must
provide the initial position as well as the initial velocity of the object if we are to determine its position as a function of time: x ( 0 ) = x 0 and x' ( 0 ) = v 0 . From (7) you can see that the term k m
has units of an inverse time squared. This inverse time is the natural frequency of oscillation of
the system: = k m . The motion of the mass is completely specified by the following:
2
x'' ( t ) + x ( t ) = 0
x ( 0 ) = x0
(8)
x' ( 0 ) = v 0
The analytical solution of (8) is easy to obtain, but well state it without proof:
v
x ( t ) = x 0 cos ( t ) + ----0- sin ( t ) .
(9)
You can check this result by substituting it back into (8). The important thing to notice is that the
solution is oscillatory with an oscillation frequency given by . A plot of the solution looks like:
1.50
1.00
x(t) [m]
0.50
0.00
-0.50
-1.00
-1.50
0.00
10.00
20.00
30.00
40.00
t [sec]
for the case k = 1.0 N/m, m = 1.0 kg, x0 = 1.0 m and v0 = 1.0 m/s.
50.00
-4-
(10)
(11)
(13)
t i = t 0 + it
For simplicity, we typically take t 0 = 0 . Starting from the initial conditions (i = 0), the left-handsides of (13) are completely specified. This allows us to compute v 1 and x 1 . Knowing these latter
values we can then compute v 2 and x 2 , and so forth. This iterative procedure is repeated until the
solution duration is reached.
-5-
Heres a program to solve the mass-spring problem using the Euler Method:
/*
* spring.c: program that solves the spring-mass problem using Euler's method
*
to solve a second order differential equation.
*/
#include <stdio.h>
#include <math.h>
#define M 1.0
/* mass */
#define K 1.0
/* spring constant */
#define OUTFILE "spring.out" /* output file name */
void
main()
{
double x, v, x_new, v_new, tmax, t, dt, f(double, double, double);
int n, i;
FILE *fp;
fp = fopen(OUTFILE, "w");
printf("\nEnter X0, V0, Tmax and N: ");
scanf("%le %le", &x, &v, &tmax, &n);
dt = tmax/(n-1);
for (t = 0.0, i = 0; i < n; i++) {
fprintf(fp, "%le %le %le\n", t, x, v);
v_new = v + dt * f(t, x, v);
x_new = x + dt * v;
v = v_new;
x = x_new;
t += dt;
}
fclose(fp);
exit(0);
}
double
f(double t, double x, double v)
{
return -K*x/M;
}
egs:ed:362% spring
Enter X0, V0, Tmax and N: 1.0 1.0 20.0 1000
egs:ed:363% cat spring.out
0.000000e+00 1.000000e+00 1.000000e+00
-6-
are
2.0
1.5
x(t) [m]
1.0
0.5
0.0
-0.5
Exact Solution
-1.0
Euler Solution
-1.5
-2.0
0.0
5.0
10.0
15.0
20.0
t [s]
As can be seen in the above figure, the Euler method solution departs from the exact solution with
a magnitude of error increasing with time. The problem lies in the secant approximation of the derivative. Recall that for a second-order differential equations we are effectively approximating the
second derivative of the unknown function by applying the secant method to the curve representing the first derivative of the unknown function. But the first derivative itself was approximated
using the secant method. In other words were approximating an approximation! Its not at all surprising that the error accumulates quickly. Another problem is that the solution has turning points
(places where the sign of the slope changes) where the second derivative is large. You can see
from the figure that these are precisely the places where the Euler method is poorest. To obtain 4
significant figure accuracy in the above solution, we would need to decrease the time-step to
4
t = 2 10 , or 100,000 Euler steps!
Is there a more efficient way? Yes, its called the Runge-Kutta method.
-7-
(14)
(15)
k 1 = xF ( x n, y n )
k1
x
k 2 = xF x n + ------, y n + -----
2
2
k2
x
k 3 = xF x n + ------, y n + -----
2
2
(16)
k 4 = xF ( x n + x, y n + k 3 )
On examination of (16), one sees that the constant k 1 depends on only x n and y n , while k 2 depends on only x n and k 1 , and so forth. Therefore, the right-hand-side of (15) ultimately depends
only upon x n and y n . This was also the property of the Euler method equation (equation (2)) that
allowed it to be iterated. Thus, the fourth-order Runge-Kutta solution of (14) is obtained by iterating (15), beginning at the known initial condition y 0 = y ( x 0 ) .
. For a detailed description and analysis of the method, see Press et al.s Numerical Recipes in C.
-8-
=
=
=
=
dt*f(t, x);
dt*f(t+dt/2, x+k1/2);
dt*f(t+dt/2, x+k2/2);
dt*f(t+dt, x+k3);
v += (k1+2*k2+2*k3+k4)/6;
k1 = k2 = k3 = k4 = dt*v;
x += (k1+2*k2+2*k3+k4)/6;
t += dt;
}
fclose(fp);
exit(0);
}
-9-
double
f(double t, double x)
{
return -K*x/M;
}
Take note of a few things about this program: (i) the variable v is updated immediately and the
new value is used in updating x, (ii) the right-hand-side of the Runge-Kutta equation for updating
x depends only on v which does not explicitly depend on any other variables, hence we have the
statement k1 = k2 = k3 = k4 = dt*v. We could therefore have simplified the program
slightly by writing x += dt*v, omitting the k1 = k2 = k3 = k4 = dt*v statement.
The Runge-Kutta solution for the same system parameters and value of t looks like:
2.0
1.5
x(t) [m]
1.0
0.5
0.0
-0.5
Exact Solution
-1.0
Euler Solution
-1.5
Runge-Kutta Solution
-2.0
0.0
5.0
10.0
15.0
20.0
t [s]
You can see the far better agreement between the Runge-Kutta solution and the exact solution
than that between the Euler method and the exact solutions.