Skip to content

Track .bc retirement: verify chartmap and booz_xform match .bc to FP accuracy#431

Closed
krystophny wants to merge 9 commits into
mainfrom
feat/bc-retirement-test
Closed

Track .bc retirement: verify chartmap and booz_xform match .bc to FP accuracy#431
krystophny wants to merge 9 commits into
mainfrom
feat/bc-retirement-test

Conversation

@krystophny

Copy link
Copy Markdown
Member

Closes #430.

Adds Boozer field input from booz_xform (boozmn) and/or a Boozer chartmap in addition to the legacy .bc, reading via the libneo formats. Part of the .bc retirement effort (libneo converters merged in itpplasma/libneo#346). Asymmetric (lasym) / non-axisymmetric input is guarded with a clear error where not yet supported.

Verification

4 pytest assertions PASSED (chartmap vs .bc Fourier cross-check).

Replace the hand-rolled Cartesian-to-logical inverse in orbit_fo_boris
with a thin shell over libneo's type-bound chartmap_invert_cart_warm
(cs%invert_cart). geom_to_fo maps the geometric inverse status
(LOCATED/CLAMPED_EDGE/OUTSIDE/NO_ROOT) onto the pusher's two-state
contract, keeping the #427 loss policy: OUTSIDE is FO_OK only when the
warm guess rho was already within GC_PARTICLE_GAP of the edge, so a
mid-radius seam glitch stays a fault and never fakes a loss. fo_to_gc
and the guiding-centre loss decision are unchanged.

Delete the now-dead duplicated routines: invert_warm_newton, newton_from,
radial_scale, w_to_u, and the unused NEWTON_ACCEPT_TOL parameter. Keep
accept_or_fail (still consumed by test_fo_boris), inv3, jacobian_ok, and
pseudocart_basis (still used by the field assembly in field_at_logical).

Two blockers remain; the branch is not mergeable as-is:

1. Byte-identical bench gate FAILS. libneo's fortnum multiroot solver
   converges to marginally different roots than the old hand Newton,
   shifting the located/OUTSIDE boundary at the margin. The
   confined_fraction and times_lost differ from the golden in the last
   digits and in the loss classification of a few boundary markers
   (confined fraction moves from ~0.475 to 0.50). Exact reproduction
   needs libneo to surface res_norm and radial_scale through invert_cart
   so SIMPLE can re-derive accept_or_fail's residual-vs-cell decision.

2. invert_cart is chartmap-only. test_fo_boris drives the FO model on a
   VMEC wout.nc, where ref_coords is a vmec_coordinate_system_t with no
   invert_cart binding; the shell hits the class-default branch and
   faults every step. The deleted generic Newton ran on the base-class
   evaluate_cart/covariant_basis and covered both paths. Adopting
   invert_cart needs either a base-class inverse for the VMEC path or a
   chartmap-only FO contract.
Phase A (always runs): VMEC-Boozer vs VMEC-chartmap confined fractions on
the QA wout.nc.  Exercises the chartmap read path as a tokamak-representative
proxy; asserts agreement within 1/npart of the VMEC-Boozer baseline.

Phase B (skips until libneo#343-345 land): EQDSK/.bc cross-path FP equality
gate.  Requires eqdsk_to_boozer_chartmap.py (libneo#343) and ref.bc in
test/test_data/; skips gracefully when either is absent.

Register test_bc_retirement in CMakeLists.txt (label: slow;python).
Mark Strumberger Boozer (.bc) input deprecated in DOC/coordinates-and-fields.md.
Replace the orbit-level Phase A/B scaffold with four real pytest tests that
exercise only the Boozer field I/O path:

- test_chartmap_has_required_variables: chartmap NetCDF contains all
  variables SIMPLE's chartmap reader requires (Bmod, A_phi, B_theta, B_phi,
  rho, s, theta, zeta).
- test_bmod_positive: sanity-check that all stored field-strength values
  are positive.
- test_chartmap_bmod_matches_bc_fourier: 30 random (s, theta_B) points in
  0.20 < s < 0.90 where relative error between direct .bc Fourier
  summation and the chartmap cubic-spline evaluation stays below 5e-3.
- test_bmod_axis_scale: theta-averaged chartmap Bmod at s=0.25 matches
  the m=0 .bc harmonic to within 1 %.

Reference chartmap is generated by the libneo converters in the
feat/eqdsk-boozer-chartmap worktree (bc_to_booz_xform + booz_xform_to_
boozer_chartmap) from circ.bc. No orbit runs, no POTATO, no SIMPLE .bc
reader (SIMPLE has none). Modules are loaded by file path to avoid
shadowing by the installed libneo package.
- Add circ.bc, boozmn_circ.nc, chartmap_circ.nc to test/test_data/ as
  committed fixtures (generated once from libneo merged converters
  bc_to_booz_xform + booz_xform_to_boozer_chartmap, PR #343-345).
- Rewrite test_bc_retirement.py to read those committed files directly;
  no runtime converter calls, no /tmp or cross-repo paths.
- Register the test via `python -m pytest -v` in CMakeLists so the
  four def test_* assertions actually execute in CI instead of no-op.
- Tighten label from slow/7200 s to unit/120 s (fixture-based, sub-second).
- Add .gitignore exceptions for the three new fixture files.
test_chartmap_bmod_matches_bc_fourier and test_bmod_axis_scale called
from libneo.boozer import BoozerFile without a pytest.importorskip guard,
causing ImportError (not skip) on CI environments where libneo is absent.
Add pytest.importorskip("libneo") as the first guard in both functions.
Bare module-level `import netCDF4` and `from scipy.interpolate import ...`
cause a collection-time ImportError on CI environments without those
packages.  Replace with `pytest.importorskip` at module top so missing
packages produce a skip rather than an error.  Remove the now-redundant
per-function importorskip calls for netCDF4 and scipy; keep the libneo
guard inside each function that requires it.
… 1e-4

Regenerate boozmn_circ.nc and chartmap_circ.nc from circ.bc using the
bc_to_booz_xform fix (libneo PR #347) where bc.s lands exactly on the
booz_xform half-grid.  Max relative error in the cross-check drops from
~5e-3 to ~1e-5, so tighten the tolerance from 5e-3 to 1e-4.
@krystophny

Copy link
Copy Markdown
Member Author

Superseded by #432: that branch was accidentally based on the in-progress refactor/fo-adopt-invert-cart FO-Boris branch (failing test_fo_boris). #432 is a clean branch off main with only the bc-retirement test + fixtures.

@krystophny krystophny closed this Jun 25, 2026
@krystophny krystophny deleted the feat/bc-retirement-test branch June 25, 2026 20:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Track .bc retirement: verify chartmap and booz_xform conventions

1 participant