Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Part 2: Building Better Methods - Runge-Kutta

Module 3: ODE Methods & Conservation | COMP 521

Learning Objectives

By the end of this section, you will be able to:


The Key Insight: Sample Multiple Points

Euler extends the initial tangent through the step. Curvature introduces a one-step defect, which motivates sampling additional slopes. Runge-Kutta methods evaluate the derivative at carefully chosen intermediate points, then combine these samples with specific weights to achieve higher-order accuracy.

This connects to quadrature from Module 2: We’re essentially performing numerical integration on:

xn+1=xn+∫tntn+1f(t,x(t))dtx_{n+1} = x_n + \int_{t_n}^{t_{n+1}} f(t, x(t)) dt

But now the integrand depends on the unknown solution x(t)x(t) itself, requiring us to estimate intermediate values.

RK2 - The Midpoint Method

Geometric Intuition

Instead of blindly following the tangent from the starting point, we:

  1. Take a half-step using the initial derivative

  2. Evaluate the derivative at this midpoint

  3. Use this midpoint derivative for the full step

This is analogous to the midpoint rule for integration, which we know from Module 2 is second-order accurate!

Complete Mathematical Formulation

Predictor-corrector method: A two-stage process where an initial estimate (predictor) is refined using better information (corrector).

The RK2 midpoint method is a predictor-corrector method:

Stage 1 - Predictor:

k1=f(tn,xn)k_1 = f(t_n, x_n)

xmid=xn+h2k1x_{mid} = x_n + \frac{h}{2}k_1

Stage 2 - Corrector:

k2=f(tn+h2,xmid)k_2 = f(t_n + \frac{h}{2}, x_{mid})

xn+1=xn+hk2x_{n+1} = x_n + h k_2
RK2 midpoint method: First evaluate derivative at start (k_{1}), use it to estimate midpoint, evaluate derivative there (k_{2}), then use midpoint derivative for full step

Figure 1:This dimensionless example solves y′=−y+sin⁡ty'=-y+\sin t, y(0)=1y(0)=1, with exact reference y(t)=32e−t+12(sin⁡t−cos⁡t)y(t)=\tfrac32e^{-t}+\tfrac12(\sin t-\cos t) (the figure labels the independent variable xx). In the left panel, h=1h=1: the initial slope predicts the midpoint state, and the slope at that predicted state advances the full step. Its absolute error is about 0.2770, versus Euler’s 0.7024; this coarse step is still inaccurate. The right panel compares errors at the fixed endpoint t=2t=2 as hh decreases. The asymptotic trends approach first order for Euler and second order for midpoint RK2.

Open full-size figure

Error Analysis via Taylor Series

Differentiate the ODE along its solution. For a vector state, let J=∂f/∂xJ=\partial f/\partial x be the state Jacobian. Then

x′′=ft+Jf,x''=f_t+Jf,

so the exact solution begins

x(t+h)=x+hf+h22(ft+Jf)+O(h3).x(t+h)=x+h f+\frac{h^2}{2}(f_t+Jf)+O(h^3).

Try two stages, with k1=f(t,x)k_1=f(t,x) and k2=f(t+ch,x+ahf)k_2=f(t+ch,x+ah f), and an update x+h(b1k1+b2k2)x+h(b_1k_1+b_2k_2). A multivariate expansion gives

k2=f+h(cft+aJf)+O(h2),k_2=f+h(c f_t+aJf)+O(h^2),

and the resulting update is

x+h(b1+b2)f+h2b2(cft+aJf)+O(h3).x+h(b_1+b_2)f+h^2b_2(c f_t+aJf)+O(h^3).

Matching the independent terms requires

b1+b2=1,b2c=12,b2a=12.b_1+b_2=1,\qquad b_2c=\frac12,\qquad b_2a=\frac12.

Choose b2=1b_2=1. Then b1=0b_1=0 and a=c=1/2a=c=1/2, giving the explicit midpoint formulas above. The midpoint slope consequently satisfies

f(tmid,xmid)=f+h2(ft+Jf)+O(h2).f(t_{mid},x_{mid})=f+\frac h2(f_t+Jf)+O(h^2).

