Verification benchmarks
Canonical cases with known answers: textbook plate and beam solutions, the standard shell obstacle course, closed-form laminate results, conservation identities, and analytic derivatives. Each script runs a mesh-refinement sweep and reports its converged value against a published or independently computed reference.
These are examples first and a regression gate second. Every file in
examples/verification/ is a readable, self-contained script you can run to watch
Hermit reproduce a result you already trust:
conda activate hermit
python examples/verification/ex_scordelis_lo.py # full convergence sweep
python examples/verification/ex_scordelis_lo.py --quick # the single level CI runs
python examples/verification/ex_scordelis_lo.py --level 32
Each run prints the reference, its citation, the tolerance, and a level-by-level
table of value, value/reference and relative error, ending in PASS or FAIL. The
harness warns separately when the error is not monotone under refinement, because a
sweep that converges beautifully to the wrong number is diagnostic of a bad reference
rather than a bad element.
Where the reference values come from
The failure mode this suite must not have is a benchmark that passes while verifying nothing. Four rules govern every reference, in priority order.
1. Compute the reference rather than quoting it, wherever a closed form allows. Most cases sum their own Navier series in NumPy, or assemble the laminate \(A\)/\(B\)/\(D\) by hand from the ply definitions, inside the example file. A computed reference cannot be misremembered. A constant is quoted only when the reference genuinely is a published number from a converged numerical study — in practice, the obstacle-course cases.
2. Every quoted constant carries a real citation — author, work, and the table or
equation it came from — in the case’s citation field, and therefore in the generated
reference table.
3. The reference and the tolerance are fixed before the first run, and are not adjustable to fit the result. A case that misses its reference is reporting a finding about Hermit; the API redesign turned up nine real defects exactly this way, and several of them looked at first like “this case is a bit off”. Loosening the gate throws that signal away.
4. Quoted constants get an independent review pass that re-derives or re-sources the number without seeing the original justification. Disagreements are resolved before the example lands, never by adjusting the tolerance.
REFERENCES.md is generated from the Case objects by
python examples/verification/_references.py, and CI fails if it is stale, so the
table cannot drift away from the declarations it describes.
When a case does not meet its reference
The case sets open_finding= with what is known and what is merely suspected. The
reference and tolerance stay at their correct values, the sweep still runs and prints,
and the test suite reports the case as an expected failure with that string as the
reason. Resolving one means fixing Hermit or correcting the reference — never editing
the field to be less honest.
This is not a formality. Five cases failed on first run: one had a wrong analytic
target, one a wrong load magnitude, one a measurement point at the wrong place, one a
genuine element defect (the warped-quadrilateral curvature, since fixed), and one an
optimiser failure (ex_optimal_thickness_taper, since resolved). Four of the five
would have been erased by a slightly wider tolerance.
One case is currently open: ex_curved_beam plateaus about 3.9% below the
MacNeal–Harder value on a deliberately extreme one-element-wide strip. Widening the
strip to four elements closes the gap to 1.9%, and the in-plane load case converges to
1.3%, so this is a documented element limitation for out-of-plane twisting at extreme
aspect ratio, not a general membrane offset.
The cases
Analytic plate and beam solutions
The reference is a closed form the example evaluates itself.
case |
quantity |
reference |
|---|---|---|
|
tip deflection |
Timoshenko beam formula, computed |
|
tip deflection and rotation |
Euler–Bernoulli constant curvature, computed |
|
tip deflection |
Timoshenko beam formula, computed |
|
centre deflection |
Kirchhoff–Love Navier double series, 801 terms/direction |
|
centre deflection |
Kirchhoff–Love single Navier mode |
|
centre deflection |
Timoshenko & Woinowsky-Krieger (1959), Table 35, p. 202 |
|
centre deflection |
\(w = q a^4 / (64 D)\), computed |
|
FE / analytic ratio vs. \(a/h\) |
Reissner–Mindlin single mode, computed |
ex_thin_limit_shear sweeps slenderness rather than mesh size: a ratio that falls
away as the plate thins is shear locking.
The shell obstacle course
Published constants from converged numerical studies, all from MacNeal & Harder, A proposed standard set of problems to test finite element accuracy, Finite Elements in Analysis and Design 1(1), 1985.
case |
quantity |
reference |
|---|---|---|
|
free-edge midspan deflection |
0.3024 |
|
radial deflection under the load |
1.8248e-5 |
|
radial deflection under the load |
0.0924 |
|
tip deflection in \(z\) |
0.005424 |
|
tip deflection in \(z\) |
0.5022 (open finding, above) |
|
mid-right-edge deflection |
23.9 — Cook (1974) |
Scordelis–Lo and the pinched hemisphere each appear twice, on triangles and on quadrilaterals. That pairing is deliberate: it is the standing check that the two cell types converge to the same answer.
Warped quadrilaterals
case |
what it gates |
|---|---|
|
warped-quad tip deflection / triangle tip deflection → 1 |
|
hypar free-edge deflection against a converged triangle solution |
These record the resolved warped-cell defect and gate its replacement. The former curvature differentiated the cell normal along with the rotation, which stored bending energy under rigid-body motion; it gave a 40% high twisted-beam answer that got worse under refinement, and the consistency ratio converged to 1.407. Hermit’s constant-normal, shallow-shell curvature makes the quadrilateral and triangular sequences converge together. Triangles are therefore no longer required merely because a surface is doubly curved — but see the formulation limits in Background before applying flat-facet theory to a moderately thick, strongly curved, membrane-loaded shell.
Laminates and failure
case |
quantity |
reference |
|---|---|---|
|
\(A\)/\(B\)/\(D\) assembly discrepancy |
independent NumPy evaluation of the CLT thickness integrals |
|
laminate vs. |
same-run isotropic solution |
|
midpoint deflection |
one-term Navier solution from the independently assembled \(D\) |
|
Tsai–Wu field and KS discrepancy |
criterion evaluated by hand from the ply strengths |
ex_laminate_matches_isotropic is the cross-path check: two spellings of one physical
shell — an isotropic material and a laminate of isotropic plies — must agree to
round-off. It is gated at a relative 1e-8.
Conservation and identities
case |
quantity |
reference |
|---|---|---|
|
mass and CG, uniform and graded thickness |
closed-form area integrals |
|
energy / compliance identity residual |
Hermit’s own output conventions |
These have a reference of zero and a tolerance near machine precision: their residual is round-off in the direct solve, not a discretisation error.
Derivatives
case |
quantity |
reference |
|---|---|---|
|
\(\mathrm{d}C/\mathrm{d}t \,/\, (-3C/t)\) |
Euler–Bernoulli pure-bending scaling |
|
CSDL vs. central differences, thickness |
second-order central-difference formula |
|
CSDL vs. central differences, mesh coordinates |
second-order central-difference formula |
|
CSDL vs. central differences, Tsai-Wu index under a |
second-order central-difference formula |
|
optimiser-recovered taper exponent |
\(t \propto \sqrt{M}\), hence \((L-x)\); cross-checked against a 1-D SLSQP solve |
ex_gradient_finite_difference and ex_shape_derivative_fd run a step study, so the
reported number separates FD truncation error from cancellation; their tolerances are
FD-limited, not Hermit-limited. ex_shape_derivative_direction_failure differs in one
important way: its finite differences perturb the mesh coordinates and rebuild the
mesh, rather than perturbing a node_disp variable. A node_disp perturbation leaves
domain.local_frames() untouched, so an orientation frozen at the reference geometry
stays equally frozen in both legs and the check passes even when the gradient is
wrong. That is exactly how the defect this case now gates escaped earlier review. ex_optimal_thickness_taper needs the optional optimiser stack
(pip install 'hermit[opt]') and is skipped, not failed, without it.
Adding a benchmark
Copy ex_scordelis_lo.py (curved geometry, distributed load) or
ex_pinched_cylinder.py (symmetry planes, point load). The shape is always the same:
A module docstring whose first line is the title — the docs build turns it into a page and requires it. Follow it with the physical setup, the reference value, and what makes the case worth having.
A
solve_at(level) -> floatreturning the single scalar the reference is quoted for.A
CASE = Case(...)declaringreference,tolerance,citation,levelsandquick_level.if __name__ == "__main__": main(CASE).
quick_level is the level CI runs, so it should be the cheapest one that is still
honest about the case. Prefer the coarsest level meeting tolerance; where no swept
level meets it, keep the most diagnostic affordable level rather than moving the
target (ex_ss_plate_uniform does this, and eight of the cases run their finest
swept level). Keep a full sweep under about 30 seconds.
Mesh builders live in _geometry.py; add one there rather than inlining a mesh.
Meshes are built in memory (the environment has no meshio, and a benchmark’s mesh
is a function of its refinement level anyway).
Every case, in full
- Analytic compliance gradient of a thin cantilever plate.
- Cantilever plate under a tip force
- Cantilever plate under a tip moment
- Cantilever plate under uniform pressure
- Clamped circular plate under uniform pressure.
- Clamped square plate under uniform pressure.
- Classical-lamination-theory ABD assembly
- Cook’s membrane
- Navier bending solution for a symmetric cross-ply laminate
- MacNeal-Harder curved beam (out-of-plane load)
- Elastic-energy and compliance identity
- Nodal-thickness compliance gradient versus central finite differences.
- Hyperbolic-paraboloid cantilever: restored warped-quad consistency
- An isotropic-ply laminate matches an isotropic shell
- Mass and centre of gravity of a plate with uniform and graded thickness
- Compliance-optimal cantilever taper: recovering the analytic exponent
- Pinched cylinder with end diaphragms
- Pinched hemisphere with an 18-degree hole
- Pinched hemisphere with an 18-degree hole (quadrilaterals)
- Scordelis-Lo roof
- Scordelis-Lo roof (quadrilateral control)
- Shape derivative of failure index for direction-oriented laminates.
- Mesh-coordinate compliance derivative versus central finite differences.
- Simply supported square plate under a sinusoidal pressure.
- Simply supported square plate under uniform pressure.
- Thin-limit transverse-shear study for a simply supported plate.
- Tsai-Wu transverse-shear failure in a uniaxially loaded laminate
- MacNeal-Harder twisted beam (out-of-plane)
- Warped quadrilateral cells preserve rigid-body consistency