Repository navigation
Equilibrium - g-file reader differentiates FPOL and PRES and discards FFPRIM and PPRIME, putting rounding noise on Δ′ #504
Description
Summary
For eq_type = "efit", read_efit parses FFPRIM and PPRIME and discards them. F′ and p′ then come from cubic splines of FPOL and PRES. F′ enters the Euler-Lagrange matrices directly (jtheta = -F′), and Δ′ depends on how F′ varies across each rational surface. F changes by only a few percent across the plasma, so rounding noise in FPOL leaves F′ nearly right in value (0.04 % rms) but wrong in slope at the node scale: the error in dF′/dψ grows as roughly 1/(h²δ) (h = node spacing, δ = fractional variation of F). On 257-node g-files written in single precision this puts noise of a few units on Δ′(2/1).
Evidence
Static, in-repo file. examples/DIIID-like_ideal_example/TkMkr_D3Dlike_Hmode.geqdsk (257 nodes; every FPOL value is exactly a single-precision number). The spline F′ matches FFPRIM/F to 0.04 % rms, but its slope scatters about the FFPRIM-derived slope by up to 37 % near q = 2. No F″ is formed explicitly; the slope enters through the ψ-variation of the splined coefficient matrices:
Same state, two g-files. Five pairs of g-files of one equilibrium state (inputs agree to 1e-5) gave Δ′(2/1) differing by up to 6.2 (rms 3.7). The gap is unchanged on develop, on an identical fixed ψ grid, and with #398, #480 and #491 applied. Swapping only the FPOL block between the two files moves 82–101 % of the gap with it. Rebuilding FPOL as the integral of the file's own FFPRIM closes it (rms 0.17).
Noise ladder. Seeded relative noise on FPOL shifts Δ′(2/1) linearly, about 9e7 × noise: 0.15 at 1e-9, 2.1 at single precision (2.4e-8). The same experiment on FFPRIM is about 900 times less sensitive.
Ten g-files of different provenance. Δ′(2/1), n = 1, Riccati, auto grid:
writer, nodes, precision of FPOL |
as written | F from FFPRIM |
F and P from FFPRIM, PPRIME |
|---|---|---|---|
| TokaMaker 257, single (the in-repo example above) | 9.21 | 7.27 | 7.29 |
| TokaMaker 257, single | 5.89 | 6.25 | 6.11 |
| TokaMaker 257, single | 16.48 | 14.40 | 14.52 |
| TokaMaker 257, single | 9.43 | 9.12 | 9.10 |
| TokaMaker 257, single (near a Δ′ pole) | −29.1 | −0.03 | −39.0 |
| EFIT 257, double | −1.56 | −1.42 | −1.40 |
| kinetic EFIT 257, single | −10.10 | −6.83 | −5.46 |
| EFIT 129, single | 2.76 | 2.93 | 2.96 |
| kinetic EFIT 129, single | 3.03 | 2.86 | 3.00 |
| EFIT 65, double | −3.981 | −3.974 | −3.974 |
The effect grows with g-file resolution and with single precision: negligible at 65 nodes, about ±0.2 at 129, units at 257 single precision. Rebuilding P as well changes 2/1 by ≤ 0.14 on eight of ten files.
Caveats for a fix
FFPRIMis not clean at the end nodes of TokaMaker files (axis-node spike, last-node drop). The 2/1 result is insensitive to how these are integrated (12.35 spline quadrature, 12.50 trapezoid), but an edge 4/1 entry is not (13 as written, 35 or 50 rebuilt). A fix needs an explicit end-node treatment.- For P the question is consistency, not noise: where
PRESandPPRIMEdisagree the result moves (kinetic EFIT 257 above, and outer surfaces), and these tests do not say which array is right. - Every
efit-type result will move, including the regression cases built on the in-repo example.
Notes
- Upstream: TokaMaker's
gs_save_eqdskwrites every array asREAL(x,4). Writing doubles would reduce the noise to the 9-digit print limit (about ±0.1 here), but would not help existing files or single-precision EFIT output. - The Fortran reader has the same behaviour, and its CHEASE reader already builds P by integrating the file's dp/dψ.
- Runs: commit
1b385a504;read_efitis unchanged on develop57ec7e16a. Settings:psilow = 0.01,psihigh = 0.998,mtheta = 512,delta_mlow = delta_mhigh = 8,qlow = 1.02,dmlim = 0.2,sing_order = 6.
Activity
d-burg commentedon Oct 5, 2026
Correction to the first caveat above. The large 4/1 changes (13 as written, 35 or 50 rebuilt) came from rebuilding F alone, which leaves it inconsistent with the as-written P near the edge. With F and P both rebuilt from
FFPRIMandPPRIME:So a fix should take F and P together from
FFPRIMandPPRIME, never one alone. The end-node features remain an open but smaller question. Rebuilding P alone moves Δ′(2/1) by ≤ 0.27 on eight of the ten files; the kinetic EFIT 257 file moves by 2.1, cause not yet identified.d-burg commentedon Oct 9, 2026
Update: the writer fix is enough for new files; the GPEC-side change (#506) is parked
OpenFUSIONToolkit/OpenFUSIONToolkit#358 (merged 2026-10-07) makes TokaMaker's
gs_save_eqdskwrite doubles instead of single precision. I tested it with GPEC unchanged.Test. bouquet's public D3D-like H-mode example: four equilibria, each written by the old and the new writer from the same solver state (one OFT build with only that change added). develop
0e68a0553, n = 1, Riccati, settings as in the issue.Same state, two g-files whose inputs differ only in the last digits. rms gap in Δ′ over three states:
Why #506 is parked. Integrating FF′ and p′ needs an assumed shape between nodes, and near profile kinks that assumption moves Δ′ by more than the noise it removes.
FPOLandPRESas the trapezoid integral ofFFPRIMandPPRIME(trapezoid reproduces them to rounding); TokaMaker files with piecewise-linear profiles do not follow that rule.FFPRIMare not what moves the edge surface. Changing the axis node has no effect on Δ′, and the boundary node moves 4/1 by at most 0.4. The kinks in the pedestal foot are the cause.Still open.
FPOLis exactly single precision would at least make it visible.PSIRZmatters too: single-precision ψ(R,Z) alone puts about 0.03 on Δ′(2/1) per file on a fixed grid. Only the writer can fix that, and VAC - REFACTOR - Give the Vacuum module its own output struct #358 does.StuartBenjamin commentedon Oct 13, 2026
@d-burg thanks for the update. I tried to reproduce the "integrate moves the pedestal surfaces" result with files where I know the answer: one TokaMaker state written both as double-precision g-files and as i-files. An i-file can be written with as many surfaces as you like, so I could follow each rule as the file gets finer.
Setup
psihigh0.999 with dmlim truncation.Your effect reproduces on the 257-node g-file:
But both rules converge to the same limit as the file gets finer:
What this shows:
The Fortran integrate rule has a weakness. Fortran's
integrate(#297) uses integrated values together with the file's FF′/F as Hermite knot slopes. That makes the values and slopes slightly inconsistent, and it is the most erratic rule at 4/1 in RDCON (−17.1 … −18.6 across files). RDCON's 4/1 and 5/1 also scatter by ±0.4 and ±10 with smooth profiles, so part of that is the solver, not the profiles.What I'm doing with it:
values, as you suggested, withintegrateopt-in.Plots and scripts are available if useful.