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