BraggIntegrationEngineCPU: background clip reads the ring pixels pass A gathered, output unchanged

The one-pass sigma clip of the background ring walked the reflection's whole box a second time,
recomputing every pixel's stencil distances and neighbour mask. Pass A now keeps the ring pixels the
clip reads (readable, not a neighbour's flux), with their radial offset, in pixel order, and the clip
sums those - the same values in the same order.

Measured on cytochrome C (CPU-only, Apple M6): the clip loop was 8.4% of CPU; the run is 4-5% faster
with this and the ring-histogram change together. Merged reflections and maps byte-identical.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Filip LeonarskiandClaude Opus 5.5 committed 2026-10-14 19:42:31 +02:00
1 parent 93958cfdc7
commit 1c748ba41e
1 file changed
+17 -17
@@ -208,6 +208,10 @@ std::vector<Reflection> BraggIntegrationEngineCPU::RunImpl(const Sampler &img,
std::vector<Rough> rough(npredicted);
double inv_d2_min = std::numeric_limits<double>::max(), inv_d2_max = 0.0;
std::vector<int32_t> bkg_vals; // reused per reflection for the trimmed-mean background (idea 1)
// The ring pixels the background clip below reads, with their radial offsets, gathered while pass
// A walks the box anyway - in the order the clip sums them, so it sums the same values.
struct ClipPixel { int32_t px; float rad; };
std::vector<ClipPixel> clip_ring;
// Radial background curve, accumulated from the annulus pixels this pass already reads. A pixel's
// radius is the reflection's radius plus the pixel's projection on the beam->reflection direction,
@@ -266,10 +270,13 @@ std::vector<Reflection> BraggIntegrationEngineCPU::RunImpl(const Sampler &img,
// separable from what the detector took.
int n_ring = 0, n_clean = 0;
bkg_vals.clear();
clip_ring.clear();
for (int y = y0; y <= y1; ++y)
for (int x = x0; x <= x1; ++x) {
const auto d = BraggStencilDistances(st, x - r.predicted_x, y - r.predicted_y);
const int32_t px = img[y * W + x];
if (do_clip && d.inner >= r2_sq && d.outer < r3_sq && valid(px) && refl_mask.Get(x, y) != MASK_FLUX)
clip_ring.push_back({px, d.rad});
if (BraggStencilInSignal(st, x - r.predicted_x, y - r.predicted_y, d.signal, r1_sq)) {
// A pixel a nearer neighbour owns carries that neighbour's flux, so in Exclude
// mode it leaves the disk entirely - the sum, the pixel count the background is
@@ -353,23 +360,16 @@ std::vector<Reflection> BraggIntegrationEngineCPU::RunImpl(const Sampler &img,
* std::max(out.bkg, 1.0));
double s = 0.0;
int n = 0;
for (int y = y0; y <= y1; ++y)
for (int x = x0; x <= x1; ++x) {
const auto d = BraggStencilDistances(st, x - r.predicted_x, y - r.predicted_y);
if (!(d.inner >= r2_sq && d.outer < r3_sq)) continue;
if (refl_mask.Get(x, y) == MASK_FLUX) continue;
const int32_t px = img[y * W + x];
if (!valid(px)) continue;
if (static_cast<double>(px) <= thr) {
s += px;
++n;
if (bkg_radial) {
// The radial curve is binned on the TRUE detector radius, so the
// offset here is the unshrunk radial projection.
const int b = std::clamp(static_cast<int>(std::lround(st.r0 + d.rad)), 0, n_rad - 1);
rad_sum[b] += static_cast<double>(px);
++rad_cnt[b];
}
for (const auto &[px, rad] : clip_ring)
if (static_cast<double>(px) <= thr) {
s += px;
++n;
if (bkg_radial) {
// The radial curve is binned on the TRUE detector radius, so the
// offset here is the unshrunk radial projection.
const int b = std::clamp(static_cast<int>(std::lround(st.r0 + rad)), 0, n_rad - 1);
rad_sum[b] += static_cast<double>(px);
++rad_cnt[b];
}
}
if (n > 5) { out.bkg = s / n; n_bkg_used = n; }