One changeset, developed together in response to a review of this branch, so the files carry several of the changes at once. Full test suite passes (733 cases). Spot finding - Split ImageSpotFinder into Detect() (flag strong pixels - the expensive per-pixel pass) and ExtractSpots() (CCL + min/max-pix + resolution mask), with Run() = both. The per-image min-pix escalation now detects ONCE and repeats only the cheap extraction, instead of re-running the whole finder four times per frame as it did on the default path. It also keeps the winning attempt's spot list rather than re-extracting it, so the frame that is integrated is exactly the frame that was scored - which a GPU re-extract could not guarantee (float atomic ordering). - spot_finding_time_s no longer swallows indexing time, and indexing_time_s now sums every escalation call instead of reporting only the last. Detection limits follow the detector - The azimuthal-integration upper q and the spot-finding high-resolution limit are now std::optional, in the C++ structs AND in the OpenAPI schema, and resolve to the detector's own maximum (DiffractionExperiment::GetDetectorMaxQ_ recipA). Adaptive detection reads a pixel's ring from the azimuthal bins, so a pixel outside that q range could never be strong - the integration range silently bounded what detection could see, regardless of the requested resolution limit. Regenerated the C++ and TypeScript clients; the viewer and the web frontend each gained a "to detector edge" switch. Detection defaults are now per workflow (measured, not assumed) - Stills: adaptive detection, min-pix chosen per image, no resolution clipping. - Rotation: fixed-threshold finder, min-pix 2, 1.5 A limit. On a 33-crystal rotation battery, adaptive detection helped four hard crystals but deterministically broke three (a lost space group, a halved indexing rate, a collapsed merge), and the detector-edge limit cost indexing on a strong rotation set (100.0 -> 96.8%). Each is still overridable by its flag, and --no-adaptive-spots is new. Indexer seed escalation - Stop escalating once a seed's lattice explains >= 90% of the seed spots. Previously any frame with >= 80 spots always paid three indexer calls, online broker included. Merge-consistency filter - --min-image-cc gated on a per-image CC computed BEFORE the stills partiality post-refinement and never refreshed; the refiner now recomputes it, so the reported CC describes the data that are actually merged. - Replaced the per-call cc_mask argument with one MergeOnTheFly flag, so the merge, the error model and MergeStats can no longer disagree about which images are in (the --scale path merged unfiltered while its statistics were filtered). Per-image B-factor refinement (-B) removed - Measured on four serial-stills datasets: it is a no-op where the per-image fit is well conditioned and actively harmful where it is not (CC1/2 -8.1, R_meas +23.2 on the weakest large-cell set, whose fits hit their [-50, 200] bounds on 14-25% of images). It had also been silently DISCARDED since the partiality post-refinement landed - reported but not applied. Rather than fix and keep a knob with no demonstrated benefit, the flag and the whole image_scale_b_factor chain are gone: setting, scaling fit, message field, CBOR, HDF5 write and read-back, per-image plot, OpenAPI enum, viewer column and checkbox, docs. ScaleOnTheFly no longer needs Ceres at all - the fit is a linear IRLS. (The Wilson per-image b_factor is a different quantity and stays.) Stills partiality width now fits both of its components - sigma^2 = gamma0^2 + (gamma_e*d*)^2 instead of a purely angular gamma_e*d* with gamma0 pinned to 0. Fitted per crystal by least squares of dist_ewald^2 on d*^2. The angular-only width is fitted over a d*^2-dense population, so it was pinned by the high-resolution edge and collapsed at low d*: median partiality 0.008 beyond 13 A for reflections that were plainly recorded, 55% of them under the merge's partiality floor, and the survivors divided by those values - which inflated the merged low-resolution intensity scale 3.6x (~ +9 A^2 of apparent B). Measured on 5000 stills: the ramp flattens to 0.89x, no observation is dropped any more (701750 -> 716811), shell-mean CC1/2 and R-free improve slightly. Note CC1/2, R_meas, completeness and a B-refining R-free are all blind to that ramp, which is why it survived earlier validation; the cost is high-resolution R_meas (98.5 -> 101.9 shell-averaged). Removed dead code from add-then-remove churn - Prediction-time "still partiality" (unreachable: no setter), the phantom IndexingSettings::min_indexed_spot_fraction knob (getter, no setter - now the constant it always was), StillsPartialityRefine's caller-less Settings constructor and its reference to a long-gone env var, ProcessImage's unread bool return, an unused include, and a dead viewer overlay hook. Also - Viewer: the magnifier compared a QImage with itself, so its scene rect was set once ever and it could not pan into a larger dataset; the hover tail timer could fire after leaveEvent and resurrect the resolution readout outside the image. - update_version.sh regenerated the frontend lock file BEFORE bumping the version (every release shipped an off-by-one lock), and did git rm/git add on a path that has not existed since the client moved to src/client - with no set -e, both failed silently. - fpga/pcie_driver/postinstall.sh tested "[ ! occurrences > 0 ]", which is a redirect, not a test, so dkms add never ran. - Unit tests for the adaptive-threshold host functions, which had none. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
649 lines
25 KiB
C++
649 lines
25 KiB
C++
// SPDX-FileCopyrightText: 2024 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
#include "JFJochReceiverPlots.h"
|
|
|
|
#include <algorithm>
|
|
|
|
MultiLinePlot JFJochReceiverPlots::GetROIPlot(PlotType type, int64_t nbins, float start, float incr,
|
|
const std::optional<float> &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 AzimuthalIntegrationMapping &mapping) {
|
|
std::unique_lock ul(m);
|
|
|
|
az_int_profile = std::make_unique<AzimuthalIntegrationProfile>(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);
|
|
ice_ring_score.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);
|
|
profile_radius.Clear(r);
|
|
mosaicity_deg.Clear(r);
|
|
b_factor.Clear(r);
|
|
beam_center_x.Clear(r);
|
|
beam_center_y.Clear(r);
|
|
pixel_sum.Clear(r);
|
|
integrated_reflections.Clear(r);
|
|
image_scale_factor.Clear(r);
|
|
image_scale_cc.Clear(r);
|
|
|
|
refinement_time.Clear(r);
|
|
spot_finding_time.Clear(r);
|
|
integration_time.Clear(r);
|
|
total_processing_time.Clear(r);
|
|
indexing_time.Clear(r);
|
|
bragg_prediction_time.Clear(r);
|
|
preprocessing_time.Clear(r);
|
|
compression_time.Clear(r);
|
|
azint_time.Clear(r);
|
|
indexing_analysis_time.Clear(r);
|
|
image_scale_time.Clear(r);
|
|
compression_ratio.Clear(r);
|
|
indexing_lattice_count.Clear(r);
|
|
}
|
|
|
|
void JFJochReceiverPlots::Add(const DataMessage &msg, const AzimuthalIntegrationProfile &profile) {
|
|
bkg_estimate.AddElement(msg.number, msg.bkg_estimate);
|
|
ice_ring_score.AddElement(msg.number, msg.ice_ring_score);
|
|
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);
|
|
integrated_reflections.AddElement(msg.number, msg.integrated_reflections);
|
|
|
|
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);
|
|
total_processing_time.AddElement(msg.number, msg.processing_time_s);
|
|
spot_finding_time.AddElement(msg.number, msg.spot_finding_time_s);
|
|
integration_time.AddElement(msg.number, msg.integration_time_s);
|
|
refinement_time.AddElement(msg.number, msg.refinement_time_s);
|
|
bragg_prediction_time.AddElement(msg.number, msg.bragg_prediction_time_s);
|
|
preprocessing_time.AddElement(msg.number, msg.preprocessing_time_s);
|
|
compression_time.AddElement(msg.number, msg.compression_time_s);
|
|
azint_time.AddElement(msg.number, msg.azint_time_s);
|
|
indexing_analysis_time.AddElement(msg.number, msg.index_analysis_time_s);
|
|
image_scale_time.AddElement(msg.number, msg.image_scale_time_s);
|
|
compression_ratio.AddElement(msg.number, msg.compression_ratio);
|
|
|
|
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);
|
|
}
|
|
|
|
indexing_lattice_count.AddElement(msg.number, msg.indexing_lattice_count);
|
|
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);
|
|
image_scale_factor.AddElement(msg.number, msg.image_scale_factor);
|
|
image_scale_cc.AddElement(msg.number, msg.image_scale_cc);
|
|
|
|
{
|
|
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<double>(value.sum) / static_cast<double>(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<double>(value.x_weighted) / static_cast<double>(value.sum));
|
|
it->second.y.AddElement(msg.number, static_cast<double>(value.y_weighted) / static_cast<double>(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<GridScanSettings> 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<int64_t>(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::IceRingScore:
|
|
ret = ice_ring_score.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::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::CompressionRatio:
|
|
ret = compression_ratio.GetMeanPlot(nbins, start, incr, request.fill_value);
|
|
break;
|
|
case PlotType::IndexingLatticeCount:
|
|
ret = indexing_lattice_count.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::IntegratedReflections:
|
|
ret = integrated_reflections.GetMeanPlot(nbins, start, incr, request.fill_value);
|
|
break;
|
|
case PlotType::ImageScaleCC:
|
|
ret = image_scale_cc.GetMeanPlot(nbins, start, incr, request.fill_value);
|
|
break;
|
|
case PlotType::ImageScaleFactor:
|
|
ret = image_scale_factor.GetMeanPlot(nbins, start, incr, request.fill_value);
|
|
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: {
|
|
auto preprocessing = preprocessing_time.GetMeanPerBin(nbins, start, incr, request.fill_value);
|
|
preprocessing.title = "preprocessing";
|
|
if (!preprocessing.x.empty())
|
|
ret.AddPlot(preprocessing);
|
|
|
|
auto spot_finding = spot_finding_time.GetMeanPerBin(nbins, start, incr, request.fill_value);
|
|
spot_finding.title = "spot finding";
|
|
if (!spot_finding.x.empty())
|
|
ret.AddPlot(spot_finding);
|
|
|
|
auto indexing = indexing_time.GetMeanPerBin(nbins, start, incr, request.fill_value);
|
|
indexing.title = "indexing";
|
|
if (!indexing.x.empty())
|
|
ret.AddPlot(indexing);
|
|
|
|
auto indexing_analysis = indexing_analysis_time.GetMeanPerBin(nbins, start, incr, request.fill_value);
|
|
indexing_analysis.title = "indexing analysis";
|
|
if (!indexing_analysis.x.empty())
|
|
ret.AddPlot(indexing_analysis);
|
|
|
|
auto integration = integration_time.GetMeanPerBin(nbins, start, incr, request.fill_value);
|
|
integration.title = "integration";
|
|
if (!integration.x.empty())
|
|
ret.AddPlot(integration);
|
|
|
|
auto refinement = refinement_time.GetMeanPerBin(nbins, start, incr, request.fill_value);
|
|
refinement.title = "refinement";
|
|
if (!refinement.x.empty())
|
|
ret.AddPlot(refinement);
|
|
|
|
auto bragg_prediction = bragg_prediction_time.GetMeanPerBin(nbins, start, incr, request.fill_value);
|
|
bragg_prediction.title = "bragg prediction";
|
|
if (!bragg_prediction.x.empty())
|
|
ret.AddPlot(bragg_prediction);
|
|
|
|
auto compression = compression_time.GetMeanPerBin(nbins, start, incr, request.fill_value);
|
|
compression.title = "compression";
|
|
if (!compression.x.empty())
|
|
ret.AddPlot(compression);
|
|
|
|
auto azint = azint_time.GetMeanPerBin(nbins, start, incr, request.fill_value);
|
|
azint.title = "azint";
|
|
if (!azint.x.empty())
|
|
ret.AddPlot(azint);
|
|
|
|
auto scaling = image_scale_time.GetMeanPerBin(nbins, start, incr, request.fill_value);
|
|
scaling.title = "scaling";
|
|
if (!scaling.x.empty())
|
|
ret.AddPlot(scaling);
|
|
|
|
auto total = total_processing_time.GetMeanPerBin(nbins, start, incr, request.fill_value);
|
|
total.title = "total";
|
|
ret.AddPlot(total);
|
|
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<float> JFJochReceiverPlots::GetIndexingRate() const {
|
|
auto tmp = indexing_solution.Mean();
|
|
if (std::isfinite(tmp))
|
|
return tmp;
|
|
else
|
|
return {};
|
|
}
|
|
|
|
std::optional<float> JFJochReceiverPlots::GetBkgEstimate() const {
|
|
auto tmp = bkg_estimate.Mean();
|
|
if (std::isfinite(tmp))
|
|
return tmp;
|
|
else
|
|
return {};
|
|
}
|
|
|
|
MeanProcessingTime JFJochReceiverPlots::GetMeanProcessingTime() const {
|
|
MeanProcessingTime ret{};
|
|
ret.compression = compression_time.Mean();
|
|
ret.spot_finding = spot_finding_time.Mean();
|
|
ret.indexing = indexing_time.Mean();
|
|
ret.integration = integration_time.Mean();
|
|
ret.refinement = refinement_time.Mean();
|
|
ret.bragg_prediction = bragg_prediction_time.Mean();
|
|
ret.processing = total_processing_time.Mean();
|
|
ret.preprocessing = preprocessing_time.Mean();
|
|
ret.azint = azint_time.Mean();
|
|
ret.indexing_analysis = indexing_analysis_time.Mean();
|
|
ret.image_scale = image_scale_time.Mean();
|
|
return ret;
|
|
}
|
|
|
|
void JFJochReceiverPlots::GetXFELPulseID(std::vector<uint64_t> &v) const {
|
|
std::unique_lock ul(m);
|
|
v = xfel_pulse_id.vec();
|
|
}
|
|
|
|
void JFJochReceiverPlots::GetXFELEventCode(std::vector<uint64_t> &v) const {
|
|
std::unique_lock ul(m);
|
|
v = xfel_event_code.vec();
|
|
}
|
|
|
|
std::vector<float> 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<float> &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::IceRingScore:
|
|
v = ice_ring_score.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::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::ImageScaleCC:
|
|
v = image_scale_cc.ExportArray();
|
|
break;
|
|
case PlotType::ImageScaleFactor:
|
|
v = image_scale_factor.ExportArray();
|
|
break;
|
|
case PlotType::CompressionRatio:
|
|
v = compression_ratio.ExportArray();
|
|
break;
|
|
case PlotType::IndexingLatticeCount:
|
|
v = indexing_lattice_count.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 = total_processing_time.ExportArray();
|
|
break;
|
|
case PlotType::RefinementBeamX:
|
|
v = beam_center_x.ExportArray();
|
|
break;
|
|
case PlotType::RefinementBeamY:
|
|
v = beam_center_y.ExportArray();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|