Skip to content

GVEC QA Boozer chartmap validation#334

Open
krystophny wants to merge 21 commits into
mainfrom
feature/boozer-chartmap-gvec-qa
Open

GVEC QA Boozer chartmap validation#334
krystophny wants to merge 21 commits into
mainfrom
feature/boozer-chartmap-gvec-qa

Conversation

@krystophny
Copy link
Copy Markdown
Member

@krystophny krystophny commented Mar 28, 2026

Summary

GVEC QA branch for Boozer chartmap validation after #360. The branch is now restacked on
main at 171c998 and keeps the remaining GVEC converter, QA, fixture, and
documentation work.

Current contracts in this branch:

  • Chartmap A_phi is tabulated on the file rho grid and chain-ruled to s on readback.
  • Chartmap export and the GVEC converter write rmajor; the reader restores it before
    parameter initialization so VMEC and chartmap runs use the same dtaumin and ntau.
  • The e2e chartmap test checks the exported rmajor and compares the VMEC/chartmap
    microstep directly.
  • The optional GVEC QA CTest is registered only when the configured Python can import
    gvec.
  • The older broad field-equivalence tests were removed. The remaining tests check smaller
    contracts: reader metadata, A_phi abscissa, start-mode sampling, scaling, roundtrip,
    and selected e2e equilibria.

Stack

Merge order is now:

  1. boozer chartmap: fix rho-grid fields and start sampling #360, already merged into main.
  2. GVEC QA Boozer chartmap validation #334, this branch, after review and green checks.

Already on main before this branch:

Verification

Failing before data refresh:

OMP_NUM_THREADS=1 ctest --test-dir build -R '^(test_chartmap_aphi_abscissa|generate_test_boozer_chartmap_data|test_boozer_chartmap|test_chartmap_startmode1|test_boozer_chartmap_roundtrip|test_e2e_boozer_chartmap|test_figure8_boozer_chartmap|test_coord_transform_roundtrip)$' --output-on-failure -j1
88% tests passed, 1 tests failed out of 8
test_figure8_boozer_chartmap failed because the external figure8 start.dat was a Git LFS pointer

Passing after pulling the external figure8 LFS files:

python3 -m py_compile test/tests/test_e2e_boozer_chartmap.py test/tests/boozer_chartmap_artifacts.py tools/gvec_to_boozer_chartmap.py test/tests/run_gvec_qa_roundtrip.py test/tests/test_figure8_boozer_chartmap.py
$HOME/code/prompts/scripts/check-writing-slop.py DOC/coordinates-and-fields.md
PASS: no writing-slop candidates at threshold medium
cmake -S . -B build -G Ninja
-- SIMPLE version: v1.5.0-68-g4c662b7
-- gvec Python package not found; skipping GVEC chartmap QA test
-- Configuring done
-- Generating done
cmake --build build -j2
[153/153] Linking Fortran executable test/tests/orbit/test_orbit.x
OMP_NUM_THREADS=1 ctest --test-dir build -R '^(test_chartmap_aphi_abscissa|generate_test_boozer_chartmap_data|test_boozer_chartmap|test_chartmap_startmode1|test_boozer_chartmap_roundtrip|test_figure8_boozer_chartmap|test_coord_transform_roundtrip)$' --output-on-failure -j1
100% tests passed, 7 tests passed out of 7
Total Test time (real) = 20.58 sec
OMP_NUM_THREADS=1 ctest --test-dir build -R '^test_figure8_boozer_chartmap$' --output-on-failure -j1
100% tests passed, 1 tests passed out of 1
Total Test time (real) = 5.98 sec

The long e2e test passed before the external LFS-pointer failure stopped the first
focused run:

test_e2e_boozer_chartmap ... Passed 420.24 sec

The default build Python on this machine does not provide gvec, so
test_boozer_chartmap_gvec_qa is not registered in this local CTest configuration.

Base automatically changed from feature/boozer-chartmap-realcart to main March 28, 2026 17:38
@krystophny krystophny force-pushed the feature/boozer-chartmap-gvec-qa branch from 3a42c9b to fbd730d Compare March 28, 2026 18:07
@krystophny krystophny force-pushed the feature/boozer-chartmap-gvec-qa branch from 08e0b6d to 4b1c23a Compare April 14, 2026 20:56
@krystophny krystophny enabled auto-merge (squash) April 14, 2026 21:41
- Remove duplicate test_chartmap_scaling registration in CMakeLists.txt
- Extract run_cmd() to boozer_chartmap_artifacts.py (was duplicated in
  test_e2e and test_figure8)
- Make private plot helpers public in artifacts (close_curve,
  close_surface_toroidally, sample_indices, set_equal_3d_limits) and
  import them in test_figure8 instead of redefining locally
- Extract _compare_and_summarize() from run_single_equilibrium to
  improve readability
- Add "Boozer Chartmap Mode" section to README documenting the GVEC
  workflow: convert with gvec_to_boozer_chartmap.py, configure with
  field_input/coord_input, run as usual
- Add examples/simple_chartmap.in as a commented starting point for
  chartmap-mode runs
