Receivers: mechanical cleanups before the stream parent
LiveModel converts a result to a status model and is called from the stills analysis too, so it goes to RugnuxLiveStatus. SetSpotFindingSettings has one body, in the base; the FPGA receiver keeps its override, which adds the push to the cards. SecondsSince is written once, in time_utc.h. JFJochReceiverPedestal loses what it copied from the FPGA receiver and does not use: the azimuthal bin count check (a pedestal run integrates nothing, so such a configuration is no longer refused here), the per-module ADU histograms that were created and never fed, and the spot finder parameters pushed to the cards. Whether the card needs those before a pedestal run is inferred from the FPGA puller, which arms without them; it is tested on the simulator only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HVeDQsU5a8AJUdJPgWevAK
This commit is contained in:
1 parent
4c3a7852e9
commit
308b7dfb2a
15 files changed
+113
-138
No files matched your search
@@ -12,6 +12,10 @@
|
||||
#include <ctime>
|
||||
#include <cstdio>
|
||||
|
||||
inline double SecondsSince(std::chrono::steady_clock::time_point t0) {
|
||||
return std::chrono::duration<double>(std::chrono::steady_clock::now() - t0).count();
|
||||
}
|
||||
|
||||
inline std::string time_UTC(const std::chrono::time_point<std::chrono::system_clock> &input) {
|
||||
auto time_ms = std::chrono::duration_cast<std::chrono::milliseconds>(input.time_since_epoch()).count();
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -463,12 +463,6 @@ float JFJochReceiverLite::GetProgress() const {
|
||||
return static_cast<float>(max_image_number_received) / static_cast<float>(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)
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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<ADUHistogram>());
|
||||
|
||||
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();
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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<double>(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<double> &out, double v) {
|
||||
if (std::isfinite(v))
|
||||
out = v;
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<RugnuxLiveModel> 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<int64_t>(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<double> 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 {
|
||||
|
||||
@@ -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<RugnuxLiveModel> 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
|
||||
|
||||
@@ -3,6 +3,11 @@
|
||||
|
||||
#include "RugnuxLiveStatus.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
#include "../rugnux/Rugnux.h"
|
||||
|
||||
double RugnuxLiveStatus::Since(std::chrono::steady_clock::time_point t) const {
|
||||
return std::chrono::duration<double>(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<double> &out, double v) {
|
||||
if (std::isfinite(v))
|
||||
out = v;
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<RugnuxLiveModel> 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<int64_t>(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;
|
||||
}
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <vector>
|
||||
|
||||
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<RugnuxLiveModel> LiveModel(const ProcessResult &result);
|
||||
@@ -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,
|
||||
|
||||
@@ -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<double>(std::chrono::steady_clock::now() - t0).count();
|
||||
}
|
||||
|
||||
bool Cut(const ModelStepSettings &settings) {
|
||||
return settings.cut != nullptr && settings.cut->load();
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <ctime>
|
||||
|
||||
#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<double>(std::chrono::steady_clock::now() - t0).count();
|
||||
}
|
||||
|
||||
size_t ImagesWithReflections(const std::vector<IntegrationOutcome> &outcomes) {
|
||||
size_t n = 0;
|
||||
for (const auto &o : outcomes)
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
#include <cmath>
|
||||
|
||||
#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"
|
||||
|
||||
|
||||
Reference in new issue
Block a user