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) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D1G8gJVAy6gp1K5Dz3NE5C
This commit is contained in:
2026-09-26 22:50:11 +02:00
co-authored by Claude Opus 5.5
parent 45a8db03d4
commit 2c48ed3fcd
2 changed files with 8 additions and 2 deletions
@@ -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<int>(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<int>(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
@@ -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<float> 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.