// SPDX-FileCopyrightText: 2024 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only #pragma once #include #include #include #include "StatusVector.h" #include "Histogram.h" #include "ADUHistogram.h" #include "AutoIncrVector.h" #include "DiffractionExperiment.h" #include "AzimuthalIntegrationProfile.h" #include "JFJochMessages.h" #include "Plot.h" #include "ScanResult.h" struct MeanProcessingTime { float compression; float preprocessing; float azint; float spot_finding; float indexing; float refinement; float integration; float bragg_prediction; float processing; float indexing_analysis; float image_scale; }; class JFJochReceiverPlots { mutable std::mutex m; // protects xfel_pulse_id, xfel_event_code and az_int_profile std::optional goniometer; std::optional grid_scan; int64_t default_binning = 1; std::unique_ptr az_int_profile; AutoIncrVector xfel_pulse_id; AutoIncrVector xfel_event_code; StatusVector bkg_estimate; StatusVector spindle_blind_fraction; StatusVector ice_ring_score; StatusVector spot_count; StatusVector spot_count_low_res; StatusVector spot_count_indexed; StatusVector spot_count_ice; StatusVector spot_count_ice_control; StatusVector indexing_solution; StatusVector indexing_lattice_count; StatusVector indexing_uc_a; StatusVector indexing_uc_b; StatusVector indexing_uc_c; StatusVector indexing_uc_alpha; StatusVector indexing_uc_beta; StatusVector indexing_uc_gamma; StatusVector error_pixels; StatusVector saturated_pixels; StatusVector strong_pixels; StatusVector receiver_delay; StatusVector receiver_buf_available; StatusVector receiver_buf_in_sending; StatusVector receiver_buf_in_preparation; StatusVector image_collection_efficiency; StatusVector packets_received; StatusVector max_value; StatusVector resolution_estimate; StatusVector integrated_reflections; StatusVector image_scale_factor; StatusVector image_scale_cc; StatusVector compression_ratio; // StatusVector objects are fully thread-safe (protected by internal mutex) // It is OK to have concurrent access to StatusVector // roi_m lock is needed to make sure that std::map is not mutable within critical section // so no new elements added outside of a unique lock, but it is OK to modify ROIStatus under shared lock struct ROIStatus { StatusVector sum; StatusVector max_count; StatusVector pixels; StatusVector x; StatusVector y; StatusVector mean; }; mutable std::shared_mutex roi_m; std::map roi_status; StatusVector profile_radius; StatusVector mosaicity_deg; StatusVector b_factor; StatusVector pixel_sum; StatusVector beam_center_x; StatusVector beam_center_y; StatusVector spot_finding_time; StatusVector indexing_time; StatusVector refinement_time; StatusVector integration_time; StatusVector bragg_prediction_time; StatusVector total_processing_time; StatusVector preprocessing_time; StatusVector compression_time; StatusVector azint_time; StatusVector indexing_analysis_time; StatusVector image_scale_time; MultiLinePlot GetROIPlot(PlotType type, int64_t nbins, float start, float incr, const std::optional &fill_value) const; void ClearVectors_i(size_t reserve); public: void Setup(const DiffractionExperiment& experiment, const AzimuthalIntegrationMapping& mapping); // Drop the previous run's plots (nothing to plot until the next Setup). void Clear(); void Add(const DataMessage& msg, const AzimuthalIntegrationProfile &profile); void AddEmptyImage(const DataMessage& msg); MultiLinePlot GetPlots(const PlotRequest& request); void GetXFELPulseID(std::vector& v) const; void GetXFELEventCode(std::vector& v) const; std::optional GetIndexingRate() const; std::optional GetBkgEstimate() const; // Run mean of the per-image spindle severity, over the frames that had one; nothing when none did. std::optional GetSpindleBlindFraction() const; std::optional GetIceRingScore() const; // Pooled over the run: spots on the hexagonal rings over the same q width of ice-free control // flanks. 1 = spots spread evenly, > 1 = they pile up on the rings (textured ice). [[nodiscard]] std::optional GetIceRingSpotRatio() const; // The run's spot-finding resolution estimate: the MEDIAN of the per-image estimates. A median and // not a mean - a few blank or badly-shot frames pull a mean a long way and leave the median where // the run actually is. [[nodiscard]] std::optional GetResolutionEstimate() const; std::vector GetIceRingScoreArray() const; std::vector GetAzIntProfile() const; // The run-summed profile object itself, rather than the array GetAzIntProfile() flattens it to. // Powder calibration reads the ring positions off it and wants its own GetResult(), which leaves a // bin no pixel fell in as NaN - as 0 it would read as a deep hole in the ring instead. Null before // Setup(); not synchronised, so use it once the run is over rather than while images arrive. [[nodiscard]] const AzimuthalIntegrationProfile *GetAzIntProfileObject() const { return az_int_profile.get(); } MultiLinePlot GetAzIntProfilePlot(bool force_1d = false, PlotAzintUnit azint_unit = PlotAzintUnit::Q_recipA) const; MeanProcessingTime GetMeanProcessingTime() const; void GetPlotRaw(std::vector &v, PlotType type, const std::string &roi); };