Verification suite

Canonical benchmarks with known answers — textbook plate and beam solutions, the standard shell obstacle course, closed-form laminate results, conservation identities, and analytic derivatives. Each one runs a mesh refinement sweep and reports its value against a published or independently computed reference.

These are examples first and a regression gate second: every file is a readable, self-contained script that a user can run to see Hermit reproduce a result they already trust.

conda activate hermit
python examples/verification/ex_scordelis_lo.py            # convergence sweep
python examples/verification/ex_scordelis_lo.py --quick    # the single level CI runs

Writing a new one

Copy ex_scordelis_lo.py (curved geometry, distributed load) or ex_pinched_cylinder.py (symmetry planes, point load). The shape is always the same:

  1. 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.

  2. A solve_at(level) -> float returning the single scalar the reference is quoted for.

  3. A CASE = Case(...) declaring reference, tolerance, citation, levels and quick_level.

  4. if __name__ == "__main__": main(CASE).

Mesh builders live in _geometry.py — add one there rather than inlining a mesh in an example. Meshes are built in memory: the env has no meshio, and a benchmark’s mesh is a function of its refinement level anyway.

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 (see ex_ss_plate_uniform). Keep a full sweep under ~30 s.

Reference-value integrity

The failure mode this suite must not have is a benchmark that passes while verifying nothing. Four rules, in priority order:

  1. Compute the reference rather than quoting it, wherever the closed form allows. Sum the Navier series in NumPy; assemble the laminate A/B/D by hand from the ply definitions. A computed reference cannot be misremembered, and it documents itself. Quote a constant only when the reference genuinely is a published number from a converged numerical study (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.citation field and in REFERENCES.md.

  3. The reference and the tolerance are fixed before the first run and are not adjustable to fit the result. If a case misses, report the convergence table and say so. A benchmark that misses its reference is a finding about Hermit — the API redesign turned up nine real defects this way, and several of them looked exactly like “this case is a bit off”. Loosening the gate throws that signal away.

  4. Assert convergence, not just the endpoint. A wrong reference constant usually shows up as a sweep converging beautifully to a different number, which is diagnostic. The harness warns when the error is not monotone under refinement.

When a benchmark does not meet its reference

Set open_finding= on the Case 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. Of the five cases that first failed here, one was 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 — it passes). Four of the five would have been erased by a slightly wider tolerance.

ex_curved_beam is the only case still carrying an open_finding, and it is a documented element limitation on a deliberately extreme 1-element-wide strip rather than a defect — see its open_finding string for the measurements that establish that.

Warped quadrilateral cells

ex_warped_quad_consistency.py records the resolved warped-cell defect and gates its replacement. The former curvature gave a 40% wrong twisted-beam answer that worsened under refinement. Hermit’s constant-normal, shallow-shell curvature now makes the quadrilateral and triangular sequences converge together. Triangles are therefore no longer required merely because a surface is doubly curved; see the formulation limits in the user guide before applying this flat-facet theory to moderately thick, strongly curved, membrane-loaded shells.

Layout

file

what

_geometry.py

analytic in-memory mesh builders (plate, cylinder, sphere, disk, annulus, twisted strip, curved beam)

_harness.py

Case, the convergence table, the pass/fail gate, the CLI

ex_*.py

one benchmark each

REFERENCES.md

every reference value with its source