From 3b6da6d1c69e2a7073928c1080942b55bd98b1a8 Mon Sep 17 00:00:00 2001 From: d-burg Date: Fri, 23 Oct 2026 13:45:37 -0400 Subject: [PATCH] =?UTF-8?q?Equilibrium=20-=20FEATURE=20-=20Warn=20when=20a?= =?UTF-8?q?=20g-file's=20FPOL=20is=20single=20precision=20and=20the=20run?= =?UTF-8?q?=20computes=20=CE=94=E2=80=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GPEC splines FPOL and differentiates it, so the rounding of a single-precision FPOL column becomes noise of order ±2–3 on Δ′ at 257 radial nodes. Runs with the riccati or galerkin integrator on such a g-file now warn and suggest regenerating it in double precision. The check is gfile_fpol_single_precision: every FPOL value within 1e-8 of its Float32 rounding. Co-Authored-By: Claude Opus 5.5 --- src/Equilibrium/ReadEquilibrium.jl | 14 ++++++++++++++ src/GeneralizedPerturbedEquilibrium.jl | 6 ++++++ test/runtests_equil.jl | 7 +++++++ 3 files changed, 27 insertions(+) diff --git a/src/Equilibrium/ReadEquilibrium.jl b/src/Equilibrium/ReadEquilibrium.jl index f8436f26e..6247d3609 100644 --- a/src/Equilibrium/ReadEquilibrium.jl +++ b/src/Equilibrium/ReadEquilibrium.jl @@ -40,6 +40,20 @@ function _read_1d_gfile_format(lines_block::Vector{String}, num_values::Int) return parsed_values end +""" + gfile_fpol_single_precision(filename) -> Bool + +Whether the g-file's FPOL column was written in single precision: every value lies within 1e-8 +(relative) of its Float32 rounding. Double-precision values printed to the format's ten digits +sit about 1.5e-8 from it on average, so a whole column below 1e-8 is single precision. +""" +function gfile_fpol_single_precision(filename::AbstractString) + lines = readlines(filename) + nw = parse(Int, split(lines[1])[end-1]) + fpol = _read_1d_gfile_format(lines[6:(5+cld(nw, 5))], nw) + return all(f -> abs(Float64(Float32(f)) - f) <= 1e-8 * abs(f), fpol) +end + """ _read_efit(equil_in) diff --git a/src/GeneralizedPerturbedEquilibrium.jl b/src/GeneralizedPerturbedEquilibrium.jl index 251e6da84..aa0339746 100755 --- a/src/GeneralizedPerturbedEquilibrium.jl +++ b/src/GeneralizedPerturbedEquilibrium.jl @@ -221,6 +221,12 @@ function main_from_inputs( resolve_mode_space!(intr, ctrl) equil = Equilibrium.setup_equilibrium(eq_config, additional_input) + # GPEC differentiates the spline of F, so single-precision FPOL rounding becomes noise in Δ′. + if eq_config.eq_type in Equilibrium.EFIT_KINDS && ctrl.integrator in ("riccati", "galerkin") && + Equilibrium.gfile_fpol_single_precision(eq_config.eq_filename) + @warn "The g-file's FPOL is single precision. Its rounding puts noise of order ±2–3 on Δ′ at 257 radial " * + "nodes; regenerate the file in double precision for converged Δ′." file = eq_config.eq_filename + end kf_ctrl, kinetic_profiles, kf_species = load_kinetic_context(inputs, intr, ctrl, equil) equil = maybe_reform_equilibrium(equil, eq_config, additional_input, intr, ctrl, kinetic_profiles; diff --git a/test/runtests_equil.jl b/test/runtests_equil.jl index 4bfa677f9..cb16b9122 100644 --- a/test/runtests_equil.jl +++ b/test/runtests_equil.jl @@ -21,6 +21,13 @@ using Statistics @test 6.5 < plasma_eq_efit.ro < 7.5 # Physical sanity check end + @testset "Single-precision g-file FPOL is detected" begin + single_precision = GeneralizedPerturbedEquilibrium.Equilibrium.gfile_fpol_single_precision + @test single_precision(joinpath(@__DIR__, "..", "examples", "DIIID-like_ideal_example", "TkMkr_D3Dlike_Hmode.geqdsk")) + @test !single_precision(joinpath(@__DIR__, "test_data", "TokaMaker_ifile", "g65.geqdsk")) + @test !single_precision(joinpath(data_dir, "EQDSK_COCOS_02")) + end + @testset "Load EFIT Data (arclength)" begin arclength_config = GeneralizedPerturbedEquilibrium.Equilibrium.EquilibriumConfig(; eq_filename=joinpath(data_dir, "EQDSK_COCOS_02"),