KineticForces - BUGFIX! - Drop the spurious major radius from the omega_D prefactor - #391
KineticForces - BUGFIX! - Drop the spurious major radius from the omega_D prefactor#391logan-nc wants to merge 3 commits into
Conversation
…ga_D prefactor The general-aspect-ratio precession prefactor carried ro^2 where it should carry ro. wbbar = ro*2pi/((2-sigma)*I1) already contains one factor of ro that its own normalization bhat = sqrt(2T/m)/ro cancels; reusing wbbar inside wdbar imports that ro a third time, while dhat = (T/q)/(bo*ro^2) removes only the two written explicitly. Dimensionally, both bounce integrals carry the J*b*dtheta = dl length, so I1 is a length and I2/I1 is 1/Wb. With T/q in volts and V/Wb = 1/s, the prefactor 4*pi*wdfac*(I2/I1)*(T/q) is already a frequency, and the surviving ro left omega_D in m/s. Verified by holding the physics fixed and varying only the machine size: the old form scales as ro (ratio 2.0 when ro is doubled), the corrected form is ro-invariant (ratio 1.0). omega_b, built from the same I1, is untouched and keeps its correct v_th/L scaling. Julia analog of Fortran GPEC PR #281, which measured the same correction against an independently validated guiding-centre precession operator: the least-squares slope of omega_D against the reference moves from -6.49 (= -ro on that ITER equilibrium) to -1.02, with omega_b agreeing to within [0.9964, 1.0011] both before and after as the control. This changes omega_D by a factor of ro on every machine, so it moves the resonance denominator and all NTV torque. Only the magnitude is addressed here; the overall sign convention is a separate question and is not touched. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Ready for review; not yet ready to merge. The physics/code argument is complete and self-contained, so review can start now. The regression-harness table is still outstanding and is a merge gate per CLAUDE.md — I'll post it here before this is merged. Note the machine currently has other regression runs in flight, so the kinetic cases are queued behind the PR #339 re-baseline rather than run in parallel. |
Regression harness —
|
| Case | R₀ | Result |
|---|---|---|
diiid_n1 |
1.743 m | 2 changed (both NTV), 46 unchanged |
solovev_kinetic_ntv |
1.0 m | 6 unchanged |
solovev_kinetic_nuzero |
1.0 m | 5 changed, all ~1e-7 (FP noise) |
solovev_kinetic_calculated |
1.0 m | 6 changed, all ~1e-7 (FP noise) |
The only physically meaningful movement in the whole suite:
diiid_n1 develop branch Diff
NTV torque FGAR [N·m] 5.591200e-01 5.336824e-01 2.544e-02 (4.55%)
NTV kinetic energy dW FGAR [J] 6.909782e-02 7.997363e-02 1.088e-02 (15.74%)
All 46 other diiid_n1 quantities — energies, q profile, singular surfaces, Δ′, island widths, ODE steps — are exactly unchanged, which is the containment check: this patch moves omega_D and nothing else. The response is nonlinear in omega_D (it enters the resonance denominator ℓ_eff·ω_b·√x + n·(ω_E + ω_D·x)), so a 1.74× change in the frequency gives a few-percent shift in the integrated torque rather than a proportional one.
⚠️ The regression suite is nearly blind to this bug
The Solovev fixtures set r0 = 1.0 exactly (examples/Solovev_kinetic_calculated_example/gpec.toml:73). With ro = 1, ro² ≡ ro, so this fix is an algebraic no-op on every Solovev case — the ~1e-7 movements above are floating-point reassociation from writing ro * instead of ro^2 *, nothing more.
That means:
diiid_n1(R₀ = 1.743 m) is the only tracked case that exercises this at all, and only through its two NTV quantities.- A unit-magnitude major radius in the primary kinetic fixtures hides this entire class of dimensional error. Upstream needed an ITER case (R₀ = 6.411 m) to see it as a 6.4× discrepancy; at R₀ = 1.74 m it is a 1.74× error in
omega_D, and at R₀ = 1.0 m it is invisible.
Worth considering as a follow-up: either a Solovev kinetic variant with r0 ≠ 1 (cheap — the analytic equilibrium takes r0 directly), or a note in the case TOMLs that r0 = 1 makes them insensitive to major-radius scaling errors. I have not changed the fixtures in this PR, since re-baselining them here would obscure the containment result above.
Validation summary
runtests_kinetic.jl277/277.- Dimensional argument verified independently of upstream: holding physics fixed and doubling
ro,omega_Dscales as2.0before the fix (i.e. carries a length) and1.0after;omega_b, built from the same bounce integral, keeps its correctv_th/Lscaling as the control.
|
This pull request is missing a reviewer. If you are not ready to name them, mark this pull request as a draft. |
Regression re-run after re-syncing with developPR #339 merged, so this branch was updated to Every changed row on the two Solovev kinetic cases is at 0.00% relative (absolute diffs ~1e-6 to 1e-8 on O(1) eigenvalues, plus one-step ODE count moves) — they cross the harness's tight The one substantive movement is on The other 45 |
The metadata job read only requested_reviewers, which holds pending review requests. GitHub removes a reviewer from that list as soon as they submit a review, so the check went quiet while nobody had reviewed and fired once somebody did -- nagging precisely the pull requests furthest along. Treat a submitted review from anyone other than the author as evidence that a reviewer was named. Assignment alone still suffices; the reviewer never has to act. Verified against all open pull requests: silences #390, #391, #392, #407, leaves every pending-request PR untouched, and still nags the nine with nobody named. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Dh1NCejnd3fYMmcRKoQRcG
Release note
The general-aspect-ratio precession prefactor carried an extra factor of the major radius, leaving omega_D with units of m/s rather than a frequency. Torque and kinetic-energy results move on any machine whose major radius is not 1 m; the overall sign convention is a separate question and is not touched here.
What
One factor in the general-aspect-ratio precession prefactor (
src/KineticForces/BounceAveraging.jl):Julia analog of Fortran GPEC PR #281.
Why
wbbar = ro·2π/((2−σ)·I₁)already carries one factor ofro, which its own normalizationbhat = √(2T/m)/rocancels. Reusingwbbarinsidewdbarimports thatroa third time, whiledhat = (T/q)/(B₀·ro²)removes only the two written explicitly.Dimensionally: both bounce integrals carry the
J·b·dθ = dllength, soI₁is a length andI₂/I₁is 1/Wb. WithT/qin volts and V/Wb = 1/s, the prefactor4π·wdfac·(I₂/I₁)·(T/q)is already a frequency — the survivingroleftomega_Din m/s.Verification
Holding the physics fixed and varying only the machine size (both bounce integrals scale as the length they carry, so
I₂/I₁isro-independent):omega_Dratio whenrois doubledro^2)2.0ro^1)1.0ro-invariantomega_b, built from the sameI₁, is untouched and keeps its correctv_th/Lscaling (ratio0.5) — that is the control showing the change is confined to the precession prefactor.Upstream measured the same correction against an independently validated guiding-centre precession operator: the least-squares slope of
omega_Dagainst the reference moves from-6.494(median over 7 surfaces;-ro = -6.411 mon that ITER equilibrium) to-1.021, withomega_bagreeing to within[0.9964, 1.0011]both before and after.Impact — this is not a small change
omega_Dchanges by a factor ofroon every machine (≈6.4× on ITER scale). It feeds the resonance denominatorℓ_eff·ω_b·√x + n·(ω_E + ω_D·x), so all NTV torque and kinetic-δW results move. Every kinetic regression case will need re-baselining; that is expected, not a regression.Only the magnitude is addressed here. The overall sign of the precession is a separate convention question (it depends on whether
P_φ = ±q·ψ_p, which cannot be read off from the native chart) and is deliberately not touched.Validation
runtests_kinetic.jl: 277/277. Not sufficient alone — those unit tests do not exercise the pitch-integration /compute_bounce_datapaths.🤖 Generated with Claude Code