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();