Install verification: nrhjsur-verify

A test suite that ships inside the package, so a user with pip install nrhjsurrogate and the downloaded model files can check that both work, against reference values recorded from the released models. Written 2026-09-02 on feat/eval-release-tests.

What it is

nrhjsurrogate/verify/ is a subpackage: checks.py holds the checks, __init__.py the runner (nrhjsur-verify, python -m nrhjsurrogate.verify), test_installed_model.py thin pytest wrappers (pytest --pyargs nrhjsurrogate.verify), and reference_values.npz the fixture (151 arrays, 116,605 bytes, scripts/generate_verify_reference_values.py). All three entry points call the same functions. The runner has no dependency beyond the package; pytest is optional.

The fixture stores outputs at three parameter points, (1, 0, 0), (3, 0.4, -0.3) and (7, -0.5, 0.6), at RECORDED sample times. The checks re-evaluate at those exact times (the models synthesise directly at any requested time), so nothing depends on a grid. Reference values are regenerated only when a released artifact changes.

What it checks

In order (checks.ALL_CHECKS): package imports; reference values load; which released files are present and where the package searched; each present file's SHA-256 and size against nrhjsurrogate.models.MODELS (a file carrying one released name but another registered digest is reported as that artifact); the action-angle model loads with its merger-ringdown arm; waveform (seven modes, uniform grid, peak near t = 0, recorded span, values); parameter derivatives (modes_grad(with_mr=True): same sample count as the waveform, endpoints within one spacing, values); the model's own error estimate (all seven modes, whole span, amplitude and phase, values); hybridisation (f_low below reach starts earlier, hybridize=False refuses, values in the extended window); dynamics (omega positive and rising, values); remnant (remnant and remnant_physical, values); physical units (start frequency within 5 percent of f_min, strain magnitude at 440 Mpc, values); the adiabatic-angle model loads, its modes match, hull_mask answers; its derivatives (compiled backend only, see limits); the previous-generation files when present; the compiled backend against numpy when built.

Tolerances, with the evidence

checks.TOLERANCE_NATIVE_SPAN = 1e-6 of the per-mode peak for everything in the native span. Measured legitimate differences are far below it: the fast evaluation flavour (safe=False, a proxy for a different summation order) against the shipped reference read 0.0 on the waveform, 1.2e-11 on the error estimate, 1.9e-11 on dynamics, 3.6e-10 on physical units and 1e-11 to 6.8e-10 on derivative rows; the compiled and NumPy evaluators agree to 1.4e-14 on derivatives, a batched and an unbatched contraction to about 1e-10. A wrong-generation artifact moves the waveform by the model's own accuracy class, about 1e-3. TOLERANCE_EXTENSION = 1e-4 for the post-Newtonian extension, ten times the documented cross-machine class of 1e-5 (ACCURACY.md section 2). TOLERANCE_REMNANT = 1e-8 absolute.

The measure is not naive. At (1, 0, 0) the odd-m modes vanish identically and the mass-ratio derivative of every even-m mode vanishes by exchange symmetry, so those arrays are roundoff (7.9e-18 against chi-rows of 1.71); a derivative row is scaled by the mode's largest derivative row and a vanishing array by its largest sibling at that point (checks._relative_to_peak). At the same point the phase uncertainty of the odd-m modes is +inf by construction (amplitude uncertainty over a zero amplitude) and is accepted only there.

Limits

What it found on its first consumer-route run

On a clean venv install of the wheel, modes_grad(with_mr=True) and get_waveform_error_estimate() both failed with FileNotFoundError: swsph_mixing_tables.npz: physics.spin_weighted_angular_harmonics.data_path promises the table under nrhjsurrogate/data/ on an install, and nothing shipped it there. The source tree hid the defect through the paper_data/ fallback. Fixed in the same branch by shipping the table as package data. This is the class of defect a shipped suite exists to catch.