The decay/absorption correction surfaces previously forced the CPU 3D
combine (absorption needs each full's predicted detector position, which
the GPU SoA did not carry), so they could not be default-on without losing
the fast GPU path. Put them on the GPU:
- carry px/py (peak partial) through the GPU combine and download them with
the fulls (GetFullsPxPy);
- add SetFullsCorr to re-upload the host-corrected corr to the resident
fulls before the merge.
The surfaces themselves stay as cheap host fits on the downloaded fulls;
only px/py download + corr upload are added (~two O(n_fulls) transfers).
Measured +2% wall-time on lyso_ref (9.7 -> 9.9 s), and the GPU-combine and
CPU-combine (--dump-observations) paths give identical results.
Enable by default via a single master toggle ScalingSettings::
CorrectionSurfaces (default true; decoupled from the stills-only -B, which
is rejected for rotation again). Both surfaces are cross-validated, so they
no-op where their systematic is absent - safe to leave on. Off-switch wired
through the rugnux CLI (--no-scaling-corrections; --absorption removed) and
the viewer (a "Correction surfaces" checkbox). Documented in docs/RUGNUX.md.
Battery (24 rotation crystals), default-on vs --no-scaling-corrections:
EcwtCQ066S +2.4 ISa, lyso_ref +0.5 (and R-free 0.194 -> 0.185, better than
XDS); every other crystal within run-to-run noise; corrections skip (CV /
dB-floor) wherever there is no signal. lyso_ref anomalous S/Cl peaks are
already ~45% above XDS's - the ISa gap is metric convention, not data.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>