From 7786fc1af30418a03e950fc4ca8b77d313fea97a Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Fri, 31 Jul 2026 09:30:11 +0200 Subject: [PATCH] Stills geometry refinement: stop sampling once there are enough strong frames The first pass sampled min(n, max(refine_frames * 50, 8000)) images to keep the 200 strongest, so any serial run of 10000 frames or fewer indexed every frame TWICE - and 99.3% of the pass was that sampling, the bundle adjust itself taking 0.24 s. The budget is sized for a low-hit-rate dataset; on data that indexes well almost all of it was wasted. Stop once four times the bundle size has been found, which still leaves the "strongest N" selection a real pool and still spans the run, because the sample is equally spaced. On a lysozyme jet dataset that is 1500 frames examined instead of 4000, the same 200 bundled, and the same refined geometry - beam and distance to the pixel, cell to 0.01 A. Warm cache: the pass drops 33 s -> 9.1 s and the whole run 65 s -> 35 s, with CC1/2 and R-meas unchanged inside replicate noise. Stills only - rotation has its own two-pass and returns from this function early. Co-Authored-By: Claude Opus 5 (1M context) --- rugnux/Rugnux.cpp | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/rugnux/Rugnux.cpp b/rugnux/Rugnux.cpp index cf3b0308..f9f4a8d3 100644 --- a/rugnux/Rugnux.cpp +++ b/rugnux/Rugnux.cpp @@ -117,9 +117,21 @@ void Rugnux::RefineStillsGeometry(int start_image, int end_image, int images_to_ pass_settings.indexing = true; pass_settings.quick_integration = false; + // A frame is worth bundling only if it indexed this many spots; the bundle then takes the + // refine_frames strongest of those. + constexpr int MIN_STRONG_SPOTS = 20; + // Stop sampling once there are comfortably more strong frames than the bundle will use, instead of + // draining the whole budget. The budget is sized for a low-hit-rate dataset (refine_frames * 50, at + // least 8000), so on data that indexes well it meant re-indexing the ENTIRE run to keep 200 frames - + // 99% of this pass was sampling. Four times the bundle leaves the "strongest N" selection a real + // pool to choose from; the frames are equally spaced, so an early stop still spans the run. + const int strong_target = refine_frames * 4; + std::vector frames; std::mutex frames_mutex; std::atomic next_i = 0; + std::atomic strong_found = 0; + std::atomic examined = 0; auto worker = [&]() { pin_gpu(); // round-robin per worker thread; must precede engine construction @@ -127,9 +139,10 @@ void Rugnux::RefineStillsGeometry(int start_image, int end_image, int images_to_ /*enable_fused_adaptive_gpu=*/true); AzimuthalIntegrationProfile profile(mapping); - while (!cancelled_) { + while (!cancelled_ && strong_found.load(std::memory_order_relaxed) < strong_target) { const int idx = next_i.fetch_add(1); if (idx >= static_cast(sample.size())) break; + examined.fetch_add(1, std::memory_order_relaxed); const int ordinal = sample[idx]; const int image_idx = start_image + ordinal * config_.stride; @@ -164,6 +177,8 @@ void Rugnux::RefineStillsGeometry(int start_image, int end_image, int images_to_ f.spots.push_back(GeomRefineSpot{s.x, s.y, static_cast(s.h), static_cast(s.k), static_cast(s.l)}); if (f.spots.size() >= 6) { + if (static_cast(f.spots.size()) >= MIN_STRONG_SPOTS) + strong_found.fetch_add(1, std::memory_order_relaxed); const std::unique_lock ul(frames_mutex); frames.push_back(std::move(f)); } @@ -182,7 +197,6 @@ void Rugnux::RefineStillsGeometry(int start_image, int end_image, int images_to_ // Keep the strongest frames (most indexed spots) for the bundle - the true cell indexes many // spots per frame, and orientation diversity comes for free from independent serial stills. - constexpr int MIN_STRONG_SPOTS = 20; std::vector strong; for (auto &f : frames) if (static_cast(f.spots.size()) >= MIN_STRONG_SPOTS) @@ -192,8 +206,10 @@ void Rugnux::RefineStillsGeometry(int start_image, int end_image, int images_to_ if (static_cast(strong.size()) > refine_frames) strong.resize(refine_frames); - logger.Info("Geometry refinement: indexed {} of {} sampled frames, bundling {} strong frames (>= {} spots)", - frames.size(), sample.size(), strong.size(), MIN_STRONG_SPOTS); + logger.Info("Geometry refinement: indexed {} of {} sampled frames (budget {}), bundling {} strong " + "frames (>= {} spots)", + frames.size(), std::min(examined.load(), static_cast(sample.size())), + sample.size(), strong.size(), MIN_STRONG_SPOTS); GeometryRefinerSettings gr_settings; gr_settings.crystal_system = experiment_.GetCrystalSystem();