Repository navigation
Tearing - BUGFIX - Doppler-shift each GGJ surface into its own E×B frame in the coupled growth rates - #612
Conversation
…ame in the coupled growth rates GGJ is a plasma-frame layer, so rotation enters only as a Doppler shift: surface k sees s + i·n·Ω_E,k. surface_coupling(::GGJModel, ...) takes omega_E and n, and one layer_argument helper applies each model's shift (real on SLAYER's Q, imaginary on GGJ's s) in the scalar, reduced and full determinants. Tests: a common rotation only shifts ω; a differential one moves the coupled γ, and only the relative rotation matters. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0186CLfjeJeSusNTva5RMfGU
|
Merged develop into this branch at 7056464 so it sits on top of the kinetic-profiles move (#581); the merge was clean and the diff against develop is still exactly your commit. At that head, on alfven with 3 threads: runtests_dispersion_ggj 33/33, dispersion_rotation 20/20, dispersion_winding 56/56, dispersion_amr 50/50, slayer_profile_transport 20/20, dispersion_coupled 43/43, dispersion_coupled_full 26/26, slayer_runner 164/164. Nothing else touched. |
…te the GGJ rotation tests Remove the unreachable _q_shift fallback, which would silently drop E×B rotation for a non-SLAYER surface; note in the ggj_growth_rates docstring that omega_range must cover the lab-frame ω when rotation is set; share one secant helper in the GGJ coupled tests and drop the assertions that restate the implementation or repeat the frame-change check. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VdRsGGg4YRG6E9fgLGbpdF
|
Reviewed #612 and pushed the fixes as Physics: correct. Mapping SLAYER's existing shift Changed in
Verification: the dispersion GGJ, rotation, coupled, coupled-full, SLAYER-runner and critical-resonant-field test files pass on alfven at Deferred to the GGJ runner port: the Still needs a human approval before merge; matt-pharr is requested. |

Release note
Coupled GGJ growth rates can now account for differential E×B rotation between rational surfaces. Each GGJ surface is evaluated in its own rotating frame,
surface_coupling(GGJModel(), params, dp_diag; omega_E=Ω_E, n=n). Before this, every coupled surface saw the same frequency, which is correct only when the surfaces rotate together.Closes #611
Regression report
regress --refs 10ec452da,705646449 --force(all cases, after develop with #581 was merged in) on feynman (SLURM, 8 threads, Julia 1.11.9, manifest pinned): every case is unchanged, includingdiiid_slayer_n1,diiid_slayer_n1_coupledanddiiid_slayer_n1_winding;gal_resistive_peis N/A on both refs, as on develop. No harness case runs the coupled GGJ path, which is reachable only through the API. The five test files below also pass on feynman (the runner file now has 164 tests).On the Mac (Julia 1.11.6) at
4f7f6657e:runtests_dispersion_ggj.jlpasses 33/33, including the 5 new rotation tests.runtests_dispersion_coupled.jl(43),runtests_dispersion_coupled_full.jl(26),runtests_dispersion_residual.jl(20) andruntests_slayer_runner.jl(156) pass unchanged.Follow-up at
c62678e11(review fixes, pushed by @logan-nc): deletes the unreachable_q_shift(::InnerLayerParameters, ::Real) = 0.0fallback in the runner, notes in theggj_growth_ratesdocstring thatomega_rangemust cover the lab-frame ω when rotation is set, and trims the rotation tests (one shared secant helper; the==wiring check and the second frame-invariance check are dropped as covered by the common-rotation root test). Itssrc/changes are a dead-method deletion and docstring/comment text, so the harness result at705646449carries over; no case reaches the coupled GGJ path. On alfven atc62678e11:runtests_dispersion_ggj(31),_dispersion_rotation(20),_dispersion_coupled_full(26),_dispersion_coupled(43),_slayer_runner(164) and_critical_resonant_field(71) pass.Notes for reviewers
Why. GGJ is derived in the plasma frame. Rotation enters its equations only beyond the order the derivation keeps (Johnson & Greene 1967, Plasma Phys. 9, 611, Appendix B), so its rotation physics is a Doppler shift. There is no differential rotation inside one layer, but there is between layers. With the determinant scanned in the lab frame, surface k must see s_k = s + i·n·Ω_E,k. This is SLAYER's existing frame change,
Q_layer = τ_k·ω_lab − τ_k·n·Ω_E, written in GGJ's variable s = γ + iω (s = −i·Q·Q₀). Thanks to @matt-pharr for pointing this out.Change.
surface_coupling(::GGJModel, ...)takesomega_E(rad/s, per unit n, as in SLAYER) andn, and storesq_shift = n·omega_E. A nonzeroomega_Ewithoutn ≥ 1throws.layer_argument(sc, x), applies each model's shift in its own frequency variable: added to SLAYER's normalized Q, and asi·q_shiftto GGJ's s. It is used at all three evaluation sites (the scalarSurfaceCoupling, the reducedMultiSurfaceCouplingand the fullMultiSurfaceCouplingFull), so there is no second Doppler path.Q·ratio + q_shift.Tests, on the existing two-surface coupled fixture:
omega_Ewithoutnthrows.Not in this PR.
TearingProblembelongs to the plannedsolve(TearingProblem(...), GGJModel(...))port, which can pass the sameomega_Eper surface that the SLAYER runner uses.ωis reported with rotation set (lab frame) is stated in theggj_growth_ratesdocstring.🤖 Generated with Claude Code