InnerLayer.SLAYER - FEATURE! - Derive the toroidal critical-Δ geometric factor in the r_s reference - #441
Draft
d-burg wants to merge 4 commits into
Conversation
…b-layer matching The SLAYER dispersion relation paired a ψ_N-referenced BVP Δ' with an r_s-referenced layer side (Δ(Q), S=τ_R/τ_H on r_s, and the critical-Δ, whose Ŵ_d is W/r_s). Apply the Frobenius reference-length transform Δ̂_ij = K_i^(1/2+μ_i)·Δ'_ij·K_j^(μ_j−1/2), K = r_s·(dψ_N/dr)|_s, μ = √(−D_I), at the matching point. Verified parameter-free against the TJ circular benchmarks (median residual +1% over 23 points; absolute 2/1 agreement 17.5%→2.5% (β) and 17.6%→1.1% (ε)). BVP Δ' outputs are unchanged; only the SLAYER matching (γ, Δ_eff) moves. GGJ untouched. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…el options to build_slayer_inputs The cylindrical layer model needs a single minor radius; on a shaped torus that label is ambiguous. Add rs_method options :halfwidth (midplane half-chord, the shift-free stand-in for the circular-theory flux label; reproduces it to ~1% on circular benchmarks) and :volume (cylinder-equivalent √(V/2π²R₀), the Rutherford-literature convention) alongside the existing :midplane default and :fsa. Every label feeds S, the r-based shear, W_d, and k_ref together, so each choice is self-consistent by construction. Programmatic API only — not exposed via TOML; the default and all TOML-driven results are unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…nd unify the label plumbing Factor the rs_method radial-label options out of build_slayer_inputs into one exported radial_label(equil; rs_method, theta) returning (r, dr/dpsi) closures, and add a fifth label :flux — Fitzpatrick's toroidal-flux surface label (Nucl. Fusion 2025, Eq. 30), r = sqrt(2 psi_t / B0) with the g = F/(B0 R0) correction carried. All five labels now use analytic psi-derivatives from the interpolants themselves; the finite-difference stencils (which silently clamped within 1e-4 of the flux boundaries) are removed. The :fsa branch gains the max(r^2, 0) guard needed on extrapolated surfaces. k_ref and the K^(2mu) Delta-prime conversion consume the same closures, so the label choice drives S, the r-based shear, W_d and the Delta-prime reference length together for every option. Default :midplane behavior is unchanged up to the analytic-derivative refinement. Shared infrastructure for the resistive layer-overlap psihigh cap branch, which evaluates its criterion in :flux. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ic factor in the r_s reference
The Connor et al. 2015 (PPCF 57 065001) Eq. 59 geometric factor of the toroidal
critical-Δ (dc_type=:toroidal) is now derived per surface from the equilibrium
instead of requiring a user-supplied dgeo_val. `toroidal_dgeo` evaluates
V_s·(α²Λ²/(⟨B²⟩⟨|∇V|²⟩))^{1/4} with Λ = ψ_t'² ι'/2π and converts it from the paper's
Y = (V−V_s)/V_s reference to the x̂ = (r−r_s)/r_s reference shared by the slab layer,
the rfitzp critical-Δ and the reference-length-converted Δ'; the factor r_s(dV/dr)/V_s
= k_ref·v1/V_s cancels V_s. ResistGeometry gains the ⟨|∇ψ_N|²⟩ average it needs.
At large aspect ratio the factor reduces to √(n s r_s/R₀), so :toroidal coincides
with :rfitzp there; the factor is dimensionless and scales with the radial label
exactly as the converted Δ' does. The PerSurface/D_geo dataset now carries derived
values instead of zeros.
Tests: derivation wiring and label invariance (LayerInputs), large-aspect-ratio
limit and scale invariance (TJ analytic). Benchmarks regenerate the convergence,
verification, label-sensitivity and TJ ε-scan figures.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
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
dc_type = "none"); withdc_type = "toroidal"the critical-Δ offset is now computed from the equilibrium rather than from a user-supplieddgeo_val. The HDF5 datasetTearing/PerSurface/D_geocarries derived values instead of zeros. (harness @ d433522)dc_type = "toroidal"no longer errors withoutdgeo_val; passingdgeo_valstill overrides the derivation.The toroidal critical-Δ of Connor, Ham, Hastie & Liu 2015 (PPCF 57 065001, Eq. 59) can now be used on any equilibrium: its geometric factor is derived per rational surface from the flux-surface averages GPEC already computes, expressed in the same r_s reference length as the rest of the SLAYER layer stack.
Regression report
regress --cases diiid_slayer_n1,diiid_n1_riccati --refs baf674659,d433522fa(#403 head vs this branch, both freshly run, same pinned manifest, julia 1.11.6):Every SLAYER layer input (rs, shear, S, D_norm, P_perp, tauk, iota_e) and the whole Riccati case are bit-identical, as expected: with
dc_type = "none"the new code only adds theD_geodiagnostic. The single flagged line, γ at 0.01 % (0.12 Hz) with Q_root within 8e-6 and ω within 3e-5 Hz, is the threaded AMR root-search sample dependence documented on #403 and #418; no input to the dispersion changed. No tolerance or acceptance criterion was altered.Base branch
This PR is based on and targets
bugfix/slayer-dprime-reference-length(#403), because #403 defines the r_s reference length K = r_s·dψ_N/dr that the conversion below uses and rewrites the same region ofbuild_slayer_inputs. Retarget todeveloponce #403 merges.Derivation
Connor's Eq. 59, in Hamada coordinates with ψ(V) the toroidal flux, χ(V) the poloidal flux, primes d/dV, ι/2π = χ'/ψ' = 1/q, Λ = ψ'² ι'/2π, α = 2πn/χ':
In GPEC quantities (ψ_N normalized poloidal flux,
chi1 = 2π·psio= dχ/dψ_N with χ the full poloidal flux,v1 = dV/dψ_N,q1 = dq/dψ_N):Two points where the paper's notation has to be read carefully, both verified against the paper's own large-aspect-ratio limit (Eq. 61):
jac/V'weighting above. A literal 1/2π leaves a (2π)^{1/2} mismatch with Eq. 61.rfitzpcritical-Δ, and the Tearing - BUGFIX! - Convert Δ' to the r_s reference length before slab-layer matching #403-converted Δ' are all referenced to x̂ = (r−r_s)/r_s. Because Eq. 59 is derived at H = 0 (Frobenius exponent μ = 1/2), the conversion is linear: multiply by r_s(dV/dr)/V_s = K·v1/V_s. V_s cancels, so no volume integral is needed. Without this conversion Eq. 59 gives exactly half ofrfitzpat large aspect ratio (V ∝ r²).With the conversion the geometric factor reduces at large aspect ratio to √(n s r_s/R₀) with s = (r_s/q)dq/dr, which is exactly the factor inside
rfitzp, so the two branches coincide there and the paper's Eq. 61 is recovered after dividing by r_s.Implementation
ResistGeometry(src/ForceFreeStates/ResistEval.jl) gainsavg_dpsisq= ⟨|∇ψ_N|²⟩, an eighth column of the existing θ-loop.toroidal_dgeo(src/InnerLayer/SLAYER/LayerInputs.jl, exported) evaluateswith α and Λ as above.
k_ref · v1is the Y → x̂ reference conversion; this is the only place the coordinate transformation enters, andk_refis the same K thatdelta_prime_to_rs_referenceapplies to Δ'.build_slayer_inputsderivesdgeo_valwhenever the surface carries aResistGeometry(sing.restype, populated byresist_eval_all!), for everydc_type; only:toroidalconsumes it, via the unchanged_solve_dc_tmpformula0.5·(−D_R)·π^{3/2}·(χ∥/χ⊥)^{1/4}·dgeo. It throws only ifdc_type=:toroidalis requested on a surface without aResistGeometry. An explicitdgeo_valstill overrides.Verification
rfitzpcode formula: all consistent, pinning the prefactor.slayer_growthratebranch of the Fortran GPEC, which carries one power of ψ_t' in Λ instead of two, fails this by √2 and is off by ψ_t'^{-1/2} (2.3× at ε = 0.1, 3.2× at ε = 0.05). That branch also feeds D_I rather than D_R and writes log(q) asshear; none of that is used here.ResistGeometryto 1e-7–1e-4 on interior surfaces of the circular and DIII-D-like cases.k_ref(dgeo/k_refidentical across:midplane,:flux,:volumeto 1e-10; unit test).runtests_slayer_inputs.jl70/70,runtests_tj_analytic.jl20/20,runtests_slayer_params.jl49/49.Radial-label sensitivity (benchmarks)
Two benchmark scripts regenerate every figure:
benchmarks/benchmark_toroidal_delta_crit.jl(convergence, scale invariance, independent metric, DIII-D Δ_crit per surface) andbenchmarks/benchmark_delta_crit_radial_label.jl(threshold margin Δ'_rs/Δ_crit per radial label on the DIII-D-like SLAYER example with a fresh Riccati Δ', plus a TJ circular ε scan). Figures are archived in the maintainer's benchmark repo (maintainer access): figures + NOTES.md —lar_convergence.png,diiid_delta_crit_234.png,dgeo_diiid_delta_crit.png,diiid_threshold_margin_by_label.png,tj_epsilon_scan_by_label.png.DIII-D-like SLAYER example, n = 1 (Δ' diagonal reproduces #403's table: 9.097, −6.196, −16.374):
:midplane(current default):flux:volumerfitzptoroidalBecause dgeo ∝ K exactly and the converted Δ' ∝ K^{2μ} with μ ≈ 1/2, the toroidal threshold margin is nearly label-invariant; the cylindrical
rfitzpformula (∝ r_s/√(da/dψ)) is not. The residual toroidal spread is ~1 % from K^{2μ−1} and ~6 % from χ∥ through the (cylindrical) W_d loop. With either branch the 2/1 sits at about half its threshold under every label, whereas withdc_type = "none"it is unstable.TJ circular ε scan (fresh Δ' per point, surfaces 2/1 and 3/1): the label spread of the margin and the toroidal/rfitzp deviation both vanish roughly linearly in ε (rfitzp spread 1.3–1.7 % at ε = 0.05, toroidal 0.2 %; toroidal/rfitzp 1.006–1.012 midplane, 0.995–0.998 flux). No residual at small ε, so no implementation artefact; finite-ε differences are label physics.
Notes for reviewers
toroidal_dgeodocstring; a reviewer decision.:midplanefrom Tearing - BUGFIX! - Convert Δ' to the r_s reference length before slab-layer matching #403. The evidence in InnerLayer.SLAYER - API - Choose one default radial label for the Fitzpatrick layer formalism #417 and the tables above point to:flux(Fitzpatrick's toroidal-flux label, the one the layer formulas are derived in) as the default for shaped plasmas;:volumeonly coincides withrfitzpby accident of near-circularity. Flipping the default moves rs, S, shear and every SLAYER result and is deliberately left to InnerLayer.SLAYER - API - Choose one default radial label for the Fitzpatrick layer formalism #417 as its own!-tagged PR.D_geois written for everydc_typeonce aResistGeometryexists; it is a diagnostic and does not feed the dispersion unlessdc_type = "toroidal".NO MERGE WITHOUT HUMAN REVIEW. This PR is a draft and requires a named human reviewer and an assignee before it can be considered for merge. This is non-negotiable.
🤖 Generated with Claude Code