diff --git a/common/TestImagePusher.cpp b/common/TestImagePusher.cpp index c6f9b178..6e89a5e7 100644 --- a/common/TestImagePusher.cpp +++ b/common/TestImagePusher.cpp @@ -83,11 +83,18 @@ bool TestImagePusher::CheckImage(const DiffractionExperiment &x, const std::vect logger.Error("Image empty"); no_errors = false; } else { - std::vector decompressed_image; + std::vector decompressed_image_16; + std::vector decompressed_image_32; + // Image decompression try { - JFJochDecompress(decompressed_image, x.GetCompressionAlgorithmEnum(), + if (x.GetPixelDepth() == 2) + JFJochDecompress(decompressed_image_16, x.GetCompressionAlgorithmEnum(), receiver_generated_image, x.GetPixelsNum()); + else + JFJochDecompress(decompressed_image_32, x.GetCompressionAlgorithmEnum(), + receiver_generated_image, x.GetPixelsNum()); + } catch (const JFJochException &e) { logger.Error(e.what()); no_errors = false; @@ -100,18 +107,51 @@ bool TestImagePusher::CheckImage(const DiffractionExperiment &x, const std::vect if (x.GetStorageCellNumber() > 1) storage_cell = image_id % x.GetStorageCellNumber(); - double result = CheckConversionWithGeomTransform(x, calibration, - raw_reference_image.data(), - decompressed_image.data(), - storage_cell); + double result = 0; + if (x.GetPixelDepth() == 2) { + if (x.IsPixelSigned()) + result = CheckConversionWithGeomTransform(x, calibration, + raw_reference_image.data(), + (int16_t *) decompressed_image_16.data(), + storage_cell); + else + result = CheckConversionWithGeomTransform(x, calibration, + raw_reference_image.data(), + (uint16_t *) decompressed_image_16.data(), + storage_cell); + } else if (x.GetPixelDepth() == 4) { + if (x.IsPixelSigned()) + result = CheckConversionWithGeomTransform(x, calibration, + raw_reference_image.data(), + (int32_t *) decompressed_image_32.data(), + storage_cell); + else + result = CheckConversionWithGeomTransform(x, calibration, + raw_reference_image.data(), + (uint32_t *) decompressed_image_32.data(), + storage_cell); + } + if (result > 0.5) { logger.Error("Mean conversion error ({:.3f}) larger than threshold", result); no_errors = false; } else logger.Info("Mean conversion error: {:.3f}", result); } else if (x.GetDetectorMode() == DetectorMode::Raw) { - if (memcmp(raw_reference_image.data(), decompressed_image.data(), sizeof(uint16_t) * x.GetPixelsNum()) != - 0) { + size_t diff = 0; + if (x.GetPixelDepth() == 2) { + for (int i = 0; i < x.GetPixelsNum(); i++) { + if (raw_reference_image[i] != decompressed_image_16[i]) + diff++; + } + } else { + for (int i = 0; i < x.GetPixelsNum(); i++) { + if (raw_reference_image[i] != decompressed_image_32[i]) + diff++; + } + } + + if (diff != 0) { logger.Error("Raw data mismatch"); no_errors = false; } diff --git a/jungfrau/JFConversionFloatingPoint.cpp b/jungfrau/JFConversionFloatingPoint.cpp index e5263523..236b71c3 100644 --- a/jungfrau/JFConversionFloatingPoint.cpp +++ b/jungfrau/JFConversionFloatingPoint.cpp @@ -6,6 +6,29 @@ JFConversionFloatingPoint::JFConversionFloatingPoint() : gain_g0(RAW_MODULE_SIZE), gain_g1(RAW_MODULE_SIZE), gain_g2(RAW_MODULE_SIZE), pedestal_g0(RAW_MODULE_SIZE), pedestal_g1(RAW_MODULE_SIZE), pedestal_g2(RAW_MODULE_SIZE) {} +JFConversionFloatingPoint::JFConversionFloatingPoint(const DiffractionExperiment &experiment) : JFConversionFloatingPoint() { + summation = experiment.GetSummation(); + pixel_signed = experiment.IsPixelSigned(); + + if (experiment.GetPixelDepth() == 2) { + if (pixel_signed) { + err_pixel = INT16_MIN; + overload_pixel = INT16_MAX; + } else { + err_pixel = UINT16_MAX; + overload_pixel = UINT16_MAX - 1; + } + } else if (experiment.GetPixelDepth() == 4) { + if (pixel_signed) { + err_pixel = INT32_MIN; + overload_pixel = INT32_MAX; + } else { + err_pixel = UINT32_MAX; + overload_pixel = UINT32_MAX - 1; + } + } +} + inline double one_over_gain_energy(double gain_factor, double energy) { double tmp = gain_factor * energy; if (!std::isfinite(tmp) || (tmp == 0.0)) @@ -115,8 +138,15 @@ void JFConversionFloatingPoint::ConvertFP(double *dest, const uint16_t *source) break; } + if (summation > 1) + expected *= summation; + if ((expected > overload_pixel) && !special_val) expected = overload_pixel; - dest[i] = expected; + + if ((!pixel_signed) && (expected < 0)) + dest[i] = 0; + else + dest[i] = expected; } } diff --git a/jungfrau/JFConversionFloatingPoint.h b/jungfrau/JFConversionFloatingPoint.h index 7c8e07a3..ded2e760 100644 --- a/jungfrau/JFConversionFloatingPoint.h +++ b/jungfrau/JFConversionFloatingPoint.h @@ -16,9 +16,11 @@ class JFConversionFloatingPoint { double err_pixel = INT16_MIN; double overload_pixel = INT16_MAX; + int64_t summation = 1; + bool pixel_signed = true; public: JFConversionFloatingPoint(); - + JFConversionFloatingPoint(const DiffractionExperiment& experiment); void Setup(const JFModuleGainCalibration &gain_calibration, const JFModulePedestal &pedestal_g0, const JFModulePedestal &pedestal_g1, diff --git a/tests/FPGAUnitTest.h b/tests/FPGAUnitTest.h index 9f18fe53..6aa83976 100644 --- a/tests/FPGAUnitTest.h +++ b/tests/FPGAUnitTest.h @@ -25,6 +25,8 @@ template double Compare(T *source, std::vector &reference, int for (size_t i = 0; i < npixel; i++) { double diff = reference[i] - source[i]; + if (fabs(diff) >= 1000) + std::cout << i << " " << reference[i] << " " << source[i] << std::endl; result += diff * diff; } @@ -36,8 +38,6 @@ template double MaxErrorOnConversion(T *source, std::vector &r for (size_t i = 0; i < npixel; i++) { double val = abs(reference[i] - source[i]); - if (val >= 32768) - std::cout << i << " " << reference[i] << " " << source[i] << std::endl; if (val > ret) ret = val; } return ret; @@ -50,7 +50,7 @@ template double CheckConversion(const DiffractionExperiment &experimen std::vector conversion_ref(RAW_MODULE_SIZE); - JFConversionFloatingPoint conversion; + JFConversionFloatingPoint conversion(experiment); conversion.Setup(calib.GainCalibration(0), calib.Pedestal(0, 0, storage_cell), calib.Pedestal(0, 1, storage_cell), @@ -65,13 +65,23 @@ template double CheckConversionWithGeomTransform(const DiffractionExpe const JFCalibration &calib, const uint16_t *raw, T *converted, size_t storage_cell = 0) { - T fill_value = INT16_MIN; - if (experiment.GetPixelDepth() == 4) - fill_value = INT32_MIN; + T fill_value; + if (sizeof(T) == 2) { + if (std::is_signed::value) + fill_value = INT16_MIN; + else + fill_value = UINT16_MAX; + } else if (sizeof(T) == 4) { + if (std::is_signed::value) + fill_value = INT32_MIN; + else + fill_value = UINT32_MAX; + } + std::vector conversion_ref(experiment.GetModulesNum() * RAW_MODULE_SIZE); std::vector conversion_ref_transformed(experiment.GetPixelsNum(), fill_value); - JFConversionFloatingPoint conversion; + JFConversionFloatingPoint conversion(experiment); for (int m = 0; m < experiment.GetModulesNum(); m ++) { conversion.Setup(calib.GainCalibration(m), diff --git a/tests/JFJochReceiverIntegrationTest.cpp b/tests/JFJochReceiverIntegrationTest.cpp index 0d055f70..4e8f0c4b 100644 --- a/tests/JFJochReceiverIntegrationTest.cpp +++ b/tests/JFJochReceiverIntegrationTest.cpp @@ -67,6 +67,91 @@ TEST_CASE("JFJochReceiverTest_Conversion", "[JFJochReceiver]") { REQUIRE(!output.cancelled()); } +TEST_CASE("JFJochReceiverTest_Conversion_U16", "[JFJochReceiver]") { + Logger logger("JFJochReceiverTest_Conversion"); + + DiffractionExperiment x(DetectorGeometry(2)); + const uint16_t nthreads = 4; + + x.Mode(DetectorMode::Conversion); + x.PedestalG0Frames(0).NumTriggers(1).UseInternalPacketGenerator(true) + .ImagesPerTrigger(32).DataFileCount(16).PhotonEnergy_keV(12.4).Compression(JFJochProtoBuf::BSHUF_ZSTD).FPGAOutputMode(JFJochProtoBuf::UINT16); + + REQUIRE(!x.IsPixelSigned()); + std::vector> aq_devices; + for (int i = 0; i < x.GetDataStreamsNum(); i++) { + HLSSimulatedDevice *test; + test = new HLSSimulatedDevice(i, 64); + test->EnableLogging(&logger); + aq_devices.emplace_back(test); + } + + JFJochProtoBuf::ReceiverOutput output; + bool ret; + REQUIRE_NOTHROW(ret = JFJochReceiverTest(output, logger, aq_devices, x, nthreads, false)); + REQUIRE(ret); + REQUIRE(output.efficiency() == 1.0); + REQUIRE(output.images_sent() == x.GetImageNum()); + + REQUIRE(!output.cancelled()); +} + +TEST_CASE("JFJochReceiverTest_Conversion_I32", "[JFJochReceiver]") { + Logger logger("JFJochReceiverTest_Conversion"); + + DiffractionExperiment x(DetectorGeometry(2)); + const uint16_t nthreads = 4; + + x.Mode(DetectorMode::Conversion); + x.PedestalG0Frames(0).NumTriggers(1).UseInternalPacketGenerator(true) + .ImagesPerTrigger(32).DataFileCount(16).PhotonEnergy_keV(12.4).Compression(JFJochProtoBuf::BSHUF_ZSTD).FPGAOutputMode(JFJochProtoBuf::INT32); + + std::vector> aq_devices; + for (int i = 0; i < x.GetDataStreamsNum(); i++) { + HLSSimulatedDevice *test; + test = new HLSSimulatedDevice(i, 64); + test->EnableLogging(&logger); + aq_devices.emplace_back(test); + } + + JFJochProtoBuf::ReceiverOutput output; + bool ret; + REQUIRE_NOTHROW(ret = JFJochReceiverTest(output, logger, aq_devices, x, nthreads, false)); + REQUIRE(ret); + REQUIRE(output.efficiency() == 1.0); + REQUIRE(output.images_sent() == x.GetImageNum()); + + REQUIRE(!output.cancelled()); +} + +TEST_CASE("JFJochReceiverTest_Conversion_Summation2", "[JFJochReceiver]") { + Logger logger("JFJochReceiverTest_Conversion"); + + DiffractionExperiment x(DetectorGeometry(2)); + const uint16_t nthreads = 4; + + x.Mode(DetectorMode::Conversion); + x.PedestalG0Frames(0).NumTriggers(1).UseInternalPacketGenerator(true) + .ImagesPerTrigger(32).DataFileCount(16).PhotonEnergy_keV(12.4).Compression(JFJochProtoBuf::BSHUF_ZSTD).Summation(2); + + std::vector> aq_devices; + for (int i = 0; i < x.GetDataStreamsNum(); i++) { + HLSSimulatedDevice *test; + test = new HLSSimulatedDevice(i, 64); + test->EnableLogging(&logger); + aq_devices.emplace_back(test); + } + + JFJochProtoBuf::ReceiverOutput output; + bool ret; + REQUIRE_NOTHROW(ret = JFJochReceiverTest(output, logger, aq_devices, x, nthreads, false)); + REQUIRE(ret); + REQUIRE(output.efficiency() == 1.0); + REQUIRE(output.images_sent() == x.GetImageNum()); + + REQUIRE(!output.cancelled()); +} + TEST_CASE("JFJochReceiverTest_Conversion_StorageCell", "[JFJochReceiver]") { Logger logger("JFJochReceiverTest_Conversion_StorageCell");