Repository navigation
Conversation
Sounds like this should be marked draft until this is done
"Should" is scary - benchmark it! There is a benchmark script for comparing to fortran - modify that for your needs (using scratch scripts - no need to commit run scripts)
Mark this as draft until the IO and benchmarks are done then ping us for reviews. You can make a "Task" type issue describing future plans (and assign yourself) so we have it on record as work in progress. |
Pull request was converted to draft
Review (combining my findings with Claude's)Structure is sound and Cole Eq. 62 is the right target. Physics claims below were checked numerically against a DIII-D-like 2/1 Checked, no action needed
Blocking
Should fix
Example is internally inconsistent
Separately, Merge readiness
Cleanup
Hygiene
SummaryCore calculation holds up better than expected: conventions consistent, branch lands where it should, α is a 4% effect. Before sign-off I'd want the item-1 test, κ̂, the example's viscous_input_type mismatch plus a re-run figure, and conflicts resolved with a fresh harness run. Cleanup can ride along. Drafted with assistance from Claude Code; physics verified numerically against origin/feature/b_crit_calculation. |
|
Chiming in without having read all of the more thorough review 😝
|
Take develop's version of every file outside the critical resonant field code: drops the formatter and whitespace churn, the edits to ForceFreeStates files develop has reorganized, the notebook, the Cole PDF, the test_ang_mom_diff kinetic dataset and the .gitignore entry. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e on Cole's Q axis solve_inner mirrors the real-Q axis, so the torque balance paired a mirrored Δ with an unmirrored Q0 and put the diamagnetic poles at −Q_e, −Q_i. Map back with conj(Δ(−Q)) so the branch lies between Q_e and Q0 as in Cole and Fitzpatrick 2006 and Fortran gslayer.f. Replace the two-largest-samples search with true local maxima, reject maxima within one grid step of a pole, derive the scan window from Q0, Q_e, Q_i as gslayer.f does, and carry κ̂ explicitly (held at 2/s² for Fortran parity). Fix the header equation and attach the docstrings. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…the layer P_tor Remove viscous_input and viscous_input_type: the torque balance now uses each surface's SLAYER P_tor, so χ_φ (or a future τ_E closure) set in InnerLayer flows through unchanged. Q0 gains the toroidal mode number, τ_k·n·ω_E, matching Q_e and Q_i, and ω_E is read at each surface's own ψ. Results use concrete types; HDF5 datasets are snake_case with metadata and the scans are written only with store_scan. The CRF block moves into the shipped SLAYER example. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Unit tests pin the Cole-axis branch (Q_e < Q_peak < Q0), the scan window, local-maximum and pole selection, P = P_tor, Q0 = τ_k·n·ω_E, TOML parsing and the HDF5 metadata contract. The diiid_slayer_n1 regression case now tracks b_r/B_φ crit and Q_peak on the inner three surfaces. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…pole region A one-grid-step exclusion lets the Q_e pole spike win on fine scans. Exclude maxima within 0.02 of Q_e and Q_i, Fortran SLAYER's pole-regularization radius, so the threshold is the maximum between Q_e and Q0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nchmark Add the Cole-Fitzpatrick torque balance, its inputs and approximations, the HDF5 outputs and the Fortran gslayer.f comparison figure to the Tearing page, cite Cole and Fitzpatrick 2006, and add the module to the API reference. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Just fyi, working on a clean-up and mostly Fortran parallel implementation of this for GPEC 2.0. One substantial change vs the above work and conversation is that now that I properly understand the diffusion inputs and metrics for the inner layer, the whole critical resonant field specific momentum input stuff is not necessary. Going forward it will just inherit the P_phi calculated for the inner layer, whether that is from chi_phi or tau_e. |
|
Modest pole avoidance will be implemented here but a more robust, database-ready version along with some other nice to have features like profile-dependent kappa, and the explicit Delta prime inlcusion will come post v 2.0. |
|
@d-burg thanks for the thorough review. Point by point: Blocking
Should fix
Example
Merge readiness
Cleanup and hygieneAll done:
🤖 Generated with Claude Code |
|
@logan-nc point by point:
🤖 Generated with Claude Code |
Release note
Tearing can now compute the critical resonant field b_r/B_φ for error-field penetration at each SLAYER surface, using the torque balance of Cole and Fitzpatrick, Phys. Plasmas 13, 032503 (2006), Eqs. 61–62. Turn it on with
[SLAYER.CriticalResonantField] enabled = true. The magnetic Prandtl number is each surface's SLAYERP_tor, so χ_φ from the kinetic file (or a future τ_E closure) carries through with no extra input. Results are written toTearing/CriticalResonantField/ingpec.h5. Resolves #371.What changed since the reviews
viscous_input/viscous_input_typeoptions, the second HDF5 read of the kinetic file, the default χ = 1 m²/s, and thetest_ang_mom_diffdataset are all gone. P is each surface'sP_tor= μ0 χ_φ/η, the same quantity the old code computed, now taken straight from SLAYER.solve_innermirrors the real-Q axis (conj Δ_Julia(−Q) = Δ_Fortran(Q)). The PR was pairing that mirrored Δ with an unmirrored Q0. The torque balance now evaluates Δ(Q) = conj(Δ_solve_inner(−Q)), so the diamagnetic poles sit at +Q_e and +Q_i and the solution branch lies between Q_e and Q0, as in Cole and in Fortrangslayer.f. Growth-rate root finding is untouched.gslayer.f: between Q0 and the Q_e pole.Qmin/Qmaxare now optional overrides.layfac).@infoinstead ofprintln, unused imports removed.store_scanis honoured;combined_resultis rebuilt fromfieldnames.br_crit,q_peak,q0,p_phi,rational_index)..gitignoreentry and the renamed example directory are removed. The CRF block now lives inexamples/DIIID-like_SLAYER_example/gpec.toml.test/runtests_critical_resonant_field.jl(28 tests) covers:diiid_slayer_n1now pins b_r/B_φ crit and Q_peak on the inner three surfaces.Fortran benchmark
Both codes were run on Fortran's normalized inputs for the DIII-D-like example: 2/1–6/1, n = 1, P = 1, κ̂ = 2/s², Q ∈ [−5, 5], 20001 points.
gpecwithsingthresh_slayer_flag, frombcrit_fine_grid@ 96d0cfbe (ebursch/GPEC). That commit fixesmaxbalthere: b_crit was always 0, and MAXLOC was off by one.SLAYERParametersbuilt from Fortran's S, τ_k, Q_e, Q_i, τ and c_β.gslayer.f(global max)The figure is also in the docs preview under Tearing → Critical resonant field. Run scripts are not committed.
Regression report
regress --cases diiid_slayer_n1,diiid_n1 --refs 4b3a7014a,acd8bca78(develop vs this branch, both fresh, manifest pinned).diiid_n1is unchanged. Indiiid_slayer_n1every layer parameter is unchanged and the two new CRF pins are recorded. SLAYER γ on the inner three surfaces differs by 0.23 Hz (0.02 %), just over the case's 0.1 Hz threshold, with Q_root and ω inside theirs. Nothing on the root-finding path changed in this PR: the only edit there is a comment inRiccati.jl, and the CRF runs after the roots are found. This is the run-to-run spread of the threaded AMR root search tracked in #420. A single-threaded rerun (GPEC_REGRESS_THREADS=1 regress --cases diiid_slayer_n1 --refs 4b3a7014a,acd8bca78 --force) confirms it: all 17 existing quantities are unchanged, with γ differing by 1.3e-5 Hz, Q_root by 5.1e-10 and ω by 5.9e-7 Hz.Notes for reviewers
P_perp_model = "tau_E"sets P_tor = τ_R/τ_E, so once it merges the 0D τ_E route logan-nc asked for reaches the critical resonant field with no further change.src/InnerLayer/SLAYER/Riccati.jlrecords that real-Q callers see a mirrored axis. The sign of SLAYER's root frequencies is a separate question, raised in the Julia-vs-Fortran SLAYER comparison, and is left alone here.🤖 Generated with Claude Code