From 2c48ed3fcd100d76d00fd16dba09c2f69f5729a1 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Sat, 26 Sep 2026 22:50:11 +0200 Subject: [PATCH] RotationScaleMerge: measure the rocking-event span once, not twice per Run At the smoothing window every Run has just restored corr to what Ingest built, and nothing else the measurement reads changes after Ingest, so its answer is the same on every Run; it walked all the partials twice per Run on the CPU path. Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01D1G8gJVAy6gp1K5Dz3NE5C --- image_analysis/scale_merge/RotationScaleMerge.cpp | 7 +++++-- image_analysis/scale_merge/RotationScaleMerge.h | 3 +++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/image_analysis/scale_merge/RotationScaleMerge.cpp b/image_analysis/scale_merge/RotationScaleMerge.cpp index a644b54a9..ae82fcf68 100644 --- a/image_analysis/scale_merge/RotationScaleMerge.cpp +++ b/image_analysis/scale_merge/RotationScaleMerge.cpp @@ -510,6 +510,7 @@ void RotationScaleMerge::Ingest() { // straight from the source reflections (and the smoothing between there and here never // touches corr). if (!resident_ingest) { + rocking_event_frames_at_start = -1; corr_ingested.resize(partials.size()); ParallelChunks(static_cast(partials.size()), ThreadsForWork(partials.size(), nthreads), [&](int lo, int hi) { @@ -5408,12 +5409,14 @@ RotationScaleMerge::Result RotationScaleMerge::Run(bool for_search, bool full_st const double osc_deg = gonio ? std::fabs(gonio->GetIncrement_deg()) : 0.0; int smooth_window = 1; if (smooth_g_deg > 0.0 && osc_deg > 1e-6) { + if (rocking_event_frames_at_start < 0) + rocking_event_frames_at_start = RockingEventFrames(); smooth_window = std::max(static_cast(std::lround(smooth_g_deg / osc_deg)), - SMOOTH_G_MIN_ROCKING_EVENTS * RockingEventFrames()); + SMOOTH_G_MIN_ROCKING_EVENTS * rocking_event_frames_at_start); if (smooth_window % 2 == 0) ++smooth_window; logger.Info("Per-frame scale smoothing window: {} frames ({:.1f} deg; {} deg asked, rocking " "curves span {} frames)", smooth_window, smooth_window * osc_deg, smooth_g_deg, - RockingEventFrames()); + rocking_event_frames_at_start); } ScalingLoopOutcome partial_loop; #ifdef JFJOCH_USE_CUDA diff --git a/image_analysis/scale_merge/RotationScaleMerge.h b/image_analysis/scale_merge/RotationScaleMerge.h index 4db567d58..f0806d8b4 100644 --- a/image_analysis/scale_merge/RotationScaleMerge.h +++ b/image_analysis/scale_merge/RotationScaleMerge.h @@ -288,6 +288,9 @@ private: // nine-iteration merge is wrong. A later pass inherits that state rather than creating it, so this // is a defect of the P1 search arm, and it reaches the user through the point group that arm picks. std::vector corr_ingested; + // RockingEventFrames at the start of a Run, where corr has just been restored to corr_ingested - so + // the same for every Run on the same ingest; -1 until the first Run takes it. + int rocking_event_frames_at_start = -1; // Raw-hkl ordering, built ONCE by Ingest and reused: `perm` lists partial indices sorted by // (raw h,k,l, image_number); each distinct raw hkl is a contiguous run [rawrun_start, +count) of it.