---
title: Solver convergence
summary: "The pseudo-transient Newton–Krylov solver reduces the residual by ten orders from a free stream; its terminal convergence is linear at the forcing rate of the inexact Newton iteration, and p-multigrid preconditioning cuts the Krylov iteration count compared with block Jacobi alone. What those iterations cost is measured and reported without a threshold: operator applications counted from the cycle, and the wall time of each solve repeated with compiled kernels."
section: verification
order: 5
level: 2
study: solver_convergence
studies: [line_smoother, line_smoother_3d, mixed_precision]
keywords: [Newton, Krylov, p-multigrid, convergence history, line smoother, wall-resolved mesh]
---
<!-- gyre docs: expanded Markdown of verification/solvers.md (generated tables, verification numbers and chart data are written out). Base level of this page: L2 Practice; passages at another level are bracketed by 'begin level N' / 'end level N' comments and start with [LN Name]. Built from revision ceb1f4b0be. -->

**Verification status: Nonlinear and linear solver convergence** (study `solver_convergence`): **PASSED**, 16 of 16 checks passed, 890.1 s.

Residual histories of the pseudo-transient Newton–Krylov solver from a uniform free stream, with element-block-Jacobi and with p-multigrid preconditioned FGMRES. The linear systems are solved to a fixed relative tolerance (inexact Newton), so once the pseudo-time step is large the residual is expected to fall by about that factor per step: linear convergence at the forcing rate, not quadratic convergence. The checks require a residual reduction of ten orders, a terminal contraction per step within a factor five of the forcing term (the signature of an exact Jacobian), and fewer than half the Krylov iterations with p-multigrid. What those iterations cost is measured and reported without a threshold: operator applications counted from the definition of the multigrid cycle, and the wall time of each solve repeated with compiled kernels.

| Check | Value | Expected | Result |
|---|---|---|---|
| Euler NACA 0012, p = 2, block Jacobi: converged 10 orders (final / reference residual) | 2.8557e-12 | <= 1e-10 | pass |
| Euler NACA 0012, p = 2, block Jacobi: terminal residual contraction per step (geometric mean) | 0.0109235 | <= 0.05 (5 x forcing term lin_tol = 0.01) | pass |
| Euler NACA 0012, p = 2, p-multigrid: converged 10 orders (final / reference residual) | 1.9270e-12 | <= 1e-10 | pass |
| Euler NACA 0012, p = 2, p-multigrid: terminal residual contraction per step (geometric mean) | 0.010203 | <= 0.05 (5 x forcing term lin_tol = 0.01) | pass |
| Euler NACA 0012, p = 2: Krylov iterations, p-MG / block Jacobi | 0.117745 | < 0.5 | pass |
| Laminar cylinder Re = 40, p = 2, block Jacobi: converged 10 orders (final / reference residual) | 1.5243e-12 | <= 1e-10 | pass |
| Laminar cylinder Re = 40, p = 2, block Jacobi: terminal residual contraction per step (geometric mean) | 0.00980497 | <= 0.05 (5 x forcing term lin_tol = 0.01) | pass |
| Laminar cylinder Re = 40, p = 2, p-multigrid: converged 10 orders (final / reference residual) | 8.2062e-11 | <= 1e-10 | pass |
| Laminar cylinder Re = 40, p = 2, p-multigrid: terminal residual contraction per step (geometric mean) | 0.0076328 | <= 0.05 (5 x forcing term lin_tol = 0.01) | pass |
| Laminar cylinder Re = 40, p = 2: Krylov iterations, p-MG / block Jacobi | 0.0837727 | < 0.5 | pass |
| Euler NACA 0012, p = 3, block Jacobi: converged 10 orders (final / reference residual) | 3.3017e-12 | <= 1e-10 | pass |
| Euler NACA 0012, p = 3, block Jacobi: terminal residual contraction per step (geometric mean) | 0.0117945 | <= 0.05 (5 x forcing term lin_tol = 0.01) | pass |
| Euler NACA 0012, p = 3, p-multigrid: converged 10 orders (final / reference residual) | 5.9042e-11 | <= 1e-10 | pass |
| Euler NACA 0012, p = 3, p-multigrid: terminal residual contraction per step (geometric mean) | 0.00582304 | <= 0.05 (5 x forcing term lin_tol = 0.01) | pass |
| Euler NACA 0012, p = 3: Krylov iterations, p-MG / block Jacobi | 0.113235 | < 0.5 | pass |
| cost of the two preconditioners measured: the repeated, compiled solves converged | yes | true | pass |

Run notes: Measured in this run: below 0.0001 of the reference residual the residual fell by a factor 5.8e-03 to 1.2e-02 per step (geometric means; worst single step 1.7e-02) with a forcing term of 0.01. p-multigrid needed 0.08 to 0.12 of the Krylov iterations of block Jacobi. That is a ratio of iteration counts, not of work: one multigrid-preconditioned iteration applies the operator several times (smoothing sweeps on every level). In fine-level operator applications the ratio was 0.63 to 0.89, and in wall time of the repeated solve, with every kernel compiled, 0.88 to 1.38 (below 1: p-multigrid cheaper). The wall times of the first solves in the effort table include one-off JIT compilation. Machine load while the study ran: The timings were taken on a busy machine (other processes used 51 % of the capacity of the 8 CPUs while the study ran).

Provenance: gyre 0.4.0; revision `39979fcf90` (commit `39979fcf902ad6116eb550b881b4278d4599c8e2`); 2026-11-12T10:42:49-0500; device cpu; quick suite. **Revision check: Same code as this build.** Produced by 39979fcf902ad6116eb550b881b4278d4599c8e2. Every commit between it and the commit this site was built from (ceb1f4b0bed41de53e586df10858079f5a2bcdd8) changes only documentation text, evidence records or bookkeeping: the code is the same. Full record: [solver_convergence.json](../data/verification/solver_convergence.json).

**Chart: Residual history** (Nonlinear and linear solver convergence). History chart of |Rw| against nonlinear iteration, y axis log; 6 series. The table holds the plotted data.

