V19 — Backward Euler vs Crank-Nicolson order study
Tier A+S - Analytic + Self-consistent
Tier A+S (analytic + solver-internal) - priority P1
Reference frozen on 2026-08-15. Nabla 0.1.0,
solver licence mode enforcing,
run in 126.8 s.
1. Problem
Nabla integrates every transient with the one-parameter theta scheme, and offers
two settings of it: Backward Euler (theta = 1) and Crank-Nicolson
(theta = 1/2, a Core Pro capability). The first is documented as first-order
accurate and the second as second-order. This chapter measures both claims, and
measures what the second one is worth.
Two problems, twenty-four solves.
rl_* |
a 200-turn coil on a linear (mu_r = 1000) closed core, fed from a 100 V step through 20 ohm, planar, no eddy currents |
slab_* |
1-D magnetic diffusion into a 10 mm half-slab of copper (sigma = 5.8e7), driven by a step current sheet across a 5 mm air gap |
| Levels | 16, 32, 64, 128, 256 steps over the same window - 16x in dt |
| Schemes | Backward Euler and Crank-Nicolson, each at every level |
| Extra | one 2048-step run of the slab, and one run per problem with Crank-Nicolson forced through its Rannacher startup on every step |
| Element order | P1 throughout - this is a study of time, and the element order is held fixed |

2. The trap this case is built around
A temporal order study is easy to run and easy to get wrong, and the way it goes
wrong is always the same: the reference carries a spatial error, the spatial
error does not shrink when dt does, the convergence curve flattens onto it, and
the fit reports the ruler rather than the scheme. A fit that reads 1.7 where it
should read 2 looks like a mild implementation defect and is usually not one.
So the two problems are chosen for two different relationships to that trap.
The circuit has no spatial error at all in the quantity it is judged on. For
a coil of any geometry on a linear core, the semi-discrete field-circuit system
is K A = C i with lambda = C^T A, so
lambda = (C^T K^-1 C) i = L i identically
L is a constant of the mesh, not an approximation to one, and the loop equation
is exactly L di/dt + R i = V. The whole spatial discretization sits inside one
number, which the case measures with a single static solve at 1 A on the same
mesh: L = 0.423693 H, tau = L/R = 0.0211846 s. The
exponential (V/R)(1 - e^(-t/tau)) is therefore the exact solution of the
discretized problem the transient is integrating - refine the mesh and the run
and its reference move together - and every deviation from it is time-integration
error and nothing else.
The slab is the opposite, deliberately. It is a real field problem, its spatial error is real, and this chapter measures it: at 2048 steps, where the temporal error is negligible, the flux density inside the slab sits 0.00124568 of the surface value away from the exact series. That is the floor, and §5 shows what it does to an order fit that does not know it is there.
3. Reference
Derived in full in the case's reference notes. Four things, and only the first two are about the schemes.
The orders. Expanding the theta scheme about t_(n+1/2) gives a local
truncation error O(dt^2) for theta != 1/2 and O(dt^3) at theta = 1/2,
hence global orders 1 and 2 (Butcher §3.2). Those integers are the
references; the tolerance is the +/-0.15 band the validation plan §3.4 fixes for
a fitted order.
Crank-Nicolson is A-stable but not L-stable, so the discontinuous initial
condition both problems have - a step response from a field-free state - excites
a (-1)^n mode that decays only algebraically (Hairer & Wanner §IV.3). The
remedy is Rannacher's: take the leading steps fully implicitly. One such step of
size dt costs O(dt^2) globally, which is second order and not below it. Nabla
does this by default (cnStartupSteps = 2), and the case measures the scheme as
shipped, startup included.
The drive on the slab is Ampere's law, exactly. The far edge of the model is
natural, so there is no field beyond the current sheet; a loop from there into the
air gap encloses the sheet and nothing else, whatever the slab is doing. So
B_surface = mu0 J w for all t > 0, independent of the response. Nabla reads
0.0628318 T against 0.0628319 T,
-0.000 %.
The response is Carslaw & Jaeger. With mu constant, B = -dA/dx obeys the
diffusion equation with alpha = 1/(mu sigma), so this is the slab quenched at
both faces (§3.4 eq. 6) - the same series V08 problem 5 already uses, shared as
one function rather than transcribed twice.

