Two independent pieces in the same code path.
The background-estimate variance was never propagated. A reflection's background comes
from a finite ring of n_b pixels, so subtracting it adds var(B)/n_b per signal pixel -
sqrt(1 + n_d/n_b) = 1.109 with the shipped stencil. Both engines omitted it, which is
exactly the 1.11-1.19 gap measured between the off-ring scatter and the reported sigma.
Three lines each; it affects every dataset, not only iced ones.
The radial correction is new and OFF by default (--background-radial). The signal disk
and the background ring are concentric, so for any background LINEAR in position
<B>_ann == <B>_disk identically and a plane fit buys nothing; the leading error is the
CURVATURE of the radial background, which on a sharp ice ring reaches +26 counts on a
single reflection. Since every reflection uses the same stencil, that error is a fixed
kernel over radial offset - one short dot product per reflection and no extra pixel
reads. Validated on empty apertures before any C++: mean |bias| over 9 bands / 3
crystals 4.33 -> 0.79 counts with the scatter unchanged.
Three things it cost a battery each to learn, all now in the code:
- the radial curve must be accumulated from CLIPPED annulus pixels, inside the clip
pass, or it carries neighbour tails and zingers (so it is inert under --integrator
boxsum, which has no clip pass);
- the GPU version was a 1.8x slowdown from atomicAdd contention on a small radial
array - staged in shared memory per block it now costs nothing measurable;
- it is battery-NEUTRAL as a default, because the reflections whose bias it fixes are
the ones the ice handling already excludes. Hence off by default.
CPU/GPU parity extended with two radial sections: 9002 assertions.
Also fixes a latent French-Wilson quadrature collapse: j_max = I + 8 sigma on a fixed
400-point grid degenerates to a single cell once sigma >> 50 <I>, giving F = 0.1 sqrt(sigma)
with sigmaF -> 0. Harmless today, but any sigma-inflation scheme detonates it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>