Skip to content

Commit 8315b5a

Browse files
d-burgclaude
andcommitted
InnerLayer.SLAYER - NEW FEATURE - Add halfwidth and volume radial-label 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>
1 parent 5e646b3 commit 8315b5a

2 files changed

Lines changed: 44 additions & 3 deletions

File tree

src/InnerLayer/SLAYER/LayerInputs.jl

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
using ..Utilities: KineticProfiles
1717
using ...Utilities.NeoclassicalResistivity: NeoResistivityModel, SpitzerModel,
1818
coulomb_log_e, nu_star_e
19-
using FastInterpolations: DerivOp
19+
using FastInterpolations: DerivOp, integrate
2020

2121
"""
2222
surface_minor_radius(equil, psi; theta=0.0) -> Float64
@@ -114,6 +114,20 @@ profiles, without an intermediate file round-trip.
114114
a prescribed value. (For `dc_type=:rfitzp` and `:lar`, dgeo_val is
115115
not consulted.)
116116
- `dc_type` -- `:none` (default), `:lar`, `:rfitzp`, or `:toroidal`.
117+
- `rs_method` -- radial label defining `r_s` for the whole layer stack
118+
(S, r-based shear, W_d, and the Δ' reference-length factor `k_ref` all
119+
follow it together, so every choice is self-consistent). `:midplane`
120+
(default): outboard-midplane chord from the magnetic axis — natural for
121+
comparison with midplane diagnostics. `:halfwidth`: midplane half-chord
122+
`(R_out − R_in)/2` — shift-free, the closest stand-in for the circular
123+
flux label the Fitzpatrick layer formulas are derived in (reproduces the
124+
cylindrical-theory label to ~1% on circular benchmark equilibria).
125+
`:fsa`: θ-mean surface radius. `:volume`: cylinder-equivalent label
126+
`√(V(ψ)/(2π²R₀))`, the Rutherford-literature convention. On shaped
127+
equilibria the labels agree at low-q surfaces (~±3% in growth rate at
128+
q=2) and diverge strongly near the edge, where the slab-layer matching
129+
is label-ambiguous regardless of choice. Not exposed via TOML —
130+
programmatic use only.
117131
- `theta` -- poloidal angle at which to measure minor radius (default
118132
`0.0`, outboard midplane).
119133
- `resistivity_model` -- `SauterNeoModel()` (default), `RedlNeoModel()`,
@@ -158,7 +172,9 @@ function build_slayer_inputs(equil, sings, profiles::KineticProfiles;
158172

159173
# Minor-radius extractor: `:midplane` = outboard-midplane chord
160174
# (original behavior); `:fsa` = θ-mean of √rzphi_rsquared, the
161-
# flux-surface-averaged minor radius.
175+
# flux-surface-averaged minor radius; `:halfwidth` = midplane half-chord
176+
# (R_out − R_in)/2, the shift-free circular flux label; `:volume` = the
177+
# cylinder-equivalent label r_V = √(V(ψ)/(2π²R₀)).
162178
_rs_at(ψ) =
163179
if rs_method === :fsa
164180
integrand(θ) = sqrt(equil.rzphi_rsquared((Float64(ψ), Float64(θ))))
@@ -168,11 +184,18 @@ function build_slayer_inputs(equil, sings, profiles::KineticProfiles;
168184
s += integrand((k - 0.5) / N)
169185
end
170186
s / N
187+
elseif rs_method === :halfwidth
188+
0.5 * (surface_minor_radius(equil, ψ; theta=0.0) +
189+
surface_minor_radius(equil, ψ; theta=0.5))
190+
elseif rs_method === :volume
191+
lo = 1e-4
192+
V = integrate(equil.profiles.dVdpsi_spline, lo, Float64(ψ))
193+
sqrt(max(V, 0.0) / (2π^2 * equil.ro))
171194
else
172195
surface_minor_radius(equil, ψ; theta=theta)
173196
end
174197
_da_dpsi_at(ψ) =
175-
if rs_method === :fsa
198+
if rs_method !== :midplane
176199
# central finite difference on _rs_at
177200
h = 1e-5
178201
lo = ψ - h

test/runtests_slayer_inputs.jl

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,24 @@
158158
@test sl_var[1].P_perp sl_s[1].P_perp * 6.0 / 2.0 rtol = 1e-10
159159
end
160160

161+
@testset "build_slayer_inputs: rs_method radial labels are self-consistent" begin
162+
sings = [_mk_sing(psi=0.5, q=2.4, q1=1.2, m=2, n=1)]
163+
got = Dict{Symbol,Any}()
164+
for rsm in (:midplane, :halfwidth, :fsa, :volume)
165+
sl = build_slayer_inputs(equil, sings, profiles; bt=2.0, dr_val=0.0, rs_method=rsm)
166+
got[rsm] = sl[1]
167+
@test isfinite(sl[1].rs) && sl[1].rs > 0
168+
@test isfinite(sl[1].k_ref) && sl[1].k_ref > 0
169+
@test isfinite(sl[1].sval_r)
170+
end
171+
# The outboard-shifted axis compresses the outboard chord, so the shift-free
172+
# half-chord is at least the outboard axis-to-edge distance.
173+
@test got[:halfwidth].rs >= got[:midplane].rs
174+
# Labels genuinely differ (each self-consistent set has its own rs, S, k_ref)
175+
@test got[:fsa].rs != got[:midplane].rs
176+
@test got[:volume].lu != got[:midplane].lu
177+
end
178+
161179
@testset "build_slayer_inputs: dc_type propagates and dr_val activates offset" begin
162180
sings = [_mk_sing(psi=0.5, q=2.4, q1=1.2, m=2, n=1)]
163181

0 commit comments

Comments
 (0)