From 5667a9ee65d7821386a79686be28394a6a216d07 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Tue, 4 Nov 2025 16:29:31 +0100 Subject: [PATCH 01/69] PixelMask: Add option to include DECTRIS pixel mask and load additional mask from dark measurement --- broker/OpenAPIConvert.cpp | 4 +- common/PixelMask.cpp | 70 +++++++++++++++++++++---------- common/PixelMask.h | 7 ++-- tests/PixelMaskTest.cpp | 86 +++++++++++++++++++++++++++++++++------ 4 files changed, 129 insertions(+), 38 deletions(-) diff --git a/broker/OpenAPIConvert.cpp b/broker/OpenAPIConvert.cpp index 637eb6cc..c5dd5c21 100644 --- a/broker/OpenAPIConvert.cpp +++ b/broker/OpenAPIConvert.cpp @@ -741,8 +741,8 @@ org::openapitools::server::model::Zeromq_metadata_settings Convert(const ZMQMeta org::openapitools::server::model::Pixel_mask_statistics Convert(const PixelMaskStatistics& input) { org::openapitools::server::model::Pixel_mask_statistics ret; ret.setUserMask(input.user_mask); - ret.setWrongGain(input.wrong_gain); - ret.setTooHighPedestalRms(input.too_high_pedestal_rms); + ret.setWrongGain(input.error_pixel); + ret.setTooHighPedestalRms(input.noisy_pixel); return ret; } diff --git a/common/PixelMask.cpp b/common/PixelMask.cpp index aa3cb4a9..4bf317ac 100644 --- a/common/PixelMask.cpp +++ b/common/PixelMask.cpp @@ -19,15 +19,15 @@ PixelMask::PixelMask(const DiffractionExperiment &experiment) PixelMask::PixelMask(const std::vector &in_mask) : mask(in_mask) { statistics.user_mask = 0; - statistics.wrong_gain = 0; - statistics.too_high_pedestal_rms = 0; + statistics.error_pixel = 0; + statistics.noisy_pixel = 0; for (unsigned int i : mask) { if (i & (1 << UserMaskedPixelBit)) statistics.user_mask++; if (i & (1 << ErrorPixelBit)) - statistics.wrong_gain++; - if (i & (1 << TooHighPedestalRMSPixelBit)) - statistics.too_high_pedestal_rms++; + statistics.error_pixel++; + if (i & (1 << NoisyPixelBit)) + statistics.noisy_pixel++; } } @@ -131,8 +131,8 @@ std::vector PixelMask::GetUserMask(const DiffractionExperiment& experi void PixelMask::LoadDetectorBadPixelMask(const DiffractionExperiment &experiment, const JFCalibration *calib) { if (experiment.GetDetectorType() == DetectorType::DECTRIS) { - statistics.wrong_gain = 0; - statistics.too_high_pedestal_rms = 0; + statistics.error_pixel = 0; + statistics.noisy_pixel = 0; return; } @@ -167,11 +167,11 @@ void PixelMask::LoadDetectorBadPixelMask(const DiffractionExperiment &experiment std::vector input_mask_conv(experiment.GetPixelsNumConv(), 0); RawToConvertedGeometry(experiment, input_mask_conv.data(), input_mask.data()); - statistics.wrong_gain = LoadMask(input_mask_conv, ErrorPixelBit); + statistics.error_pixel = LoadMask(input_mask_conv, ErrorPixelBit); std::vector input_mask_rms_conv(experiment.GetPixelsNumConv(), 0); RawToConvertedGeometry(experiment, input_mask_rms_conv.data(), input_mask_rms.data()); - statistics.too_high_pedestal_rms = LoadMask(input_mask_rms_conv, TooHighPedestalRMSPixelBit); + statistics.noisy_pixel = LoadMask(input_mask_rms_conv, NoisyPixelBit); CalcEdgePixels(experiment); } @@ -199,22 +199,50 @@ void PixelMask::LoadDECTRISBadPixelMask(const std::vector &input_mask) "Input match doesn't fit the detector "); uint32_t user_bitmask = (1 << UserMaskedPixelBit); - uint32_t det_bitmask = ~user_bitmask; uint32_t bad_pixel_bitmask = ~((1 << UserMaskedPixelBit) | (1 << ModuleGapPixelBit) | (1 << ChipGapPixelBit)); statistics.user_mask = 0; - statistics.wrong_gain = 0; - statistics.too_high_pedestal_rms = 0; + statistics.error_pixel = 0; + statistics.noisy_pixel = 0; for (int i = 0; i < mask.size(); i++) { - uint32_t user_mask = (mask[i] & user_bitmask); - if (user_mask != 0) - ++statistics.user_mask; - uint32_t detector_mask = (input_mask[i] & det_bitmask); - uint32_t bad_pixel = (input_mask[i] & bad_pixel_bitmask); - if (bad_pixel != 0) - ++statistics.wrong_gain; - - mask[i] = user_mask | detector_mask; + if ((input_mask[i] & (1 << ModuleGapPixelBit)) != 0) { + mask[i] = (1 << ModuleGapPixelBit); + } else { + mask[i] = 0; + if (input_mask[i] & bad_pixel_bitmask) { + ++statistics.error_pixel; + mask[i] |= (1 << ErrorPixelBit); + } + // User and chip gap are just transferred + if ((input_mask[i] & (1 << UserMaskedPixelBit)) != 0) { + ++statistics.user_mask; + mask[i] |= (1 << UserMaskedPixelBit); + } + if ((input_mask[i] & (1 << ChipGapPixelBit)) != 0) { + mask[i] |= (1 << ChipGapPixelBit); + } + } + } +} + +void PixelMask::LoadDarkBadPixelMask(const std::vector &input_mask) { + if (input_mask.size() != mask.size()) + throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, + "Input match doesn't fit the detector "); + + statistics.noisy_pixel = 0; + + for (int i = 0; i < mask.size(); i++) { + // Ignore module gap (doesn't matter) or bad pixels + if ((mask[i] & (1 << ModuleGapPixelBit | 1 << ErrorPixelBit)) != 0) + continue; + + if (input_mask[i] != 0) { + mask[i] |= (1 << NoisyPixelBit); + ++statistics.noisy_pixel; + } else { + mask[i] &= ~(1 << NoisyPixelBit); + } } } diff --git a/common/PixelMask.h b/common/PixelMask.h index 4ee97533..4e2cb485 100644 --- a/common/PixelMask.h +++ b/common/PixelMask.h @@ -10,8 +10,8 @@ struct PixelMaskStatistics { uint32_t user_mask; - uint32_t too_high_pedestal_rms; - uint32_t wrong_gain; + uint32_t noisy_pixel; + uint32_t error_pixel; }; class PixelMask { @@ -22,7 +22,7 @@ public: // NXmx bits constexpr static const uint8_t ModuleGapPixelBit = 0; constexpr static const uint8_t ErrorPixelBit = 1; - constexpr static const uint8_t TooHighPedestalRMSPixelBit = 2; + constexpr static const uint8_t NoisyPixelBit = 4; constexpr static const uint8_t UserMaskedPixelBit = 8; constexpr static const uint8_t ChipGapPixelBit = 31; constexpr static const uint8_t ModuleEdgePixelBit = 30; @@ -35,6 +35,7 @@ public: void CalcEdgePixels(const DiffractionExperiment& experiment); void LoadUserMask(const DiffractionExperiment& experiment, const std::vector& mask); void LoadDECTRISBadPixelMask(const std::vector& mask); + void LoadDarkBadPixelMask(const std::vector& mask); void LoadDetectorBadPixelMask(const DiffractionExperiment& experiment, const JFCalibration *calib); [[nodiscard]] std::vector GetMaskRaw(const DiffractionExperiment& experiment) const; diff --git a/tests/PixelMaskTest.cpp b/tests/PixelMaskTest.cpp index bf993993..2622cbc8 100644 --- a/tests/PixelMaskTest.cpp +++ b/tests/PixelMaskTest.cpp @@ -80,8 +80,8 @@ TEST_CASE("PixelMask_MaskWrongGain","[PixelMask]") { CHECK(mask_out[2*RAW_MODULE_SIZE + 346] != 0); CHECK(mask_out[2*RAW_MODULE_SIZE + 347] != 0); - CHECK(mask.GetStatistics().too_high_pedestal_rms == 0); - CHECK(mask.GetStatistics().wrong_gain == 3); + CHECK(mask.GetStatistics().noisy_pixel == 0); + CHECK(mask.GetStatistics().error_pixel == 3); CHECK(mask.GetStatistics().user_mask == 0); image_format.MaskPixelsWithoutG0(false); @@ -95,8 +95,8 @@ TEST_CASE("PixelMask_MaskWrongGain","[PixelMask]") { CHECK(mask_out[2*RAW_MODULE_SIZE + 346] != 0); CHECK(mask_out[2*RAW_MODULE_SIZE + 347] != 0); - CHECK(mask.GetStatistics().too_high_pedestal_rms == 0); - CHECK(mask.GetStatistics().wrong_gain == 2); + CHECK(mask.GetStatistics().noisy_pixel == 0); + CHECK(mask.GetStatistics().error_pixel == 2); CHECK(mask.GetStatistics().user_mask == 0); } @@ -129,14 +129,14 @@ TEST_CASE("PixelMask_MaskG0RMS","[PixelMask]") { auto mask_out = mask.GetMaskRaw(experiment); REQUIRE(mask_out.size() == experiment.GetModulesNum() * RAW_MODULE_SIZE); - CHECK(mask_out[2*RAW_MODULE_SIZE + 245] == (1 << PixelMask::TooHighPedestalRMSPixelBit)); + CHECK(mask_out[2*RAW_MODULE_SIZE + 245] == (1 << PixelMask::NoisyPixelBit)); CHECK(mask_out[2*RAW_MODULE_SIZE + 345] == (1 << PixelMask::ErrorPixelBit)); - CHECK(mask_out[2*RAW_MODULE_SIZE + 346] == ((1 << PixelMask::ErrorPixelBit) | (1 << PixelMask::TooHighPedestalRMSPixelBit))); + CHECK(mask_out[2*RAW_MODULE_SIZE + 346] == ((1 << PixelMask::ErrorPixelBit) | (1 << PixelMask::NoisyPixelBit))); CHECK(mask_out[2*RAW_MODULE_SIZE + 347] == (1 << PixelMask::ErrorPixelBit)); - CHECK(mask.GetStatistics().too_high_pedestal_rms == 2); - CHECK(mask.GetStatistics().wrong_gain == 3); + CHECK(mask.GetStatistics().noisy_pixel == 2); + CHECK(mask.GetStatistics().error_pixel == 3); CHECK(mask.GetStatistics().user_mask == 0); } @@ -169,11 +169,11 @@ TEST_CASE("PixelMask_SCs","[PixelMask]") { CHECK(mask_out[456] == (1 << PixelMask::ErrorPixelBit)); CHECK(mask_out[RAW_MODULE_SIZE * 1 + 324] == (1 << PixelMask::ErrorPixelBit)); - CHECK(mask_out[RAW_MODULE_SIZE * 2 + 324] == (1 << PixelMask::TooHighPedestalRMSPixelBit)); - CHECK(mask_out[RAW_MODULE_SIZE * 3 + 0] == ((1 << PixelMask::ErrorPixelBit) | (1 << PixelMask::TooHighPedestalRMSPixelBit))); + CHECK(mask_out[RAW_MODULE_SIZE * 2 + 324] == (1 << PixelMask::NoisyPixelBit)); + CHECK(mask_out[RAW_MODULE_SIZE * 3 + 0] == ((1 << PixelMask::ErrorPixelBit) | (1 << PixelMask::NoisyPixelBit))); - CHECK(mask.GetStatistics().too_high_pedestal_rms == 2); - CHECK(mask.GetStatistics().wrong_gain == 3); + CHECK(mask.GetStatistics().noisy_pixel == 2); + CHECK(mask.GetStatistics().error_pixel == 3); } TEST_CASE("PixelMask_CalculateNexusMask_UserMaskRaw","[PixelMask]") { @@ -262,3 +262,65 @@ TEST_CASE("PixelMask_MaskDetectorGaps","[PixelMask]") { REQUIRE(mask_export[(1030*2+8)*514 + 566] == 1); REQUIRE(mask_export[(1030*2+8)*(514*3+36*2+12) + 566] == 1); } + +TEST_CASE("PixelMask_LoadDECTRISBadPixelMask","[PixelMask]") { + DiffractionExperiment experiment(DetJF(4,1)); + PixelMask mask(experiment); + + std::vector det_mask(experiment.GetPixelsNum(), 0); + det_mask[0] = (1 << PixelMask::UserMaskedPixelBit); + det_mask[534] = (1 << PixelMask::UserMaskedPixelBit) | (1 << PixelMask::ModuleGapPixelBit); + det_mask[535] = (1 << PixelMask::ModuleGapPixelBit); + det_mask[2 * 1000 * 5] = (1 << 3); + det_mask[2 * 1000 * 5 + 3] = (1 << 2); + det_mask[2 * 1000 * 5 + 4] = (1 << PixelMask::NoisyPixelBit); + det_mask[23 * 1000 * 5] = (1 << 5) | (1 << PixelMask::UserMaskedPixelBit); + + mask.LoadDECTRISBadPixelMask(det_mask); + + CHECK(mask.GetStatistics().user_mask == 2); + CHECK(mask.GetStatistics().error_pixel == 4); + CHECK(mask.GetStatistics().noisy_pixel == 0); + + CHECK(mask.GetMask()[0] == (1 << PixelMask::UserMaskedPixelBit)); + CHECK(mask.GetMask()[534] == (1 << PixelMask::ModuleGapPixelBit)); + CHECK(mask.GetMask()[535] == (1 << PixelMask::ModuleGapPixelBit)); + CHECK(mask.GetMask()[2 * 1000 * 5] == (1 << PixelMask::ErrorPixelBit)); + CHECK(mask.GetMask()[2 * 1000 * 5 + 3] == (1 << PixelMask::ErrorPixelBit)); + CHECK(mask.GetMask()[2 * 1000 * 5 + 4] == (1 << PixelMask::ErrorPixelBit)); + CHECK(mask.GetMask()[23 * 1000 * 5] == ((1 << PixelMask::ErrorPixelBit) | (1 << PixelMask::UserMaskedPixelBit))); +} + + +TEST_CASE("PixelMask_LoadDarkBadPixelMask","[PixelMask]") { + DiffractionExperiment experiment(DetJF(4,1)); + PixelMask mask(experiment); + + std::vector det_mask(experiment.GetPixelsNum(), 0); + det_mask[0] = (1 << PixelMask::UserMaskedPixelBit); + det_mask[534] = (1 << PixelMask::UserMaskedPixelBit) | (1 << PixelMask::ModuleGapPixelBit); + det_mask[535] = (1 << PixelMask::ModuleGapPixelBit); + det_mask[2 * 1000 * 5] = (1 << 3); + det_mask[2 * 1000 * 5 + 3] = (1 << 2); + det_mask[2 * 1000 * 5 + 4] = (1 << PixelMask::NoisyPixelBit); + det_mask[23 * 1000 * 5] = (1 << 5) | (1 << PixelMask::UserMaskedPixelBit); + + mask.LoadDECTRISBadPixelMask(det_mask); + + std::vector dark_mask(experiment.GetPixelsNum(), 0); + dark_mask[0] = 1; // user masked, should be included + dark_mask[534] = 1; // On gap, should be ignored + dark_mask[2 * 1000 * 5] = 1; // bad pixel, should be ignored + dark_mask[67867] = 1; // Nothing else, should be included + mask.LoadDarkBadPixelMask(dark_mask); + + CHECK(mask.GetStatistics().user_mask == 2); + CHECK(mask.GetStatistics().error_pixel == 4); + CHECK(mask.GetStatistics().noisy_pixel == 2); + + CHECK(mask.GetMask()[0] == (1 << PixelMask::UserMaskedPixelBit | 1 << PixelMask::NoisyPixelBit)); + + CHECK(mask.GetMask()[534] == (1 << PixelMask::ModuleGapPixelBit)); + CHECK(mask.GetMask()[2 * 1000 * 5] == (1 << PixelMask::ErrorPixelBit)); + CHECK(mask.GetMask()[67867] == (1 << PixelMask::NoisyPixelBit)); +} \ No newline at end of file -- 2.49.1 From 84f1ca2dcd57e90982b14cf2748794d04ab9edaa Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Tue, 4 Nov 2025 16:39:33 +0100 Subject: [PATCH 02/69] MaskDarkAnalysis: Add --- image_analysis/CMakeLists.txt | 4 +- .../mask_dark_analysis/MaskDarkAnalysis.cpp | 55 +++++++++++++++++++ .../mask_dark_analysis/MaskDarkAnalysis.h | 30 ++++++++++ 3 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 image_analysis/mask_dark_analysis/MaskDarkAnalysis.cpp create mode 100644 image_analysis/mask_dark_analysis/MaskDarkAnalysis.h diff --git a/image_analysis/CMakeLists.txt b/image_analysis/CMakeLists.txt index ae5450be..cac33e00 100644 --- a/image_analysis/CMakeLists.txt +++ b/image_analysis/CMakeLists.txt @@ -4,7 +4,9 @@ ADD_LIBRARY(JFJochImageAnalysis STATIC MXAnalysisAfterFPGA.h MXAnalysisAfterFPGA.cpp SpotAnalyze.cpp - SpotAnalyze.h) + SpotAnalyze.h + mask_dark_analysis/MaskDarkAnalysis.cpp + mask_dark_analysis/MaskDarkAnalysis.h) FIND_PACKAGE(Eigen3 3.4 REQUIRED NO_MODULE) # provides Eigen3::Eigen diff --git a/image_analysis/mask_dark_analysis/MaskDarkAnalysis.cpp b/image_analysis/mask_dark_analysis/MaskDarkAnalysis.cpp new file mode 100644 index 00000000..8b09195a --- /dev/null +++ b/image_analysis/mask_dark_analysis/MaskDarkAnalysis.cpp @@ -0,0 +1,55 @@ +// SPDX-FileCopyrightText: 2024 Filip Leonarski, Paul Scherrer Institute +// SPDX-License-Identifier: GPL-3.0-only + +#include "MaskDarkAnalysis.h" +#include "../../common/JFJochException.h" + +MaskDarkAnalysis::MaskDarkAnalysis(size_t det_size) : mask(det_size, 0) {} + +template +void MaskDarkAnalysis::check(const T *ptr) { + std::unique_lock ul(m); + for (int i = 0; i < mask.size(); i++) { + auto v64 = static_cast(ptr[i]); + if (v64 > max_allowed_value) + mask[i]++; + } +} + +void MaskDarkAnalysis::AnalyzeImage(const DataMessage &data, std::vector buffer) { + if (data.image.GetWidth() * data.image.GetHeight() != mask.size()) + throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Invalid size of input image"); + + auto ptr = data.image.GetUncompressedPtr(buffer); + + switch (data.image.GetMode()) { + case CompressedImageMode::Int8: + check(reinterpret_cast(ptr)); + break; + case CompressedImageMode::Uint8: + check(reinterpret_cast(ptr)); + break; + case CompressedImageMode::Int16: + check(reinterpret_cast(ptr)); + break; + case CompressedImageMode::Uint16: + check(reinterpret_cast(ptr)); + break; + case CompressedImageMode::Int32: + check(reinterpret_cast(ptr)); + break; + case CompressedImageMode::Uint32: + check(reinterpret_cast(ptr)); + break; + default: + throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "RGB/float image mode not supported"); + } +} + +void MaskDarkAnalysis::ApplyMask(PixelMask &in_mask) const { + std::unique_lock ul(m); + std::vector tmp(mask.size(), 0); + for (int i = 0; i < mask.size(); i++) + tmp[i] = (mask[i] > max_allowed_freq) ? 1 : 0; + in_mask.LoadDarkBadPixelMask(tmp); +} diff --git a/image_analysis/mask_dark_analysis/MaskDarkAnalysis.h b/image_analysis/mask_dark_analysis/MaskDarkAnalysis.h new file mode 100644 index 00000000..b223015f --- /dev/null +++ b/image_analysis/mask_dark_analysis/MaskDarkAnalysis.h @@ -0,0 +1,30 @@ +// SPDX-FileCopyrightText: 2024 Filip Leonarski, Paul Scherrer Institute +// SPDX-License-Identifier: GPL-3.0-only + +#ifndef JFJOCH_MASKDARKANALYSIS_H +#define JFJOCH_MASKDARKANALYSIS_H + +#include +#include +#include +#include "../common/CompressedImage.h" +#include "../common/PixelMask.h" + +class MaskDarkAnalysis { + mutable std::mutex m; + + const int64_t max_allowed_value = 1; + const int64_t max_allowed_freq = 10; + + std::vector mask; + + + template void check(const T *ptr); +public: + explicit MaskDarkAnalysis(size_t det_size); + void AnalyzeImage(const DataMessage &msg, std::vector buffer); + void ApplyMask(PixelMask &mask) const; +}; + + +#endif //JFJOCH_MASKDARKANALYSIS_H \ No newline at end of file -- 2.49.1 From 3096454e7d42e206036c15e3fa38fc5f230714aa Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Tue, 4 Nov 2025 17:01:11 +0100 Subject: [PATCH 03/69] DiffractionExperiment: Add DarkMask setting to DetectorMode enum --- common/DiffractionExperiment.cpp | 23 +++++++++++++++++++++++ common/DiffractionExperiment.h | 2 +- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/common/DiffractionExperiment.cpp b/common/DiffractionExperiment.cpp index 21d45974..1cc58a69 100644 --- a/common/DiffractionExperiment.cpp +++ b/common/DiffractionExperiment.cpp @@ -39,6 +39,10 @@ DiffractionExperiment::DiffractionExperiment(const DetectorSetup& det_setup) // setter functions DiffractionExperiment &DiffractionExperiment::Detector(const DetectorSetup &input) { detector = input; + + // Conversion is always default mode after switching detectors + mode = DetectorMode::Conversion; + auto settings = detector.GetDefaultSettings(); if (settings) detector_settings = *settings; @@ -47,6 +51,25 @@ DiffractionExperiment &DiffractionExperiment::Detector(const DetectorSetup &inpu DiffractionExperiment &DiffractionExperiment::Mode(DetectorMode input) { mode = input; + + // Handle allowed mode settings + switch (GetDetectorType()) { + case DetectorType::JUNGFRAU: + if (input == DetectorMode::DarkMask) + throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Dark mask is not supported for PSI JUNGFRAU detector"); + break; + case DetectorType::DECTRIS: + if ((input == DetectorMode::PedestalG0) || (input == DetectorMode::PedestalG1) || (input == DetectorMode::PedestalG2)) + throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Pedestal data collection is not supported for DECTRIS detector"); + if (input == DetectorMode::Raw) + throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Raw data collection is not supported for DECTRIS detector"); + break; + case DetectorType::EIGER: + if ((input == DetectorMode::PedestalG0) || (input == DetectorMode::PedestalG1) || (input == DetectorMode::PedestalG2) || (input == DetectorMode::DarkMask)) + throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Pedestal or dark mask data collection is not supported for PSI EIGER detector"); + break; + } + if (input == DetectorMode::Conversion) Conversion(); if (input == DetectorMode::Raw) diff --git a/common/DiffractionExperiment.h b/common/DiffractionExperiment.h index a9407219..73fcf781 100644 --- a/common/DiffractionExperiment.h +++ b/common/DiffractionExperiment.h @@ -31,7 +31,7 @@ #include "../symmetry/gemmi/symmetry.hpp" enum class DetectorMode { - Conversion, Raw, PedestalG0, PedestalG1, PedestalG2 + Conversion, Raw, PedestalG0, PedestalG1, PedestalG2, DarkMask }; struct AcquisitionDeviceNetConfig { -- 2.49.1 From 5431f9cefb02fa723bb5ea4a2b3539e713a826f3 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Tue, 4 Nov 2025 20:52:36 +0100 Subject: [PATCH 04/69] DiffractionExperiment: Remove DetectorMode::Raw --- common/DiffractionExperiment.cpp | 22 +++--- common/DiffractionExperiment.h | 6 +- tests/DiffractionExperimentTest.cpp | 61 ++++++++-------- tests/FPGAIntegrationTest.cpp | 94 ++++++++++--------------- tests/FrameTransformationTest.cpp | 20 +++--- tests/JFJochReceiverIntegrationTest.cpp | 38 +++++----- tests/PedestalCalcTest.cpp | 8 +-- tests/PixelMaskTest.cpp | 4 +- tests/RawToConvertedGeometryTest.cpp | 10 +-- tests/StreamWriterTest.cpp | 6 +- tests/StrongPixelSetTest.cpp | 2 +- tests/ZMQImagePusherTest.cpp | 6 +- tools/jfjoch_fpga_test.cpp | 4 +- tools/jfjoch_hdf5_test.cpp | 2 +- 14 files changed, 123 insertions(+), 160 deletions(-) diff --git a/common/DiffractionExperiment.cpp b/common/DiffractionExperiment.cpp index 1cc58a69..600ec158 100644 --- a/common/DiffractionExperiment.cpp +++ b/common/DiffractionExperiment.cpp @@ -29,7 +29,7 @@ DiffractionExperiment::DiffractionExperiment(const DetectorSetup& det_setup) series_id = 0; - mode = DetectorMode::Conversion; + mode = DetectorMode::Standard; image_format_settings.Conv(); summation = 1; @@ -41,7 +41,7 @@ DiffractionExperiment &DiffractionExperiment::Detector(const DetectorSetup &inpu detector = input; // Conversion is always default mode after switching detectors - mode = DetectorMode::Conversion; + mode = DetectorMode::Standard; auto settings = detector.GetDefaultSettings(); if (settings) @@ -50,8 +50,6 @@ DiffractionExperiment &DiffractionExperiment::Detector(const DetectorSetup &inpu } DiffractionExperiment &DiffractionExperiment::Mode(DetectorMode input) { - mode = input; - // Handle allowed mode settings switch (GetDetectorType()) { case DetectorType::JUNGFRAU: @@ -61,19 +59,15 @@ DiffractionExperiment &DiffractionExperiment::Mode(DetectorMode input) { case DetectorType::DECTRIS: if ((input == DetectorMode::PedestalG0) || (input == DetectorMode::PedestalG1) || (input == DetectorMode::PedestalG2)) throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Pedestal data collection is not supported for DECTRIS detector"); - if (input == DetectorMode::Raw) - throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Raw data collection is not supported for DECTRIS detector"); - break; + break; case DetectorType::EIGER: if ((input == DetectorMode::PedestalG0) || (input == DetectorMode::PedestalG1) || (input == DetectorMode::PedestalG2) || (input == DetectorMode::DarkMask)) throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Pedestal or dark mask data collection is not supported for PSI EIGER detector"); break; } - if (input == DetectorMode::Conversion) - Conversion(); - if (input == DetectorMode::Raw) - Raw(); + mode = input; + return *this; } @@ -1241,12 +1235,14 @@ std::optional DiffractionExperiment::GetJungfrauConversionFactor_keV() co return image_format_settings.GetJungfrauConvFactor_keV(); } -void DiffractionExperiment::Conversion() { +DiffractionExperiment & DiffractionExperiment::Conversion() { image_format_settings.Conv(); + return *this; } -void DiffractionExperiment::Raw() { +DiffractionExperiment & DiffractionExperiment::Raw() { image_format_settings.Raw(); + return *this; } DiffractionExperiment &DiffractionExperiment::ImportDetectorSettings(const DetectorSettings &input) { diff --git a/common/DiffractionExperiment.h b/common/DiffractionExperiment.h index 73fcf781..2ec66191 100644 --- a/common/DiffractionExperiment.h +++ b/common/DiffractionExperiment.h @@ -31,7 +31,7 @@ #include "../symmetry/gemmi/symmetry.hpp" enum class DetectorMode { - Conversion, Raw, PedestalG0, PedestalG1, PedestalG2, DarkMask + Standard, PedestalG0, PedestalG1, PedestalG2, DarkMask }; struct AcquisitionDeviceNetConfig { @@ -355,8 +355,8 @@ public: bool IsPedestalRun() const; - void Raw(); - void Conversion(); + DiffractionExperiment &Raw(); + DiffractionExperiment &Conversion(); float GetPedestalG0RMSLimit() const; uint32_t GetPedestalMinImageCount() const; diff --git a/tests/DiffractionExperimentTest.cpp b/tests/DiffractionExperimentTest.cpp index 7eabba04..d2aa5f51 100644 --- a/tests/DiffractionExperimentTest.cpp +++ b/tests/DiffractionExperimentTest.cpp @@ -172,7 +172,7 @@ TEST_CASE("DiffractionExperiment_DataStreams","[DiffractionExperiment]") { TEST_CASE("DiffractionExperiment_DetectorGeometry","[DiffractionExperiment]") { DiffractionExperiment x(DetJF(18)); // 9M configuration #1 - via constructor - x.Mode(DetectorMode::Conversion); + x.Conversion(); x.DataStreams(4); REQUIRE(x.GetDataStreamsNum() == 4); @@ -191,13 +191,13 @@ TEST_CASE("DiffractionExperiment_DetectorGeometry","[DiffractionExperiment]") { REQUIRE(x.GetPixelsNum() == 18 * 514 * 1030); - x.Mode(DetectorMode::Raw); + x.Raw(); REQUIRE(x.GetPixelsNum() == 18 * 512 * 1024); REQUIRE(x.GetXPixelsNum() == 1024); REQUIRE(x.GetYPixelsNum() == 512 * 18); - x.Mode(DetectorMode::Conversion); + x.Conversion(); x = DiffractionExperiment(DetJF(18, 2)); // 9M configuration #2 @@ -219,7 +219,7 @@ TEST_CASE("DiffractionExperiment_DetectorGeometry","[DiffractionExperiment]") { REQUIRE_THROWS(x.GetPixel0OfModuleConv(18)); - x.Mode(DetectorMode::Raw); + x.Raw(); REQUIRE(x.GetPixelsNum() == 1024 * 512 * 18); REQUIRE(x.GetXPixelsNum() == 1024); @@ -232,7 +232,7 @@ TEST_CASE("DiffractionExperiment_DetectorGeometry_gaps","[DiffractionExperiment] const size_t gap_y = 36; DiffractionExperiment x(DetJF(18, 2, gap_x, gap_y, false)); - x.Mode(DetectorMode::Conversion); + x.Conversion(); x.DataStreams(4); REQUIRE(x.GetDataStreamsNum() == 4); @@ -266,7 +266,7 @@ TEST_CASE("DiffractionExperiment_DetectorGeometry_gaps_mirror_y","[DiffractionEx const size_t gap_y = 36; DiffractionExperiment x(DetJF(20, 2, gap_x, gap_y, true)); - x.Mode(DetectorMode::Conversion); + x.Conversion(); REQUIRE(x.GetPixel0OfModuleConv(0) == (2*1030+gap_x) * 513 + (2*1030 + gap_x) * 9 * (514 + gap_y)); REQUIRE(x.GetPixel0OfModuleConv(1) == (2*1030+gap_x) * 513 + (2*1030 + gap_x) * 9 * (514 + gap_y) + 1030 + gap_x); @@ -425,17 +425,15 @@ TEST_CASE("DiffractionExperiment_InternalPacketGenerator", "[DiffractionExperime } TEST_CASE("DiffractionExperiment_CopyConstructor", "[DiffractionExperiment]") { - DiffractionExperiment a = DiffractionExperiment().Mode(DetectorMode::Raw); + DiffractionExperiment a = DiffractionExperiment(); a.BeamX_pxl(150); REQUIRE(a.GetBeamX_pxl() == 150.0); - REQUIRE(a.GetDetectorMode() == DetectorMode::Raw); DiffractionExperiment b(a); REQUIRE(b.GetBeamX_pxl() == 150.0); b.BeamX_pxl(100); REQUIRE(a.GetBeamX_pxl() == 150.0); REQUIRE(b.GetBeamX_pxl() == 100.0); - REQUIRE(b.GetDetectorMode() == DetectorMode::Raw); DiffractionExperiment c = b; REQUIRE (c.GetBeamX_pxl() == 100.0); @@ -646,7 +644,7 @@ TEST_CASE("DiffractionExperiment_PulsedSource","[DiffractionExperiment]") { DiffractionExperiment x; REQUIRE(!x.IsPulsedSource()); // default must be off - x.ImagesPerTrigger(50).NumTriggers(100).Mode(DetectorMode::Conversion).PedestalG0Frames(1000) + x.ImagesPerTrigger(50).NumTriggers(100).Mode(DetectorMode::Standard).PedestalG0Frames(1000) .PedestalG1Frames(200).PedestalG2Frames(100); x.PulsedSource(true); @@ -659,7 +657,7 @@ TEST_CASE("DiffractionExperiment_PulsedSource","[DiffractionExperiment]") { REQUIRE(x.GetFrameNum() == 100 * 10); REQUIRE(x.GetImageNum() == 100); - x.Mode(DetectorMode::Raw); + x.Raw(); REQUIRE(x.GetSummation() == 1); REQUIRE(x.GetFrameNumPerTrigger() == 1); REQUIRE(x.GetNumTriggers() == 100); @@ -690,32 +688,32 @@ TEST_CASE("DiffractionExperiment_DefaultDataProcessingSettings","[DiffractionExp TEST_CASE("DiffractionExperiment_FPGA_PixelSigned_JUNGFRAU","[DiffractionExperiment]") { DiffractionExperiment x(DetJF(4)); - x.Mode(DetectorMode::Conversion).PixelSigned({}); + x.Conversion().PixelSigned({}); REQUIRE(x.IsPixelSigned()); - x.Mode(DetectorMode::Raw).PixelSigned({}); + x.Raw().PixelSigned({}); REQUIRE(!x.IsPixelSigned()); - x.Mode(DetectorMode::Conversion).PixelSigned(false); + x.Conversion().PixelSigned(false); REQUIRE(!x.IsPixelSigned()); - x.Mode(DetectorMode::Raw).PixelSigned(true); + x.Raw().PixelSigned(true); REQUIRE(x.IsPixelSigned()); } TEST_CASE("DiffractionExperiment_FPGA_PixelSigned_EIGER","[DiffractionExperiment]") { DiffractionExperiment x(DetEIGER(4)); - x.Mode(DetectorMode::Conversion).PixelSigned({}); + x.Conversion().PixelSigned({}); REQUIRE(!x.IsPixelSigned()); - x.Mode(DetectorMode::Raw).PixelSigned({}); + x.Raw().PixelSigned({}); REQUIRE(!x.IsPixelSigned()); - x.Mode(DetectorMode::Conversion).PixelSigned(false); + x.Conversion().PixelSigned(false); REQUIRE(!x.IsPixelSigned()); - x.Mode(DetectorMode::Raw).PixelSigned(true); + x.Raw().PixelSigned(true); REQUIRE(x.IsPixelSigned()); } @@ -878,10 +876,10 @@ TEST_CASE("DiffractionExperiment_Appendix","") { TEST_CASE("DiffractionExperiment_ConversionOnFPGA","[DiffractionExperiment]") { DiffractionExperiment x; - x.Mode(DetectorMode::Conversion); + x.Conversion(); REQUIRE(x.IsJungfrauConvPhotonCnt()); // conversion on FPGA must be default true! - x.Mode(DetectorMode::Raw); + x.Raw(); REQUIRE(!x.IsJungfrauConvPhotonCnt()); // conversion on FPGA off for raw mode x.Mode(DetectorMode::PedestalG0); @@ -893,16 +891,17 @@ TEST_CASE("DiffractionExperiment_ConversionOnFPGA","[DiffractionExperiment]") { x.Mode(DetectorMode::PedestalG2); REQUIRE(!x.IsJungfrauConvPhotonCnt()); // conversion on FPGA off for pedestal modes - x.Mode(DetectorMode::Conversion).JungfrauConvPhotonCnt(false); + x.Mode(DetectorMode::Standard); + x.JungfrauConvPhotonCnt(false); REQUIRE(!x.IsJungfrauConvPhotonCnt()); // conversion on FPGA turned explicitly off - x.Mode(DetectorMode::Conversion).JungfrauConvPhotonCnt(true); + x.JungfrauConvPhotonCnt(true); REQUIRE(x.IsJungfrauConvPhotonCnt()); // conversion on FPGA back on } TEST_CASE("DiffractionExperiment_EIGER","[DiffractionExperiment]") { DiffractionExperiment x(DetEIGER(4)); - x.Mode(DetectorMode::Conversion); + x.Conversion(); REQUIRE(!x.IsJungfrauConvPhotonCnt()); REQUIRE(!x.IsPixelSigned()); x.ImagesPerTrigger(245).NumTriggers(100); @@ -911,7 +910,7 @@ TEST_CASE("DiffractionExperiment_EIGER","[DiffractionExperiment]") { TEST_CASE("DiffractionExperiment_JungfrauConversionFactor","[DiffractionExperiment]") { DiffractionExperiment x(DetJF(4)); - x.Mode(DetectorMode::Conversion).IncidentEnergy_keV(16.0); + x.Conversion().IncidentEnergy_keV(16.0); REQUIRE(!x.GetJungfrauConversionFactor_keV().has_value()); REQUIRE(x.GetIncidentEnergy_keV() == 16.0f); REQUIRE(x.GetPhotonEnergyForConversion_keV() == 16.0f); @@ -979,11 +978,11 @@ TEST_CASE("DiffractionExperiment_AutoSummation", "[DiffractionExperiment]") { DiffractionExperiment x(DetJF4M()); x.Summation(4).AutoSummation(true); - x.Mode(DetectorMode::Conversion).StorageCells(1); + x.Conversion().StorageCells(1); x.AutoSummation(true); REQUIRE(x.GetSummation() == 4); - x.Mode(DetectorMode::Raw).StorageCells(1); + x.Raw().StorageCells(1); x.AutoSummation(true); REQUIRE(x.GetSummation() == 4); @@ -991,22 +990,22 @@ TEST_CASE("DiffractionExperiment_AutoSummation", "[DiffractionExperiment]") { x.AutoSummation(true); REQUIRE(x.GetSummation() == 1); - x.Mode(DetectorMode::Conversion).StorageCells(2); + x.Conversion().StorageCells(2); x.AutoSummation(true); REQUIRE(x.GetSummation() == 1); - x.Mode(DetectorMode::Conversion).StorageCells(1); + x.Conversion().StorageCells(1); x.AutoSummation(false); REQUIRE(x.GetSummation() == 1); - x.Mode(DetectorMode::Raw).StorageCells(1); + x.Raw().StorageCells(1); x.AutoSummation(false); REQUIRE(x.GetSummation() == 1); } TEST_CASE("DiffractionExperiment_ExportROIMask", "[DiffractionExperiment]") { DiffractionExperiment x(DetJF4M()); - x.Mode(DetectorMode::Raw); + x.Raw(); x.ROI().SetROI(ROIDefinition{.boxes = { ROIBox("roi0", 800 , 800, 0, 4), diff --git a/tests/FPGAIntegrationTest.cpp b/tests/FPGAIntegrationTest.cpp index 6ed18119..2fd6358d 100644 --- a/tests/FPGAIntegrationTest.cpp +++ b/tests/FPGAIntegrationTest.cpp @@ -16,7 +16,7 @@ TEST_CASE("HLS_C_Simulation_internal_packet_generator", "[FPGA][Full]") { DiffractionExperiment x(DetJF(nmodules)); - x.Mode(DetectorMode::Raw); + x.Raw(); x.UseInternalPacketGenerator(true).ImagesPerTrigger(4).PedestalG0Frames(0); HLSSimulatedDevice test(0, 64); @@ -50,7 +50,7 @@ TEST_CASE("HLS_C_Simulation_internal_packet_generator_data_stream", "[FPGA][Full DiffractionExperiment x(DetJF(nmodules)); x.DataStreams(4); - x.Mode(DetectorMode::Raw); + x.Raw(); x.UseInternalPacketGenerator(true).ImagesPerTrigger(4).PedestalG0Frames(0); HLSSimulatedDevice test(3, 64); @@ -89,7 +89,7 @@ TEST_CASE("HLS_C_Simulation_internal_packet_generator_custom_frame", "[FPGA][Ful for (auto &i: test_frame) i = dist(g1); - x.Mode(DetectorMode::Raw); + x.Raw(); x.UseInternalPacketGenerator(true).ImagesPerTrigger(nframes).PedestalG0Frames(0); HLSSimulatedDevice test(0, 128); @@ -126,7 +126,7 @@ TEST_CASE("HLS_C_Simulation_check_raw", "[FPGA][Full]") { DiffractionExperiment x(DetJF(nmodules)); uint16_t data[4096]; - x.Mode(DetectorMode::Raw); + x.Raw(); x.PedestalG0Frames(0).ImagesPerTrigger(1).NumTriggers(1); HLSSimulatedDevice test(0, 64); @@ -160,7 +160,7 @@ TEST_CASE("HLS_C_Simulation_check_missing_modules", "[FPGA][Full]") { std::vector raw_frames(nframes * RAW_MODULE_SIZE, 0); DiffractionExperiment x(DetJF(nmodules)); - x.Mode(DetectorMode::Raw); + x.Raw(); x.PedestalG0Frames(0).ImagesPerTrigger(nframes).NumTriggers(1); HLSSimulatedDevice test(0, nframes + 2); @@ -188,7 +188,7 @@ TEST_CASE("HLS_C_Simulation_check_cancel", "[FPGA][Full]") { uint16_t data[4096]; - x.Mode(DetectorMode::Raw); + x.Raw(); x.PedestalG0Frames(0).ImagesPerTrigger(5).NumTriggers(1); HLSSimulatedDevice test(0, 64); @@ -213,7 +213,6 @@ TEST_CASE("HLS_C_Simulation_check_cancel_conversion", "[FPGA][Full]") { uint16_t data[4096]; - x.Mode(DetectorMode::Conversion); x.PedestalG0Frames(0).ImagesPerTrigger(5).NumTriggers(1); HLSSimulatedDevice test(0, 64); @@ -238,7 +237,7 @@ TEST_CASE("HLS_C_Simulation_check_delay", "[FPGA][Full]") { uint16_t data[4096]; - x.Mode(DetectorMode::Raw); + x.Raw(); x.PedestalG0Frames(0).ImagesPerTrigger(3).NumTriggers(1); HLSSimulatedDevice test(0, 64); @@ -283,7 +282,7 @@ TEST_CASE("HLS_C_Simulation_check_lost_frame_raw", "[FPGA][Full]") { uint16_t data[4096]; for (int i = 0; i < 4096; i++) data[i] = i; - x.Mode(DetectorMode::Raw); + x.Raw(); x.PedestalG0Frames(0).ImagesPerTrigger(3).NumTriggers(1); HLSSimulatedDevice test(0, 64); @@ -314,7 +313,6 @@ TEST_CASE("HLS_C_Simulation_check_lost_frame_conversion", "[FPGA][Full]") { uint16_t data[4096]; for (int i = 0; i < 4096; i++) data[i] = i; - x.Mode(DetectorMode::Conversion); x.PedestalG0Frames(0).ImagesPerTrigger(3).NumTriggers(1); HLSSimulatedDevice test(0, 64); @@ -350,7 +348,7 @@ TEST_CASE("HLS_C_Simulation_check_single_packet_raw", "[FPGA][Full]") { wrong[i] = UINT16_MAX; } - x.Mode(DetectorMode::Raw); + x.Raw(); x.PedestalG0Frames(0).ImagesPerTrigger(3).NumTriggers(1); HLSSimulatedDevice test(0, 64); @@ -414,7 +412,6 @@ TEST_CASE("HLS_C_Simulation_check_single_packet_conv", "[FPGA][Full]") { wrong[i] = INT16_MIN; } - x.Mode(DetectorMode::Conversion); x.PedestalG0Frames(0).ImagesPerTrigger(3).NumTriggers(1); HLSSimulatedDevice test(0, 64); @@ -473,7 +470,6 @@ TEST_CASE("HLS_C_Simulation_check_convert_full_range", "[FPGA][Full]") { const uint16_t nmodules = 1; DiffractionExperiment x(DetJF(nmodules)); - x.Mode(DetectorMode::Conversion); HLSSimulatedDevice test(0, 64); auto gain_from_file = GainCalibrationFromTestFile(); @@ -522,7 +518,7 @@ TEST_CASE("HLS_C_Simulation_check_convert_full_range_HG0", "[FPGA][Full]") { const uint16_t nmodules = 1; DiffractionExperiment x(DetJF(nmodules)); - x.Mode(DetectorMode::Conversion).UsingGainHG0(true); + x.UsingGainHG0(true); HLSSimulatedDevice test(0, 64); auto gain_from_file = GainCalibrationFromTestFile(); @@ -604,7 +600,7 @@ TEST_CASE("HLS_C_Simulation_check_convert_full_range_fixedG1", "[FPGA][Full]") { const uint16_t nmodules = 1; DiffractionExperiment x(DetJF(nmodules)); - x.Mode(DetectorMode::Conversion).FixedGainG1(true); + x.FixedGainG1(true); HLSSimulatedDevice test(0, 64); auto gain_from_file = GainCalibrationFromTestFile(); @@ -655,7 +651,6 @@ TEST_CASE("HLS_C_Simulation_check_convert_full_range_I32", "[FPGA][Full]") { const uint16_t nmodules = 1; DiffractionExperiment x(DetJF(nmodules)); - x.Mode(DetectorMode::Conversion); HLSSimulatedDevice test(0, 64); auto gain_from_file = GainCalibrationFromTestFile(); @@ -706,7 +701,6 @@ TEST_CASE("HLS_C_Simulation_check_convert_full_range_sum4", "[FPGA][Full]") { const uint16_t nmodules = 1; DiffractionExperiment x(DetJF(nmodules)); - x.Mode(DetectorMode::Conversion); HLSSimulatedDevice test(0, 64); auto gain_from_file = GainCalibrationFromTestFile(); @@ -761,7 +755,6 @@ TEST_CASE("HLS_C_Simulation_check_convert_full_range_U16", "[FPGA][Full]") { const uint16_t nmodules = 1; DiffractionExperiment x(DetJF(nmodules)); - x.Mode(DetectorMode::Conversion); HLSSimulatedDevice test(0, 64); auto gain_from_file = GainCalibrationFromTestFile(); @@ -815,7 +808,7 @@ TEST_CASE("HLS_C_Simulation_check_poisson_full_range", "[FPGA][Full]") { for (int sqrtmult: {1, 2,4,8}) { DiffractionExperiment x(DetJF(nmodules)); - x.Mode(DetectorMode::Raw).PixelSigned(true).BitDepthImage(16); + x.Raw().PixelSigned(true).BitDepthImage(16); HLSSimulatedDevice test(0, 64); x.NumTriggers(1).ImagesPerTrigger(1).LossyCompressionPoisson(sqrtmult); @@ -862,7 +855,7 @@ TEST_CASE("HLS_C_Simulation_check_threshold_full_range", "[FPGA][Full]") { for (int threshold: {1, 2, 4, 8}) { DiffractionExperiment x(DetJF(nmodules)); - x.Mode(DetectorMode::Raw).PixelSigned(true).BitDepthImage(16); + x.Raw().PixelSigned(true).BitDepthImage(16); HLSSimulatedDevice test(0, 64); x.NumTriggers(1).ImagesPerTrigger(1).PixelValueLowThreshold(threshold); @@ -914,7 +907,6 @@ TEST_CASE("HLS_C_Simulation_check_convert_full_range_poisson", "[FPGA][Full]") { const uint16_t nmodules = 1; DiffractionExperiment x(DetJF(nmodules)); x.LossyCompressionPoisson(2); - x.Mode(DetectorMode::Conversion); HLSSimulatedDevice test(0, 64); auto gain_from_file = GainCalibrationFromTestFile(); @@ -963,7 +955,7 @@ TEST_CASE("HLS_C_Simulation_no_conversion_U16", "[FPGA][Full]") { const uint16_t nmodules = 1; DiffractionExperiment x(DetJF(nmodules)); - x.Mode(DetectorMode::Conversion).JungfrauConvPhotonCnt(false); + x.JungfrauConvPhotonCnt(false); HLSSimulatedDevice test(0, 64); x.PedestalG0Frames(0).NumTriggers(1).ImagesPerTrigger(1).PixelSigned(false).BitDepthImage(16); @@ -998,7 +990,7 @@ TEST_CASE("HLS_C_Simulation_no_conversion_U32", "[FPGA][Full]") { const uint16_t nmodules = 1; DiffractionExperiment x(DetJF(nmodules)); - x.Mode(DetectorMode::Conversion).JungfrauConvPhotonCnt(false); + x.JungfrauConvPhotonCnt(false); HLSSimulatedDevice test(0, 64); x.PedestalG0Frames(0).NumTriggers(1).ImagesPerTrigger(1).PixelSigned(false).BitDepthImage(32); @@ -1034,7 +1026,7 @@ TEST_CASE("HLS_C_Simulation_no_conversion_I32", "[FPGA][Full]") { const uint16_t nmodules = 1; DiffractionExperiment x(DetJF(nmodules)); - x.Mode(DetectorMode::Conversion).JungfrauConvPhotonCnt(false); + x.JungfrauConvPhotonCnt(false); HLSSimulatedDevice test(0, 64); x.PedestalG0Frames(0).NumTriggers(1).ImagesPerTrigger(1).PixelSigned(true).BitDepthImage(32); @@ -1080,7 +1072,6 @@ TEST_CASE("HLS_C_Simulation_internal_packet_generator_convert_full_range", "[FPG data[i] = i % RAW_MODULE_SIZE; } - x.Mode(DetectorMode::Conversion); x.PedestalG0Frames(0).NumTriggers(1).ImagesPerTrigger(1).UseInternalPacketGenerator(true).IncidentEnergy_keV(energy) .GeometryTransformation(false); REQUIRE(x.GetIncidentEnergy_keV() == Catch::Approx(energy)); @@ -1185,7 +1176,6 @@ TEST_CASE("HLS_C_Simulation_internal_packet_generator_convert_full_range_adu_his data[i] = i % RAW_MODULE_SIZE; } - x.Mode(DetectorMode::Conversion); x.PedestalG0Frames(0).NumTriggers(1).ImagesPerTrigger(1).UseInternalPacketGenerator(true).IncidentEnergy_keV(energy); REQUIRE(x.GetIncidentEnergy_keV() == Catch::Approx(energy)); @@ -1244,7 +1234,6 @@ TEST_CASE("HLS_C_Simulation_check_2_trigger_convert", "[FPGA][Full]") { uint16_t data[4096]; - x.Mode(DetectorMode::Conversion); x.PedestalG0Frames(0).NumTriggers(1).ImagesPerTrigger(1); HLSSimulatedDevice test(0, 64); @@ -1301,7 +1290,6 @@ TEST_CASE("HLS_C_Simulation_check_detect_last_frame", "[FPGA][Full]") { uint16_t data[4096]; - x.Mode(DetectorMode::Conversion); x.PedestalG0Frames(0).NumTriggers(2).ImagesPerTrigger(5); HLSSimulatedDevice test(0, 64); @@ -1324,7 +1312,6 @@ TEST_CASE("HLS_C_Simulation_check_wrong_packet_size", "[FPGA][Full]") { uint16_t data[8192]; - x.Mode(DetectorMode::Conversion); x.PedestalG0Frames(0).NumTriggers(1).ImagesPerTrigger(5); HLSSimulatedDevice test(0, 64); @@ -1369,7 +1356,6 @@ TEST_CASE("HLS_C_Simulation_internal_packet_generator_15_storage_cell_convert_G0 DiffractionExperiment x(DetJF(nmodules)); - x.Mode(DetectorMode::Conversion); x.PedestalG0Frames(0).NumTriggers(ntrigger).ImagesPerTrigger(nstoragecells).UseInternalPacketGenerator(true) .IncidentEnergy_keV(10.0).StorageCells(nstoragecells); @@ -1419,7 +1405,6 @@ TEST_CASE("HLS_C_Simulation_internal_packet_generator_8_storage_cell_convert_G0" DiffractionExperiment x(DetJF(nmodules)); - x.Mode(DetectorMode::Conversion); x.PedestalG0Frames(0).NumTriggers(ntrigger).ImagesPerTrigger(nstoragecells).UseInternalPacketGenerator(true) .IncidentEnergy_keV(10.0).StorageCells(nstoragecells); @@ -1470,7 +1455,6 @@ TEST_CASE("HLS_C_Simulation_internal_packet_generator_16_storage_cell_convert_G0 DiffractionExperiment x(DetJF(nmodules)); - x.Mode(DetectorMode::Conversion); x.PedestalG0Frames(0).NumTriggers(ntrigger).ImagesPerTrigger(nstoragecells).UseInternalPacketGenerator(true) .IncidentEnergy_keV(10.0).StorageCells(nstoragecells); @@ -1516,7 +1500,6 @@ TEST_CASE("HLS_C_Simulation_internal_packet_generator_storage_cell_convert_G1", const uint16_t nmodules = 2; DiffractionExperiment x(DetJF(nmodules)); - x.Mode(DetectorMode::Conversion); x.PedestalG0Frames(0).NumTriggers(1).ImagesPerTrigger(16).UseInternalPacketGenerator(true) .IncidentEnergy_keV(10.0).StorageCells(16); @@ -1564,7 +1547,7 @@ TEST_CASE("HLS_C_Simulation_internal_packet_generator_integration", "[FPGA][Full DiffractionExperiment x(DetJF(nmodules)); - x.Mode(DetectorMode::Raw); + x.Raw(); x.UseInternalPacketGenerator(true).ImagesPerTrigger(1).PedestalG0Frames(0); HLSSimulatedDevice test(0, 64); @@ -1623,7 +1606,7 @@ TEST_CASE("HLS_C_Simulation_internal_packet_generator_integration_mask", "[FPGA] DiffractionExperiment x(DetJF(nmodules)); - x.Mode(DetectorMode::Raw); + x.Raw(); x.UseInternalPacketGenerator(true).ImagesPerTrigger(1).PedestalG0Frames(0).ApplyPixelMask(false); HLSSimulatedDevice test(0, 64); @@ -1676,7 +1659,7 @@ TEST_CASE("HLS_C_Simulation_internal_packet_generator_spot_finder_count_threshol DiffractionExperiment x(DetJF(nmodules)); - x.Mode(DetectorMode::Raw); + x.Raw(); x.UseInternalPacketGenerator(true).ImagesPerTrigger(1).PedestalG0Frames(0); HLSSimulatedDevice test(0, 64); @@ -1728,7 +1711,7 @@ TEST_CASE("HLS_C_Simulation_internal_packet_generator_spot_finder_mask", "[FPGA] DiffractionExperiment x(DetJF(nmodules)); - x.Mode(DetectorMode::Raw); + x.Raw(); x.UseInternalPacketGenerator(true).ImagesPerTrigger(1).PedestalG0Frames(0); x.ApplyPixelMask(false); @@ -1801,7 +1784,7 @@ TEST_CASE("HLS_C_Simulation_internal_packet_generator_spot_finder_overload", "[F DiffractionExperiment x(DetJF(nmodules)); - x.Mode(DetectorMode::Raw); + x.Raw(); x.UseInternalPacketGenerator(true).ImagesPerTrigger(1).PedestalG0Frames(0).PixelSigned(true); HLSSimulatedDevice test(0, 64); @@ -1851,7 +1834,7 @@ TEST_CASE("HLS_C_Simulation_internal_packet_generator_spot_finder_min_pix_per_sp DiffractionExperiment x(DetJF(nmodules)); - x.Mode(DetectorMode::Raw); + x.Raw(); x.UseInternalPacketGenerator(true).ImagesPerTrigger(1).PedestalG0Frames(0); HLSSimulatedDevice test(0, 64); @@ -1913,7 +1896,7 @@ TEST_CASE("HLS_C_Simulation_internal_packet_generator_spot_finder_d_min_max", "[ DiffractionExperiment x(DetJF(nmodules)); - x.Mode(DetectorMode::Raw); + x.Raw(); x.UseInternalPacketGenerator(true).ImagesPerTrigger(1).PedestalG0Frames(0); HLSSimulatedDevice test(0, 64); @@ -1969,7 +1952,7 @@ TEST_CASE("HLS_C_Simulation_internal_packet_generator_spot_finder_snr_threshold" DiffractionExperiment x(DetJF(nmodules)); - x.Mode(DetectorMode::Raw); + x.Raw(); x.UseInternalPacketGenerator(true).ImagesPerTrigger(1).PedestalG0Frames(0); HLSSimulatedDevice test(0, 64); @@ -2028,7 +2011,7 @@ TEST_CASE("HLS_C_Simulation_internal_packet_generator_pixel_threshold_summation" DiffractionExperiment x(DetJF(nmodules)); - x.Mode(DetectorMode::Raw); + x.Raw(); x.UseInternalPacketGenerator(true).ImagesPerTrigger(1).PedestalG0Frames(0).Summation(4) .PixelValueLowThreshold(4).AutoSummation(true).PixelSigned(true) .PixelValueHighThreshold(500); @@ -2070,7 +2053,7 @@ TEST_CASE("HLS_C_Simulation_internal_packet_generator_summation_mask", "[FPGA][F DiffractionExperiment x(DetJF(nmodules)); - x.Mode(DetectorMode::Raw); + x.Raw(); x.UseInternalPacketGenerator(true).ImagesPerTrigger(1).PedestalG0Frames(0).Summation(4) .AutoSummation(true).ApplyPixelMask(true).BitDepthImage(16).PixelSigned(true); @@ -2136,7 +2119,7 @@ TEST_CASE("HLS_C_Simulation_internal_packet_generator_32bit", "[FPGA][Full]") { for (auto &i: test_frame) i = dist(g1); - x.Mode(DetectorMode::Raw); + x.Raw(); x.UseInternalPacketGenerator(true).ImagesPerTrigger(nframes).PedestalG0Frames(0).PixelSigned(false).BitDepthImage(32); HLSSimulatedDevice test(0, 64); @@ -2186,7 +2169,6 @@ TEST_CASE("HLS_C_Simulation_internal_packet_generator_summation", "[FPGA][Full]" for (auto &i: test_frame) i = dist(g1); - x.Mode(DetectorMode::Conversion); x.UseInternalPacketGenerator(true).ImagesPerTrigger(nframes).PedestalG0Frames(0).Summation(nsummation) .JungfrauConvPhotonCnt(false).PixelSigned(true).BitDepthImage(32); @@ -2226,7 +2208,7 @@ TEST_CASE("HLS_C_Simulation_count_sat_and_err_pixels", "[FPGA][Full]") { DiffractionExperiment x(DetJF(nmodules)); - x.Mode(DetectorMode::Raw); + x.Raw(); x.UseInternalPacketGenerator(true).ImagesPerTrigger(4).PedestalG0Frames(0).PixelSigned(true); HLSSimulatedDevice test(0, 64); @@ -2268,7 +2250,7 @@ TEST_CASE("HLS_C_Simulation_pixel_count_mask", "[FPGA][Full]") { DiffractionExperiment x(DetJF(nmodules)); - x.Mode(DetectorMode::Raw); + x.Raw(); x.UseInternalPacketGenerator(true).ImagesPerTrigger(4).PedestalG0Frames(0).PixelSigned(true); x.ApplyPixelMask(false); @@ -2317,7 +2299,7 @@ TEST_CASE("HLS_C_Simulation_count_pixel_sum", "[FPGA][Full]") { DiffractionExperiment x(DetJF(nmodules)); - x.Mode(DetectorMode::Raw); + x.Raw(); x.UseInternalPacketGenerator(true).ImagesPerTrigger(4).PedestalG0Frames(0).PixelSigned(true); HLSSimulatedDevice test(0, 64); @@ -2352,7 +2334,7 @@ TEST_CASE("HLS_C_Simulation_check_bunchid", "[FPGA][Full]") { const uint16_t nmodules = 4; DiffractionExperiment x(DetJF(nmodules)); - x.Mode(DetectorMode::Raw); + x.Raw(); x.PedestalG0Frames(0).ImagesPerTrigger(3).NumTriggers(1); HLSSimulatedDevice test(0, 64); test.CreateXfelBunchIDPacket(bunchid, 0); @@ -2380,7 +2362,7 @@ TEST_CASE("HLS_C_Simulation_check_raw_eiger", "[FPGA][Full]") { DetectorSetup detector(DetEIGER(nmodules)); DiffractionExperiment x(detector); - x.Mode(DetectorMode::Raw); + x.Raw(); x.PedestalG0Frames(0).ImagesPerTrigger(1).NumTriggers(1); HLSSimulatedDevice test(0, 64); @@ -2430,7 +2412,7 @@ TEST_CASE("HLS_C_Simulation_check_raw_eiger_8bit", "[FPGA][Full]") { DiffractionExperiment x(detector); - x.Mode(DetectorMode::Raw); + x.Raw(); x.PedestalG0Frames(0).ImagesPerTrigger(1).NumTriggers(1).EigerBitDepth(8).BitDepthImage(8); REQUIRE(x.GetByteDepthImage() == 1); @@ -2492,7 +2474,7 @@ TEST_CASE("HLS_C_Simulation_check_raw_eiger_32bit", "[FPGA][Full]") { DiffractionExperiment x(detector); - x.Mode(DetectorMode::Raw); + x.Raw(); x.PedestalG0Frames(0).ImagesPerTrigger(1).NumTriggers(1).EigerBitDepth(32).BitDepthImage(32); REQUIRE(x.GetByteDepthImage() == 4); @@ -2554,7 +2536,7 @@ TEST_CASE("HLS_C_Simulation_internal_packet_generator_eiger", "[FPGA][Full]") { DiffractionExperiment x(DetEIGER(nmodules)); - x.Mode(DetectorMode::Raw); + x.Raw(); x.UseInternalPacketGenerator(true).ImagesPerTrigger(4).PedestalG0Frames(0); HLSSimulatedDevice test(0, 64); @@ -2593,7 +2575,7 @@ TEST_CASE("HLS_C_Simulation_internal_packet_generator_eiger_8bit", "[FPGA][Full] DiffractionExperiment x(DetEIGER(nmodules)); - x.Mode(DetectorMode::Raw); + x.Raw(); x.UseInternalPacketGenerator(true).ImagesPerTrigger(4).PedestalG0Frames(0); x.EigerBitDepth(8); @@ -2674,7 +2656,7 @@ TEST_CASE("HLS_C_Simulation_internal_packet_generator_roi_calc", "[FPGA][Full]") DiffractionExperiment x(DetJF(nmodules)); - x.Mode(DetectorMode::Raw); + x.Raw(); x.UseInternalPacketGenerator(true).ImagesPerTrigger(nimages).PedestalG0Frames(0); HLSSimulatedDevice test(0, 64); @@ -2741,7 +2723,7 @@ TEST_CASE("HLS_C_Simulation_internal_packet_generator_4_images", "[FPGA][Full]") const uint16_t nimages = 4; DiffractionExperiment x(DetJF(nmodules)); - x.Mode(DetectorMode::Raw); + x.Raw(); x.UseInternalPacketGenerator(true).ImagesPerTrigger(nimages).PedestalG0Frames(0).InternalPacketGeneratorImages(nimages); HLSSimulatedDevice test(0, 64); diff --git a/tests/FrameTransformationTest.cpp b/tests/FrameTransformationTest.cpp index 62073882..1ac5d701 100644 --- a/tests/FrameTransformationTest.cpp +++ b/tests/FrameTransformationTest.cpp @@ -32,7 +32,7 @@ TEST_CASE("FrameTransformation_Raw_NoCompression" ,"") { DiffractionExperiment experiment(DetJF(ndatastreams * nmodules, 1)); experiment.DataStreams(ndatastreams); - experiment.Mode(DetectorMode::Raw); + experiment.Raw(); experiment.Compression(CompressionAlgorithm::NO_COMPRESSION); FrameTransformation transformation(experiment); @@ -73,7 +73,7 @@ TEST_CASE("FrameTransformation_Raw_NoCompression_bshuf_lz4" ,"") { DiffractionExperiment experiment(DetJF(ndatastreams * nmodules, 1)); experiment.DataStreams(ndatastreams); - experiment.Mode(DetectorMode::Raw); + experiment.Raw(); experiment.Compression(CompressionAlgorithm::BSHUF_LZ4); FrameTransformation transformation(experiment); @@ -122,7 +122,7 @@ TEST_CASE("FrameTransformation_Conversion_NoGeomTransformation_NoCompression" ," DiffractionExperiment experiment(DetJF(ndatastreams * nmodules, 1)); experiment.DataStreams(ndatastreams); - experiment.Mode(DetectorMode::Conversion).GeometryTransformation(false); + experiment.GeometryTransformation(false); experiment.Compression(CompressionAlgorithm::NO_COMPRESSION); FrameTransformation transformation(experiment); @@ -162,7 +162,7 @@ TEST_CASE("FrameTransformation_Converted_NoCompression" ,"") { const uint16_t ndatastreams = 2; DiffractionExperiment experiment(DetJF(ndatastreams * nmodules, 2)); experiment.DataStreams(ndatastreams); - experiment.Mode(DetectorMode::Conversion).Compression(CompressionAlgorithm::NO_COMPRESSION); + experiment.Compression(CompressionAlgorithm::NO_COMPRESSION); FrameTransformation transformation(experiment); @@ -212,7 +212,7 @@ TEST_CASE("FrameTransformation_Converted_bshuf_lz4" ,"") { DiffractionExperiment experiment(DetJF(ndatastreams * nmodules, 2)); experiment.DataStreams(ndatastreams); - experiment.Mode(DetectorMode::Conversion).Compression(CompressionAlgorithm::BSHUF_LZ4); + experiment.Compression(CompressionAlgorithm::BSHUF_LZ4); FrameTransformation transformation(experiment); @@ -272,7 +272,7 @@ TEST_CASE("FrameTransformation_Converted_bshuf_zstd" ,"") { DiffractionExperiment experiment(DetJF(ndatastreams * nmodules, 2)); experiment.DataStreams(ndatastreams); - experiment.Mode(DetectorMode::Conversion).Compression(CompressionAlgorithm::BSHUF_ZSTD); + experiment.Compression(CompressionAlgorithm::BSHUF_ZSTD); FrameTransformation transformation(experiment); @@ -331,7 +331,7 @@ TEST_CASE("FrameTransformation_Converted_bshuf_zstd_rle" ,"") { DiffractionExperiment experiment(DetJF(ndatastreams * nmodules, 2)); experiment.DataStreams(ndatastreams); - experiment.Mode(DetectorMode::Conversion).Compression(CompressionAlgorithm::BSHUF_ZSTD_RLE); + experiment.Compression(CompressionAlgorithm::BSHUF_ZSTD_RLE); FrameTransformation transformation(experiment); @@ -390,7 +390,7 @@ TEST_CASE("FrameTransformation_Converted_bshuf_zstd_32bit" ,"") { DiffractionExperiment experiment(DetJF(ndatastreams * nmodules, 2)); experiment.DataStreams(ndatastreams); - experiment.Mode(DetectorMode::Conversion).Compression(CompressionAlgorithm::BSHUF_ZSTD).BitDepthImage(32); + experiment.Compression(CompressionAlgorithm::BSHUF_ZSTD).BitDepthImage(32); FrameTransformation transformation(experiment); @@ -453,7 +453,7 @@ TEST_CASE("FrameTransformation_Converted_bshuf_zstd_8bit" ,"") { DiffractionExperiment experiment(DetJF(ndatastreams * nmodules, 2)); experiment.DataStreams(ndatastreams); - experiment.Mode(DetectorMode::Conversion).Compression(CompressionAlgorithm::BSHUF_ZSTD).BitDepthImage(8); + experiment.Compression(CompressionAlgorithm::BSHUF_ZSTD).BitDepthImage(8); FrameTransformation transformation(experiment); @@ -516,7 +516,7 @@ TEST_CASE("FrameTransformation_Converted_bshuf_zstd_unsigned_16bit" ,"") { DiffractionExperiment experiment(DetJF(ndatastreams * nmodules, 2)); experiment.DataStreams(ndatastreams); - experiment.Mode(DetectorMode::Conversion).Compression(CompressionAlgorithm::BSHUF_ZSTD).PixelSigned(false); + experiment.Compression(CompressionAlgorithm::BSHUF_ZSTD).PixelSigned(false); REQUIRE(!experiment.IsPixelSigned()); REQUIRE(experiment.GetByteDepthImage() == 2); diff --git a/tests/JFJochReceiverIntegrationTest.cpp b/tests/JFJochReceiverIntegrationTest.cpp index 2f9a9d57..74ec6d7a 100644 --- a/tests/JFJochReceiverIntegrationTest.cpp +++ b/tests/JFJochReceiverIntegrationTest.cpp @@ -15,7 +15,7 @@ TEST_CASE("JFJochReceiverTest_Raw", "[JFJochReceiver]") { DiffractionExperiment x(DetJF(4)); const uint16_t nthreads = 4; - x.Mode(DetectorMode::Raw); + x.Raw(); x.PedestalG0Frames(0).NumTriggers(1).UseInternalPacketGenerator(true) .ImagesPerTrigger(100).ImagesPerFile(10).IncidentEnergy_keV(12.4).Compression(CompressionAlgorithm::NO_COMPRESSION); @@ -47,7 +47,7 @@ TEST_CASE("JFJochReceiverTest_Conversion", "[JFJochReceiver]") { DiffractionExperiment x(DetJF(2)); const uint16_t nthreads = 4; - x.Mode(DetectorMode::Conversion); + x.Conversion(); x.PedestalG0Frames(0).NumTriggers(1).UseInternalPacketGenerator(true) .ImagesPerTrigger(32).ImagesPerFile(10).IncidentEnergy_keV(12.4).Compression(CompressionAlgorithm::BSHUF_ZSTD); @@ -77,7 +77,7 @@ TEST_CASE("JFJochReceiverTest_Conversion_NoGeomTransform", "[JFJochReceiver]") { DiffractionExperiment x(DetJF(2)); const uint16_t nthreads = 4; - x.Mode(DetectorMode::Conversion); + x.Conversion(); x.PedestalG0Frames(0).NumTriggers(1).UseInternalPacketGenerator(true) .ImagesPerTrigger(32).ImagesPerFile(10).IncidentEnergy_keV(12.4).Compression(CompressionAlgorithm::BSHUF_ZSTD) .GeometryTransformation(false); @@ -106,7 +106,7 @@ TEST_CASE("JFJochReceiverTest_Conversion_Poisson", "[JFJochReceiver]") { DiffractionExperiment x(DetJF(2)); const uint16_t nthreads = 4; - x.Mode(DetectorMode::Conversion); + x.Conversion(); x.PedestalG0Frames(0).NumTriggers(1).UseInternalPacketGenerator(true) .ImagesPerTrigger(32).ImagesPerFile(10).IncidentEnergy_keV(12.4).Compression( CompressionAlgorithm::BSHUF_ZSTD); @@ -136,7 +136,7 @@ TEST_CASE("JFJochReceiverTest_Conversion_Threshold", "[JFJochReceiver]") { DiffractionExperiment x(DetJF(2)); const uint16_t nthreads = 4; - x.Mode(DetectorMode::Conversion); + x.Conversion(); x.PedestalG0Frames(0).NumTriggers(1).UseInternalPacketGenerator(true) .ImagesPerTrigger(32).ImagesPerFile(10).IncidentEnergy_keV(12.4).Compression( CompressionAlgorithm::BSHUF_ZSTD); @@ -166,7 +166,7 @@ TEST_CASE("JFJochReceiverTest_Conversion_ApplyMask", "[JFJochReceiver]") { DiffractionExperiment x(DetJF(2)); const uint16_t nthreads = 4; - x.Mode(DetectorMode::Conversion); + x.Conversion(); x.PedestalG0Frames(0).NumTriggers(1).UseInternalPacketGenerator(true) .ImagesPerTrigger(32).ImagesPerFile(10).IncidentEnergy_keV(12.4).Compression(CompressionAlgorithm::BSHUF_ZSTD); x.ApplyPixelMask(true).MaskChipEdges(true).MaskModuleEdges(true); @@ -195,7 +195,7 @@ TEST_CASE("JFJochReceiverTest_Conversion_Threshold_Summation", "[JFJochReceiver] DiffractionExperiment x(DetJF(2)); const uint16_t nthreads = 4; - x.Mode(DetectorMode::Conversion); + x.Conversion(); x.PedestalG0Frames(0).NumTriggers(1).UseInternalPacketGenerator(true) .ImagesPerTrigger(1).Summation(4).ImagesPerFile(10).IncidentEnergy_keV(12.4).Compression( CompressionAlgorithm::BSHUF_ZSTD); @@ -225,7 +225,7 @@ TEST_CASE("JFJochReceiverTest_Conversion_FixedGainG1", "[JFJochReceiver]") { DiffractionExperiment x(DetJF(2)); const uint16_t nthreads = 4; - x.Mode(DetectorMode::Conversion); + x.Conversion(); x.PedestalG0Frames(0).NumTriggers(1).UseInternalPacketGenerator(true) .ImagesPerTrigger(32).ImagesPerFile(10).IncidentEnergy_keV(12.4).Compression(CompressionAlgorithm::BSHUF_ZSTD) .FixedGainG1(true); @@ -255,7 +255,7 @@ TEST_CASE("JFJochReceiverTest_Conversion_FixedGainG1_onlyG1", "[JFJochReceiver]" DiffractionExperiment x(DetJF(2)); const uint16_t nthreads = 4; - x.Mode(DetectorMode::Conversion); + x.Conversion(); x.PedestalG0Frames(0).NumTriggers(1).UseInternalPacketGenerator(true) .ImagesPerTrigger(32).ImagesPerFile(10).IncidentEnergy_keV(12.4).Compression(CompressionAlgorithm::BSHUF_ZSTD) .FixedGainG1(true); @@ -285,7 +285,7 @@ TEST_CASE("JFJochReceiverTest_Conversion_U16", "[JFJochReceiver]") { DiffractionExperiment x(DetJF(2)); const uint16_t nthreads = 4; - x.Mode(DetectorMode::Conversion); + x.Conversion(); x.PedestalG0Frames(0).NumTriggers(1).UseInternalPacketGenerator(true) .ImagesPerTrigger(32).ImagesPerFile(10).IncidentEnergy_keV(12.4).Compression(CompressionAlgorithm::BSHUF_ZSTD) .BitDepthImage(16).PixelSigned(false); @@ -315,7 +315,7 @@ TEST_CASE("JFJochReceiverTest_Conversion_U8", "[JFJochReceiver]") { DiffractionExperiment x(DetJF(2)); const uint16_t nthreads = 4; - x.Mode(DetectorMode::Conversion); + x.Conversion(); x.PedestalG0Frames(0).NumTriggers(1).UseInternalPacketGenerator(true) .ImagesPerTrigger(32).ImagesPerFile(10).IncidentEnergy_keV(12.4).Compression(CompressionAlgorithm::BSHUF_ZSTD) .BitDepthImage(8).PixelSigned(false); @@ -347,7 +347,7 @@ TEST_CASE("JFJochReceiverTest_Conversion_I32", "[JFJochReceiver]") { DiffractionExperiment x(DetJF(2)); const uint16_t nthreads = 4; - x.Mode(DetectorMode::Conversion); + x.Conversion(); x.PedestalG0Frames(0).NumTriggers(1).UseInternalPacketGenerator(true) .ImagesPerTrigger(32).ImagesPerFile(10).IncidentEnergy_keV(12.4).Compression(CompressionAlgorithm::BSHUF_ZSTD) .PixelSigned(true).BitDepthImage(32); @@ -376,7 +376,7 @@ TEST_CASE("JFJochReceiverTest_Conversion_Summation2", "[JFJochReceiver]") { DiffractionExperiment x(DetJF(2)); const uint16_t nthreads = 4; - x.Mode(DetectorMode::Conversion); + x.Conversion(); x.PedestalG0Frames(0).NumTriggers(1).UseInternalPacketGenerator(true) .ImagesPerTrigger(32).ImagesPerFile(10).IncidentEnergy_keV(12.4).Compression(CompressionAlgorithm::BSHUF_ZSTD).Summation(2); @@ -404,7 +404,7 @@ TEST_CASE("JFJochReceiverTest_Conversion_Summation7_CPU", "[JFJochReceiver]") { DiffractionExperiment x(DetJF(2)); const uint16_t nthreads = 4; - x.Mode(DetectorMode::Conversion); + x.Conversion(); x.PedestalG0Frames(0).NumTriggers(1).UseInternalPacketGenerator(true) .ImagesPerTrigger(8).ImagesPerFile(10).IncidentEnergy_keV(12.4).Compression(CompressionAlgorithm::BSHUF_ZSTD) .Summation(7).CPUSummation(true); @@ -433,7 +433,7 @@ TEST_CASE("JFJochReceiverTest_Conversion_StorageCell", "[JFJochReceiver]") { DiffractionExperiment x(DetJF(2)); const uint16_t nthreads = 4; - x.Mode(DetectorMode::Conversion); + x.Conversion(); x.PedestalG0Frames(0).NumTriggers(1).UseInternalPacketGenerator(true) .ImagesPerTrigger(32).ImagesPerFile(10).IncidentEnergy_keV(12.4).Compression(CompressionAlgorithm::BSHUF_ZSTD).StorageCells(16); @@ -793,7 +793,7 @@ TEST_CASE("JFJochReceiverTest_PacketLost_Raw", "[JFJochReceiver]") { std::vector frame_in(RAW_MODULE_SIZE); for (auto &i: frame_in) i = 776; - x.Mode(DetectorMode::Raw); + x.Raw(); x.PedestalG0Frames(0).NumTriggers(1) .UseInternalPacketGenerator(false).ImagesPerTrigger(4).IncidentEnergy_keV(12.4) .Compression(CompressionAlgorithm::NO_COMPRESSION); @@ -856,7 +856,7 @@ TEST_CASE("JFJochReceiverTest_Cancel", "[JFJochReceiver]") { std::vector frame_in(RAW_MODULE_SIZE); for (auto &i: frame_in) i = 776; - x.Mode(DetectorMode::Raw); + x.Raw(); x.PedestalG0Frames(0).NumTriggers(1) .UseInternalPacketGenerator(false).ImagesPerTrigger(4).IncidentEnergy_keV(12.4); @@ -896,7 +896,7 @@ TEST_CASE("JFJochReceiverTest_EIGER", "[JFJochReceiver]") { DiffractionExperiment x(DetEIGER(2)); const uint16_t nthreads = 4; - x.Mode(DetectorMode::Raw); + x.Raw(); x.PedestalG0Frames(0).NumTriggers(1).UseInternalPacketGenerator(true) .ImagesPerTrigger(32).ImagesPerFile(10).IncidentEnergy_keV(12.4).Compression(CompressionAlgorithm::BSHUF_ZSTD); @@ -980,7 +980,7 @@ TEST_CASE("JFJochReceiverTest_EIGER_conversion", "[JFJochReceiver]") { DiffractionExperiment x(DetEIGER(2)); const uint16_t nthreads = 4; - x.Mode(DetectorMode::Conversion); + x.Conversion(); x.PedestalG0Frames(0).NumTriggers(1).UseInternalPacketGenerator(true) .ImagesPerTrigger(32).ImagesPerFile(10).IncidentEnergy_keV(12.4).Compression(CompressionAlgorithm::BSHUF_ZSTD); diff --git a/tests/PedestalCalcTest.cpp b/tests/PedestalCalcTest.cpp index b38c6d48..69279a74 100644 --- a/tests/PedestalCalcTest.cpp +++ b/tests/PedestalCalcTest.cpp @@ -9,27 +9,23 @@ TEST_CASE("JFPedestalCalc", "[JFPedestalCalc]") { for (int gain_level = 0; gain_level < 3; gain_level++) { uint16_t base_value; uint16_t wrong_value; - uint16_t mask_value; DiffractionExperiment x(DetJF(1)); switch (gain_level) { case 1: base_value = 0x4000; wrong_value = 0xc000; - mask_value = 4; x.Mode(DetectorMode::PedestalG1); break; case 2: base_value = 0xc000; wrong_value = 0; - mask_value = 8; x.Mode(DetectorMode::PedestalG2); break; default: base_value = 0; wrong_value = 0x4000; - mask_value = 2; - x.Mode(DetectorMode::Conversion); + x.Mode(DetectorMode::PedestalG0); break; } @@ -88,8 +84,6 @@ int16_t r(std::mt19937 &g, std::normal_distribution &dist) { TEST_CASE("JFPedestalCalc_MaskRMS", "[JFPedestalCalc]") { DiffractionExperiment x(DetJF(1)); - x.Mode(DetectorMode::Conversion); - std::vector image(RAW_MODULE_SIZE, 0); JFPedestalCalc calc(x); diff --git a/tests/PixelMaskTest.cpp b/tests/PixelMaskTest.cpp index 2622cbc8..a957b113 100644 --- a/tests/PixelMaskTest.cpp +++ b/tests/PixelMaskTest.cpp @@ -6,7 +6,7 @@ TEST_CASE("PixelMask_MaskModuleEdges","[PixelMask]") { DiffractionExperiment experiment(DetJF(4, 1)); - experiment.MaskModuleEdges(true).MaskChipEdges(false).Mode(DetectorMode::Raw); + experiment.MaskModuleEdges(true).MaskChipEdges(false).Raw(); PixelMask mask(experiment); @@ -30,7 +30,7 @@ TEST_CASE("PixelMask_MaskModuleEdges","[PixelMask]") { TEST_CASE("PixelMask_MaskChipEdges","[PixelMask]") { DiffractionExperiment experiment(DetJF(4,1)); - experiment.MaskChipEdges(true).MaskModuleEdges(false).Mode(DetectorMode::Raw); + experiment.MaskChipEdges(true).MaskModuleEdges(false).Raw(); PixelMask mask(experiment); auto mask_out = mask.GetMaskRaw(experiment); diff --git a/tests/RawToConvertedGeometryTest.cpp b/tests/RawToConvertedGeometryTest.cpp index cf535f2d..43e601e7 100644 --- a/tests/RawToConvertedGeometryTest.cpp +++ b/tests/RawToConvertedGeometryTest.cpp @@ -92,7 +92,6 @@ TEST_CASE("RawToConvertedGeometry_Transform","[RawToConvertedGeometry]") { DiffractionExperiment x(DetJF(20, 2, 0, 0, false)); x.DataStreams(4); - x.Mode(DetectorMode::Conversion); REQUIRE(x.GetModulesNum(2) == 5); REQUIRE(x.GetPixelsNum() == CONVERTED_MODULE_SIZE * x.GetModulesNum()); @@ -152,7 +151,7 @@ TEST_CASE("RawToConvertedGeometry_Transform_AdjustMultipixels","[RawToConvertedG DiffractionExperiment x(DetJF(20, 2, 0, 0, false)); x.DataStreams(4); - x.Mode(DetectorMode::Conversion).PixelSigned(true).BitDepthImage(32); + x.PixelSigned(true).BitDepthImage(32); REQUIRE(x.GetByteDepthImage() == 4); REQUIRE(x.GetModulesNum(0) == 5); @@ -215,7 +214,6 @@ TEST_CASE("RawToConvertedGeometry_Transform_upside_down","[RawToConvertedGeometr DiffractionExperiment x(DetJF(24, 2, 0, 0, true)); x.DataStreams(4); - x.Mode(DetectorMode::Conversion); REQUIRE(x.GetModulesNum(3) == 6); REQUIRE(x.GetPixelsNum() == CONVERTED_MODULE_SIZE * x.GetModulesNum()); @@ -367,7 +365,6 @@ TEST_CASE("RawToConvertedGeometry","[RawToConvertedGeometry]") { DiffractionExperiment x(DetJF(20, 2, 0, 0, true)); x.DataStreams(4); - x.Mode(DetectorMode::Conversion); REQUIRE(x.GetModulesNum(2) == 5); REQUIRE(x.GetPixelsNum() == CONVERTED_MODULE_SIZE * x.GetModulesNum()); @@ -396,7 +393,6 @@ TEST_CASE("RawToConvertedGeometry","[RawToConvertedGeometry]") { TEST_CASE("RawToConvertedGeometry_int64","[RawToConvertedGeometry]") { DiffractionExperiment x(DetJF(20, 2, 0, 0, true)); x.DataStreams(4); - x.Mode(DetectorMode::Conversion); REQUIRE(x.GetModulesNum(2) == 5); REQUIRE(x.GetPixelsNum() == CONVERTED_MODULE_SIZE * x.GetModulesNum()); @@ -421,7 +417,7 @@ TEST_CASE("RawToConvertedGeometry_int64","[RawToConvertedGeometry]") { TEST_CASE("RawToConvertedGeometry_FP","[RawToConvertedGeometry]") { DiffractionExperiment x(DetJF(20, 2, 0, 0, true)); x.DataStreams(4); - x.Mode(DetectorMode::Conversion); + REQUIRE(x.GetModulesNum(2) == 5); REQUIRE(x.GetPixelsNum() == CONVERTED_MODULE_SIZE * x.GetModulesNum()); @@ -446,7 +442,6 @@ TEST_CASE("RawToConvertedGeometry_Gaps","[RawToConvertedGeometry]") { DiffractionExperiment x(DetJF(8, 2, 8, 36, true)); x.DataStreams(2); - x.Mode(DetectorMode::Conversion); REQUIRE(x.GetModulesNum(1) == 4); REQUIRE(x.GetXPixelsNum() == 2 * CONVERTED_MODULE_COLS + 8); REQUIRE(x.GetYPixelsNum() == 4 * CONVERTED_MODULE_LINES + 3*36); @@ -490,7 +485,6 @@ TEST_CASE("RawToConvertedGeometry_Vertical","[RawToConvertedGeometry]") { DiffractionExperiment x(DetJF(geometry)); x.DataStreams(3); - x.Mode(DetectorMode::Conversion); std::vector input(x.GetModulesNum() * RAW_MODULE_SIZE); std::vector input2(x.GetModulesNum() * RAW_MODULE_SIZE); std::vector output(x.GetPixelsNum(), UINT32_MAX); diff --git a/tests/StreamWriterTest.cpp b/tests/StreamWriterTest.cpp index cff61a17..bde59540 100644 --- a/tests/StreamWriterTest.cpp +++ b/tests/StreamWriterTest.cpp @@ -16,7 +16,7 @@ TEST_CASE("StreamWriterTest_ZMQ", "[StreamWriter]") { DiffractionExperiment x(DetJF(2)); x.FilePrefix("subdir/StreamWriterTest").NumTriggers(1).ImagesPerTrigger(5) - .UseInternalPacketGenerator(true).Mode(DetectorMode::Raw).PedestalG0Frames(0).OverwriteExistingFiles(true); + .UseInternalPacketGenerator(true).Raw().PedestalG0Frames(0).OverwriteExistingFiles(true); PixelMask pixel_mask(x); @@ -72,7 +72,7 @@ TEST_CASE("StreamWriterTest_ZMQ_Update", "[StreamWriter]") { DatasetSettings d; d.FilePrefix("subdir/StreamWriterTest2").NumTriggers(1).ImagesPerTrigger(5).RunName("run1").RunNumber(256); DiffractionExperiment x(DetJF(2)); - x.UseInternalPacketGenerator(true).Mode(DetectorMode::Raw).PedestalG0Frames(0) + x.UseInternalPacketGenerator(true).Raw().PedestalG0Frames(0) .ImportDatasetSettings(d).OverwriteExistingFiles(true); PixelMask pixel_mask(x); @@ -133,7 +133,7 @@ TEST_CASE("StreamWriterTest_ZMQ_Update_NoNotification", "[StreamWriter]") { DatasetSettings d; d.FilePrefix("subdir/StreamWriterTest3").NumTriggers(1).ImagesPerTrigger(5).RunName("run1").RunNumber(256); DiffractionExperiment x(DetJF(2)); - x.UseInternalPacketGenerator(true).Mode(DetectorMode::Raw).PedestalG0Frames(0) + x.UseInternalPacketGenerator(true).Raw().PedestalG0Frames(0) .ImportDatasetSettings(d).OverwriteExistingFiles(true); PixelMask pixel_mask(x); diff --git a/tests/StrongPixelSetTest.cpp b/tests/StrongPixelSetTest.cpp index 8b13a7c5..c2243e10 100644 --- a/tests/StrongPixelSetTest.cpp +++ b/tests/StrongPixelSetTest.cpp @@ -21,7 +21,7 @@ TEST_CASE("DiffractionSpot_AddOperator","[StrongPixelSet]") { TEST_CASE("StrongPixelSet_BuildSpots","[StrongPixelSet]") { DiffractionExperiment experiment(DetJF(1,1,0,0,false)); - experiment.Mode(DetectorMode::Raw); + experiment.Raw(); SpotFindingSettings settings; settings.low_resolution_limit = 200.0; diff --git a/tests/ZMQImagePusherTest.cpp b/tests/ZMQImagePusherTest.cpp index bf8e52ad..c19a937e 100644 --- a/tests/ZMQImagePusherTest.cpp +++ b/tests/ZMQImagePusherTest.cpp @@ -58,7 +58,7 @@ TEST_CASE("ZMQImageCommTest_1Writer","[ZeroMQ]") { Logger logger(Catch::getResultCapture().getCurrentTestName()); DiffractionExperiment x(DetJF(1)); - x.Mode(DetectorMode::Raw); + x.Raw(); x.PedestalG0Frames(0).NumTriggers(1).UseInternalPacketGenerator(false).IncidentEnergy_keV(12.4) .ImagesPerTrigger(nframes).Compression(CompressionAlgorithm::NO_COMPRESSION); @@ -128,7 +128,7 @@ TEST_CASE("ZMQImageCommTest_2Writers","[ZeroMQ]") { Logger logger(Catch::getResultCapture().getCurrentTestName()); DiffractionExperiment x(DetJF(1)); - x.Mode(DetectorMode::Raw); + x.Raw(); x.PedestalG0Frames(0).NumTriggers(1).UseInternalPacketGenerator(false).IncidentEnergy_keV(12.4) .ImagesPerTrigger(nframes).Compression(CompressionAlgorithm::NO_COMPRESSION); @@ -221,7 +221,7 @@ TEST_CASE("ZMQImageCommTest_4Writers","[ZeroMQ]") { Logger logger(Catch::getResultCapture().getCurrentTestName()); DiffractionExperiment x(DetJF(1)); - x.Mode(DetectorMode::Raw); + x.Raw(); x.PedestalG0Frames(0).NumTriggers(1).UseInternalPacketGenerator(false).IncidentEnergy_keV(12.4) .ImagesPerTrigger(nframes).Compression(CompressionAlgorithm::NO_COMPRESSION); diff --git a/tools/jfjoch_fpga_test.cpp b/tools/jfjoch_fpga_test.cpp index cfe1fb57..a4d30d76 100644 --- a/tools/jfjoch_fpga_test.cpp +++ b/tools/jfjoch_fpga_test.cpp @@ -164,9 +164,7 @@ int main(int argc, char **argv) { DiffractionExperiment x(DetectorSetup(DetectorGeometryModular(nmodules, 2, 8, 36, true), detector_type)); if (raw_data) - x.Mode(DetectorMode::Raw); - else - x.Mode(DetectorMode::Conversion); + x.Raw(); x.ImagesPerTrigger(nimages).Summation(nsummation).PedestalG0Frames(0).UseInternalPacketGenerator(true). IncidentEnergy_keV(12.4).NumTriggers(1); diff --git a/tools/jfjoch_hdf5_test.cpp b/tools/jfjoch_hdf5_test.cpp index 848b1039..7457ce55 100644 --- a/tools/jfjoch_hdf5_test.cpp +++ b/tools/jfjoch_hdf5_test.cpp @@ -75,7 +75,7 @@ int main(int argc, char **argv) { } else x.SetFileWriterFormat(FileWriterFormat::NXmxLegacy); - x.Mode(DetectorMode::Conversion).ImagesPerTrigger(nimages); + x.ImagesPerTrigger(nimages); std::vector image_conv ( nimages * file_space.GetDimensions()[1] * file_space.GetDimensions()[2]); -- 2.49.1 From b219ce4489c690b846e9892eb99f70de4470bdc4 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Tue, 4 Nov 2025 21:29:14 +0100 Subject: [PATCH 05/69] DarkMaskSettings: Add --- common/CMakeLists.txt | 2 + common/DarkMaskSettings.cpp | 69 +++++++++++++++++++ common/DarkMaskSettings.h | 31 +++++++++ common/DetectorSettings.cpp | 10 +++ common/DetectorSettings.h | 6 ++ common/DiffractionExperiment.cpp | 10 ++- .../mask_dark_analysis/MaskDarkAnalysis.cpp | 7 +- .../mask_dark_analysis/MaskDarkAnalysis.h | 8 +-- 8 files changed, 134 insertions(+), 9 deletions(-) create mode 100644 common/DarkMaskSettings.cpp create mode 100644 common/DarkMaskSettings.h diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 8b1791a8..5fd87876 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -117,6 +117,8 @@ ADD_LIBRARY(JFJochCommon STATIC XrayFluorescenceSpectrum.h ResolutionShells.cpp ResolutionShells.h + DarkMaskSettings.cpp + DarkMaskSettings.h ) TARGET_LINK_LIBRARIES(JFJochCommon JFJochLogger Compression JFCalibration gemmi Threads::Threads -lrt ) diff --git a/common/DarkMaskSettings.cpp b/common/DarkMaskSettings.cpp new file mode 100644 index 00000000..aaf162e3 --- /dev/null +++ b/common/DarkMaskSettings.cpp @@ -0,0 +1,69 @@ +// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute +// SPDX-License-Identifier: GPL-3.0-only + +#include "DarkMaskSettings.h" +#include "JFJochException.h" +#include + +#define check_max(param, val, max) if ((val) > (max)) throw JFJochException(JFJochExceptionCategory::InputParameterAboveMax, param) +#define check_min(param, val, min) if ((val) < (min)) throw JFJochException(JFJochExceptionCategory::InputParameterBelowMin, param) +#define check_finite(param, val) if (!std::isfinite(val)) throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, param) + +DarkMaskSettings::DarkMaskSettings() + : number_of_frames(1000), + frame_time(std::chrono::milliseconds(10)), + threshold_keV(4.0f), + max_frames_with_counts(10), + max_counts(1) { +} + +DarkMaskSettings &DarkMaskSettings::NumberOfFrames(int64_t input) { + check_min("Number of frames", input, 10); + number_of_frames = input; + return *this; +} + +DarkMaskSettings &DarkMaskSettings::FrameTime(std::chrono::microseconds input) { + check_min("Frame time for dark images for mask", input.count(), 1); + frame_time = input; + return *this; +} + +DarkMaskSettings &DarkMaskSettings::Threshold_keV(float input) { + check_finite("Dark mask settings: threshold [keV]", input); + check_min("Dark mask settings: threshold", input, 2.7); + threshold_keV = input; + return *this; +} + +DarkMaskSettings &DarkMaskSettings::MaxFramesWithCounts(int64_t input) { + check_min("Max allowed frames with signal in dark images for mask", input, 0); + max_frames_with_counts = input; + return *this; +} + +DarkMaskSettings &DarkMaskSettings::MaxCounts(int64_t input) { + check_min("Max allowed counts in dark images for mask", input, 1); + max_counts = input; + return *this; +} + +int64_t DarkMaskSettings::GetNumberOfFrames() const { + return number_of_frames; +} + +std::chrono::microseconds DarkMaskSettings::GetFrameTime() const { + return frame_time; +} + +float DarkMaskSettings::GetThreshold_keV() const { + return threshold_keV; +} + +int64_t DarkMaskSettings::GetMaxFramesWithCounts() const { + return max_frames_with_counts; +} + +int64_t DarkMaskSettings::GetMaxCounts() const { + return max_counts; +} diff --git a/common/DarkMaskSettings.h b/common/DarkMaskSettings.h new file mode 100644 index 00000000..329e2d22 --- /dev/null +++ b/common/DarkMaskSettings.h @@ -0,0 +1,31 @@ +// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute +// SPDX-License-Identifier: GPL-3.0-only + +#ifndef JFJOCH_DARKMASKSETTINGS_H +#define JFJOCH_DARKMASKSETTINGS_H + +#include +#include +class DarkMaskSettings { + int64_t number_of_frames; + std::chrono::microseconds frame_time; + float threshold_keV; + int64_t max_frames_with_counts; + int64_t max_counts; +public: + DarkMaskSettings(); + DarkMaskSettings& NumberOfFrames(int64_t input); + DarkMaskSettings& FrameTime(std::chrono::microseconds input); + DarkMaskSettings& Threshold_keV(float input); + DarkMaskSettings& MaxFramesWithCounts(int64_t input); + DarkMaskSettings& MaxCounts(int64_t input); + + [[nodiscard]] int64_t GetNumberOfFrames() const; + [[nodiscard]] std::chrono::microseconds GetFrameTime() const; + [[nodiscard]] float GetThreshold_keV() const; + [[nodiscard]] int64_t GetMaxFramesWithCounts() const; + [[nodiscard]] int64_t GetMaxCounts() const; +}; + + +#endif //JFJOCH_DARKMASKSETTINGS_H \ No newline at end of file diff --git a/common/DetectorSettings.cpp b/common/DetectorSettings.cpp index a0a7e536..df4f7cdc 100644 --- a/common/DetectorSettings.cpp +++ b/common/DetectorSettings.cpp @@ -219,3 +219,13 @@ bool DetectorSettings::NeedsJUNGFRAURecalibration(const DetectorSettings &other) || this->storage_cell_delay != other.storage_cell_delay || this->internal_fpga_packet_generator != other.internal_fpga_packet_generator; } + +DarkMaskSettings DetectorSettings::GetDarkMaskSettings() const { + return dark_mask_settings; +} + +DetectorSettings &DetectorSettings::Import(const DarkMaskSettings &settings) { + dark_mask_settings = settings; + return *this; +} + diff --git a/common/DetectorSettings.h b/common/DetectorSettings.h index f9ec9f91..e8e1dd97 100644 --- a/common/DetectorSettings.h +++ b/common/DetectorSettings.h @@ -8,6 +8,7 @@ #include #include +#include "DarkMaskSettings.h" #include "../common/Definitions.h" enum class DetectorTiming {Auto, Trigger, Burst, Gated}; @@ -35,6 +36,8 @@ class DetectorSettings { std::optional eiger_bitwidth; DetectorTiming timing = DetectorTiming::Trigger; + + DarkMaskSettings dark_mask_settings; public: DetectorSettings& InternalGeneratorEnable(bool input); DetectorSettings& InternalGeneratorImages(int64_t input); @@ -77,6 +80,9 @@ public: [[nodiscard]] DetectorTiming GetTiming() const; [[nodiscard]] bool NeedsJUNGFRAURecalibration(const DetectorSettings& other) const; + + DetectorSettings& Import(const DarkMaskSettings& settings); + DarkMaskSettings GetDarkMaskSettings() const; }; diff --git a/common/DiffractionExperiment.cpp b/common/DiffractionExperiment.cpp index 600ec158..81679009 100644 --- a/common/DiffractionExperiment.cpp +++ b/common/DiffractionExperiment.cpp @@ -228,14 +228,16 @@ DetectorMode DiffractionExperiment::GetDetectorMode() const { } std::chrono::microseconds DiffractionExperiment::GetFrameTime() const { - if ((GetDetectorType() != DetectorType::JUNGFRAU) && dataset.GetImageTime().has_value()) - return dataset.GetImageTime().value(); - switch (GetDetectorMode()) { + case DetectorMode::DarkMask: + return detector_settings.GetDarkMaskSettings().GetFrameTime(); case DetectorMode::PedestalG1: case DetectorMode::PedestalG2: return detector_settings.GetFrameTimePedestalG1G2(); default: + if ((GetDetectorType() != DetectorType::JUNGFRAU) && dataset.GetImageTime().has_value()) + return dataset.GetImageTime().value(); + return detector_settings.GetFrameTime(); } } @@ -277,6 +279,8 @@ int64_t DiffractionExperiment::GetFrameNum() const { int64_t DiffractionExperiment::GetFrameNumPerTrigger() const { switch (GetDetectorMode()) { + case DetectorMode::DarkMask: + return detector_settings.GetDarkMaskSettings().GetNumberOfFrames(); case DetectorMode::PedestalG0: return GetPedestalG0Frames() * GetStorageCellNumber(); case DetectorMode::PedestalG1: diff --git a/image_analysis/mask_dark_analysis/MaskDarkAnalysis.cpp b/image_analysis/mask_dark_analysis/MaskDarkAnalysis.cpp index 8b09195a..43df6291 100644 --- a/image_analysis/mask_dark_analysis/MaskDarkAnalysis.cpp +++ b/image_analysis/mask_dark_analysis/MaskDarkAnalysis.cpp @@ -4,7 +4,10 @@ #include "MaskDarkAnalysis.h" #include "../../common/JFJochException.h" -MaskDarkAnalysis::MaskDarkAnalysis(size_t det_size) : mask(det_size, 0) {} +MaskDarkAnalysis::MaskDarkAnalysis(const DarkMaskSettings &settings, size_t det_size) + : max_allowed_value(settings.GetMaxCounts()), + max_frames_with_signal(settings.GetMaxFramesWithCounts()), + mask(det_size, 0) {} template void MaskDarkAnalysis::check(const T *ptr) { @@ -50,6 +53,6 @@ void MaskDarkAnalysis::ApplyMask(PixelMask &in_mask) const { std::unique_lock ul(m); std::vector tmp(mask.size(), 0); for (int i = 0; i < mask.size(); i++) - tmp[i] = (mask[i] > max_allowed_freq) ? 1 : 0; + tmp[i] = (mask[i] > max_frames_with_signal) ? 1 : 0; in_mask.LoadDarkBadPixelMask(tmp); } diff --git a/image_analysis/mask_dark_analysis/MaskDarkAnalysis.h b/image_analysis/mask_dark_analysis/MaskDarkAnalysis.h index b223015f..e96a82e5 100644 --- a/image_analysis/mask_dark_analysis/MaskDarkAnalysis.h +++ b/image_analysis/mask_dark_analysis/MaskDarkAnalysis.h @@ -9,19 +9,19 @@ #include #include "../common/CompressedImage.h" #include "../common/PixelMask.h" +#include "../common/DiffractionExperiment.h" class MaskDarkAnalysis { mutable std::mutex m; - const int64_t max_allowed_value = 1; - const int64_t max_allowed_freq = 10; + const int64_t max_allowed_value; + const int64_t max_frames_with_signal; std::vector mask; - template void check(const T *ptr); public: - explicit MaskDarkAnalysis(size_t det_size); + MaskDarkAnalysis(const DarkMaskSettings& settings, size_t det_size); void AnalyzeImage(const DataMessage &msg, std::vector buffer); void ApplyMask(PixelMask &mask) const; }; -- 2.49.1 From 624158f4121859d596963d2e346579cc6fa2531a Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Wed, 5 Nov 2025 06:24:47 +0100 Subject: [PATCH 06/69] DiffractionExperiment: Improve DarkMask mode behavior --- common/DarkMaskSettings.cpp | 2 +- common/DarkMaskSettings.h | 1 + common/DetectorSettings.h | 2 +- common/DiffractionExperiment.cpp | 36 ++++++++++++++++++++++------- common/DiffractionExperiment.h | 2 ++ tests/DiffractionExperimentTest.cpp | 34 +++++++++++++++++++++++++++ 6 files changed, 67 insertions(+), 10 deletions(-) diff --git a/common/DarkMaskSettings.cpp b/common/DarkMaskSettings.cpp index aaf162e3..eac3b802 100644 --- a/common/DarkMaskSettings.cpp +++ b/common/DarkMaskSettings.cpp @@ -18,7 +18,7 @@ DarkMaskSettings::DarkMaskSettings() } DarkMaskSettings &DarkMaskSettings::NumberOfFrames(int64_t input) { - check_min("Number of frames", input, 10); + check_min("Number of frames", input, 0); // zero is allowed, as in case of pedestal == disabled number_of_frames = input; return *this; } diff --git a/common/DarkMaskSettings.h b/common/DarkMaskSettings.h index 329e2d22..a82e58a7 100644 --- a/common/DarkMaskSettings.h +++ b/common/DarkMaskSettings.h @@ -6,6 +6,7 @@ #include #include + class DarkMaskSettings { int64_t number_of_frames; std::chrono::microseconds frame_time; diff --git a/common/DetectorSettings.h b/common/DetectorSettings.h index e8e1dd97..f16c9605 100644 --- a/common/DetectorSettings.h +++ b/common/DetectorSettings.h @@ -82,7 +82,7 @@ public: [[nodiscard]] bool NeedsJUNGFRAURecalibration(const DetectorSettings& other) const; DetectorSettings& Import(const DarkMaskSettings& settings); - DarkMaskSettings GetDarkMaskSettings() const; + [[nodiscard]] DarkMaskSettings GetDarkMaskSettings() const; }; diff --git a/common/DiffractionExperiment.cpp b/common/DiffractionExperiment.cpp index 81679009..44811081 100644 --- a/common/DiffractionExperiment.cpp +++ b/common/DiffractionExperiment.cpp @@ -214,7 +214,8 @@ DiffractionExperiment &DiffractionExperiment::OverwriteExistingFiles(bool input) // getter functions int64_t DiffractionExperiment::GetNumTriggers() const { - if (IsPedestalRun()) + if (GetDetectorMode() != DetectorMode::Standard) + // For pedestal and dark mask modes return 1; else if (IsPulsedSource()) // For pulsed source summation happens over multiple triggers @@ -230,7 +231,7 @@ DetectorMode DiffractionExperiment::GetDetectorMode() const { std::chrono::microseconds DiffractionExperiment::GetFrameTime() const { switch (GetDetectorMode()) { case DetectorMode::DarkMask: - return detector_settings.GetDarkMaskSettings().GetFrameTime(); + return GetDarkMaskSettings().GetFrameTime(); case DetectorMode::PedestalG1: case DetectorMode::PedestalG2: return detector_settings.GetFrameTimePedestalG1G2(); @@ -270,7 +271,9 @@ std::chrono::microseconds DiffractionExperiment::GetImageTime() const { } int64_t DiffractionExperiment::GetImageNum() const { - return IsPedestalRun() ? 0 : (GetFrameNum() / GetSummation()); + if (GetDetectorMode() == DetectorMode::Standard) + return GetFrameNum() / GetSummation(); + return 0; } int64_t DiffractionExperiment::GetFrameNum() const { @@ -280,7 +283,7 @@ int64_t DiffractionExperiment::GetFrameNum() const { int64_t DiffractionExperiment::GetFrameNumPerTrigger() const { switch (GetDetectorMode()) { case DetectorMode::DarkMask: - return detector_settings.GetDarkMaskSettings().GetNumberOfFrames(); + return GetDarkMaskSettings().GetNumberOfFrames(); case DetectorMode::PedestalG0: return GetPedestalG0Frames() * GetStorageCellNumber(); case DetectorMode::PedestalG1: @@ -1317,11 +1320,18 @@ uint32_t DiffractionExperiment::GetPedestalMinImageCount() const { } float DiffractionExperiment::GetEigerThreshold_keV() const { - float thr = GetIncidentEnergy_keV() / 2.0f; + float thr; - auto val = detector_settings.GetEigerThreshold_keV(); - if (val) - thr = val.value(); + if (GetDetectorMode() == DetectorMode::DarkMask) + thr = GetDarkMaskSettings().GetThreshold_keV(); + else { + auto val = detector_settings.GetEigerThreshold_keV(); + + if (val) + thr = val.value(); + else + thr = GetIncidentEnergy_keV() / 2.0f; + } if (thr < detector.GetMinThreshold_keV()) thr = detector.GetMinThreshold_keV(); @@ -1616,3 +1626,13 @@ bool DiffractionExperiment::IsDetectIceRings() const { const XrayFluorescenceSpectrum &DiffractionExperiment::GetFluorescenceSpectrum() const { return dataset.GetFluorescenceSpectrum(); } + +DarkMaskSettings DiffractionExperiment::GetDarkMaskSettings() const { + return detector_settings.GetDarkMaskSettings(); +} + +int64_t DiffractionExperiment::GetDarkMaskNumberOfFrames() const { + if (GetDetectorType() == DetectorType::DECTRIS) + return GetDarkMaskSettings().GetNumberOfFrames(); + return 0; +} diff --git a/common/DiffractionExperiment.h b/common/DiffractionExperiment.h index 2ec66191..6e1a0d7f 100644 --- a/common/DiffractionExperiment.h +++ b/common/DiffractionExperiment.h @@ -398,6 +398,8 @@ public: const XrayFluorescenceSpectrum &GetFluorescenceSpectrum() const; bool IsDetectIceRings() const; + DarkMaskSettings GetDarkMaskSettings() const; + int64_t GetDarkMaskNumberOfFrames() const; }; #endif //DIFFRACTIONEXPERIMENT_H diff --git a/tests/DiffractionExperimentTest.cpp b/tests/DiffractionExperimentTest.cpp index d2aa5f51..acd2250b 100644 --- a/tests/DiffractionExperimentTest.cpp +++ b/tests/DiffractionExperimentTest.cpp @@ -874,6 +874,40 @@ TEST_CASE("DiffractionExperiment_Appendix","") { REQUIRE(message.user_data == "HeaderAppendix"); } +TEST_CASE("DiffractionExperiment_DarkMask","[DiffractionExperiment]") { + DiffractionExperiment x(DetJF4M()); + REQUIRE_THROWS(x.Mode(DetectorMode::DarkMask)); + REQUIRE(x.GetDetectorMode() == DetectorMode::Standard); + + x.Detector(DetEIGER(1)); + REQUIRE_THROWS(x.Mode(DetectorMode::DarkMask)); + REQUIRE(x.GetDetectorMode() == DetectorMode::Standard); + + x.Detector(DetDECTRIS(1024,1024, "Det1", "")); + x.FrameTime(std::chrono::milliseconds(100)).ImagesPerTrigger(100).NumTriggers(3); + + DarkMaskSettings dark_mask_settings; + dark_mask_settings.FrameTime(std::chrono::milliseconds(20)).NumberOfFrames(456).Threshold_keV(3.4); + x.ImportDetectorSettings(x.GetDetectorSettings().Import(dark_mask_settings).EigerThreshold_keV(5.0)); + + CHECK(x.GetNumTriggers() == 3); + CHECK(x.GetImageNum() == 3 * 100); + CHECK(x.GetEigerThreshold_keV() == Catch::Approx(5.0)); + CHECK(x.GetDarkMaskNumberOfFrames() == 456); + + REQUIRE_NOTHROW(x.Mode(DetectorMode::DarkMask)); + REQUIRE(x.GetDetectorMode() == DetectorMode::DarkMask); + + CHECK(x.GetNumTriggers() == 1); + CHECK(x.GetFrameNumPerTrigger() == 456); + CHECK(x.GetFrameNum() == 456); + CHECK(x.GetEigerThreshold_keV() == Catch::Approx(3.4)); + CHECK(x.GetFrameTime() == std::chrono::milliseconds(20)); + CHECK(x.GetImageTime() == std::chrono::milliseconds(20)); + CHECK(x.GetImageNum() == 0); + +} + TEST_CASE("DiffractionExperiment_ConversionOnFPGA","[DiffractionExperiment]") { DiffractionExperiment x; x.Conversion(); -- 2.49.1 From 8309643b95cdf3278735d032d2a4b59914b8f69c Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Wed, 5 Nov 2025 06:36:06 +0100 Subject: [PATCH 07/69] MaskDarkAnalysis: Change GetMask() function --- image_analysis/mask_dark_analysis/MaskDarkAnalysis.cpp | 4 ++-- image_analysis/mask_dark_analysis/MaskDarkAnalysis.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/image_analysis/mask_dark_analysis/MaskDarkAnalysis.cpp b/image_analysis/mask_dark_analysis/MaskDarkAnalysis.cpp index 43df6291..0f798951 100644 --- a/image_analysis/mask_dark_analysis/MaskDarkAnalysis.cpp +++ b/image_analysis/mask_dark_analysis/MaskDarkAnalysis.cpp @@ -49,10 +49,10 @@ void MaskDarkAnalysis::AnalyzeImage(const DataMessage &data, std::vector MaskDarkAnalysis::GetMask() const { std::unique_lock ul(m); std::vector tmp(mask.size(), 0); for (int i = 0; i < mask.size(); i++) tmp[i] = (mask[i] > max_frames_with_signal) ? 1 : 0; - in_mask.LoadDarkBadPixelMask(tmp); + return tmp; } diff --git a/image_analysis/mask_dark_analysis/MaskDarkAnalysis.h b/image_analysis/mask_dark_analysis/MaskDarkAnalysis.h index e96a82e5..fa74c974 100644 --- a/image_analysis/mask_dark_analysis/MaskDarkAnalysis.h +++ b/image_analysis/mask_dark_analysis/MaskDarkAnalysis.h @@ -23,7 +23,7 @@ class MaskDarkAnalysis { public: MaskDarkAnalysis(const DarkMaskSettings& settings, size_t det_size); void AnalyzeImage(const DataMessage &msg, std::vector buffer); - void ApplyMask(PixelMask &mask) const; + std::vector GetMask() const; }; -- 2.49.1 From a6020c00cac039ab0fc42be0c96d7795c830ab9c Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Wed, 5 Nov 2025 06:49:36 +0100 Subject: [PATCH 08/69] JFJochReceiverLite: Implement dark mask analysis (experimental, not tested) --- image_analysis/CMakeLists.txt | 4 +- .../DarkMaskAnalysis.cpp} | 10 +- .../DarkMaskAnalysis.h} | 8 +- receiver/JFJochReceiverLite.cpp | 104 ++++++++++++++---- receiver/JFJochReceiverLite.h | 5 + receiver/JFJochReceiverOutput.h | 1 + 6 files changed, 99 insertions(+), 33 deletions(-) rename image_analysis/{mask_dark_analysis/MaskDarkAnalysis.cpp => dark_mask_analysis/DarkMaskAnalysis.cpp} (88%) rename image_analysis/{mask_dark_analysis/MaskDarkAnalysis.h => dark_mask_analysis/DarkMaskAnalysis.h} (81%) diff --git a/image_analysis/CMakeLists.txt b/image_analysis/CMakeLists.txt index cac33e00..33ed4ed6 100644 --- a/image_analysis/CMakeLists.txt +++ b/image_analysis/CMakeLists.txt @@ -5,8 +5,8 @@ ADD_LIBRARY(JFJochImageAnalysis STATIC MXAnalysisAfterFPGA.cpp SpotAnalyze.cpp SpotAnalyze.h - mask_dark_analysis/MaskDarkAnalysis.cpp - mask_dark_analysis/MaskDarkAnalysis.h) + dark_mask_analysis/DarkMaskAnalysis.cpp + dark_mask_analysis/DarkMaskAnalysis.h) FIND_PACKAGE(Eigen3 3.4 REQUIRED NO_MODULE) # provides Eigen3::Eigen diff --git a/image_analysis/mask_dark_analysis/MaskDarkAnalysis.cpp b/image_analysis/dark_mask_analysis/DarkMaskAnalysis.cpp similarity index 88% rename from image_analysis/mask_dark_analysis/MaskDarkAnalysis.cpp rename to image_analysis/dark_mask_analysis/DarkMaskAnalysis.cpp index 0f798951..3a53bc3d 100644 --- a/image_analysis/mask_dark_analysis/MaskDarkAnalysis.cpp +++ b/image_analysis/dark_mask_analysis/DarkMaskAnalysis.cpp @@ -1,16 +1,16 @@ // SPDX-FileCopyrightText: 2024 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only -#include "MaskDarkAnalysis.h" +#include "DarkMaskAnalysis.h" #include "../../common/JFJochException.h" -MaskDarkAnalysis::MaskDarkAnalysis(const DarkMaskSettings &settings, size_t det_size) +DarkMaskAnalysis::DarkMaskAnalysis(const DarkMaskSettings &settings, size_t det_size) : max_allowed_value(settings.GetMaxCounts()), max_frames_with_signal(settings.GetMaxFramesWithCounts()), mask(det_size, 0) {} template -void MaskDarkAnalysis::check(const T *ptr) { +void DarkMaskAnalysis::check(const T *ptr) { std::unique_lock ul(m); for (int i = 0; i < mask.size(); i++) { auto v64 = static_cast(ptr[i]); @@ -19,7 +19,7 @@ void MaskDarkAnalysis::check(const T *ptr) { } } -void MaskDarkAnalysis::AnalyzeImage(const DataMessage &data, std::vector buffer) { +void DarkMaskAnalysis::AnalyzeImage(const DataMessage &data, std::vector buffer) { if (data.image.GetWidth() * data.image.GetHeight() != mask.size()) throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Invalid size of input image"); @@ -49,7 +49,7 @@ void MaskDarkAnalysis::AnalyzeImage(const DataMessage &data, std::vector MaskDarkAnalysis::GetMask() const { +std::vector DarkMaskAnalysis::GetMask() const { std::unique_lock ul(m); std::vector tmp(mask.size(), 0); for (int i = 0; i < mask.size(); i++) diff --git a/image_analysis/mask_dark_analysis/MaskDarkAnalysis.h b/image_analysis/dark_mask_analysis/DarkMaskAnalysis.h similarity index 81% rename from image_analysis/mask_dark_analysis/MaskDarkAnalysis.h rename to image_analysis/dark_mask_analysis/DarkMaskAnalysis.h index fa74c974..997d69b4 100644 --- a/image_analysis/mask_dark_analysis/MaskDarkAnalysis.h +++ b/image_analysis/dark_mask_analysis/DarkMaskAnalysis.h @@ -1,8 +1,8 @@ // SPDX-FileCopyrightText: 2024 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only -#ifndef JFJOCH_MASKDARKANALYSIS_H -#define JFJOCH_MASKDARKANALYSIS_H +#ifndef JFJOCH_DARKMASKANALYSIS_H +#define JFJOCH_DARKMASKANALYSIS_H #include #include @@ -11,7 +11,7 @@ #include "../common/PixelMask.h" #include "../common/DiffractionExperiment.h" -class MaskDarkAnalysis { +class DarkMaskAnalysis { mutable std::mutex m; const int64_t max_allowed_value; @@ -21,7 +21,7 @@ class MaskDarkAnalysis { template void check(const T *ptr); public: - MaskDarkAnalysis(const DarkMaskSettings& settings, size_t det_size); + DarkMaskAnalysis(const DarkMaskSettings& settings, size_t det_size); void AnalyzeImage(const DataMessage &msg, std::vector buffer); std::vector GetMask() const; }; diff --git a/receiver/JFJochReceiverLite.cpp b/receiver/JFJochReceiverLite.cpp index f7e1da24..017e9d77 100644 --- a/receiver/JFJochReceiverLite.cpp +++ b/receiver/JFJochReceiverLite.cpp @@ -3,6 +3,7 @@ #include "JFJochReceiverLite.h" #include "../image_analysis/indexing/IndexerFactory.h" +#include "../image_analysis/dark_mask_analysis/MaskDarkAnalysis.h" using namespace std::chrono_literals; @@ -43,31 +44,38 @@ JFJochReceiverLite::JFJochReceiverLite(const DiffractionExperiment &in_experimen ZMQPreviewSocket *in_zmq_preview_socket, ZMQMetadataSocket *in_zmq_metadata_socket, IndexerThreadPool *indexing_thread_pool) - : JFJochReceiver(in_experiment, - in_image_buffer, - in_image_pusher, - in_preview_image, - in_current_status, - in_plots, - in_spot_finding_settings, - in_logger, - in_numa_policy, - in_pixel_mask, - in_zmq_preview_socket, - in_zmq_metadata_socket, - indexing_thread_pool), - image_puller(in_image_puller), - data_analysis_nthreads(NumberOfDataAnalysisThreads(forward_and_sum_nthreads, in_experiment)), - data_analysis_started(data_analysis_nthreads), - measurement_started(1){ - + : JFJochReceiver(in_experiment, + in_image_buffer, + in_image_pusher, + in_preview_image, + in_current_status, + in_plots, + in_spot_finding_settings, + in_logger, + in_numa_policy, + in_pixel_mask, + in_zmq_preview_socket, + in_zmq_metadata_socket, + indexing_thread_pool), + image_puller(in_image_puller), + data_analysis_nthreads(NumberOfDataAnalysisThreads(forward_and_sum_nthreads, in_experiment)), + data_analysis_started(data_analysis_nthreads), + measurement_started(1), + dark_mask_analysis(in_experiment.GetDarkMaskSettings(), in_experiment.GetPixelsNum()) { logger.Info("Starting {} data analysis threads", data_analysis_nthreads); - // Start frame transformation threads - for (int i = 0; i < data_analysis_nthreads; i++) - data_analysis_futures.emplace_back( + if (experiment.GetDetectorMode() == DetectorMode::DarkMask) { + for (int i = 0; i < data_analysis_nthreads; i++) + data_analysis_futures.emplace_back( + std::async(std::launch::async, &JFJochReceiverLite::MaskThread, this, i) + ); + } else { + // Start frame transformation threads + for (int i = 0; i < data_analysis_nthreads; i++) + data_analysis_futures.emplace_back( std::async(std::launch::async, &JFJochReceiverLite::DataAnalysisThread, this, i) - ); + ); + } measurement = std::async(std::launch::async, &JFJochReceiverLite::MeasurementThread, this); @@ -170,6 +178,51 @@ void JFJochReceiverLite::Configure(const StartMessage &msg) { experiment.Detector().BitDepthReadout(msg.bit_depth_readout.value()); } +void JFJochReceiverLite::MaskThread(uint32_t id) { + std::vector buffer; + data_analysis_started.count_down(); + measurement_started.wait(); + + while (!cancelled && !end_message_received) { + try { + auto msg = image_puller.PollImage(std::chrono::milliseconds(5)); + + if (!msg.has_value() || !msg->cbor) { + // Message not received or not parsed + continue; + } else if (msg->cbor->end_message) { + end_message_received = true; + logger.Debug("Thread {} end message received in JFJochReceiverLite", id); + } else if (msg->cbor->data_message) { + ++images_collected; + DataMessage data_msg = msg->cbor->data_message.value(); + compressed_size += data_msg.image.GetCompressedSize(); + uncompressed_size += data_msg.image.GetUncompressedSize(); + UpdateMaxImageReceived(data_msg.number); + + auto loc = image_buffer.GetImageSlot(); + + if (loc == nullptr) + writer_queue_full = true; + else { + auto writer_buffer = (uint8_t *) loc->GetImage(); + CBORStream2Serializer serializer(writer_buffer, experiment.GetImageBufferLocationSize()); + serializer.SerializeImage(data_msg); + loc->SetImageNumber(data_msg.number); + loc->SetImageSize(serializer.GetBufferSize()); + loc->SetIndexed(false); + loc->release(); + } + } + current_status.SetProgress(GetProgress()); + current_status.SetStatus(GetStatus()); + } catch (const JFJochException &e) { + logger.ErrorException(e); + Cancel(e); + } + } +} + void JFJochReceiverLite::DataAnalysisThread(uint32_t id) { std::vector buffer; std::unique_ptr analysis; @@ -317,3 +370,10 @@ void JFJochReceiverLite::SetSpotFindingSettings(const SpotFindingSettings &in_sp 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) + ret.dark_mask_result = dark_mask_analysis.GetMask(); + return ret; +} diff --git a/receiver/JFJochReceiverLite.h b/receiver/JFJochReceiverLite.h index c598e130..06a721e7 100644 --- a/receiver/JFJochReceiverLite.h +++ b/receiver/JFJochReceiverLite.h @@ -24,6 +24,7 @@ #include "JFJochReceiverOutput.h" #include "../image_puller/ZMQImagePuller.h" #include "../image_analysis/MXAnalysisWithoutFPGA.h" +#include "../image_analysis/dark_mask_analysis/MaskDarkAnalysis.h" class JFJochReceiverLite : public JFJochReceiver { ImagePuller &image_puller; @@ -38,6 +39,9 @@ class JFJochReceiverLite : public JFJochReceiver { std::latch measurement_started; std::latch data_analysis_started; + DarkMaskAnalysis dark_mask_analysis; + + void MaskThread(uint32_t id); void MeasurementThread(); void DataAnalysisThread(uint32_t id); void Configure(const StartMessage &message); @@ -67,6 +71,7 @@ public: float GetProgress() const override; void SetSpotFindingSettings(const SpotFindingSettings &spot_finding_settings) override; + JFJochReceiverOutput GetFinalStatistics() const override; }; #endif //JFJOCH_JFJOCHRECEIVERLITE_H diff --git a/receiver/JFJochReceiverOutput.h b/receiver/JFJochReceiverOutput.h index bb5e9d98..9c12d0de 100644 --- a/receiver/JFJochReceiverOutput.h +++ b/receiver/JFJochReceiverOutput.h @@ -13,6 +13,7 @@ struct JFJochReceiverOutput { std::vector pedestal_result; + std::vector dark_mask_result; ScanResult scan_result; std::vector received_packets; std::vector expected_packets; -- 2.49.1 From 2fb98a700adf5cd8e7329e64247b940292e17bd9 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Wed, 5 Nov 2025 07:05:43 +0100 Subject: [PATCH 09/69] JFJochReceiverLite: Fix wrong include --- receiver/JFJochReceiverLite.cpp | 1 - receiver/JFJochReceiverLite.h | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/receiver/JFJochReceiverLite.cpp b/receiver/JFJochReceiverLite.cpp index 017e9d77..5bc3947b 100644 --- a/receiver/JFJochReceiverLite.cpp +++ b/receiver/JFJochReceiverLite.cpp @@ -3,7 +3,6 @@ #include "JFJochReceiverLite.h" #include "../image_analysis/indexing/IndexerFactory.h" -#include "../image_analysis/dark_mask_analysis/MaskDarkAnalysis.h" using namespace std::chrono_literals; diff --git a/receiver/JFJochReceiverLite.h b/receiver/JFJochReceiverLite.h index 06a721e7..a48339ad 100644 --- a/receiver/JFJochReceiverLite.h +++ b/receiver/JFJochReceiverLite.h @@ -24,7 +24,7 @@ #include "JFJochReceiverOutput.h" #include "../image_puller/ZMQImagePuller.h" #include "../image_analysis/MXAnalysisWithoutFPGA.h" -#include "../image_analysis/dark_mask_analysis/MaskDarkAnalysis.h" +#include "../image_analysis/dark_mask_analysis/DarkMaskAnalysis.h" class JFJochReceiverLite : public JFJochReceiver { ImagePuller &image_puller; -- 2.49.1 From 39cb3907bdae1c41bddf1640a2eca725745d2a32 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Wed, 5 Nov 2025 07:41:59 +0100 Subject: [PATCH 10/69] JFJochReceiverLite: Dark mask analysis integrated and tested --- receiver/JFJochReceiverLite.cpp | 7 ++- tests/JFJochReceiverLiteTest.cpp | 85 +++++++++++++++++++++++++++++++- 2 files changed, 89 insertions(+), 3 deletions(-) diff --git a/receiver/JFJochReceiverLite.cpp b/receiver/JFJochReceiverLite.cpp index 5bc3947b..dc0f3359 100644 --- a/receiver/JFJochReceiverLite.cpp +++ b/receiver/JFJochReceiverLite.cpp @@ -195,6 +195,9 @@ void JFJochReceiverLite::MaskThread(uint32_t id) { } else if (msg->cbor->data_message) { ++images_collected; DataMessage data_msg = msg->cbor->data_message.value(); + + dark_mask_analysis.AnalyzeImage(data_msg, buffer); + compressed_size += data_msg.image.GetCompressedSize(); uncompressed_size += data_msg.image.GetUncompressedSize(); UpdateMaxImageReceived(data_msg.number); @@ -352,9 +355,9 @@ void JFJochReceiverLite::StopReceiver() { } float JFJochReceiverLite::GetEfficiency() const { - if (experiment.GetImageNum() == 0) + if (experiment.GetFrameNum() == 0) return 0; - return static_cast(images_collected) / static_cast(experiment.GetImageNum()); + return static_cast(images_collected) / static_cast(experiment.GetFrameNum()); } float JFJochReceiverLite::GetProgress() const { diff --git a/tests/JFJochReceiverLiteTest.cpp b/tests/JFJochReceiverLiteTest.cpp index 8dfd2ba4..c306efcc 100644 --- a/tests/JFJochReceiverLiteTest.cpp +++ b/tests/JFJochReceiverLiteTest.cpp @@ -12,7 +12,7 @@ #include "../image_puller/TestImagePuller.h" TEST_CASE("JFJochReceiverLite", "[JFJochReceiver]") { - Logger logger("JFJochIntegrationTest_ZMQ_lysozyme_spot_and_index"); + Logger logger("FJochReceiverLite"); RegisterHDF5Filter(); @@ -135,4 +135,87 @@ TEST_CASE("JFJochReceiverLite_Cancel", "[JFJochReceiver]") { CHECK(receiver_out.efficiency == 0.0); CHECK(receiver_out.status.cancelled); +} + +TEST_CASE("JFJochReceiverLite_DarkMask", "[JFJochReceiver]") { + Logger logger("JFJochReceiverLite_DarkMask"); + + RegisterHDF5Filter(); + + const uint16_t nthreads = 4; + + DiffractionExperiment experiment(DetDECTRIS(2068, 2164, "Test", {})); + + auto det_settings = experiment.GetDetectorSettings(); + det_settings.Import(DarkMaskSettings{}.NumberOfFrames(10).MaxCounts(1).MaxFramesWithCounts(5)).FrameTime(std::chrono::milliseconds(5)); + experiment.Mode(DetectorMode::DarkMask).ImportDetectorSettings(det_settings); + + PixelMask pixel_mask(experiment); + + HDF5FilePusher pusher; + + auto puller = std::make_shared(); + + StartMessage start_msg; + experiment.FillMessage(start_msg); + + puller->Put(ImagePullerOutput{ + .cbor = std::make_shared(start_msg) + }); + + + std::vector image(experiment.GetPixelsNum(), 0); + image[1] = 1; + image[2] = 2; + image[3] = 3; + + std::vector image_last(experiment.GetPixelsNum(), 0); + image_last[1] = 0; + image_last[2] = 0; + image_last[3] = 0; + image_last[68] = 10000; + + for (int i = 0; i < experiment.GetFrameNum(); i++) { + DataMessage data_msg; + if (i == experiment.GetFrameNum() - 1) + data_msg.image = CompressedImage(image_last, experiment.GetXPixelsNum(), experiment.GetYPixelsNum()); + else + data_msg.image = CompressedImage(image, experiment.GetXPixelsNum(), experiment.GetYPixelsNum()); + data_msg.number = i; + puller->Put(ImagePullerOutput{ + .cbor = std::make_shared(data_msg) + }); + } + + EndMessage end_msg{}; + + puller->Put(ImagePullerOutput{ + .cbor = std::make_shared(end_msg) + }); + + AcquisitionDeviceGroup group; + JFJochReceiverService service(group, logger, pusher); + + service.NumThreads(nthreads); + + // No progress value at the start of measurement + REQUIRE(!service.GetProgress().has_value()); + + service.Start(experiment, pixel_mask, nullptr, puller); + auto receiver_out = service.Stop(); + + CHECK(receiver_out.efficiency == 1.0); + CHECK(receiver_out.status.images_sent == 0); + CHECK(receiver_out.dark_mask_result.size() == experiment.GetPixelsNum()); + CHECK(receiver_out.dark_mask_result[0] == 0); + CHECK(receiver_out.dark_mask_result[1] == 0); + CHECK(receiver_out.dark_mask_result[2] != 0); + CHECK(receiver_out.dark_mask_result[3] != 0); + CHECK(receiver_out.dark_mask_result[4] == 0); + CHECK(receiver_out.dark_mask_result[68] == 0); + + CHECK(!receiver_out.status.cancelled); + + // No progress value at the end of the measurement + REQUIRE(!service.GetProgress().has_value()); } \ No newline at end of file -- 2.49.1 From 4c9ce8a42020396be8005ca882408c8909ee5109 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Wed, 5 Nov 2025 07:51:03 +0100 Subject: [PATCH 11/69] JFJochStateMachine: Slowly implement dark mask data taking into the workflow --- broker/JFJochStateMachine.cpp | 30 ++++++++++++++++++++++++++++++ broker/JFJochStateMachine.h | 1 + 2 files changed, 31 insertions(+) diff --git a/broker/JFJochStateMachine.cpp b/broker/JFJochStateMachine.cpp index 8f699236..253d510d 100644 --- a/broker/JFJochStateMachine.cpp +++ b/broker/JFJochStateMachine.cpp @@ -110,6 +110,36 @@ void JFJochStateMachine::TakePedestalInternalAll(std::unique_lock &u logger.Info("Pedestal sequence done"); } +void JFJochStateMachine::TakeDarkMaskInternal(std::unique_lock &ul) { + if (experiment.GetDarkMaskNumberOfFrames() == 0) + return; + if (cancel_sequence) { + SetState(JFJochState::Inactive, + "Mask sequence cancelled", + BrokerStatus::MessageSeverity::Warning); + return; + } + + DiffractionExperiment local_experiment(experiment); + local_experiment.Mode(DetectorMode::DarkMask); + + SetState(JFJochState::Pedestal, "Dark sequence for mask calculation", BrokerStatus::MessageSeverity::Info); + services.ConfigureDetector(local_experiment); + services.Start(local_experiment, pixel_mask, *calibration); + + ul.unlock(); + // Allow to cancel/abort during the mask data collection + auto mask_output = services.Stop(); + ul.lock(); + + if (mask_output.receiver_output.dark_mask_result.size() == local_experiment.GetPixelsNum()) { + pixel_mask.LoadDarkBadPixelMask(mask_output.receiver_output.dark_mask_result); + SetState(JFJochState::Idle); + } else + SetState(JFJochState::Error, + "Mask not collected properly", + BrokerStatus::MessageSeverity::Error); +} void JFJochStateMachine::TakePedestalInternalG0(std::unique_lock &ul) { DiffractionExperiment local_experiment(experiment); diff --git a/broker/JFJochStateMachine.h b/broker/JFJochStateMachine.h index 3d856f34..183c712a 100644 --- a/broker/JFJochStateMachine.h +++ b/broker/JFJochStateMachine.h @@ -140,6 +140,7 @@ class JFJochStateMachine { bool ImportPedestalG0(const JFJochReceiverOutput &receiver_output); bool IsRunning() const; // Is state Busy/Pedestal/Measure void ResetError() noexcept; + void TakeDarkMaskInternal(std::unique_lock &ul); void TakePedestalInternalAll(std::unique_lock &ul); void TakePedestalInternalG0(std::unique_lock &ul); void TakePedestalInternalG1(std::unique_lock &ul, int32_t storage_cell = 0); -- 2.49.1 From 74a55d8bc9b70bee34ee1d5e481b0accf735bc99 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Wed, 5 Nov 2025 07:55:56 +0100 Subject: [PATCH 12/69] DectrisSimplonClient: counting_mode retrigger for standard, normal for dark mask data taking --- detector_control/DectrisSimplonClient.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/detector_control/DectrisSimplonClient.cpp b/detector_control/DectrisSimplonClient.cpp index fd93b35a..47a176b2 100644 --- a/detector_control/DectrisSimplonClient.cpp +++ b/detector_control/DectrisSimplonClient.cpp @@ -231,7 +231,12 @@ void DectrisSimplonClient::ConfigureDetector(const DiffractionExperiment &experi SetConfig(SimplonModule::Stream, "mode", "enabled"); SetConfig(SimplonModule::Filewriter, "mode", "disabled"); SetConfig(SimplonModule::Monitor, "mode", "disabled"); - + + // TODO: Check if counting_mode retrigger is available + if (experiment.GetDetectorMode() == DetectorMode::DarkMask) + SetConfig(SimplonModule::Detector, "counting_mode", "normal"); + else + SetConfig(SimplonModule::Detector, "counting_mode", "retrigger"); SetConfig(SimplonModule::Detector, "photon_energy", experiment.GetIncidentEnergy_keV() * 1e3f); auto thr = experiment.GetEigerThreshold_keV(); SetConfig(SimplonModule::Detector, "threshold_energy", thr * 1e3f); -- 2.49.1 From 96de9e41eac7c0d503ec4baa27bea94a449650d3 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Wed, 5 Nov 2025 09:16:00 +0100 Subject: [PATCH 13/69] JFJochServices: Take calibration as pointer (it can be nullptr) --- broker/JFJochServices.cpp | 8 ++------ broker/JFJochServices.h | 2 +- broker/JFJochStateMachine.cpp | 12 ++++++------ 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/broker/JFJochServices.cpp b/broker/JFJochServices.cpp index ac8ad3a3..cf0210a6 100644 --- a/broker/JFJochServices.cpp +++ b/broker/JFJochServices.cpp @@ -10,18 +10,14 @@ JFJochServices::JFJochServices(Logger &in_logger) : logger(in_logger) {} void JFJochServices::Start(const DiffractionExperiment& experiment, const PixelMask &pixel_mask, - const JFCalibration &calibration) { + const JFCalibration *calibration) { logger.Info("Measurement start for: {}", experiment.GetFilePrefix()); cannot_stop_detector = false; if (receiver != nullptr) { logger.Info(" ... receiver start"); - if (experiment.IsJungfrauConvPhotonCnt()) - receiver->Start(experiment, pixel_mask, &calibration); - else - receiver->Start(experiment, pixel_mask, nullptr); - + receiver->Start(experiment, pixel_mask, calibration); if (detector && !experiment.IsUsingInternalPacketGen()) { logger.Info(" ... detector start"); detector->Start(experiment); diff --git a/broker/JFJochServices.h b/broker/JFJochServices.h index 196a1743..4595fc24 100644 --- a/broker/JFJochServices.h +++ b/broker/JFJochServices.h @@ -27,7 +27,7 @@ public: void ConfigureDetector(const DiffractionExperiment& experiment); void Start(const DiffractionExperiment& experiment, const PixelMask &pixel_mask, - const JFCalibration &calibration); + const JFCalibration *calibration = nullptr); JFJochServicesOutput Stop(); void Cancel(); void Trigger(); diff --git a/broker/JFJochStateMachine.cpp b/broker/JFJochStateMachine.cpp index 253d510d..ef840fd4 100644 --- a/broker/JFJochStateMachine.cpp +++ b/broker/JFJochStateMachine.cpp @@ -63,7 +63,7 @@ void JFJochStateMachine::TakePedestalInternalAll(std::unique_lock &u if (experiment.GetDetectorSetup().GetDetectorType() != DetectorType::JUNGFRAU) { try { calibration.reset(); - logger.Info("EIGER configuration"); + logger.Info("Photon counting detector configuration"); services.ConfigureDetector(experiment); logger.Info(" ... done "); SetState(JFJochState::Idle, @@ -125,7 +125,7 @@ void JFJochStateMachine::TakeDarkMaskInternal(std::unique_lock &ul) SetState(JFJochState::Pedestal, "Dark sequence for mask calculation", BrokerStatus::MessageSeverity::Info); services.ConfigureDetector(local_experiment); - services.Start(local_experiment, pixel_mask, *calibration); + services.Start(local_experiment, pixel_mask, nullptr); ul.unlock(); // Allow to cancel/abort during the mask data collection @@ -169,7 +169,7 @@ void JFJochStateMachine::TakePedestalInternalG0(std::unique_lock &ul SetState(JFJochState::Pedestal, message, BrokerStatus::MessageSeverity::Info); services.ConfigureDetector(local_experiment); - services.Start(local_experiment, pixel_mask, *calibration); + services.Start(local_experiment, pixel_mask, calibration.get()); services.Trigger(); @@ -212,7 +212,7 @@ void JFJochStateMachine::TakePedestalInternalG1(std::unique_lock &ul "Pedestal G1 SC" + std::to_string(storage_cell), BrokerStatus::MessageSeverity::Info); services.ConfigureDetector(local_experiment); - services.Start(local_experiment, pixel_mask, *calibration); + services.Start(local_experiment, pixel_mask, calibration.get()); services.Trigger(); @@ -252,7 +252,7 @@ void JFJochStateMachine::TakePedestalInternalG2(std::unique_lock &ul "Pedestal G2 SC" + std::to_string(storage_cell), BrokerStatus::MessageSeverity::Info); services.ConfigureDetector(local_experiment); - services.Start(local_experiment, pixel_mask, *calibration); + services.Start(local_experiment, pixel_mask, calibration.get()); services.Trigger(); @@ -361,7 +361,7 @@ void JFJochStateMachine::Start(const DatasetSettings &settings) { try { SetState(JFJochState::Busy, "Preparing measurement", BrokerStatus::MessageSeverity::Info); services.SetSpotFindingSettings(GetSpotFindingSettings()); - services.Start(experiment, pixel_mask, *calibration); + services.Start(experiment, pixel_mask, calibration.get()); SetState(JFJochState::Measuring, "Measuring ...", BrokerStatus::MessageSeverity::Info); measurement = std::async(std::launch::async, &JFJochStateMachine::MeasurementThread, this); -- 2.49.1 From 1dfe08a141cac8fc2d2621b79066b6125aee42d3 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Wed, 5 Nov 2025 10:05:44 +0100 Subject: [PATCH 14/69] JFJochStateMachine: Implement improved calibration routines (to be field tested) --- broker/JFJochBrokerHttp.cpp | 2 +- broker/JFJochStateMachine.cpp | 104 +++++++++++++++---------------- broker/JFJochStateMachine.h | 5 +- broker/OpenAPIConvert.cpp | 2 +- tests/JFJochStateMachineTest.cpp | 6 +- 5 files changed, 60 insertions(+), 59 deletions(-) diff --git a/broker/JFJochBrokerHttp.cpp b/broker/JFJochBrokerHttp.cpp index 3816efbe..a6fc3ec8 100644 --- a/broker/JFJochBrokerHttp.cpp +++ b/broker/JFJochBrokerHttp.cpp @@ -82,7 +82,7 @@ void JFJochBrokerHttp::wait_till_done_post(const std::optional &timeout throw WrongDAQStateException(status.message.value_or("Unknown error")); case JFJochState::Measuring: case JFJochState::Busy: - case JFJochState::Pedestal: + case JFJochState::Calibration: response.send(Pistache::Http::Code::Gateway_Timeout); break; } diff --git a/broker/JFJochStateMachine.cpp b/broker/JFJochStateMachine.cpp index ef840fd4..8d55755f 100644 --- a/broker/JFJochStateMachine.cpp +++ b/broker/JFJochStateMachine.cpp @@ -11,9 +11,9 @@ JFJochStateMachine::JFJochStateMachine(const DiffractionExperiment& in_experiment, JFJochServices &in_services, Logger &in_logger) - : experiment(in_experiment), - logger(in_logger), + : logger(in_logger), services(in_services), + experiment(in_experiment), pixel_mask(experiment), current_detector_setup(0), data_processing_settings(DiffractionExperiment::DefaultDataProcessingSettings()), @@ -59,60 +59,60 @@ bool JFJochStateMachine::ImportPedestalG1G2(const JFJochReceiverOutput &receiver return true; } -void JFJochStateMachine::TakePedestalInternalAll(std::unique_lock &ul) { - if (experiment.GetDetectorSetup().GetDetectorType() != DetectorType::JUNGFRAU) { - try { - calibration.reset(); - logger.Info("Photon counting detector configuration"); - services.ConfigureDetector(experiment); - logger.Info(" ... done "); - SetState(JFJochState::Idle, - "Detector configured", - BrokerStatus::MessageSeverity::Success); - return; - } catch (const std::exception &e) { - logger.Error("Configuration error {}", e.what()); - SetState(JFJochState::Error, e.what(), BrokerStatus::MessageSeverity::Error); - throw; - } - } - - calibration = std::make_unique(experiment); - +void JFJochStateMachine::CalibrateJUNGFRAU(std::unique_lock &ul) { if (!gain_calibration.empty()) { if (gain_calibration.size() != experiment.GetModulesNum()) - throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Mismatch in gain files number"); + throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, + "Mismatch in gain files number"); for (int i = 0; i < gain_calibration.size(); i++) calibration->GainCalibration(i) = gain_calibration[i]; } + TakePedestalInternalG0(ul); + if (!experiment.IsFixedGainG1()) { + for (int i = 0; i < experiment.GetStorageCellNumber(); i++) { + TakePedestalInternalG1(ul, i); + TakePedestalInternalG2(ul, i); + } + } + pixel_mask.LoadDetectorBadPixelMask(experiment, calibration.get()); +} + +void JFJochStateMachine::CalibrateDetector(std::unique_lock &ul) { cancel_sequence = false; - logger.Info("Pedestal sequence started"); + pixel_mask = PixelMask(experiment); + UpdatePixelMaskStatistics(pixel_mask.GetStatistics()); + logger.Info("Calibration sequence started"); try { - TakePedestalInternalG0(ul); - if (!experiment.IsFixedGainG1()) { - for (int i = 0; i < experiment.GetStorageCellNumber(); i++) { - TakePedestalInternalG1(ul, i); - TakePedestalInternalG2(ul, i); - } + if (experiment.GetDetectorType() == DetectorType::EIGER) { + // PSI EIGER - only reset calibration + calibration.reset(); + } else if (experiment.GetDetectorType() == DetectorType::DECTRIS) { + // DECTRIS - take dark data for mask + calibration.reset(); + TakeDarkMaskInternal(ul); + } else { + // PSI JUNGFRAU - take pedestal + calibration = std::make_unique(experiment); + CalibrateJUNGFRAU(ul); } - services.ConfigureDetector(experiment); - pixel_mask.LoadDetectorBadPixelMask(experiment, calibration.get()); + // Update pixel mask statistics UpdatePixelMaskStatistics(pixel_mask.GetStatistics()); - SetState(JFJochState::Idle, "Pedestal sequence done", BrokerStatus::MessageSeverity::Success); + // configure detector for standard operation + services.ConfigureDetector(experiment); } catch (const std::exception &e) { - logger.Error("Pedestal sequence error {}", e.what()); + logger.Error("Calibration sequence error {}", e.what()); SetState(JFJochState::Error, e.what(), BrokerStatus::MessageSeverity::Error); throw; } + SetState(JFJochState::Idle, "Calibration sequence done", BrokerStatus::MessageSeverity::Success); + logger.Info("Pedestal sequence done"); } void JFJochStateMachine::TakeDarkMaskInternal(std::unique_lock &ul) { - if (experiment.GetDarkMaskNumberOfFrames() == 0) - return; if (cancel_sequence) { SetState(JFJochState::Inactive, "Mask sequence cancelled", @@ -120,10 +120,15 @@ void JFJochStateMachine::TakeDarkMaskInternal(std::unique_lock &ul) return; } + services.LoadDetectorPixelMask(pixel_mask); + + if (experiment.GetDarkMaskNumberOfFrames() == 0) + return; + DiffractionExperiment local_experiment(experiment); local_experiment.Mode(DetectorMode::DarkMask); - SetState(JFJochState::Pedestal, "Dark sequence for mask calculation", BrokerStatus::MessageSeverity::Info); + SetState(JFJochState::Calibration, "Dark sequence for mask calculation", BrokerStatus::MessageSeverity::Info); services.ConfigureDetector(local_experiment); services.Start(local_experiment, pixel_mask, nullptr); @@ -136,9 +141,7 @@ void JFJochStateMachine::TakeDarkMaskInternal(std::unique_lock &ul) pixel_mask.LoadDarkBadPixelMask(mask_output.receiver_output.dark_mask_result); SetState(JFJochState::Idle); } else - SetState(JFJochState::Error, - "Mask not collected properly", - BrokerStatus::MessageSeverity::Error); + SetState(JFJochState::Error, "Mask not collected properly", BrokerStatus::MessageSeverity::Error); } void JFJochStateMachine::TakePedestalInternalG0(std::unique_lock &ul) { @@ -167,7 +170,7 @@ void JFJochStateMachine::TakePedestalInternalG0(std::unique_lock &ul if (local_experiment.GetPedestalG0Frames() == 0) return; - SetState(JFJochState::Pedestal, message, BrokerStatus::MessageSeverity::Info); + SetState(JFJochState::Calibration, message, BrokerStatus::MessageSeverity::Info); services.ConfigureDetector(local_experiment); services.Start(local_experiment, pixel_mask, calibration.get()); @@ -208,7 +211,7 @@ void JFJochStateMachine::TakePedestalInternalG1(std::unique_lock &ul return; - SetState(JFJochState::Pedestal, + SetState(JFJochState::Calibration, "Pedestal G1 SC" + std::to_string(storage_cell), BrokerStatus::MessageSeverity::Info); services.ConfigureDetector(local_experiment); @@ -248,7 +251,7 @@ void JFJochStateMachine::TakePedestalInternalG2(std::unique_lock &ul return; - SetState(JFJochState::Pedestal, + SetState(JFJochState::Calibration, "Pedestal G2 SC" + std::to_string(storage_cell), BrokerStatus::MessageSeverity::Info); services.ConfigureDetector(local_experiment); @@ -306,7 +309,7 @@ void JFJochStateMachine::Pedestal() { void JFJochStateMachine::PedestalThread(std::unique_lock ul) { - TakePedestalInternalAll(ul); + CalibrateDetector(ul); } void JFJochStateMachine::InitializeThread(std::unique_lock ul) { @@ -322,17 +325,14 @@ void JFJochStateMachine::InitializeThread(std::unique_lock ul) { ul.lock(); experiment = local_experiment; - detector_setup[current_detector_setup] = experiment.GetDetectorSetup(); - pixel_mask = PixelMask(experiment); - services.LoadDetectorPixelMask(pixel_mask); - UpdatePixelMaskStatistics(pixel_mask.GetStatistics()); + } catch (const std::exception &e) { logger.Error("Initialize error {}", e.what()); SetState(JFJochState::Error, e.what(), BrokerStatus::MessageSeverity::Error); throw; } - TakePedestalInternalAll(ul); + CalibrateDetector(ul); } void JFJochStateMachine::Trigger() { @@ -420,7 +420,7 @@ void JFJochStateMachine::MeasurementThread() { void JFJochStateMachine::Cancel() { // This is inconsistency in naming - need to solve later std::unique_lock ul(m); - if ((state == JFJochState::Pedestal) || (state == JFJochState::Measuring)) { + if ((state == JFJochState::Calibration) || (state == JFJochState::Measuring)) { services.Cancel(); cancel_sequence = true; } @@ -536,7 +536,7 @@ void JFJochStateMachine::LoadDetectorSettings(const DetectorSettings &settings) break; case JFJochState::Measuring: case JFJochState::Busy: - case JFJochState::Pedestal: + case JFJochState::Calibration: throw WrongDAQStateException("Cannot change detector settings during data collection"); } } @@ -691,7 +691,7 @@ bool JFJochStateMachine::IsRunning() const { return false; case JFJochState::Measuring: case JFJochState::Busy: - case JFJochState::Pedestal: + case JFJochState::Calibration: return true; default: throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "State unknown"); diff --git a/broker/JFJochStateMachine.h b/broker/JFJochStateMachine.h index 183c712a..1bc0eb8e 100644 --- a/broker/JFJochStateMachine.h +++ b/broker/JFJochStateMachine.h @@ -16,7 +16,7 @@ #include "JFJochServices.h" #include "../common/ROIMap.h" -enum class JFJochState {Inactive, Idle, Measuring, Error, Busy, Pedestal}; +enum class JFJochState {Inactive, Idle, Measuring, Error, Busy, Calibration}; struct BrokerStatus { JFJochState state = JFJochState::Inactive; @@ -141,7 +141,8 @@ class JFJochStateMachine { bool IsRunning() const; // Is state Busy/Pedestal/Measure void ResetError() noexcept; void TakeDarkMaskInternal(std::unique_lock &ul); - void TakePedestalInternalAll(std::unique_lock &ul); + void CalibrateDetector(std::unique_lock &ul); + void CalibrateJUNGFRAU(std::unique_lock &ul); void TakePedestalInternalG0(std::unique_lock &ul); void TakePedestalInternalG1(std::unique_lock &ul, int32_t storage_cell = 0); void TakePedestalInternalG2(std::unique_lock &ul, int32_t storage_cell = 0); diff --git a/broker/OpenAPIConvert.cpp b/broker/OpenAPIConvert.cpp index c5dd5c21..10a480c9 100644 --- a/broker/OpenAPIConvert.cpp +++ b/broker/OpenAPIConvert.cpp @@ -215,7 +215,7 @@ org::openapitools::server::model::Broker_status Convert(const BrokerStatus& inpu case JFJochState::Busy: ret.setState("Busy"); break; - case JFJochState::Pedestal: + case JFJochState::Calibration: ret.setState("Pedestal"); break; } diff --git a/tests/JFJochStateMachineTest.cpp b/tests/JFJochStateMachineTest.cpp index 78ab097b..1aba3055 100644 --- a/tests/JFJochStateMachineTest.cpp +++ b/tests/JFJochStateMachineTest.cpp @@ -37,14 +37,14 @@ TEST_CASE("JFJochStateMachine_State_Pedestal") { DatasetSettings setup; - state_machine.DebugOnly_SetState(JFJochState::Pedestal); + state_machine.DebugOnly_SetState(JFJochState::Calibration); - REQUIRE(state_machine.GetStatus().state == JFJochState::Pedestal); + REQUIRE(state_machine.GetStatus().state == JFJochState::Calibration); REQUIRE_THROWS(state_machine.Start(setup)); REQUIRE_THROWS(state_machine.Pedestal()); REQUIRE_THROWS(state_machine.Initialize()); - REQUIRE(state_machine.WaitTillMeasurementDone(std::chrono::milliseconds(1)).state == JFJochState::Pedestal); + REQUIRE(state_machine.WaitTillMeasurementDone(std::chrono::milliseconds(1)).state == JFJochState::Calibration); } TEST_CASE("JFJochStateMachine_State_Measure") { -- 2.49.1 From 543e319d52f8344192ed7f58f093c27535adbfa8 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Wed, 5 Nov 2025 10:14:52 +0100 Subject: [PATCH 15/69] DiffractionExperiment: Dark mask settings are separate from detector settings (not sure still what is the best solution...) --- common/DetectorSettings.cpp | 10 ---------- common/DetectorSettings.h | 5 ----- common/DiffractionExperiment.cpp | 7 ++++++- common/DiffractionExperiment.h | 6 +++++- tests/DiffractionExperimentTest.cpp | 5 +++-- tests/JFJochReceiverLiteTest.cpp | 6 +++--- 6 files changed, 17 insertions(+), 22 deletions(-) diff --git a/common/DetectorSettings.cpp b/common/DetectorSettings.cpp index df4f7cdc..a0a7e536 100644 --- a/common/DetectorSettings.cpp +++ b/common/DetectorSettings.cpp @@ -219,13 +219,3 @@ bool DetectorSettings::NeedsJUNGFRAURecalibration(const DetectorSettings &other) || this->storage_cell_delay != other.storage_cell_delay || this->internal_fpga_packet_generator != other.internal_fpga_packet_generator; } - -DarkMaskSettings DetectorSettings::GetDarkMaskSettings() const { - return dark_mask_settings; -} - -DetectorSettings &DetectorSettings::Import(const DarkMaskSettings &settings) { - dark_mask_settings = settings; - return *this; -} - diff --git a/common/DetectorSettings.h b/common/DetectorSettings.h index f16c9605..e6770e35 100644 --- a/common/DetectorSettings.h +++ b/common/DetectorSettings.h @@ -36,8 +36,6 @@ class DetectorSettings { std::optional eiger_bitwidth; DetectorTiming timing = DetectorTiming::Trigger; - - DarkMaskSettings dark_mask_settings; public: DetectorSettings& InternalGeneratorEnable(bool input); DetectorSettings& InternalGeneratorImages(int64_t input); @@ -80,9 +78,6 @@ public: [[nodiscard]] DetectorTiming GetTiming() const; [[nodiscard]] bool NeedsJUNGFRAURecalibration(const DetectorSettings& other) const; - - DetectorSettings& Import(const DarkMaskSettings& settings); - [[nodiscard]] DarkMaskSettings GetDarkMaskSettings() const; }; diff --git a/common/DiffractionExperiment.cpp b/common/DiffractionExperiment.cpp index 44811081..b1d00635 100644 --- a/common/DiffractionExperiment.cpp +++ b/common/DiffractionExperiment.cpp @@ -1628,7 +1628,12 @@ const XrayFluorescenceSpectrum &DiffractionExperiment::GetFluorescenceSpectrum() } DarkMaskSettings DiffractionExperiment::GetDarkMaskSettings() const { - return detector_settings.GetDarkMaskSettings(); + return dark_mask_settings; +} + +DiffractionExperiment &DiffractionExperiment::ImportDarkMaskSettings(const DarkMaskSettings &input) { + dark_mask_settings = input; + return *this; } int64_t DiffractionExperiment::GetDarkMaskNumberOfFrames() const { diff --git a/common/DiffractionExperiment.h b/common/DiffractionExperiment.h index 6e1a0d7f..ab35096f 100644 --- a/common/DiffractionExperiment.h +++ b/common/DiffractionExperiment.h @@ -74,6 +74,8 @@ class DiffractionExperiment { IndexingSettings indexing; BraggIntegrationSettings bragg_integration_settings; + DarkMaskSettings dark_mask_settings; + ROIMap roi_mask; int64_t summation; bool cpu_summation; @@ -176,6 +178,9 @@ public: DiffractionExperiment& ImportFileWriterSettings(const FileWriterSettings& input); FileWriterSettings GetFileWriterSettings() const; + DiffractionExperiment &ImportDarkMaskSettings(const DarkMaskSettings &input); + DarkMaskSettings GetDarkMaskSettings() const; + DatasetSettings GetDatasetSettings() const; void FillMessage(StartMessage &message) const; @@ -398,7 +403,6 @@ public: const XrayFluorescenceSpectrum &GetFluorescenceSpectrum() const; bool IsDetectIceRings() const; - DarkMaskSettings GetDarkMaskSettings() const; int64_t GetDarkMaskNumberOfFrames() const; }; diff --git a/tests/DiffractionExperimentTest.cpp b/tests/DiffractionExperimentTest.cpp index acd2250b..697f9192 100644 --- a/tests/DiffractionExperimentTest.cpp +++ b/tests/DiffractionExperimentTest.cpp @@ -885,10 +885,11 @@ TEST_CASE("DiffractionExperiment_DarkMask","[DiffractionExperiment]") { x.Detector(DetDECTRIS(1024,1024, "Det1", "")); x.FrameTime(std::chrono::milliseconds(100)).ImagesPerTrigger(100).NumTriggers(3); - + x.IncidentEnergy_keV(10.0); + DarkMaskSettings dark_mask_settings; dark_mask_settings.FrameTime(std::chrono::milliseconds(20)).NumberOfFrames(456).Threshold_keV(3.4); - x.ImportDetectorSettings(x.GetDetectorSettings().Import(dark_mask_settings).EigerThreshold_keV(5.0)); + x.ImportDarkMaskSettings(dark_mask_settings); CHECK(x.GetNumTriggers() == 3); CHECK(x.GetImageNum() == 3 * 100); diff --git a/tests/JFJochReceiverLiteTest.cpp b/tests/JFJochReceiverLiteTest.cpp index c306efcc..3a9f119c 100644 --- a/tests/JFJochReceiverLiteTest.cpp +++ b/tests/JFJochReceiverLiteTest.cpp @@ -146,9 +146,9 @@ TEST_CASE("JFJochReceiverLite_DarkMask", "[JFJochReceiver]") { DiffractionExperiment experiment(DetDECTRIS(2068, 2164, "Test", {})); - auto det_settings = experiment.GetDetectorSettings(); - det_settings.Import(DarkMaskSettings{}.NumberOfFrames(10).MaxCounts(1).MaxFramesWithCounts(5)).FrameTime(std::chrono::milliseconds(5)); - experiment.Mode(DetectorMode::DarkMask).ImportDetectorSettings(det_settings); + DarkMaskSettings mask_settings; + mask_settings.NumberOfFrames(10).MaxCounts(1).MaxFramesWithCounts(5); + experiment.Mode(DetectorMode::DarkMask).ImportDarkMaskSettings(mask_settings); PixelMask pixel_mask(experiment); -- 2.49.1 From 213cac77652300238490714963503209bfc55c07 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Wed, 5 Nov 2025 10:44:25 +0100 Subject: [PATCH 16/69] OpenAPI: Dark mask settings can be configured through the API --- broker/JFJochBrokerHttp.cpp | 10 + broker/JFJochBrokerHttp.h | 4 + broker/JFJochBrokerParser.cpp | 3 + broker/JFJochStateMachine.cpp | 23 +- broker/JFJochStateMachine.h | 5 + broker/OpenAPIConvert.cpp | 22 +- broker/OpenAPIConvert.h | 3 + broker/gen/api/DefaultApi.cpp | 52 ++++ broker/gen/api/DefaultApi.h | 18 ++ broker/gen/model/Dark_mask_settings.cpp | 227 ++++++++++++++++++ broker/gen/model/Dark_mask_settings.h | 104 ++++++++ broker/gen/model/Jfjoch_settings.cpp | 32 ++- broker/gen/model/Jfjoch_settings.h | 10 + broker/gen/model/Jfjoch_statistics.cpp | 30 ++- broker/gen/model/Jfjoch_statistics.h | 10 + broker/jfjoch_api.yaml | 83 +++++++ broker/redoc-static.html | 70 ++++-- common/DarkMaskSettings.cpp | 4 +- docs/python_client/README.md | 3 + docs/python_client/docs/DarkMaskSettings.md | 34 +++ docs/python_client/docs/DefaultApi.md | 132 ++++++++++ docs/python_client/docs/JfjochSettings.md | 1 + docs/python_client/docs/JfjochStatistics.md | 1 + etc/broker_local.json | 7 + frontend/package-lock.json | 4 +- frontend/src/openapi/index.ts | 1 + .../src/openapi/models/dark_mask_settings.ts | 31 +++ .../src/openapi/models/jfjoch_settings.ts | 2 + .../src/openapi/models/jfjoch_statistics.ts | 2 + .../src/openapi/services/DefaultService.ts | 37 +++ 30 files changed, 934 insertions(+), 31 deletions(-) create mode 100644 broker/gen/model/Dark_mask_settings.cpp create mode 100644 broker/gen/model/Dark_mask_settings.h create mode 100644 docs/python_client/docs/DarkMaskSettings.md create mode 100644 frontend/src/openapi/models/dark_mask_settings.ts diff --git a/broker/JFJochBrokerHttp.cpp b/broker/JFJochBrokerHttp.cpp index a6fc3ec8..a444f354 100644 --- a/broker/JFJochBrokerHttp.cpp +++ b/broker/JFJochBrokerHttp.cpp @@ -412,6 +412,7 @@ void JFJochBrokerHttp::statistics_get(const std::optional &compression, Pi statistics.setAzInt(Convert(state_machine.GetRadialIntegrationSettings())); statistics.setBuffer(Convert(state_machine.GetImageBufferStatus())); statistics.setIndexing(Convert(state_machine.GetIndexingSettings())); + statistics.setDarkMask(Convert(state_machine.GetDarkMaskSettings())); auto zeromq_prev = state_machine.GetPreviewSocketSettings(); if (!zeromq_prev.address.empty()) @@ -586,3 +587,12 @@ void JFJochBrokerHttp::result_scan_get(Pistache::Http::ResponseWriter &response) else response.send(Pistache::Http::Code::Not_Found); } + +void JFJochBrokerHttp::config_dark_mask_put(const org::openapitools::server::model::Dark_mask_settings &darkMaskSettings, Pistache::Http::ResponseWriter &response) { + state_machine.SetDarkMaskSettings(Convert(darkMaskSettings)); + response.send(Pistache::Http::Code::Ok); +} + +void JFJochBrokerHttp::config_dark_mask_get(Pistache::Http::ResponseWriter &response) { + ProcessOutput(Convert(state_machine.GetDarkMaskSettings()), response); +} diff --git a/broker/JFJochBrokerHttp.h b/broker/JFJochBrokerHttp.h index 74e5b776..30d710a1 100644 --- a/broker/JFJochBrokerHttp.h +++ b/broker/JFJochBrokerHttp.h @@ -174,6 +174,10 @@ class JFJochBrokerHttp : public org::openapitools::server::api::DefaultApi { Pistache::Http::ResponseWriter &response) override; void result_scan_get(Pistache::Http::ResponseWriter &response) override; + + void config_dark_mask_get(Pistache::Http::ResponseWriter &response) override; + void config_dark_mask_put(const org::openapitools::server::model::Dark_mask_settings &darkMaskSettings, + Pistache::Http::ResponseWriter &response) override; public: JFJochBrokerHttp(const DiffractionExperiment& experiment, std::shared_ptr &rtr); void AddDetectorSetup(const DetectorSetup &setup); diff --git a/broker/JFJochBrokerParser.cpp b/broker/JFJochBrokerParser.cpp index af07c3b9..f6331d53 100644 --- a/broker/JFJochBrokerParser.cpp +++ b/broker/JFJochBrokerParser.cpp @@ -166,6 +166,9 @@ void ParseFacilityConfiguration(const org::openapitools::server::model::Jfjoch_s if (j.indexingIsSet()) experiment.ImportIndexingSettings(Convert(j.getIndexing())); + + if (j.darkMaskIsSet()) + experiment.ImportDarkMaskSettings(Convert(j.getDarkMask())); } std::unique_ptr ParseZMQImagePusher(const org::openapitools::server::model::Jfjoch_settings &j) { diff --git a/broker/JFJochStateMachine.cpp b/broker/JFJochStateMachine.cpp index 8d55755f..811c1def 100644 --- a/broker/JFJochStateMachine.cpp +++ b/broker/JFJochStateMachine.cpp @@ -1012,4 +1012,25 @@ std::optional JFJochStateMachine::GetScanResult() const { throw WrongDAQStateException("Cannot check scan result, when running"); return scan_result; -} \ No newline at end of file +} + +DarkMaskSettings JFJochStateMachine::GetDarkMaskSettings() const { + std::unique_lock ul(experiment_dark_mask_settings_mutex); + return experiment.GetDarkMaskSettings(); +} + +void JFJochStateMachine::SetDarkMaskSettings(const DarkMaskSettings &settings) { + std::unique_lock ul(m); + if (IsRunning()) + throw WrongDAQStateException("Cannot change dark mask calculation settings during data collection"); + { + // Setting dark mask settings in experiment requires BOTH mutexes + std::unique_lock ul2(experiment_dark_mask_settings_mutex); + experiment.ImportDarkMaskSettings(settings); + } + if ((experiment.GetDetectorType() == DetectorType::DECTRIS) && (state == JFJochState::Idle)) { + // Need to redo the calibration + SetState(JFJochState::Busy, "Loading settings", BrokerStatus::MessageSeverity::Info); + measurement = std::async(std::launch::async, &JFJochStateMachine::PedestalThread, this, std::move(ul)); + } +} diff --git a/broker/JFJochStateMachine.h b/broker/JFJochStateMachine.h index 1bc0eb8e..d52c98d1 100644 --- a/broker/JFJochStateMachine.h +++ b/broker/JFJochStateMachine.h @@ -95,6 +95,7 @@ class JFJochStateMachine { mutable std::mutex experiment_image_format_settings_mutex; mutable std::mutex experiment_file_writer_settings_mutex; mutable std::mutex experiment_indexing_settings_mutex; + mutable std::mutex experiment_dark_mask_settings_mutex; DiffractionExperiment experiment; // mutex m is protecting: @@ -147,6 +148,7 @@ class JFJochStateMachine { void TakePedestalInternalG1(std::unique_lock &ul, int32_t storage_cell = 0); void TakePedestalInternalG2(std::unique_lock &ul, int32_t storage_cell = 0); bool ImportDetectorSettings(const DetectorSettings& input); + void UpdateROIDefinition(); public: JFJochStateMachine(const DiffractionExperiment& experiment, @@ -244,6 +246,9 @@ public: void AddDetectorSetup(const DetectorSetup& setup); // Not thread safe, only during setup std::optional GetScanResult() const; + + void SetDarkMaskSettings(const DarkMaskSettings& settings); + DarkMaskSettings GetDarkMaskSettings() const; }; diff --git a/broker/OpenAPIConvert.cpp b/broker/OpenAPIConvert.cpp index 10a480c9..52278dc6 100644 --- a/broker/OpenAPIConvert.cpp +++ b/broker/OpenAPIConvert.cpp @@ -1020,4 +1020,24 @@ org::openapitools::server::model::Scan_result Convert(const ScanResult& input) { } ret.setImages(v); return ret; -} \ No newline at end of file +} + +org::openapitools::server::model::Dark_mask_settings Convert(const DarkMaskSettings &input) { + org::openapitools::server::model::Dark_mask_settings ret{}; + ret.setDetectorThresholdKeV(input.GetThreshold_keV()); + ret.setFrameTimeUs(input.GetFrameTime().count()); + ret.setMaxFramesWithSignal(input.GetMaxFramesWithCounts()); + ret.setMaxAllowedPixelCount(input.GetMaxCounts()); + ret.setNumberOfFrames(input.GetNumberOfFrames()); + return ret; +} + +DarkMaskSettings Convert(const org::openapitools::server::model::Dark_mask_settings &input) { + DarkMaskSettings ret{}; + ret.FrameTime(std::chrono::microseconds(input.getFrameTimeUs())) + .NumberOfFrames(input.getNumberOfFrames()) + .MaxCounts(input.getMaxAllowedPixelCount()) + .MaxFramesWithCounts(input.getMaxFramesWithSignal()) + .Threshold_keV(input.getDetectorThresholdKeV()); + return ret; +} diff --git a/broker/OpenAPIConvert.h b/broker/OpenAPIConvert.h index f226cda8..e381de73 100644 --- a/broker/OpenAPIConvert.h +++ b/broker/OpenAPIConvert.h @@ -4,6 +4,7 @@ #ifndef JFJOCH_OPENAPICONVERT_H #define JFJOCH_OPENAPICONVERT_H +#include "Dark_mask_settings.h" #include "gen/model/Spot_finding_settings.h" #include "gen/model/Measurement_statistics.h" #include "gen/model/Detector_settings.h" @@ -88,4 +89,6 @@ ColorScaleEnum ConvertColorScale(const std::optional& input); org::openapitools::server::model::Scan_result Convert(const ScanResult& input); +org::openapitools::server::model::Dark_mask_settings Convert(const DarkMaskSettings& input); +DarkMaskSettings Convert(const org::openapitools::server::model::Dark_mask_settings& input); #endif //JFJOCH_OPENAPICONVERT_H diff --git a/broker/gen/api/DefaultApi.cpp b/broker/gen/api/DefaultApi.cpp index beb1cf10..e1b8890e 100644 --- a/broker/gen/api/DefaultApi.cpp +++ b/broker/gen/api/DefaultApi.cpp @@ -36,6 +36,8 @@ void DefaultApi::setupRoutes() { Routes::Post(*router, base + "/cancel", Routes::bind(&DefaultApi::cancel_post_handler, this)); Routes::Get(*router, base + "/config/azim_int", Routes::bind(&DefaultApi::config_azim_int_get_handler, this)); Routes::Put(*router, base + "/config/azim_int", Routes::bind(&DefaultApi::config_azim_int_put_handler, this)); + Routes::Get(*router, base + "/config/dark_mask", Routes::bind(&DefaultApi::config_dark_mask_get_handler, this)); + Routes::Put(*router, base + "/config/dark_mask", Routes::bind(&DefaultApi::config_dark_mask_put_handler, this)); Routes::Get(*router, base + "/config/detector", Routes::bind(&DefaultApi::config_detector_get_handler, this)); Routes::Put(*router, base + "/config/detector", Routes::bind(&DefaultApi::config_detector_put_handler, this)); Routes::Get(*router, base + "/config/file_writer", Routes::bind(&DefaultApi::config_file_writer_get_handler, this)); @@ -193,6 +195,56 @@ void DefaultApi::config_azim_int_put_handler(const Pistache::Rest::Request &requ response.send(Pistache::Http::Code::Internal_Server_Error, e.what()); } +} +void DefaultApi::config_dark_mask_get_handler(const Pistache::Rest::Request &, Pistache::Http::ResponseWriter response) { + try { + + + try { + this->config_dark_mask_get(response); + } catch (Pistache::Http::HttpError &e) { + response.send(static_cast(e.code()), e.what()); + return; + } catch (std::exception &e) { + this->handleOperationException(e, response); + return; + } + + } catch (std::exception &e) { + response.send(Pistache::Http::Code::Internal_Server_Error, e.what()); + } + +} +void DefaultApi::config_dark_mask_put_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response) { + try { + + + // Getting the body param + + Dark_mask_settings darkMaskSettings; + + try { + nlohmann::json::parse(request.body()).get_to(darkMaskSettings); + darkMaskSettings.validate(); + } catch (std::exception &e) { + this->handleParsingException(e, response); + return; + } + + try { + this->config_dark_mask_put(darkMaskSettings, response); + } catch (Pistache::Http::HttpError &e) { + response.send(static_cast(e.code()), e.what()); + return; + } catch (std::exception &e) { + this->handleOperationException(e, response); + return; + } + + } catch (std::exception &e) { + response.send(Pistache::Http::Code::Internal_Server_Error, e.what()); + } + } void DefaultApi::config_detector_get_handler(const Pistache::Rest::Request &, Pistache::Http::ResponseWriter response) { try { diff --git a/broker/gen/api/DefaultApi.h b/broker/gen/api/DefaultApi.h index c29dc59b..26ba29ea 100644 --- a/broker/gen/api/DefaultApi.h +++ b/broker/gen/api/DefaultApi.h @@ -31,6 +31,7 @@ #include "Azim_int_settings.h" #include "Broker_status.h" #include "Calibration_statistics_inner.h" +#include "Dark_mask_settings.h" #include "Dataset_settings.h" #include "Detector_list.h" #include "Detector_selection.h" @@ -71,6 +72,8 @@ private: void cancel_post_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response); void config_azim_int_get_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response); void config_azim_int_put_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response); + void config_dark_mask_get_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response); + void config_dark_mask_put_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response); void config_detector_get_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response); void config_detector_put_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response); void config_file_writer_get_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response); @@ -178,6 +181,21 @@ private: /// (optional) virtual void config_azim_int_put(const org::openapitools::server::model::Azim_int_settings &azimIntSettings, Pistache::Http::ResponseWriter &response) = 0; /// + /// Get settings for dark data collection to calculate mask + /// + /// + /// + /// + virtual void config_dark_mask_get(Pistache::Http::ResponseWriter &response) = 0; + /// + /// Set configuration for dark data collection to calculate mask + /// + /// + /// This is only possible when operating DECTRIS detectors at the moment; it will be also available for PSI EIGER at some point. This can only be done when detector is `Idle`, `Error` or `Inactive` states. + /// + /// (optional) + virtual void config_dark_mask_put(const org::openapitools::server::model::Dark_mask_settings &darkMaskSettings, Pistache::Http::ResponseWriter &response) = 0; + /// /// Get detector configuration /// /// diff --git a/broker/gen/model/Dark_mask_settings.cpp b/broker/gen/model/Dark_mask_settings.cpp new file mode 100644 index 00000000..5ab9f103 --- /dev/null +++ b/broker/gen/model/Dark_mask_settings.cpp @@ -0,0 +1,227 @@ +/** +* Jungfraujoch +* API to control Jungfraujoch developed by the Paul Scherrer Institute (Switzerland). Jungfraujoch is a data acquisition and analysis system for pixel array detectors, primarly PSI JUNGFRAU. Jungfraujoch uses FPGA boards to acquire data at high data rates. # License Clarification While this API definition is licensed under GPL-3.0, **the GPL copyleft provisions do not apply** when this file is used solely to generate OpenAPI clients or when implementing applications that interact with the API. Generated client code and applications using this API definition are not subject to the GPL license requirements and may be distributed under terms of your choosing. This exception is similar in spirit to the Linux Kernel's approach to userspace API headers and the GCC Runtime Library Exception. The Linux Kernel developers have explicitly stated that user programs that merely use the kernel interfaces (syscalls, ioctl definitions, etc.) are not derivative works of the kernel and are not subject to the terms of the GPL. This exception is intended to allow wider use of this API specification without imposing GPL requirements on applications that merely interact with the API, regardless of whether they communicate through network calls or other mechanisms. +* +* The version of the OpenAPI document: 1.0.0-rc.96 +* Contact: filip.leonarski@psi.ch +* +* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + + +#include "Dark_mask_settings.h" +#include "Helpers.h" + +#include + +namespace org::openapitools::server::model +{ + +Dark_mask_settings::Dark_mask_settings() +{ + m_Detector_threshold_keV = 3.5f; + m_Frame_time_us = 10000L; + m_Number_of_frames = 1000L; + m_Max_allowed_pixel_count = 1L; + m_Max_frames_with_signal = 10L; + +} + +void Dark_mask_settings::validate() const +{ + std::stringstream msg; + if (!validate(msg)) + { + throw org::openapitools::server::helpers::ValidationException(msg.str()); + } +} + +bool Dark_mask_settings::validate(std::stringstream& msg) const +{ + return validate(msg, ""); +} + +bool Dark_mask_settings::validate(std::stringstream& msg, const std::string& pathPrefix) const +{ + bool success = true; + const std::string _pathPrefix = pathPrefix.empty() ? "Dark_mask_settings" : pathPrefix; + + + + /* Detector_threshold_keV */ { + const float& value = m_Detector_threshold_keV; + const std::string currentValuePath = _pathPrefix + ".detectorThresholdKeV"; + + + if (value < static_cast(2.5)) + { + success = false; + msg << currentValuePath << ": must be greater than or equal to 2.5;"; + } + if (value > static_cast(100.0)) + { + success = false; + msg << currentValuePath << ": must be less than or equal to 100.0;"; + } + + } + + + /* Frame_time_us */ { + const int64_t& value = m_Frame_time_us; + const std::string currentValuePath = _pathPrefix + ".frameTimeUs"; + + + if (value < 500ll) + { + success = false; + msg << currentValuePath << ": must be greater than or equal to 500;"; + } + if (value > 100000ll) + { + success = false; + msg << currentValuePath << ": must be less than or equal to 100000;"; + } + + } + + + /* Number_of_frames */ { + const int64_t& value = m_Number_of_frames; + const std::string currentValuePath = _pathPrefix + ".numberOfFrames"; + + + if (value < 0ll) + { + success = false; + msg << currentValuePath << ": must be greater than or equal to 0;"; + } + + } + + + /* Max_allowed_pixel_count */ { + const int64_t& value = m_Max_allowed_pixel_count; + const std::string currentValuePath = _pathPrefix + ".maxAllowedPixelCount"; + + + if (value < 0ll) + { + success = false; + msg << currentValuePath << ": must be greater than or equal to 0;"; + } + + } + + + /* Max_frames_with_signal */ { + const int64_t& value = m_Max_frames_with_signal; + const std::string currentValuePath = _pathPrefix + ".maxFramesWithSignal"; + + + if (value < 0ll) + { + success = false; + msg << currentValuePath << ": must be greater than or equal to 0;"; + } + + } + + return success; +} + +bool Dark_mask_settings::operator==(const Dark_mask_settings& rhs) const +{ + return + + + (getDetectorThresholdKeV() == rhs.getDetectorThresholdKeV()) + && + + (getFrameTimeUs() == rhs.getFrameTimeUs()) + && + + (getNumberOfFrames() == rhs.getNumberOfFrames()) + && + + (getMaxAllowedPixelCount() == rhs.getMaxAllowedPixelCount()) + && + + (getMaxFramesWithSignal() == rhs.getMaxFramesWithSignal()) + + + ; +} + +bool Dark_mask_settings::operator!=(const Dark_mask_settings& rhs) const +{ + return !(*this == rhs); +} + +void to_json(nlohmann::json& j, const Dark_mask_settings& o) +{ + j = nlohmann::json::object(); + j["detector_threshold_keV"] = o.m_Detector_threshold_keV; + j["frame_time_us"] = o.m_Frame_time_us; + j["number_of_frames"] = o.m_Number_of_frames; + j["max_allowed_pixel_count"] = o.m_Max_allowed_pixel_count; + j["max_frames_with_signal"] = o.m_Max_frames_with_signal; + +} + +void from_json(const nlohmann::json& j, Dark_mask_settings& o) +{ + j.at("detector_threshold_keV").get_to(o.m_Detector_threshold_keV); + j.at("frame_time_us").get_to(o.m_Frame_time_us); + j.at("number_of_frames").get_to(o.m_Number_of_frames); + j.at("max_allowed_pixel_count").get_to(o.m_Max_allowed_pixel_count); + j.at("max_frames_with_signal").get_to(o.m_Max_frames_with_signal); + +} + +float Dark_mask_settings::getDetectorThresholdKeV() const +{ + return m_Detector_threshold_keV; +} +void Dark_mask_settings::setDetectorThresholdKeV(float const value) +{ + m_Detector_threshold_keV = value; +} +int64_t Dark_mask_settings::getFrameTimeUs() const +{ + return m_Frame_time_us; +} +void Dark_mask_settings::setFrameTimeUs(int64_t const value) +{ + m_Frame_time_us = value; +} +int64_t Dark_mask_settings::getNumberOfFrames() const +{ + return m_Number_of_frames; +} +void Dark_mask_settings::setNumberOfFrames(int64_t const value) +{ + m_Number_of_frames = value; +} +int64_t Dark_mask_settings::getMaxAllowedPixelCount() const +{ + return m_Max_allowed_pixel_count; +} +void Dark_mask_settings::setMaxAllowedPixelCount(int64_t const value) +{ + m_Max_allowed_pixel_count = value; +} +int64_t Dark_mask_settings::getMaxFramesWithSignal() const +{ + return m_Max_frames_with_signal; +} +void Dark_mask_settings::setMaxFramesWithSignal(int64_t const value) +{ + m_Max_frames_with_signal = value; +} + + +} // namespace org::openapitools::server::model + diff --git a/broker/gen/model/Dark_mask_settings.h b/broker/gen/model/Dark_mask_settings.h new file mode 100644 index 00000000..67299b79 --- /dev/null +++ b/broker/gen/model/Dark_mask_settings.h @@ -0,0 +1,104 @@ +/** +* Jungfraujoch +* API to control Jungfraujoch developed by the Paul Scherrer Institute (Switzerland). Jungfraujoch is a data acquisition and analysis system for pixel array detectors, primarly PSI JUNGFRAU. Jungfraujoch uses FPGA boards to acquire data at high data rates. # License Clarification While this API definition is licensed under GPL-3.0, **the GPL copyleft provisions do not apply** when this file is used solely to generate OpenAPI clients or when implementing applications that interact with the API. Generated client code and applications using this API definition are not subject to the GPL license requirements and may be distributed under terms of your choosing. This exception is similar in spirit to the Linux Kernel's approach to userspace API headers and the GCC Runtime Library Exception. The Linux Kernel developers have explicitly stated that user programs that merely use the kernel interfaces (syscalls, ioctl definitions, etc.) are not derivative works of the kernel and are not subject to the terms of the GPL. This exception is intended to allow wider use of this API specification without imposing GPL requirements on applications that merely interact with the API, regardless of whether they communicate through network calls or other mechanisms. +* +* The version of the OpenAPI document: 1.0.0-rc.96 +* Contact: filip.leonarski@psi.ch +* +* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ +/* + * Dark_mask_settings.h + * + * Settings for collection of dark images to be used for mask calculation + */ + +#ifndef Dark_mask_settings_H_ +#define Dark_mask_settings_H_ + + +#include + +namespace org::openapitools::server::model +{ + +/// +/// Settings for collection of dark images to be used for mask calculation +/// +class Dark_mask_settings +{ +public: + Dark_mask_settings(); + virtual ~Dark_mask_settings() = default; + + + /// + /// Validate the current data in the model. Throws a ValidationException on failure. + /// + void validate() const; + + /// + /// Validate the current data in the model. Returns false on error and writes an error + /// message into the given stringstream. + /// + bool validate(std::stringstream& msg) const; + + /// + /// Helper overload for validate. Used when one model stores another model and calls it's validate. + /// Not meant to be called outside that case. + /// + bool validate(std::stringstream& msg, const std::string& pathPrefix) const; + + bool operator==(const Dark_mask_settings& rhs) const; + bool operator!=(const Dark_mask_settings& rhs) const; + + ///////////////////////////////////////////// + /// Dark_mask_settings members + + /// + /// Energy threshold for dark image collection + /// + float getDetectorThresholdKeV() const; + void setDetectorThresholdKeV(float const value); + /// + /// Time between frames for dark image collection + /// + int64_t getFrameTimeUs() const; + void setFrameTimeUs(int64_t const value); + /// + /// Number of frames for dark image collection; zero means no dark collection + /// + int64_t getNumberOfFrames() const; + void setNumberOfFrames(int64_t const value); + /// + /// Maximum count in a pixel considered normal (not-masked) + /// + int64_t getMaxAllowedPixelCount() const; + void setMaxAllowedPixelCount(int64_t const value); + /// + /// Maximum number of frames with signal in a pixel considered normal (not-masked) + /// + int64_t getMaxFramesWithSignal() const; + void setMaxFramesWithSignal(int64_t const value); + + friend void to_json(nlohmann::json& j, const Dark_mask_settings& o); + friend void from_json(const nlohmann::json& j, Dark_mask_settings& o); +protected: + float m_Detector_threshold_keV; + + int64_t m_Frame_time_us; + + int64_t m_Number_of_frames; + + int64_t m_Max_allowed_pixel_count; + + int64_t m_Max_frames_with_signal; + + +}; + +} // namespace org::openapitools::server::model + +#endif /* Dark_mask_settings_H_ */ diff --git a/broker/gen/model/Jfjoch_settings.cpp b/broker/gen/model/Jfjoch_settings.cpp index 920d3dec..29370407 100644 --- a/broker/gen/model/Jfjoch_settings.cpp +++ b/broker/gen/model/Jfjoch_settings.cpp @@ -41,6 +41,7 @@ Jfjoch_settings::Jfjoch_settings() m_SslIsSet = false; m_Zeromq_previewIsSet = false; m_Zeromq_metadataIsSet = false; + m_Dark_maskIsSet = false; } @@ -138,7 +139,7 @@ bool Jfjoch_settings::validate(std::stringstream& msg, const std::string& pathPr } } - + return success; } @@ -199,7 +200,10 @@ bool Jfjoch_settings::operator==(const Jfjoch_settings& rhs) const ((!zeromqPreviewIsSet() && !rhs.zeromqPreviewIsSet()) || (zeromqPreviewIsSet() && rhs.zeromqPreviewIsSet() && getZeromqPreview() == rhs.getZeromqPreview())) && - ((!zeromqMetadataIsSet() && !rhs.zeromqMetadataIsSet()) || (zeromqMetadataIsSet() && rhs.zeromqMetadataIsSet() && getZeromqMetadata() == rhs.getZeromqMetadata())) + ((!zeromqMetadataIsSet() && !rhs.zeromqMetadataIsSet()) || (zeromqMetadataIsSet() && rhs.zeromqMetadataIsSet() && getZeromqMetadata() == rhs.getZeromqMetadata())) && + + + ((!darkMaskIsSet() && !rhs.darkMaskIsSet()) || (darkMaskIsSet() && rhs.darkMaskIsSet() && getDarkMask() == rhs.getDarkMask())) ; } @@ -245,6 +249,8 @@ void to_json(nlohmann::json& j, const Jfjoch_settings& o) j["zeromq_preview"] = o.m_Zeromq_preview; if(o.zeromqMetadataIsSet()) j["zeromq_metadata"] = o.m_Zeromq_metadata; + if(o.darkMaskIsSet()) + j["dark_mask"] = o.m_Dark_mask; } @@ -328,6 +334,11 @@ void from_json(const nlohmann::json& j, Jfjoch_settings& o) j.at("zeromq_metadata").get_to(o.m_Zeromq_metadata); o.m_Zeromq_metadataIsSet = true; } + if(j.find("dark_mask") != j.end()) + { + j.at("dark_mask").get_to(o.m_Dark_mask); + o.m_Dark_maskIsSet = true; + } } @@ -610,6 +621,23 @@ void Jfjoch_settings::unsetZeromq_metadata() { m_Zeromq_metadataIsSet = false; } +org::openapitools::server::model::Dark_mask_settings Jfjoch_settings::getDarkMask() const +{ + return m_Dark_mask; +} +void Jfjoch_settings::setDarkMask(org::openapitools::server::model::Dark_mask_settings const& value) +{ + m_Dark_mask = value; + m_Dark_maskIsSet = true; +} +bool Jfjoch_settings::darkMaskIsSet() const +{ + return m_Dark_maskIsSet; +} +void Jfjoch_settings::unsetDark_mask() +{ + m_Dark_maskIsSet = false; +} } // namespace org::openapitools::server::model diff --git a/broker/gen/model/Jfjoch_settings.h b/broker/gen/model/Jfjoch_settings.h index f53bdc60..5a4543b1 100644 --- a/broker/gen/model/Jfjoch_settings.h +++ b/broker/gen/model/Jfjoch_settings.h @@ -20,6 +20,7 @@ #include "Zeromq_preview_settings.h" +#include "Dark_mask_settings.h" #include "Pcie_devices_inner.h" #include #include "File_writer_settings.h" @@ -192,6 +193,13 @@ public: void setZeromqMetadata(org::openapitools::server::model::Zeromq_metadata_settings const& value); bool zeromqMetadataIsSet() const; void unsetZeromq_metadata(); + /// + /// + /// + org::openapitools::server::model::Dark_mask_settings getDarkMask() const; + void setDarkMask(org::openapitools::server::model::Dark_mask_settings const& value); + bool darkMaskIsSet() const; + void unsetDark_mask(); friend void to_json(nlohmann::json& j, const Jfjoch_settings& o); friend void from_json(const nlohmann::json& j, Jfjoch_settings& o); @@ -232,6 +240,8 @@ protected: bool m_Zeromq_previewIsSet; org::openapitools::server::model::Zeromq_metadata_settings m_Zeromq_metadata; bool m_Zeromq_metadataIsSet; + org::openapitools::server::model::Dark_mask_settings m_Dark_mask; + bool m_Dark_maskIsSet; }; diff --git a/broker/gen/model/Jfjoch_statistics.cpp b/broker/gen/model/Jfjoch_statistics.cpp index 23381df8..5d8df648 100644 --- a/broker/gen/model/Jfjoch_statistics.cpp +++ b/broker/gen/model/Jfjoch_statistics.cpp @@ -34,6 +34,7 @@ Jfjoch_statistics::Jfjoch_statistics() m_CalibrationIsSet = false; m_Zeromq_previewIsSet = false; m_Zeromq_metadataIsSet = false; + m_Dark_maskIsSet = false; m_Pixel_maskIsSet = false; m_RoiIsSet = false; m_Az_intIsSet = false; @@ -103,7 +104,7 @@ bool Jfjoch_statistics::validate(std::stringstream& msg, const std::string& path } } - + return success; } @@ -152,6 +153,9 @@ bool Jfjoch_statistics::operator==(const Jfjoch_statistics& rhs) const ((!zeromqMetadataIsSet() && !rhs.zeromqMetadataIsSet()) || (zeromqMetadataIsSet() && rhs.zeromqMetadataIsSet() && getZeromqMetadata() == rhs.getZeromqMetadata())) && + ((!darkMaskIsSet() && !rhs.darkMaskIsSet()) || (darkMaskIsSet() && rhs.darkMaskIsSet() && getDarkMask() == rhs.getDarkMask())) && + + ((!pixelMaskIsSet() && !rhs.pixelMaskIsSet()) || (pixelMaskIsSet() && rhs.pixelMaskIsSet() && getPixelMask() == rhs.getPixelMask())) && @@ -203,6 +207,8 @@ void to_json(nlohmann::json& j, const Jfjoch_statistics& o) j["zeromq_preview"] = o.m_Zeromq_preview; if(o.zeromqMetadataIsSet()) j["zeromq_metadata"] = o.m_Zeromq_metadata; + if(o.darkMaskIsSet()) + j["dark_mask"] = o.m_Dark_mask; if(o.pixelMaskIsSet()) j["pixel_mask"] = o.m_Pixel_mask; if(o.roiIsSet()) @@ -283,6 +289,11 @@ void from_json(const nlohmann::json& j, Jfjoch_statistics& o) j.at("zeromq_metadata").get_to(o.m_Zeromq_metadata); o.m_Zeromq_metadataIsSet = true; } + if(j.find("dark_mask") != j.end()) + { + j.at("dark_mask").get_to(o.m_Dark_mask); + o.m_Dark_maskIsSet = true; + } if(j.find("pixel_mask") != j.end()) { j.at("pixel_mask").get_to(o.m_Pixel_mask); @@ -532,6 +543,23 @@ void Jfjoch_statistics::unsetZeromq_metadata() { m_Zeromq_metadataIsSet = false; } +org::openapitools::server::model::Dark_mask_settings Jfjoch_statistics::getDarkMask() const +{ + return m_Dark_mask; +} +void Jfjoch_statistics::setDarkMask(org::openapitools::server::model::Dark_mask_settings const& value) +{ + m_Dark_mask = value; + m_Dark_maskIsSet = true; +} +bool Jfjoch_statistics::darkMaskIsSet() const +{ + return m_Dark_maskIsSet; +} +void Jfjoch_statistics::unsetDark_mask() +{ + m_Dark_maskIsSet = false; +} org::openapitools::server::model::Pixel_mask_statistics Jfjoch_statistics::getPixelMask() const { return m_Pixel_mask; diff --git a/broker/gen/model/Jfjoch_statistics.h b/broker/gen/model/Jfjoch_statistics.h index bdf6b243..5d6a185d 100644 --- a/broker/gen/model/Jfjoch_statistics.h +++ b/broker/gen/model/Jfjoch_statistics.h @@ -26,6 +26,7 @@ #include "Spot_finding_settings.h" #include "Zeromq_preview_settings.h" #include "Detector_list.h" +#include "Dark_mask_settings.h" #include "File_writer_settings.h" #include "Azim_int_settings.h" #include "Image_format_settings.h" @@ -170,6 +171,13 @@ public: /// /// /// + org::openapitools::server::model::Dark_mask_settings getDarkMask() const; + void setDarkMask(org::openapitools::server::model::Dark_mask_settings const& value); + bool darkMaskIsSet() const; + void unsetDark_mask(); + /// + /// + /// org::openapitools::server::model::Pixel_mask_statistics getPixelMask() const; void setPixelMask(org::openapitools::server::model::Pixel_mask_statistics const& value); bool pixelMaskIsSet() const; @@ -232,6 +240,8 @@ protected: bool m_Zeromq_previewIsSet; org::openapitools::server::model::Zeromq_metadata_settings m_Zeromq_metadata; bool m_Zeromq_metadataIsSet; + org::openapitools::server::model::Dark_mask_settings m_Dark_mask; + bool m_Dark_maskIsSet; org::openapitools::server::model::Pixel_mask_statistics m_Pixel_mask; bool m_Pixel_maskIsSet; org::openapitools::server::model::Roi_definitions m_Roi; diff --git a/broker/jfjoch_api.yaml b/broker/jfjoch_api.yaml index 1eaf738f..594f50d1 100644 --- a/broker/jfjoch_api.yaml +++ b/broker/jfjoch_api.yaml @@ -1507,6 +1507,8 @@ components: $ref: '#/components/schemas/zeromq_preview_settings' zeromq_metadata: $ref: '#/components/schemas/zeromq_metadata_settings' + dark_mask: + $ref: '#/components/schemas/dark_mask_settings' pixel_mask: $ref: '#/components/schemas/pixel_mask_statistics' roi: @@ -1657,6 +1659,49 @@ components: $ref: '#/components/schemas/roi_circle_list' azim: $ref: '#/components/schemas/roi_azim_list' + dark_mask_settings: + type: object + description: "Settings for collection of dark images to be used for mask calculation" + required: + - detector_threshold_keV + - frame_threshold_keV + - max_allowed_pixel_count + - max_frames_with_signal + - frame_time_us + - number_of_frames + properties: + detector_threshold_keV: + type: number + format: float + description: "Energy threshold for dark image collection" + minimum: 2.5 + default: 3.5 + maximum: 100.0 + frame_time_us: + type: integer + format: int64 + description: "Time between frames for dark image collection" + minimum: 500 + default: 10000 + maximum: 100000 + number_of_frames: + type: integer + format: int64 + description: "Number of frames for dark image collection; zero means no dark collection" + minimum: 0 + default: 1000 + max_allowed_pixel_count: + type: integer + format: int64 + description: "Maximum count in a pixel considered normal (not-masked)" + minimum: 0 + default: 1 + max_frames_with_signal: + type: integer + format: int64 + description: "Maximum number of frames with signal in a pixel considered normal (not-masked)" + minimum: 0 + default: 10 indexing_settings: type: object description: "Settings for crystallography indexing" @@ -2059,6 +2104,8 @@ components: $ref: '#/components/schemas/zeromq_preview_settings' zeromq_metadata: $ref: '#/components/schemas/zeromq_metadata_settings' + dark_mask: + $ref: '#/components/schemas/dark_mask_settings' zeromq_metadata_settings: type: object required: @@ -2706,6 +2753,42 @@ paths: application/json: schema: $ref: '#/components/schemas/zeromq_metadata_settings' + /config/dark_mask: + put: + summary: Set configuration for dark data collection to calculate mask + description: | + This is only possible when operating DECTRIS detectors at the moment; it will be also available for PSI EIGER at some point. + This can only be done when detector is `Idle`, `Error` or `Inactive` states. + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/dark_mask_settings' + responses: + "200": + description: Everything OK + "400": + description: Input parsing or validation error + content: + text/plain: + schema: + type: string + description: Exception error + "500": + description: Error within Jungfraujoch code - see output message. + content: + application/json: + schema: + $ref: '#/components/schemas/error_message' + get: + summary: Get settings for dark data collection to calculate mask + responses: + "200": + description: Everything OK + content: + application/json: + schema: + $ref: '#/components/schemas/dark_mask_settings' /status: get: summary: Get Jungfraujoch status diff --git a/broker/redoc-static.html b/broker/redoc-static.html index 566408ca..208e812d 100644 --- a/broker/redoc-static.html +++ b/broker/redoc-static.html @@ -379,7 +379,7 @@ data-styled.g138[id="sc-enPhjR"]{content:"SikXG,"}/*!sc*/ -

Get Jungfraujoch status

http://localhost:5232/config/zeromq_metadata

Response samples

Content type
application/json
{
  • "enabled": true,
  • "period_ms": 1000,
  • "socket_address": "string"
}

Set configuration for dark data collection to calculate mask

This is only possible when operating DECTRIS detectors at the moment; it will be also available for PSI EIGER at some point. +This can only be done when detector is Idle, Error or Inactive states.

+
Request Body schema: application/json
detector_threshold_keV
required
number <float> [ 2.5 .. 100 ]
Default: 3.5

Energy threshold for dark image collection

+
frame_time_us
required
integer <int64> [ 500 .. 100000 ]
Default: 10000

Time between frames for dark image collection

+
number_of_frames
required
integer <int64> >= 0
Default: 1000

Number of frames for dark image collection; zero means no dark collection

+
max_allowed_pixel_count
required
integer <int64> >= 0
Default: 1

Maximum count in a pixel considered normal (not-masked)

+
max_frames_with_signal
required
integer <int64> >= 0
Default: 10

Maximum number of frames with signal in a pixel considered normal (not-masked)

+

Responses

Request samples

Content type
application/json
{
  • "detector_threshold_keV": 3.5,
  • "frame_time_us": 10000,
  • "number_of_frames": 1000,
  • "max_allowed_pixel_count": 1,
  • "max_frames_with_signal": 10
}

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Get settings for dark data collection to calculate mask

Responses

Response samples

Content type
application/json
{
  • "detector_threshold_keV": 3.5,
  • "frame_time_us": 10000,
  • "number_of_frames": 1000,
  • "max_allowed_pixel_count": 1,
  • "max_frames_with_signal": 10
}

Get Jungfraujoch status

Status of the data acquisition

Responses

Response samples

Content type
application/json
{
  • "state": "Inactive",
  • "progress": 1,
  • "message": "string",
  • "message_severity": "success",
  • "gpu_count": 0
}

Get status of FPGA devices

Responses

Response samples

Content type
application/json
{
  • "state": "Inactive",
  • "progress": 1,
  • "message": "string",
  • "message_severity": "success",
  • "gpu_count": 0
}

Get status of FPGA devices

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Return XFEL pulse IDs for the current data acquisition

http://localhost:5232/fpga_status

Response samples

Content type
application/json
[
  • {
    }
]

Return XFEL pulse IDs for the current data acquisition

Return array of XFEL pulse IDs - (-1) if image not recorded

Responses

Response samples

Content type
application/json
[
  • 0
]

Return XFEL event codes for the current data acquisition

http://localhost:5232/xfel/pulse_id

Response samples

Content type
application/json
[
  • 0
]

Return XFEL event codes for the current data acquisition

Return array of XFEL event codes

Responses

Response samples

Content type
application/json
[
  • 0
]

Get detector status

http://localhost:5232/xfel/event_code

Response samples

Content type
application/json
[
  • 0
]

Get detector status

Status of the JUNGFRAU detector

Responses

Response samples

Content type
application/json
{
  • "state": "Idle",
  • "powerchip": "PowerOn",
  • "server_version": "string",
  • "number_of_triggers_left": 0,
  • "fpga_temp_degC": [
    ],
  • "high_voltage_V": [
    ]
}

Get ROI definitions

Responses

Response samples

Content type
application/json
{
  • "state": "Idle",
  • "powerchip": "PowerOn",
  • "server_version": "string",
  • "number_of_triggers_left": 0,
  • "fpga_temp_degC": [
    ],
  • "high_voltage_V": [
    ]
}

Get ROI definitions

Responses

Response samples

Content type
application/json
{
  • "box": {
    },
  • "circle": {
    },
  • "azim": {
    }
}

Upload ROI definitions

Request Body schema: application/json
required
object (roi_box_list)
http://localhost:5232/config/roi

Response samples

Content type
application/json
{
  • "box": {
    },
  • "circle": {
    },
  • "azim": {
    }
}

Upload ROI definitions

Request Body schema: application/json
required
object (roi_box_list)

List of box ROIs

required
object (roi_circle_list)

List of circular ROIs

@@ -1147,13 +1173,13 @@ Address follows ZeroMQ convention for sockets - in practice ipc:// " class="sc-eVqvcJ sc-fszimp sc-etsjJW kIppRw jnwENr ljKHqG">

Error within Jungfraujoch code - see output message.

Request samples

Content type
application/json
{
  • "box": {
    },
  • "circle": {
    },
  • "azim": {
    }
}

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Get general statistics

query Parameters
compression
boolean
Default: false
http://localhost:5232/config/roi

Request samples

Content type
application/json
{
  • "box": {
    },
  • "circle": {
    },
  • "azim": {
    }
}

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Get general statistics

query Parameters
compression
boolean
Default: false

Enable DEFLATE compression of output data.

Responses

Response samples

Content type
application/json
{
  • "detector": {
    },
  • "detector_list": {
    },
  • "detector_settings": {
    },
  • "image_format_settings": {
    },
  • "instrument_metadata": {
    },
  • "file_writer_settings": {
    },
  • "data_processing_settings": {
    },
  • "measurement": {
    },
  • "broker": {
    },
  • "fpga": [
    ],
  • "calibration": [
    ],
  • "zeromq_preview": {
    },
  • "zeromq_metadata": {
    },
  • "pixel_mask": {
    },
  • "roi": {
    },
  • "az_int": {
    },
  • "buffer": {
    },
  • "indexing": {
    }
}

Get data collection statistics

http://localhost:5232/statistics

Response samples

Content type
application/json
{
  • "detector": {
    },
  • "detector_list": {
    },
  • "detector_settings": {
    },
  • "image_format_settings": {
    },
  • "instrument_metadata": {
    },
  • "file_writer_settings": {
    },
  • "data_processing_settings": {
    },
  • "measurement": {
    },
  • "broker": {
    },
  • "fpga": [
    ],
  • "calibration": [
    ],
  • "zeromq_preview": {
    },
  • "zeromq_metadata": {
    },
  • "dark_mask": {
    },
  • "pixel_mask": {
    },
  • "roi": {
    },
  • "az_int": {
    },
  • "buffer": {
    },
  • "indexing": {
    }
}

Get data collection statistics

Results of the last data collection

Responses

Response samples

Content type
application/json
{
  • "file_prefix": "string",
  • "run_number": 0,
  • "experiment_group": "string",
  • "images_expected": 0,
  • "images_collected": 0,
  • "images_sent": 0,
  • "images_discarded_lossy_compression": 0,
  • "max_image_number_sent": 0,
  • "collection_efficiency": 1,
  • "compression_ratio": 5.3,
  • "cancelled": true,
  • "max_receiver_delay": 0,
  • "indexing_rate": 0.1,
  • "detector_width": 0,
  • "detector_height": 0,
  • "detector_pixel_depth": 2,
  • "bkg_estimate": 0.1,
  • "unit_cell": "string",
  • "error_pixels": 0.1,
  • "saturated_pixels": 0.1,
  • "roi_beam_pixels": 0.1,
  • "roi_beam_sum": 0.1
}

Get calibration statistics

http://localhost:5232/statistics/data_collection

Response samples

Content type
application/json
{
  • "file_prefix": "string",
  • "run_number": 0,
  • "experiment_group": "string",
  • "images_expected": 0,
  • "images_collected": 0,
  • "images_sent": 0,
  • "images_discarded_lossy_compression": 0,
  • "max_image_number_sent": 0,
  • "collection_efficiency": 1,
  • "compression_ratio": 5.3,
  • "cancelled": true,
  • "max_receiver_delay": 0,
  • "indexing_rate": 0.1,
  • "detector_width": 0,
  • "detector_height": 0,
  • "detector_pixel_depth": 2,
  • "bkg_estimate": 0.1,
  • "unit_cell": "string",
  • "error_pixels": 0.1,
  • "saturated_pixels": 0.1,
  • "roi_beam_pixels": 0.1,
  • "roi_beam_sum": 0.1
}

Get calibration statistics

Statistics are provided for each module/storage cell separately

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Get mask of the detector (binary)

http://localhost:5232/statistics/calibration

Response samples

Content type
application/json
[
  • {
    }
]

Get mask of the detector (binary)

Detector must be Initialized. @@ -1205,7 +1231,7 @@ User mask is stored in NXmx pixel mask (bit 8), as well as used in spot finding " class="sc-eVqvcJ sc-fszimp sc-etsjJW kIppRw jnwENr ljKHqG">

Error within Jungfraujoch code - see output message.

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Get mask of the detector (TIFF)

http://localhost:5232/config/user_mask

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Get mask of the detector (TIFF)

Should be in Idle state. @@ -1245,7 +1271,7 @@ User mask is not automatically applied - i.e. pixels with user mask will have a " class="sc-eVqvcJ sc-fszimp sc-etsjJW kIppRw jnwENr ljKHqG">

Error within Jungfraujoch code - see output message.

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Get pedestal in TIFF format

query Parameters
gain_level
required
integer
http://localhost:5232/config/user_mask.tiff

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Get pedestal in TIFF format

query Parameters
gain_level
required
integer

Gain level (0, 1, 2)

sc
integer

Storage cell number

@@ -1277,7 +1303,7 @@ For still measurement the number is ignored

" class="sc-eVqvcJ sc-fszimp sc-etsjJW kIppRw jnwENr ljKHqG">

Input parsing or validation error

Response samples

Content type
application/json
{
  • "title": "string",
  • "unit_x": "image_number",
  • "size_x": 0.1,
  • "size_y": 0.1,
  • "plot": [
    ]
}

Get full scan result

Responses

Response samples

Content type
application/json
{
  • "title": "string",
  • "unit_x": "image_number",
  • "size_x": 0.1,
  • "size_y": 0.1,
  • "plot": [
    ]
}

Get full scan result

Responses

Response samples

Content type
application/json
{
  • "file_prefix": "string",
  • "images": [
    ]
}

Get Start message in CBOR format

http://localhost:5232/result/scan

Response samples

Content type
application/json
{
  • "file_prefix": "string",
  • "images": [
    ]
}

Get Start message in CBOR format

Contains metadata for a dataset (e.g., experimental geometry)

Responses

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Get image message in CBOR format

http://localhost:5232/image_buffer/start.cbor

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Get image message in CBOR format

Contains full image data and metadata. The image must come from the latest data collection.

query Parameters
id
integer <int64> >= -2
Default: -1

Image ID in the image buffer. Special values: -1 - last image in the buffer, -2: last indexed image in the buffer

@@ -1307,7 +1333,7 @@ For still measurement the number is ignored

" class="sc-eVqvcJ sc-fszimp sc-etsjJW kIppRw jnwENr ljKHqG">

Error within Jungfraujoch code - see output message.

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Get preview image in JPEG format using custom settings

query Parameters
id
integer <int64> >= -2
Default: -1
http://localhost:5232/image_buffer/image.cbor

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Get preview image in JPEG format using custom settings

query Parameters
id
integer <int64> >= -2
Default: -1

Image ID in the image buffer. Special values: -1 - last image in the buffer, -2: last indexed image in the buffer

show_user_mask
boolean
Default: false

Show user mask

@@ -1335,7 +1361,7 @@ For still measurement the number is ignored

" class="sc-eVqvcJ sc-fszimp sc-etsjJW kIppRw jnwENr ljKHqG">

Error within Jungfraujoch code - see output message.

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Get preview image in TIFF format

query Parameters
id
integer <int64> >= -2
Default: -1
http://localhost:5232/image_buffer/image.jpeg

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Get preview image in TIFF format

query Parameters
id
integer <int64> >= -2
Default: -1

Image ID in the image buffer. Special values: -1 - last image in the buffer, -2: last indexed image in the buffer

Responses

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Get status of the image buffers

http://localhost:5232/image_buffer/clear

Response samples

Content type
application/json
{
  • "msg": "Detector in wrong state",
  • "reason": "WrongDAQState"
}

Get status of the image buffers

Can be run at any stage of Jungfraujoch operation, including during data collection. @@ -1363,13 +1389,13 @@ then image might be replaced in the buffer between calling /images and /image.cb " class="sc-eVqvcJ sc-fszimp sc-etsjJW kIppRw jnwENr ljKHqG">

Error within Jungfraujoch code - see output message.

Response samples

Content type
application/json
{
  • "min_image_number": 0,
  • "max_image_number": 0,
  • "image_numbers": [
    ],
  • "total_slots": 0,
  • "available_slots": 0
}

Get Jungfraujoch version of jfjoch_broker

Responses

Response samples

Content type
application/json
{
  • "min_image_number": 0,
  • "max_image_number": 0,
  • "image_numbers": [
    ],
  • "total_slots": 0,
  • "available_slots": 0
}

Get Jungfraujoch version of jfjoch_broker

Responses