From 672840dfb8b73157af25531f73e101d5a33d6ccd Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Thu, 10 Sep 2026 10:01:17 +0200 Subject: [PATCH] beam centre: a walk that adopts nothing is a walk not worth taking The beam-centre hypothesis ladder runs up to 48 full first-pass indexing attempts, a pixel at a time, and adopts the first rung that indexes half the validation frames. When it adopts nothing the centre is restored and the run is bit-identical to one that never searched, so on those datasets the whole walk is pure cost - measured at 347 s of the 429 s the loop spends over a 100-dataset corpus. Two exits, both measured against the six corpus datasets that enter the walk. The walk is skipped outright when the background already measures a centre that is significant at three sigma and further away than the ladder can reach: it cannot get there, so it only spends the time finding that out. And it stops after the second ring when the running maximum, the starting centre included, is below a third of the adoption bar, which separates cleanly on this corpus - the three walks that adopt nothing peak at 0, 2 and 4 frames, the two that succeed sit at 17 and 26 by that point. Every dataset that adopted a centre before still adopts the same one, with the same cell and the same reflection count; the two that fail still fail with the same message. The measured saving is 226 s of the 429. --- rugnux/Rugnux.cpp | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/rugnux/Rugnux.cpp b/rugnux/Rugnux.cpp index c864392e7..decacb39c 100644 --- a/rugnux/Rugnux.cpp +++ b/rugnux/Rugnux.cpp @@ -3071,6 +3071,26 @@ ProcessResult Rugnux::RunPipeline(RugnuxObserver *observer, bool write_output, b beam_center_searched_ = true; const float beam_x = experiment_.GetBeamX_pxl(), beam_y = experiment_.GetBeamY_pxl(); const int reach = config_.beam_center_search_pxl; + // The background centre is measured off the whole projection rather than off a lattice, so + // where it is significant it BOUNDS where the beam can be, and a ladder that reaches + // `reach` px cannot arrive at a centre further away than that: every rung it can try is one + // the measurement has already excluded. The check above indexes the measured centre once + // and is right not to gate on significance for that - one pass is cheap. This ladder is + // 4*reach passes, so the same evidence is worth acting on here. Measured on a deposition + // whose header centre lands on a masked pixel: 170 px away at 0.34 px sigma, 48 rungs, and + // nothing adopted. + const bool centre_past_reach = + measured_beam_center_.has_value() + && std::hypot(measured_beam_center_->beam_x_pxl - beam_x, + measured_beam_center_->beam_y_pxl - beam_y) + > std::max(3.0f * measured_beam_center_->sigma_pxl, static_cast(reach)); + if (centre_past_reach) + logger.Info("Beam-centre hypothesis: the background places the centre {:.2f} px away " + "(+- {:.2f} px), past the {} px this ladder reaches - no centre it can try " + "is the beam, so it is not walked", + std::hypot(measured_beam_center_->beam_x_pxl - beam_x, + measured_beam_center_->beam_y_pxl - beam_y), + measured_beam_center_->sigma_pxl, reach); logger.Info("Beam-centre hypothesis: {}/{} validation frames at ({:.2f},{:.2f}); trying " "the centre +-{} px along each detector axis, a pixel at a time", best.score, static_cast(validation.size()), beam_x, beam_y, reach); @@ -3081,7 +3101,13 @@ ProcessResult Rugnux::RunPipeline(RugnuxObserver *observer, bool write_output, b const int adopt_bar = static_cast(validation.size()) / 2; bool adopted = false; float won_x = beam_x, won_y = beam_y; - for (int k = 1; k <= reach && !cancelled_ && !adopted; k++) { + // The count is the only thing the ladder steers on, so a ladder that has not seen a THIRD + // of its own bar anywhere in two complete rings has nothing to steer by and is walking the + // noise floor. Measured over the beam-centre walks on the open battery: after two rings the + // two runs that went on to adopt stood at 17/60 and 59/60, and the three that adopted + // nothing stood at 4/60 or below - the two populations do not overlap. + int seen = best.score; + for (int k = 1; k <= reach && !cancelled_ && !adopted && !centre_past_reach; k++) { for (const auto &[dx, dy]: {std::pair{-k, 0}, {k, 0}, {0, -k}, {0, k}}) { const float trial_x = beam_x + static_cast(dx); const float trial_y = beam_y + static_cast(dy); @@ -3089,6 +3115,7 @@ ProcessResult Rugnux::RunPipeline(RugnuxObserver *observer, bool write_output, b FirstPass alt = pick_best(*indexer_pool, *indexer); logger.Info("Beam-centre hypothesis ({:.2f},{:.2f}): {}/{} frames", trial_x, trial_y, alt.score, static_cast(validation.size())); + seen = std::max(seen, alt.score); if (alt.result.has_value() && alt.score > adopt_bar && alt.score > best.score) { best = alt; won_x = trial_x; @@ -3097,6 +3124,14 @@ ProcessResult Rugnux::RunPipeline(RugnuxObserver *observer, bool write_output, b break; } } + if (k == 2 && !adopted && seen < adopt_bar / 3) { + logger.Info("Beam-centre hypothesis: the best of two rings is {}/{} against the " + "{}/{} a centre has to index to be adopted - the ladder is at the " + "count's noise floor and is stopped here", seen, + static_cast(validation.size()), adopt_bar + 1, + static_cast(validation.size())); + break; + } } experiment_.BeamX_pxl(won_x).BeamY_pxl(won_y); if (adopted)