- Reference DOC/coordinates-and-fields.md for full coordinate details
@krystophny krystophny force-pushed the feature/boozer-chartmap-gvec-qa branch from 0433f16 to 8beab16 Compare May 15, 2026 20:05
@Rykath Rykath temporarily deployed to github-pages June 1, 2026 15:23 — with GitHub Actions Inactive
@Rykath Rykath temporarily deployed to github-pages June 1, 2026 15:23 — with GitHub Actions Inactive
@krystophny krystophny changed the title Add GVEC QA Boozer chartmap validation GVEC QA Boozer chartmap validation (restack after #360) Jun 3, 2026
krystophny added a commit that referenced this pull request Jun 3, 2026
## Summary

Fix the Boozer chartmap radial contract end to end.

Changes:
- `A_phi`, `B_theta`, `B_phi`, and `Bmod` are read on the chartmap `rho`
grid. Radial derivatives are converted to `s = rho^2` by chain rule.
- Chartmap files now carry and restore `rmajor`; both chartmap field
consumers use `boozer_chartmap_io.read_boozer_chartmap`.
- `Bmod` is read on the endpoint-included `theta_field`/`zeta_field`
grid.
- Chartmap startmode=1 now stores sampled starts in reference
coordinates. The tracer returns integrator coordinates `(s, theta_B,
phi_B)`; chartmap `zstart` stores `(rho, theta_B, phi_B)`, so `sbeg=0.5`
now writes `rho=sqrt(0.5)`.
- Chartmap `generate_start_only` now stops after writing corrected
starts instead of tracing orbits.
- Grid starts use the same conversion, and their linear index stride is
fixed.
- Duplicate chartmap diagnostics were removed. The synthetic
`test_chartmap_aphi_abscissa` now covers reader metadata and the
analytic `A_phi(rho)` chain-rule contract.
- Chartmap tolerances were tightened to measured floors. The roundtrip
`Bmod` floor is the current export resolution, about `7.90e-5`; the
orbit floor is about `1.68e-9`.

Closes #358 and fixes the chartmap `sbeg` issue tracked in #359.

## Stack

Base: `main`.

Merge order:
1. Merge this PR first.
2. Restack #334 after this PR. Do not merge #334 as it stands; its
branch is based before several commits that are already on `main` and
before this fix.

Already on `main`: #329, #332, #333, #338, #340, #346, #348, #355, and
the Boozer flux-sign doc commit.

## Verification

### Test fails before the start-sampling fix

```
$ OMP_NUM_THREADS=1 ctest --test-dir build -R '^test_chartmap_startmode1$' --output-on-failure -j1
AssertionError: chartmap startmode=1 wrote s instead of rho
0% tests passed, 1 tests failed out of 1
```

### Tests pass after the fix

```
$ cmake --build build --target simple.x -j2
[25/26] Linking Fortran executable simple.x
```

```
$ OMP_NUM_THREADS=1 ctest --test-dir build -R '^test_chartmap_startmode1$' --output-on-failure -j1
100% tests passed, 0 tests failed out of 1
Total Test time (real) =   3.96 sec
```

```
$ OMP_NUM_THREADS=1 ctest --test-dir build -R '^test_chartmap_aphi_abscissa$|^test_boozer_chartmap$|^test_chartmap_scaling$|^test_boozer_chartmap_roundtrip$|^test_chartmap_startmode1$' --output-on-failure -j1
100% tests passed, 0 tests failed out of 5
Total Test time (real) =   8.43 sec
```

```
$ OMP_NUM_THREADS=1 ctest --test-dir build -R '^test_chartmap_pipeline$|^test_chartmap_rz_consistency$|^test_coord_transform_roundtrip$' --output-on-failure -j1
100% tests passed, 0 tests failed out of 3
Total Test time (real) =  94.36 sec
```

```
$ OMP_NUM_THREADS=1 ctest --test-dir build -R '^test_e2e_boozer_chartmap$' --output-on-failure -j1
100% tests passed, 0 tests failed out of 1
Total Test time (real) = 102.43 sec
```

```
$ check-writing-slop.py test/tests/test_chartmap_startmode1.py
PASS: no writing-slop candidates at threshold medium
```

### External W7X/GVEC reruns

Run with `OMP_NUM_THREADS=1` using the rebased
`fix/chartmap-aphi-rho-abscissa` build. These cases do not use
`generate_start_only`, so they were not rerun after `cf3ff9e`.

```
W7X/vmec/simple-s1-p4k:
  final confined_fraction.dat line:
  1.0000000000000000E-003  0.67993164062500000  1.4648437500000000E-003  4096

W7X/vmec2gvec/simple-f1-n50/s316-p1k:
  final confined_fraction.dat line:
  9.9999999999999980E-004  0.64746093750000000  1.0742187500000000E-002  1024
  start.dat radial min=max=0.56213877290220782 = sqrt(0.316)

W7X/vmec2gvec/simple-f1-n50/s317-p1k:
  final confined_fraction.dat line:
  9.9999999999999980E-004  0.64843750000000000  4.8828125000000000E-003  1024
  start.dat radial min=max=0.5630275304103699 = sqrt(0.317)
```
@krystophny krystophny changed the title GVEC QA Boozer chartmap validation (restack after #360) GVEC QA Boozer chartmap validation Jun 3, 2026
@Rykath
Copy link
Copy Markdown

Rykath commented Jun 4, 2026

From my side this looks good! 🎉

Comparison on W7-X with 1% beta at s=0.25 with 16k particles:

image
Name Passing Trapped Total
gvec/f1-r99-t33-z180-d0604/s25-p16k 0.671204 0.00921631 0.68042
gvec/f1-r99-t33-z180-d0604-pol/s25-p16k 0.671204 0.00970459 0.680908
vmec/s25-p16k-d0604 0.663147 0.00378418 0.666931
vmec+gvec/f1-r99-t33-z180-d0604/s25-p16k 0.666077 0.00860596 0.674683
vmec+chartmap/s25-p16k-d0604 0.663757 0.0045166 0.668274

The remaining differences are most likely due to actual differences in the equilibrium (representation).

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.

2 participants