Another choice, b1=b2=1/2b_1=b_2=1/2 and a=c=1a=c=1, gives Heun’s explicit trapezoidal method. Both are second-order RK methods, but their intermediate states differ. This reading uses explicit midpoint when it says RK2. On a linear autonomous system they have the same one-step map; a nonlinear test can separate them. For x′=x2x'=x^2, x(0)=1x(0)=1, their one-step values are 1+h+h2+h3/41+h+h^2+h^3/4 and 1+h+h2+h3/21+h+h^2+h^3/2, respectively. Neither cubic coefficient matches the exact local expansion of 1/(1−h)1/(1-h); both methods match through second order. Do not mix their stages and weights.

The RK2 update matches the true solution through O(h2)O(h^2):

In a resolved truncation regime at fixed duration, halving the timestep reduces the leading global error by approximately four.

From mathematics to your implementation

The stage equations are the specification you will translate into Python. Write the RK2 and RK4 implementations yourself. We will use complete Euler examples to demonstrate array handling, stepping, and diagnostics; a working RK routine is not supplied here.

For Python, use independent variable first: f(t, state) returns the rate of change of the NumPy-array state. In the equations above, xnx_n denotes that state; it can have several components. Addition and scalar multiplication then operate on the entire array. The stage slopes must have the same shape as the state. Their units are state units divided by time units; multiplying a slope by hh gives a state increment.

Separate two responsibilities:

ResponsibilityInputsOutputWhat to establish
One stepA derivative callable, starting time and state, and a step lengthA new stateStage times, stage states, weights, shape, and no mutation of the supplied state
Repeated stepsA step routine and an integration intervalThe endpoint or a recorded trajectory, as the caller needsEndpoint handling, time bookkeeping, and where samples are stored

First explain the method in mathematical statements, then write your own code. Before writing the loop, answer: which quantities belong to the original state, and which belong to a temporary stage? If a stage accidentally overwrites the starting state, later formulas describe a different method.

Do not judge correctness from a smooth-looking trajectory alone. A constant right-hand side checks basic increments. A time-dependent right-hand side tests whether stage times are used. A nonlinear state-dependent right-hand side tests whether intermediate states are used. Refinement over a fixed interval then checks the claimed global order. These checks probe different mistakes; none is a replacement for deriving the update.

RK4 - The Classical Workhorse

Runge-Kutta 4 (RK4): A classical explicit method with four derivative evaluations per step and fourth-order global accuracy under its smoothness and stability assumptions.

RK4 samples the derivative at four carefully chosen points:

Stage 1: k1=f(tn,xn)k_1 = f(t_n, x_n) (derivative at start)

Stage 2: k2=f(tn+h2,xn+h2k1)k_2 = f(t_n + \frac{h}{2}, x_n + \frac{h}{2}k_1) (derivative at midpoint using k1k_1)

Stage 3: k3=f(tn+h2,xn+h2k2)k_3 = f(t_n + \frac{h}{2}, x_n + \frac{h}{2}k_2) (derivative at midpoint using k2k_2)

Stage 4: k4=f(tn+h,xn+hk3)k_4 = f(t_n + h, x_n + hk_3) (derivative at endpoint using k3k_3)

Final update:

xn+1=xn+h6(k1+2k2+2k3+k4)\boxed{x_{n+1} = x_n + \frac{h}{6}(k_1 + 2k_2 + 2k_3 + k_4)}

The Connection to Simpson’s Rule

For a time-only right-hand side x′=g(t)x'=g(t), the two midpoint evaluations are identical. The RK4 update then becomes

xn+1=xn+h6[g(tn)+4g(tn+h/2)+g(tn+h)],x_{n+1}=x_n+\frac h6\left[g(t_n)+4g(t_n+h/2)+g(t_n+h)\right],

which is exactly Simpson quadrature over the time interval. Euler similarly reduces to left rectangles and explicit midpoint RK2 to midpoint quadrature.

For f(t,x)f(t,x), however, k2k_2 and k3k_3 generally differ: they evaluate different predicted states at the same time. Simpson’s weights alone do not establish fourth-order ODE accuracy. The stage locations and dependencies must satisfy additional order conditions involving state derivatives of ff.

Check: for x′=xx'=x, start at x=1x=1, t=0t=0 with h=0.1h=0.1. Then k1=1k_1=1, k2=1.05k_2=1.05, k3=1.0525k_3=1.0525, and k4=1.10525k_4=1.10525. The unequal midpoint slopes are precisely what the state-dependent problem adds to the quadrature analogy.

