Skip to content

Add a multi-n perturbed-equilibrium regression case (+ threaded verification) for singular-coupling threading #334

Description

@logan-nc

Motivation

PR #325 parallelized the singular-coupling loop in PerturbedEquilibrium/SingularCoupling.jl over resonant (surface, n) pairs (and the NTV / field-reconstruction paths). During review we found that the regression harness has no multi-n perturbed-equilibrium case, and CI never sets JULIA_NUM_THREADS, so:

  • diiid_n1 is single-n (nn = 1).
  • solovev_multi_n is multi-n but ideal-only — it does not run perturbed equilibrium / singular coupling.
  • Every @threads region runs on 1 thread in CI, so none of the "bit-identical across thread counts" behavior is exercised by automation.

The specific untested path: for a surface with (near-)integer q, the same surface index s appears on multiple rows (n=1 → m, n=2 → 2m, …). This repeated-s path is only reachable in a multi-n PE run. A write-only data race on sing[s].grri/.grre lived exactly here (removed in #325 424463c); any future per-(s,n) singular-surface state would reintroduce this hazard with no regression coverage to catch it.

Ask

Add a multi-n perturbed-equilibrium regression case whose equilibrium + n-range place an integer-q rational surface in range at more than one n, and verify the threaded coupling output is deterministic vs serial and across thread counts.

Subtleties to work through (why this warrants its own PR)

  1. Case selection. Need an equilibrium where an integer-q surface resonates at multiple n within both [nlow, nhigh] and [mlow, mhigh] — i.e. n·q lands on an in-range integer m for ≥2 values of n. This must be deliberately constructed, not assumed.
  2. New example deck. No existing example runs multi-n PE. Likely need a new examples/…_multi_n_pe_example/gpec.toml (Solovev-based to keep runtime low) with [PerturbedEquilibrium] enabled and [ForcingTerms] forcing spanning the n-range. Follow the TOML annotation conventions in CLAUDE.md.
  3. Quantity extraction. The coupling outputs (C_resonant_*, resonant_*, island half-widths, delta_prime, b^r) are per-row (surface, n). The harness case needs to track them as arrays with a stable, n-keyed ordering so diffs are meaningful.
  4. Thread-count determinism. The harness currently caches by commit, not by thread count. Decide how to assert bit-identity between serial and JULIA_NUM_THREADS>1 (e.g. a dedicated threads-vs-serial test outside the commit-cached harness, or a harness extension) and how BLAS pinning interacts.
  5. CI. Consider a threaded CI job (or a targeted threads-vs-serial unit test) so the @threads paths in SingularCoupling, FieldReconstruction, and KineticForces/Compute.jl are actually exercised — today they are not.
  6. Runtime budget. Multi-n PE is heavier; keep the case small enough for CI/harness time.

Context

Metadata

Metadata

Assignees

No one assigned

    Labels

    Unit testsIssues related to unit testsenhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions