From 078cd1580dc8b1a25325a1b38df6446854a7e27f Mon Sep 17 00:00:00 2001 From: menzel Date: Wed, 1 Jul 2026 17:48:05 +0200 Subject: [PATCH] Add intensity_map_predict_gap with corrected 3-parameter fit Undulator gap predictor for cSAXS, regenerated from plot_intensity_map.py. Calibrated on the operating locus (per-energy lowest-gap odd/even flux maxima, harmonics labelled from the global resonance fit): 3-parameter pure-exponential field model, gap-residual RMS ~14 um. Supersedes the earlier 4-parameter (quadratic) constants: c2 was insignificant (0.2 sigma) and left E_inf degenerate (+/-11 keV). Co-Authored-By: Claude Opus 4.8 (1M context) --- .../cSAXS/intensity_map_predict_gap.py | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 csaxs_bec/bec_ipython_client/plugins/cSAXS/intensity_map_predict_gap.py diff --git a/csaxs_bec/bec_ipython_client/plugins/cSAXS/intensity_map_predict_gap.py b/csaxs_bec/bec_ipython_client/plugins/cSAXS/intensity_map_predict_gap.py new file mode 100644 index 0000000..dbdc992 --- /dev/null +++ b/csaxs_bec/bec_ipython_client/plugins/cSAXS/intensity_map_predict_gap.py @@ -0,0 +1,26 @@ +"""Undulator gap predictor emitted by plot_intensity_map.py. +Edit the fitted constants in the signature to retune.""" + +import numpy as np + + +def predict_gap(energy, n=3, gap_min=5.0, + E_inf=3.2878, c0=2.46086, c1=-0.468091, c2=0.0): + """Undulator gap [mm] to place `energy` [keV] on harmonic `n`. + Fitted constants are the defaults below; edit them to retune. + Returns NaN where the energy is unreachable on that harmonic.""" + energy = np.asarray(energy, float) + arg = E_inf * n / energy - 1.0 # required K^2/2; must be > 0 + with np.errstate(invalid="ignore", divide="ignore"): + y = np.log(arg) + if abs(c2) < 1e-12: + g = (y - c0) / c1 + else: + disc = c1 * c1 - 4.0 * c2 * (c0 - y) + sq = np.sqrt(np.where(disc >= 0, disc, np.nan)) + r1 = (-c1 + sq) / (2.0 * c2) + r2 = (-c1 - sq) / (2.0 * c2) + g = np.where(c1 + 2.0 * c2 * r1 < 0, r1, r2) + g = np.where(arg > 0, g, np.nan) # above harmonic cutoff + g = np.where(g >= gap_min, g, np.nan) # below mechanical minimum + return g