// SPDX-FileCopyrightText: 2024 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only #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); az_int_profile = std::make_unique(mapping); az_int_profile->SetTitle("dataset"); goniometer = experiment.GetGoniometer(); grid_scan = experiment.GetGridScan(); 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); } bkg_estimate.Clear(r); spot_count.Clear(r); spot_count_low_res.Clear(r); spot_count_indexed.Clear(r); spot_count_ice.Clear(r); indexing_solution.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_buf_available.Clear(r); receiver_buf_in_preparation.Clear(r); receiver_buf_in_sending.Clear(r); image_collection_efficiency.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); indexing_time.Clear(r); profile_radius.Clear(r); mosaicity_deg.Clear(r); b_factor.Clear(r); processing_time.Clear(r); beam_center_x.Clear(r); beam_center_y.Clear(r); pixel_sum.Clear(r); } void JFJochReceiverPlots::Add(const DataMessage &msg, const AzimuthalIntegrationProfile &profile) { bkg_estimate.AddElement(msg.number, msg.bkg_estimate); resolution_estimate.AddElement(msg.number, msg.resolution_estimate); spot_count.AddElement(msg.number, msg.spot_count); spot_count_low_res.AddElement(msg.number, msg.spot_count_low_res); spot_count_indexed.AddElement(msg.number, msg.spot_count_indexed); spot_count_ice.AddElement(msg.number, msg.spot_count_ice_rings); error_pixels.AddElement(msg.number, msg.error_pixel_count); saturated_pixels.AddElement(msg.number, msg.saturated_pixel_count); pixel_sum.AddElement(msg.number, msg.pixel_sum); strong_pixels.AddElement(msg.number, msg.strong_pixel_count); packets_received.AddElement(msg.number, msg.packets_received); image_collection_efficiency.AddElement(msg.number, msg.image_collection_efficiency); receiver_delay.AddElement(msg.number, msg.receiver_aq_dev_delay); receiver_buf_available.AddElement(msg.number, msg.receiver_buf_available); receiver_buf_in_sending.AddElement(msg.number, msg.receiver_buf_in_sending); receiver_buf_in_preparation.AddElement(msg.number, msg.receiver_buf_in_preparation); max_value.AddElement(msg.number, msg.max_viable_pixel_value); indexing_time.AddElement(msg.number, msg.indexing_time_s); processing_time.AddElement(msg.number, msg.processing_time_s); if (msg.indexing_unit_cell) { 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); beam_center_y.AddElement(msg.number, msg.beam_corr_y); profile_radius.AddElement(msg.number, msg.profile_radius); mosaicity_deg.AddElement(msg.number, msg.mosaicity_deg); b_factor.AddElement(msg.number, msg.b_factor); indexing_solution.AddElement(msg.number, msg.indexing_result); { std::unique_lock ul(m); if (az_int_profile) *az_int_profile += profile; if (msg.xfel_pulse_id.has_value()) xfel_pulse_id[msg.number] = msg.xfel_pulse_id.value(); if (msg.xfel_event_code.has_value()) xfel_event_code[msg.number] = msg.xfel_event_code.value(); } for (const auto &[key, value] : msg.roi) { 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)); } } } void JFJochReceiverPlots::AddEmptyImage(const DataMessage &msg) { image_collection_efficiency.AddElement(msg.number, msg.image_collection_efficiency); } MultiLinePlot JFJochReceiverPlots::GetPlots(const PlotRequest &request) { MultiLinePlot ret; MultiLinePlotUnits units = MultiLinePlotUnits::ImageNumber; int64_t nbins = 1; std::optional local_grid_scan; float start = 0.0; float incr = 1.0; if (request.type != PlotType::AzInt && request.type != PlotType::AzInt1D) { std::unique_lock ul(m); if (request.experimental_coord && grid_scan) { local_grid_scan = grid_scan; units = MultiLinePlotUnits::Grid_um; nbins = 1; } else { nbins = default_binning; if (request.binning > 0) nbins = request.binning; nbins = std::max(1, nbins); if (request.experimental_coord && goniometer) { start = goniometer->GetStart_deg(); incr = goniometer->GetIncrement_deg(); units = MultiLinePlotUnits::Angle_deg; } } } else { switch (request.azint_unit) { case PlotAzintUnit::Q_recipA: units = MultiLinePlotUnits::Q_recipA; break; case PlotAzintUnit::TwoTheta_deg: units = MultiLinePlotUnits::Angle_deg; break; case PlotAzintUnit::D_A: units = MultiLinePlotUnits::d_A; break; } } switch (request.type) { case PlotType::SpotCount: ret = spot_count.GetMeanPlot(nbins, start, incr, request.fill_value); break; case PlotType::SpotCountLowRes: ret = spot_count_low_res.GetMeanPlot(nbins, start, incr, request.fill_value); break; case PlotType::SpotCountIndexed: ret = spot_count_indexed.GetMeanPlot(nbins, start, incr, request.fill_value); break; case PlotType::SpotCountIceRing: ret = spot_count_ice.GetMeanPlot(nbins, start, incr, request.fill_value); break; case PlotType::IndexingRate: ret = indexing_solution.GetMeanPlot(nbins, start, incr, request.fill_value); break; case PlotType::BkgEstimate: ret = bkg_estimate.GetMeanPlot(nbins, start, incr, request.fill_value); break; case PlotType::ResolutionEstimate: ret = resolution_estimate.GetMeanPlot(nbins, start, incr, request.fill_value); break; case PlotType::ErrorPixels: ret = error_pixels.GetMeanPlot(nbins, start, incr, request.fill_value); break; case PlotType::SaturatedPixels: ret = saturated_pixels.GetMeanPlot(nbins, start, incr, request.fill_value); break; case PlotType::IndexingTime: ret = indexing_time.GetMeanPlot(nbins, start, incr, request.fill_value); break; case PlotType::ProfileRadius: ret = profile_radius.GetMeanPlot(nbins, start, incr, request.fill_value); break; case PlotType::Mosaicity: ret = mosaicity_deg.GetMeanPlot(nbins, start, incr, request.fill_value); break; case PlotType::BFactor: ret = b_factor.GetMeanPlot(nbins, start, incr, request.fill_value); break; case PlotType::ImageCollectionEfficiency: ret = image_collection_efficiency.GetMeanPlot(nbins, start, incr, request.fill_value); break; case PlotType::ReceiverDelay: ret = receiver_delay.GetMeanPlot(nbins, start, incr, request.fill_value); break; case PlotType::ReceiverFreeSendBuf: { auto available = receiver_buf_available.GetMeanPerBin(nbins, start, incr, request.fill_value); auto sending = receiver_buf_in_sending.GetMeanPerBin(nbins, start, incr, request.fill_value); auto preparation = receiver_buf_in_preparation.GetMeanPerBin(nbins, start, incr, request.fill_value); available.title = "available"; sending.title = "sending"; preparation.title = "preparation"; ret.AddPlot(available); ret.AddPlot(sending); ret.AddPlot(preparation); break; } case PlotType::StrongPixels: ret = strong_pixels.GetMeanPlot(nbins, start, incr, request.fill_value); break; case PlotType::ROISum: case PlotType::ROIMaxCount: case PlotType::ROIPixels: case PlotType::ROIMean: case PlotType::ROIWeightedX: case PlotType::ROIWeightedY: ret = GetROIPlot(request.type, nbins, start, incr, request.fill_value); break; case PlotType::AzInt: ret = GetAzIntProfilePlot(false, request.azint_unit); break; case PlotType::AzInt1D: ret = GetAzIntProfilePlot(true, request.azint_unit); break; 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: { 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; case PlotType::PixelSum: ret = pixel_sum.GetMeanPlot(nbins, start, incr, request.fill_value); break; case PlotType::ImageProcessingTime: ret = processing_time.GetMeanPlot(nbins, start, incr, request.fill_value); break; case PlotType::RefinementBeamX: ret = beam_center_x.GetMeanPlot(nbins, start, incr, request.fill_value); break; case PlotType::RefinementBeamY: ret = beam_center_y.GetMeanPlot(nbins, start, incr, request.fill_value); break; default: break; } ret.SetUnits(units); if (local_grid_scan && request.type != PlotType::AzInt && request.type != PlotType::AzInt1D) ret.Convert2D(local_grid_scan.value()); return ret; } std::optional JFJochReceiverPlots::GetIndexingRate() const { auto tmp = indexing_solution.Mean(); if (std::isfinite(tmp)) return tmp; else return {}; } std::optional JFJochReceiverPlots::GetBkgEstimate() const { auto tmp = bkg_estimate.Mean(); if (std::isfinite(tmp)) return tmp; else return {}; } void JFJochReceiverPlots::GetXFELPulseID(std::vector &v) const { std::unique_lock ul(m); v = xfel_pulse_id.vec(); } void JFJochReceiverPlots::GetXFELEventCode(std::vector &v) const { std::unique_lock ul(m); v = xfel_event_code.vec(); } std::vector JFJochReceiverPlots::GetAzIntProfile() const { std::unique_lock ul(m); if (!az_int_profile) return {}; auto plot = az_int_profile->GetResult(); for (auto &i: plot) if (!std::isfinite(i)) i = 0; return plot; } MultiLinePlot JFJochReceiverPlots::GetAzIntProfilePlot(bool force_1d, PlotAzintUnit azint_unit) const { std::unique_lock ul(m); if (!az_int_profile) return {}; return az_int_profile->GetPlot(force_1d, azint_unit); } void JFJochReceiverPlots::GetPlotRaw(std::vector &v, PlotType type, const std::string &roi) { switch (type) { case PlotType::SpotCount: v = spot_count.ExportArray(); break; case PlotType::SpotCountLowRes: v = spot_count_low_res.ExportArray(); break; case PlotType::SpotCountIndexed: v = spot_count_indexed.ExportArray(); break; case PlotType::SpotCountIceRing: v = spot_count_ice.ExportArray(); break; case PlotType::IndexingRate: v = indexing_solution.ExportArray(); break; case PlotType::BkgEstimate: v = bkg_estimate.ExportArray(); break; case PlotType::ResolutionEstimate: v = resolution_estimate.ExportArray(); break; case PlotType::ErrorPixels: v = error_pixels.ExportArray(); break; case PlotType::SaturatedPixels: v = saturated_pixels.ExportArray(); break; case PlotType::IndexingTime: v = indexing_time.ExportArray(); break; case PlotType::ProfileRadius: v = profile_radius.ExportArray(); break; case PlotType::BFactor: v = b_factor.ExportArray(); break; case PlotType::ImageCollectionEfficiency: v = image_collection_efficiency.ExportArray(); break; case PlotType::ReceiverDelay: v = receiver_delay.ExportArray(); break; case PlotType::ReceiverFreeSendBuf: v = receiver_buf_available.ExportArray(); break; case PlotType::StrongPixels: v = strong_pixels.ExportArray(); break; case PlotType::ROISum: case PlotType::ROIMaxCount: case PlotType::ROIPixels: case PlotType::ROIMean: case PlotType::ROIWeightedX: 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) v = az_int_profile->GetResult(); break; } case PlotType::AzInt1D: { std::unique_lock ul(m); if (az_int_profile) v = az_int_profile->GetResult1D(); break; } case PlotType::PacketsReceived: v = packets_received.ExportArray(); break; case PlotType::MaxValue: v = max_value.ExportArray(); break; case PlotType::PixelSum: v = pixel_sum.ExportArray(); break; case PlotType::ImageProcessingTime: v = processing_time.ExportArray(); break; case PlotType::RefinementBeamX: v = beam_center_x.ExportArray(); break; case PlotType::RefinementBeamY: v = beam_center_y.ExportArray(); break; default: break; } }