Kinetic-aware equilibrium grid packing: place knots on rational and kinetic-resonance surfaces #309
Description
Sub-issue of #302.
Motivation
#302 showed the auto grid (log_asymptotic, mpsi=0) places knots by a curvature/separatrix heuristic that is blind to where the solution is actually sharp — it under-resolves the edge and, to converge, over-resolves the mid-region (~4× the knots ldp needs). The right fix is to place knots where the physics has sharp features rather than globally tightening a tolerance.
With #112 (KineticForces/NTV) merged, the grid must also serve kinetic calculations, which add new sharp radial features the current heuristic ignores:
- Rational surfaces (q = m/n). Orbit-pitch / bounce-harmonic resonances near rationals produce large, sharp kinetic features. The grid should land points on the rationals. (This also directly addresses the auto mpsi under-resolves the edge, giving spurious dW and Delta-prime #302 near-separatrix-rational symptom, independent of kinetics.)
- Kinetic resonance surfaces. The superbanana-plateau resonance near ω_E ≈ 0 and other bounce/precession resonances (Logan 2013, §IV–V) are sharp and localized. Their ψ-locations are cheaply estimable from cylindrical approximations of the resonance operator evaluated at thermal energy x = 1.
Proposal: a two-pass "form → refine grid → reform" workflow
The equilibrium↔kinetic ordering is physical: resonance frequencies (ω_b, ω_d) need the formed geometry, and rational surfaces need the q-extrema that only exist after the first build. The solver also builds psi_nodes before the field-line integration that produces the geometry, so a true single pass is impossible. Equilibrium formation is fast and the existing rerun path re-forms from the same in-memory input (no file re-read), so a second pass is cheap.
Driver flow:
- Form the equilibrium once on the default/coarse grid.
refined_psi_nodes(equil, base_nodes; kinetic_profiles, n, m-range, …)→ augmented ψ vector: union of (a) rationals q=m/n (q forced positive, via the existingsing_find!bisection on the q-spline + q-extrema) and (b) kinetic-resonance ψ where Ω(x=1; ψ) = ℓ_eff·ω_b·√x + n·(ω_E + ω_d·x) changes sign (cylindrical ω_b/ω_d from Logan 2013), each locally packed with a few knots.- Re-form on the augmented grid via the existing in-memory rerun path; discard the first pass.
Merge must guard against near-duplicate nodes. A mandatory node landing a hair from an existing one (existing […0.5, 0.6…], rational at 0.5+1e-15) creates a near-zero interval that pollutes the bicubic spline reconstruction of those surfaces with ringing. A plain unique! does not catch this. Enforce a minimum spacing δ_min (a fraction of local base spacing, not float epsilon): either snap — drop the redundant existing node, keep the mandatory one ([…0.5+1e-15, 0.6…], default) — or displace — nudge neighbors outward to open room while preserving local psi_accuracy ([…0.45, 0.5+1e-15, 0.6…]). Post-merge grid must be strictly monotone with every interval ≥ δ_min.
Minimal code surface
- Equilibrium: add optional
override_psi_nodeskwarg toequilibrium_solver/setup_equilibrium;_build_psi_gridbranches untouched. Only aVector{Float64}crosses the module boundary — no kinetic physics enters the Equilibrium foundation module. - ForceFreeStates:
rational_psi_nodes(equil; n, m-range)reusing thesing_find!root-find. - KineticForces:
refined_psi_nodes(...)(resonance locator + merge/pack), reusingBounceAveraging.jl/EnergyIntegration.find_resonance_energies.
Activation
- Rational-surface packing: always-on (benefits ideal runs too).
- Kinetic-resonance packing: auto-enabled whenever kinetic profiles are loaded.
Acceptance criteria
- Auto grid lands knots on (or symmetrically straddling) every q=m/n rational in range, including near-separatrix ones, with a few packing knots each.
- When kinetic profiles are present, knots are packed near the ω_E≈0 surface and the dominant bounce/precession resonance surfaces predicted by the x=1 cylindrical estimate.
- The auto mpsi under-resolves the edge, giving spurious dW and Delta-prime #302 case (
et[1] ≈ 0.80) converges at a total knot count comparable toldp, mpsi=256, not the ~1012 the current auto heuristic needs. - A regression case (kinetic NTV torque on an example deck) shows the refined grid reaches the converged torque at far fewer knots than uniform tightening of
psi_accuracy. - No near-duplicate nodes survive the merge: every post-merge interval ≥
δ_min, and a mandatory node withinδ_minof an existing node is resolved by snap-or-displace (no0.5 / 0.5+1e-15pairs that ring the reconstructed surfaces). - No dependency from Equilibrium onto KineticForces.
References
- Logan et al., Neoclassical toroidal viscosity in perturbed equilibria with general tokamak geometry, Phys. Plasmas 20, 122507 (2013), §IV (pitch-angle resonance) and §V (superbanana plateau) —
docs/resources/2013-Logan-...pdf. - Parent: auto mpsi under-resolves the edge, giving spurious dW and Delta-prime #302. Kinetic module: KineticForces Module (formerly PENTRC) #112.
Activity