diff --git a/rugnux/Rugnux.cpp b/rugnux/Rugnux.cpp index 4d226c7e..ed1e51b6 100644 --- a/rugnux/Rugnux.cpp +++ b/rugnux/Rugnux.cpp @@ -366,7 +366,18 @@ void Rugnux::PreScan(int start_image, int images_to_process, int frame_count, Ru const bool want_beam_center = config_.estimate_beam_center && !beam_center_placed_; // The spot width is a property of the crystal, not of the geometry, so the second pass reuses the // radius the first one measured rather than re-reading the frames. - const bool want_width = config_.adaptive_integration_radius && !spot_width_measured_; + // + // It is READ OFF the geometry as it stands, though, and a beam centre this same pass is about to + // correct leaves that geometry provisional: candidates are excluded within MIN_BEAM_DISTANCE_PX + // of the centre and stratified into resolution bands about it, so a placeholder header centre + // both measures a different set of spots and labels them at the wrong resolution - and + // spot_width_measured_ would then stop the corrected pass from ever revisiting it. Where a + // second pass follows, leave the width to that one, which starts from the corrected centre. A + // run with no second pass measures it here: a provisional radius beats none. + const bool second_pass_follows = want_beam_center && config_.rotation_indexing + && config_.two_pass_rotation && experiment_.IsRotationIndexing(); + const bool want_width = config_.adaptive_integration_radius && !spot_width_measured_ + && !second_pass_follows; if (!want_shadow && !want_beam_center && !want_width) return; @@ -486,6 +497,10 @@ void Rugnux::PreScan(int start_image, int images_to_process, int frame_count, Ru // Images the width ended up being measured on, for the log: the tiers below stop as soon as the // answer has settled, so this is a property of the crystal and worth reporting. size_t width_images = 0; + // Frames that could actually be read. Counted here rather than asked of the shadow finder, which + // is only fed when the shadow is wanted and would report zero for a pass that read every frame + // for the beam centre alone. + std::atomic frames_read{0}; // Read the sample on several workers. The reader serialises on the HDF5 lock, but the // decompression, the projection and the spot finding - which is all of the cost on a large @@ -568,7 +583,13 @@ void Rugnux::PreScan(int start_image, int images_to_process, int frame_count, Ru msg.image = img->image; msg.number = ordinal; msg.original_number = image_idx; - if (shadow_set.contains(ordinal)) + frames_read.fetch_add(1, std::memory_order_relaxed); + // Gated on want_shadow, not on the frame set alone: AddImage projects the + // whole image, and with --detect-beam-stop=off (or a shadow already in the + // mask) that is the pass's largest per-frame cost paid for a result nobody + // reads. The set still decides WHICH frames feed it, so the mask is built + // from the frames it always was. + if (want_shadow && shadow_set.contains(ordinal)) finder.AddImage(msg, w.shadow_buffer, t); // The width is measured on the projection's own even spread over the sweep, @@ -644,7 +665,7 @@ void Rugnux::PreScan(int start_image, int images_to_process, int frame_count, Ru } } - if (finder.GetFrameCount() == 0) { + if (frames_read.load() == 0) { logger.Warning("Pre-scan: no image could be read. Skipping."); return; }