Skip to content

KF/PE - BUGFIX! - Self-consistent xi_s for the NTV kernel input; static scheduling for the kinetic kernel loop - #425

Closed
logan-nc wants to merge 2 commits into
feature/kinetic-axis-validityfrom
bugfix/kinetic-clebsch-xi-s
Closed

KF/PE - BUGFIX! - Self-consistent xi_s for the NTV kernel input; static scheduling for the kinetic kernel loop#425
logan-nc wants to merge 2 commits into
feature/kinetic-axis-validityfrom
bugfix/kinetic-clebsch-xi-s

Conversation

@logan-nc

Copy link
Copy Markdown
Collaborator

Stacked on #422 (feature/kinetic-resonance-knots). The overnight resolution of the PE-vs-NTV torque discrepancy (issue #423's measured motivation; RESULTS.md §34–§35).

The bug

In kinetic runs, the Clebsch ξ^α fed to the NTV kernel (via dbob_m/divx_m) was re-solved from the ideal A, B, C matrices — inconsistent with the self-consistent kinetic tangential response exactly where resonant layers live. Fortran (gpeq.f, kin_flag) instead scales the stored self-consistent ξ_s by the singfac regularization factor and inverts nothing. This is the same physics flaw #407 fixes on the MatrixSplines branch (there: a silently broken Cholesky of the non-Hermitian kinetic A; here: a valid Cholesky of the wrong — ideal — A).

The consequence (measured, DIII-D kinetic-calculated full chain)

The perturbative NTV evaluation was driven by a tangential displacement that ignores the kinetic layer response, producing a phantom 4× torque concentrated in a ~2e-3-wide resonant core at the pedestal ω_E crossing (fgar: 0.7241 N·m, of which +0.622 in ψ∈[0.90, 0.95]; the self-consistent EL solution collects 0.046 there — and the EL side was verified faithful at every level: boundary ≡ volume torque to 7 digits, FKG assembly and kinetic RHS sign-by-sign Fortran-conformant per fortran-physics-reviewer, matrix-spline resolution and integrator step size both exonerated by direct null experiments).

With the fix, the phantom collapses (+0.622 → +0.033) and the two independent torque calculations agree band-by-band (resonant layer: 0.0461 vs 0.0455). Domain-matched totals (ΔIm over [ψ_c, psilim] — fgar's exact domain; the sub-ψ_c Im(u1†u2) offset is non-dissipative initial-condition content, ±0.05 with opposite signs across cases):

case (deterministic, post-:static) PE (domain-matched) fgar agreement
rot factor 0.2, reg_spot 0.05 0.1456 0.1460 0.3%
rot factor 1.0, reg_spot 0.05 0.1322 0.1655 20%
rot factor 1.0, reg_spot 0.01 0.1322 0.1397 5.4%

Where the comparison is regularization-unambiguous (rot=0.2: resonances away from rationals), the two independent torque calculations now agree to 0.3%. The rot=1.0 residual sits inside fgar's own reg_spot sensitivity band (its answer moves 18% between reg 0.05 and 0.01 — the acknowledged near-rational input ambiguity, present in Fortran too); PE is reg-independent by construction.

Second fix in this PR: determinism

CalculatedKineticMatrices.jl's per-surface kernel loop was the only threaded loop in the codebase using Threads.@threads without :static while indexing per-thread scratch by threadid() — dynamic-scheduling task migration corrupts kinetic matrix rows at rare-migration frequency. Observed live: three runs of one identical deck gave et[1] = 1.0053 / 1.1355 / 0.9895. With :static, identical decks reproduce bit-identically (verified), and et returns exactly to the pre-fix value — every historical calculated-kinetic result carries this latent race.

Effects on outputs: kinetic-run regularized quantities (xi_clebsch_alpha, *_reg fields) and every NTV torque driven by them change; ideal runs and reg_spot = 0 are bit-unaffected. Kinetic harness cases will move — new baselines with this physics justification.

Review items

⚠️ REQUIRES THIRD-PARTY HUMAN REVIEW BEFORE MERGING — NON-NEGOTIABLE. DO NOT MERGE WITHOUT AN APPROVING HUMAN REVIEW.

🤖 Generated with Claude Code

https://claude.ai/code/session_01LzbLFQKyuRE5DYZmLokKmk

logan-nc added a commit that referenced this pull request Aug 22, 2026
…iguous case); PR #425

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LzbLFQKyuRE5DYZmLokKmk
@logan-nc
logan-nc force-pushed the bugfix/kinetic-clebsch-xi-s branch from 2e168ab to d5eec3c Compare August 22, 2026 15:02
@logan-nc
logan-nc changed the base branch from feature/kinetic-resonance-knots to feature/kinetic-axis-validity August 22, 2026 15:02
@logan-nc
logan-nc force-pushed the bugfix/kinetic-clebsch-xi-s branch 3 times, most recently from 7c47c07 to 3b37787 Compare August 22, 2026 21:45
@logan-nc
logan-nc force-pushed the feature/kinetic-axis-validity branch from 530ade4 to b3d7ab9 Compare August 22, 2026 22:03
@logan-nc
logan-nc force-pushed the bugfix/kinetic-clebsch-xi-s branch from 3b37787 to 861c998 Compare August 22, 2026 22:03
logan-nc and others added 2 commits August 22, 2026 18:31
…eq.f kin_flag analog)

