---
title: Verification
summary: Every numerical claim in this documentation is backed by an executable study. The studies run as a pipeline, write machine-readable results with provenance, and the charts and tables on these pages are rendered from those files.
section: verification
order: 0
level: 1
keywords: [verification, validation, evidence, provenance]
---
<!-- gyre docs: expanded Markdown of verification/index.md (generated tables, verification numbers and chart data are written out). Base level of this page: L1 Essentials; passages at another level are bracketed by 'begin level N' / 'end level N' comments and start with [LN Name]. Built from revision ceb1f4b0be. -->

Verification asks whether the equations are solved correctly; validation asks whether they are
the right equations. Gyre's suite is mostly verification — exact properties and convergence
rates that leave no room for interpretation — plus a small physical plausibility check.

**39 of 39 verification studies passed.** This site was built from revision `ceb1f4b0bed41de53e586df10858079f5a2bcdd8`.

| Study | Id | Result | Checks | Wall time (s) | Commit | Date | Device | Suite | Revision vs build |
|---|---|---|---|---|---|---|---|---|---|
| [Summation-by-parts operators](discrete-invariants.md) | `operators` | PASSED | 1/1 | 0.29 | `39979fcf902ad6116eb550b881b4278d4599c8e2` | 2026-11-12T10:22:15-0500 | cpu | quick | Same code as this build |
| [Free-stream preservation on curved meshes](discrete-invariants.md) | `free_stream` | PASSED | 1/1 | 18.67 | `39979fcf902ad6116eb550b881b4278d4599c8e2` | 2026-11-12T10:22:33-0500 | cpu | quick | Same code as this build |
| [Entropy conservation and stability](discrete-invariants.md) | `entropy_conservation` | PASSED | 41/41 | 15.77 | `39979fcf902ad6116eb550b881b4278d4599c8e2` | 2026-11-12T10:22:32-0500 | cpu | quick | Same code as this build |
| [Structure of the BR2 viscous operator](discrete-invariants.md) | `viscous_operator` | PASSED | 17/17 | 116.91 | `39979fcf902ad6116eb550b881b4278d4599c8e2` | 2026-11-12T10:24:33-0500 | cpu | quick | Same code as this build |
| [Independent 1-D model of the BR2 formulation](order-of-accuracy.md) | `diffusion_1d` | PASSED | 17/17 | 4.93 | `39979fcf902ad6116eb550b881b4278d4599c8e2` | 2026-11-12T10:22:38-0500 | cpu | quick | Same code as this build |
| [Exact linearization by automatic differentiation](derivatives.md) | `linearization` | PASSED | 40/40 | 198.07 | `39979fcf902ad6116eb550b881b4278d4599c8e2` | 2026-11-12T10:27:54-0500 | cpu | quick | Same code as this build |
| [Differentiable mesh deformation](derivatives.md) | `mesh_deformation` | PASSED | 9/9 | 2.45 | `39979fcf902ad6116eb550b881b4278d4599c8e2` | 2026-11-12T10:22:42-0500 | cpu | quick | Same code as this build |
| [Advected density wave](order-of-accuracy.md) | `density_wave` | PASSED | 4/4 | 40.98 | `39979fcf902ad6116eb550b881b4278d4599c8e2` | 2026-11-12T10:22:56-0500 | gpu · NVIDIA GeForce RTX 3060 Ti | quick | Same code as this build |
| [Isentropic vortex convection](order-of-accuracy.md) | `isentropic_vortex` | PASSED | 10/10 | 65.18 | `39979fcf902ad6116eb550b881b4278d4599c8e2` | 2026-11-12T10:24:02-0500 | gpu · NVIDIA GeForce RTX 3060 Ti | quick | Same code as this build |
| [Manufactured solution: Euler](order-of-accuracy.md) | `mms_euler` | PASSED | 6/6 | 212.49 | `39979fcf902ad6116eb550b881b4278d4599c8e2` | 2026-11-12T10:27:38-0500 | gpu · NVIDIA GeForce RTX 3060 Ti | quick | Same code as this build |
| [Manufactured solutions: Navier–Stokes](order-of-accuracy.md) | `mms_navier_stokes` | PASSED | 14/14 | 1225.27 | `39979fcf902ad6116eb550b881b4278d4599c8e2` | 2026-11-12T10:48:07-0500 | gpu · NVIDIA GeForce RTX 3060 Ti | quick | Same code as this build |
| [Nonlinear and linear solver convergence](solvers.md) | `solver_convergence` | PASSED | 16/16 | 890.13 | `39979fcf902ad6116eb550b881b4278d4599c8e2` | 2026-11-12T10:42:49-0500 | cpu | quick | Same code as this build |
| [Line-implicit smoothing on a wall-resolved mesh](solvers.md) | `line_smoother` | PASSED | 7/7 | 2159.53 | `39979fcf902ad6116eb550b881b4278d4599c8e2` | 2026-11-12T10:58:43-0500 | cpu | quick | Same code as this build |
| [Line-implicit smoothing in three dimensions](solvers.md) | `line_smoother_3d` | PASSED | 6/6 | 620.35 | `39979fcf902ad6116eb550b881b4278d4599c8e2` | 2026-11-12T10:58:47-0500 | gpu · NVIDIA GeForce RTX 3060 Ti | quick | Same code as this build |
| [Single-precision blocks in the preconditioner](solvers.md) | `mixed_precision` | PASSED | 6/6 | 2648.96 | `39979fcf902ad6116eb550b881b4278d4599c8e2` | 2026-11-12T11:27:02-0500 | cpu | quick | Same code as this build |
| [Adjoint gradients versus finite differences](derivatives.md) | `adjoint_gradients` | PASSED | 18/18 | 1176.07 | `39979fcf902ad6116eb550b881b4278d4599c8e2` | 2026-11-12T11:18:25-0500 | cpu | quick | Same code as this build |
| [Output error estimation](output-error.md) | `output_error` | PASSED | 5/5 | 367.66 | `39979fcf902ad6116eb550b881b4278d4599c8e2` | 2026-11-12T11:33:17-0500 | cpu | quick | Same code as this build |
| [Laminar cylinder at Re = 40](validation.md) | `cylinder_re40` | PASSED | 7/7 | 417.19 | `39979fcf902ad6116eb550b881b4278d4599c8e2` | 2026-11-12T11:25:40-0500 | cpu | quick | Same code as this build |
| [Three-dimensional consistency](three-dimensional.md) | `extruded_3d` | PASSED | 8/8 | 300.8 | `39979fcf902ad6116eb550b881b4278d4599c8e2` | 2026-11-12T11:03:54-0500 | gpu · NVIDIA GeForce RTX 3060 Ti | quick | Same code as this build |
| [Inviscid flow past a sphere (3-D)](three-dimensional.md) | `sphere_inviscid` | PASSED | 9/9 | 424.67 | `39979fcf902ad6116eb550b881b4278d4599c8e2` | 2026-11-12T11:11:04-0500 | gpu · NVIDIA GeForce RTX 3060 Ti | quick | Same code as this build |
| [Laminar flow past a sphere, Re = 100 (3-D)](three-dimensional.md) | `sphere_re100` | PASSED | 5/5 | 187.76 | `39979fcf902ad6116eb550b881b4278d4599c8e2` | 2026-11-12T11:14:26-0500 | gpu · NVIDIA GeForce RTX 3060 Ti | quick | Same code as this build |
| [Adjoint derivatives of 3-D outputs](three-dimensional.md) | `adjoint_3d` | PASSED | 6/6 | 297.74 | `39979fcf902ad6116eb550b881b4278d4599c8e2` | 2026-11-12T11:38:18-0500 | cpu | quick | Same code as this build |
| [Largest 3-D solve on one device](three-dimensional.md) | `scale_3d` | PASSED | 7/7 | 452.04 | `39979fcf902ad6116eb550b881b4278d4599c8e2` | 2026-11-12T11:22:06-0500 | gpu · NVIDIA GeForce RTX 3060 Ti | quick | Same code as this build |
| [Manufactured solutions: RANS with the Spalart-Allmaras model](turbulence.md) | `rans_mms` | PASSED | 9/9 | 455.83 | `39979fcf902ad6116eb550b881b4278d4599c8e2` | 2026-11-12T11:33:19-0500 | cpu | quick | Same code as this build |
| [Exact linearization with the Spalart-Allmaras model](turbulence.md) | `rans_linearization` | PASSED | 20/20 | 158.63 | `39979fcf902ad6116eb550b881b4278d4599c8e2` | 2026-11-12T11:40:59-0500 | cpu | quick | Same code as this build |
| [Turbulent flat plate (NASA TMR) with the Spalart-Allmaras model](turbulence.md) | `rans_flat_plate` | PASSED | 8/8 | 162.14 | `39979fcf902ad6116eb550b881b4278d4599c8e2` | 2026-11-12T11:36:05-0500 | cpu | quick | Same code as this build |
| [Three-dimensional consistency with the Spalart-Allmaras model](turbulence.md) | `rans_extruded_3d` | PASSED | 10/10 | 675.08 | `39979fcf902ad6116eb550b881b4278d4599c8e2` | 2026-11-12T11:33:26-0500 | gpu · NVIDIA GeForce RTX 3060 Ti | quick | Same code as this build |
| [Adjoint gradients with the Spalart-Allmaras model](turbulence.md) | `rans_adjoint` | PASSED | 6/6 | 119 | `39979fcf902ad6116eb550b881b4278d4599c8e2` | 2026-11-12T11:43:02-0500 | cpu | quick | Same code as this build |
| [Discipline contract for MDO integration](discipline-contract.md) | `discipline_contract` | PASSED | 15/15 | 249.94 | `39979fcf902ad6116eb550b881b4278d4599c8e2` | 2026-11-12T11:40:21-0500 | cpu | quick | Same code as this build |
| [Imported meshes](imported-meshes.md) | `imported_mesh` | PASSED | 29/29 | 184.52 | `39979fcf902ad6116eb550b881b4278d4599c8e2` | 2026-11-12T11:46:10-0500 | cpu | quick | Same code as this build |
| [Output-driven order selection](order-selection.md) | `order_selection` | PASSED | 13/13 | 364.44 | `39979fcf902ad6116eb550b881b4278d4599c8e2` | 2026-11-12T11:46:30-0500 | cpu | quick | Same code as this build |
| [Example: inviscid NACA 0012](../examples/naca0012-euler.md) | `example_airfoil` | PASSED | 4/4 | 104.52 | `39979fcf902ad6116eb550b881b4278d4599c8e2` | 2026-11-12T11:35:15-0500 | gpu · NVIDIA GeForce RTX 3060 Ti | quick | Same code as this build |
| [Example: laminar cylinder, Re = 40](../examples/cylinder-re40.md) | `example_cylinder` | PASSED | 4/4 | 51.5 | `39979fcf902ad6116eb550b881b4278d4599c8e2` | 2026-11-12T11:47:06-0500 | cpu | quick | Same code as this build |
| [Example: turbulent flat plate (Spalart-Allmaras)](../examples/turbulent-flat-plate.md) | `example_flat_plate` | PASSED | 5/5 | 119.87 | `39979fcf902ad6116eb550b881b4278d4599c8e2` | 2026-11-12T11:48:33-0500 | cpu | quick | Same code as this build |
| [Example: lift polar with adjoint slopes](../examples/lift-polar.md) | `example_polar` | PASSED | 5/5 | 686.1 | `39979fcf902ad6116eb550b881b4278d4599c8e2` | 2026-11-12T11:58:34-0500 | cpu | quick | Same code as this build |
| [Example: coupled aero-structural adjoint](../examples/aerostructural-coupling.md) | `example_coupling` | PASSED | 2/2 | 822.97 | `39979fcf902ad6116eb550b881b4278d4599c8e2` | 2026-11-12T12:02:29-0500 | cpu | quick | Same code as this build |
| [Example: transonic aerofoil with shock capturing](../examples/transonic.md) | `example_transonic` | PASSED | 9/9 | 151.78 | `39979fcf902ad6116eb550b881b4278d4599c8e2` | 2026-11-12T11:37:50-0500 | gpu · NVIDIA GeForce RTX 3060 Ti | quick | Same code as this build |
| [Kernel throughput (cpu)](../engineering/performance.md) | `performance_cpu` | PASSED | 2/2 | 123.77 | `39979fcf902ad6116eb550b881b4278d4599c8e2` | 2026-11-12T12:04:40-0500 | cpu | quick | Same code as this build |
| [Kernel throughput (NVIDIA GeForce RTX 3060 Ti)](../engineering/performance.md) | `performance_gpu` | PASSED | 2/2 | 103.55 | `39979fcf902ad6116eb550b881b4278d4599c8e2` | 2026-11-12T12:06:32-0500 | gpu · NVIDIA GeForce RTX 3060 Ti | quick | Same code as this build |

