From 6e97b7c15c65616bbbab29aaaaebafb0975176d2 Mon Sep 17 00:00:00 2001 From: leonarski_f Date: Sat, 28 Feb 2026 16:09:14 +0100 Subject: [PATCH] JFJochReceiverPlots: Safer code --- common/StatusVector.cpp | 53 --------- common/StatusVector.h | 16 --- receiver/JFJochReceiverPlots.cpp | 190 ++++++++++++++++++++++--------- receiver/JFJochReceiverPlots.h | 34 ++++-- tests/StatusVectorTest.cpp | 22 ---- 5 files changed, 164 insertions(+), 151 deletions(-) diff --git a/common/StatusVector.cpp b/common/StatusVector.cpp index 34ec53b1..a0af404a 100644 --- a/common/StatusVector.cpp +++ b/common/StatusVector.cpp @@ -189,56 +189,3 @@ MultiLinePlot StatusVector::GetMaxPlot(int64_t bin_size, float x_start, float x_ ret.AddPlot(GetMaxPerBin(bin_size, x_start, x_incr, fill_value)); return ret; } - -void StatusMultiVector::Clear(size_t reserve) { - std::unique_lock ul(m); - if (reserve > 0) - r = reserve; - status.clear(); -} - -void StatusMultiVector::AddElement(const std::string &s, uint32_t id, float val) { - std::unique_lock ul(m); - if (!status.contains(s)) { - status[s] = std::make_unique(); - status[s]->Clear(r); - } - status[s]->AddElement(id, val); -} - -void StatusMultiVector::AddElement(const std::string &s, uint32_t id, std::optional val) { - // no need to lock, as AddElement(string, u32, T) has lock already - if (val.has_value()) - AddElement(s, id, val.value()); -} - -MultiLinePlotStruct StatusMultiVector::GetMeanPerBin(const std::string &in_key, int64_t bin_size, float x_start, - float x_incr, - const std::optional &fill_value) const { - MultiLinePlotStruct ret{}; - for (const auto &[key, value]: status) { - if (key == in_key) { - ret = value->GetMeanPerBin(bin_size, x_start, x_incr, fill_value); - ret.title = key; - } - } - return ret; -} - -MultiLinePlot StatusMultiVector::GetMeanPlot(int64_t bin_size, float x_start, float x_incr, - const std::optional &fill_value) const { - MultiLinePlot ret; - for (const auto &[key, value]: status) { - auto tmp = value->GetMeanPerBin(bin_size, x_start, x_incr, fill_value); - tmp.title = key; - ret.AddPlot(tmp); - } - return ret; -} - -std::vector StatusMultiVector::ExportArray(const std::string &s) const { - auto iter = status.find(s); - if (iter == status.end() || !iter->second) - return {}; - return iter->second->ExportArray(); -} diff --git a/common/StatusVector.h b/common/StatusVector.h index 65ea4956..c8c7e4b7 100644 --- a/common/StatusVector.h +++ b/common/StatusVector.h @@ -41,20 +41,4 @@ public: const std::optional &fill_value = {}) const; }; -class StatusMultiVector { - std::mutex m; - std::map> status; - size_t r = 0; -public: - void Clear(size_t reserve = 0); - void AddElement(const std::string& s, uint32_t id, float val); - void AddElement(const std::string& s, uint32_t id, std::optional val); - - [[nodiscard]] MultiLinePlotStruct GetMeanPerBin(const std::string& in_key, int64_t bin_size, float x_start, float x_incr, - const std::optional &fill_value = {}) const; - [[nodiscard]] MultiLinePlot GetMeanPlot(int64_t bin_size, float x_start, float x_incr, - const std::optional &fill_value = {}) const; - [[nodiscard]] std::vector ExportArray(const std::string& s) const; -}; - #endif //JUNGFRAUJOCH_STATUSVECTOR_H diff --git a/receiver/JFJochReceiverPlots.cpp b/receiver/JFJochReceiverPlots.cpp index 3edd7d0c..5578770d 100644 --- a/receiver/JFJochReceiverPlots.cpp +++ b/receiver/JFJochReceiverPlots.cpp @@ -3,6 +3,44 @@ #include "JFJochReceiverPlots.h" +#include + +MultiLinePlot JFJochReceiverPlots::GetROIPlot(PlotType type, int64_t nbins, float start, float incr, + const std::optional &fill_value) const { + MultiLinePlot ret; + + std::shared_lock sl(roi_m); + for (const auto &[key, roi] : roi_status) { + MultiLinePlotStruct plot; + switch (type) { + case PlotType::ROISum: + plot = roi.sum.GetMeanPerBin(nbins, start, incr, fill_value); + break; + case PlotType::ROIMaxCount: + plot = roi.max_count.GetMeanPerBin(nbins, start, incr, fill_value); + break; + case PlotType::ROIPixels: + plot = roi.pixels.GetMeanPerBin(nbins, start, incr, fill_value); + break; + case PlotType::ROIMean: + plot = roi.mean.GetMeanPerBin(nbins, start, incr, fill_value); + break; + case PlotType::ROIWeightedX: + plot = roi.x.GetMeanPerBin(nbins, start, incr, fill_value); + break; + case PlotType::ROIWeightedY: + plot = roi.y.GetMeanPerBin(nbins, start, incr, fill_value); + break; + default: + continue; + } + plot.title = key; + ret.AddPlot(plot); + } + + return ret; +} + void JFJochReceiverPlots::Setup(const DiffractionExperiment &experiment, const AzimuthalIntegration &mapping) { std::unique_lock ul(m); @@ -14,13 +52,14 @@ void JFJochReceiverPlots::Setup(const DiffractionExperiment &experiment, const A default_binning = experiment.GetDefaultPlotBinning(); size_t r = experiment.GetImageNum(); + // Reset all status vectors xfel_pulse_id.Clear(); + xfel_event_code.Clear(); if (experiment.IsPulsedSource()) { xfel_pulse_id.reserve(r); xfel_event_code.reserve(r); } - xfel_event_code.Clear(); bkg_estimate.Clear(r); spot_count.Clear(r); spot_count_low_res.Clear(r); @@ -28,20 +67,33 @@ void JFJochReceiverPlots::Setup(const DiffractionExperiment &experiment, const A spot_count_ice.Clear(r); indexing_solution.Clear(r); - indexing_unit_cell_angle.Clear(r); - indexing_unit_cell_len.Clear(r); + indexing_uc_a.Clear(r); + indexing_uc_b.Clear(r); + indexing_uc_c.Clear(r); + indexing_uc_alpha.Clear(r); + indexing_uc_beta.Clear(r); + indexing_uc_gamma.Clear(r); error_pixels.Clear(r); saturated_pixels.Clear(r); strong_pixels.Clear(r); receiver_delay.Clear(r); receiver_free_send_buf.Clear(r); image_collection_efficiency.Clear(r); - roi_sum.Clear(r); - roi_max_count.Clear(r); - roi_pixels.Clear(r); - roi_x.Clear(r); - roi_y.Clear(r); - roi_mean.Clear(r); + + { + std::unique_lock roi_lock(roi_m); + roi_status.clear(); + for (const auto &[name, _id] : experiment.ROI().GetROINameMap()) { + auto &entry = roi_status[name]; + entry.sum.Clear(r); + entry.max_count.Clear(r); + entry.pixels.Clear(r); + entry.x.Clear(r); + entry.y.Clear(r); + entry.mean.Clear(r); + } + } + packets_received.Clear(r); max_value.Clear(r); resolution_estimate.Clear(r); @@ -77,12 +129,12 @@ void JFJochReceiverPlots::Add(const DataMessage &msg, const AzimuthalIntegration processing_time.AddElement(msg.number, msg.processing_time_s); if (msg.indexing_unit_cell) { - indexing_unit_cell_len.AddElement("a", msg.number, msg.indexing_unit_cell->a); - indexing_unit_cell_len.AddElement("b", msg.number, msg.indexing_unit_cell->b); - indexing_unit_cell_len.AddElement("c", msg.number, msg.indexing_unit_cell->c); - indexing_unit_cell_angle.AddElement("alpha", msg.number, msg.indexing_unit_cell->alpha); - indexing_unit_cell_angle.AddElement("beta", msg.number, msg.indexing_unit_cell->beta); - indexing_unit_cell_angle.AddElement("gamma", msg.number, msg.indexing_unit_cell->gamma); + indexing_uc_a.AddElement(msg.number, msg.indexing_unit_cell->a); + indexing_uc_b.AddElement(msg.number, msg.indexing_unit_cell->b); + indexing_uc_c.AddElement(msg.number, msg.indexing_unit_cell->c); + indexing_uc_alpha.AddElement(msg.number, msg.indexing_unit_cell->alpha); + indexing_uc_beta.AddElement(msg.number, msg.indexing_unit_cell->beta); + indexing_uc_gamma.AddElement(msg.number, msg.indexing_unit_cell->gamma); } beam_center_x.AddElement(msg.number, msg.beam_corr_x); @@ -104,12 +156,22 @@ void JFJochReceiverPlots::Add(const DataMessage &msg, const AzimuthalIntegration } for (const auto &[key, value] : msg.roi) { - roi_sum.AddElement(key, msg.number, value.sum); - roi_mean.AddElement(key, msg.number, static_cast(value.sum) / static_cast(value.pixels)); - roi_max_count.AddElement(key, msg.number, value.max_count); - roi_pixels.AddElement(key, msg.number, value.pixels); - roi_x.AddElement(key, msg.number, static_cast(value.x_weighted) / static_cast(value.sum)); - roi_y.AddElement(key, msg.number, static_cast(value.y_weighted) / static_cast(value.sum)); + if (value.pixels == 0) + continue; + + std::shared_lock sl(roi_m); + auto it = roi_status.find(key); + if (it == roi_status.end()) + continue; // ROI not configured in setup -> ignore + + it->second.sum.AddElement(msg.number, value.sum); + it->second.mean.AddElement(msg.number, static_cast(value.sum) / static_cast(value.pixels)); + it->second.max_count.AddElement(msg.number, value.max_count); + it->second.pixels.AddElement(msg.number, value.pixels); + if (value.sum > 0) { + it->second.x.AddElement(msg.number, static_cast(value.x_weighted) / static_cast(value.sum)); + it->second.y.AddElement(msg.number, static_cast(value.y_weighted) / static_cast(value.sum)); + } } } @@ -120,7 +182,7 @@ void JFJochReceiverPlots::AddEmptyImage(const DataMessage &msg) { MultiLinePlot JFJochReceiverPlots::GetPlots(const PlotRequest &request) { MultiLinePlot ret; MultiLinePlotUnits units = MultiLinePlotUnits::ImageNumber; - int64_t nbins; + int64_t nbins = 1; std::optional local_grid_scan; float start = 0.0; @@ -137,6 +199,7 @@ MultiLinePlot JFJochReceiverPlots::GetPlots(const PlotRequest &request) { nbins = default_binning; if (request.binning > 0) nbins = request.binning; + nbins = std::max(1, nbins); if (request.experimental_coord && goniometer) { start = goniometer->GetStart_deg(); @@ -211,22 +274,12 @@ MultiLinePlot JFJochReceiverPlots::GetPlots(const PlotRequest &request) { ret = strong_pixels.GetMeanPlot(nbins, start, incr, request.fill_value); break; case PlotType::ROISum: - ret = roi_sum.GetMeanPlot(nbins, start, incr, request.fill_value); - break; case PlotType::ROIMaxCount: - ret = roi_max_count.GetMeanPlot(nbins, start, incr, request.fill_value); - break; case PlotType::ROIPixels: - ret = roi_pixels.GetMeanPlot(nbins, start, incr, request.fill_value); - break; case PlotType::ROIMean: - ret = roi_mean.GetMeanPlot(nbins, start, incr, request.fill_value); - break; case PlotType::ROIWeightedX: - ret = roi_x.GetMeanPlot(nbins, start, incr, request.fill_value); - break; case PlotType::ROIWeightedY: - ret = roi_y.GetMeanPlot(nbins, start, incr, request.fill_value); + ret = GetROIPlot(request.type, nbins, start, incr, request.fill_value); break; case PlotType::AzInt: ret = GetAzIntProfilePlot(false, request.azint_unit); @@ -234,18 +287,36 @@ MultiLinePlot JFJochReceiverPlots::GetPlots(const PlotRequest &request) { case PlotType::AzInt1D: ret = GetAzIntProfilePlot(true, request.azint_unit); break; - case PlotType::IndexingUnitCellLength: - ret = indexing_unit_cell_len.GetMeanPlot(nbins, start, incr, request.fill_value); + case PlotType::IndexingUnitCellLength: { + auto a = indexing_uc_a.GetMeanPerBin(nbins, start, incr, request.fill_value); + auto b = indexing_uc_b.GetMeanPerBin(nbins, start, incr, request.fill_value); + auto c = indexing_uc_c.GetMeanPerBin(nbins, start, incr, request.fill_value); + a.title = "a"; + b.title = "b"; + c.title = "c"; + ret.AddPlot(a); + ret.AddPlot(b); + ret.AddPlot(c); break; - case PlotType::IndexingUnitCellAngle: - ret = indexing_unit_cell_angle.GetMeanPlot(nbins, start, incr, request.fill_value); + } + case PlotType::IndexingUnitCellAngle: { + auto alpha = indexing_uc_alpha.GetMeanPerBin(nbins, start, incr, request.fill_value); + auto beta = indexing_uc_beta.GetMeanPerBin(nbins, start, incr, request.fill_value); + auto gamma = indexing_uc_gamma.GetMeanPerBin(nbins, start, incr, request.fill_value); + alpha.title = "alpha"; + beta.title = "beta"; + gamma.title = "gamma"; + ret.AddPlot(alpha); + ret.AddPlot(beta); + ret.AddPlot(gamma); break; + } case PlotType::PacketsReceived: ret = packets_received.GetMeanPlot(nbins, start, incr, request.fill_value); break; case PlotType::MaxValue: ret = max_value.GetMaxPlot(nbins, start, incr, request.fill_value); - break; // doesn't make sense to give mean here + break; case PlotType::PixelSum: ret = pixel_sum.GetMeanPlot(nbins, start, incr, request.fill_value); break; @@ -259,7 +330,6 @@ MultiLinePlot JFJochReceiverPlots::GetPlots(const PlotRequest &request) { ret = beam_center_y.GetMeanPlot(nbins, start, incr, request.fill_value); break; default: - // Do nothing break; } @@ -367,23 +437,41 @@ void JFJochReceiverPlots::GetPlotRaw(std::vector &v, PlotType type, const v = strong_pixels.ExportArray(); break; case PlotType::ROISum: - v = roi_sum.ExportArray(roi); - break; case PlotType::ROIMaxCount: - v = roi_max_count.ExportArray(roi); - break; case PlotType::ROIPixels: - v = roi_pixels.ExportArray(roi); - break; case PlotType::ROIMean: - v = roi_mean.ExportArray(roi); - break; case PlotType::ROIWeightedX: - v = roi_x.ExportArray(roi); - break; - case PlotType::ROIWeightedY: - v = roi_y.ExportArray(roi); + case PlotType::ROIWeightedY: { + std::shared_lock sl(roi_m); + auto it = roi_status.find(roi); + if (it == roi_status.end()) { + v.clear(); + break; + } + switch (type) { + case PlotType::ROISum: + v = it->second.sum.ExportArray(); + break; + case PlotType::ROIMaxCount: + v = it->second.max_count.ExportArray(); + break; + case PlotType::ROIPixels: + v = it->second.pixels.ExportArray(); + break; + case PlotType::ROIMean: + v = it->second.mean.ExportArray(); + break; + case PlotType::ROIWeightedX: + v = it->second.x.ExportArray(); + break; + case PlotType::ROIWeightedY: + v = it->second.y.ExportArray(); + break; + default: + break; + } break; + } case PlotType::AzInt: { std::unique_lock ul(m); if (az_int_profile) diff --git a/receiver/JFJochReceiverPlots.h b/receiver/JFJochReceiverPlots.h index 7c81a87b..d7989467 100644 --- a/receiver/JFJochReceiverPlots.h +++ b/receiver/JFJochReceiverPlots.h @@ -4,6 +4,10 @@ #ifndef JUNGFRAUJOCH_JFJOCHRECEIVERPLOTS_H #define JUNGFRAUJOCH_JFJOCHRECEIVERPLOTS_H +#include +#include +#include + #include "../common/StatusVector.h" #include "../common/Histogram.h" #include "../common/ADUHistogram.h" @@ -31,8 +35,12 @@ class JFJochReceiverPlots { StatusVector spot_count_ice; StatusVector indexing_solution; - StatusMultiVector indexing_unit_cell_len; - StatusMultiVector indexing_unit_cell_angle; + 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; @@ -42,12 +50,18 @@ class JFJochReceiverPlots { StatusVector packets_received; StatusVector max_value; StatusVector resolution_estimate; - StatusMultiVector roi_sum; - StatusMultiVector roi_max_count; - StatusMultiVector roi_pixels; - StatusMultiVector roi_x; - StatusMultiVector roi_y; - StatusMultiVector roi_mean; + + 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 indexing_time; StatusVector profile_radius; StatusVector mosaicity_deg; @@ -58,6 +72,9 @@ class JFJochReceiverPlots { StatusVector beam_center_y; StatusVector processing_time; + + MultiLinePlot GetROIPlot(PlotType type, int64_t nbins, float start, float incr, + const std::optional &fill_value) const; public: void Setup(const DiffractionExperiment& experiment, const AzimuthalIntegration& mapping); @@ -77,5 +94,4 @@ public: void GetPlotRaw(std::vector &v, PlotType type, const std::string &roi); }; - #endif //JUNGFRAUJOCH_JFJOCHRECEIVERPLOTS_H diff --git a/tests/StatusVectorTest.cpp b/tests/StatusVectorTest.cpp index f919892e..6562ddc6 100644 --- a/tests/StatusVectorTest.cpp +++ b/tests/StatusVectorTest.cpp @@ -272,28 +272,6 @@ TEST_CASE("StatusVector_Plot_NoBinning","[StatusVector]") { REQUIRE(plot_out.GetPlots()[0].y[0] == Catch::Approx(11)); } -TEST_CASE("StatusMultiVector","[StatusMultiVector]") { - StatusMultiVector status_vector; - status_vector.AddElement("plot1", 0, 4); - status_vector.AddElement("plot1", 1, 3); - status_vector.AddElement("plot2", 0, 5); - status_vector.AddElement("plot2", 1, 4); - - auto ret = status_vector.GetMeanPlot(1, 3.0, 5.0); - REQUIRE(ret.GetPlots().size() == 2); - REQUIRE(ret.GetPlots()[0].title == "plot1"); - REQUIRE(ret.GetPlots()[0].x.size() == 2); - REQUIRE(ret.GetPlots()[0].y.size() == 2); - REQUIRE(ret.GetPlots()[0].x[0] == 3.0 + 5.0 * 0.0f); - REQUIRE(ret.GetPlots()[0].y[1] == 3.0f); - - REQUIRE(ret.GetPlots()[1].title == "plot2"); - REQUIRE(ret.GetPlots()[1].x.size() == 2); - REQUIRE(ret.GetPlots()[1].y.size() == 2); - REQUIRE(ret.GetPlots()[1].x[1] == 3.0 + 5.0 * 1.0f); - REQUIRE(ret.GetPlots()[1].y[1] == 4.0f); -} - TEST_CASE("StatusVector_Clear","[StatusVector]") { StatusVector status_vector; status_vector.AddElement(5, 800);