image_analysis: add retain_outcomes flag to IndexAndRefine; viewer opts out

IndexAndRefine::integration_outcome is a whole-run vector (resize(GetImageNum()))
holding up to ~0.8 MB of reflections per indexed image. It is consumed only by
the offline scaling/merge pass in rugnux (ScaleAllImages / GetIntegrationOutcome).
In the viewer's interactive/live analysis it is written but never read - dead
storage that, with auto-reanalyze on during live follow, grew ~0.8 MB per frame
for the whole run.

Add a retain_outcomes constructor flag (default true). When false, skip the
whole-run resize and the per-image store; the current image's reflections are
still returned via the outgoing message. The viewer's live IndexAndRefine passes
false. rugnux (including GUI processing jobs, which build their own Rugnux ->
IndexAndRefine) and the online receiver keep the default true, so scaling/merge
still has the accumulated data.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-09 11:02:10 +02:00
co-authored by Claude Fable 5
parent dc8a80f3e0
commit b2f0af12db
3 changed files with 16 additions and 5 deletions
+8 -3
View File
@@ -12,15 +12,18 @@
#include "lattice_search/LatticeSearch.h"
#include "scale_merge/ScaleOnTheFly.h"
IndexAndRefine::IndexAndRefine(const DiffractionExperiment &x, IndexerThreadPool *indexer)
IndexAndRefine::IndexAndRefine(const DiffractionExperiment &x, IndexerThreadPool *indexer, bool retain_outcomes)
: index_ice_rings(x.GetIndexingSettings().GetIndexIceRings()),
retain_outcomes_(retain_outcomes),
experiment(x),
geom_(x.GetDiffractionGeometry()),
indexer_(indexer),
rotation_indexer_counter(x) {
if (indexer && x.IsRotationIndexing())
rotation_indexer = std::make_unique<RotationIndexer>(x, *indexer);
integration_outcome.resize(x.GetImageNum());
// Only retain the whole-run per-image reflections when a later scaling/merge pass will read them.
if (retain_outcomes_)
integration_outcome.resize(x.GetImageNum());
mosaicity.resize(x.GetImageNum(), NAN);
scale_cc.resize(x.GetImageNum(), 0);
@@ -363,7 +366,9 @@ void IndexAndRefine::QuickPredictAndIntegrate(DataMessage &msg,
// Copy reflections to outgoing message
msg.reflections = i_outcome.reflections;
{
// Persist the per-image result for the whole-run scaling/merge pass, unless the caller opted out
// (viewer interactive use only needs the current image, returned above via msg).
if (retain_outcomes_) {
const std::unique_lock ul(reflections_mutex);
integration_outcome[msg.number] = std::move(i_outcome);
}
+5 -1
View File
@@ -30,6 +30,10 @@ using BraggIntegrateFn = std::function<std::vector<Reflection>(
class IndexAndRefine {
const bool index_ice_rings;
// When false, the current image's result is still returned via the outgoing message, but the
// whole-run integration_outcome vector is not retained (viewer live/interactive use, which never
// scales the accumulated run). rugnux/receiver keep it true so ScaleAllImages/merge have the data.
const bool retain_outcomes_;
const DiffractionExperiment& experiment;
const DiffractionGeometry geom_;
@@ -79,7 +83,7 @@ class IndexAndRefine {
std::optional<float> RotationAngle(int64_t image) const; // mid-exposure angle for the indexer
public:
IndexAndRefine(const DiffractionExperiment &x, IndexerThreadPool *indexer);
IndexAndRefine(const DiffractionExperiment &x, IndexerThreadPool *indexer, bool retain_outcomes = true);
void AddImageToRotationIndexer(DataMessage &msg);
void ForceRotationIndexerLattice(const CrystalLattice& lattice);
+3 -1
View File
@@ -364,7 +364,9 @@ void JFJochImageReadingWorker::LoadImage(int64_t image_number, int64_t summation
void JFJochImageReadingWorker::UpdateAzint_i(const JFJochReaderDataset *dataset) {
if (dataset) {
azint_mapping = std::make_unique<AzimuthalIntegrationMapping>(curr_experiment, *dataset->pixel_mask);
index_and_refine = std::make_unique<IndexAndRefine>(curr_experiment, indexing.get());
// Interactive/live analysis only needs the current image's result (returned per image); it
// never scales the accumulated run, so don't retain the whole-run integration_outcome vector.
index_and_refine = std::make_unique<IndexAndRefine>(curr_experiment, indexing.get(), /*retain_outcomes=*/false);
image_analysis = std::make_unique<MXAnalysisWithoutFPGA>(curr_experiment, *azint_mapping, *dataset->pixel_mask,
*index_and_refine.get());