From d8be435be68dc4363f084a5c43ee5e8dc4492032 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Fri, 1 May 2026 12:58:42 +0200 Subject: [PATCH] PixelMask: Precalculate raw maskto avoid copying it in the later code --- broker/JFJochStateMachine.cpp | 2 +- common/AzimuthalIntegrationMapping.cpp | 2 +- common/PixelMask.cpp | 43 +++++++++++++++++++------ common/PixelMask.h | 15 ++++++--- receiver/JFJochReceiverTest.cpp | 2 +- tests/JFJochReceiverProcessingTest.cpp | 2 +- tests/PixelMaskTest.cpp | 44 ++++++++++++++++++++++---- 7 files changed, 86 insertions(+), 24 deletions(-) diff --git a/broker/JFJochStateMachine.cpp b/broker/JFJochStateMachine.cpp index 3c9b54cf..10e4193b 100644 --- a/broker/JFJochStateMachine.cpp +++ b/broker/JFJochStateMachine.cpp @@ -145,7 +145,7 @@ void JFJochStateMachine::TakeDarkMaskInternal(std::unique_lock &ul) ul.lock(); if (mask_output.receiver_output.dark_mask_result.size() == local_experiment.GetPixelsNum()) { - pixel_mask.LoadDarkBadPixelMask(mask_output.receiver_output.dark_mask_result); + pixel_mask.LoadDarkBadPixelMask(local_experiment, mask_output.receiver_output.dark_mask_result); SetState(JFJochState::Idle); } else SetState(JFJochState::Error, "Mask not collected properly", BrokerStatus::MessageSeverity::Error); diff --git a/common/AzimuthalIntegrationMapping.cpp b/common/AzimuthalIntegrationMapping.cpp index 03480451..41e58afb 100644 --- a/common/AzimuthalIntegrationMapping.cpp +++ b/common/AzimuthalIntegrationMapping.cpp @@ -40,7 +40,7 @@ AzimuthalIntegrationMapping::AzimuthalIntegrationMapping(const DiffractionExperi nthreads = std::clamp(nthreads, 1, 64); if (!experiment.IsGeometryTransformed()) - SetupRawGeom(experiment, mask.GetMaskRaw(experiment), nthreads); + SetupRawGeom(experiment, mask.GetMaskRaw(), nthreads); else SetupConvGeom(experiment.GetDiffractionGeometry(),mask.GetMask(), nthreads); diff --git a/common/PixelMask.cpp b/common/PixelMask.cpp index f5e60b78..c25aec66 100644 --- a/common/PixelMask.cpp +++ b/common/PixelMask.cpp @@ -35,7 +35,20 @@ uint32_t PixelMask::LoadMask(const std::vector &input_mask, uint8_t bi return ret; } -void PixelMask::CalcEdgePixels(const DiffractionExperiment &experiment) { +void PixelMask::UpdateRawMask(const DiffractionExperiment &experiment) { + switch (experiment.GetDetectorType()) { + case DetectorType::JUNGFRAU: + case DetectorType::EIGER: + raw_mask.resize(experiment.GetModulesNum() * RAW_MODULE_SIZE, 0); + ConvertedToRawGeometry(experiment, raw_mask.data(), mask.data()); + break; + default: + raw_mask.clear(); + break; + } +} + +void PixelMask::CalcEdgePixels_i(const DiffractionExperiment &experiment) { if (experiment.GetDetectorType() == DetectorType::DECTRIS) return; @@ -81,21 +94,27 @@ void PixelMask::CalcEdgePixels(const DiffractionExperiment &experiment) { LoadMask(chip_edge_conv, ChipGapPixelBit); } -std::vector PixelMask::GetMaskRaw(const DiffractionExperiment &experiment) const { - std::vector ret(experiment.GetModulesNum() * RAW_MODULE_SIZE, 0); - ConvertedToRawGeometry(experiment, ret.data(), mask.data()); - return ret; +void PixelMask::CalcEdgePixels(const DiffractionExperiment &experiment) { + CalcEdgePixels_i(experiment); + UpdateRawMask(experiment); +} + +const std::vector &PixelMask::GetMaskRaw() const { + if (raw_mask.empty()) + throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, + "Raw format not available for this detector"); + return raw_mask; } const std::vector &PixelMask::GetMask() const { return mask; } -std::vector PixelMask::GetMask(const DiffractionExperiment& experiment) const { +const std::vector &PixelMask::GetMask(const DiffractionExperiment& experiment) const { if (experiment.IsGeometryTransformed()) return GetMask(); else - return GetMaskRaw(experiment); + return GetMaskRaw(); } std::vector PixelMask::GetUserMask() const { @@ -159,7 +178,9 @@ void PixelMask::LoadDetectorBadPixelMask(const DiffractionExperiment &experiment LoadMask(input_mask_conv, ErrorPixelBit); LoadMask(input_mask_rms_conv, NoisyPixelBit); - CalcEdgePixels(experiment); + CalcEdgePixels_i(experiment); + + UpdateRawMask(experiment); } PixelMaskStatistics PixelMask::GetStatistics() const { @@ -186,10 +207,12 @@ PixelMaskStatistics PixelMask::GetStatistics() const { void PixelMask::LoadUserMask(const DiffractionExperiment& experiment, const std::vector &in_mask) { if (in_mask.size() == mask.size()) { LoadMask(in_mask, UserMaskedPixelBit); + UpdateRawMask(experiment); } else if (in_mask.size() == experiment.GetModulesNum() * RAW_MODULE_SIZE) { std::vector tmp(experiment.GetPixelsNumConv(), 0); RawToConvertedGeometry(experiment, tmp.data(), in_mask. data()); LoadMask(tmp, UserMaskedPixelBit); + UpdateRawMask(experiment); } else throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Size of input user mask invalid"); @@ -220,9 +243,10 @@ void PixelMask::LoadDECTRISBadPixelMask(const std::vector &input_mask) } } } + raw_mask = {}; // For DECTRIS - there is no raw mask } -void PixelMask::LoadDarkBadPixelMask(const std::vector &input_mask) { +void PixelMask::LoadDarkBadPixelMask(const DiffractionExperiment& experiment, const std::vector &input_mask) { if (input_mask.size() != mask.size()) throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Input match doesn't fit the detector "); @@ -238,4 +262,5 @@ void PixelMask::LoadDarkBadPixelMask(const std::vector &input_mask) { mask[i] &= ~(1 << NoisyPixelBit); } } + UpdateRawMask(experiment); } diff --git a/common/PixelMask.h b/common/PixelMask.h index cc0e3001..f4210861 100644 --- a/common/PixelMask.h +++ b/common/PixelMask.h @@ -19,7 +19,13 @@ struct PixelMaskStatistics { class PixelMask { std::vector mask; + std::vector raw_mask; + uint32_t LoadMask(const std::vector& mask, uint8_t bit); + void UpdateRawMask(const DiffractionExperiment& experiment); + + void CalcEdgePixels_i(const DiffractionExperiment& experiment); + public: // NXmx bits constexpr static const uint8_t ModuleGapPixelBit = 0; @@ -37,13 +43,14 @@ 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 LoadDarkBadPixelMask(const DiffractionExperiment& experiment, const std::vector& mask); void LoadDetectorBadPixelMask(const DiffractionExperiment& experiment, const JFCalibration *calib); - [[nodiscard]] std::vector GetMaskRaw(const DiffractionExperiment& experiment) const; - [[nodiscard]] std::vector GetMask(const DiffractionExperiment& experiment) const; - [[nodiscard]] std::vector GetUserMask(const DiffractionExperiment& experiment) const; + [[nodiscard]] const std::vector &GetMaskRaw() const; + [[nodiscard]] const std::vector &GetMask(const DiffractionExperiment& experiment) const; [[nodiscard]] const std::vector &GetMask() const; + + [[nodiscard]] std::vector GetUserMask(const DiffractionExperiment& experiment) const; [[nodiscard]] std::vector GetUserMask() const; [[nodiscard]] PixelMaskStatistics GetStatistics() const; }; diff --git a/receiver/JFJochReceiverTest.cpp b/receiver/JFJochReceiverTest.cpp index 602cad98..1e00e7ab 100644 --- a/receiver/JFJochReceiverTest.cpp +++ b/receiver/JFJochReceiverTest.cpp @@ -63,7 +63,7 @@ bool JFJochReceiverTest(JFJochReceiverOutput &output, Logger &logger, std::vector raw_expected_image_with_mask = raw_expected_image; if (x.IsApplyPixelMask()) { for (int i = 0; i < raw_expected_image_with_mask.size(); i++) - if (pixel_mask.GetMaskRaw((x)).at(i) != 0) + if (pixel_mask.GetMaskRaw().at(i) != 0) raw_expected_image_with_mask[i] = UINT16_MAX; } diff --git a/tests/JFJochReceiverProcessingTest.cpp b/tests/JFJochReceiverProcessingTest.cpp index dd623e40..82aff890 100644 --- a/tests/JFJochReceiverProcessingTest.cpp +++ b/tests/JFJochReceiverProcessingTest.cpp @@ -1251,7 +1251,7 @@ TEST_CASE("JFJochIntegrationTest_ZMQ_ROI", "[JFJochReceiver]") { ConvertedToRawGeometry(experiment, image_raw_geom.data(), image_conv.data()); logger.Info("Loaded image"); - auto mask = pixel_mask.GetMaskRaw(experiment); + auto &mask = pixel_mask.GetMaskRaw(); uint64_t sat_pixels = 0; uint64_t err_pixels = 0; diff --git a/tests/PixelMaskTest.cpp b/tests/PixelMaskTest.cpp index 4f34c6bf..361c35d0 100644 --- a/tests/PixelMaskTest.cpp +++ b/tests/PixelMaskTest.cpp @@ -10,7 +10,7 @@ TEST_CASE("PixelMask_MaskModuleEdges","[PixelMask]") { PixelMask mask(experiment); - auto mask_out = mask.GetMaskRaw(experiment); + auto mask_out = mask.GetMaskRaw(); REQUIRE(mask_out.size() == experiment.GetModulesNum() * RAW_MODULE_SIZE); @@ -33,7 +33,7 @@ TEST_CASE("PixelMask_MaskChipEdges","[PixelMask]") { experiment.MaskChipEdges(true).MaskModuleEdges(false).Raw(); PixelMask mask(experiment); - auto mask_out = mask.GetMaskRaw(experiment); + auto mask_out = mask.GetMaskRaw(); REQUIRE(mask_out.size() == experiment.GetModulesNum() * RAW_MODULE_SIZE); CHECK(mask_out[255] == (1u<<31)); @@ -73,7 +73,7 @@ TEST_CASE("PixelMask_MaskWrongGain","[PixelMask]") { mask.LoadDetectorBadPixelMask(experiment, &calibration); - auto mask_out = mask.GetMaskRaw(experiment); + auto mask_out = mask.GetMaskRaw(); REQUIRE(mask_out.size() == experiment.GetModulesNum() * RAW_MODULE_SIZE); CHECK(mask_out[2*RAW_MODULE_SIZE + 345] != 0); @@ -89,7 +89,7 @@ TEST_CASE("PixelMask_MaskWrongGain","[PixelMask]") { REQUIRE(!experiment.IsMaskPixelsWithoutG0()); mask.LoadDetectorBadPixelMask(experiment, &calibration); - mask_out = mask.GetMaskRaw(experiment); + mask_out = mask.GetMaskRaw(); CHECK(mask_out[2*RAW_MODULE_SIZE + 345] == 0); CHECK(mask_out[2*RAW_MODULE_SIZE + 346] != 0); @@ -126,7 +126,7 @@ TEST_CASE("PixelMask_MaskG0RMS","[PixelMask]") { mask.LoadDetectorBadPixelMask(experiment, &calibration); - auto mask_out = mask.GetMaskRaw(experiment); + auto mask_out = mask.GetMaskRaw(); REQUIRE(mask_out.size() == experiment.GetModulesNum() * RAW_MODULE_SIZE); CHECK(mask_out[2*RAW_MODULE_SIZE + 245] == (1 << PixelMask::NoisyPixelBit)); @@ -164,7 +164,7 @@ TEST_CASE("PixelMask_SCs","[PixelMask]") { mask.LoadDetectorBadPixelMask(experiment, &calibration); - auto mask_out = mask.GetMaskRaw(experiment); + auto mask_out = mask.GetMaskRaw(); REQUIRE(mask_out.size() == experiment.GetModulesNum() * RAW_MODULE_SIZE); CHECK(mask_out[456] == (1 << PixelMask::ErrorPixelBit)); @@ -199,6 +199,10 @@ TEST_CASE("PixelMask_CalculateNexusMask_UserMaskConv","[PixelMask]") { REQUIRE(user_mask_v[1030 * 700 + 300] == 1); REQUIRE(user_mask_v[(1030+8)*514] == 0); + + experiment.Raw(); + const auto &raw_mask_v = mask.GetMask(experiment); + REQUIRE(raw_mask_v.size() == experiment.GetModulesNum() * RAW_MODULE_SIZE); } TEST_CASE("PixelMask_MaskDetectorGaps","[PixelMask]") { @@ -271,7 +275,7 @@ TEST_CASE("PixelMask_LoadDarkBadPixelMask","[PixelMask]") { 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); + mask.LoadDarkBadPixelMask(experiment, dark_mask); CHECK(mask.GetStatistics().user_mask == 2); CHECK(mask.GetStatistics().error_pixel == 4); @@ -282,4 +286,30 @@ TEST_CASE("PixelMask_LoadDarkBadPixelMask","[PixelMask]") { CHECK(mask.GetMask()[534] == (1 << PixelMask::ModuleGapPixelBit)); CHECK(mask.GetMask()[2 * 1000 * 5] == (1 << PixelMask::ErrorPixelBit)); CHECK(mask.GetMask()[67867] == (1 << PixelMask::NoisyPixelBit)); +} + +TEST_CASE("PixelMask_LoadUserMaskRaw_UpdatesCachedRawMask", "[PixelMask]") { + DiffractionExperiment experiment(DetJF(1, 1)); + experiment.MaskModuleEdges(true).MaskChipEdges(false).Raw(); + + PixelMask mask(experiment); + + std::vector raw_user_mask(experiment.GetModulesNum() * RAW_MODULE_SIZE, 0); + raw_user_mask[345] = 1; + + REQUIRE_NOTHROW(mask.LoadUserMask(experiment, raw_user_mask)); + + const auto &raw_mask_out = mask.GetMaskRaw(); + + REQUIRE(raw_mask_out.size() == experiment.GetModulesNum() * RAW_MODULE_SIZE); + CHECK((raw_mask_out[345] & (1u << PixelMask::UserMaskedPixelBit)) != 0); + CHECK((raw_mask_out[0] & (1u << PixelMask::ModuleEdgePixelBit)) != 0); +} + +TEST_CASE("PixelMask_GetMaskRaw_ThrowsForDECTRIS", "[PixelMask]") { + DiffractionExperiment experiment(DetDECTRIS(2068, 2164, "Test", "")); + PixelMask mask(experiment); + + REQUIRE_THROWS(mask.GetMaskRaw()); + REQUIRE(mask.GetMask(experiment).size() == experiment.GetPixelsNum()); } \ No newline at end of file