Error Analysis

Through Taylor series expansion to fourth order:

In a resolved truncation regime at fixed duration, halving the timestep reduces the leading global error by approximately sixteen.

The General Runge-Kutta Framework

Butcher tableau: A compact notation for Runge-Kutta methods invented by John Butcher (1964), organizing the coefficients that define each method.

All explicit RK methods follow this pattern:

ki=f(tn+cih,xn+h∑j=1i−1aijkj)k_i = f\left(t_n + c_ih, x_n + h\sum_{j=1}^{i-1} a_{ij}k_j\right)
xn+1=xn+h∑i=1sbikix_{n+1} = x_n + h\sum_{i=1}^s b_i k_i

The coefficients (aij,bi,ci)(a_{ij}, b_i, c_i) define the method and are displayed in a Butcher tableau:

c₁ |
c₂ | a₂₁
c₃ | a₃₁ a₃₂
⋮  | ⋮
cₛ | aₛ₁ aₛ₂ ... aₛ,ₛ₋₁
---|--------------------
   | b₁  b₂  ...  bₛ

For RK4:

0   |
1/2 | 1/2
1/2 | 0   1/2
1   | 0   0   1
----|----------------
    | 1/6 2/6 2/6 1/6

Follow the dependencies, not just the weights

The two midpoint stages occur at the same time but generally at different predicted states. The second midpoint evaluation revises the slope information used to predict the endpoint.

Every stage state in the formulas is built from the original xnx_n plus a specified increment. The arrows show dependencies; they do not mean that stage states are advanced sequentially by a full ODE step. The two midpoint states are generally not points on the exact trajectory either.

Four RK4 slope samples for x prime equals x are shown at the start, two distinct midpoint predictions, and an endpoint prediction, alongside the exact exponential trajectory.

Figure 2:For x′=xx'=x, x(0)=1x(0)=1, and h=0.5h=0.5, the midpoint predictions are 1.25 and 1.3125, whereas the exact midpoint value is e0.25e^{0.25}. RK4 uses information from approximate stage states to construct an accurate endpoint; it does not require every intermediate state to have fourth-order accuracy.

Open full-size figure

Adaptive Timestep Control

Real problems have varying timescales. When a planet is far from the sun, we can take large steps. During close encounters, we need tiny steps. Adaptive methods adjust hh dynamically.

The Embedded Runge-Kutta Approach

The idea: compute two different order estimates using the same function evaluations, then use their difference to estimate error.

An embedded example: Fehlberg 4(5)

The original six-stage Fehlberg pair computes both fourth- and fifth-order solutions. The name RK45 is also used for other pairs: SciPy uses Dormand–Prince, not these six stages. For the Fehlberg example:

  1. Compute six kik_i values (shared between both estimates)

  2. Combine with 4th-order weights →\to x(4)x_{(4)}

  3. Combine with 5th-order weights →\to x(5)x_{(5)}

  4. Error estimate: ϵ=∣∣x(5)−x(4)∣∣\epsilon = ||x_{(5)} - x_{(4)}||

  5. Suggested next timestep (with a safety factor): hnew=h⋅0.9⋅(tolerance/ϵ)1/5h_{new} = h \cdot 0.9 \cdot (\text{tolerance}/\epsilon)^{1/5}

For vectors, first scale each component by an allowance such as atol + rtol * abs(reference_state) and use a stated norm. Bound the step-growth factor and handle a zero estimate explicitly. If the scaled estimate is acceptable, accept the step and continue. Otherwise, reject and retry with smaller hh.

Exact Kepler ellipse at eccentricity 0.9 sampled in 64 equal eccentric-anomaly intervals. The corresponding time intervals are shorter near perihelion and longer near aphelion.

Figure 3:This is a kinematic sampling schematic, not an adaptive-solver benchmark. The exact Kepler ellipse has eccentricity e=0.9e=0.9 and is sampled at 64 equal increments of eccentric anomaly EE. Kepler’s relation t/P=(E−esin⁡E)/(2π)t/P=(E-e\sin E)/(2\pi) gives the time of each point. The left panel colors each point by the following time interval; the right plots those intervals against their time midpoints. This illustrates why the rapid motion near perihelion calls for finer time resolution. It makes no accuracy or efficiency claim; the executable Euler experiment below demonstrates an actual error-controlled acceptance rule.