Records (JSON): `../data/verification/<id>.json`, index [index.json](../data/verification/index.json).

<!-- begin level 2 (Practice) -->
**[L2 Practice] How to read the evidence**

Each study produces **checks** (a measured value, the expectation, pass or fail), **tables** and
**charts**, and a **provenance stamp**: the source revision, the compute device and the time of
the run. A page built from a different revision than the one deployed says so in its stamp.
Nothing on these pages is typed in by hand.

| Layer | Question | Studies |
|---|---|---|
| [Discrete invariants](discrete-invariants.md) | Do exact algebraic properties hold to round-off? | `operators`, `free_stream`, `entropy_conservation`, `viscous_operator` |
| [Order of accuracy](order-of-accuracy.md) | Does the error fall at the designed rate? | `density_wave`, `isentropic_vortex`, `mms_euler`, `mms_navier_stokes`, `diffusion_1d` |
| [Derivatives](derivatives.md) | Are linearisations and gradients exact? | `linearization`, `adjoint_gradients`, `mesh_deformation` |
| [Solvers](solvers.md) | Do the iterations converge as theory predicts, and does the answer stay the same when the preconditioner changes? | `solver_convergence`, `line_smoother`, `line_smoother_3d` |
| [Output error](output-error.md) | Is the error estimate trustworthy? | `output_error` |
| [Order selection](order-selection.md) | Does the estimate select the lowest sufficient degree, and say so when none suffices? | `order_selection` |
| [Three-dimensional flows](three-dimensional.md) | Does a genuinely 3-D flow on an unstructured hexahedral mesh come out right, with its derivatives? | `sphere_inviscid`, `sphere_re100`, `adjoint_3d`, `scale_3d`, `extruded_3d` |
| [Turbulence closure](turbulence.md) | Is the RANS model discretized at design order, linearised exactly and implemented as published? | `rans_mms`, `rans_linearization`, `rans_flat_plate`, `rans_adjoint` |
| [Discipline contract](discipline-contract.md) | Are the operations an MDO framework calls consistent with each other? | `discipline_contract` |
| [Imported meshes](imported-meshes.md) | Does a mesh from a file behave exactly like a generated one? | `imported_mesh` |
| [Physical validation](validation.md) | Does a canonical flow come out right? | `cylinder_re40` |
| [Testing strategy](../engineering/testing-strategy.md) | What guards every commit? | unit, integration, end-to-end tests |