| series | nonlinear iteration | \|Rw\| |
|---|---|---|
| Euler NACA 0012, p = 2: block Jacobi | 0 | 0.366317 |
| Euler NACA 0012, p = 2: block Jacobi | 1 | 0.238266 |
| Euler NACA 0012, p = 2: block Jacobi | 2 | 0.153701 |
| Euler NACA 0012, p = 2: block Jacobi | 3 | 0.128176 |
| Euler NACA 0012, p = 2: block Jacobi | 4 | 0.107526 |
| Euler NACA 0012, p = 2: block Jacobi | 5 | 0.0911261 |
| Euler NACA 0012, p = 2: block Jacobi | 6 | 0.0708977 |
| Euler NACA 0012, p = 2: block Jacobi | 7 | 0.0507337 |
| Euler NACA 0012, p = 2: block Jacobi | 8 | 0.0305722 |
| Euler NACA 0012, p = 2: block Jacobi | 9 | 0.0140312 |
| Euler NACA 0012, p = 2: block Jacobi | 10 | 0.00539924 |
| Euler NACA 0012, p = 2: block Jacobi | 11 | 9.9688e-04 |
| Euler NACA 0012, p = 2: block Jacobi | 12 | 6.0154e-05 |
| Euler NACA 0012, p = 2: block Jacobi | 13 | 8.0257e-07 |
| Euler NACA 0012, p = 2: block Jacobi | 14 | 7.8549e-09 |
| Euler NACA 0012, p = 2: block Jacobi | 15 | 7.7948e-11 |
| Euler NACA 0012, p = 2: block Jacobi | 16 | 1.0461e-12 |
| Euler NACA 0012, p = 2: p-multigrid | 0 | 0.366317 |
| Euler NACA 0012, p = 2: p-multigrid | 1 | 0.238446 |
| Euler NACA 0012, p = 2: p-multigrid | 2 | 0.15374 |
| Euler NACA 0012, p = 2: p-multigrid | 3 | 0.127815 |
| Euler NACA 0012, p = 2: p-multigrid | 4 | 0.10725 |
| Euler NACA 0012, p = 2: p-multigrid | 5 | 0.0910524 |
| Euler NACA 0012, p = 2: p-multigrid | 6 | 0.0707134 |
| Euler NACA 0012, p = 2: p-multigrid | 7 | 0.0507297 |
| Euler NACA 0012, p = 2: p-multigrid | 8 | 0.0306123 |
| Euler NACA 0012, p = 2: p-multigrid | 9 | 0.0141012 |
| Euler NACA 0012, p = 2: p-multigrid | 10 | 0.00544363 |
| Euler NACA 0012, p = 2: p-multigrid | 11 | 0.00100033 |
| Euler NACA 0012, p = 2: p-multigrid | 12 | 6.0277e-05 |
| Euler NACA 0012, p = 2: p-multigrid | 13 | 6.6459e-07 |
| Euler NACA 0012, p = 2: p-multigrid | 14 | 6.4517e-09 |
| Euler NACA 0012, p = 2: p-multigrid | 15 | 4.5689e-11 |
| Euler NACA 0012, p = 2: p-multigrid | 16 | 7.0588e-13 |
| Laminar cylinder Re = 40, p = 2: block Jacobi | 0 | 20.2116 |
| Laminar cylinder Re = 40, p = 2: block Jacobi | 1 | 13.1423 |
| Laminar cylinder Re = 40, p = 2: block Jacobi | 2 | 9.47857 |
| Laminar cylinder Re = 40, p = 2: block Jacobi | 3 | 6.10869 |
| Laminar cylinder Re = 40, p = 2: block Jacobi | 4 | 4.09279 |
| Laminar cylinder Re = 40, p = 2: block Jacobi | 5 | 3.38947 |
| Laminar cylinder Re = 40, p = 2: block Jacobi | 6 | 1.97246 |
| Laminar cylinder Re = 40, p = 2: block Jacobi | 7 | 0.483745 |
| Laminar cylinder Re = 40, p = 2: block Jacobi | 8 | 0.141892 |
| Laminar cylinder Re = 40, p = 2: block Jacobi | 9 | 0.074575 |
| Laminar cylinder Re = 40, p = 2: block Jacobi | 10 | 0.0199166 |
| Laminar cylinder Re = 40, p = 2: block Jacobi | 11 | 0.0024487 |
| Laminar cylinder Re = 40, p = 2: block Jacobi | 12 | 3.2684e-05 |
| Laminar cylinder Re = 40, p = 2: block Jacobi | 13 | 3.2557e-07 |
| Laminar cylinder Re = 40, p = 2: block Jacobi | 14 | 3.2121e-09 |
| Laminar cylinder Re = 40, p = 2: block Jacobi | 15 | 3.0809e-11 |
| Laminar cylinder Re = 40, p = 2: p-multigrid | 0 | 20.2116 |
| Laminar cylinder Re = 40, p = 2: p-multigrid | 1 | 13.1323 |
| Laminar cylinder Re = 40, p = 2: p-multigrid | 2 | 9.44805 |
| Laminar cylinder Re = 40, p = 2: p-multigrid | 3 | 6.06778 |
| Laminar cylinder Re = 40, p = 2: p-multigrid | 4 | 4.06751 |
| Laminar cylinder Re = 40, p = 2: p-multigrid | 5 | 3.34489 |
| Laminar cylinder Re = 40, p = 2: p-multigrid | 6 | 1.94072 |
| Laminar cylinder Re = 40, p = 2: p-multigrid | 7 | 0.477141 |
| Laminar cylinder Re = 40, p = 2: p-multigrid | 8 | 0.141383 |
| Laminar cylinder Re = 40, p = 2: p-multigrid | 9 | 0.0735677 |
| Laminar cylinder Re = 40, p = 2: p-multigrid | 10 | 0.0196538 |
| Laminar cylinder Re = 40, p = 2: p-multigrid | 11 | 0.00245037 |
| Laminar cylinder Re = 40, p = 2: p-multigrid | 12 | 2.8469e-05 |
| Laminar cylinder Re = 40, p = 2: p-multigrid | 13 | 1.9200e-07 |
| Laminar cylinder Re = 40, p = 2: p-multigrid | 14 | 1.6586e-09 |
| Euler NACA 0012, p = 3: block Jacobi | 0 | 0.311716 |
| Euler NACA 0012, p = 3: block Jacobi | 1 | 0.313325 |
| Euler NACA 0012, p = 3: block Jacobi | 2 | 0.138704 |
| Euler NACA 0012, p = 3: block Jacobi | 3 | 0.0970839 |
| Euler NACA 0012, p = 3: block Jacobi | 4 | 0.074958 |
| Euler NACA 0012, p = 3: block Jacobi | 5 | 0.0617388 |
| Euler NACA 0012, p = 3: block Jacobi | 6 | 0.0472716 |
| Euler NACA 0012, p = 3: block Jacobi | 7 | 0.0336438 |
| Euler NACA 0012, p = 3: block Jacobi | 8 | 0.0197131 |
| Euler NACA 0012, p = 3: block Jacobi | 9 | 0.0086172 |
| Euler NACA 0012, p = 3: block Jacobi | 10 | 0.00352864 |
| Euler NACA 0012, p = 3: block Jacobi | 11 | 6.8180e-04 |
| Euler NACA 0012, p = 3: block Jacobi | 12 | 4.6864e-05 |
| Euler NACA 0012, p = 3: block Jacobi | 13 | 6.2728e-07 |
| Euler NACA 0012, p = 3: block Jacobi | 14 | 6.1512e-09 |
| Euler NACA 0012, p = 3: block Jacobi | 15 | 6.0011e-11 |
| Euler NACA 0012, p = 3: block Jacobi | 16 | 1.0292e-12 |
| Euler NACA 0012, p = 3: p-multigrid | 0 | 0.311716 |
| Euler NACA 0012, p = 3: p-multigrid | 1 | 0.313727 |
| Euler NACA 0012, p = 3: p-multigrid | 2 | 0.13878 |
| Euler NACA 0012, p = 3: p-multigrid | 3 | 0.0967875 |
| Euler NACA 0012, p = 3: p-multigrid | 4 | 0.074779 |
| Euler NACA 0012, p = 3: p-multigrid | 5 | 0.0616541 |
| Euler NACA 0012, p = 3: p-multigrid | 6 | 0.0471596 |
| Euler NACA 0012, p = 3: p-multigrid | 7 | 0.0336347 |
| Euler NACA 0012, p = 3: p-multigrid | 8 | 0.0197123 |
| Euler NACA 0012, p = 3: p-multigrid | 9 | 0.00862647 |
| Euler NACA 0012, p = 3: p-multigrid | 10 | 0.00352607 |
| Euler NACA 0012, p = 3: p-multigrid | 11 | 6.7471e-04 |
| Euler NACA 0012, p = 3: p-multigrid | 12 | 4.6216e-05 |
| Euler NACA 0012, p = 3: p-multigrid | 13 | 5.4278e-07 |
| Euler NACA 0012, p = 3: p-multigrid | 14 | 3.3127e-09 |
| Euler NACA 0012, p = 3: p-multigrid | 15 | 1.8404e-11 |

Provenance: gyre 0.4.0; revision `39979fcf90` (commit `39979fcf902ad6116eb550b881b4278d4599c8e2`); 2026-11-12T10:42:49-0500; device cpu; quick suite. **Revision check: Same code as this build.** Produced by 39979fcf902ad6116eb550b881b4278d4599c8e2. Every commit between it and the commit this site was built from (ceb1f4b0bed41de53e586df10858079f5a2bcdd8) changes only documentation text, evidence records or bookkeeping: the code is the same. Full record: [solver_convergence.json](../data/verification/solver_convergence.json).

<!-- begin level 2 (Practice) -->
**[L2 Practice] Reading the histories**

From a uniform free stream the residual first falls slowly while the pseudo-time step ramps up,
then drops by a roughly constant factor per step. The linear systems are solved to a fixed
relative tolerance, `lin_tol` = $10^{-2}$ (inexact Newton with a fixed forcing term), so the
terminal convergence is linear at the forcing rate, about two orders per step, not quadratic.
The study checks three things per configuration: a residual reduction of ten orders relative
to the reference residual, a terminal contraction per step (geometric mean) of at most
$5 \times$ `lin_tol`, and fewer than half the Krylov iterations with p-multigrid. A contraction
near the forcing term is the signature of an exact Jacobian; a wrong Jacobian gives a
contraction of order one. Both preconditioners solve the same Newton systems — they differ in
how much linear work each step costs.

<!-- end level 2 -->

**Table: Solver effort** (Nonlinear and linear solver convergence)