4. Two instrument checks, before any slope
The circuit really is that ODE. The same elimination that gives the
exponential gives the exact discrete solution of the theta scheme,
i_n = [i_(n-1)(L/dt - (1-theta)R) + V]/(L/dt + theta R). Nabla's Backward-Euler
run reproduces it to 7.45626e-13 of the steady-state
current, worst step of all five levels - and Crank-Nicolson reproduces its own
recurrence, Rannacher startup included, to
7.61702e-13. Both are round-off.
This row is not decoration. A coupling that carried an inductance the case did not know about - an end-winding term, a stray branch, a factor on the flux linkage - would shift the effective time constant and appear in the order fit only as a small, plausible, wrong number. It is checked first because after it there is nothing left in the circuit problem except the time integrator.
theta = 1 inside the Crank-Nicolson path is Backward Euler. The validation plan
asks for this invariant by name. It is reachable through the shipped API by asking
for more Rannacher startup steps than the run has, since theta_eff = 1 while
simStep < max(1, cnStartupSteps). Both problems return exactly zero
difference: 0 on the circuit and
0 on the field. Bit-identical, which matters
because the field path assembles a second, frozen matrix for Crank-Nicolson
(K_cn = K_stiff + M/(theta dt)) and is supposed to leave it unused at
theta_eff = 1.
5. Result
Every judged row passes. The four orders:
| Problem | Scheme | Reference | Fitted | Theory |
|---|---|---|---|---|
| circuit | Backward Euler | exact exponential | 0.959764 | 1 |
| circuit | Crank-Nicolson | exact exponential | 1.9637 | 2 |
| slab | Backward Euler | 2048-step run | 0.924403 | 1 |
| slab | Crank-Nicolson | 2048-step run | 2.09515 | 2 |
One feature of the figures needs saying, because it looks like a mistake and is
not: at the coarsest level the Crank-Nicolson error equals the Backward-Euler
error, on both problems. The error is a maximum over the shared time stations, and
at 16 steps the coarsest station is the single Rannacher startup step, which
both schemes take fully implicitly. From the second level on, that station is a
Crank-Nicolson step and the curves separate. The startup is the reason
Crank-Nicolson converges here at all - without it a trapezoidal rule meets a
discontinuous initial condition with a (-1)^n mode it cannot damp - and the
price it charges is exactly this one point.

And the trap, measured. The slab's orders above are fitted against the 2048-step run, because there the spatial error is identical in every run and cancels exactly in the difference. Fit the same five solutions against the exact series instead and Backward Euler is unmoved - 0.943266 against 0.924403 - while Crank-Nicolson reads 1.67998, and that number is published without a verdict because it is not about the time integrator at all.
The five-point fit understates how sharply it happens, because it averages the levels that were still converging with the ones that have stopped. The last interval alone is the honest statement, and it costs no extra run:
| Finest pair of levels (128 -> 256 steps) | vs the 2048-step run | vs the exact series |
|---|---|---|
| Backward Euler | 0.997557 | 1.0408 |
| Crank-Nicolson | 1.97001 | 0.0992163 |
Same two solutions in both columns. Halving the time step still buys Crank-Nicolson the full second order - and buys it nothing at all when the error is read against the exact PDE solution, because by then it is below the 0.00124568 spatial error of the mesh. Backward Euler, whose error at 256 steps is still an order of magnitude above that floor, does not notice which reference it is measured against.
This is the same warning V09 carries about a mesh convergence study: a convergence study that shows the wrong order may only have found its own ruler. Here it is not a warning, it is a row.
6. What second order is worth
An order is an asymptotic statement. The number a reader can use is the step size
it buys at a stated accuracy, so the case solves the fitted err = C dt^p at 1 %
error and reports it in units of each problem's own time constant.
| Problem | Backward Euler | Crank-Nicolson | Ratio |
|---|---|---|---|
circuit (dt/tau) |
0.0564884 | 0.176667 | 3.12749x |
slab (dt/t1) |
0.0066173 | 0.0312465 | 4.72194x |

Three things a user should take from that table.
- The advantage is a ratio, not a factor. It grows as the accuracy demanded tightens - at 10 % error the two schemes are much closer, and at 0.1 % much further apart. Quoting "Crank-Nicolson is twice as good" is meaningless without an accuracy attached.
- The two problems disagree, and are entitled to: a circuit is one mode and a
diffusion equation is a stiff spectrum, so the constant in front of
dt^pdiffers and the crossover moves with it. - Both schemes need a small step in absolute terms. 1 % on the diffusion problem costs 0.0312465 of a diffusion time constant even at second order. A second-order scheme is not permission to take a coarse step; it is permission to take a less fine one.
At the finest step of the study the accuracy delivered is 0.00355529 (BE) against 0.000130951 (CN) on the circuit, and 0.00857612 against 0.000320472 on the slab - a factor of 27 in both cases, from the same mesh, the same matrix and the same number of solves.
7. Limitations
- Linear, both problems. The theta scheme's order is a statement about the time discretization; a saturating core adds a Newton loop whose tolerance becomes part of the answer. Nothing here says what Crank-Nicolson does when the nonlinear residual is only driven to 1e-6.
- No motion. A sliding band rebuilds its constraints each step; whether the second order survives that is V20's question, not this one.
- P1 only. The element order is held fixed on purpose - mixing a spatial and a temporal refinement in one fit is how a study loses the ability to say which one it measured.
- The slab's spatial floor is this mesh's, not Nabla's. A finer mesh or P2 would push it down and let the exact series see further; the point of §5 is that a study has to know where its floor is, not that this one is low.
8. All quantities
| Quantity | Metric | Nabla | Reference | Error | Tolerance | Verdict |
|---|---|---|---|---|---|---|
rl_recurrence_be_max_abs |
abs | 7.45626e-13 - | 0 - | 7.456e-13 | 1e-07 | PASS |
rl_recurrence_cn_max_abs |
report | 7.61702e-13 - | - - | - | - | REPORT |
rl_order_be |
slope | 0.959764 - | 1 - | -0.0402 | +/-0.15 | PASS |
rl_order_cn |
slope | 1.9637 - | 2 - | -0.0363 | +/-0.15 | PASS |
rl_error_be_finest |
abs | 0.00355529 - | 0 - | 0.003555 | 0.01 | PASS |
rl_error_cn_finest |
abs | 0.000130951 - | 0 - | 0.000131 | 0.001 | PASS |
rl_theta1_vs_be_max_abs |
abs | 0 - | 0 - | 0 | 1e-12 | PASS |
rl_L_H |
report | 0.423693 H | - H | - | - | REPORT |
rl_tau_s |
report | 0.0211846 s | - s | - | - | REPORT |
rl_dt_over_tau_1pct_be |
report | 0.0564884 - | - - | - | - | REPORT |
rl_dt_over_tau_1pct_cn |
report | 0.176667 - | - - | - | - | REPORT |
rl_dt_ratio_cn_over_be |
report | 3.12749 - | - - | - | - | REPORT |
slab_surface_B_T |
rel | 0.0628318 T | 0.0628319 T | -0.000 % | 1.000 % | PASS |
slab_fine_vs_series_max_abs |
abs | 0.00124568 - | 0 - | 0.001246 | 0.01 | PASS |
slab_order_be |
slope | 0.924403 - | 1 - | -0.0756 | +/-0.15 | PASS |
slab_order_cn |
slope | 2.09515 - | 2 - | 0.0951 | +/-0.15 | PASS |
slab_order_be_vs_series |
slope | 0.943266 - | 1 - | -0.0567 | +/-0.15 | PASS |
slab_order_cn_vs_series |
report | 1.67998 - | - - | - | - | REPORT |
slab_last_order_cn |
report | 1.97001 - | - - | - | - | REPORT |
slab_last_order_cn_vs_series |
report | 0.0992163 - | - - | - | - | REPORT |
slab_last_order_be |
report | 0.997557 - | - - | - | - | REPORT |
slab_last_order_be_vs_series |
report | 1.0408 - | - - | - | - | REPORT |
slab_error_be_finest |
abs | 0.00857612 - | 0 - | 0.008576 | 0.02 | PASS |
slab_error_cn_finest |
abs | 0.000320472 - | 0 - | 0.0003205 | 0.001 | PASS |
slab_theta1_vs_be_max_abs |
abs | 0 - | 0 - | 0 | 1e-12 | PASS |
slab_dt_over_t1_1pct_be |
report | 0.0066173 - | - - | - | - | REPORT |
slab_dt_over_t1_1pct_cn |
report | 0.0312465 - | - - | - | - | REPORT |
slab_dt_ratio_cn_over_be |
report | 4.72194 - | - - | - | - | REPORT |
rl_dt_over_tau |
report | (series) | - | - | - | REPORT |
rl_dt_s |
report | (series) | - | - | - | REPORT |
rl_err_be |
report | (series) | - | - | - | REPORT |
rl_err_cn |
report | (series) | - | - | - | REPORT |
slab_dt_over_t1 |
report | (series) | - | - | - | REPORT |
slab_dt_s |
report | (series) | - | - | - | REPORT |
slab_err_be |
report | (series) | - | - | - | REPORT |
slab_err_be_vs_series |
report | (series) | - | - | - | REPORT |
slab_err_cn |
report | (series) | - | - | - | REPORT |
slab_err_cn_vs_series |
report | (series) | - | - | - | REPORT |
rl_recurrence_cn_max_abs: the same comparison for Crank-Nicolson, including the Rannacher startup steps; published without a verdict because the startup rule the reference assumes is read off the solver source rather than from a specificationrl_L_H: the finite-element inductance this mesh has, which is half of the ODE both the run and its reference obeyrl_tau_s: L/R, the circuit's only time scale and the unit every step size below is quoted inrl_dt_over_tau_1pct_be: the practical number: the largest step, in circuit time constants, at which Backward Euler holds 1 % errorrl_dt_over_tau_1pct_cn: the same for Crank-Nicolsonrl_dt_ratio_cn_over_be: how many times larger a step Crank-Nicolson buys at 1 % error on this problemslab_order_cn_vs_series: published without a verdict BY DECLARATION: this fit is expected to read well below 2, and the reason is the case's own spatial error rather than anything the time integrator didslab_last_order_cn: the order the FINEST pair of levels alone shows, against the 2048-step run - the reference in which the spatial error cancelsslab_last_order_cn_vs_series: the same finest pair, measured against the exact series instead - this is the number that shows the floor rather than describing itslab_last_order_be: the same finest-pair order for Backward Euler, against the 2048-step runslab_last_order_be_vs_series: the same, against the exact seriesslab_dt_over_t1_1pct_be: the largest step, in diffusion time constants, at which Backward Euler holds 1 % error on the field problemslab_dt_over_t1_1pct_cn: the same for Crank-Nicolsonslab_dt_ratio_cn_over_be: how many times larger a step Crank-Nicolson buys at 1 % error on the field problemrl_dt_over_tau: extracted but not frozen in expected.json - reported onlyrl_dt_s: extracted but not frozen in expected.json - reported onlyrl_err_be: extracted but not frozen in expected.json - reported onlyrl_err_cn: extracted but not frozen in expected.json - reported onlyslab_dt_over_t1: extracted but not frozen in expected.json - reported onlyslab_dt_s: extracted but not frozen in expected.json - reported onlyslab_err_be: extracted but not frozen in expected.json - reported onlyslab_err_be_vs_series: extracted but not frozen in expected.json - reported onlyslab_err_cn: extracted but not frozen in expected.json - reported onlyslab_err_cn_vs_series: extracted but not frozen in expected.json - reported only
Mesh, per sub-model:
| Sub-model | Element order | Nodes | Elements |
|---|---|---|---|
rl_static |
P1 | 1832 | 3554 |
rl_be_L0 |
P1 | 1832 | 3554 |
rl_be_L1 |
P1 | 1832 | 3554 |
rl_be_L2 |
P1 | 1832 | 3554 |
rl_be_L3 |
P1 | 1832 | 3554 |
rl_be_L4 |
P1 | 1832 | 3554 |
rl_cn_L0 |
P1 | 1832 | 3554 |
rl_cn_L1 |
P1 | 1832 | 3554 |
rl_cn_L2 |
P1 | 1832 | 3554 |
rl_cn_L3 |
P1 | 1832 | 3554 |
rl_cn_L4 |
P1 | 1832 | 3554 |
rl_theta1 |
P1 | 1832 | 3554 |
slab_fine |
P1 | 1263 | 2317 |
slab_be_L0 |
P1 | 1263 | 2317 |
slab_be_L1 |
P1 | 1263 | 2317 |
slab_be_L2 |
P1 | 1263 | 2317 |
slab_be_L3 |
P1 | 1263 | 2317 |
slab_be_L4 |
P1 | 1263 | 2317 |
slab_cn_L0 |
P1 | 1263 | 2317 |
slab_cn_L1 |
P1 | 1263 | 2317 |
slab_cn_L2 |
P1 | 1263 | 2317 |
slab_cn_L3 |
P1 | 1263 | 2317 |
slab_cn_L4 |
P1 | 1263 | 2317 |
slab_theta1 |
P1 | 1263 | 2317 |
9. Frozen-reference changelog
No entry: the reference values and tolerances are as first frozen.
10. Reproduce
cd validation
python -m harness.run_case V19
The twenty-four models are published beside this chapter in models/.