# Spectral QNM verification bundle

This standalone finite reference benchmark uses dimensionless black-hole
coordinates r/(GM) and frequencies w=GM omega. It checks the fundamental
axial Schwarzschild mode and a supplied fixed-A Kerr radial problem, plus
an exact Pöschl–Teller barrier (V0=1, alpha=0.2).
The Kerr calculation is not a coupled angular–radial solve.

## Download and verify

Download the six files linked on the Spectral Collocation and Direct
Eigenvalue Methods page into a fresh directory: spectral_qnm.py,
requirements.txt, this README, spectral-qnm-candidates.csv,
spectral-qnm-residuals.csv and spectral-qnm-checks.json.
The links work on the same served site or local preview as the page;
no private repository or unlisted input is required.

The corrected scientific files have these SHA-256 fingerprints:

~~~text
dbd0d857e31bbf51d37a74114fad00dc88ecf2178fbe5185872409f365c1d0d6  spectral_qnm.py
b1a0c4b6e571a19ffd3f71d95fbb5e48203c8d9f3b9cdde86f7c3b6f9643aa95  requirements.txt
45c7ca011917b3c5a2a4ed48bd636d49ce7ebb66ceb27646573ec186eaac759d  spectral-qnm-candidates.csv
a26fa27f068fd1d119cb6871464e2888d3ca804608c44f16e8a20176e0ea9a9d  spectral-qnm-residuals.csv
0c29d6c79d003340d1295a5c487828f175ad428e7df85bfe421f1d9d7f8ab260  spectral-qnm-checks.json
~~~

Compare these with the output of "shasum -a 256" on the downloaded files.
The saved files supersede the earlier 554-candidate/70-survivor output.
That version contained a PT first-derivative sign error, inconsistent
mapped interpolation and insufficient branch matching.

## Reproduce

Use CPython 3.9.6, NumPy 2.0.2 and SciPy 1.13.1. The reference machine is
arm64 macOS with Apple Accelerate BLAS/LAPACK. The solver uses complex
double precision. With the required interpreter available, these POSIX
commands write new outputs, preserving the downloaded references:

~~~sh
python3 --version
python3 -m venv .venv-spectral
. .venv-spectral/bin/activate
python -m pip install --requirement requirements.txt
python spectral_qnm.py \
  --cases poschl-teller,schwarzschild,kerr-radial \
  --orders 12,20,24,28,32,36,40,44 \
  --maps 0.7,1.0,1.4 \
  --write-candidates rerun-candidates.csv \
  --write-residuals rerun-residuals.csv \
  --write-checks rerun-checks.json
~~~

All 72 case/order/map configurations are mandatory for this finite benchmark.
Other input lists are rejected rather than silently weakening its test scope.
The eigensolver requires no network. Installing pinned packages is a separate
environment-setup operation.

## Interpret the outputs

- The candidate CSV retains all 536 finite frequencies in the strict window
  0<Re(w)<1, -1<Im(w)<0 (Omega replaces w for the barrier).
- The residual CSV retains 64 fundamental-reference rows: PT 24,
  Schwarzschild 20, and fixed-A Kerr 20. For each black-hole case all three
  N=12 rows and N=20,c=1.4 fail required comparisons.
- The checks JSON retains all candidate diagnostics, forward and reverse
  nearest/second-nearest distances, comparison failures, 335 branch
  components, 381 passed pair edges, reference anchors, 40 positive
  numerical controls and 10 negative controls.
- Pair matching does not use reference frequencies. It compares every
  adjacent N at fixed map and both alternate maps at fixed N, requiring
  mutual nearest frequencies, difference<5e-6, second-best gaps>5e-6 in both
  directions and weighted profile mismatch<1e-3. An absent second candidate
  has a null gap and no competitor; an empty peer configuration fails.
- A branch contains at most one candidate per configuration. Only afterward,
  a separated reference match at N=44,c=1 labels the fundamental branch.
  Final acceptance is local_pass AND matching_pass AND branch_unique AND
  reference_pass. The JSON and CSV preserve each separate flag.
- Off-grid checks evaluate the degree-N polynomial in computational u and
  apply both inverse-map derivative terms. The norm is
  max_i abs(sum_k T_ki)/max_i sum_k abs(T_ki); a zero/nonfinite global
  denominator is undefined and fails. It avoids unstable pointwise ratios
  at eigenfunction nodes. Endpoint and radiation-phase tests are separate.
- Overlaps use 64-point Gauss–Legendre quadrature in physical x on [0,1],
  not collocation-node Euclidean products or a black-hole energy norm.
  Undefined overlap or diagnostic values are JSON null/empty CSV fields
  and fail, never finite success sentinels.
- The pencil residual gate is 1e-10. The transformed/raw ODE, endpoint,
  phase and coefficient-tail gates are 1e-4; reference difference is <5e-6.
  Every threshold and diagnostic definition is also in the checks JSON.

The constant PT fundamental cannot detect derivative errors. The corrected
program therefore checks the nonconstant n=1 profile and its full raw ODE,
known mapped polynomial derivatives, node-safe normalization and deliberately
incorrect matching inputs. These are additional controls, not a fourth
reference branch in the accepted CSV.

Repeated runs in the recorded environment produced byte-identical files.
Other BLAS implementations may change low floating-point digits, especially
for rejected candidates. Compare frequencies, branch identities, decisions
and declared gates; do not mistake either byte identity or a small residual
for a continuum-convergence theorem. The retained evidence permits accepted
diagnostic changes below 5e-8 (1e-11 for pencil residuals), preserving the strict gates and mode
identities; this finite tolerance is not a universal cross-platform guarantee.

Smooth endpoints and leading radiation-phase limits can admit unwanted
subdominant solutions. Reference agreement supports the selected finite
radial benchmarks; it does not classify every unconfirmed candidate as
spurious, establish a complete spectrum, certify an extremal limit, or prove
a physical energy/pseudospectral norm bound.
