You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Cross-platform golden-record drift in Lambda_A (~4.6e-7 relative) is caused by adaptive quadrature in src/utils/integrate.f90 amplifying ULP-level libm differences. A three-version comparison confirms the drift is purely environment, not code, and reproduces the macOS-vs-Linux symptom already described in #88. The open question is whether to widen the tolerance (#88) or make the quadrature reproducible, which connects to the libneo/fortnum quadrature-replacement work.
What was measured
The golden-record corpus build (plasma/proj/golden/rabe) ran the landremanpaul2021_QH_lowres case three ways and compared with compare_golden.py:
A: the committed historical test/golden/expected/rabe.nc (original binary, original build environment).
B: the same source rebuilt at commit a8c3b21 with the current toolchain (gfortran 14.2.0).
A vs B (compiler/environment): Lambda_A 4.6e-7, remainder 6.0e-8, Lambda_S 3.6e-9, lambda_LC_bB 2.8e-9, nu_star_crit 1.7e-10; s_tor, split_maxima, R exact.
B vs C (code change a8c3b21 -> main): all nine variables bitwise identical.
A vs C: identical to A vs B.
So all observed drift between the historical record and a current build is environment. No code change between a8c3b21 and main moves any output. The Lambda_A 4.6e-7 and the ~3e-9 floor match #88 exactly ("~4e-7 for Lambda_A through libm and adaptive-quadrature differences").
Mechanism
Lambda_A, nu_star_crit, and remainder are the variables that go through integrate_1d in src/utils/integrate.f90, which calls quadpack dqag (globally adaptive subdivision, jacobwilliams/quadpack via cmake/quadpack.cmake). The integrand is evaluated through libneo field/spline routines (pinned at libneo 752aae9c in cmake/libneo.cmake). Adaptive subdivision turns ULP-level libm and field-evaluation differences into a different sequence of panels, so the error lands two orders of magnitude above the 3e-9 floor of the non-quadrature outputs. The 3e-9 outputs are direct arithmetic; the 4.6e-7 outputs are the adaptive integrals.
This is the same class of non-reproducibility the libneo modularization and fortnum effort target (itpplasma/libneo#291): adaptive quadrature and special functions whose results depend on the math library and link configuration.
Why this is worth more than a tolerance bump
#88 widens the golden tolerance to 1e-6 and #86 reverted both that and the quadpack link change (#87). Widening to 1e-6 still catches algorithmic regressions (which start at 1e-3), but it hides whether Lambda_A's 4.6e-7 is benign rounding or an ill-conditioned integrand. The two-order gap between the quadrature outputs and the floor is the signal worth checking: a near-singular integrand plus a loose epsabs/epsrel in dqag would produce exactly this, and would also explain the macOS reproduction failures.
Concrete questions:
Is the Lambda_A integrand near-singular at the substitution boundaries (integrate_1d_substituted)? What epsabs/epsrel/limit does dqag use, and does tightening them shrink the cross-platform spread?
Does pinning vs bumping libneo (the field/spline side of the integrand) change Lambda_A independently of the quadrature? Test with LIBNEO_BRANCH against the pinned 752aae9c.
Use the golden-record corpus to separate the two regimes instead of one tolerance:
Same-machine ref-vs-cur (the gr-runner build_ref vs build_cur model) stays strict (1e-10): catches real code changes to machine precision.
Cross-platform / cross-compiler check runs at the looser tolerance, documented as the libm + adaptive-quadrature floor, until the quadrature is made deterministic.
Summary
Cross-platform golden-record drift in
Lambda_A(~4.6e-7 relative) is caused by adaptive quadrature insrc/utils/integrate.f90amplifying ULP-levellibmdifferences. A three-version comparison confirms the drift is purely environment, not code, and reproduces the macOS-vs-Linux symptom already described in #88. The open question is whether to widen the tolerance (#88) or make the quadrature reproducible, which connects to the libneo/fortnum quadrature-replacement work.What was measured
The golden-record corpus build (
plasma/proj/golden/rabe) ran thelandremanpaul2021_QH_lowrescase three ways and compared withcompare_golden.py:test/golden/expected/rabe.nc(original binary, original build environment).main(1e5ef76), current toolchain.Result:
Lambda_A4.6e-7,remainder6.0e-8,Lambda_S3.6e-9,lambda_LC_bB2.8e-9,nu_star_crit1.7e-10;s_tor,split_maxima,Rexact.So all observed drift between the historical record and a current build is environment. No code change between a8c3b21 and main moves any output. The
Lambda_A4.6e-7 and the ~3e-9 floor match #88 exactly ("~4e-7 for Lambda_A through libm and adaptive-quadrature differences").Mechanism
Lambda_A,nu_star_crit, andremainderare the variables that go throughintegrate_1dinsrc/utils/integrate.f90, which calls quadpackdqag(globally adaptive subdivision, jacobwilliams/quadpack viacmake/quadpack.cmake). The integrand is evaluated through libneo field/spline routines (pinned at libneo 752aae9c incmake/libneo.cmake). Adaptive subdivision turns ULP-levellibmand field-evaluation differences into a different sequence of panels, so the error lands two orders of magnitude above the 3e-9 floor of the non-quadrature outputs. The 3e-9 outputs are direct arithmetic; the 4.6e-7 outputs are the adaptive integrals.This is the same class of non-reproducibility the libneo modularization and fortnum effort target (itpplasma/libneo#291): adaptive quadrature and special functions whose results depend on the math library and link configuration.
Why this is worth more than a tolerance bump
#88 widens the golden tolerance to 1e-6 and #86 reverted both that and the quadpack link change (#87). Widening to 1e-6 still catches algorithmic regressions (which start at 1e-3), but it hides whether
Lambda_A's 4.6e-7 is benign rounding or an ill-conditioned integrand. The two-order gap between the quadrature outputs and the floor is the signal worth checking: a near-singular integrand plus a looseepsabs/epsrelindqagwould produce exactly this, and would also explain the macOS reproduction failures.Concrete questions:
Lambda_Aintegrand near-singular at the substitution boundaries (integrate_1d_substituted)? Whatepsabs/epsrel/limitdoesdqaguse, and does tightening them shrink the cross-platform spread?Lambda_Aindependently of the quadrature? Test withLIBNEO_BRANCHagainst the pinned 752aae9c.fortnumlibneo#291/#288) make the golden record bit-reproducible across platforms, removing the need for the 1e-6 band-aid?Suggested split
Use the golden-record corpus to separate the two regimes instead of one tolerance:
libm+ adaptive-quadrature floor, until the quadrature is made deterministic.References
src/utils/integrate.f90(dqag),cmake/quadpack.cmake,cmake/libneo.cmake(libneo 752aae9c),src/coefficients.f90,src/deviation.f90.fortnumlibneo#291 (fortnum: replace avoidable numerical dependencies), #288 (quadrature).gitlab.tugraz.at:plasma/proj/golden/rabe), three-version env-vs-code comparison.