Repository navigation
InnerLayer.SLAYER - FEATURE! - 🚨 Derive the toroidal critical-Δ geometric factor in the r_s reference - #441
Conversation
d433522 to
1197cfb
Compare
Review packageToroidal Critical-Δ Review Package — a single self-contained page with the derivation (including the two notation readings that had to be checked against Eq. 61), the implementation data path showing the one place the coordinate transformation enters, the symbolic (SymPy, 12/12) and numerical verification ladder, the radial-label sensitivity tables and the TJ ε scan, with all figures embedded. Decision recorded in the PR body and the 🤖 Generated with Claude Code |
…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>
…ision for the toroidal critical-Δ Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…M-processing They are one-off physics studies, archived with their figures under CTM-processing/julia_deltaprime_harness/figures/delta_crit_toroidal/. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… the dgeo_val reference, and tighten its guards - Cite Connor, Ham, Hastie & Liu 2015 (PPCF 57 065001) everywhere the source was credited to "Connor-Hastie-Helander". - A prescribed dgeo_val must be in the r_s reference (Eq. 59's value times k_ref·v1/V_s). - toroidal_dgeo requires dV/dψ_N > 0 and a non-zero chi1; the q guard could not fire. - Name the Mercier exponent α_M so it no longer collides with Connor's α, and drop the equilibrium-specific percentages from the docstring. - The k_ref fallback warning names the critical-Δ too; ResistGeometry docs name ψ_N and the eight integrands. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nst rfitzp and the stable-D_R sign dc_tmp(:toroidal)/dc_tmp(:rfitzp) must equal dgeo/√(n|s|r_s/R₀) exactly (up to the W_d iteration's convergence), which checks the shared χ-matching prefactor end to end; a stable D_R < 0 surface must get a positive offset. The direct-evaluation and label checks are labelled as the wiring checks they are. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… case Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
dc653ed to
c0dba9f
Compare
…-ratio residual by local ε and require it to halve The old rtol = 1e-2 sat inside the measured spread of a genuine O(ε) toroidal correction and passed only because the two sampled surfaces fell under it. The residual is now bounded by the local r_s/R₀ (measured coefficient 0.15–0.18 at ε = 0.05) and must halve from ε = 0.05 to 0.025 within 10 % (measured 0.491–0.495), which a wrong O(1) factor cannot satisfy. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…te GGJ 1975 The bare | in |∇ψ|² split the Markdown table cells, truncating avg_bsq_over_dpsisq and leaving avg_dpsisq undocumented. Use ‖∇ψ_N‖, state the normalized-average convention, list the eighth integrand in the file header, and replace the Fortran routine citation in the edited resist_geometry docstring with Glasser, Greene & Johnson 1975. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…te the D_geo override An explicit dgeo_val = 0.0 only disables the offset for dc_type = :toroidal; dr_val = 0.0 disables it for every dc_type. The D_geo dataset holds the prescribed value when dgeo_val is overridden. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
D_geo is derived independently of dc_type, so the toroidal variant of the same deck tracked an identical vector twice. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e toroidal critical-Δ parallel-conduction closure dc_type = "toroidal" took Connor, Ham, Hastie & Liu 2015 (PPCF 57 065001) Eq. 59's toroidal geometry only in its final prefactor; the self-consistent W_d loop and the free-streaming χ∥ inside it still used the cylindrical field-line pitch n·s/R₀ (Fitzpatrick 1995). Both now come from the same Eq. 20 transport balance, χ⊥⟨|∇V|²⟩∂²_x = χ∥(α²Λ²/⟨B²⟩)x²: W_d = √8·(χ⊥/χ∥)^¼ / D_geo χ∥,fs = 2·v_te / (√π·K∥·W_d), K∥ = |αΛ|·r_s(dV/dr)/√⟨B²⟩ (new toroidal_kpar) K∥ is not D_geo²/r_s outside a cylinder (they differ by r_s√⟨|∇ψ_N|²⟩/k_ref, 0.57–0.76 on the DIII-D-like deck), so it is derived separately. Both reduce to the cylindrical forms at large aspect ratio (K∥ at O(ε²), D_geo at O(ε)), and the whole toroidal critical-Δ is now invariant under the choice of radial label up to k_ref. :lar and :rfitzp are algebraically unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…der the toroidal critical-Δ model With k_ref = 1 the toroidal critical Δ stayed in the ψ_N reference while Δ' was reported per r_s. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tity Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…elta-crit-geometry Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nce length for every critical-Δ model Erroring under the toroidal model only was inconsistent: with k_ref = 1 the derived toroidal critical Δ stays consistent with Δ', and the mismatch against the layer response exists under every model. This restores the behaviour the branch had before ff50706. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…cites them Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
The new toroidal closure API has inconsistent K∥ defaults and lacks validation for invalid geometry values.
Review effort: Balanced
Findings: 2
Open (2)
What changed in this PR
Derives toroidal critical-Δ geometry from equilibrium data and propagates it through SLAYER’s thermal-conduction closure.
Changes:
- Adds
D_geo,K∥, and ⟨|∇ψ_N|²⟩ calculations. - Integrates derived geometry into SLAYER and HDF5 output.
- Adds analytic, unit, and regression coverage.
THIRD-PARTY HUMAN REVIEW IS REQUIRED BEFORE MERGE.
| File | Description |
|---|---|
src/ForceFreeStates/Surfaces/ResistEval.jl |
Adds the gradient flux-surface average. |
src/InnerLayer/SLAYER/LayerInputs.jl |
Derives toroidal geometry per surface. |
src/InnerLayer/SLAYER/LayerParameters.jl |
Applies geometry to the closure. |
src/InnerLayer/SLAYER/SLAYER.jl |
Exports geometry helpers. |
src/InnerLayer/InnerLayer.jl |
Re-exports geometry helpers. |
src/Tearing/Runner/Control.jl |
Documents control semantics. |
src/Tearing/Runner/HDF5Output.jl |
Updates critical-Δ metadata. |
test/runtests_tj_analytic.jl |
Tests asymptotic and scale limits. |
test/runtests_slayer_params.jl |
Tests closure algebra. |
test/runtests_slayer_inputs.jl |
Tests geometry derivation and wiring. |
regression-harness/cases/diiid_slayer_n1.toml |
Tracks derived D_geo. |
regression-harness/cases/diiid_slayer_n1_toroidal.toml |
Adds toroidal regression coverage. |
docs/development/references.md |
Adds the Connor et al. reference. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| g_w, kpar = if dc_type === :toroidal | ||
| (dgeo_val, kpar_val === nothing ? kpar_cyl : kpar_val) | ||
| else | ||
| (sqrt((rs / R0) * abs(sval_r) * n_tor), kpar_cyl) | ||
| end |
…elta-crit-geometry
@d-burg I am getting a page not found error when trying to view the review package |
Brings in the TOML renames, the TearingProblem API and the layer-overlap cap. The toroidal critical-Δ docs, harness case and tests now use D_c_type, D_R and D_geo and the renamed :fitzpatrick offset, and the TJ analytic tests the renamed config keywords; the error for a missing dgeo_val stays removed, since this branch derives it from the surface geometry. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…reject invalid critical-Δ geometric factors A hand-built SLAYERParameters now stores the cylindrical K∥ = n·|s|/R₀ when none is given, as slayer_parameters does, instead of zero. The critical-Δ iteration rejects a non-finite or non-positive geometric factor or K∥ up front, rather than failing later with NaNs or a generic non-convergence error; dgeo_val = 0 still disables the toroidal offset. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@jhalpern30 should be fixed, can you access it now? |
…idal critical-Δ tests Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
dc_type='toroidal' used a geometric factor (STRIDE Delta_geo) that was not correct in the r_s reference length the layer matching now uses. On the DIII-D-like example it came out within 1% of 'rfitzp', while the validated derivation (Connor et al. 2015 Eq. 59 in the r_s reference, with a toroidal parallel-conduction closure; OpenFUSIONToolkit/GPEC#441) puts it 22-60% above. The option now stops with a message pointing to 'rfitzp'. STRIDE no longer computes or writes Delta_geo and keeps only the shear output SLAYER reads. dgeo_val stays in the namelist, unused, so older inputs still read. A port of the Julia derivation can follow once it is merged there. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jhalpern30
left a comment
There was a problem hiding this comment.
Seems legit, but this is quite far outside of my expertise - nothing I could offer would be more than "here is what my Claude said about your code". So if you've done all those checks yourself for accuracy, then go for it
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…elta-crit-geometry # Conflicts: # test/runtests_tj_analytic.jl
…elta-crit-geometry # Conflicts: # src/InnerLayer/SLAYER/LayerParameters.jl
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@d-burg — completed the requested full SDCC fanout comparison against develop Result: two diagnostic changes and one failed baseline run; harness exit code 1. This is not an all-pass comparison.
The release-note stamp records the tested commit, not a claim that the failed baseline case passed. Environment: Julia 1.12.6, x86_64 Linux, CI manifest pin ./regress_fanout.sh --refs 057c4af0d,a0305d167 --harness-ref a0305d167 --name pr441_a0305d167_vs_057c4af0d_20261028SDCC report: Full regression report (22 cases)Third-party human review and approval are required before merge. |
…elta-crit-geometry # Conflicts: # src/InnerLayer/SLAYER/LayerParameters.jl

Release note
D_c_type = "none"); withD_c_type = "toroidal"the critical-Δ offset is now computed from the equilibrium rather than from a user-suppliedD_geo, and its parallel-conduction closure uses the same toroidal geometry (Δ_crit +3.7 to +5.9 % from the closure on the DIII-D-like example). The HDF5 datasetTearing/PerSurface/D_geocarries derived values instead of zeros. (harness @ c72188c)D_c_type = "none"are unaffected. UnderD_c_type = "toroidal", dropD_geoto take the derived geometric factor;D_c_type = "toroidal"no longer errors when it is absent. A prescribedD_geonow means the factor in the r_s reference, i.e. Eq. 59's own value ×k_ref·v1/V_s(≈ 2 at large aspect ratio). A value that was passed as Eq. 59's own factor must be converted, or it gives about half the intended Δ_crit. Anything readingTearing/PerSurface/D_geomust now expect derived values where it previously read zeros.:larand:fitzpatrickare unchanged.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.
Left: the critical Δ at each rational surface of the DIII-D-like example under the cylindrical
fitzpatrickmodel, under the toroidal geometric factor with a cylindrical parallel-conduction closure, and under the full toroidal model. The toroidal model is 22 to 60 % abovefitzpatrick; the closure accounts for 3.7 to 5.9 % of that. Right: SLAYER growth rates with no critical Δ (the default) and under each model. The figure was made at276288065, before develop's χ_e and resistivity changes; atfa5c2596bthe toroidal 2/1 is still damped, at −230 s⁻¹ (see the regression report).Changes since the last review
3fcedcd4e, develop9a51446df). The SLAYER deck renames carry through:dc_type→D_c_type,dgeo_val→D_geo,dr_val→D_R, and the cylindrical modelrfitzp→fitzpatrick. The internal keyword arguments (dc_type,dgeo_val) keep their names.b16b95795):SLAYERParametersnow defaults K∥ to the cylindrical n·|s|/R₀, asslayer_parametersdoes, instead of zero;D_geo = 0still disables the toroidal offset.5633fc4d6): the new toroidal tests inruntests_tj_analytic.jluse the renamed TJ keywords. Test-only, after the harness stamp.36f623cf2, developdb90e824d;fa5c2596b, develop0b4b9fbfb).runtests_tj_analytic.jlbuilds its equilibria withPlasmaEquilibrium, after develop removedsetup_equilibrium.LayerParameters.jl: kept this PR's documentation table with InnerLayer.SLAYER - FEATURE! - Build P_perp from the perpendicular particle diffusivity by default and add an ion heat diffusivity profile #501'sP_perp_modelrow, and InnerLayer.SLAYER - FEATURE! - Build P_perp from the perpendicular particle diffusivity by default and add an ion heat diffusivity profile #501's keyword arguments with this PR'skpar_val; W_d uses InnerLayer.SLAYER - FEATURE! - Build P_perp from the perpendicular particle diffusivity by default and add an ion heat diffusivity profile #501'schi_perp_e.chi_perp_ekeyword and passP_perp_model = :chi_perp_e, as develop's tests in that file do, so the@test_throwschecks still fail for the reason they test.0fa614f7f): the D_geo wiring test pinsrs_method = :fluxinstead of taking its referencek_reffrom the midplane helpers, so it passes with or without InnerLayer.SLAYER - API! - Default the layer radial label to the toroidal-flux label #599's default flip. Test-only.a0305d167, develop057c4af0d); no SLAYER changes come with it.Regression report
Latest full run (2026-10-29):
regress --refs f43b5bee8,c72188cc5 --force(all cases) on feynman (SLURM, 8 threads, Julia 1.11.9, manifest pinned). Every case is unchanged exceptD_geoindiiid_slayer_n1anddiiid_slayer_n1_chi_perp_e(zeros on develop, derived values here; all γ, Q and Δ′ rows unchanged).diiid_slayer_n1_toroidalfails on develop, which has no derived factor, so the harness exits 1;gal_resistive_peis N/A on both refs.Previous SDCC fanout rerun (2026-10-28): develop
057c4af0dvsa0305d167— 22 cases; D_geo diagnostic changes; the toroidal case fails on the baseline, so the harness exits 1. Full report and limitations. This comparison also includes the existinggal_resistive_pecase with all quantities missing. Earlier reports are retained below.Previous full run, before @matt-pharr's develop merge:
regress --refs 0b4b9fbfb,fa5c2596b --force(all cases) on feynman (SLURM, 8 threads; both fresh, manifest pinned). Every case not listed here is unchanged;gal_resistive_peis N/A on both refs, as on develop. The nine SLAYER and layer test files pass atfa5c2596b.D_geo: changes from zeros to the derived factor. This is the intended change, and the only one: every layer input and every root is unchanged.diiid_slayer_n1_chi_perp_eshows the same single change.diiid_slayer_n1_toroidal: develop fails this case (D_c_type = "toroidal"without aD_geoerrors there), so it has values only at this head:fa5c2596bb16b9579590c320185fa5c2596bb16b9579590c320185Both moves come from develop, not from this PR. Since
b16b95795, Δ_crit moves by −1.2 to +3.3 % and the modes are 17–40 % more damped; the values at36f623cf2are identical tob16b95795's, so the change arrives with develop0b4b9fbfb, which brings #501's split of χ⊥ into electron and ion parts and itsD_perpdefault for P_perp. Before that, from90c320185tob16b95795, Δ_crit was 20 % lower on every surface (ratio 0.794–0.797). That comes from develop, not from this PR: develop doubled the example's χ_e and now takes Z_eff(ψ) from the kinetic file. Doubling χ⊥ alone lowers Δ_crit by 2^{−1/4} = 0.84 in the collisional limit and by 2^{−1/3} = 0.79 in the free-streaming limit (closed form in the closure section), and Z_eff enters only the collisional part of χ∥. The measured 0.795 sits in that range, near the free-streaming end. D_R and D_geo are unchanged by the merge. The tracked modes stay damped.The closure commit's own effect, measured before the develop merge (
regress --refs d0e8a0261,276288065):The per-surface numbers are in the closure section below.
D_Rand every layer input are identical.Review package
A self-contained page with the derivation, the implementation data path (where the coordinate transformation enters), the symbolic and numerical verification ladder, and all figures embedded: Toroidal Critical-Δ Review Package.
Base branch
Originally based on and targeted at
bugfix/slayer-dprime-reference-length(#403), which defines the r_s reference length K = r_s·dψ_N/dr used below. #403 has since merged intodevelop(f36ecef86), so this branch was rebased onto #403's final head12f64da8cand the PR now targetsdevelopwith a single commit.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.fitzpatrickcritical-Δ, 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 offitzpatrickat 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
fitzpatrick, so the two branches coincide there and the paper's Eq. 61 is recovered after dividing by r_s.Implementation
ResistGeometry(src/ForceFreeStates/Surfaces/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_solve_dc_tmp's0.5·(−D_R)·π^{3/2}·(χ∥/χ⊥)^{1/4}·dgeo, whose χ∥ closure now uses the same toroidal geometry (next section). It throws only ifdc_type=:toroidalis requested on a surface without aResistGeometry. An explicitD_geoin the deck (dgeo_valin the API) still overrides.Toroidal χ∥ closure
Eq. 59 needs χ∥/χ⊥. GPEC gets χ∥ by harmonically combining a collisional (Spitzer–Härm) value with a free-streaming value. That combination is solved self-consistently with the critical width W_d.
Until
276288065,:toroidalused Eq. 59's toroidal geometry only in the final prefactor. The W_d loop and the free-streaming χ∥ inside it still used the cylindrical field-line pitch n·s/R₀ (Fitzpatrick 1995, Phys. Plasmas 2 825, Eq. 132 and Sec. VII). Both now come from the balance that produces Eq. 59.The balance. Connor's Eq. 18 with the Eq. 20 coefficients, written in x = V − V_s, reads
That is χ⊥k⊥² = χ∥k∥² with k∥(x) = |αΛ|·x/√⟨B²⟩ [1/m].
Critical width. Fitzpatrick's w_D (Connor Eq. 65) is 2√2 times the cylindrical x_T. In the x̂ reference, with the same conversion K·v1 = r_s·dV/dr as D_geo:
The second relation is the same identity that links
:larand:fitzpatrick.Free-streaming χ∥. The form and the 2/√π flux-limit factor are unchanged; only k∥ changes, to its value from the balance at x = W_d·K·v1:
K∥ is computed by the new
toroidal_kpar.In a circular cylinder, αΛ = −n s B₀/(4π²R₀²r²) and K·v1 = 4π²R₀r², so K∥ = n·s/R₀. That is exactly the previous code.
K∥ is not D_geo²/r_s. Algebraically, K∥ = (D_geo²/r_s)·g, with g = r_s√⟨|∇ψ_N|²⟩/K. The metric factor g is 1 in a cylinder, but 0.57–0.76 on the DIII-D-like surfaces. Taking K∥ from D_geo would put it 24–43 % off and make χ∥ depend on the radial label. So K∥ is computed separately.
Limits.
That factor bounds the change on the DIII-D-like equilibrium (midplane label):
Measured with the
diiid_slayer_n1_toroidalharness case, which uses the same equilibrium with psihigh = 0.9995 and so also reaches the 7/1. It comparesd0e8a0261(before) with276288065(after):Every surface stays inside its free-streaming bound, and close to it: at these temperatures χ∥ is mostly free-streaming. D_R, D_geo and every layer input are bit-identical. The three tracked modes were already stable and become 3.0–7.3 % more stable.
Checks. All but the last are in the unit tests:
runtests_tj_analytic.jl): on TJ circular equilibria at ε = 0.1, 0.05 and 0.025, K∥/(n s/R₀) − 1 = (0.37–0.47)·ε². That is second order; the test requires |dev| ≤ ε² and a quartering from ε = 0.05 to 0.025. D_geo's first-order deviation is entirely the metric factor, g − 1 ≈ −2·(D_geo/D_cyl − 1), which checks the K∥–D_geo identity numerically.runtests_slayer_params.jl, Test 1e)::toroidalreproduces:larto 1e-12 and:fitzpatrickto 1e-8.dgeo_val = 0still gives no offset.runtests_slayer_inputs.jl)::midplane,:fluxand:volumeto 1e-8. The previous cylindrical closure does not have this property, because its r-based shear and r_s change with the label.D_geokeeps the derived K∥, and without aResistGeometrythe closure falls back to the cylindrical K∥ with a warning.v1_local,avg_bsqandavg_dpsisqare the normalized-average quantities the formulas need.Still a modelling choice (also in the code comments and docstrings):
:larand:fitzpatrickkeep the cylindrical geometry by definition.Verification
fitzpatrickformula through Connor's Eq. 65; the factor is invariant under B → λB and lengths → μ·lengths, while the Fortran one-power form scales as (λ/μ)^{-1/2}. The consequences that can be checked numerically are pinned by this PR's unit tests rather than by the script: the large-aspect-ratio limit and its linear ε-scaling (runtests_tj_analytic.jl), scale invariance, which the one-power form fails by √2 (runtests_tj_analytic.jl), and the exact:toroidal/:fitzpatrickprefactor identity (runtests_slayer_inputs.jl).fitzpatrickcode 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.:toroidalreproduces:larto 1e-12 and:fitzpatrickto 1e-8 (unit test). This checks the shared χ-matching prefactor. With toroidal geometry the closure checks are listed in the closure section above.toroidal_dgeowith the surface's inputs, and the radial label reaches it only throughk_ref.5633fc4d6(feynman):runtests_slayer_params.jl87/87,runtests_slayer_inputs.jl84/84,runtests_tj_analytic.jl28/28,runtests_slayer_runner.jl88/88, and the other SLAYER, GGJ and layer-overlap suites all pass.Radial-label sensitivity
The numbers below come from one-off runs, not from code in this PR, so this is how to regenerate them from the public API. On
examples/DIIID-like_SLAYER_example, form the equilibrium and a fresh Riccati Δ′, then callbuild_slayer_inputs(equil, sings, profiles; rs_method=lab, dc_type=:toroidal)and the same withdc_type=:fitzpatrick, forlabin(:midplane, :flux, :volume). The ratio of the twodc_tmpvalues, andΔ′_rs/dc_tmp, give the rows. The TJ ε scan isruntests_tj_analytic.jl's_lar_equilibrium(ε)swept over ε.DIII-D-like SLAYER example, n = 1 (Δ' diagonal reproduces #403's table: 9.097, −6.196, −16.374):
:midplane(current default):flux:volumefitzpatricktoroidalBecause dgeo ∝ K exactly and the converted Δ' ∝ K^{2μ} with μ ≈ 1/2, the toroidal threshold margin is nearly label-invariant; the cylindrical
fitzpatrickformula (∝ r_s/√(da/dψ)) is not. The residual toroidal spread in this table is ~1 % from K^{2μ−1} and ~6 % from χ∥ through the W_d loop. The table predates276288065, which makes that loop toroidal and removes the second source exactly: Δ_crit/K is now identical across labels to 1e-8 (unit test). With either branch the 2/1 sits at about half its threshold under every label, whereas withD_c_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/fitzpatrick deviation both vanish roughly linearly in ε (fitzpatrick spread 1.3–1.7 % at ε = 0.05, toroidal 0.2 %; toroidal/fitzpatrick 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
Reference-conversion exponent — decision: linear. The critical-Δ is converted from Connor's Y = (V−V_s)/V_s reference to x̂ = (r−r_s)/r_s with the linear rule (Frobenius exponent ½, exact in the paper's H = 0 ordering). The alternative would be this PR's base's K^(2α) rule with the equilibrium's Mercier exponent α = √(−D_I). Linear is the defensible choice: Δ_crit is a layer-side quantity like the slab Δ̂(Q), W_d and
fitzpatrick, all defined with the slab exponents ½ ± ½; only the outer Δ' genuinely carries ½ ± α, which is why Tearing - BUGFIX! - Convert Δ' to the r_s reference length before slab-layer matching #403 converts it with K^(2α). Applying c^(2α) to the offset would put an outer-region exponent on a quantity derived without one; the consistent generalization would be a finite-D_I layer theory with thermal conduction, which changes the structure of the D_R term and does not exist. Recorded in thetoroidal_dgeodocstring. Cost of the alternative, c^(2α−1) on Δ_crit (always stabilizing), and the residual label-covariance mismatch of the threshold under the linear rule, K^(2α−1), on the DIII-D-like equilibrium (midplane label):At the 2/1 and 3/1, where accurate γ matters most, the ambiguity is 5–7 % on Δ_crit and the label mismatch is ≤ 1 %. The 10 % mismatch at the 3/2 comes from the midplane label deep in the Shafranov-shifted core (K = 0.52), an argument for the flux label (InnerLayer.SLAYER - API - Choose one default radial label for the Fitzpatrick layer formalism #417), not for changing the exponent. The 5/1 (α = 0.83, D_R = −0.67) is outside the small-D_R ordering under either rule.
Default radial label. This PR inherits
: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 withfitzpatrickby accident of near-circularity. InnerLayer.SLAYER - API! - Default the layer radial label to the toroidal-flux label #599 makes that flip. The two PRs are independent: with both merged,D_geoandk_refmove by the same factor (0.811 on the test surface), Δ_crit/K stays label-invariant, and the tests here pass either way. Whichever merges second needs a new harness stamp.D_geois written for everyD_c_typeonce aResistGeometryexists; it is a diagnostic and does not feed the dispersion unlessD_c_type = "toroidal".🤖 Generated with Claude Code