InnerLayer (GGJ) - NEW - rotated-ray collocation backend (:ray), robust to |Q| ~ 500 - #323
InnerLayer (GGJ) - NEW - rotated-ray collocation backend (:ray), robust to |Q| ~ 500#323matt-pharr wants to merge 42 commits into
Conversation
…location method implementation of GGJ that avoids Delta poles on the imaginary Q axis and can solve for Delta_even adn Delta_odd up to very high (at least ~500) |Q|
|
@logan-nc @d-burg this is something I have been working on with claude for a few weeks. It has a number of advantages over the galerkin GGJ solver. It uses collocation which is also a finite element method, but I learned that the reason that the galerkin solver sometimes freaks out is because there are poles to the GGJ solutions in Q space, and when you get near those poles the solutions become super oscillatory on the real axis. However, since we are solving this in a complex domain, you can show that the GGJ solutions should be entire in the complex plane, so the mercier terms in the large |X| limit are the same polynomial + coefficient even off of the real-axis (which is where the physically-relevant part of the solution lies). So you can get a much cleaner/quicker exponential decay of the non-limiting terms if you integrate on a ray that is rotated off of the real axis. This also gives way to an entirely different numerical stability check, which is to re-integrate for multiple rotation angles and see that you get the same Delta_even and Delta_odd. Overall this method is far superior to the galerkin one in all of my testing so far, and can safely go up to Q ~ 500i with a maximum error in the final Delta of ~1e-4 which is pretty good for this problem. Error stays ~1e-7 for more reasonable Q. This enables scanning to lower resistivities (Q ~ 1/eta^1/3) and higher rotation rates (or to absurd growth rates). It also makes the solve more robust for lower |Q|. I will do some more testing on this branch before I merge but I am opening it for review now. |
…ayer :ray page with provenance-tracked figures Establishes a repeatable "Journal of Computational Physics"-style documentation standard and applies it to the new GGJ rotated-ray (:ray) inner-layer backend. Standard and figure infrastructure: - docs/DOC_STANDARD.md: module-page template (equations -> numerical method -> validation figures -> API), figure-organization principle, provenance policy, and the regenerate-only-when-`depends`-change rule. - docs/figure_tools.jl: save_doc_figure stamps each PNG with the git commit/date, writes a machine-readable manifest.toml with per-figure `depends`, and centralizes the step_series spectrum helper. - Content figures now live in docs/src/figures/<module>/ (script + PNG together); docs/src/assets/ is reserved for Documenter chrome. .gitignore updated. InnerLayer page (docs/src/inner_layer.md, stub -> full page) with four computed, provenance-stamped figures: backend accuracy vs :ray along the imaginary axis, the rotated-ray/pseudo-resonance geometry, the seamless collocation<->asymptotic field match, and the Q=500i convergence error bar. Ballooning figures migrated to docs/src/figures/ballooning/ as the second exemplar and registered legacy (generators predate the provenance system). Hardening and review fixes: - regression-harness case ggj_ray_q500i (+ runner template) pinning the :ray matching data at Q=500i on the q=4 benchmark surface. - test/runtests_innerlayer.jl: internal-machinery unit tests (cheblobatto, ode_matrix, parity_rows, decaying_pair, profile diagnostics, delta_convergence). - GGJParameters.jl: corrected the rescale_delta docstring exponent (X0^(-2*sqrt(-D_I)), was mislabeled with the reciprocal sign). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Documentation for the
|
|
@matt-pharr I was having trouble understanding/trusting all your claims from the pure text descriptions above. As such, I am taking this opportunity to initiate a new, more-complete docs standard that includes figures. Figures were already creeping in (see legacy ballooning figures) and a standard was needed anyways - I figured I might as well lump it in here so i could actually see what was happening 😝 |
|
@matt-pharr can you check the "Review-related fixes folded in". |
…eld from the inner layer. Calculates penetrated field from a B_pen object that gets passed in from forcefreestates. If resistive, this comes from the inner layer model. If ideal, this is set to exactly 0. This is carried through in PerturbedEquilibrium and used for all B_pen outputs.
…_mn for gal -> PE
…ive matching default
…al for resistive matching
…p-boundary-cond-riccati
…cati Loop boundary cond riccati
|
@matt-pharr what's the plan for this one? can we merge it soon so we have fewer active PRs to juggle? |
|
@logan-nc I have kept it up to date with develop. It can be merged soon but needs some cleanup. The GGJ portion is validated but we want to see what Via's last couple of weeks of work gets us |
- Updated paths in the Fortran-Julia correspondence map to be relative to the repository. - Clarified descriptions in the kinetic NTV and resistive layer maps regarding Fortran source locations. - Modified benchmark scripts to accept Fortran run directories from environment variables or command line, removing hardcoded paths. - Improved comments and documentation across various files for clarity and consistency. - Removed unnecessary code and comments in the InnerLayer GGJ tests to enhance readability.
…solution and update related functions
…ve_inner_profile interface
…inner-layer matching function documentation
…ivity scans for delta_coil with corrected edge harmonic
…ivity scans for delta_coil with corrected edge harmonic
…ccati files for consistency
…d in favor of penetrated_area_weighted_field_inner. fallback when running kinetic to be implemented later
… ForceFreeStates and PerturbedEquilibrium structs for clarity
…ck code for penetrated field and fix some docstrings
Summary
Adds a third interchangeable GGJ inner-layer solver —
GGJModel{:ray}, a rotated-contour spectral-element collocation method — and makes it the default. It returns the same parity-projected matching data(Δ_odd, Δ_even)in the same deltac convention as:galerkinand:shooting, but stays accurate far past where both existing backends fail: validated to Q = 500i, the regime resistivity scans (|Q| ∝ η^(−1/3)) and rotation physics actually visit. The branch then integrates the layer into the RPEC outer↔inner matching pipeline: a backend-agnosticsolve_inner_profileinterface, the composite (cut + layer) inner-region solution, a corrected layer-based penetrated field, and new HDF5 outputs.The
:raybackendMethod. The layer equations are continued analytically onto the ray x = e^{iθ}s with θ = arg(Q)/4, which makes the parabolic-cylinder WKB exponent exactly real and lifts the coefficient pseudo-resonance x² ≈ −Q²(G+KF) — which sits on the real axis for imaginary Q — off the contour. On [0, s_m] a global Chebyshev spectral-element collocation BVP is solved with parity conditions at the origin and (Δ, c₁, c₂) as bordered unknowns: one sparse LU per mesh plus a rank-3 Woodbury correction for the second parity. The far-field condition reuses the existing validated inps Wasow kernel (evaluated at complex x by the new
RayAsymptotics.jl; construction untouched), applied at the series radius S and transported inward by an L-stable 2-stage Radau IIA march in the quotient modulo the decaying exponential pair. The damped-zone march runs inComplex{Double64}: at large S, Float64 linear algebra floors Δ at ~1e-4 mixing — a limit generic to any inps-based method, removed by extended precision. Since Δ is an analytic invariant of the contour angle, a θ-perturbed re-solve doubles as a built-in error bar (delta_convergence).Validation.
:galerkincross-checks at moderate Q: 1e-5–1e-9.test/runtests_innerlayer.jlgains:raytestsets (GW2020 Eq. 55 paper point vs:galerkin; q=4 physical pins at Q = 500i; θ-invariance; internal machinery units;solve_inner_profilecontract for both backends).Default change.
GGJModel()now constructsGGJModel{:ray}(). There are no bareGGJModel()call sites in the repo — all benchmark and harness uses passsolver=explicitly — and the backends take disjoint numerical-knob keywords, so stale galerkin-knob calls fail loudly rather than returning a wrong Δ.RPEC matching integration
solve_inner_profileinterface (InnerLayerInterface.jl): matching data + reconstructed layer profiles + unit conversions, so matching drivers never touch model internals. The:rayimplementation takes certified Δ from the optimal-θ contour and profiles from a θ = 0 re-solve (the on-axis pseudo-resonance is a regular point for the BVP); their Δ agreement is logged as a runtime certificate (certΔ).gal_inner_solvercontrol ("ray"default |"galerkin"), with the galerkin numerical knobs exposed asgal_inner_*TOML keys.sing_get_ua_res_cut,xi_cut/cut_range) supplies the smooth outer background the layer solution grafts onto — matching Fortran match.f intotsol, and required for the inner b^ψ profile to overlap the outer eigenfunction.B_pennow flows from ForceFreeStates into PerturbedEquilibrium viainner_bpenand contracts through the standard C_coeffs machinery. Ideal runs produce exactly zero (perfect shielding). Kinetic runs currently also report zero — the pointwise fallback was retired and a kinetic-appropriate replacement is deferred to a follow-up.delta_coil: edge coil-response block from the Riccati S-axis BVP (unit source per edge poloidal mode; one factorization, all modes as RHS columns).Outputs, docs, infrastructure
galerkin/match/inner_params/{E,F,G,H,K,M,taua,taur,v1},galerkin/match/inner/b_$i,galerkin/solution/{xi_cut, cut_range},singular/delta_coil,singular_coupling/{forcing_solution_weights, rational_area},response/psi_n.docs/DOC_STANDARD.md) with provenance-stamped, manifest-tracked figures; full InnerLayer methods page with four generated figures; citation fixes.ggj_ray_q500icomputed case (Δ at Q = 500i, 1e-4 absolute noise floor reflecting BLAS-dependent damped-zone roundoff at ~1e-5 relative).LAR_resistive_match_test/LAR_ideal_match_test— a second geometry for the matched solve, with its ideal-limit companion.Dependencies
Random(stdlib) promoted from test-extras to[deps]— fixed-seed decaying-pair extraction (provably Δ-neutral; seeded for bit-reproducibility).DoubleFloatswas already a dependency; only theusingis new.Physics motivation
On a DIII-D k_η scan the legacy galerkin layer produces a non-monotonic-in-η jump of the matched resonant field at the lowest resistivity (|Q| ≳ 1); the ray backend restores a smooth, monotonic shielding family — the inner-layer solver choice materially changes a physical prediction exactly where |Q| leaves the legacy regime. A replication-grade methods write-up exists and will accompany the paper in preparation.