<!-- end level 2 -->

<!-- begin level 2 (Practice) -->
**[L2 Practice] Reproduce it**

```bash
gyre verify --suite quick -o var/verification      # all studies
gyre verify --only isentropic_vortex,mms_euler     # a subset
gyre docs build                                    # re-render these pages from the new results
```

The quick suite is not short: its last complete run on the development host (39 studies in
three parallel lanes, CPU plus an RTX 3060 Ti) took 104 minutes, and the studies' own wall
times, shown on each study card, add up to 273 minutes. A subset such as
`--only free_stream,entropy_conservation` takes about a minute. `--suite full` adds finer meshes and higher degrees. Each study runs in its own process on the
device suited to its size; results land in `var/verification/<study>.json`. The timing studies
run last, one at a time, and the GPU timing study is skipped on a host without a GPU.

`index.json` lists every result file in the directory, not only those of the last invocation.
Each entry carries the level, commit, device and timestamp of the run that produced it, and
`stale: true` if that was an earlier invocation. `requested`, `skipped` and `summary` describe
the last invocation. `gyre verify` ends with the line `P/R studies of this invocation passed`
and exits with status 1 only when a study of this invocation failed; failing results that an
earlier invocation left in the directory are named separately
(`; stale failing results not re-run: ...`) and do not change the exit status.