The Clebsch xi_alpha fed to the NTV kernel was re-solved from the IDEAL A,B,C
even in kinetic runs, inconsistent with the self-consistent kinetic tangential
response exactly where resonant layers live. Mirror Fortran: scale the stored
xi_s by the singfac regularization factor and invert nothing (analog of the
#407 fix, adapted to the FourFitVars API; kinetic-ness detected via populated
kwmats pending proper flag threading).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LzbLFQKyuRE5DYZmLokKmk
The per-surface kernel loop indexed per-thread scratch (thread_intrs and the
four matrix buffers) by threadid() under DEFAULT dynamic scheduling -- the only
threaded loop in the codebase missing :static. Task migration at yield points
lets two tasks share a buffer and corrupt matrix rows, making every
calculated-kinetic run nondeterministic at rare-migration frequency (observed:
three runs of an identical DIII-D deck gave et[1] = 1.0053, 1.1355, 0.9895).
All other threadid-indexed loops already use :static per the GPEC convention.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LzbLFQKyuRE5DYZmLokKmk
@logan-nc
logan-nc force-pushed the bugfix/kinetic-clebsch-xi-s branch from 861c998 to 225ac39 Compare August 22, 2026 22:31
@logan-nc

logan-nc commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator Author

Closing without merging — both halves are superseded, and one of my claims here needs correcting.

1. The :static fix is already on develop. Commit 9fe8a60c9 ("KineticForces - IMPROVEMENT - :static kinetic-matrix threading + typed species + shared constants") added exactly this scheduling fix, with the same reasoning in its comment. It landed after this stack forked (our fork point 9491f893d is dated 2026-08-16), so this branch never had it — which is why the nondeterminism was observable here.

Correction to this PR's description: it claimed "every historical calculated-kinetic run carries this latent race." That is wrong as written. The race is real and was real on this stack, but develop has been fixed since 9fe8a60c9; only runs on branches forked before it (like this one) are affected. The observed scatter — et[1] = 1.0053 / 1.1355 / 0.9895 on identical decks — was a symptom of the stack being behind develop, not of a live defect in develop.

2. The ξ_s self-consistency fix is owned by #407. Same file, same function, same physics (kinetic runs must regularize the stored self-consistent ξ_s rather than re-solve it from the ideal matrices, mirroring Fortran gpeq.f kin_flag). #407 is based on develop, already reviewed, and additionally adds [ForcingTerms]/[PerturbedEquilibrium] to Solovev_kinetic_calculated_example plus tracked harness quantities — the coverage this branch lacked. No reason to ask anyone to reconcile two versions of one fix.

Worth flagging for #407 and #414 reviewers: #414 forces reg_spot = 0 in self-consistent kinetic runs, and compute_clebsch_displacements early-returns when reg_spot == 0 before the kinetic branch. So once #414 lands, the kinetic branch #407 fixes is unreachable on that path — still correct, still the right safety net if regularization is ever re-enabled, but no longer load-bearing. The physics evidence for turning regularization off is in #414 and in handoff/issue376/RESULTS.md §36–§37.

The measurement this PR produced still stands and is recorded in #414: with regularization off, the NTV torque and the Euler–Lagrange solution's own dissipation agree to 0.15% (0.1324 vs 0.1322 N·m) on the DIII-D kinetic-calculated case.

Branch bugfix/kinetic-clebsch-xi-s is left in place for the record.

@logan-nc logan-nc closed this Sep 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant