diff --git a/common/time_utc.h b/common/time_utc.h index bec55fd75..2dfaedb20 100644 --- a/common/time_utc.h +++ b/common/time_utc.h @@ -12,6 +12,10 @@ #include #include +inline double SecondsSince(std::chrono::steady_clock::time_point t0) { + return std::chrono::duration(std::chrono::steady_clock::now() - t0).count(); +} + inline std::string time_UTC(const std::chrono::time_point &input) { auto time_ms = std::chrono::duration_cast(input.time_since_epoch()).count(); diff --git a/receiver/JFJochReceiver.cpp b/receiver/JFJochReceiver.cpp index 46183780f..ccaaf68ee 100644 --- a/receiver/JFJochReceiver.cpp +++ b/receiver/JFJochReceiver.cpp @@ -61,6 +61,12 @@ SpotFindingSettings JFJochReceiver::GetSpotFindingSettings() { return spot_finding_settings; } +void JFJochReceiver::SetSpotFindingSettings(const SpotFindingSettings &in_spot_finding_settings) { + std::unique_lock ul(spot_finding_settings_mutex); + DiffractionExperiment::CheckDataProcessingSettings(in_spot_finding_settings); + spot_finding_settings = in_spot_finding_settings; +} + void JFJochReceiver::UpdateMaxImageSent(int64_t image_number) { std::unique_lock ul(max_image_number_sent_mutex); if (image_number + 1 > max_image_number_sent) diff --git a/receiver/JFJochReceiver.h b/receiver/JFJochReceiver.h index 416aab14a..2afe52c31 100644 --- a/receiver/JFJochReceiver.h +++ b/receiver/JFJochReceiver.h @@ -125,7 +125,7 @@ public: virtual void Cancel(bool silent); virtual float GetProgress() const = 0; - virtual void SetSpotFindingSettings(const SpotFindingSettings &spot_finding_settings) = 0; + virtual void SetSpotFindingSettings(const SpotFindingSettings &spot_finding_settings); virtual JFJochReceiverOutput GetFinalStatistics() const; }; diff --git a/receiver/JFJochReceiverLite.cpp b/receiver/JFJochReceiverLite.cpp index 55cb9299c..362c4bf22 100644 --- a/receiver/JFJochReceiverLite.cpp +++ b/receiver/JFJochReceiverLite.cpp @@ -463,12 +463,6 @@ float JFJochReceiverLite::GetProgress() const { return static_cast(max_image_number_received) / static_cast(ExpectedImages()); } -void JFJochReceiverLite::SetSpotFindingSettings(const SpotFindingSettings &in_spot_finding_settings) { - std::unique_lock ul(spot_finding_settings_mutex); - DiffractionExperiment::CheckDataProcessingSettings(in_spot_finding_settings); - spot_finding_settings = in_spot_finding_settings; -} - JFJochReceiverOutput JFJochReceiverLite::GetFinalStatistics() const { JFJochReceiverOutput ret = JFJochReceiver::GetFinalStatistics(); if (experiment.GetDetectorMode() == DetectorMode::DarkMask) diff --git a/receiver/JFJochReceiverLite.h b/receiver/JFJochReceiverLite.h index f33fadd4c..277a25d90 100644 --- a/receiver/JFJochReceiverLite.h +++ b/receiver/JFJochReceiverLite.h @@ -92,7 +92,6 @@ public: float GetEfficiency() const override; float GetProgress() const override; - void SetSpotFindingSettings(const SpotFindingSettings &spot_finding_settings) override; JFJochReceiverOutput GetFinalStatistics() const override; }; diff --git a/receiver/JFJochReceiverPedestal.cpp b/receiver/JFJochReceiverPedestal.cpp index 580461833..0009a32b3 100644 --- a/receiver/JFJochReceiverPedestal.cpp +++ b/receiver/JFJochReceiverPedestal.cpp @@ -30,19 +30,8 @@ JFJochReceiverPedestal::JFJochReceiverPedestal(const DiffractionExperiment &in_e ndatastreams(experiment.GetDataStreamsNum()), pedestal_nthreads((experiment.GetStorageCellNumber() > 2) ? 1 : 4), data_acquisition_ready(ndatastreams) { - // The same limit as for an image run, so a configuration is refused the same way in both. - const auto &azint_settings = experiment.GetAzimuthalIntegrationSettings(); - if (!azint_settings.IsForceCPUinFPGAWorkflow() && azint_settings.GetBinCount() > FPGA_INTEGRATION_BIN_COUNT) - throw JFJochException(JFJochExceptionCategory::InputParameterAboveMax, - fmt::format("Azimuthal integration bin count ({}) exceeds the FPGA limit ({}). " - "Enable ForceCPUinFPGAWorkflow to compute it on the CPU.", - azint_settings.GetBinCount(), FPGA_INTEGRATION_BIN_COUNT)); - image_buffer.StartMeasurement(experiment); - for (int m = 0; m < experiment.GetModulesNum(); m++) - adu_histogram_module.emplace_back(std::make_unique()); - if (acquisition_device.size() < ndatastreams) throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Number of acquisition devices has to match data streams"); @@ -50,8 +39,6 @@ JFJochReceiverPedestal::JFJochReceiverPedestal(const DiffractionExperiment &in_e expected_packets_per_image = 0; for (int d = 0; d < ndatastreams; d++) { acquisition_device[d].PrepareAction(experiment); - acquisition_device[d].SetSpotFinderParameters(spot_finding_settings); - expected_packets_per_image += acquisition_device[d].Counters().GetExpectedPacketsPerImage(); logger.Debug("Acquisition device {} prepared", d); @@ -222,14 +209,6 @@ void JFJochReceiverPedestal::FinalizeMeasurement() { current_status.SetStatus(GetStatus()); } -void JFJochReceiverPedestal::SetSpotFindingSettings(const SpotFindingSettings &in_spot_finding_settings) { - std::unique_lock ul(spot_finding_settings_mutex); - DiffractionExperiment::CheckDataProcessingSettings(in_spot_finding_settings); - spot_finding_settings = in_spot_finding_settings; - for (int i = 0; i < ndatastreams; i++) - acquisition_device[i].SetSpotFinderParameters(spot_finding_settings); -} - void JFJochReceiverPedestal::StopReceiver() { if (measurement.valid()) { measurement.get(); diff --git a/receiver/JFJochReceiverPedestal.h b/receiver/JFJochReceiverPedestal.h index a56abad44..fdb68db91 100644 --- a/receiver/JFJochReceiverPedestal.h +++ b/receiver/JFJochReceiverPedestal.h @@ -63,7 +63,5 @@ public: void Cancel(bool silent) override; float GetProgress() const override; - void SetSpotFindingSettings(const SpotFindingSettings &spot_finding_settings) override; - JFJochReceiverOutput GetFinalStatistics() const override; }; diff --git a/receiver/JFJochReceiverRugnux.cpp b/receiver/JFJochReceiverRugnux.cpp index 042b10d60..c84b6cd13 100644 --- a/receiver/JFJochReceiverRugnux.cpp +++ b/receiver/JFJochReceiverRugnux.cpp @@ -11,6 +11,7 @@ #include "JFJochReceiverLite.h" #include "../common/HostMemory.h" +#include "../common/time_utc.h" #include "../frame_serialize/CBORStream2Deserializer.h" #include "../frame_serialize/CBORStream2Serializer.h" #include "../image_analysis/indexing/IndexerThreadPool.h" @@ -37,10 +38,6 @@ namespace { return budget > taken ? budget - taken : 1; } - double SecondsSince(std::chrono::steady_clock::time_point t) { - return std::chrono::duration(std::chrono::steady_clock::now() - t).count(); - } - // A run reachable for Cut while it exists: registered in `slot` (under `m`, cancelled at once where the // cut came first) and taken off again before it is destroyed, an exception included. class Reachable { @@ -99,90 +96,6 @@ namespace { } } -namespace { - // A score the status carries only where it is a number: JSON has no NaN or infinity (nlohmann writes null) - void SetIfFinite(std::optional &out, double v) { - if (std::isfinite(v)) - out = v; - } -} - -std::optional LiveModel(const ProcessResult &result) { - if (!result.model_validation && !result.model_prior) - return std::nullopt; - RugnuxLiveModel m; - m.placement = result.model_placement; - if (result.model_prior) { - const MolecularReplacementResult &mr = *result.model_prior; - m.model_name = mr.model_name; - m.predicted = mr.predicted_model; - m.mr_decision = mr.decision; - if (!mr.ok) - m.reason = mr.failure_reason; - if (mr.chosen >= 0) { - const MRCandidate &c = mr.candidates[mr.chosen]; - m.mr_space_group = c.space_group.xhm(); - m.copies = c.copies; - SetIfFinite(m.tf_z, c.tf_z); - SetIfFinite(m.rf_z, c.rf_z); - SetIfFinite(m.llg_z, c.llg_z); - SetIfFinite(m.fit_sigma, c.null_sigma); - SetIfFinite(m.mr_d_min, mr.d_min_search); - } - } - if (result.model_validation) { - const ModelValidationResult &v = *result.model_validation; - if (!v.model_name.empty()) - m.model_name = v.model_name; - if (!v.ok) { - if (m.reason.empty()) - m.reason = v.failure_reason; - } else { - SetIfFinite(m.r_work, v.r_work); - SetIfFinite(m.r_free, v.r_free); - SetIfFinite(m.cc_model, v.cc_model_overall); - if (v.fit_tested) - SetIfFinite(m.fit_sigma, v.r_work_sigma); - SetIfFinite(m.map_atom_sigma, v.mean_atom_density_sigma); - if (v.rigid_body_applied) { - SetIfFinite(m.rigid_body_angle_deg, v.rigid_body_angle_deg); - SetIfFinite(m.rigid_body_shift_A, v.rigid_body_shift_A); - } - if (!v.anomalous_sites.empty()) { - m.anomalous_site = v.anomalous_sites.front().label; - SetIfFinite(m.anomalous_site_sigma, v.anomalous_sites.front().sigma); - } - } - } - if (result.refinement) { - const RefinementResult &rf = *result.refinement; - RugnuxLiveRefinement r; - r.performed = rf.ok; - r.cancelled = rf.cancelled; - r.reason = rf.failure_reason; - r.on_gpu = rf.on_gpu; - r.seconds = rf.seconds; - if (rf.ok) { - SetIfFinite(r.r_work, rf.restrained ? rf.r_work : rf.r_work_placement); - SetIfFinite(r.r_free, rf.restrained ? rf.r_free : rf.r_free_placement); - if (rf.restrained) { - SetIfFinite(r.rmsd_bonds_A, rf.geometry.rmsd_bonds); - SetIfFinite(r.rmsd_angles_deg, rf.geometry.rmsd_angles); - } - } - r.blob_count = static_cast(rf.blobs.size()); - for (size_t i = 0; i < std::min(rf.blobs.size(), RugnuxLiveRefinement::MAX_BLOBS); i++) { - const DensityBlob &b = rf.blobs[i]; - RugnuxLiveBlob blob{DensityBlobKindName(b.kind), b.centroid.x, b.centroid.y, b.centroid.z, b.peak_sigma, - b.volume, b.nearest_atom, std::nullopt}; - SetIfFinite(blob.nearest_atom_distance_A, b.nearest_atom_distance); // infinite: no atom near - r.blobs.push_back(blob); - } - m.refinement = std::move(r); - } - return m; -} - JFJochReceiverRugnux::JFJochReceiverRugnux(const DiffractionExperiment &in_experiment, const PixelMask &in_pixel_mask, ImagePuller &in_image_puller, @@ -635,7 +548,8 @@ void JFJochReceiverRugnux::RugnuxThread() { // The numbers the summary's Space group, Resolution and Signal rows give std::optional d_min, isa; if (result.has_merge_statistics) - SetIfFinite(d_min, result.merge_statistics.overall.d_min); + if (std::isfinite(result.merge_statistics.overall.d_min)) + d_min = result.merge_statistics.overall.d_min; if (!result.merge_statistics.stills && result.error_model_isa_resolved && result.error_model_isa > 0.0) isa = result.error_model_isa; live_status.Headline(result.space_group ? result.space_group->xhm() : "", d_min, isa); @@ -882,11 +796,8 @@ void JFJochReceiverRugnux::StopReceiver() { void JFJochReceiverRugnux::SetSpotFindingSettings(const SpotFindingSettings &in_spot_finding_settings) { // A rotation run takes rugnux's own spot finding; the frames of a serial run are analysed with these. - if (!stills_run) - return; - std::unique_lock ul(spot_finding_settings_mutex); - DiffractionExperiment::CheckDataProcessingSettings(in_spot_finding_settings); - spot_finding_settings = in_spot_finding_settings; + if (stills_run) + JFJochReceiver::SetSpotFindingSettings(in_spot_finding_settings); } float JFJochReceiverRugnux::GetEfficiency() const { diff --git a/receiver/JFJochReceiverRugnux.h b/receiver/JFJochReceiverRugnux.h index 1065f449c..c1020f1a7 100644 --- a/receiver/JFJochReceiverRugnux.h +++ b/receiver/JFJochReceiverRugnux.h @@ -13,9 +13,6 @@ #include "RugnuxLiveStatus.h" #include "StillsGPUAnalysis.h" -// What the run made of the model it was given, for the live status; none where no model was given. -std::optional LiveModel(const ProcessResult &result); - // A DECTRIS rotation collection forwarded to the writer as JFJochReceiverLite does, but analysed by // rugnux while it arrives instead of image by image: the forward threads put each image into the // image buffer and send it on, and one rugnux thread reads the collection back from that buffer. The diff --git a/receiver/RugnuxLiveStatus.cpp b/receiver/RugnuxLiveStatus.cpp index 755700609..dd33c6240 100644 --- a/receiver/RugnuxLiveStatus.cpp +++ b/receiver/RugnuxLiveStatus.cpp @@ -3,6 +3,11 @@ #include "RugnuxLiveStatus.h" +#include +#include + +#include "../rugnux/Rugnux.h" + double RugnuxLiveStatus::Since(std::chrono::steady_clock::time_point t) const { return std::chrono::duration(t - start).count(); } @@ -157,3 +162,87 @@ RugnuxLiveSnapshot RugnuxLiveStatus::Get() const { *ret.cut_s -= zero; return ret; } + +namespace { + // A score the status carries only where it is a number: JSON has no NaN or infinity (nlohmann writes null) + void SetIfFinite(std::optional &out, double v) { + if (std::isfinite(v)) + out = v; + } +} + +std::optional LiveModel(const ProcessResult &result) { + if (!result.model_validation && !result.model_prior) + return std::nullopt; + RugnuxLiveModel m; + m.placement = result.model_placement; + if (result.model_prior) { + const MolecularReplacementResult &mr = *result.model_prior; + m.model_name = mr.model_name; + m.predicted = mr.predicted_model; + m.mr_decision = mr.decision; + if (!mr.ok) + m.reason = mr.failure_reason; + if (mr.chosen >= 0) { + const MRCandidate &c = mr.candidates[mr.chosen]; + m.mr_space_group = c.space_group.xhm(); + m.copies = c.copies; + SetIfFinite(m.tf_z, c.tf_z); + SetIfFinite(m.rf_z, c.rf_z); + SetIfFinite(m.llg_z, c.llg_z); + SetIfFinite(m.fit_sigma, c.null_sigma); + SetIfFinite(m.mr_d_min, mr.d_min_search); + } + } + if (result.model_validation) { + const ModelValidationResult &v = *result.model_validation; + if (!v.model_name.empty()) + m.model_name = v.model_name; + if (!v.ok) { + if (m.reason.empty()) + m.reason = v.failure_reason; + } else { + SetIfFinite(m.r_work, v.r_work); + SetIfFinite(m.r_free, v.r_free); + SetIfFinite(m.cc_model, v.cc_model_overall); + if (v.fit_tested) + SetIfFinite(m.fit_sigma, v.r_work_sigma); + SetIfFinite(m.map_atom_sigma, v.mean_atom_density_sigma); + if (v.rigid_body_applied) { + SetIfFinite(m.rigid_body_angle_deg, v.rigid_body_angle_deg); + SetIfFinite(m.rigid_body_shift_A, v.rigid_body_shift_A); + } + if (!v.anomalous_sites.empty()) { + m.anomalous_site = v.anomalous_sites.front().label; + SetIfFinite(m.anomalous_site_sigma, v.anomalous_sites.front().sigma); + } + } + } + if (result.refinement) { + const RefinementResult &rf = *result.refinement; + RugnuxLiveRefinement r; + r.performed = rf.ok; + r.cancelled = rf.cancelled; + r.reason = rf.failure_reason; + r.on_gpu = rf.on_gpu; + r.seconds = rf.seconds; + if (rf.ok) { + SetIfFinite(r.r_work, rf.restrained ? rf.r_work : rf.r_work_placement); + SetIfFinite(r.r_free, rf.restrained ? rf.r_free : rf.r_free_placement); + if (rf.restrained) { + SetIfFinite(r.rmsd_bonds_A, rf.geometry.rmsd_bonds); + SetIfFinite(r.rmsd_angles_deg, rf.geometry.rmsd_angles); + } + } + r.blob_count = static_cast(rf.blobs.size()); + for (size_t i = 0; i < std::min(rf.blobs.size(), RugnuxLiveRefinement::MAX_BLOBS); i++) { + const DensityBlob &b = rf.blobs[i]; + RugnuxLiveBlob blob{DensityBlobKindName(b.kind), b.centroid.x, b.centroid.y, b.centroid.z, b.peak_sigma, + b.volume, b.nearest_atom, std::nullopt}; + SetIfFinite(blob.nearest_atom_distance_A, b.nearest_atom_distance); // infinite: no atom near + r.blobs.push_back(blob); + } + m.refinement = std::move(r); + } + return m; +} diff --git a/receiver/RugnuxLiveStatus.h b/receiver/RugnuxLiveStatus.h index a076f9225..5d98c2a70 100644 --- a/receiver/RugnuxLiveStatus.h +++ b/receiver/RugnuxLiveStatus.h @@ -12,6 +12,7 @@ #include class RugnuxStructure; // RugnuxStructure.h +struct ProcessResult; // rugnux/Rugnux.h // Where the live rugnux run of the last collection is, for the broker's status route: the steps it has // taken with what each found ("lattice found", "space group P 21 21 21"), the step it is on and how far @@ -174,3 +175,6 @@ public: void Clear(); RugnuxLiveSnapshot Get() const; }; + +// What the run made of the model it was given, for the live status; none where no model was given. +std::optional LiveModel(const ProcessResult &result); diff --git a/receiver/StillsGPUAnalysis.cpp b/receiver/StillsGPUAnalysis.cpp index 3115a2d21..f42350589 100644 --- a/receiver/StillsGPUAnalysis.cpp +++ b/receiver/StillsGPUAnalysis.cpp @@ -12,7 +12,6 @@ #include "../rugnux/RugnuxDefaults.h" #include "../frame_serialize/CBORStream2Serializer.h" #include "../writer/RugnuxResultBlocks.h" -#include "JFJochReceiverRugnux.h" #include "RugnuxStructure.h" StillsGPUAnalysis::StillsGPUAnalysis(const DiffractionExperiment &in_experiment, const PixelMask &in_mask, diff --git a/rugnux/ModelStep.cpp b/rugnux/ModelStep.cpp index 3a80082fa..4d3d338bb 100644 --- a/rugnux/ModelStep.cpp +++ b/rugnux/ModelStep.cpp @@ -8,15 +8,12 @@ #include "spdlog/fmt/fmt.h" +#include "../common/time_utc.h" #include "../image_analysis/scale_merge/CrystalSetting.h" #include "../image_analysis/scale_merge/ReindexAmbiguity.h" #include "../image_analysis/scale_merge/RfreeFlags.h" namespace { - double SecondsSince(std::chrono::steady_clock::time_point t0) { - return std::chrono::duration(std::chrono::steady_clock::now() - t0).count(); - } - bool Cut(const ModelStepSettings &settings) { return settings.cut != nullptr && settings.cut->load(); } diff --git a/rugnux/StillsLiveMerge.cpp b/rugnux/StillsLiveMerge.cpp index a84f7afbe..49b8786bc 100644 --- a/rugnux/StillsLiveMerge.cpp +++ b/rugnux/StillsLiveMerge.cpp @@ -7,6 +7,7 @@ #include #include "../common/ParallelFor.h" +#include "../common/time_utc.h" #include "../image_analysis/scale_merge/Merge.h" #include "../image_analysis/scale_merge/ReferenceFreeReindex.h" #include "../image_analysis/scale_merge/ReindexAmbiguity.h" @@ -14,10 +15,6 @@ #include "../image_analysis/scale_merge/SublatticeRelabel.h" namespace { - double SecondsSince(std::chrono::steady_clock::time_point t0) { - return std::chrono::duration(std::chrono::steady_clock::now() - t0).count(); - } - size_t ImagesWithReflections(const std::vector &outcomes) { size_t n = 0; for (const auto &o : outcomes) diff --git a/tests/RugnuxLiveStatusTest.cpp b/tests/RugnuxLiveStatusTest.cpp index b57e19dca..1ec13a40b 100644 --- a/tests/RugnuxLiveStatusTest.cpp +++ b/tests/RugnuxLiveStatusTest.cpp @@ -6,7 +6,8 @@ #include #include "../receiver/RugnuxLiveStatus.h" -#include "../receiver/JFJochReceiverRugnux.h" +#include "../receiver/RugnuxLiveStatus.h" +#include "../rugnux/Rugnux.h" #include "../broker/OpenAPIConvert.h" #include "../image_puller/TestImagePuller.h"