// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only #pragma once #include #include #include #include "../common/DiffractionSpot.h" #include "../common/DiffractionExperiment.h" #include "../common/AzimuthalIntegrationMapping.h" #include "../common/AzimuthalIntegrationProfile.h" #include "../common/Reflection.h" #include "bragg_prediction/BraggPrediction.h" #include "indexing/IndexerThreadPool.h" #include "lattice_search/LatticeSearch.h" #include "rotation_indexer/RotationIndexer.h" #include "rotation_indexer/RotationIndexerCounter.h" #include "scale_merge/ScaleOnTheFly.h" #include "scale_merge/ScalingResult.h" #include "IntegrationOutcome.h" // Integrates the predicted reflections off whatever image the caller holds: the preprocessed GPU/CPU // buffer on the WithoutFPGA path (GPU when available), or the assembled detector image read straight, // on the CPU, on the forced-CPU FPGA path. Keeps IndexAndRefine independent of the image representation. using BraggIntegrateFn = std::function( const std::vector &predicted, size_t npredicted, int64_t image_number)>; 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_; std::optional indexed_lattice; std::optional axis_; IndexerThreadPool *indexer_; std::unique_ptr rotation_indexer; RotationIndexerCounter rotation_indexer_counter; struct IndexingOutcome { std::optional lattice_candidate; std::vector extra_lattice_candidates; std::vector extra_lattice_rotations; DiffractionExperiment experiment; LatticeMessage symmetry{ .centering = 'P', .niggli_class = 0, .crystal_system = gemmi::CrystalSystem::Triclinic }; bool beam_center_updated = false; explicit IndexingOutcome(const DiffractionExperiment& experiment_ref) : experiment(experiment_ref) {} }; mutable std::mutex reflections_mutex; std::vector integration_outcome; std::vector mosaicity; std::vector scale_cc; std::vector > unit_cells; IndexingOutcome DetermineLatticeAndSymmetryRotation(DataMessage &msg); IndexingOutcome DetermineLatticeAndSymmetry(DataMessage &msg); // Shared indexing path: determine the lattice/symmetry, refine geometry, and run AnalyzeIndexing. // Returns the outcome (ready for integration) when the frame indexes, nullopt otherwise. Both the // real per-image ProcessImage and the first-pass scheme validation go through this, so they cannot // diverge. std::optional DetermineRefineAnalyze(DataMessage &msg, const SpotFindingSettings &spot_finding_settings); void RefineGeometryIfNeeded(DataMessage &msg, IndexingOutcome &outcome); void QuickPredictAndIntegrate(DataMessage &msg, const SpotFindingSettings &spot_finding_settings, BraggPrediction &prediction, const BraggIntegrateFn &integrate, const IndexingOutcome &outcome); std::unique_ptr scaling_engine; void ScaleImage(DataMessage &msg, IntegrationOutcome& outcome); std::optional RotationAngle(int64_t image) const; // mid-exposure angle for the indexer public: IndexAndRefine(const DiffractionExperiment &x, IndexerThreadPool *indexer, bool retain_outcomes = true); void AddImageToRotationIndexer(DataMessage &msg); void ForceRotationIndexerLattice(const CrystalLattice& lattice); void ForceRotationIndexerResult(const RotationIndexerResult& result); void ProcessImage(DataMessage &msg, const SpotFindingSettings &settings, BraggPrediction &prediction, const BraggIntegrateFn &integrate); // Index a single frame (no integration) with the current forced rotation lattice; used to score // first-pass sampling schemes on the real per-image path. Returns whether the frame indexed. bool IndexFrameOnly(DataMessage &msg, const SpotFindingSettings &settings); IndexAndRefine& ReferenceIntensities(std::vector &reference); ScalingResult ScaleAllImages(const std::vector &reference, size_t nthreads = 0); std::optional FinalizeRotationIndexing(); std::optional GetConsensusUnitCell() const; // Not thread safe, need to be run after processing is all done const std::vector &GetImageCC() const; const std::vector > &GetUnitCells() const; std::vector &GetIntegrationOutcome(); const std::vector &GetIntegrationOutcome() const; };