200 lines
7.7 KiB
C++
200 lines
7.7 KiB
C++
// SPDX-FileCopyrightText: 2024 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
#include "JFJochReceiver.h"
|
|
#include "../common/CUDAWrapper.h"
|
|
#include "../common/time_utc.h"
|
|
#include "JFJochCompressor.h"
|
|
|
|
JFJochReceiver::JFJochReceiver(const DiffractionExperiment &in_experiment,
|
|
ImageBuffer &in_image_buffer,
|
|
ImagePusher &in_image_pusher,
|
|
PreviewImage &in_preview_image,
|
|
JFJochReceiverCurrentStatus &in_current_status,
|
|
JFJochReceiverPlots &in_plots,
|
|
const SpotFindingSettings &spot_finding_settings,
|
|
Logger &logger,
|
|
const NUMAHWPolicy &in_numa_policy,
|
|
const PixelMask &in_pixel_mask,
|
|
ZMQPreviewSocket *in_zmq_preview_socket,
|
|
ZMQMetadataSocket *in_zmq_metadata_socket,
|
|
IndexerThreadPool *indexing_thread_pool)
|
|
: experiment(in_experiment),
|
|
image_buffer(in_image_buffer),
|
|
image_pusher(in_image_pusher),
|
|
preview_image(in_preview_image),
|
|
current_status(in_current_status),
|
|
plots(in_plots),
|
|
spot_finding_settings(spot_finding_settings),
|
|
logger(logger),
|
|
numa_policy(in_numa_policy),
|
|
zmq_preview_socket(in_zmq_preview_socket),
|
|
zmq_metadata_socket(in_zmq_metadata_socket),
|
|
serialmx_filter(in_experiment),
|
|
pixel_mask(in_pixel_mask),
|
|
az_int_mapping(experiment, pixel_mask),
|
|
scan_result(in_experiment),
|
|
indexer_thread_pool(indexing_thread_pool) {
|
|
image_buffer.StartMeasurement(experiment);
|
|
|
|
current_status.SetProgress(0);
|
|
current_status.SetEfficiency({});
|
|
current_status.SetStatus(JFJochReceiverStatus{}); // GetStatus() is virtual function and cannot be called yet!
|
|
|
|
plots.Setup(experiment, az_int_mapping);
|
|
|
|
push_images_to_writer = (experiment.GetImageNum() > 0) && (!experiment.GetFilePrefix().empty());
|
|
|
|
preview_image.Configure(experiment, pixel_mask);
|
|
}
|
|
|
|
JFJochReceiver::~JFJochReceiver() = default;
|
|
|
|
SpotFindingSettings JFJochReceiver::GetSpotFindingSettings() {
|
|
std::unique_lock ul(spot_finding_settings_mutex);
|
|
return 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)
|
|
max_image_number_sent = image_number + 1;
|
|
}
|
|
|
|
void JFJochReceiver::UpdateMaxImageReceived(int64_t image_number) {
|
|
std::unique_lock ul(max_image_number_received_mutex);
|
|
if (image_number + 1 > max_image_number_received)
|
|
max_image_number_received = image_number + 1;
|
|
}
|
|
|
|
void JFJochReceiver::UpdateMaxDelay(uint64_t delay) {
|
|
std::unique_lock ul(max_delay_mutex);
|
|
if (!max_delay || (delay > max_delay))
|
|
max_delay = delay;
|
|
}
|
|
|
|
JFJochReceiverStatus JFJochReceiver::GetStatus() const {
|
|
JFJochReceiverStatus ret;
|
|
|
|
ret.indexing_rate = plots.GetIndexingRate();
|
|
ret.bkg_estimate = plots.GetBkgEstimate();
|
|
|
|
if ((experiment.GetImageNum() > 0) && (compressed_size > 0)) {
|
|
ret.compressed_ratio = static_cast<double>(uncompressed_size) / static_cast<double>(compressed_size);
|
|
}
|
|
|
|
ret.saturated_pixels = saturated_pixels.Read();
|
|
ret.error_pixels = error_pixels.Read();
|
|
ret.roi_beam_npixel = roi_beam_npixel.Read();
|
|
ret.roi_beam_sum = roi_beam_sum.Read();
|
|
|
|
ret.compressed_size = compressed_size;
|
|
ret.max_receive_delay = max_delay;
|
|
ret.max_image_number_sent = max_image_number_sent;
|
|
ret.images_collected = images_collected;
|
|
ret.images_sent = images_sent;
|
|
ret.images_skipped = images_skipped;
|
|
ret.cancelled = cancelled;
|
|
ret.efficiency = GetEfficiency();
|
|
return ret;
|
|
}
|
|
|
|
|
|
void JFJochReceiver::SendStartMessage() {
|
|
StartMessage message{};
|
|
experiment.FillMessage(message);
|
|
message.arm_date = time_UTC(std::chrono::system_clock::now());
|
|
message.az_int_q_bin_count = az_int_mapping.GetQBinCount();
|
|
message.az_int_bin_to_q = az_int_mapping.GetBinToQ();
|
|
message.az_int_bin_to_two_theta = az_int_mapping.GetBinToTwoTheta();
|
|
message.az_int_phi_bin_count = az_int_mapping.GetAzimuthalBinCount();
|
|
if (az_int_mapping.GetAzimuthalBinCount() > 1)
|
|
message.az_int_bin_to_phi = az_int_mapping.GetBinToPhi();
|
|
message.writer_notification_zmq_addr = image_pusher.GetWriterNotificationSocketAddress();
|
|
message.rois = experiment.ROI().ExportMetadata();
|
|
message.max_spot_count = experiment.GetMaxSpotCount();
|
|
|
|
std::vector<uint32_t> nexus_mask;
|
|
message.pixel_mask["default"] = pixel_mask.GetMask(experiment);
|
|
|
|
SaveStartMessageToImageBuffer(message);
|
|
|
|
if (push_images_to_writer)
|
|
image_pusher.StartDataCollection(message);
|
|
|
|
if (zmq_preview_socket != nullptr)
|
|
zmq_preview_socket->StartDataCollection(message);
|
|
|
|
if (zmq_metadata_socket != nullptr)
|
|
zmq_metadata_socket->StartDataCollection(message);
|
|
}
|
|
|
|
void JFJochReceiver::SaveStartMessageToImageBuffer(const StartMessage &msg) {
|
|
std::vector<uint8_t> buffer(MESSAGE_SIZE_FOR_START_END);
|
|
CBORStream2Serializer serializer(buffer.data(), buffer.size());
|
|
serializer.SerializeSequenceStart(msg);
|
|
buffer.resize(serializer.GetBufferSize());
|
|
image_buffer.SaveStartMessage(buffer);
|
|
}
|
|
|
|
void JFJochReceiver::SendEndMessage() {
|
|
EndMessage message{};
|
|
message.max_image_number = max_image_number_sent;
|
|
message.images_collected_count = images_collected;
|
|
message.images_sent_to_write_count = images_sent;
|
|
|
|
message.max_receiver_delay = max_delay;
|
|
message.efficiency = GetEfficiency();
|
|
message.end_date = time_UTC(std::chrono::system_clock::now());
|
|
message.run_number = experiment.GetRunNumber();
|
|
message.run_name = experiment.GetRunName();
|
|
|
|
message.bkg_estimate = plots.GetBkgEstimate();
|
|
message.indexing_rate = plots.GetIndexingRate();
|
|
|
|
message.az_int_result["dataset"] = plots.GetAzIntProfile();
|
|
|
|
for (int i = 0; i < adu_histogram_module.size(); i++)
|
|
message.adu_histogram["module" + std::to_string(i)] = adu_histogram_module[i]->GetHistogram();
|
|
|
|
if (push_images_to_writer) {
|
|
if (!image_pusher.EndDataCollection(message))
|
|
logger.Error("End message not sent via ZeroMQ (time-out)");
|
|
|
|
logger.Info("Disconnected from writers");
|
|
}
|
|
|
|
if (zmq_metadata_socket != nullptr)
|
|
zmq_metadata_socket->EndDataCollection(message);
|
|
|
|
if (zmq_preview_socket != nullptr)
|
|
zmq_preview_socket->EndDataCollection(message);
|
|
}
|
|
|
|
JFJochReceiverOutput JFJochReceiver::GetFinalStatistics() const {
|
|
JFJochReceiverOutput ret;
|
|
ret.efficiency = GetEfficiency();
|
|
ret.start_time_ms = std::chrono::duration_cast<std::chrono::milliseconds>(start_time.time_since_epoch()).count();
|
|
ret.end_time_ms = std::chrono::duration_cast<std::chrono::milliseconds>(end_time.time_since_epoch()).count();
|
|
ret.writer_queue_full_warning = writer_queue_full;
|
|
ret.status = GetStatus();
|
|
ret.writer_err = writer_error;
|
|
ret.scan_result = scan_result.GetResult();
|
|
return ret;
|
|
}
|
|
|
|
void JFJochReceiver::Cancel(bool silent) {
|
|
if (!silent) {
|
|
// Remote abort: This tells FPGAs to stop but doesn't do anything to CPU code
|
|
logger.Warning("Cancelling on request");
|
|
cancelled = true;
|
|
}
|
|
}
|
|
|
|
void JFJochReceiver::Cancel(const JFJochException &e) {
|
|
logger.Error("Cancelling data collection due to exception");
|
|
logger.ErrorException(e);
|
|
// Error abort: This tells FPGAs to stop and also prevents deadlock in CPU code by setting abort to 1
|
|
cancelled = true;
|
|
}
|