Repository navigation
Tearing - FEATURE - Extract GGJ growth rates from the full matching determinant - #598
Conversation
|
@d-burg I haven't fully read through these 3 PRs yet but I can see that you did not implement this through the new API standard, and solve(TearingProblem(),GGJModel()) still errors... IMO the public syntax for this should look like this: If you agree, I will work on reviewing these as-is and get them merged, and then I can open a new PR on top of #602 and add you as a reviewer on that, where I just purely move the new functionality you have here into the planned public API above (I would prefer to do it myself to lessen the need for back-and-forths as I am still working on #602 which is the big cleanup PR). |
…eterminant Add GGJDispersion and ggj_growth_rates to Dispersion. The full Pletzer-Dewar 4m x 4m determinant (multi_surface_coupling_full), which keeps the interchange channel and the Glasser stabilization, is mapped into the SLAYER Q plane, g(Q) = mc(-i Q Q0) with Q0 = S^(-1/3)/tau_A of the reference surface, scanned with amr_scan and classified by winding number (zeros wind +1). Results are a GrowthRateResult with gamma in s^-1. Coupled and single-surface cases both work. The runner's GGJ warning and ggj_inner_deltas now point here. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…lve, refuse the branch cut, and stop the runner's GGJ placeholder Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
0ed7b88 to
3dc5f80
Compare
Bound classification circles, expanded retries, polishing trust regions and derivative probes to the GGJ positive-growth half-plane. Keep other residuals unrestricted and cover stable-root escape and nearby unstable roots with regression tests.
There was a problem hiding this comment.
We made a small change to keep classification circles, expand retries, polishing steps, and derivative probes inside γ > 0. This fixes a demonstrated DIII-D-like coupled case that returned γ ≈ −877 s⁻¹ despite a positive-growth search. Other residuals, including SLAYER, remain unrestricted. Added regression tests and corrected the branch-cut documentation.
Work to port this to the new API spec remains outstanding and I will do that on a PR stacked on top of V.
Release note
run_slayer_from_inputsnow throws for a GGJ inner model instead of returning placeholder growth rates; useggj_growth_rates(andggj_inner_deltasfor the layer's Δ).GGJ tearing growth rates can now be computed in the package.
ggj_growth_rates(multi_surface_coupling_full(...); gamma_range, omega_range)scans the full Pletzer-Dewar 4m × 4m determinant, which keeps the interchange channel and therefore the Glasser stabilization, and classifies every root by winding number. It works for coupled surfaces, and for a single surface through its own 2 × 2 block of the raw Δ′. Results come back as aGrowthRateResult, as for SLAYER.Changes since the review
8a6ae1bdd: constrain GGJ classification circles, expanded retries, polishing trust regions and derivative probes to gamma > 0; other residuals remain unrestricted. Add regression tests for stable-root escape, nearby unstable roots and boundary rejection.0ed7b88ac: the two-surface test against a direct solve, the γ-range validation, the:no_root/:winding_unresolvedwarnings, the cost and frame notes in the docstring, and the runner's GGJ path turned into an error with its dead branches removed.81fe84749), soggj_growth_ratesuses the consolidated winding classifier.Regression report
Latest full SDCC harness:
36d54d2fa(parent) versus8a6ae1bdd, all 22 cases / 44 tasks on sirius, Julia 1.12.6, pinned manifest4c9d54fa, 8 Julia threads / 4 BLAS threads. All 317 comparable quantities across 21 cases are unchanged, including uncoupled, alternate-transport, coupled and winding SLAYER cases. All tasks and report job1300503completed with exit 0. The existing eightgal_resistive_pequantities remain missing/N/A on both refs and provide no numerical validation. Report:/home/ITER/pharrm/Projects/GPEC_dev/regress-fanout/runs/pr598_8a6ae1bdd_full/report.txt.GGJ domain-fix validation: a separate SDCC study tested the exact source patch committed as
8a6ae1bdd, with the production classifier/polisher active and determinant evaluations instrumented to reject gamma <= 0. All eight study cases completed, with zero nonpositive-growth evaluations and results matching the earlier domain-limited prototype. In the DIII-D-like three-surface coupled case, the original implementation returned gamma = -876.82 s^-1 from a requested positive interval of 0.72–14410 s^-1; the fix reportsno_rooton both coarse and refined scans. This establishes containment, not proof that the search found every root. The other seven comparisons were unchanged. The study used actual raw DIII-D-like matching matrices, SLAYER-derived resistivity and rho = ion_massM_Pn_e, with no rotation shift; constructed-root benchmarks used manufactured outer matrices and real GGJ kernels. Both versions still miss the manufactured normalized-growth 0.0003 root in the tested scans, so search completeness remains a limitation.All 175 focused SDCC checks passed: GGJ growth rates (28), full matching determinant (26), winding (56), polishing (65). Study array
1300477, report job1300483; report:/home/ITER/pharrm/Projects/GPEC_dev/pr598-domain-fix-20261029/report.txt. The general harness has no coupled GGJ growth-extraction case, so this targeted study is reported separately.Earlier harness report (before the domain fix):
regress --refs fbdd6eb07,0ed7b88ac --force(all cases, against #597's head) on feynman (SLURM, 8 threads, Julia 1.11.9, manifest pinned): every case is unchanged, includingdiiid_slayer_n1_winding(17) anddiiid_slayer_n1_coupled(7);gal_resistive_peis N/A on both refs. No harness case runs the coupled GGJ path, which is reachable only through the API; the tests below cover it.runtests_dispersion_ggj.jl(15),runtests_dispersion_coupled_full.jl(26),runtests_dispersion_winding.jl(56) andruntests_slayer_runner.jl(156) pass on feynman at0ed7b88ac.Notes for reviewers
What was missing. The package could evaluate the GGJ determinant (
multi_surface_coupling_full) but had no root finder for it. The runner rejectsggj_*inner models inSLAYERControl. Its GGJ path, reachable throughrun_slayer_from_inputs, scans the tearing-only residual and warned that contour matching did not reliably find GGJ roots and that its growth rates are placeholders. GGJ γ's have therefore been computed by out-of-tree drivers.What this adds (
src/Tearing/Dispersion/GGJGrowthRates.jl, about 70 lines):GGJDispersion(mc)maps the determinant into the Q plane the SLAYER scans use,g(Q) = mc(−i·Q·Q₀), with Q₀ = S^(−1/3)/τ_A of the reference surface (GWP2016 Eq. A16). The determinant takes s = γ + iω, and the SLAYER convention is Q = τ·(−ω + iγ), so s = −iQ/τ with τ = 1/Q₀. As a result the AMR scan, the contour extraction andGrowthRateResult(gamma_Hz= γ in s⁻¹,omega_Hz= −ω in rad/s) carry over unchanged.ggj_growth_ratesrunsamr_scanover a physical box andfind_growth_rates(...; classification = :winding, zero_winding = +1)from Tearing - FEATURE - Classify tearing roots by winding number #597. The map s ↦ Q is holomorphic, so the determinant's zeros wind +1, the opposite of the SLAYER residual.The method is the one the out-of-tree driver used on the TJ circular β scans: AMR in the scaled variable, winding-number acceptance, polish. The difference is that candidates are the shared classifier's contour intersections rather than the driver's per-cell windings, so SLAYER and GGJ go through one classifier.
Tests.
:ray), with the raw Δ′ block built in the parity basis P = M⁻¹DᵀM with P₁₂ = P₂₁ = 0, which makes the determinant (P₁₁ − Δ_int)(P₂₂ − Δ_tear); P₂₂ = Δ_tear(s₀) puts a root exactly at s₀ = 0.1234·Q₀. Checks the plane convention, winding +1 and γ = s₀ to 1e-6.ggj_growth_ratesagrees with an independent complex-secant solve of the 8 × 8 determinant to 1.5e-10 relative, which also shows that the polish converges on the coupled GGJ determinant.Runner.
run_slayer_from_inputsnow throws for a GGJ inner model and points here and toggj_inner_deltas, instead of scanning the tearing-only residual and returning placeholder growth rates; its GGJ-only branches are removed. Routing[SLAYER]decks with GGJ throughggj_growth_ratesneeds the raw 2m × 2m Δ′ in the runner (it receives the m × m matrix today) and would let the function reuseSLAYERControl's scan settings; that is left for a follow-up.Domain.
gamma_rangemust lie at γ > 0. The principal square-root cut is on the negative real s-axis. Classification circles, expanded retries, polishing steps and finite-difference probes now remain strictly in the supported positive-growth half-plane; stable-root searches and continuation across the cut are not implemented. A solver failure inside the layer stops the scan rather than being turned into NaN.:no_rootand:winding_unresolvedresults warn. The docstring gives the cost: the default 40 × 40 grid alone is about 1,600 determinant evaluations, each solving every surface.Caveats. Without drifts the GGJ roots come in ±ω pairs, so either member of a pair can be reported. GGJ surfaces carry no time normalization, so no E×B Doppler shift is applied and roots are in the plasma frame.
Stacked on #597 (
feature/tearing-winding-classification), which is stacked on #577.🤖 Generated with Claude Code