Repository navigation
Conversation
… matrices T_xe and T_coil Build the cumulative torque response of a forward kinetic Euler-Lagrange solve on the applied root-area-weighted field (T_xe, the Fortran GPEC gpout_dw_matrix array) and in coil-set space (T_coil), write them under PerturbedEquilibrium/TorqueResponse/, and contract the run's own forcing into a cumulative torque profile. Gated by the new [PerturbedEquilibrium] compute_torque_response control. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BzKDmtKYDotJWrcxWf1oJu
…r node Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BzKDmtKYDotJWrcxWf1oJu
Collaborator
Author
|
Not urgent — @matt-pharr, this is a self-contained addition (new output only, gated off by default) and can wait behind your current work. The one thing worth a skeptical eye when you get to it is the 13 % gap between the T_xe-contracted torque and the fgar quadrature, stated as an open question in the body. |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Release note
solovev_kinetic_calculatedexample deck gains coil forcing so three torque routes are now tracked there (harness @ 8a60480)A forward kinetic solve (
integrator = "forward",kinetic_factor > 0) can now write the ψ-resolved torque response matrices of Fortran GPEC'sgpout_dw_matrix:T_xe(ψ, m, m′)on the applied root-area-weighted control-surface field andT_coil(ψ)in coil-set space, underPerturbedEquilibrium/TorqueResponse/, gated by the new[PerturbedEquilibrium] compute_torque_responsecontrol. The run's own forcing is contracted into a cumulative torque profile, andtorque_profiledoes the same for any applied spectrum.Regression report
regress --cases solovev_kinetic_calculated,diiid_n1 --refs develop,feature/pe-torque-response-matrixfrom the main repo root (job 126616):The main root's case file predates this branch, so the Solovev report there lists only the 14 pre-existing quantities (all unchanged). Re-extracted with this branch's case file (
--dbpointed at the same cache,--force, job 126618), showing the three new torque quantities:Every pre-existing quantity is unchanged. The
solovev_kinetic_calculatedcase deck now carries two analytic window-pane coil sets and[PerturbedEquilibrium], so it gains three tracked torques (TorqueResponse/total_torque,Energies/toroidal_torque,KineticForces/fgar/total_torque) and its runtime grows by the response and NTV-quadrature stages.Notes for reviewers
Construction. Per stored node
k,T_xe(ψ_k) = K†·[U₁(ψ_k)†U₂(ψ_k)]·K · 2n·i/(2μ₀)withK = U₁ₗ⁻¹·D·P·R(D = diag(1/(χ₁(m − n·q_lim)·2πi)),Pthe flux-space permeability,R = S·Athe b̃ → Φ conform). This is the Fortrandwks → bsurfmat → gind → gres → ptofchain collapsed to one edge inverse, which the globally consistentu_storebasis allows; a scratch check against the literal Fortran route (U₂U₁⁻¹,U₁/U₁ₗ, per-step) agreed to 2e-16 at a mid-ψ node.T_coil = Kc†·[U₁†U₂]·Kc·2n·i/(2μ₀)withKc = U₁ₗ⁻¹·D·P·M.Decisions the Fortran left open, and what was chosen:
T_xematches the Fortran array (no/2; "general (2×) inductance"). The physical torque isb̃†·T_xe·b̃/2, applied intorque_profileand in the storedT_applied/total_torque. With this conventionreal(T_applied[end])equalsEnergies/toroidal_torqueexactly (both reduce to−n·Im(ξ†U₂U₁⁻¹ξ)/(2μ₀); the vacuum part ofwt0is Hermitian and drops out). Note the OMFIT consumerntv_limits_of_efc.pyomits the/2and therefore reports twice the torque;pypec/post.pyoptimize_torquekeeps it.T_xeacts on b̃ (forcing_b_rootarea, the basis of the stored response matrices), not on unit-norm Φ_x —R†·gres·Ris exactly Fortran'sptof†·gres·ptofsinceptof = Σ√A = R.M[:, c]is each coil set's unit-norm Φ_x as built, at its deck currents, on the run's own boundary grid (Fortrancoilmnfromfield_bs_psicarriescoil%curtoo), soΣ_c M[:, c]reproduces the run's forcing to 1e-10 andsum(T_coil)/2 == T_appliedat every node. Driving the sets at scale factorssgivess†·T_coil·s/2. Left empty for file forcing andRMPFieldSum.imag(b̃†T_xe b̃/2) = 2n·δWof the whole Euler-Lagrange energy (ideal + kinetic), not the KineticForcestotal_energy(kinetic only) — named and annotated accordingly.nn_low != nn_high; the2nprefactor is per harmonic.Self-consistency test (
test/runtests_torque_response.jl, Solovev calculated-kinetic fixture with two window-pane coil sets): the run's forcing referred to the solution basis directly fromu_storegivesT = 1.1060988185e-3 + 2.6342971530e-2 iN·m;T_applied[end] = 1.1060988185e-3 + 2.6342971530e-2 i(agrees to 1e-15),Energies/toroidal_torque = 1.1060987849e-3(3e-8 relative, the Λ-route algebra). Also checked: the same contraction at an interior node, Hermitian/anti-Hermitian split,T_coilvsM̃†T_xe M̃, shapes vsInfo/mn_index, and the HDF5 metadata contract on the new group.Benchmark against the NTV quadrature (
examples/DIIID-like_error_field_example, C-coil only,kinetic_source="calculated",kinetic_factor=1, forward,grid_type="ldp",mpsi=64, kinetic profiles built pressure-consistent with the geqdsk; scratch deck, not committed):psihigh=0.985(ends between q=5.2 and 6), tol 1e-10Open question: the two routes differ by 13 %. They are two evaluations of the same torque from the same response and should agree better than that; I have not resolved why they do not, and this PR does not claim they agree. Best hypothesis: discretization.
T_xeinherits the torque from the Euler-Lagrange kinetic matrices — the drift-kinetic operator projected onto the (m, m′) Fourier basis, evaluated on the equilibrium ψ grid (mpsi=64) and splined — whereasfgarre-integrates the full ψ–energy–pitch integrand of the response ξ with its own adaptive quadrature, whose outer tolerance defaults tortol_psi = 1e-2and whose ψ panels are placed independently of the solve's grid. Near the edge the kinetic profile is steep (n floored at 1e17 m⁻³ at ψ_N = 1) and the response is dominated by the q = 5 resonance at ψ_N ≈ 0.974, four grid intervals from ψ_lim, so a few-percent difference in how each route resolves that region is plausible; the run's "W inverse matrix was non-Hermitian beyond tolerance at 1497 integration steps" warning is the kinetic solve's expected non-Hermiticity and is not by itself evidence for either route. The check that would settle it is a convergence sweep inmpsiandrtol_psion this deck; that is a follow-up. The HermitianT_xe(ψ_lim)is positive definite there (λ ∈ [2.6, 6.0e7] N·m/T²).Caveat observed on the way: with the example's default
psihigh=0.995(domain ending at q=6.2, just past the q=6 rational;cond(U₁) ~ 1e7–1e9over the last nodes, tol 1e-8) the identity broke —T_xeroute −110 N·m vs boundary route 1.95 N·m vs fgar 1739 N·m, andU₂U₁⁻¹at the last stored node differed from the free-boundaryW_plasmaby 300 % and from the previous node by 116 %. The construction is only as good as the edge solution it is built from; whenEnergies/toroidal_torqueandTorqueResponse/total_torquedisagree, the solve's edge is ill-conditioned. This is a property of the forward solve near a rational, not of this PR, but worth knowing before trusting either torque on such a deck.Also in passing: the stale
kinetic_sourcedocstring inForceFreeStatesControl("calculated (PENTRC — not yet implemented)") now describes the implemented path.🤖 Generated with Claude Code
https://claude.ai/code/session_01BzKDmtKYDotJWrcxWf1oJu