| case | preconditioner | levels | Newton steps | Krylov iterations | max Krylov / step | converged | final / reference residual | terminal contraction (mean) | terminal contraction (worst step) | wall time [s] |
|---|---|---|---|---|---|---|---|---|---|---|
| Euler NACA 0012, p = 2 | block Jacobi | 2 | 16 | 1206 | 182 | yes | 2.8557e-12 | 0.0109235 | 0.0134203 | 58.5489 |
| Euler NACA 0012, p = 2 | p-multigrid | 2, 1, 0 | 16 | 142 | 17 | yes | 1.9270e-12 | 0.010203 | 0.0154498 | 104.262 |
| Laminar cylinder Re = 40, p = 2 | block Jacobi | 2 | 15 | 1707 | 320 | yes | 1.5243e-12 | 0.00980497 | 0.00996111 | 48.199 |
| Laminar cylinder Re = 40, p = 2 | p-multigrid | 2, 1, 0 | 14 | 143 | 19 | yes | 8.2062e-11 | 0.0076328 | 0.00863853 | 73.4588 |
| Euler NACA 0012, p = 3 | block Jacobi | 3 | 16 | 1360 | 202 | yes | 3.3017e-12 | 0.0117945 | 0.0171502 | 74.6616 |
| Euler NACA 0012, p = 3 | p-multigrid | 3, 1, 0 | 15 | 154 | 23 | yes | 5.9042e-11 | 0.00582304 | 0.00610324 | 79.4693 |

Provenance: gyre 0.4.0; revision `39979fcf90` (commit `39979fcf902ad6116eb550b881b4278d4599c8e2`); 2026-11-12T10:42:49-0500; device cpu; quick suite. **Revision check: Same code as this build.** Produced by 39979fcf902ad6116eb550b881b4278d4599c8e2. Every commit between it and the commit this site was built from (ceb1f4b0bed41de53e586df10858079f5a2bcdd8) changes only documentation text, evidence records or bookkeeping: the code is the same. Full record: [solver_convergence.json](../data/verification/solver_convergence.json).

<!-- begin level 3 (Mechanics) -->
**[L3 Mechanics] Linear work**

Block Jacobi damps element-local error only, so GMRES needs many iterations (and restarts) once
the pseudo-time step is large. The p-multigrid V-cycle adds coarse levels down to a
finite-volume discretization at $p = 0$ and reduces the Krylov iteration count; the check
requires less than half. That is a ratio of iteration counts, not of work: one
multigrid-preconditioned iteration applies the operator several times (smoothing sweeps on
every level). The wall times in the table include one-off JIT compilation, which is larger for
the multigrid hierarchy. The table also lists the final residual relative to the reference
and the terminal contraction, as the mean and for the worst step.

<!-- end level 3 -->

## What the iterations cost

**Table: What the Krylov iterations cost** (Nonlinear and linear solver convergence)

| case | preconditioner | Krylov iterations | fine-level operator applications per Krylov iteration | fine-level operator applications, total | block solves per iteration | wall time, first solve [s] | wall time, repeated solve (compiled) [s] | repeated solve converged | Krylov iterations, repeated solve |
|---|---|---|---|---|---|---|---|---|---|
| Euler NACA 0012, p = 2 | block Jacobi | 1206 | 1 | 1206 | 1 | 58.5489 | 81.5204 | yes | 1206 |
| Euler NACA 0012, p = 2 | p-multigrid | 142 | 7.55556 | 1072.89 | 16 | 104.262 | 71.3936 | yes | 142 |
| Euler NACA 0012, p = 2 | p-MG / block Jacobi | 0.117745 | — | 0.889626 | — | — | 0.875776 | — | — |
| Laminar cylinder Re = 40, p = 2 | block Jacobi | 1707 | 1 | 1707 | 1 | 48.199 | 64.3311 | yes | 1707 |
| Laminar cylinder Re = 40, p = 2 | p-multigrid | 143 | 7.55556 | 1080.44 | 16 | 73.4588 | 60.265 | yes | 143 |
| Laminar cylinder Re = 40, p = 2 | p-MG / block Jacobi | 0.0837727 | — | 0.632949 | — | — | 0.936793 | — | — |
| Euler NACA 0012, p = 3 | block Jacobi | 1360 | 1 | 1360 | 1 | 74.6616 | 71.866 | yes | 1360 |
| Euler NACA 0012, p = 3 | p-multigrid | 154 | 6.4375 | 991.375 | 16 | 79.4693 | 99.4675 | yes | 154 |
| Euler NACA 0012, p = 3 | p-MG / block Jacobi | 0.113235 | — | 0.728952 | — | — | 1.38407 | — | — |

Provenance: gyre 0.4.0; revision `39979fcf90` (commit `39979fcf902ad6116eb550b881b4278d4599c8e2`); 2026-11-12T10:42:49-0500; device cpu; quick suite. **Revision check: Same code as this build.** Produced by 39979fcf902ad6116eb550b881b4278d4599c8e2. Every commit between it and the commit this site was built from (ceb1f4b0bed41de53e586df10858079f5a2bcdd8) changes only documentation text, evidence records or bookkeeping: the code is the same. Full record: [solver_convergence.json](../data/verification/solver_convergence.json).

<!-- begin level 2 (Practice) -->
**[L2 Practice] Reading the cost table**

Fewer Krylov iterations are not yet less work: one multigrid-preconditioned iteration
applies the operator several times. The table therefore gives two measures per solve.

* **Fine-level operator applications.** Counted from the definition of the cycle: the Krylov
  product, the smoothing sweeps and the residual of every level, with coarse levels weighted
  by their share of the unknowns (`Hierarchy.cycle_work`). With the default sweeps (2 before,
  2 after, 8 on the coarsest level) and the levels 2, 1, 0 in two dimensions, one iteration
  costs about 7.6 applications where block Jacobi costs one, so the hierarchy has to cut the
  iteration count by more than that factor before it saves operator work. The weighting
  overstates the coarse levels and leaves out block solves and transfers: it is a unit for
  comparing the two preconditioners, not a time.
* **Wall time of the repeated solve.** Each solve is run a second time from the free stream
  when every kernel is compiled, which removes the one-off compilation that dominates the
  first solve and is larger for the hierarchy.

The rows "p-MG / block Jacobi" give the ratios; a value below one means p-multigrid was
cheaper in that measure. The study reports them without a threshold.

<!-- end level 2 -->

> **Warning: What these numbers do and do not show**
>
> **No evidence here says p-multigrid is cheaper in general.** The ratios are measurements on
> three small two-dimensional cases at $p = 2$ and $p = 3$, on one machine, whose load during
> the run is stated in the note of the record; the wall times of small solves carry that load.
> The first-solve times in the effort table include JIT compilation. Where block Jacobi alone
> does not converge, the question of cost does not arise: on the wall-resolved mesh of the
> turbulent flat plate the coarse level is what makes the linear solves reach their tolerance
> ([turbulence closure](turbulence.md#adjoint-derivatives)).

## Line smoothing on a wall-resolved mesh

**Verification status: Line-implicit smoothing on a wall-resolved mesh** (study `line_smoother`): **PASSED**, 7 of 7 checks passed, 2160 s.

The turbulent flat plate of the preset flat_plate_sa (Spalart-Allmaras, first cell 5e-5 high) solved with element-block Jacobi and with line Jacobi as the smoother, each on the p-multigrid levels 2-1-0 and on one level, and once more with line Jacobi whose blocks are assembled every second nonlinear step only. Line Jacobi inverts the block-tridiagonal system of every line of strongly coupled elements; the lines follow the thin direction of the cells and are found from the mesh. At the converged flow one forward and one transposed system with the same right-hand side are solved to a relative tolerance of 1e-10. The checks require that the answer does not depend on the preconditioner (drag coefficient, adjoint derivatives), that line Jacobi needs fewer than half the Krylov iterations of block Jacobi on three levels, and that it reaches the tolerance on one level. What block Jacobi does on one level is reported without a threshold, and so are all wall times.

| Check | Value | Expected | Result |
|---|---|---|---|
| flow solves converged with block Jacobi on three levels, with line Jacobi on three levels and on one, and with line Jacobi whose blocks are assembled every second step | yes | true | pass |
| lines found on the wall-resolved mesh (elements in lines) | 131 | > 0 | pass |
| drag coefficient does not depend on the preconditioner (largest relative difference) | 2.0627e-09 | < 1e-6 | pass |
| forward solve to 1e-10, three levels, both smoothers reaching the tolerance: Krylov iterations, line Jacobi / block Jacobi | 0.277311 | < 0.5 | pass |
| transposed (adjoint) solve to 1e-10, three levels, both smoothers reaching the tolerance: Krylov iterations, line Jacobi / block Jacobi | 0.283401 | < 0.5 | pass |
| one level, line Jacobi: forward and transposed solves reach the tolerance | yes | true | pass |
| adjoint derivatives of the drag (Mach, Reynolds, free-stream turbulence) from transposed solves that reached 1e-10: largest relative difference between the two smoothers | 3.1572e-09 | < 1e-6 | pass |

Run notes: The mesh has 18 lines holding 131 of its 150 elements (the longest 12 elements, 3 colours). On three levels the transposed solve took 70 Krylov iterations with line Jacobi against 247 with block Jacobi (ratio 0.28; wall time of the compiled solve, ratio 0.67); the forward solve 66 against 238. One assembly of the preconditioner on three levels took 4.04 s with line Jacobi against 0.19 s with block Jacobi (the coupling blocks of the line elements are assembled as well, one batch of derivatives per colour). With one level and a tolerance of 1e-10 on the transposed system, block Jacobi reduced the residual by 2.9e-04 in 720 iterations and stopped at the iteration limit; line Jacobi reached the tolerance in 465 iterations. A flow solve assembles the preconditioner at every nonlinear step; the last row of the flow table assembles it every second step only (the repeated solves took 33.1 s (block Jacobi, levels 2-1-0), 233.6 s (line Jacobi, levels 2-1-0), 113.3 s (block Jacobi, one level), 392.5 s (line Jacobi, one level), 147.9 s (line Jacobi, levels 2-1-0, blocks every 2nd step)). Wall times: the column of the linear table is the Krylov solve alone, with a preconditioner that is already assembled; one assembly is timed separately (table 'assembly'). The first flow solve of a configuration includes the one-off compilation. The suite runs its studies in parallel lanes, so other studies were running while these times were taken; they are measurements of small cases on a machine that was not idle, reported without a threshold. Machine load while the study ran: The timings were taken on a busy machine (other processes used 45 % of the capacity of the 8 CPUs while the study ran).

Provenance: gyre 0.4.0; revision `39979fcf90` (commit `39979fcf902ad6116eb550b881b4278d4599c8e2`); 2026-11-12T10:58:43-0500; device cpu; quick suite. **Revision check: Same code as this build.** Produced by 39979fcf902ad6116eb550b881b4278d4599c8e2. Every commit between it and the commit this site was built from (ceb1f4b0bed41de53e586df10858079f5a2bcdd8) changes only documentation text, evidence records or bookkeeping: the code is the same. Full record: [line_smoother.json](../data/verification/line_smoother.json).

**Table: Linear solves at the converged flow (tolerance 1e-10)** (Line-implicit smoothing on a wall-resolved mesh)

| preconditioner | system | Krylov iterations | residual reduction | tolerance reached | wall time of the Krylov solve, compiled, preconditioner assembled before [s] |
|---|---|---|---|---|---|
| block Jacobi, levels 2-1-0 | forward | 238 | 8.9804e-11 | yes | 6.18439 |
| block Jacobi, levels 2-1-0 | transposed (adjoint) | 247 | 9.4097e-11 | yes | 10.9862 |
| line Jacobi, levels 2-1-0 | forward | 66 | 9.5595e-11 | yes | 4.98718 |
| line Jacobi, levels 2-1-0 | transposed (adjoint) | 70 | 9.4827e-11 | yes | 7.34169 |
| block Jacobi, one level | forward | 720 | 1.1248e-04 | no | 4.00668 |
| block Jacobi, one level | transposed (adjoint) | 720 | 2.8702e-04 | no | 12.8319 |
| line Jacobi, one level | forward | 441 | 9.9505e-11 | yes | 5.62206 |
| line Jacobi, one level | transposed (adjoint) | 465 | 8.7870e-11 | yes | 5.46822 |

Provenance: gyre 0.4.0; revision `39979fcf90` (commit `39979fcf902ad6116eb550b881b4278d4599c8e2`); 2026-11-12T10:58:43-0500; device cpu; quick suite. **Revision check: Same code as this build.** Produced by 39979fcf902ad6116eb550b881b4278d4599c8e2. Every commit between it and the commit this site was built from (ceb1f4b0bed41de53e586df10858079f5a2bcdd8) changes only documentation text, evidence records or bookkeeping: the code is the same. Full record: [line_smoother.json](../data/verification/line_smoother.json).

<!-- begin level 2 (Practice) -->
**[L2 Practice] What is compared**

The turbulent flat plate of the preset `flat_plate_sa`: 150 elements of degree 2, the first
row $5\times10^{-5}$ high, so the cells at the wall are between 400 and about 10 600 times
longer than they are thick. The flow is converged with block Jacobi and with
[line Jacobi](../theory/implicit-solver.md#preconditioning-without-assembling-a-matrix) as the
smoother, each on the p-multigrid levels 2, 1, 0 and on one level, and once more with line
Jacobi whose blocks are assembled every second step (`solver.precond_lag: 2`). At the
converged flow one
forward and one transposed system with the same right-hand side are then solved to a
relative tolerance of $10^{-10}$, which is what a direct sensitivity and an adjoint ask for.

The checks require that the answer does not depend on the preconditioner (drag coefficient
and three adjoint derivatives agree to $10^{-6}$ relative), that line Jacobi needs fewer than
half the Krylov iterations of block Jacobi on three levels, and that it reaches the
tolerance on one level. What block Jacobi does on one level is reported as it comes out:
it is the stalled solve that made
[a missed tolerance an error](../engineering/design-decisions.md).

<!-- end level 2 -->

**Table: Lines of the mesh** (Line-implicit smoothing on a wall-resolved mesh)

| lines | elements in lines | elements | longest line | colours | stored line slots |
|---|---|---|---|---|---|
| 18 | 131 | 150 | 12 | 3 | 152 |

Provenance: gyre 0.4.0; revision `39979fcf90` (commit `39979fcf902ad6116eb550b881b4278d4599c8e2`); 2026-11-12T10:58:43-0500; device cpu; quick suite. **Revision check: Same code as this build.** Produced by 39979fcf902ad6116eb550b881b4278d4599c8e2. Every commit between it and the commit this site was built from (ceb1f4b0bed41de53e586df10858079f5a2bcdd8) changes only documentation text, evidence records or bookkeeping: the code is the same. Full record: [line_smoother.json](../data/verification/line_smoother.json).

**Chart: Flow solve: residual against accumulated Krylov iterations** (Line-implicit smoothing on a wall-resolved mesh). History chart of |Rw| against Krylov iterations (accumulated over the Newton steps), y axis log; 5 series. The table holds the plotted data.

| series | Krylov iterations (accumulated over the Newton steps) | \|Rw\| |
|---|---|---|
| block Jacobi, levels 2-1-0 | 0 | 0.124629 |
| block Jacobi, levels 2-1-0 | 2 | 0.779736 |
| block Jacobi, levels 2-1-0 | 3 | 0.425046 |
| block Jacobi, levels 2-1-0 | 4 | 0.0608727 |
| block Jacobi, levels 2-1-0 | 6 | 0.0723028 |
| block Jacobi, levels 2-1-0 | 8 | 0.0489039 |
| block Jacobi, levels 2-1-0 | 10 | 0.0260923 |
| block Jacobi, levels 2-1-0 | 13 | 0.0125064 |
| block Jacobi, levels 2-1-0 | 18 | 0.00622628 |
| block Jacobi, levels 2-1-0 | 24 | 0.00437145 |
| block Jacobi, levels 2-1-0 | 29 | 0.00336179 |
| block Jacobi, levels 2-1-0 | 36 | 0.0029906 |
| block Jacobi, levels 2-1-0 | 44 | 0.00305075 |
| block Jacobi, levels 2-1-0 | 53 | 0.00231764 |
| block Jacobi, levels 2-1-0 | 65 | 0.00194994 |
| block Jacobi, levels 2-1-0 | 82 | 0.00157952 |
| block Jacobi, levels 2-1-0 | 99 | 0.00119617 |
| block Jacobi, levels 2-1-0 | 116 | 0.00110279 |
| block Jacobi, levels 2-1-0 | 136 | 0.00103203 |
| block Jacobi, levels 2-1-0 | 156 | 0.00116786 |
| block Jacobi, levels 2-1-0 | 176 | 0.0013458 |
| block Jacobi, levels 2-1-0 | 196 | 0.00156744 |
| block Jacobi, levels 2-1-0 | 215 | 0.00225501 |
| block Jacobi, levels 2-1-0 | 234 | 0.0019883 |
| block Jacobi, levels 2-1-0 | 253 | 0.00208346 |
| block Jacobi, levels 2-1-0 | 271 | 0.00171712 |
| block Jacobi, levels 2-1-0 | 290 | 0.0019675 |
| block Jacobi, levels 2-1-0 | 308 | 0.00130682 |
| block Jacobi, levels 2-1-0 | 327 | 6.4408e-04 |
| block Jacobi, levels 2-1-0 | 347 | 2.3862e-04 |
| block Jacobi, levels 2-1-0 | 368 | 3.7507e-05 |
| block Jacobi, levels 2-1-0 | 396 | 1.5333e-06 |
| block Jacobi, levels 2-1-0 | 439 | 2.6696e-08 |
| block Jacobi, levels 2-1-0 | 485 | 3.2411e-10 |
| block Jacobi, levels 2-1-0 | 540 | 2.8753e-12 |
| line Jacobi, levels 2-1-0 | 0 | 0.124629 |
| line Jacobi, levels 2-1-0 | 2 | 0.779735 |
| line Jacobi, levels 2-1-0 | 3 | 0.424873 |
| line Jacobi, levels 2-1-0 | 4 | 0.0608065 |
| line Jacobi, levels 2-1-0 | 6 | 0.0722699 |
| line Jacobi, levels 2-1-0 | 8 | 0.0488743 |
| line Jacobi, levels 2-1-0 | 10 | 0.0260662 |
| line Jacobi, levels 2-1-0 | 12 | 0.0124835 |
| line Jacobi, levels 2-1-0 | 15 | 0.00622118 |
| line Jacobi, levels 2-1-0 | 18 | 0.00437353 |
| line Jacobi, levels 2-1-0 | 20 | 0.00336289 |
| line Jacobi, levels 2-1-0 | 22 | 0.0029882 |
| line Jacobi, levels 2-1-0 | 25 | 0.00305218 |
| line Jacobi, levels 2-1-0 | 28 | 0.002317 |
| line Jacobi, levels 2-1-0 | 33 | 0.00195713 |
| line Jacobi, levels 2-1-0 | 41 | 0.00158011 |
| line Jacobi, levels 2-1-0 | 50 | 0.00119808 |
| line Jacobi, levels 2-1-0 | 60 | 0.00110831 |
| line Jacobi, levels 2-1-0 | 71 | 0.00103444 |
| line Jacobi, levels 2-1-0 | 82 | 0.00117389 |
| line Jacobi, levels 2-1-0 | 93 | 0.0013467 |
| line Jacobi, levels 2-1-0 | 104 | 0.00156734 |
| line Jacobi, levels 2-1-0 | 115 | 0.00225191 |
| line Jacobi, levels 2-1-0 | 126 | 0.0019863 |
| line Jacobi, levels 2-1-0 | 137 | 0.00207889 |
| line Jacobi, levels 2-1-0 | 147 | 0.00171564 |
| line Jacobi, levels 2-1-0 | 157 | 0.00197754 |
| line Jacobi, levels 2-1-0 | 167 | 0.00131292 |
| line Jacobi, levels 2-1-0 | 177 | 6.4372e-04 |
| line Jacobi, levels 2-1-0 | 188 | 2.3866e-04 |
| line Jacobi, levels 2-1-0 | 200 | 3.7004e-05 |
| line Jacobi, levels 2-1-0 | 212 | 1.4892e-06 |
| line Jacobi, levels 2-1-0 | 227 | 2.4781e-08 |
| line Jacobi, levels 2-1-0 | 247 | 2.6187e-10 |
| line Jacobi, levels 2-1-0 | 267 | 1.9058e-12 |
| block Jacobi, one level | 0 | 0.124629 |
| block Jacobi, one level | 2 | 0.780012 |
| block Jacobi, one level | 4 | 0.424791 |
| block Jacobi, one level | 7 | 0.0607134 |
| block Jacobi, one level | 16 | 0.0724354 |
| block Jacobi, one level | 26 | 0.0488405 |
| block Jacobi, one level | 41 | 0.0261245 |
| block Jacobi, one level | 64 | 0.0125151 |
| block Jacobi, one level | 99 | 0.00623836 |
| block Jacobi, one level | 139 | 0.0043708 |
| block Jacobi, one level | 176 | 0.00335876 |
| block Jacobi, one level | 220 | 0.00298865 |
| block Jacobi, one level | 275 | 0.00304844 |
| block Jacobi, one level | 333 | 0.00232512 |
| block Jacobi, one level | 402 | 0.00221679 |
| block Jacobi, one level | 498 | 0.0015586 |
| block Jacobi, one level | 618 | 0.00124381 |
| block Jacobi, one level | 738 | 0.00110093 |
| block Jacobi, one level | 858 | 0.00105029 |
| block Jacobi, one level | 978 | 0.00118134 |
| block Jacobi, one level | 1098 | 0.00134457 |
| block Jacobi, one level | 1218 | 0.00159304 |
| block Jacobi, one level | 1338 | 0.00228624 |
| block Jacobi, one level | 1458 | 0.002025 |
| block Jacobi, one level | 1578 | 0.00214107 |
| block Jacobi, one level | 1698 | 0.00175348 |
| block Jacobi, one level | 1818 | 0.00201657 |
| block Jacobi, one level | 1938 | 0.00133557 |
| block Jacobi, one level | 2058 | 6.4230e-04 |
| block Jacobi, one level | 2178 | 2.2451e-04 |
| block Jacobi, one level | 2298 | 3.0249e-05 |
| block Jacobi, one level | 2418 | 3.1724e-06 |
| block Jacobi, one level | 2538 | 7.8332e-07 |
| block Jacobi, one level | 2658 | 2.8510e-07 |
| block Jacobi, one level | 2778 | 9.9788e-08 |
| block Jacobi, one level | 2898 | 3.3119e-08 |
| block Jacobi, one level | 3018 | 9.3015e-09 |
| block Jacobi, one level | 3138 | 2.4657e-09 |
| block Jacobi, one level | 3258 | 6.7185e-10 |
| block Jacobi, one level | 3378 | 1.7882e-10 |
| block Jacobi, one level | 3498 | 4.2462e-11 |
| line Jacobi, one level | 0 | 0.124629 |
| line Jacobi, one level | 1 | 0.779734 |
| line Jacobi, one level | 2 | 0.423598 |
| line Jacobi, one level | 3 | 0.06012 |
| line Jacobi, one level | 7 | 0.0722277 |
| line Jacobi, one level | 12 | 0.0487814 |
| line Jacobi, one level | 18 | 0.025992 |
| line Jacobi, one level | 28 | 0.0124417 |
| line Jacobi, one level | 45 | 0.00620997 |
| line Jacobi, one level | 64 | 0.0043681 |
| line Jacobi, one level | 81 | 0.00335982 |
| line Jacobi, one level | 97 | 0.00298978 |
| line Jacobi, one level | 119 | 0.00305384 |
| line Jacobi, one level | 143 | 0.00230572 |
| line Jacobi, one level | 173 | 0.00182937 |
| line Jacobi, one level | 223 | 0.00148708 |
| line Jacobi, one level | 281 | 0.00144857 |
| line Jacobi, one level | 350 | 0.0012345 |
| line Jacobi, one level | 426 | 0.00108126 |
| line Jacobi, one level | 505 | 0.00113056 |
| line Jacobi, one level | 586 | 0.00125355 |
| line Jacobi, one level | 669 | 0.00149991 |
| line Jacobi, one level | 751 | 0.00220627 |
| line Jacobi, one level | 836 | 0.00207811 |
| line Jacobi, one level | 921 | 0.00206307 |
| line Jacobi, one level | 1004 | 0.00166118 |
| line Jacobi, one level | 1089 | 0.00183783 |
| line Jacobi, one level | 1175 | 0.00122033 |
| line Jacobi, one level | 1265 | 6.0889e-04 |
| line Jacobi, one level | 1361 | 2.2528e-04 |
| line Jacobi, one level | 1460 | 3.5600e-05 |
| line Jacobi, one level | 1563 | 1.4746e-06 |
| line Jacobi, one level | 1681 | 2.4610e-08 |
| line Jacobi, one level | 1801 | 6.0836e-10 |
| line Jacobi, one level | 1914 | 5.9566e-12 |
| line Jacobi, levels 2-1-0, blocks every 2nd step | 0 | 0.124629 |
| line Jacobi, levels 2-1-0, blocks every 2nd step | 2 | 0.779735 |
| line Jacobi, levels 2-1-0, blocks every 2nd step | 4 | 0.42343 |
| line Jacobi, levels 2-1-0, blocks every 2nd step | 5 | 0.0604124 |
| line Jacobi, levels 2-1-0, blocks every 2nd step | 8 | 0.0723523 |
| line Jacobi, levels 2-1-0, blocks every 2nd step | 10 | 0.0487729 |
| line Jacobi, levels 2-1-0, blocks every 2nd step | 12 | 0.0259908 |
| line Jacobi, levels 2-1-0, blocks every 2nd step | 14 | 0.0124298 |
| line Jacobi, levels 2-1-0, blocks every 2nd step | 17 | 0.00619779 |
| line Jacobi, levels 2-1-0, blocks every 2nd step | 20 | 0.00436293 |
| line Jacobi, levels 2-1-0, blocks every 2nd step | 22 | 0.00335731 |
| line Jacobi, levels 2-1-0, blocks every 2nd step | 24 | 0.00298214 |
| line Jacobi, levels 2-1-0, blocks every 2nd step | 27 | 0.00305558 |
| line Jacobi, levels 2-1-0, blocks every 2nd step | 30 | 0.00230067 |
| line Jacobi, levels 2-1-0, blocks every 2nd step | 35 | 0.0018162 |
| line Jacobi, levels 2-1-0, blocks every 2nd step | 43 | 0.00148714 |
| line Jacobi, levels 2-1-0, blocks every 2nd step | 53 | 0.00134297 |
| line Jacobi, levels 2-1-0, blocks every 2nd step | 63 | 0.00118022 |
| line Jacobi, levels 2-1-0, blocks every 2nd step | 74 | 0.00105966 |
| line Jacobi, levels 2-1-0, blocks every 2nd step | 85 | 0.00112072 |
| line Jacobi, levels 2-1-0, blocks every 2nd step | 96 | 0.00125874 |
| line Jacobi, levels 2-1-0, blocks every 2nd step | 107 | 0.00150899 |
| line Jacobi, levels 2-1-0, blocks every 2nd step | 118 | 0.00220882 |
| line Jacobi, levels 2-1-0, blocks every 2nd step | 129 | 0.00208793 |
| line Jacobi, levels 2-1-0, blocks every 2nd step | 139 | 0.00204449 |
| line Jacobi, levels 2-1-0, blocks every 2nd step | 149 | 0.00164751 |
| line Jacobi, levels 2-1-0, blocks every 2nd step | 159 | 0.00181937 |
| line Jacobi, levels 2-1-0, blocks every 2nd step | 169 | 0.00120896 |
| line Jacobi, levels 2-1-0, blocks every 2nd step | 179 | 6.0570e-04 |
| line Jacobi, levels 2-1-0, blocks every 2nd step | 190 | 2.2356e-04 |
| line Jacobi, levels 2-1-0, blocks every 2nd step | 202 | 3.5353e-05 |
| line Jacobi, levels 2-1-0, blocks every 2nd step | 214 | 1.4646e-06 |
| line Jacobi, levels 2-1-0, blocks every 2nd step | 228 | 2.5669e-08 |
| line Jacobi, levels 2-1-0, blocks every 2nd step | 248 | 2.6692e-10 |
| line Jacobi, levels 2-1-0, blocks every 2nd step | 268 | 2.0002e-12 |

Provenance: gyre 0.4.0; revision `39979fcf90` (commit `39979fcf902ad6116eb550b881b4278d4599c8e2`); 2026-11-12T10:58:43-0500; device cpu; quick suite. **Revision check: Same code as this build.** Produced by 39979fcf902ad6116eb550b881b4278d4599c8e2. Every commit between it and the commit this site was built from (ceb1f4b0bed41de53e586df10858079f5a2bcdd8) changes only documentation text, evidence records or bookkeeping: the code is the same. Full record: [line_smoother.json](../data/verification/line_smoother.json).

**Table: One assembly of the preconditioner at the converged flow** (Line-implicit smoothing on a wall-resolved mesh)

| preconditioner | wall time, compiled, fastest of five [s] |
|---|---|
| block Jacobi, levels 2-1-0 | 0.1873 |
| line Jacobi, levels 2-1-0 | 4.04077 |
| block Jacobi, one level | 3.00486 |
| line Jacobi, one level | 4.08774 |

Provenance: gyre 0.4.0; revision `39979fcf90` (commit `39979fcf902ad6116eb550b881b4278d4599c8e2`); 2026-11-12T10:58:43-0500; device cpu; quick suite. **Revision check: Same code as this build.** Produced by 39979fcf902ad6116eb550b881b4278d4599c8e2. Every commit between it and the commit this site was built from (ceb1f4b0bed41de53e586df10858079f5a2bcdd8) changes only documentation text, evidence records or bookkeeping: the code is the same. Full record: [line_smoother.json](../data/verification/line_smoother.json).

**Table: Flow solve from the free stream** (Line-implicit smoothing on a wall-resolved mesh)

| preconditioner | nonlinear steps | Krylov iterations | converged | drag coefficient | wall time, first solve [s] | wall time, repeated solve (compiled) [s] | repeated solve converged |
|---|---|---|---|---|---|---|---|
| block Jacobi, levels 2-1-0 | 34 | 540 | yes | 0.00575365 | 86.6006 | 33.1422 | yes |
| line Jacobi, levels 2-1-0 | 34 | 267 | yes | 0.00575365 | 159.257 | 233.618 | yes |
| block Jacobi, one level | 40 | 3498 | yes | 0.00575365 | 136.85 | 113.283 | yes |
| line Jacobi, one level | 34 | 1914 | yes | 0.00575365 | 245.519 | 392.492 | yes |
| line Jacobi, levels 2-1-0, blocks every 2nd step | 34 | 268 | yes | 0.00575365 | 189.424 | 147.94 | yes |

Provenance: gyre 0.4.0; revision `39979fcf90` (commit `39979fcf902ad6116eb550b881b4278d4599c8e2`); 2026-11-12T10:58:43-0500; device cpu; quick suite. **Revision check: Same code as this build.** Produced by 39979fcf902ad6116eb550b881b4278d4599c8e2. Every commit between it and the commit this site was built from (ceb1f4b0bed41de53e586df10858079f5a2bcdd8) changes only documentation text, evidence records or bookkeeping: the code is the same. Full record: [line_smoother.json](../data/verification/line_smoother.json).

> **Warning: What line smoothing costs, and what this does not show**
>
> **Fewer Krylov iterations in every solve; less time only where the iterations dominate.**
> Every update of the preconditioner assembles two more blocks per line element, one batch of
> derivatives per colour, on every level. The wall time of the linear solves in the first
> table is that of the Krylov iterations alone, with a preconditioner that is already
> assembled; one assembly is timed in the table above, and what a linear solve gains with
> its assembly counted follows from the two tables. A flow
> solve whose Newton steps each ask for two orders only assembles the preconditioner at every
> step, so its wall time need not fall with its iteration count, and the last row of the flow
> table shows what assembling the blocks every second step does to it. All wall times are
> those of small cases on one machine, taken while the other studies of the suite were
> running (the load is stated in the note of the record), and are reported without a
> threshold. Two small cases, one in two and one in three dimensions, do not say how the
> comparison comes out on a large mesh, at higher degree or for a turbulent flow that is
> three-dimensional in itself; `smoother: line` is therefore an option and not the default
> ([decision 13](../engineering/design-decisions.md)).

**Table: Adjoint derivatives of the drag coefficient, levels 2-1-0** (Line-implicit smoothing on a wall-resolved mesh)

| input | block Jacobi | line Jacobi | relative difference |
|---|---|---|---|
| mach | -0.0498736 | -0.0498736 | 3.1572e-09 |
| re | -3.0651e-10 | -3.0651e-10 | 1.8531e-10 |
| chi_inf | 3.6050e-06 | 3.6050e-06 | 1.6364e-09 |

Provenance: gyre 0.4.0; revision `39979fcf90` (commit `39979fcf902ad6116eb550b881b4278d4599c8e2`); 2026-11-12T10:58:43-0500; device cpu; quick suite. **Revision check: Same code as this build.** Produced by 39979fcf902ad6116eb550b881b4278d4599c8e2. Every commit between it and the commit this site was built from (ceb1f4b0bed41de53e586df10858079f5a2bcdd8) changes only documentation text, evidence records or bookkeeping: the code is the same. Full record: [line_smoother.json](../data/verification/line_smoother.json).

### In three dimensions

**Verification status: Line-implicit smoothing in three dimensions** (study `line_smoother_3d`): **PASSED**, 6 of 6 checks passed, 620.4 s.

Steady laminar flow past a sphere (Re = 100, M = 0.2, degree 2) on a cubed-sphere shell whose layers grow by a factor 2.2 from the wall, so that the first layers are several times wider than they are thick. The flow is converged with element-block Jacobi and with line Jacobi as the smoother of the p-multigrid levels 2-1-0; at the converged flow one forward and one transposed system with the same right-hand side are solved to a relative tolerance of 1e-10. The lines run radially through the anisotropic layers of all six blocks of the mesh. The checks require the same drag coefficient with both smoothers, the same adjoint derivatives when the transposed systems are solved to 1e-12 (their difference at 1e-10 is reported), and fewer than half the Krylov iterations with line Jacobi in both linear solves. Wall times are reported without a threshold.

| Check | Value | Expected | Result |
|---|---|---|---|
| flow solves converged with both smoothers | yes | true | pass |
| lines found on the shell with thin wall layers (elements in lines) | 216 | > 0 | pass |
| drag coefficient: relative difference between the two smoothers | 6.5765e-11 | < 1e-6 | pass |
| forward solve to 1e-10, both smoothers reaching the tolerance: Krylov iterations, line Jacobi / block Jacobi | 0.328571 | < 0.5 | pass |
| transposed (adjoint) solve to 1e-10, both smoothers reaching the tolerance: Krylov iterations, line Jacobi / block Jacobi | 0.346369 | < 0.5 | pass |
| adjoint derivatives of the drag (Mach, Reynolds, angle of attack) from transposed solves that reached 1e-12: largest difference between the two smoothers, relative to the largest derivative | 8.6433e-08 | < 1e-6 | pass |

Run notes: The mesh has 54 lines holding 216 of its 432 elements (the longest 4 elements, 3 colours); 58320 unknowns. The transposed solve took 62 Krylov iterations with line Jacobi against 179 with block Jacobi (ratio 0.35; compiled wall time, ratio 0.29), the forward solve 69 against 210. The adjoint derivatives of the two smoothers differ by at most 2.4e-06 of the largest derivative when the transposed systems are solved to 1e-10 (in the derivative with respect to 'mach') and by at most 8.6e-08 at 1e-12. Between the two tolerances the block-Jacobi value of that derivative itself moves by 7.5e-06 of the largest derivative (last column of the table): the difference between the smoothers is the linear tolerance, amplified by the conditioning of that derivative. One assembly of the preconditioner took 1.18 s with line Jacobi against 0.39 s with block Jacobi, and a flow solve assembles it at every nonlinear step: the repeated flow solves took 13.9 s (block Jacobi) and 19.5 s (line Jacobi). The mesh is coarse and its layers are thinner than a laminar boundary layer at this Reynolds number needs: the case measures the solver, not the flow. Wall times: the column of the linear table is the Krylov solve alone, with a preconditioner that is already assembled; one assembly is timed separately (table 'assembly'). The first flow solve of a configuration includes the one-off compilation. The suite runs its studies in parallel lanes, so other studies were running while these times were taken; they are measurements of small cases on a machine that was not idle, reported without a threshold. Machine load while the study ran: The timings were taken on a busy machine (other processes used 74 % of the capacity of the 8 CPUs while the study ran; the GPU was 17 % utilized when the study started).

Provenance: gyre 0.4.0; revision `39979fcf90` (commit `39979fcf902ad6116eb550b881b4278d4599c8e2`); 2026-11-12T10:58:47-0500; device gpu · NVIDIA GeForce RTX 3060 Ti; quick suite. **Revision check: Same code as this build.** Produced by 39979fcf902ad6116eb550b881b4278d4599c8e2. Every commit between it and the commit this site was built from (ceb1f4b0bed41de53e586df10858079f5a2bcdd8) changes only documentation text, evidence records or bookkeeping: the code is the same. Full record: [line_smoother_3d.json](../data/verification/line_smoother_3d.json).

**Table: Linear solves at the converged flow (tolerance 1e-10)** (Line-implicit smoothing in three dimensions)

| preconditioner | system | Krylov iterations | residual reduction | tolerance reached | wall time of the Krylov solve, compiled, preconditioner assembled before [s] |
|---|---|---|---|---|---|
| block Jacobi | forward | 210 | 9.2582e-11 | yes | 7.68143 |
| block Jacobi | transposed (adjoint) | 179 | 9.9328e-11 | yes | 5.71461 |
| line Jacobi | forward | 69 | 7.6571e-11 | yes | 1.86119 |
| line Jacobi | transposed (adjoint) | 62 | 7.3926e-11 | yes | 1.67616 |

Provenance: gyre 0.4.0; revision `39979fcf90` (commit `39979fcf902ad6116eb550b881b4278d4599c8e2`); 2026-11-12T10:58:47-0500; device gpu · NVIDIA GeForce RTX 3060 Ti; quick suite. **Revision check: Same code as this build.** Produced by 39979fcf902ad6116eb550b881b4278d4599c8e2. Every commit between it and the commit this site was built from (ceb1f4b0bed41de53e586df10858079f5a2bcdd8) changes only documentation text, evidence records or bookkeeping: the code is the same. Full record: [line_smoother_3d.json](../data/verification/line_smoother_3d.json).

<!-- begin level 2 (Practice) -->
**[L2 Practice] The three-dimensional case**

Steady laminar flow past a sphere at a Reynolds number of 100, degree 2, on a cubed-sphere
shell whose layers grow by a factor 2.2 from the wall: the first layers are several times
wider than they are thick, and the lines run radially through them in all six blocks of the
mesh, whose local axes are rotated against each other. Elements further out are close to
isotropic and stay with block Jacobi. The comparison is narrower than that of the flat
plate: the two smoothers on the p-multigrid levels 2, 1, 0 only, with no run on one level
and none with lagged blocks, and with blocks of $135\times135$ instead of $45\times45$.

The checks require the same drag coefficient with both smoothers to $10^{-6}$ relative,
fewer than half the Krylov iterations with line Jacobi in the forward and in the transposed
solve to $10^{-10}$, and adjoint derivatives with respect to Mach number, Reynolds number
and angle of attack that agree to $10^{-6}$ of the largest derivative when the transposed
systems are solved to $10^{-12}$. On the flat plate the derivatives come from solves to
$10^{-10}$ and each must agree to $10^{-6}$ of its own value; why this case is checked
differently is explained
[below](#why-the-derivatives-are-compared-at-a-tighter-tolerance).

<!-- end level 2 -->

**Table: Lines of the mesh** (Line-implicit smoothing in three dimensions)

| lines | elements in lines | elements | longest line | colours | stored line slots |
|---|---|---|---|---|---|
| 54 | 216 | 432 | 4 | 3 | 216 |

Provenance: gyre 0.4.0; revision `39979fcf90` (commit `39979fcf902ad6116eb550b881b4278d4599c8e2`); 2026-11-12T10:58:47-0500; device gpu · NVIDIA GeForce RTX 3060 Ti; quick suite. **Revision check: Same code as this build.** Produced by 39979fcf902ad6116eb550b881b4278d4599c8e2. Every commit between it and the commit this site was built from (ceb1f4b0bed41de53e586df10858079f5a2bcdd8) changes only documentation text, evidence records or bookkeeping: the code is the same. Full record: [line_smoother_3d.json](../data/verification/line_smoother_3d.json).

**Table: One assembly of the preconditioner at the converged flow** (Line-implicit smoothing in three dimensions)

| preconditioner | wall time, compiled, fastest of five [s] |
|---|---|
| block Jacobi | 0.391384 |
| line Jacobi | 1.17592 |

Provenance: gyre 0.4.0; revision `39979fcf90` (commit `39979fcf902ad6116eb550b881b4278d4599c8e2`); 2026-11-12T10:58:47-0500; device gpu · NVIDIA GeForce RTX 3060 Ti; quick suite. **Revision check: Same code as this build.** Produced by 39979fcf902ad6116eb550b881b4278d4599c8e2. Every commit between it and the commit this site was built from (ceb1f4b0bed41de53e586df10858079f5a2bcdd8) changes only documentation text, evidence records or bookkeeping: the code is the same. Full record: [line_smoother_3d.json](../data/verification/line_smoother_3d.json).

**Table: Flow solve from the free stream** (Line-implicit smoothing in three dimensions)

| preconditioner | levels | nonlinear steps | Krylov iterations | converged | drag coefficient | wall time, first solve [s] | wall time, repeated solve (compiled) [s] | repeated solve converged |
|---|---|---|---|---|---|---|---|---|
| block Jacobi | 2, 1, 0 | 13 | 193 | yes | 1.13546 | 141.43 | 13.8529 | yes |
| line Jacobi | 2, 1, 0 | 13 | 123 | yes | 1.13546 | 109.475 | 19.5358 | yes |

Provenance: gyre 0.4.0; revision `39979fcf90` (commit `39979fcf902ad6116eb550b881b4278d4599c8e2`); 2026-11-12T10:58:47-0500; device gpu · NVIDIA GeForce RTX 3060 Ti; quick suite. **Revision check: Same code as this build.** Produced by 39979fcf902ad6116eb550b881b4278d4599c8e2. Every commit between it and the commit this site was built from (ceb1f4b0bed41de53e586df10858079f5a2bcdd8) changes only documentation text, evidence records or bookkeeping: the code is the same. Full record: [line_smoother_3d.json](../data/verification/line_smoother_3d.json).

**Table: Adjoint derivatives of the drag coefficient** (Line-implicit smoothing in three dimensions)

| input | block Jacobi (solve to 1e-12) | line Jacobi (solve to 1e-12) | difference / largest derivative, solves to 1e-12 | difference / largest derivative, solves to 1e-10 | block Jacobi: change from 1e-10 to 1e-12 / largest derivative |
|---|---|---|---|---|---|
| mach | -0.00635239 | -0.00635239 | 8.6433e-08 | 2.4227e-06 | 7.4871e-06 |
| re | -0.0055249 | -0.0055249 | 6.1495e-11 | 2.9472e-10 | 2.6955e-10 |
| alpha | 2.2762e-14 | -3.4771e-14 | 9.0568e-12 | 6.3684e-11 | 7.2750e-11 |

Provenance: gyre 0.4.0; revision `39979fcf90` (commit `39979fcf902ad6116eb550b881b4278d4599c8e2`); 2026-11-12T10:58:47-0500; device gpu · NVIDIA GeForce RTX 3060 Ti; quick suite. **Revision check: Same code as this build.** Produced by 39979fcf902ad6116eb550b881b4278d4599c8e2. Every commit between it and the commit this site was built from (ceb1f4b0bed41de53e586df10858079f5a2bcdd8) changes only documentation text, evidence records or bookkeeping: the code is the same. Full record: [line_smoother_3d.json](../data/verification/line_smoother_3d.json).

<!-- begin level 3 (Mechanics) -->
**[L3 Mechanics] Why the derivatives are compared at a tighter tolerance**

With transposed solves to $10^{-10}$ the two smoothers give Mach-number derivatives of the
drag that differ in the sixth digit, while the Reynolds-number derivatives agree to ten. At
a fixed state the drag of this case does not depend on the Mach number (it is the momentum
flux through an adiabatic wall), so the derivative is the adjoint-weighted term
$-\boldsymbol\psi^{\mathsf T}\,\partial\mathbf R_w/\partial M$ alone
([adjoint formula](../theory/adjoint-and-sensitivities.md)). That term is badly
conditioned: the Mach number enters the residual through the far-field state, whose
pressure $1/(\gamma M^2)$ changes by $-2/(\gamma M^3)$ per unit Mach number, and at the low
Mach number of this case the flow answers mostly with a shift of its pressure level, which
exerts no net force on a closed body. The derivative of the drag is the small remainder of
that large response.
An error of $10^{-10}$ in the adjoint is amplified accordingly, with either smoother: the
last column shows that the block-Jacobi value itself moves by as much when the tolerance is
tightened. At $10^{-12}$ the two agree, which is what the check requires. For a design loop
at low Mach number the consequence is the same as everywhere else in Gyre: the tolerance of
`totals` is the accuracy of the derivative, scaled by its conditioning.

<!-- end level 3 -->

## Single-precision blocks

**Verification status: Single-precision blocks in the preconditioner** (study `mixed_precision`): **PASSED**, 6 of 6 checks passed, 2649 s.

Each case is solved twice from the free stream, with the blocks of the smoother in double and in single precision (solver.precond_precision), and at the converged flow one forward and one transposed system with the same right-hand side are solved to a relative tolerance of 1e-10. A rounded preconditioner must change neither the answers nor, to speak of, the work: the checks require the same drag coefficient, the same solutions of the linear systems, at most a tenth more Krylov iterations, and half the memory for the stored blocks. The cases cover turbulent flow, whose blocks are the worst conditioned, with both smoothers, and laminar flow in three dimensions.

| Check | Value | Expected | Result |
|---|---|---|---|
| every flow solve and every linear solve converged, in both precisions | yes | true | pass |
| drag coefficient: largest relative difference between the precisions | 2.2462e-14 | < 1e-08 | pass |
| solutions of the linear systems (tolerance 1e-10): largest relative difference between the precisions | 4.4650e-11 | < 1e-07 | pass |
| Krylov iterations of the flow solve, single / double: largest ratio | 1 | < 1.1 | pass |
| Krylov iterations of the linear solves, single / double: largest ratio | 1 | < 1.1 | pass |
| memory of the stored blocks, single / double: largest ratio | 0.5 | < 0.51 | pass |

Run notes: With solver.precond_precision 'single' the columns of the element blocks (and of the coupling blocks of the line smoother) are cast to float32 as they are computed, the inverses and the factorisation of the line systems are computed in float64 from them and rounded, and the blocks are applied in float32. The residual, its Jacobian products and the Krylov vectors are float64 throughout, so the converged flow and the solutions of the linear systems are those of the same equations: the differences in the table are the tolerances of the solves. The cases are small; what the option is for, a problem that does not fit the device otherwise, is in the study scale_3d.

Provenance: gyre 0.4.0; revision `39979fcf90` (commit `39979fcf902ad6116eb550b881b4278d4599c8e2`); 2026-11-12T11:27:02-0500; device cpu; quick suite. **Revision check: Same code as this build.** Produced by 39979fcf902ad6116eb550b881b4278d4599c8e2. Every commit between it and the commit this site was built from (ceb1f4b0bed41de53e586df10858079f5a2bcdd8) changes only documentation text, evidence records or bookkeeping: the code is the same. Full record: [mixed_precision.json](../data/verification/mixed_precision.json).

**Table: Double against single precision of the smoother's blocks** (Single-precision blocks in the preconditioner)

| case | blocks | unknowns | nonlinear steps | Krylov iterations, flow solve | drag coefficient | Krylov iterations, forward solve | Krylov iterations, transposed solve | linear solutions: relative difference to double | stored blocks [MB] |
|---|---|---|---|---|---|---|---|---|---|
| turbulent flat plate (SA) | double | 6750 | 35 | 540 | 0.00575365 | 238 | 249 | — | 2.94 |
| turbulent flat plate (SA) | single | 6750 | 35 | 540 | 0.00575365 | 238 | 249 | 1.7075e-11 | 1.47 |
| turbulent flat plate (SA), line smoother | double | 6750 | 35 | 267 | 0.00575365 | 66 | 63 | — | 8.8984 |
| turbulent flat plate (SA), line smoother | single | 6750 | 35 | 267 | 0.00575365 | 66 | 63 | 4.4650e-11 | 4.4492 |
| laminar sphere (3-D), Re = 100, degree 1 | double | 3840 | 14 | 79 | 2.13486 | 46 | 43 | — | 1.248 |
| laminar sphere (3-D), Re = 100, degree 1 | single | 3840 | 14 | 79 | 2.13486 | 46 | 43 | 4.1034e-14 | 0.624 |

Provenance: gyre 0.4.0; revision `39979fcf90` (commit `39979fcf902ad6116eb550b881b4278d4599c8e2`); 2026-11-12T11:27:02-0500; device cpu; quick suite. **Revision check: Same code as this build.** Produced by 39979fcf902ad6116eb550b881b4278d4599c8e2. Every commit between it and the commit this site was built from (ceb1f4b0bed41de53e586df10858079f5a2bcdd8) changes only documentation text, evidence records or bookkeeping: the code is the same. Full record: [mixed_precision.json](../data/verification/mixed_precision.json).

<!-- begin level 2 (Practice) -->
**[L2 Practice] What is compared, and why nothing should change**

`solver.precond_precision: single` keeps the blocks of the smoother (the element-block
inverses and the factors of the line systems) in single precision
([how](../theory/implicit-solver.md#preconditioning-without-assembling-a-matrix)). The
residual, its Jacobian products and the Krylov vectors stay in double precision, so the
equations that are solved are the same, and a preconditioner that is rounded in the eighth
digit should cost no iterations either. Each case is solved twice from the free stream and
then one forward and one transposed system are solved to $10^{-10}$ at the converged flow.
The checks require the same drag coefficient, the same solutions of the linear systems, at
most a tenth more Krylov iterations and half the memory of the stored blocks. The turbulent
flat plate is the hard case for a rounded block (its turbulence rows are scaled by six
orders against the mean-flow rows) and is run with both smoothers; a small laminar sphere
adds three dimensions.

The cases are small. What the option is for, a problem that does not fit the device with
double-precision blocks, is recorded with the
[largest 3-D solve](three-dimensional.md#largest-solve-on-one-device).

<!-- end level 2 -->

<!-- begin level 3 (Mechanics) -->
**[L3 Mechanics] Warm starts**

Inside a session each solve restarts from the previous converged state in the Newton regime.
The service test-suite asserts that a re-solve after a small change of angle of attack needs
fewer nonlinear iterations than the cold start. A solve that does not converge does not
replace that state: the next solve warm-starts from the last converged one
(`tests/test_discipline.py::test_failed_solve_keeps_last_converged_state`).

<!-- end level 3 -->