On these pages a status block or study card of a result that the last invocation did not
re-run carries the marker "Earlier run"; its tooltip names the commit and time of the run that
produced the result. Such a block shows the checks, thresholds, tables and notes of that run.
The text of a page describes the studies as they are in the code now, so the two can differ
until the study is run again with `gyre verify --only <id>`.

<!-- end level 2 -->

<!-- begin level 3 (Mechanics) -->
**[L3 Mechanics] What a failing study looks like**

Order checks have one of three kinds of threshold, and each names its basis in its `expected`
text:

* the **design rate**, for example "observed order at least $p + 1 - 0.2$", where that rate is
  established;
* the **guaranteed rate**, "at least $p$" with a tolerance, where only consistency is
  guaranteed;
* an **empirical regression floor** between the two, where a rate above $p$ was measured but
  not derived: $p + 0.35$ for the manufactured Euler solution on coarse curved meshes and
  $p + 0.4$ for the velocity in the diffusion-dominated Navier–Stokes regimes. A floor of this
  kind guards against regressions; it is not a property of the scheme.

Bounds on timing ratios and on the ratio of actual to estimated error in the order-selection
study are regression bounds of the same kind and say so. When a study fails, its badge on these pages turns red
and lists the failing checks, the CI pipeline stops before deployment, and the study's log is
kept under `var/verification/logs/`. Failures during development were instructive:

* The vortex study at $p = 4$ measured order 4.05 against an expectation of at least 4.4. The
  first explanation — time-integration error — was tested by shrinking the time step
  five-fold and was *refuted*: the error did not change. The expectation was wrong, not the
  measurement; the study now checks the guaranteed rate, reports the observed one, and keeps
  the time-step test as a permanent check.
