Repository navigation
Repo - BUGFIX! - Fix numerical edge cases in q extrema, rational surfaces, error-field correction and the 2D vacuum modes - #638
Merged
Conversation
…aces, error-field correction and the 2D vacuum modes - Equilibrium: find q′ roots per cell with the cancellation-safe quadratic formula, which also covers linear cells (q‴ = 0) that were skipped, so an exactly quadratic q keeps its extrema. - ForceFreeStates: skip a flat q interval in the rational-surface search, which never terminated when both extrema sat at the same rational q. - ErrorFields: write the NTV-limited correction-current roots without cancellation for weak residual torque; solve the joint least-squares correction with the pseudoinverse so rank-deficient arrays give the minimum-norm currents; return sampled points exactly in allowable_tolerance and interpolate an interval from scale 0 linearly. - Vacuum: reject non-contiguous poloidal mode lists in the 2D response instead of computing the wrong modes.
…ment it Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VdRsGGg4YRG6E9fgLGbpdF
logan-nc
reviewed
Nov 2, 2026
logan-nc
left a comment
Collaborator
There was a problem hiding this comment.
Review at 131c83d1b. I checked items marked ran by running them, and the rest by reading the code (traced).
What held up
- q extrema (traced and ran). In each cell q′ = b + c·x + (d/2)·x². The roots 2s/d and b/s are the cancellation-safe pair for that quadratic.
- When q‴ = 0, 2s/d is ±∞ and gets rejected, while b/s = −b/c is the linear root.
- s never reaches 0 on the two-root branch.
- The change also fixes q‴ that is tiny but not zero, where −c/d ± √… used to cancel.
- Ran: a minimum exactly on a knot is found exactly once on 15 combinations of grid size and knot position. It is neither lost nor duplicated.
- Flat segment (traced). The loop can only fail to end when dq = 0 exactly, so the guard is sufficient.
- NTV correction roots (traced). Both rewrites give the same roots in a form that avoids cancellation, given
delta_per_kat ≥ 0(it is |δ| per kAt). With zero residual torque, the upper edge used to beNaN; it is now the linear limit. pinv(traced).pinvandrank(R)share the default tolerance, so the reported rank matches the solution. Only collinearity at round-off level is cut: nearly collinear arrays still give large, opposing least-squares currents. That is correct least squares and fine for v2.0.- 2D vacuum (traced). The 3D path builds its basis from
m_modesdirectly, so only the 2D path needs the guard. - Tests. Each test is targeted, checks against an independent answer, and is fast.
- Repo rules. The stamp is at the head commit, the release note is present and the milestone is set. No PR numbers appear in the source.
Pushed: 517613152
allowable_tolerance's docstring still said the interpolation is "in the logarithms of both the scale and the risk". It now notes the linear case for a bracket that starts at scale 0.- The scale-0 test checked
0 < x < 1. The exact answer is 0.5, so it now uses≈ 0.5.
These are a docstring and a test only, so the stamp stands. Rerunning runtests_risk, _error_fields, _ntv_limits, _sing and _vacuum on that commit: pending, I'll update here.
This is not an approval. A third-party human reviewer's approval is still required before merge.
logan-nc
approved these changes
Nov 2, 2026
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.
Release note
ArgumentError; passmlow:mhigh. Deck runs are unaffected.Fixes six numerical edge cases found in a review of v2.0.0. An exactly quadratic q profile lost its interior extremum, and with it the rational surfaces on either side. The rational-surface search could loop forever on a flat rational segment. The NTV-limited correction current could come out as zero for a weak residual torque. Rank-deficient joint correction solves threw an error or returned meaningless currents.
allowable_tolerancereturnedNaNfor scans that start at scale 0. The 2D vacuum response silently computed the wrong poloidal modes for a mode list that is not contiguous.Changes
equilibrium_qfind!): each cell's q′ roots now come from the cancellation-safe quadratic formula, which also covers the linear cell (q‴ = 0) that was skipped before. Cubic splines fit a quadratic exactly on a uniform grid, so most of its cells have q‴ = 0 and the minimum was lost._find_rational_surfaces): an interval whose two extrema have the same q is skipped. If that q was rational,dm = 0and the loop never ended.correction_current,correction_current_upper): the closed-form roots are rewritten in an algebraically identical form that does not cancel when 4a·excess ≪ C².correction_requirement): the joint least-squares solve uses the pseudoinverse. Identical or collinear arrays now give the minimum-norm currents; before, a square system threwSingularExceptionand a near-singular one returned currents around 1e16 kAt.allowable_tolerance): a target equal to a sampled risk returns that sample's scale exactly, and an interval that starts at scale 0, which has no logarithm, is interpolated linearly.[1, 3]computed modes 1 and 2. Deck runs always pass contiguous ranges; only the scripting API could reach this.Each fix has a test, and each new test fails on the unfixed code. The exception is the flat-segment test, which would hang there.
Regression report
Run against the branch's base
5503af4farather than develop, so that #626, which merged after this branch was cut, does not appear in the diff. The branch merges into develop without conflicts.Notes for reviewers
--fail-on-changemisses it.🤖 Generated with Claude Code
https://claude.ai/code/session_014wKUyAaxKdTJ5ch1boMFE1