Solve Boozer chartmap cold inverse on the full torus#397
Merged
Conversation
The cold Cartesian inverse of the co-rotating cart chart constrained the logical toroidal angle to the stored field-period wedge (seed scan, line search wrap, and final reduction), but the lab-frame position of that chart is only 2pi-periodic in zeta, so any target outside the first field-period sector could never converge and an exact forward-map roundtrip failed with err_max_iter. Rotate the target back by the whole field periods of its geometric angle (an exact chart symmetry), iterate zeta unwrapped, and shift the solved zeta back, returning it modulo 2pi. Accept the cold root on its final Cartesian residual against the documented accept tolerance instead of the solver exit path, whose step-size exit sits above the reachable residual on reactor-size charts. Give the Newton residual tolerance a scale-aware floor, fix the axis-degenerate gauge in the pseudo-Cartesian step, and stop wedge-wrapping the warm inverse result for co-rotating charts. Fixes #395
Review findings: the fixed cold accept tolerance could sit below the Newton's own convergence target for coarse tol_newton or very large charts, rejecting a legitimately converged root; carry the same floors in the acceptance. The warm seam test compared zeta modulo one field period and never re-evaluated the Cartesian point, masking exactly the wrong-wedge regression it guards; compare modulo 2pi and assert the reconstructed position.
krystophny
enabled auto-merge (squash)
July 16, 2026 13:34
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #395.
Problem
chartmap_from_cyl/from_carton a rotating-frame (zeta_convention="boozer") chartmap failed an exact forward-map roundtrip withchartmap_from_cyl_err_max_iterfor interior points. The cold inverse constrained the logical toroidal angle to the stored field-period wedge in three places (seed scan, line-search wrap, finalmodulo(zeta, zeta_period)), but the lab-frame position of the co-rotating cart chart satisfiesx(rho, theta, zeta + P) = Rot_z(P) x(rho, theta, zeta)— it is only 2pi-periodic in zeta. Any target whose toroidal angle lies outside the first field-period sector could therefore never converge. The warminvert_carthad the mirror defect: it located the root, then wedge-wrapped the returned zeta, silently reportingCHARTMAP_LOCATEDwith a position hundreds of cm off.Fix
chartmap_invert_accept_tol, not on the solver exit path: the Newton step-size exit fires at a Cartesian residual of order|dx/du|*tol_step, abovetol_reson reactor-size charts, which both rejected converged roots and (via the old seed-quality branch) accepted stalled ones.100*eps*|x_target|).chartmap_newton_delta_xy(cth = xw/rhois 0/eps at an exact axis seed, freezing the iteration; usecos(atan2(yw, xw))and floor the 1/rho amplification).invert_cart: return zeta modulo 2pi for co-rotating charts; the rz chart stays wedge-native.Tests (written first, RED on main)
test_chartmap_boozer_coordinates: reactor-scale (R0 = 1000 cm, nfp = 5) endpoint-excluded rotating-frame fixture; 120 deterministic interior coldfrom_cylroundtrips including rho = 0.5, angular seams, full-torus zeta, and inputs three full turns outside the stored wedge (80 of 120 failed before the fix); negative cases for past-edge targets and near-axis non-masquerade.test_chartmap_invert_cart: warm full-torus roundtrip asserting zeta mod 2pi andevaluate_cart(u)reproducing the target (silently wrong by a field-period rotation before the fix).test_boozer_chartmap_roundtrip: the issue's exact probe sequence on the exported LandremanPaul2021 QA chartmap, plus bit-for-bit invariance of the inverse acrossload_boozer_from_chartmap.fofull pipeline passes (the Fmt WARN on the two touched files pre-exists on main; per repo policy the sweep is left to the dedicated format pass).Downstream integration is tracked in itpplasma/SIMPLE#493.