* The mesh-deformation derivative check compared against a finite difference of the whole
  domain area, a badly conditioned reference; it now uses a weighted area concentrated near the
  surface.
* A finite-difference step sweep started with a step of 0.1 rad, which pushed the flow into a
  regime with shocks; the failed solve then contaminated every later point. Perturbed solves
  now restart from the baseline state and must converge.
* The output-error study included a mesh so coarse that the bump was sampled at a single
  node; its "errors" were those of a different geometry.

In each case the suite did its job: it made a wrong assumption visible.

<!-- end level 3 -->

<!-- begin level 4 (Theory) -->
**[L4 Theory] Principles behind the suite**

1. **Prefer exact properties over convergence rates.** Round-off-level identities (conservation,
   entropy conservation, symmetry, dot-product tests) cannot be passed by accident.
2. **Test the negative.** Fluxes that should *not* conserve entropy are checked to violate the
   condition; otherwise a broken test would pass everything.
3. **Independent references.** Derivatives are compared against finite differences *and* against
   the other differentiation mode; the error estimator is compared against an actually converged
   finer solution; block preconditioners against a dense Jacobian.
4. **Manufactured forcing from the solver's own physics.** Source terms are generated by
   automatic differentiation of the flux kernels, eliminating transcription errors.
5. **Separate regimes.** Where behaviour differs by regime (diffusion- versus
   convection-dominated), the study reports them separately instead of averaging them away.

<!-- end level 4 -->

## Pages in this section

- [Discrete invariants](discrete-invariants.md) (L2 Practice): Summation by parts, free-stream preservation, conservation and entropy conservation are algebraic identities of the scheme. They hold to round-off, in two and three dimensions, on curved meshes.
- [Order of accuracy](order-of-accuracy.md) (L2 Practice): Convergence studies with exact solutions. The design rate p + 1 is required where it is established (the advected density wave, steady manufactured solutions on Cartesian meshes, heat conduction, convection-dominated flow); elsewhere the guaranteed rate p is required and the observed rate is reported.
- [Linearisation and gradients](derivatives.md) (L2 Practice): Jacobian products, preconditioner blocks, adjoint and direct total derivatives are verified against finite differences, against each other and against dense reference Jacobians. Agreement with finite differences is limited by finite-difference accuracy; adjoint and direct mode agree to the tolerance of their linear solves.
- [Solver convergence](solvers.md) (L2 Practice): 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.
- [Three-dimensional flows](three-dimensional.md) (L2 Practice): Flow past a sphere on an unstructured cubed-sphere mesh of curved hexahedra tests the 3-D path on a genuinely three-dimensional flow, inviscid against exact properties and laminar against accepted data, with adjoint derivatives of all six force and moment coefficients; a spanwise extrusion of the aerofoil case must reproduce the two-dimensional solution.
- [Turbulence closure](turbulence.md) (L2 Practice): The Spalart–Allmaras RANS closure is verified in four steps: a manufactured solution for the order of accuracy of the coupled system, exactness of its linearisation including the wall distance, the turbulent flat plate of the NASA Turbulence Modeling Resource for the model itself, and adjoint derivatives against finite differences.
- [Discipline contract](discipline-contract.md) (L2 Practice): The interface a multidisciplinary framework integrates against is itself verified. Forward and reverse products are exact transposes, the linear solves invert them, the products agree with finite differences at the solution and at a point the framework names, a stalled linear solve is never silent, and the OpenMDAO implicit component passes OpenMDAO's own derivative checks.
- [Output error estimation](output-error.md) (L2 Practice): The adjoint-weighted-residual estimate predicts the change of an output between polynomial degree p and p + 1 from a single linear solve. Its effectivity is measured against the actually converged p + 1 solution.
- [Order selection](order-selection.md) (L2 Practice): Output-driven order selection raises the polynomial degree until the estimated error of an output meets a tolerance. The study checks the selection rule itself, compares the estimate with solutions two degrees higher, and cross-checks every continued level against an independent solve.
- [Imported meshes](imported-meshes.md) (L2 Practice): A mesh read from a Gmsh or NPZ file must behave exactly like a generated one. The study reads genuine Gmsh files, tests the node-ordering tables, the operator identities on unstructured curved meshes in 2-D and 3-D, and solves a flow with an adjoint derivative on an imported mesh.
- [Physical validation](validation.md) (L2 Practice): A canonical viscous flow — the steady wake of a circular cylinder at Reynolds number 40 — is compared with the literature as a plausibility check on the physics, boundary conditions and force evaluation.