Open full-size figure

Watch an adaptive controller make a decision

We can study acceptance and rejection using Euler steps, while leaving the RK implementations to you. Consider the dimensionless decay problem u′=−uu'=-u, u(0)=1u(0)=1, with exact solution u(t)=e−tu(t)=e^{-t}. It gives us a reference for checking the numerical experiment without introducing another physical model.

Take one Euler step of length hh and, separately, two Euler steps of length h/2h/2, both starting from the same (t,u)(t,u). If the leading one-step defect is Ch2Ch^2, the two-half-step result has approximately half the defect of the coarse result. Their difference therefore estimates the two-half-step local error in the smooth, small-step regime:

e^=∣ufine−ucoarse∣.\widehat e=|u_{\rm fine}-u_{\rm coarse}|.

This is still a first-order method. We accept ufineu_{\rm fine} itself; we do not apply an extrapolation correction. The comparison estimates a local error and does not reveal the exact accumulated error of the trajectory.

For this example, define the scale and normalized estimate explicitly:

s=atol+rtolmax⁡(∣u∣,∣ufine∣),η=e^/s.s=\mathrm{atol}+\mathrm{rtol}\max(|u|,|u_{\rm fine}|), \qquad \eta=\widehat e/s.

Accept when η≤1\eta\le1. Rejection leaves both the accepted time and accepted state unchanged. The proposed next step uses hnew∝hη−1/2h_{\rm new}\propto h\eta^{-1/2} because this estimator scales as h2h^2. The exponent would change for another estimator. Growth limits and a safety factor make the controller less abrupt; they do not turn an estimate into a mathematical bound.

Predict before running: Will the initial step of length 1 be accepted? When the solution becomes small, which part of the allowance will eventually matter more? Does every accepted step imply that the final solution is within one tolerance of the exact answer?

  start t    trial h    scaled estimate   accept?
   0.0000     1.0000         247.5248   False
   0.0000     0.2000           9.9010   False
   0.0000     0.0572           0.8100   True
   0.0572     0.0572           0.8095   True
   0.1144     0.0572           0.8095   True
   0.1716     0.0572           0.8095   True
Final actual absolute error: 0.0010884703398220882

The first three statements in euler_trial are exactly Euler updates. This transparent version evaluates the starting derivative twice; caching it would save one call per trial, without changing the method. The controller records rejected trials as well as accepted ones, so the work cannot be inferred just from the number of stored solution points.

<Figure size 800x600 with 2 Axes>
rtol=1e-02: accepted=22, attempts=23, final error=3.226e-03, error/final allowance=20.05
rtol=1e-03: accepted=67, attempts=69, final error=1.088e-03, error/final allowance=39.98
rtol=1e-04: accepted=163, attempts=166, final error=4.780e-04, error/final allowance=40.57

The same controller logic can use an embedded RK error estimate, with the appropriate estimator order and vector scaling. Constructing the RK stages remains your work. A request for evenly spaced output is also different from a request for evenly spaced internal steps: established libraries can interpolate between accepted steps. SciPy’s solver documentation distinguishes these roles and describes component-dependent absolute tolerances.

When to Use Adaptive Methods

Good for:

Bad for:

Compare accuracy and work with a defined benchmark

A comparison needs a defined system, initial state, duration, step size, error metric, and cost metric. We use the dimensionless simple harmonic oscillator (SHO), q′=pq'=p, p′=−qp'=-q, with (q(0),p(0))=(1,0)(q(0),p(0))=(1,0). Its exact solution is (cos⁡t,−sin⁡t)(\cos t,-\sin t) and its period is 2π2\pi.

The reference plots below retain the comparisons among Euler, explicit midpoint RK2, classical RK4, and kick–drift–kick leapfrog. The figures were generated separately; no RK implementation is supplied in the page or an accompanying notebook. Use the mathematics to construct your own methods, and use the observables to decide what your implementation needs to establish.

One oscillator, four diagnostics

Each method uses 100 steps per period for 20 periods. Before examining the figure, predict which method increases energy, which damps it, and whether bounded energy guarantees accurate phase. The inset enlarges the trajectories near the unit circle; Euler’s growth would otherwise hide their differences.

