InnerLayer.SLAYER - BUGFIX! - Use the physical toroidal field, not the b0exp normalization - #399
Conversation
…alization
run_slayer substituted `equil.config.b0exp` for the toroidal field whenever
`[SLAYER] bt` was unset (the default). b0exp is a NORMALIZATION -- commonly
exactly 1.0 -- so the layer physics ran at B_T = 1 T while the equilibrium's own
F-spline gives ~1.95 T on the DIII-D-like deck.
build_slayer_inputs already documents this exact trap:
`bt` -- toroidal field [T]. Scalar, callable of `psi`, or `nothing`
(default). When `nothing`, the physical `B_T = F(psi)/(2*pi*R_0)` is computed
per surface from the equilibrium's F-spline. Note: `equil.config.b0exp` is a
*normalization* (often just `1.0`), not the physical field, so passing it as
a scalar is almost always wrong.
Passing `control.bt` straight through restores that documented default: unset
means the physical per-surface field, and an explicitly configured bt still wins.
B_T enters c_beta (via the local beta), hence d_beta, hence the layer thickness
delta_s, and separately tau_h and so the Lundquist number and D_norm. Layer widths
on the DIII-D-like deck move by 3-15%, and the growth rates with them, so this
changes SLAYER results -- it is a correction, not a refactor.
Found by cross-checking two independent computations of the same layer width that
disagreed; with this fix they agree to ~1e-6 (the residual being that one runs on
the pass-1 equilibrium and the other on the re-formed one).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PSrf6JCViFfVzqzkQ66o6b
|
Verified the three load-bearing claims independently: The reported moves are also self-consistent with B_T going 1.0 → 1.95 T, which is independent
Two requests before merge: 1. 2. The test asserts on source text, not behaviour. It greps Harness note: this re-baselines |
|
@d-burg please address your own review requests as you are the lead developer on this section of the code and know it best. Merge when you are happy - after you submit a formal accepting review, of course ;) |
…epping source
Addresses the two review points on this branch.
Control.jl still documented `bt` as resolving to equil.config.b0exp, which is
exactly the behaviour the fix removes and the docstring a user configuring
[SLAYER] bt reads.
The regression test asserted on the literal text of run_slayer.jl, which couples
it to the formatting of a file under active refactoring, cannot catch the bug
returning by another route (defaulting control.bt to b0exp in the constructor
would leave it passing), and its third assertion was tautological -- the
occursin("F_spline", li) fallback holds for any file mentioning F_spline.
Replaced with a behavioural check where the equilibrium fixture already lives.
Since tau_h = R0*sqrt(mu0*rho)/(n*sval_r*bt), lu is linear in the field actually
used, so the resolved bt is recoverable from the returned parameters: the test
pins that the default equals F(psi)/(2*pi*R0), that an explicit bt overrides it,
and that resolving to b0exp gives a different answer.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Pushed both fixes to this branch (1fd7974).
|
|
This pull request is missing a reviewer. If you are not ready to name them, mark this pull request as a draft. |
The b0exp comparison assumed the normalization differs from the physical field. On the Solovev fixture it does not: b0exp = 1.0 and F(psi)/(2*pi*R0) = 1.0 to roundoff, which is precisely why the original defect survived there. CI caught the bad assertion. Pins the resolution rule instead, which holds on any deck: leaving bt unset is identical to passing F(psi)/(2*pi*R0) explicitly, and lu tracks an explicit bt linearly. Where the bug is actually visible -- the DIII-D-like EFIT deck, b0exp = 1.0 against a physical ~1.95 T -- is recorded in a comment. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Release note
[SLAYER] btunset — Lundquist S +94.5%, D_norm 34.8%, tauk/Q_root 36%, γ 4.4% on the DIII-D-like deck (harness @ a00ecad)[SLAYER] btto the valueequil.config.b0exphad for that deck (1.0 on the shipped ones).SLAYER was running its layer physics at the
b0expnormalization (exactly 1.0 on the shipped decks)instead of the physical toroidal field
B_T = F(ψ)/(2π·R₀)≈ 1.95 T, so the Lundquist number andevery quantity derived from it were wrong by roughly a factor of two.
Regression report
regress --cases diiid_slayer_n1 --refs develop,local, baseline develop @ faf6d03, manifest pinned.The unchanged rows are the control:
rs, the r-based shear,P_perpandiota_ecarry no B_Tdependence and do not move.
Notes for reviewers
The bug
run_slayersubstitutedequil.config.b0expfor the toroidal field whenever[SLAYER] btwas unset, which is the default:b0expis a normalization, not a field. On the DIII-D-like deck it is exactly1.0, while the equilibrium's own F-spline givesB_T = F(ψ)/(2π·R₀) ≈ 1.95 T. SLAYER has therefore been running its layer physics at roughly half the true toroidal field.build_slayer_inputsalready documents this exact trap in its own docstring:The fix
Pass
control.btstraight through. Unset then means the physical per-surface field, exactly as documented; an explicitly configuredbtstill wins. One line, plus a regression test that pins the behaviour.Impact — this changes results
B_T enters
tau_h ∝ 1/B_T, hence the Lundquist numberS = tau_R/tau_H, and separatelyc_beta(via the local β) and sod_betaand the layer thicknessdelta_s.regress --cases diiid_slayer_n1 --refs develop,local:tau_h ∝ 1/B_T, so S nearly doubleslu^(1/3)andd_beta∝ B_T^(-2/3)The unchanged rows are the check: geometry and
P_perp = tau_R/tau_perpcarry no B_T dependence, and they do not move.diiid_slayer_n1needs re-pinning.How it was found
Cross-checking two independent computations of the same layer width that disagreed by 3–15%. With this fix they agree to ~1e-6, the residual being that one runs on the pass-1 equilibrium and the other on the re-formed one.
Scope
Only the SLAYER branch of
run_slayer. The GGJ branch does not takebt. No other caller passesb0expas a field.