This site is version 0.0.1. Most of the code on this site is drafted by an agent and needs review. I apologize for the AI-speak, we are working on rewriting it!
viv-lang.org

← Posts

demoAINumerics

Crank-Nicolson is second order in time, backward Euler first

The heat equation from , stepped to with six time steps from 0.02 down to 0.000625. Each halving cuts the Crank-Nicolson error by a factor of 4.0 to 4.7 (measured order 2.09 to 2.23, then 2.000) and the backward Euler error by 1.9 to 2.0 (order 0.94 to 0.996). The errors are measured against the exact solution of the space-discretized equation, a discrete sine series. Against the exact Fourier series of the PDE, the Crank-Nicolson error stops falling at the space error, .

Look inside this program

  • Atlas

    The program’s map: every function and which calls which.

  • There’s no recorded run of this program yet.

The rod is with both ends held at . The PDE's solution is the Fourier sine series

since has sine coefficients for odd and zero for even , and each mode decays at its own rate .

The second derivative is replaced by the centered difference on 199 interior points, . The time steps are then the only error left to measure. The Python reference, posts/refs/crank-nicolson-is-second-order-in-time.py, steps the same equations with scipy's banded solver and computes the exact space-discretized solution with a matrix exponential (output beside it).

Two schemes, one family

Both schemes average the space difference between the old and the new time level, with weight on the new one:

is backward Euler; is Crank-Nicolson, which is the trapezoidal rule in time. The left side is a tridiagonal system, with on the diagonal and beside it, . The Thomas algorithm solves it in one sweep down and one back up.

Why the order differs: backward Euler evaluates the right side at the end of the step, which makes a local error of order per step and after the steps. The trapezoidal rule evaluates it at both ends, the first-order error terms of the two ends cancel, and what remains is per step and in total.

The exact answers

The error of a time-stepping scheme is measured against the exact solution of the equations it steps, , which differs from the PDE's solution by the space error. That solution is also a sine series. The grid vectors are eigenvectors of , with eigenvalues , , which tend to as . The second difference of a quadratic is exact, so at every grid point. Expanding the constant 2 in the eigenvectors then gives the coefficients of in closed form:

which tends to as . At the sum returns to rounding (tested below). The Python reference computes the same vector as with scipy's expm and agrees to .

Printed

2.498e-16
space_error: 1.94929e-06

Tests 2 of 2 pass

  • the discrete sine series returns u0 = x(1 - x) at t = 0, to rounding (passes)
  • the space error at t = 0.1 is 1.949e-6, as the Python reference finds (to 1e-13, the gap between its expm and this series) (passes)

Halving the time step

The cell runs both schemes at (5 to 160 steps) and takes the largest error over the grid at . The measured order between two runs is of the ratio of their errors.

Backward Euler's order climbs from 0.94 to 0.996, toward 1. Crank-Nicolson's is 2.14, 2.09, 2.11, 2.23 and then 2.000. The excess over 2 comes from the fast modes. For a mode with , Crank-Nicolson's factor per step, , is negative and close to , so the scheme barely damps a mode the equation kills at once. Backward Euler's factor goes to 0 instead. At that is every mode from up, and it adds 47% (fast_share) to the error of the slowest mode alone. As shrinks those modes have decayed before they matter; at the error is the slowest mode's to 1%, and its order is 2.000.

Against the PDE's own Fourier series the Crank-Nicolson error falls with the rest until it meets the space error, (the horizontal line). The two errors have opposite signs, so at they partly cancel and the total dips below both. After that the total is the space error. Refining further buys nothing unless is refined with it.

Printed

ERR_CN: [0.000455522, 0.000103197, 2.41873e-05, 5.59196e-06, 1.19167e-06, 2.97907e-07]
ERR_BE: [0.00860374, 0.00448327, 0.00228957, 0.00115708, 0.000581647, 0.000291606]
ERR_PDE: [0.000455338, 0.000103289, 2.42488e-05, 5.62272e-06, 7.57624e-07, 1.65138e-06]
ORDER_CN: [2.14212, 2.09307, 2.11282, 2.23037, 2.00005]
ORDER_BE: [0.940413, 0.969471, 0.984595, 0.992267, 0.996126]
RATIO_CN: [4.41412, 4.26656, 4.32537, 4.69255, 4.00013]
RATIO_BE: [1.91908, 1.95812, 1.97876, 1.98931, 1.99464]
fast_share: 0.471946
Error at t = 0.1 against the time step
backward Eulerslope 1Crank-Nicolsonslope 2Crank-Nicolson against the PDE series
10⁻⁶10⁻⁴10⁻²10⁻³10⁻²dtmax errorspace error 1.95e-6

Tests 7 of 7 pass

  • the errors are the Python reference's, to 1e-6 relative (its reference vector differs from this one by 7e-14) (passes)
  • Crank-Nicolson's measured order is between 2.0 and 2.25 at every halving, and 2.000 at the last (passes)
  • backward Euler's is between 0.94 and 1, rising to 0.996 (passes)
  • each halving cuts the Crank-Nicolson error by 4.0 to 4.7 and the backward Euler error by 1.9 to 2.0 (passes)
  • at dt = 0.02 the fast modes add 47% to the error of the slowest mode alone (passes)
  • the PDE series' terms past k = 21 are below 1e-190 at t = 0.1 (passes)
  • against the PDE's Fourier series the error stops at the space error, 1.95e-6 (passes)

Checked when the site was built: 9 of 9 tests passed, in 0.6 s. Download 2026-09-25-crank-nicolson-is-second-order-in-time.viv