The per-image ice score was read off the PLAIN azimuthal profile. That profile is a per-ring mean, so a few strong Bragg reflections landing in a ring's q bin lift it exactly as ice would. Measured over 37 rotation crystals, that did not merely add noise - it INVERTED the metric: the two highest-scoring crystals had no ice at all (4.23 and 4.06), while a clean control read 1.57. A decoy null - the identical statistic evaluated at q positions where hexagonal ice cannot be - reaches 1.51 at its 99th percentile and 2.70 at its maximum, so that metric cannot support any absolute threshold whatsoever. The adaptive spot finder already computes the right input for its own threshold: a sigma-clipped per-resolution-ring background, in the same bins. A powder ring is azimuthally smooth and survives the clip; Bragg peaks do not. On the clipped profile the clean population tightens to 1.00-1.22 and the crystals with confirmed ice sit at 2.08-2.37, against a decoy null that never exceeds 1.29. That channel is blind to one thing: ice in large crystallites diffracts as DISCRETE spots and leaves the radial profile flat. So a second channel counts found spots on the rings against the same q width of ice-free flanks beside them. The two barely overlap - the smooth-ice crystals read 2.1-2.4 / ~1.0 and the textured ones ~1.1 / 3.8-17.6, while a clean crystal reads 1.04 on both. Both are then used as a GATE (--ice-min-score 1.5, --ice-min-spot-ratio 2.0, both calibrated on the battery, 0 disables): the eleven fixed hexagonal bands cover 16-26 % of the unique reflections at typical resolutions whether or not the crystal has ice, so flagging, the exclusion from the scale fit and the merge-time CC1/2 ring mask are now all skipped when neither channel sees any. The gate is applied in the full pipeline and in --scale, which reads the stored per-image values back out of the _process.h5. Also fixes the merge-time mask's control: the shoulder now excludes reflections that are themselves on an ice ring. The rings are not evenly spaced - 1.947/1.916/1.882 A sit 0.05-0.06 apart in q - so for those three the [w,3w) shoulder landed squarely on the neighbours and the test compared ice against ice. Measured, that is the only thing this changes: it removes firings on those three rings and leaves every other firing's CC pair identical to three decimals. And the online ice half-width, which was 0.02 in the API against 0.03 offline, so the same data got a narrower band online than the measured ~0.06 ring FWHM justifies. Battery (37 rotation crystals, against the previous behaviour): space groups 34/37 in both and NO crystal's space group changes; 6 crystals gain unique reflections, 1 loses. Best of them gains 7082 unique reflections with R_meas 16.0 -> 14.3, CC1/2 95.9 -> 97.3 and ISa 13.7 -> 19.0; another goes R_meas 54.9 -> 42.9, CC1/2 84.0 -> 90.4, ISa 3.9 -> 5.5; a third reaches CC1/2 99.4 from 95.7 at an unchanged reflection count. The one crystal that loses reflections improves on both R_meas and CC1/2. Not done here: the ScanResult/API/plot-type/frontend/viewer layers for the new spot_count_ice_control (they need the OpenAPI regeneration). Message, CBOR, HDF5 write/read and the receiver plots are. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
678 lines
26 KiB
C++
678 lines
26 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);
|
|
spot_count_ice_control.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);
|
|
spot_count_ice_control.AddElement(msg.number, msg.spot_count_ice_control);
|
|
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 {};
|
|
}
|
|
|
|
std::optional<float> JFJochReceiverPlots::GetIceRingSpotRatio() const {
|
|
// A ratio of MEANS, not a mean of ratios: one image holds a handful of control spots, so a
|
|
// per-image ratio is dominated by its own denominator. Pooling over the run is the measurement.
|
|
const float ring = spot_count_ice.Mean();
|
|
const float control = spot_count_ice_control.Mean();
|
|
if (!std::isfinite(ring) || !std::isfinite(control))
|
|
return std::nullopt;
|
|
// An empty control with spots on the rings is the STRONGEST evidence of ice there is, not the
|
|
// absence of it - a crystal whose found spots are all ice leaves nothing in the flanks. Report a
|
|
// large finite ratio rather than dividing by zero.
|
|
if (!(control > 0.0f))
|
|
return ring > 0.0f ? 1.0e3f : std::optional<float>{};
|
|
return ring / control;
|
|
}
|
|
|
|
std::optional<float> JFJochReceiverPlots::GetIceRingScore() const {
|
|
auto tmp = ice_ring_score.Mean();
|
|
if (std::isfinite(tmp))
|
|
return tmp;
|
|
else
|
|
return {};
|
|
}
|
|
|
|
std::vector<float> JFJochReceiverPlots::GetIceRingScoreArray() const {
|
|
return ice_ring_score.ExportArray();
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|