Uh oh!
There was an error while loading. Please reload this page.
Equilibrium - BUGFIX - Make the magnetic-axis search robust to an unreliable psi-spline Hessian - #444
Draft
d-burg wants to merge 1 commit into
Draft
Equilibrium - BUGFIX - Make the magnetic-axis search robust to an unreliable psi-spline Hessian#444d-burg wants to merge 1 commit into
d-burg wants to merge 1 commit into
Conversation
…eliable psi-spline Hessian Two failure modes of `direct_position!` on otherwise healthy geqdsks, both caused by the 2-D psi spline's second derivatives near the axis (dB_z/dR wanders between ~5 and ~0 within a few cells, so the Hessian goes near-singular or indefinite): 1. "Jacobian matrix is singular" -- one bad iterate sent the undamped Newton step across the whole box, into a region where det J underflowed. 2. "Failed to find magnetic axis after 200 iterations" -- Newton cycled between two points either side of the axis on an indefinite Hessian. Fix, in two stages that leave the converging path untouched: * Cap each Newton step at one midplane-march step. Inactive for well-behaved iterations (their steps are < dr/2); it only keeps a bad iterate inside the axis neighbourhood until the Hessian recovers. A singular Hessian now returns "not converged" instead of erroring. * If Newton does not converge, locate the axis with first derivatives only: B_z changes sign across the axis along the midplane and B_r along a column, so four alternating 1-D bisections (80 iterations each, widening bracket in Z) converge to grad(psi) = 0 without touching the spline's second derivatives. Newton is retried from that point; if it still fails, the bisection point is used as the axis (it is a converged zero of the first derivatives) with an @info message instead of an error. Healthy equilibria never enter the fallback, so their results are bit-identical (regression harness: diiid_n1 47/47, diiid_slayer_n1 15/15, efit_fixedbdy_separatrix 5/5 unchanged vs 349a0c2). Two 257x257 TJ circular geqdsks reproducing each failure mode are added as fixtures with a test that both now locate the axis where the midplane B_z crossing says it is, and that a healthy geqdsk takes the plain Newton path. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Contributor
This pull request is missing an assignee and a reviewer. If you are not ready to name them, mark this pull request as a draft. |
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 freeto 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
Reading some perfectly good geqdsks (seen on 257×257 TJ circular files, two of an 81-point β scan) used to abort with
Jacobian matrix is singular near (…)orFailed to find magnetic axis after 200 iterations. The cause is the 2-D ψ spline's second derivatives near the axis, which on these files are unreliable (∂B_z/∂R wanders between ~5 and ~0 over a few cells, so the Newton Hessian goes near-singular or indefinite). The axis search now caps each Newton step at one midplane-march step, and if Newton still fails, falls back to first-derivative bisection (B_z along the midplane, B_r along a column) before retrying Newton from there. Equilibria the old code handled never enter the fallback and are bit-identical.Regression report
regress --cases diiid_n1,diiid_slayer_n1,efit_fixedbdy_separatrix --refs 349a0c262,local(349a0c2 = thedeveloptip this branch is based on). 67/67 quantities unchanged.Notes for reviewers
TJ_circular_axis_newton_regression.geqdskfixture (singular Jacobian) is fixed by the step cap alone — capped Newton converges on its own. TheTJ_circular_axis_newton_cycling.geqdskfixture (indefinite Hessian, Newton cycles) needs the bisection stage. The test asserts which path each file takes via the@infomessage, and that a healthy geqdsk (CHEASE_test_data/EQDSK_COCOS_02) takes the plain Newton path.diiid_n1energies by 0.02% and SLAYER γ by 0.2%. Newton-first with bisection as the fallback leaves the converging path untouched, hence the clean harness.error; the only remaining hard error indirect_position!is the midplane march failing to find a B_z sign change, which is a genuinely broken file.🤖 Generated with Claude Code