From ae405aaecb9845e6587988d7a6d60ba08be8edb7 Mon Sep 17 00:00:00 2001 From: Oliver Lemke Date: Tue, 30 Jun 2026 09:18:55 +0200 Subject: [PATCH 1/2] fix: swap make_lags source/target grids in XsecRecord::Extract The make_lags call in XsecRecord::Extract had its grid arguments swapped: the output grid (f_grid_active) was passed as the source (xi) and the data grid (data_f_grid_active) as the target (xn). This caused lags.indx to index into fit_result_active using the wrong coordinate array, shifting the interpolated peak toward higher frequencies as the output grid got coarser. Swap the arguments so xi is the data grid (where fit_result_active is defined) and xn is the output grid, keeping the peak position independent of the output f_grid resolution. --- src/core/absorption/xsec_fit.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/absorption/xsec_fit.cc b/src/core/absorption/xsec_fit.cc index 19433a84c5..d7dcd91426 100644 --- a/src/core/absorption/xsec_fit.cc +++ b/src/core/absorption/xsec_fit.cc @@ -161,7 +161,7 @@ void XsecRecord::Extract(VectorView result, { const auto f_gp = lagrange_interp::make_lags<1, lagrange_interp::grid_identity>( - f_grid_active, data_f_grid_active, 0.5, "Frequency"); + data_f_grid_active, f_grid_active, 0.5, "Frequency"); const auto f_itw = reinterpweights(f_gp); // Find frequency grid positions: From f7109d85fc3be77549fac4a57c9c12637b74fdfd Mon Sep 17 00:00:00 2001 From: Oliver Lemke Date: Tue, 30 Jun 2026 09:42:05 +0200 Subject: [PATCH 2/2] test: expand xfit test to cover resampled grids Refactor the xsec/xfit regression test to exercise the native grid plus downsampled (0.2x) and upsampled (1.2x) frequency grids. The native case keeps the exact 1e-36 tolerance, while the resampled cases use 1e-18 to account for np.linspace interpolation error. Reference values are frozen as x_ref and the check is factored into _check_grid. --- tests/python/xsec/xfit.py | 78 +++++++++++++++++++++++++-------------- 1 file changed, 50 insertions(+), 28 deletions(-) diff --git a/tests/python/xsec/xfit.py b/tests/python/xsec/xfit.py index 8d04f85f3b..1ef2184d3a 100644 --- a/tests/python/xsec/xfit.py +++ b/tests/python/xsec/xfit.py @@ -1,30 +1,52 @@ -import pyarts3 as pyarts import numpy as np +import pyarts3 as pyarts + +# x_ref: pinned strided values (stride 60000) of the native-grid +# spectral_propmat output for O3 at STP. Generated once from the +# native-grid case and frozen as the regression reference. +x_ref = [ + 5.48830541e-29, + 7.01126943e-26, + 2.25566466e-25, + 3.67157516e-27, + 5.42679027e-26, + 7.56822053e-23, + 1.11608430e-21, + 3.90151892e-22, +] + +# Tolerances: 1e-36 is the native-grid round-trip floor (effectively +# exact). The resampled grids go through np.linspace, which introduces +# interpolation error, so we loosen to 1e-18 for those cases. +cases = [ + (1.0, 1e-36), # native grid; exact + (0.2, 1e-18), # downsampled; interpolation error dominates + (1.2, 1e-18), # upsampled; same note as downsampled +] + + +def _check_grid(ws, atm, nd, f, stride, atol): + x = ws.abs_xfit_data.spectral_propmat(f=f, atm=atm, spec="O3") / nd + assert np.allclose(x[::stride, 0], x_ref, atol=atol) + + +def main(): + ws = pyarts.Workspace() + + atm = pyarts.arts.AtmPoint() + atm.pressure = 101325.0 + atm.temperature = 273.15 + atm["O3"] = 1e-8 + nd = atm.number_density("O3-666") + + ws.abs_speciesSet(species=["O3-XFIT"]) + ws.ReadCatalogData() + f = ws.abs_xfit_data["O3"].fitcoeffs[0].grids[0] + + for n, atol in cases: + f_n = f if n == 1.0 else np.linspace(f[0], f[-1], int(f.size * n)) + _check_grid(ws, atm, nd, f_n, stride=int(60000 * n), atol=atol) + -ws = pyarts.Workspace() - -atm = pyarts.arts.AtmPoint() -atm.pressure = 101325.0 -atm.temperature = 273.15 -atm["O3"] = 1e-8 -nd = atm.number_density("O3-666") - -ws.abs_speciesSet(species=["O3-XFIT"]) -ws.ReadCatalogData() -f = ws.abs_xfit_data["O3"].fitcoeffs[0].grids[0] -x = ws.abs_xfit_data.spectral_propmat(f=f, atm=atm, spec="O3") / nd - -assert np.allclose( - x[::60000, 0], - [ - 5.48830541e-29, - 7.01126943e-26, - 2.25566466e-25, - 3.67157516e-27, - 5.42679027e-26, - 7.56822053e-23, - 1.11608430e-21, - 3.90151892e-22, - ], - atol=1e-36, -) +if __name__ == "__main__": + main()