// SPDX-FileCopyrightText: 2024 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only #include "ImageMetadata.h" #include inline uint64_t convert_pulse_id(double pulse_id) { if (!std::isfinite(pulse_id)) return UINT64_MAX; double integer_part; double fractional_part = std::modf(pulse_id, &integer_part); if (fractional_part != 0.0) return UINT64_MAX; return static_cast(integer_part); } ImageMetadata::ImageMetadata(const DiffractionExperiment &experiment) : pulsed_source(experiment.IsPulsedSource()) { roi_map_name = experiment.ROI().GetROINameMap(); for (const auto &[x,y]: roi_map_name) rois[x] = ROIMessage{.max_count = INT64_MIN}; } void ImageMetadata::Process(const DeviceOutput *output) { std::unique_lock ul(m); uint64_t module_pulse_id = convert_pulse_id(output->module_statistics.pulse_id); if (!first_module_loaded) { xfel_pulse_id = module_pulse_id; jf_info = output->module_statistics.debug; storage_cell = (jf_info >> 8) & 0xF; xfel_event_code = (jf_info >> 16) & UINT8_MAX; timestamp = output->module_statistics.timestamp; exptime = output->module_statistics.exptime; max_value = INT64_MIN; min_value = INT64_MAX; first_module_loaded = true; } else { if (pulsed_source && (module_pulse_id != xfel_pulse_id)) { metadata_consistent = false; xfel_pulse_id = UINT64_MAX; // mark clearly inconsistent frames } } saturated_pixels += output->module_statistics.saturated_pixels; error_pixels += output->module_statistics.err_pixels; strong_pixels += output->spot_finding_result.strong_pixel_count; packets_collected += output->module_statistics.packet_count; if (output->module_statistics.max_value > max_value) max_value = output->module_statistics.max_value; if (output->module_statistics.load_calibration_destination < min_value) min_value = output->module_statistics.load_calibration_destination; for (const auto &[key, val]: roi_map_name) { rois[key].sum += output->roi_counts[val].sum; rois[key].sum_square += output->roi_counts[val].sum2; rois[key].pixels += output->roi_counts[val].good_pixels; if (output->roi_counts[val].max_value > rois[key].max_count) rois[key].max_count = output->roi_counts[val].max_value; } } bool ImageMetadata::IsBunchIDConsistent() const { return metadata_consistent; } void ImageMetadata::Export(DataMessage &message, uint64_t packets_expected_per_image) const { std::unique_lock ul(m); if (pulsed_source) { message.xfel_pulse_id = xfel_pulse_id; message.xfel_event_code = xfel_event_code; } message.jf_info = jf_info; message.storage_cell = storage_cell; message.timestamp = timestamp; message.timestamp_base = 10*1000*1000; message.exptime = exptime; message.exptime_base = 10*1000*1000; message.saturated_pixel_count = saturated_pixels; message.error_pixel_count = error_pixels; message.strong_pixel_count = strong_pixels; message.packets_received = packets_collected; message.packets_expected = packets_expected_per_image; if (min_value != INT64_MAX) message.min_viable_pixel_value = min_value; if (max_value != INT64_MIN) message.max_viable_pixel_value = max_value; if ((packets_collected > 0) && (packets_expected_per_image > 0)) message.image_collection_efficiency = static_cast(packets_collected) / static_cast(packets_expected_per_image); else message.image_collection_efficiency = 0.0f; message.roi = rois; }