Euler, midpoint RK2, RK4, and leapfrog are compared over twenty oscillator periods using phase-plane trajectories with a magnified inset, energy error, unwrapped phase error, and state error.

Figure 4:At the same step length, the four methods differ in amplitude, phase, and state error. These are reference calculations for the stated linear oscillator, not a claim that one method wins for every equation or duration. The energy axis uses a symmetric logarithmic scale so small damping and large growth can both be seen. The inset resolves trajectories near the exact unit circle.

Open full-size figure

For this oscillator, the diagnostic definitions are

En=12(qn2+pn2),ϕn=unwrap⁡ ⁣(atan2⁡(−pn,qn)),E_n=\frac12(q_n^2+p_n^2),\qquad \phi_n=\operatorname{unwrap}\!\bigl(\operatorname{atan2}(-p_n,q_n)\bigr),
estate(tn)=∥(qn,pn)−(cos⁡tn,−sin⁡tn)∥2.e_{\rm state}(t_n)=\left\|(q_n,p_n)-(\cos t_n,-\sin t_n)\right\|_2.

The phase error is ϕn−tn\phi_n-t_n. Unwrapping chooses a continuous branch by removing 2π2\pi jumps; it requires sufficiently resolved phase advances. At this resolution, that assumption holds. A point close to the unit circle can still be at the wrong angle, so energy agreement alone is incomplete.

Tools for inspecting a trajectory

These diagnostics consume a trajectory; they do not construct RK stages. The next cell demonstrates them using a complete Euler calculation. The state has two dimensionless components; a physical state with mixed units would need specified component scales before taking a combined norm.

Euler maximum state error: 50.43601922172834
Euler final relative energy change: 2643.2399896798
Euler final phase error (rad): -0.16497620494871512

Apply the definitions to another trajectory only after checking its equations, initial condition, time units, and state ordering. The helper’s exact reference is specific to this SHO setup. A plausible output from a helper used on the wrong problem is not a validation.

MethodDerivative evaluations per stepWhat is counted?
Euler1Full oscillator right-hand side
Explicit midpoint RK22Full right-hand side
Classical RK44Full right-hand side
Leapfrog2 without reuseForce evaluations; retaining the final force can reduce later steps to 1 new call

Each trajectory has 2000 steps. A force evaluation and a full right-hand-side call need not have equal cost in an application. These counts are not timings. To compare efficiency, select the observable, duration, and error requirement first, then compare work needed to meet that same requirement. Formal order alone does not determine a universal crossover accuracy.

Why high order does not imply energy conservation

For the oscillator, put z=ihz=ih. The explicit RK stability function determines the energy factor per step. Euler gives ∣1+ih∣2=1+h2|1+ih|^2=1+h^2; explicit midpoint gives 1+h4/41+h^4/4; classical RK4 gives

∣R(ih)∣2=1−h672+h8576.|R(ih)|^2=1-\frac{h^6}{72}+\frac{h^8}{576}.

Thus RK4 damps this oscillator for 0<h<80<h<\sqrt8, while Euler and RK2 increase its energy. Neither the direction nor the size of a Kepler-orbit energy drift follows from this linear calculation. RK4 is globally fourth order and has an O(h5)O(h^5) one-step defect; those orders say how state error scales at fixed duration, not that a conserved quantity remains exact.

The explicit RK methods discussed here are not symplectic for general Hamiltonian systems. Some implicit RK methods are symplectic, so this is not a defect of every Runge–Kutta method. A measured energy drift, the Jacobian’s volume change, and the full symplectic condition are related diagnostics, but one does not substitute for the others.


Bridge to Part 3: The Need for Geometric Integration

The Runge–Kutta family improves finite-time state accuracy by evaluating the derivative at carefully chosen stages. For a short trajectory calculation, adaptive RK can be an excellent choice. For long autonomous Hamiltonian integrations, geometric preservation supplies a different source of control.

In Part 3, we will derive leapfrog and ask exactly what its geometry preserves. Second-order leapfrog does not automatically beat fourth-order RK4: the answer depends on the observable, duration, resolution, and cost. Energy can remain well behaved while orbital phase becomes inaccurate. The comparison experiment keeps these diagnostics separate so you can justify a method choice.

Next: Part 3 - Symplectic Integration