From 52d1f30a6aa227eecd37d4eb2c60636f8fe03f44 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Thu, 30 Apr 2026 10:27:17 +0200 Subject: [PATCH 1/7] JFJochReceiver: az_int_mapping is unique_ptr, so construction is explicit and can be profiled --- receiver/JFJochReceiver.cpp | 21 +++++++++++++-------- receiver/JFJochReceiver.h | 2 +- receiver/JFJochReceiverFPGA.cpp | 8 ++++---- receiver/JFJochReceiverLite.cpp | 4 ++-- tests/AzimuthalIntegrationTest.cpp | 10 ++++++++++ 5 files changed, 30 insertions(+), 15 deletions(-) diff --git a/receiver/JFJochReceiver.cpp b/receiver/JFJochReceiver.cpp index 1477b76d..153f193a 100644 --- a/receiver/JFJochReceiver.cpp +++ b/receiver/JFJochReceiver.cpp @@ -33,7 +33,6 @@ JFJochReceiver::JFJochReceiver(const DiffractionExperiment &in_experiment, serialmx_filter(in_experiment), numa_policy(in_numa_policy), pixel_mask(in_pixel_mask), - az_int_mapping(experiment, pixel_mask), indexer(experiment, indexing_thread_pool) { logger.Info("Initializing receiver"); // Ensure there is nothing running for now @@ -46,7 +45,13 @@ JFJochReceiver::JFJochReceiver(const DiffractionExperiment &in_experiment, current_status.SetEfficiency({}); current_status.SetStatus(JFJochReceiverStatus{}); // GetStatus() is virtual function and cannot be called yet! - plots.Setup(experiment, az_int_mapping); + auto start_time_point = std::chrono::steady_clock::now(); + az_int_mapping = std::make_unique(experiment, pixel_mask); + auto end_time_point = std::chrono::steady_clock::now(); + auto duration = std::chrono::duration(end_time_point - start_time_point); + logger.Info("Azimuthal integration mapping done in {:.5f} s", duration.count()); + + plots.Setup(experiment, *az_int_mapping); push_images_to_writer = (experiment.GetImageNum() > 0) && (!experiment.GetFilePrefix().empty()); @@ -110,12 +115,12 @@ void JFJochReceiver::SendStartMessage() { StartMessage message{}; experiment.FillMessage(message); message.arm_date = time_UTC(std::chrono::system_clock::now()); - message.az_int_q_bin_count = az_int_mapping.GetQBinCount(); - message.az_int_bin_to_q = az_int_mapping.GetBinToQ(); - message.az_int_bin_to_two_theta = az_int_mapping.GetBinToTwoTheta(); - message.az_int_phi_bin_count = az_int_mapping.GetAzimuthalBinCount(); - if (az_int_mapping.GetAzimuthalBinCount() > 1) - message.az_int_bin_to_phi = az_int_mapping.GetBinToPhi(); + message.az_int_q_bin_count = az_int_mapping->GetQBinCount(); + message.az_int_bin_to_q = az_int_mapping->GetBinToQ(); + message.az_int_bin_to_two_theta = az_int_mapping->GetBinToTwoTheta(); + message.az_int_phi_bin_count = az_int_mapping->GetAzimuthalBinCount(); + if (az_int_mapping->GetAzimuthalBinCount() > 1) + message.az_int_bin_to_phi = az_int_mapping->GetBinToPhi(); message.writer_notification_zmq_addr = image_pusher.GetWriterNotificationSocketAddress(); message.rois = experiment.ROI().ExportMetadata(); message.max_spot_count = experiment.GetMaxSpotCount(); diff --git a/receiver/JFJochReceiver.h b/receiver/JFJochReceiver.h index 82178d74..d415aadb 100644 --- a/receiver/JFJochReceiver.h +++ b/receiver/JFJochReceiver.h @@ -82,7 +82,7 @@ protected: std::vector> adu_histogram_module; PixelMask pixel_mask; - AzimuthalIntegration az_int_mapping; + std::unique_ptr az_int_mapping; std::optional max_delay; std::mutex max_delay_mutex; diff --git a/receiver/JFJochReceiverFPGA.cpp b/receiver/JFJochReceiverFPGA.cpp index d74e2e8c..a6efc0de 100644 --- a/receiver/JFJochReceiverFPGA.cpp +++ b/receiver/JFJochReceiverFPGA.cpp @@ -311,8 +311,8 @@ void JFJochReceiverFPGA::FrameTransformationThread(uint32_t threadid) { frame_transformation_ready.count_down(); - uint16_t az_int_min_bin = std::floor(az_int_mapping.QToBin(experiment.GetLowQForBkgEstimate_recipA())); - uint16_t az_int_max_bin = std::ceil(az_int_mapping.QToBin(experiment.GetHighQForBkgEstimate_recipA())); + uint16_t az_int_min_bin = std::floor(az_int_mapping->QToBin(experiment.GetLowQForBkgEstimate_recipA())); + uint16_t az_int_max_bin = std::ceil(az_int_mapping->QToBin(experiment.GetHighQForBkgEstimate_recipA())); int64_t image_number; while (images_to_go.Get(image_number) != 0) { @@ -340,7 +340,7 @@ void JFJochReceiverFPGA::FrameTransformationThread(uint32_t threadid) { ImageMetadata metadata(experiment); - AzimuthalIntegrationProfile az_int_profile_image(az_int_mapping); + AzimuthalIntegrationProfile az_int_profile_image(*az_int_mapping); auto local_spot_finding_settings = GetSpotFindingSettings(); @@ -678,5 +678,5 @@ void JFJochReceiverFPGA::LoadCalibrationToFPGA(uint16_t data_stream) { acquisition_device[data_stream].InitializeROIMap(experiment, roi_map); // Initialize data processing - acquisition_device[data_stream].InitializeDataProcessing(experiment, az_int_mapping); + acquisition_device[data_stream].InitializeDataProcessing(experiment, *az_int_mapping); } diff --git a/receiver/JFJochReceiverLite.cpp b/receiver/JFJochReceiverLite.cpp index f7e4029d..d8a33bf4 100644 --- a/receiver/JFJochReceiverLite.cpp +++ b/receiver/JFJochReceiverLite.cpp @@ -244,7 +244,7 @@ void JFJochReceiverLite::DataAnalysisThread(uint32_t id) { measurement_started.wait(); try { - analysis = std::make_unique(experiment, az_int_mapping, pixel_mask, indexer); + analysis = std::make_unique(experiment, *az_int_mapping, pixel_mask, indexer); } catch (const JFJochException &e) { Cancel(e); return; @@ -276,7 +276,7 @@ void JFJochReceiverLite::DataAnalysisThread(uint32_t id) { auto image_start_time = std::chrono::high_resolution_clock::now(); - AzimuthalIntegrationProfile profile(az_int_mapping); + AzimuthalIntegrationProfile profile(*az_int_mapping); analysis->Analyze(data_msg, profile, GetSpotFindingSettings()); auto image_end_time = std::chrono::high_resolution_clock::now(); diff --git a/tests/AzimuthalIntegrationTest.cpp b/tests/AzimuthalIntegrationTest.cpp index 0023254a..ad8e4b3c 100644 --- a/tests/AzimuthalIntegrationTest.cpp +++ b/tests/AzimuthalIntegrationTest.cpp @@ -19,6 +19,16 @@ TEST_CASE("AzimuthalIntegrationMapping_Constructor","[AzimuthalIntegration]") { REQUIRE_NOTHROW(radial = std::make_unique(x, pixel_mask)); } +TEST_CASE("AzimuthalIntegrationMapping_Create_16M","[AzimuthalIntegration]") { + DiffractionExperiment x(DetDECTRIS(2000, 2000, "E16M", "")); + x.DetectorDistance_mm(50).BeamX_pxl(1000).BeamY_pxl(1000); + x.QSpacingForAzimInt_recipA(0.1).QRangeForAzimInt_recipA(0.1, 10); + + PixelMask pixel_mask(x); + AzimuthalIntegration mapping(x, pixel_mask); + REQUIRE(mapping.GetBinNumber() == 99); +} + TEST_CASE("AzimuthalIntegrationMapping_GetBinNumber","[AzimuthalIntegration]") { DiffractionExperiment x(DetJF4M()); x.DetectorDistance_mm(50).BeamX_pxl(1000).BeamY_pxl(1000); -- 2.52.0 From 06d8fc3972f33cb40fabd674d816bb316457fd91 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Thu, 30 Apr 2026 10:32:38 +0200 Subject: [PATCH 2/7] AzimuthalIntegrationMapping: Go back to old name, which was more logical for this object --- acquisition_device/AcquisitionDevice.cpp | 2 +- acquisition_device/AcquisitionDevice.h | 4 +- ...on.cpp => AzimuthalIntegrationMapping.cpp} | 44 +++++++++---------- ...ration.h => AzimuthalIntegrationMapping.h} | 6 +-- common/AzimuthalIntegrationProfile.cpp | 4 +- common/AzimuthalIntegrationProfile.h | 6 +-- common/CMakeLists.txt | 4 +- image_analysis/MXAnalysisWithoutFPGA.cpp | 2 +- image_analysis/MXAnalysisWithoutFPGA.h | 6 +-- image_analysis/azint/AzIntEngine.cpp | 2 +- image_analysis/azint/AzIntEngine.h | 6 +-- image_analysis/azint/AzIntEngineCPU.cpp | 2 +- image_analysis/azint/AzIntEngineCPU.h | 2 +- image_analysis/azint/AzIntEngineGPU.cu | 2 +- image_analysis/azint/AzIntEngineGPU.h | 2 +- .../spot_finding/ImageSpotFinderCPU.h | 2 +- reader/JFJochReaderDataset.h | 2 +- receiver/JFJochReceiver.cpp | 2 +- receiver/JFJochReceiver.h | 2 +- receiver/JFJochReceiverFPGA.h | 2 +- receiver/JFJochReceiverPlots.cpp | 2 +- receiver/JFJochReceiverPlots.h | 2 +- tests/AzimuthalIntegrationTest.cpp | 30 ++++++------- tests/HDF5WritingTest.cpp | 6 +-- tests/JFJochReaderTest.cpp | 4 +- tests/JFJochReceiverPlotsTest.cpp | 6 +-- tools/jfjoch_process.cpp | 4 +- viewer/JFJochImageReadingWorker.cpp | 2 +- viewer/JFJochImageReadingWorker.h | 2 +- 29 files changed, 81 insertions(+), 81 deletions(-) rename common/{AzimuthalIntegration.cpp => AzimuthalIntegrationMapping.cpp} (75%) rename common/{AzimuthalIntegration.h => AzimuthalIntegrationMapping.h} (92%) diff --git a/acquisition_device/AcquisitionDevice.cpp b/acquisition_device/AcquisitionDevice.cpp index c252376d..452338fa 100644 --- a/acquisition_device/AcquisitionDevice.cpp +++ b/acquisition_device/AcquisitionDevice.cpp @@ -200,7 +200,7 @@ void AcquisitionDevice::InitializeEmptyPixelMask(const DiffractionExperiment &ex void AcquisitionDevice::InitializeDataProcessing(const DiffractionExperiment &experiment, - const AzimuthalIntegration &azint) { + const AzimuthalIntegrationMapping &azint) { auto offset = experiment.GetFirstModuleOfDataStream(data_stream); size_t modules = experiment.GetModulesNum(data_stream); diff --git a/acquisition_device/AcquisitionDevice.h b/acquisition_device/AcquisitionDevice.h index 49e84a2d..be54b1c4 100644 --- a/acquisition_device/AcquisitionDevice.h +++ b/acquisition_device/AcquisitionDevice.h @@ -21,7 +21,7 @@ #include "Completion.h" #include "../fpga/pcie_driver/jfjoch_fpga.h" #include "../common/NetworkAddressConvert.h" -#include "../common/AzimuthalIntegration.h" +#include "../common/AzimuthalIntegrationMapping.h" struct AcquisitionDeviceStatistics { uint64_t good_packets; @@ -101,7 +101,7 @@ public: void InitializePixelMask(const DiffractionExperiment &experiment, const PixelMask &mask_raw); virtual void InitializePixelMask(const uint32_t *module_mask, size_t module_number); void InitializeROIMap(const DiffractionExperiment& experiment, const std::vector& raw_roi_map); - void InitializeDataProcessing(const DiffractionExperiment &experiment, const AzimuthalIntegration& azint); + void InitializeDataProcessing(const DiffractionExperiment &experiment, const AzimuthalIntegrationMapping& azint); const AcquisitionCounters& Counters() const; diff --git a/common/AzimuthalIntegration.cpp b/common/AzimuthalIntegrationMapping.cpp similarity index 75% rename from common/AzimuthalIntegration.cpp rename to common/AzimuthalIntegrationMapping.cpp index 4d1fa294..bb74eda4 100644 --- a/common/AzimuthalIntegration.cpp +++ b/common/AzimuthalIntegrationMapping.cpp @@ -3,12 +3,12 @@ #include -#include "AzimuthalIntegration.h" +#include "AzimuthalIntegrationMapping.h" #include "JFJochException.h" #include "DiffractionGeometry.h" #include "RawToConvertedGeometry.h" -AzimuthalIntegration::AzimuthalIntegration(const AzimuthalIntegrationSettings& in_settings, size_t width, size_t height, +AzimuthalIntegrationMapping::AzimuthalIntegrationMapping(const AzimuthalIntegrationSettings& in_settings, size_t width, size_t height, float wavelength) : settings(in_settings), width(width), height(height), wavelength(wavelength) { if (width <= 0) @@ -24,9 +24,9 @@ AzimuthalIntegration::AzimuthalIntegration(const AzimuthalIntegrationSettings& i "Cannot handle more than 65534 az. int. bins"); } -AzimuthalIntegration::AzimuthalIntegration(const DiffractionExperiment &experiment, +AzimuthalIntegrationMapping::AzimuthalIntegrationMapping(const DiffractionExperiment &experiment, const PixelMask& mask) - : AzimuthalIntegration(experiment.GetAzimuthalIntegrationSettings(), + : AzimuthalIntegrationMapping(experiment.GetAzimuthalIntegrationSettings(), experiment.GetXPixelsNum(), experiment.GetYPixelsNum(), experiment.GetWavelength_A()) { @@ -41,7 +41,7 @@ AzimuthalIntegration::AzimuthalIntegration(const DiffractionExperiment &experime UpdateMaxBinNumber(); } -void AzimuthalIntegration::SetupConvGeom(const DiffractionGeometry &geom, +void AzimuthalIntegrationMapping::SetupConvGeom(const DiffractionGeometry &geom, const std::vector &mask) { pixel_to_bin.resize(width * height, UINT16_MAX); pixel_resolution.resize(width * height, 0); @@ -54,7 +54,7 @@ void AzimuthalIntegration::SetupConvGeom(const DiffractionGeometry &geom, SetupPixel(geom, mask, row * width + col, col, row); } -void AzimuthalIntegration::SetupRawGeom(const DiffractionExperiment &experiment, +void AzimuthalIntegrationMapping::SetupRawGeom(const DiffractionExperiment &experiment, const std::vector &mask) { if (mask.size() != RAW_MODULE_SIZE * experiment.GetModulesNum()) throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Mask size invalid"); @@ -73,7 +73,7 @@ void AzimuthalIntegration::SetupRawGeom(const DiffractionExperiment &experiment, } } -void AzimuthalIntegration::SetupPixel(const DiffractionGeometry &geom, +void AzimuthalIntegrationMapping::SetupPixel(const DiffractionGeometry &geom, const std::vector &mask, uint32_t pxl, uint32_t col, uint32_t row) { if (mask[pxl] != 0) @@ -99,35 +99,35 @@ void AzimuthalIntegration::SetupPixel(const DiffractionGeometry &geom, } } -uint16_t AzimuthalIntegration::GetBinNumber() const { +uint16_t AzimuthalIntegrationMapping::GetBinNumber() const { return settings.GetBinCount(); } -const std::vector &AzimuthalIntegration::GetPixelToBin() const { +const std::vector &AzimuthalIntegrationMapping::GetPixelToBin() const { return pixel_to_bin; } -const std::vector &AzimuthalIntegration::GetBinToQ() const { +const std::vector &AzimuthalIntegrationMapping::GetBinToQ() const { return bin_to_q; } -const std::vector &AzimuthalIntegration::GetBinToD() const { +const std::vector &AzimuthalIntegrationMapping::GetBinToD() const { return bin_to_d; } -const std::vector &AzimuthalIntegration::GetBinToTwoTheta() const { +const std::vector &AzimuthalIntegrationMapping::GetBinToTwoTheta() const { return bin_to_2theta; } -const std::vector &AzimuthalIntegration::GetBinToPhi() const { +const std::vector &AzimuthalIntegrationMapping::GetBinToPhi() const { return bin_to_phi; } -uint16_t AzimuthalIntegration::QToBin(float q) const { +uint16_t AzimuthalIntegrationMapping::QToBin(float q) const { return settings.QToBin(q); } -void AzimuthalIntegration::UpdateMaxBinNumber() { +void AzimuthalIntegrationMapping::UpdateMaxBinNumber() { bin_to_q.resize(settings.GetBinCount()); bin_to_d.resize(settings.GetBinCount()); bin_to_2theta.resize(settings.GetBinCount()); @@ -144,30 +144,30 @@ void AzimuthalIntegration::UpdateMaxBinNumber() { } } -const std::vector &AzimuthalIntegration::Corrections() const { +const std::vector &AzimuthalIntegrationMapping::Corrections() const { return corrections; } -const std::vector &AzimuthalIntegration::Resolution() const { +const std::vector &AzimuthalIntegrationMapping::Resolution() const { return pixel_resolution; } -const AzimuthalIntegrationSettings &AzimuthalIntegration::Settings() const { +const AzimuthalIntegrationSettings &AzimuthalIntegrationMapping::Settings() const { return settings; } -size_t AzimuthalIntegration::GetWidth() const { +size_t AzimuthalIntegrationMapping::GetWidth() const { return width; } -size_t AzimuthalIntegration::GetHeight() const { +size_t AzimuthalIntegrationMapping::GetHeight() const { return height; } -int32_t AzimuthalIntegration::GetAzimuthalBinCount() const { +int32_t AzimuthalIntegrationMapping::GetAzimuthalBinCount() const { return settings.GetAzimuthalBinCount(); } -int32_t AzimuthalIntegration::GetQBinCount() const { +int32_t AzimuthalIntegrationMapping::GetQBinCount() const { return settings.GetQBinCount(); } \ No newline at end of file diff --git a/common/AzimuthalIntegration.h b/common/AzimuthalIntegrationMapping.h similarity index 92% rename from common/AzimuthalIntegration.h rename to common/AzimuthalIntegrationMapping.h index 0ef3a5e9..9a84dd4d 100644 --- a/common/AzimuthalIntegration.h +++ b/common/AzimuthalIntegrationMapping.h @@ -8,7 +8,7 @@ #include "DiffractionExperiment.h" #include "PixelMask.h" -class AzimuthalIntegration { +class AzimuthalIntegrationMapping { protected: const AzimuthalIntegrationSettings settings; const float wavelength; @@ -26,7 +26,7 @@ protected: std::optional polarization_factor; void UpdateMaxBinNumber(); - AzimuthalIntegration(const AzimuthalIntegrationSettings& settings, + AzimuthalIntegrationMapping(const AzimuthalIntegrationSettings& settings, size_t width, size_t height, float wavelength); void SetupRawGeom(const DiffractionExperiment& experiment, @@ -39,7 +39,7 @@ protected: uint32_t pxl, uint32_t col, uint32_t row); public: - AzimuthalIntegration(const DiffractionExperiment& experiment, + AzimuthalIntegrationMapping(const DiffractionExperiment& experiment, const PixelMask& mask); [[nodiscard]] uint16_t GetBinNumber() const; diff --git a/common/AzimuthalIntegrationProfile.cpp b/common/AzimuthalIntegrationProfile.cpp index b76102a4..d1f128c9 100644 --- a/common/AzimuthalIntegrationProfile.cpp +++ b/common/AzimuthalIntegrationProfile.cpp @@ -11,7 +11,7 @@ inline float sum_to_count(float sum, uint64_t count) { return sum / (static_cast(count)); } -AzimuthalIntegrationProfile::AzimuthalIntegrationProfile(const AzimuthalIntegration &mapping) +AzimuthalIntegrationProfile::AzimuthalIntegrationProfile(const AzimuthalIntegrationMapping &mapping) : sum(mapping.GetBinNumber(), 0), sum2(mapping.GetBinNumber(), 0), count(mapping.GetBinNumber(), 0), @@ -23,7 +23,7 @@ AzimuthalIntegrationProfile::AzimuthalIntegrationProfile(const AzimuthalIntegrat azim_bins(mapping.GetAzimuthalBinCount()) { } -void AzimuthalIntegrationProfile::Clear(const AzimuthalIntegration &mapping) { +void AzimuthalIntegrationProfile::Clear(const AzimuthalIntegrationMapping &mapping) { std::unique_lock ul(m); bin_to_d = mapping.GetBinToD(); diff --git a/common/AzimuthalIntegrationProfile.h b/common/AzimuthalIntegrationProfile.h index 25cf4ca2..fb78fbaa 100644 --- a/common/AzimuthalIntegrationProfile.h +++ b/common/AzimuthalIntegrationProfile.h @@ -8,7 +8,7 @@ #include #include "MultiLinePlot.h" -#include "AzimuthalIntegration.h" +#include "AzimuthalIntegrationMapping.h" #include "../acquisition_device/AcquisitionDevice.h" class AzimuthalIntegrationProfile { @@ -28,8 +28,8 @@ class AzimuthalIntegrationProfile { const std::vector& GetXAxis(PlotAzintUnit unit) const; public: - explicit AzimuthalIntegrationProfile(const AzimuthalIntegration &mapping); - void Clear(const AzimuthalIntegration &mapping); + explicit AzimuthalIntegrationProfile(const AzimuthalIntegrationMapping &mapping); + void Clear(const AzimuthalIntegrationMapping &mapping); void SetTitle(const std::string& input); void Add(const DeviceOutput &result); void Add(const std::vector &sum, const std::vector &count); diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index a69422da..93aa8b70 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -72,8 +72,8 @@ ADD_LIBRARY(JFJochCommon STATIC AzimuthalIntegrationSettings.h AzimuthalIntegrationProfile.h AzimuthalIntegrationProfile.cpp - AzimuthalIntegration.h - AzimuthalIntegration.cpp + AzimuthalIntegrationMapping.h + AzimuthalIntegrationMapping.cpp CheckPath.h AutoIncrVector.h ModuleSummation.cpp diff --git a/image_analysis/MXAnalysisWithoutFPGA.cpp b/image_analysis/MXAnalysisWithoutFPGA.cpp index 30d92ab4..c7e55fb6 100644 --- a/image_analysis/MXAnalysisWithoutFPGA.cpp +++ b/image_analysis/MXAnalysisWithoutFPGA.cpp @@ -22,7 +22,7 @@ MXAnalysisWithoutFPGA::MXAnalysisWithoutFPGA(const DiffractionExperiment &in_experiment, - const AzimuthalIntegration &in_integration, + const AzimuthalIntegrationMapping &in_integration, const PixelMask &in_mask, IndexAndRefine &in_indexer) : experiment(in_experiment), diff --git a/image_analysis/MXAnalysisWithoutFPGA.h b/image_analysis/MXAnalysisWithoutFPGA.h index 9deca52d..778e0953 100644 --- a/image_analysis/MXAnalysisWithoutFPGA.h +++ b/image_analysis/MXAnalysisWithoutFPGA.h @@ -8,7 +8,7 @@ #include "../common/JFJochMessages.h" #include "../common/DiffractionExperiment.h" -#include "../common/AzimuthalIntegration.h" +#include "../common/AzimuthalIntegrationMapping.h" #include "../common/PixelMask.h" #include "../common/AzimuthalIntegrationProfile.h" #include "bragg_prediction/BraggPrediction.h" @@ -22,7 +22,7 @@ // MXAnalysisWithoutFPGA is not thread safe - it has to owned by a single thread class MXAnalysisWithoutFPGA { const DiffractionExperiment &experiment; - const AzimuthalIntegration &integration; + const AzimuthalIntegrationMapping &integration; std::vector decompression_buffer; @@ -43,7 +43,7 @@ class MXAnalysisWithoutFPGA { float mask_low_res; void UpdateMaskResolution(const SpotFindingSettings& settings); public: - MXAnalysisWithoutFPGA(const DiffractionExperiment &experiment, const AzimuthalIntegration &integration, + MXAnalysisWithoutFPGA(const DiffractionExperiment &experiment, const AzimuthalIntegrationMapping &integration, const PixelMask &mask, IndexAndRefine &indexer); void Analyze(DataMessage &output, AzimuthalIntegrationProfile &profile, const SpotFindingSettings &spot_finding_settings); }; diff --git a/image_analysis/azint/AzIntEngine.cpp b/image_analysis/azint/AzIntEngine.cpp index d5b28cea..27d0d462 100644 --- a/image_analysis/azint/AzIntEngine.cpp +++ b/image_analysis/azint/AzIntEngine.cpp @@ -3,7 +3,7 @@ #include "AzIntEngine.h" -AzIntEngine::AzIntEngine(const AzimuthalIntegration &integration) +AzIntEngine::AzIntEngine(const AzimuthalIntegrationMapping &integration) : integration(integration), npixel(integration.GetPixelToBin().size()), azint_sum(integration.GetBinNumber(), 0.0f), diff --git a/image_analysis/azint/AzIntEngine.h b/image_analysis/azint/AzIntEngine.h index adedb96f..f8e32096 100644 --- a/image_analysis/azint/AzIntEngine.h +++ b/image_analysis/azint/AzIntEngine.h @@ -3,7 +3,7 @@ #pragma once -#include "../../common/AzimuthalIntegration.h" +#include "../../common/AzimuthalIntegrationMapping.h" #include "../../common/AzimuthalIntegrationProfile.h" #include "../image_preprocessing/ImagePreprocessorBuffer.h" @@ -11,12 +11,12 @@ class AzIntEngine { protected: const uint16_t azint_bins; const size_t npixel; - const AzimuthalIntegration& integration; + const AzimuthalIntegrationMapping& integration; std::vector azint_sum; std::vector azint_sum2; std::vector azint_count; public: - AzIntEngine(const AzimuthalIntegration& integration); + AzIntEngine(const AzimuthalIntegrationMapping& integration); virtual ~AzIntEngine() = default; virtual void Run(const ImagePreprocessorBuffer &image, AzimuthalIntegrationProfile &profile) = 0; }; diff --git a/image_analysis/azint/AzIntEngineCPU.cpp b/image_analysis/azint/AzIntEngineCPU.cpp index ab706bb8..afaa6ebb 100644 --- a/image_analysis/azint/AzIntEngineCPU.cpp +++ b/image_analysis/azint/AzIntEngineCPU.cpp @@ -3,7 +3,7 @@ #include "AzIntEngineCPU.h" -AzIntEngineCPU::AzIntEngineCPU(const AzimuthalIntegration &integration) +AzIntEngineCPU::AzIntEngineCPU(const AzimuthalIntegrationMapping &integration) : AzIntEngine(integration) {} void AzIntEngineCPU::Run(const ImagePreprocessorBuffer &image, AzimuthalIntegrationProfile &profile){ diff --git a/image_analysis/azint/AzIntEngineCPU.h b/image_analysis/azint/AzIntEngineCPU.h index 9eeec271..d89c211d 100644 --- a/image_analysis/azint/AzIntEngineCPU.h +++ b/image_analysis/azint/AzIntEngineCPU.h @@ -7,6 +7,6 @@ class AzIntEngineCPU : public AzIntEngine { public: - AzIntEngineCPU(const AzimuthalIntegration& integration); + AzIntEngineCPU(const AzimuthalIntegrationMapping& integration); void Run(const ImagePreprocessorBuffer &image, AzimuthalIntegrationProfile &profile) override; }; \ No newline at end of file diff --git a/image_analysis/azint/AzIntEngineGPU.cu b/image_analysis/azint/AzIntEngineGPU.cu index 9700777f..dfc81076 100644 --- a/image_analysis/azint/AzIntEngineGPU.cu +++ b/image_analysis/azint/AzIntEngineGPU.cu @@ -88,7 +88,7 @@ void gpu_azim( } } -AzIntEngineGPU::AzIntEngineGPU(const AzimuthalIntegration &integration, std::shared_ptr stream) +AzIntEngineGPU::AzIntEngineGPU(const AzimuthalIntegrationMapping &integration, std::shared_ptr stream) : AzIntEngine(integration), stream(stream), gpu_azint_correction(npixel), diff --git a/image_analysis/azint/AzIntEngineGPU.h b/image_analysis/azint/AzIntEngineGPU.h index ad01b9fa..08394373 100644 --- a/image_analysis/azint/AzIntEngineGPU.h +++ b/image_analysis/azint/AzIntEngineGPU.h @@ -23,6 +23,6 @@ class AzIntEngineGPU : public AzIntEngine { CudaRegisteredVector cpu_sum2_reg; CudaRegisteredVector cpu_count_reg; public: - AzIntEngineGPU(const AzimuthalIntegration& integration, std::shared_ptr stream); + AzIntEngineGPU(const AzimuthalIntegrationMapping& integration, std::shared_ptr stream); void Run(const ImagePreprocessorBuffer &image, AzimuthalIntegrationProfile &profile) override; }; diff --git a/image_analysis/spot_finding/ImageSpotFinderCPU.h b/image_analysis/spot_finding/ImageSpotFinderCPU.h index 422222fa..497d09e4 100644 --- a/image_analysis/spot_finding/ImageSpotFinderCPU.h +++ b/image_analysis/spot_finding/ImageSpotFinderCPU.h @@ -10,7 +10,7 @@ #include "ImageSpotFinder.h" #include "SpotFindingSettings.h" -#include "../../common/AzimuthalIntegration.h" +#include "../../common/AzimuthalIntegrationMapping.h" #include "../../common/DiffractionSpot.h" // This is "slow" spot finder for image-based analysis diff --git a/reader/JFJochReaderDataset.h b/reader/JFJochReaderDataset.h index b1268f94..e13c100b 100644 --- a/reader/JFJochReaderDataset.h +++ b/reader/JFJochReaderDataset.h @@ -11,7 +11,7 @@ #include "../common/DiffractionGeometry.h" #include "../common/DiffractionExperiment.h" #include "../common/PixelMask.h" -#include "../common/AzimuthalIntegration.h" +#include "../common/AzimuthalIntegrationMapping.h" struct JFJochReaderDataset { std::string arm_date; diff --git a/receiver/JFJochReceiver.cpp b/receiver/JFJochReceiver.cpp index 153f193a..5e560d18 100644 --- a/receiver/JFJochReceiver.cpp +++ b/receiver/JFJochReceiver.cpp @@ -46,7 +46,7 @@ JFJochReceiver::JFJochReceiver(const DiffractionExperiment &in_experiment, current_status.SetStatus(JFJochReceiverStatus{}); // GetStatus() is virtual function and cannot be called yet! auto start_time_point = std::chrono::steady_clock::now(); - az_int_mapping = std::make_unique(experiment, pixel_mask); + az_int_mapping = std::make_unique(experiment, pixel_mask); auto end_time_point = std::chrono::steady_clock::now(); auto duration = std::chrono::duration(end_time_point - start_time_point); logger.Info("Azimuthal integration mapping done in {:.5f} s", duration.count()); diff --git a/receiver/JFJochReceiver.h b/receiver/JFJochReceiver.h index d415aadb..8cd169e3 100644 --- a/receiver/JFJochReceiver.h +++ b/receiver/JFJochReceiver.h @@ -82,7 +82,7 @@ protected: std::vector> adu_histogram_module; PixelMask pixel_mask; - std::unique_ptr az_int_mapping; + std::unique_ptr az_int_mapping; std::optional max_delay; std::mutex max_delay_mutex; diff --git a/receiver/JFJochReceiverFPGA.h b/receiver/JFJochReceiverFPGA.h index fcbbc7ae..66c5e2f2 100644 --- a/receiver/JFJochReceiverFPGA.h +++ b/receiver/JFJochReceiverFPGA.h @@ -24,7 +24,7 @@ #include "../common/PixelMask.h" #include "../image_analysis/spot_finding/StrongPixelSet.h" -#include "../common/AzimuthalIntegration.h" +#include "../common/AzimuthalIntegrationMapping.h" #include "../common/AzimuthalIntegrationProfile.h" #include "../jungfrau/JFCalibration.h" diff --git a/receiver/JFJochReceiverPlots.cpp b/receiver/JFJochReceiverPlots.cpp index b7fb3ca3..00e4ebb6 100644 --- a/receiver/JFJochReceiverPlots.cpp +++ b/receiver/JFJochReceiverPlots.cpp @@ -41,7 +41,7 @@ MultiLinePlot JFJochReceiverPlots::GetROIPlot(PlotType type, int64_t nbins, floa return ret; } -void JFJochReceiverPlots::Setup(const DiffractionExperiment &experiment, const AzimuthalIntegration &mapping) { +void JFJochReceiverPlots::Setup(const DiffractionExperiment &experiment, const AzimuthalIntegrationMapping &mapping) { std::unique_lock ul(m); az_int_profile = std::make_unique(mapping); diff --git a/receiver/JFJochReceiverPlots.h b/receiver/JFJochReceiverPlots.h index d95b82c4..ab38d9e9 100644 --- a/receiver/JFJochReceiverPlots.h +++ b/receiver/JFJochReceiverPlots.h @@ -104,7 +104,7 @@ class JFJochReceiverPlots { MultiLinePlot GetROIPlot(PlotType type, int64_t nbins, float start, float incr, const std::optional &fill_value) const; public: - void Setup(const DiffractionExperiment& experiment, const AzimuthalIntegration& mapping); + void Setup(const DiffractionExperiment& experiment, const AzimuthalIntegrationMapping& mapping); void Add(const DataMessage& msg, const AzimuthalIntegrationProfile &profile); void AddEmptyImage(const DataMessage& msg); diff --git a/tests/AzimuthalIntegrationTest.cpp b/tests/AzimuthalIntegrationTest.cpp index ad8e4b3c..9dd030db 100644 --- a/tests/AzimuthalIntegrationTest.cpp +++ b/tests/AzimuthalIntegrationTest.cpp @@ -4,19 +4,19 @@ #include #include "../common/AzimuthalIntegrationProfile.h" -#include "../common/AzimuthalIntegration.h" +#include "../common/AzimuthalIntegrationMapping.h" TEST_CASE("AzimuthalIntegrationMapping_Constructor","[AzimuthalIntegration]") { DiffractionExperiment x(DetJF4M()); REQUIRE(x.GetPixelsNum() == 2164*2068); - std::unique_ptr radial; + std::unique_ptr radial; x.QSpacingForAzimInt_recipA(0.1).QRangeForAzimInt_recipA(0.1, 5); PixelMask pixel_mask(x); - REQUIRE_NOTHROW(radial = std::make_unique(x, pixel_mask)); + REQUIRE_NOTHROW(radial = std::make_unique(x, pixel_mask)); } TEST_CASE("AzimuthalIntegrationMapping_Create_16M","[AzimuthalIntegration]") { @@ -25,7 +25,7 @@ TEST_CASE("AzimuthalIntegrationMapping_Create_16M","[AzimuthalIntegration]") { x.QSpacingForAzimInt_recipA(0.1).QRangeForAzimInt_recipA(0.1, 10); PixelMask pixel_mask(x); - AzimuthalIntegration mapping(x, pixel_mask); + AzimuthalIntegrationMapping mapping(x, pixel_mask); REQUIRE(mapping.GetBinNumber() == 99); } @@ -35,7 +35,7 @@ TEST_CASE("AzimuthalIntegrationMapping_GetBinNumber","[AzimuthalIntegration]") { x.QSpacingForAzimInt_recipA(0.1).QRangeForAzimInt_recipA(0.1, 4); PixelMask pixel_mask(x); - AzimuthalIntegration mapping(x, pixel_mask); + AzimuthalIntegrationMapping mapping(x, pixel_mask); REQUIRE(mapping.GetBinNumber() == 39); } @@ -57,7 +57,7 @@ TEST_CASE("AzimuthalIntegrationMapping_GetBinNumber_mask","[AzimuthalIntegration PixelMask pixel_mask_obj(x); pixel_mask_obj.LoadUserMask(x, pixel_mask); - AzimuthalIntegration mapping(x, pixel_mask_obj); + AzimuthalIntegrationMapping mapping(x, pixel_mask_obj); REQUIRE(mapping.GetBinNumber() == 89); } @@ -67,7 +67,7 @@ TEST_CASE("AzimuthalIntegrationMapping_GetBinNumber_DetectorLimit","[AzimuthalIn x.QSpacingForAzimInt_recipA(0.1).QRangeForAzimInt_recipA(0.1, 9.9); PixelMask pixel_mask(x); - AzimuthalIntegration mapping(x, pixel_mask); + AzimuthalIntegrationMapping mapping(x, pixel_mask); REQUIRE(mapping.GetBinNumber() == 98); } @@ -78,7 +78,7 @@ TEST_CASE("AzimuthalIntegrationMapping_GetBinToQ","[AzimuthalIntegration]") { x.QSpacingForAzimInt_recipA(0.1).QRangeForAzimInt_recipA(0.1, 4); PixelMask pixel_mask(x); - AzimuthalIntegration mapping(x, pixel_mask); + AzimuthalIntegrationMapping mapping(x, pixel_mask); auto bin_to_q = mapping.GetBinToQ(); @@ -99,7 +99,7 @@ TEST_CASE("AzimuthalIntegrationMapping_GetBinToPhi","[AzimuthalIntegration]") { x.ImportAzimuthalIntegrationSettings(settings); PixelMask pixel_mask(x); - AzimuthalIntegration mapping(x, pixel_mask); + AzimuthalIntegrationMapping mapping(x, pixel_mask); auto &bin_to_q = mapping.GetBinToQ(); @@ -144,7 +144,7 @@ TEST_CASE("AzimuthalIntegrationMapping_GetMapping","[AzimuthalIntegration]") { x.ImportAzimuthalIntegrationSettings(settings); PixelMask pixel_mask(x); - AzimuthalIntegration mapping(x, pixel_mask); + AzimuthalIntegrationMapping mapping(x, pixel_mask); auto map = mapping.GetPixelToBin(); @@ -163,7 +163,7 @@ TEST_CASE("AzimuthalIntegrationMapping_QToBin","[AzimuthalIntegration]") { x.QSpacingForAzimInt_recipA(0.1).QRangeForAzimInt_recipA(0.1, 4); PixelMask pixel_mask(x); - AzimuthalIntegration mapping(x, pixel_mask); + AzimuthalIntegrationMapping mapping(x, pixel_mask); REQUIRE(mapping.QToBin(0.0) == 0); REQUIRE(std::floor(mapping.QToBin(0.200001)) == 1); @@ -177,7 +177,7 @@ TEST_CASE("AzimuthalIntegrationProfile","[AzimuthalIntegration]") { x.QSpacingForAzimInt_recipA(0.1).QRangeForAzimInt_recipA(0.1, 4); PixelMask pixel_mask(x); - AzimuthalIntegration mapping(x, pixel_mask); + AzimuthalIntegrationMapping mapping(x, pixel_mask); AzimuthalIntegrationProfile profile(mapping); @@ -214,7 +214,7 @@ TEST_CASE("AzimuthalIntegrationProfile_operatorAdd","[AzimuthalIntegration]") { x.QSpacingForAzimInt_recipA(0.1).QRangeForAzimInt_recipA(0.1, 4); PixelMask pixel_mask(x); - AzimuthalIntegration mapping(x, pixel_mask); + AzimuthalIntegrationMapping mapping(x, pixel_mask); AzimuthalIntegrationProfile profile0(mapping), profile1(mapping); @@ -245,7 +245,7 @@ TEST_CASE("AzimuthalIntegrationProfile_GetMeanValueOfBins","[AzimuthalIntegratio x.QSpacingForAzimInt_recipA(0.1).QRangeForAzimInt_recipA(0.1, 4); PixelMask pixel_mask(x); - AzimuthalIntegration mapping(x, pixel_mask); + AzimuthalIntegrationMapping mapping(x, pixel_mask); AzimuthalIntegrationProfile profile(mapping); @@ -278,7 +278,7 @@ TEST_CASE("AzimuthalIntegrationProfile_GetResult1D","[AzimuthalIntegration]") { x.ImportAzimuthalIntegrationSettings(settings); PixelMask pixel_mask(x); - AzimuthalIntegration mapping(x, pixel_mask); + AzimuthalIntegrationMapping mapping(x, pixel_mask); AzimuthalIntegrationProfile profile(mapping); REQUIRE(mapping.GetQBinCount() == 3); diff --git a/tests/HDF5WritingTest.cpp b/tests/HDF5WritingTest.cpp index 7c910c7f..32e95ae8 100644 --- a/tests/HDF5WritingTest.cpp +++ b/tests/HDF5WritingTest.cpp @@ -442,7 +442,7 @@ TEST_CASE("HDF5MasterFile_RadInt", "[HDF5][Full]") { x.FilePrefix("test01_rad_int").ImagesPerTrigger(950); PixelMask pixel_mask(x); - AzimuthalIntegration mapping(x, pixel_mask); + AzimuthalIntegrationMapping mapping(x, pixel_mask); AzimuthalIntegrationProfile profile(mapping); StartMessage start_message; @@ -622,7 +622,7 @@ TEST_CASE("HDF5Writer_Rad_Int_Profile", "[HDF5][Full]") { x.QSpacingForAzimInt_recipA(0.1).QRangeForAzimInt_recipA(0.1, 4.0); PixelMask pixel_mask(x); - AzimuthalIntegration mapping(x, pixel_mask); + AzimuthalIntegrationMapping mapping(x, pixel_mask); std::vector rad_int_profile(mapping.GetBinNumber(), 4.0); std::vector rad_int_avg(mapping.GetBinNumber(), 0.33); @@ -989,7 +989,7 @@ TEST_CASE("HDF5Writer_NXmxIntegrated_AzInt", "[HDF5][Full]") { x.SetFileWriterFormat(FileWriterFormat::NXmxIntegrated).OverwriteExistingFiles(true); PixelMask pixel_mask(x); - AzimuthalIntegration mapping(x, pixel_mask); + AzimuthalIntegrationMapping mapping(x, pixel_mask); { RegisterHDF5Filter(); diff --git a/tests/JFJochReaderTest.cpp b/tests/JFJochReaderTest.cpp index 221d43fe..9abb8401 100644 --- a/tests/JFJochReaderTest.cpp +++ b/tests/JFJochReaderTest.cpp @@ -949,7 +949,7 @@ TEST_CASE("JFJochReader_Azint", "[HDF5][Full]") { std::vector image(x.GetPixelsNum()); - AzimuthalIntegration azint(x, PixelMask(x)); + AzimuthalIntegrationMapping azint(x, PixelMask(x)); RegisterHDF5Filter(); { StartMessage start_message; @@ -1433,7 +1433,7 @@ TEST_CASE("JFJochReader_NXmxIntegrated", "[HDF5][Full]") { image[1] = 123; image[5678] = 321; - AzimuthalIntegration azint(x, PixelMask(x)); + AzimuthalIntegrationMapping azint(x, PixelMask(x)); RegisterHDF5Filter(); { diff --git a/tests/JFJochReceiverPlotsTest.cpp b/tests/JFJochReceiverPlotsTest.cpp index d2b0e238..6848eeac 100644 --- a/tests/JFJochReceiverPlotsTest.cpp +++ b/tests/JFJochReceiverPlotsTest.cpp @@ -9,7 +9,7 @@ TEST_CASE("JFJochReceiverPlots") { experiment.Goniometer(GoniometerAxis("omega", 15, 2, Coord(0,1,0), {})); PixelMask mask(experiment); - AzimuthalIntegration integration(experiment, mask); + AzimuthalIntegrationMapping integration(experiment, mask); JFJochReceiverPlots plots; plots.Setup(experiment, integration); @@ -48,7 +48,7 @@ TEST_CASE("JFJochReceiverPlots_Angle") { experiment.Goniometer(GoniometerAxis("omega", 15, 2, Coord(0,1,0), {})); PixelMask mask(experiment); - AzimuthalIntegration integration(experiment, mask); + AzimuthalIntegrationMapping integration(experiment, mask); JFJochReceiverPlots plots; plots.Setup(experiment, integration); @@ -91,7 +91,7 @@ TEST_CASE("JFJochReceiverPlots_Grid") { experiment.ImportDatasetSettings(dataset); PixelMask mask(experiment); - AzimuthalIntegration integration(experiment, mask); + AzimuthalIntegrationMapping integration(experiment, mask); JFJochReceiverPlots plots; plots.Setup(experiment, integration); diff --git a/tools/jfjoch_process.cpp b/tools/jfjoch_process.cpp index 9c4dd593..82c25125 100644 --- a/tools/jfjoch_process.cpp +++ b/tools/jfjoch_process.cpp @@ -16,7 +16,7 @@ #include "../common/Logger.h" #include "../common/DiffractionExperiment.h" #include "../common/PixelMask.h" -#include "../common/AzimuthalIntegration.h" +#include "../common/AzimuthalIntegrationMapping.h" #include "../common/time_utc.h" #include "../common/print_license.h" #include "../image_analysis/MXAnalysisWithoutFPGA.h" @@ -346,7 +346,7 @@ int main(int argc, char **argv) { // If dataset has a mask you wish to use, you might need to load it into pixel_mask here // e.g. pixel_mask.LoadUserMask(dataset->pixel_mask, ...); - AzimuthalIntegration mapping(experiment, pixel_mask); + AzimuthalIntegrationMapping mapping(experiment, pixel_mask); IndexerThreadPool indexer_pool(experiment.GetIndexingSettings()); // Statistics collector diff --git a/viewer/JFJochImageReadingWorker.cpp b/viewer/JFJochImageReadingWorker.cpp index f6b590f9..67062c67 100644 --- a/viewer/JFJochImageReadingWorker.cpp +++ b/viewer/JFJochImageReadingWorker.cpp @@ -296,7 +296,7 @@ void JFJochImageReadingWorker::LoadImage(int64_t image_number, int64_t summation void JFJochImageReadingWorker::UpdateAzint_i(const JFJochReaderDataset *dataset) { if (dataset) { - azint_mapping = std::make_unique(curr_experiment, dataset->pixel_mask); + azint_mapping = std::make_unique(curr_experiment, dataset->pixel_mask); index_and_refine = std::make_unique(curr_experiment, indexing.get()); image_analysis = std::make_unique(curr_experiment, *azint_mapping, dataset->pixel_mask, *index_and_refine.get()); diff --git a/viewer/JFJochImageReadingWorker.h b/viewer/JFJochImageReadingWorker.h index 67e21faa..8bb57ae5 100644 --- a/viewer/JFJochImageReadingWorker.h +++ b/viewer/JFJochImageReadingWorker.h @@ -52,7 +52,7 @@ private: std::unique_ptr indexing; std::shared_ptr current_image_ptr; - std::unique_ptr azint_mapping; + std::unique_ptr azint_mapping; std::unique_ptr image_analysis; std::unique_ptr index_and_refine; -- 2.52.0 From 37495c0902facdea0011e57909db35923098b29c Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Thu, 30 Apr 2026 10:45:13 +0200 Subject: [PATCH 3/7] DectrisSimplonClient: Set energy/threshold for each acquisition (if different from currently configured by 0.01 eV) --- detector_control/DectrisSimplonClient.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/detector_control/DectrisSimplonClient.cpp b/detector_control/DectrisSimplonClient.cpp index 90ea7e39..1170fc51 100644 --- a/detector_control/DectrisSimplonClient.cpp +++ b/detector_control/DectrisSimplonClient.cpp @@ -247,6 +247,10 @@ void DectrisSimplonClient::EndAcquisitionFinished() { } void DectrisSimplonClient::StartAcquisition(const DiffractionExperiment& experiment) { + SetConfigIfDifferent(SimplonModule::Detector, "photon_energy", experiment.GetIncidentEnergy_keV() * 1e3f, 0.01f); + auto thr = experiment.GetEigerThreshold_keV(); + SetConfigIfDifferent(SimplonModule::Detector, "threshold_energy", thr * 1e3f, 0.01); + SetConfigIfDifferent(SimplonModule::Detector, "count_time", std::chrono::duration(experiment.GetFrameCountTime()).count(), 1e-9); SetConfigIfDifferent(SimplonModule::Detector, "frame_time", std::chrono::duration(experiment.GetFrameTime()).count(), 1e-9); SetConfigIfDifferent(SimplonModule::Detector, "nimages", experiment.GetFrameNumPerTrigger()); -- 2.52.0 From c7f2cad73fbd4ad837cb126592e262ebd3cbb182 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Thu, 30 Apr 2026 11:15:39 +0200 Subject: [PATCH 4/7] AzimuthalIntegrationMapping: Parallel calculation of azimuthal integration mapping --- common/AzimuthalIntegrationMapping.cpp | 102 +++++++++++++++++++------ common/AzimuthalIntegrationMapping.h | 16 ++-- receiver/JFJochReceiver.cpp | 2 +- tests/AzimuthalIntegrationTest.cpp | 96 +++++++++++++++++++++++ 4 files changed, 183 insertions(+), 33 deletions(-) diff --git a/common/AzimuthalIntegrationMapping.cpp b/common/AzimuthalIntegrationMapping.cpp index bb74eda4..03480451 100644 --- a/common/AzimuthalIntegrationMapping.cpp +++ b/common/AzimuthalIntegrationMapping.cpp @@ -2,15 +2,22 @@ // SPDX-License-Identifier: GPL-3.0-only #include +#include +#include #include "AzimuthalIntegrationMapping.h" #include "JFJochException.h" #include "DiffractionGeometry.h" #include "RawToConvertedGeometry.h" -AzimuthalIntegrationMapping::AzimuthalIntegrationMapping(const AzimuthalIntegrationSettings& in_settings, size_t width, size_t height, - float wavelength) - : settings(in_settings), width(width), height(height), wavelength(wavelength) { +AzimuthalIntegrationMapping::AzimuthalIntegrationMapping(const DiffractionExperiment &experiment, + const PixelMask& mask, + size_t in_nthreads) + : settings(experiment.GetAzimuthalIntegrationSettings()), + wavelength(experiment.GetWavelength_A()), + width(experiment.GetXPixelsNumConv()), + height(experiment.GetYPixelsNumConv()) { + if (width <= 0) throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Detector width must be above 0"); @@ -22,40 +29,60 @@ AzimuthalIntegrationMapping::AzimuthalIntegrationMapping(const AzimuthalIntegrat if (settings.GetBinCount() >= UINT16_MAX) throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Cannot handle more than 65534 az. int. bins"); -} - -AzimuthalIntegrationMapping::AzimuthalIntegrationMapping(const DiffractionExperiment &experiment, - const PixelMask& mask) - : AzimuthalIntegrationMapping(experiment.GetAzimuthalIntegrationSettings(), - experiment.GetXPixelsNum(), - experiment.GetYPixelsNum(), - experiment.GetWavelength_A()) { polarization_factor = experiment.GetPolarizationFactor(); - if (!experiment.IsGeometryTransformed()) - SetupRawGeom(experiment, mask.GetMaskRaw(experiment)); + if (in_nthreads == 0) + nthreads = std::thread::hardware_concurrency(); else - SetupConvGeom(experiment.GetDiffractionGeometry(),mask.GetMask()); + nthreads = in_nthreads; + + nthreads = std::clamp(nthreads, 1, 64); + + if (!experiment.IsGeometryTransformed()) + SetupRawGeom(experiment, mask.GetMaskRaw(experiment), nthreads); + else + SetupConvGeom(experiment.GetDiffractionGeometry(),mask.GetMask(), nthreads); UpdateMaxBinNumber(); } +void AzimuthalIntegrationMapping::SetupConvGeomRows(const DiffractionGeometry &geom, const std::vector &mask, + size_t row0, size_t row_end) { + for (size_t row = row0; row < row_end && row < height; row++) { + for (size_t col = 0; col < width; col++) + SetupPixel(geom, mask, row * width + col, col, row); + } +} + void AzimuthalIntegrationMapping::SetupConvGeom(const DiffractionGeometry &geom, - const std::vector &mask) { + const std::vector &mask, + size_t nthreads) { pixel_to_bin.resize(width * height, UINT16_MAX); pixel_resolution.resize(width * height, 0); corrections.resize(width * height, 0); if (mask.size() != width * height) throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Mask size invalid"); - for (int row = 0; row < height; row++) - for (int col = 0; col < width; col++) - SetupPixel(geom, mask, row * width + col, col, row); + + if (nthreads <= 1) { + SetupConvGeomRows(geom, mask, 0, height); + } else { + nthreads = std::min(nthreads, height); + std::vector> futures; + + for (size_t t = 0; t < nthreads; ++t) + futures.emplace_back(std::async(std::launch::async, + &AzimuthalIntegrationMapping::SetupConvGeomRows, + this, std::cref(geom), std::cref(mask), t * height / nthreads, (t + 1) * height / nthreads)); + + for (auto &f: futures) + f.get(); + } } void AzimuthalIntegrationMapping::SetupRawGeom(const DiffractionExperiment &experiment, - const std::vector &mask) { + const std::vector &mask, size_t nthreads) { if (mask.size() != RAW_MODULE_SIZE * experiment.GetModulesNum()) throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Mask size invalid"); @@ -65,11 +92,34 @@ void AzimuthalIntegrationMapping::SetupRawGeom(const DiffractionExperiment &expe auto geom = experiment.GetDiffractionGeometry(); - for (int m = 0; m < experiment.GetModulesNum(); m++) { - for (int pxl = 0; pxl < RAW_MODULE_SIZE; pxl++) { - auto [x,y] = RawToConvertedCoordinate(experiment, m, pxl); - SetupPixel(geom, mask, m * RAW_MODULE_SIZE + pxl, x, y); + if (nthreads <= 1) { + for (int m = 0; m < experiment.GetModulesNum(); m++) { + for (int pxl = 0; pxl < RAW_MODULE_SIZE; pxl++) { + auto [x,y] = RawToConvertedCoordinate(experiment, m, pxl); + SetupPixel(geom, mask, m * RAW_MODULE_SIZE + pxl, x, y); + } } + } else { + nthreads = std::min(nthreads, experiment.GetModulesNum()); + std::vector> futures; + futures.reserve(nthreads); + + for (size_t t = 0; t < nthreads; ++t) { + const size_t module_begin = t * experiment.GetModulesNum() / nthreads; + const size_t module_end = (t + 1) * experiment.GetModulesNum() / nthreads; + + futures.emplace_back(std::async(std::launch::async, [&, module_begin, module_end] { + for (size_t m = module_begin; m < module_end; ++m) { + for (int pxl = 0; pxl < RAW_MODULE_SIZE; ++pxl) { + auto [x, y] = RawToConvertedCoordinate(experiment, m, pxl); + SetupPixel(geom, mask, m * RAW_MODULE_SIZE + pxl, x, y); + } + } + })); + } + + for (auto &f: futures) + f.get(); } } @@ -170,4 +220,8 @@ int32_t AzimuthalIntegrationMapping::GetAzimuthalBinCount() const { int32_t AzimuthalIntegrationMapping::GetQBinCount() const { return settings.GetQBinCount(); -} \ No newline at end of file +} + +size_t AzimuthalIntegrationMapping::GetNThreads() const { + return nthreads; +} diff --git a/common/AzimuthalIntegrationMapping.h b/common/AzimuthalIntegrationMapping.h index 9a84dd4d..996e4b32 100644 --- a/common/AzimuthalIntegrationMapping.h +++ b/common/AzimuthalIntegrationMapping.h @@ -25,22 +25,21 @@ protected: std::optional polarization_factor; + size_t nthreads; + void UpdateMaxBinNumber(); - AzimuthalIntegrationMapping(const AzimuthalIntegrationSettings& settings, - size_t width, size_t height, float wavelength); - void SetupRawGeom(const DiffractionExperiment& experiment, - const std::vector &mask); - - void SetupConvGeom(const DiffractionGeometry &geom, - const std::vector &mask); + void SetupRawGeom(const DiffractionExperiment& experiment, const std::vector &mask, size_t nthreads); + void SetupConvGeomRows(const DiffractionGeometry &geom, const std::vector &mask, size_t row0, size_t row_end); + void SetupConvGeom(const DiffractionGeometry &geom, const std::vector &mask, size_t nthreads); void SetupPixel(const DiffractionGeometry &geom, const std::vector &mask, uint32_t pxl, uint32_t col, uint32_t row); public: AzimuthalIntegrationMapping(const DiffractionExperiment& experiment, - const PixelMask& mask); + const PixelMask& mask, + size_t nthreads = 0); [[nodiscard]] uint16_t GetBinNumber() const; [[nodiscard]] const std::vector&GetPixelToBin() const; @@ -56,6 +55,7 @@ public: [[nodiscard]] const AzimuthalIntegrationSettings& Settings() const; [[nodiscard]] int32_t GetAzimuthalBinCount() const; [[nodiscard]] int32_t GetQBinCount() const; + [[nodiscard]] size_t GetNThreads() const; }; diff --git a/receiver/JFJochReceiver.cpp b/receiver/JFJochReceiver.cpp index 5e560d18..857d4de3 100644 --- a/receiver/JFJochReceiver.cpp +++ b/receiver/JFJochReceiver.cpp @@ -49,7 +49,7 @@ JFJochReceiver::JFJochReceiver(const DiffractionExperiment &in_experiment, az_int_mapping = std::make_unique(experiment, pixel_mask); auto end_time_point = std::chrono::steady_clock::now(); auto duration = std::chrono::duration(end_time_point - start_time_point); - logger.Info("Azimuthal integration mapping done in {:.5f} s", duration.count()); + logger.Info("Azimuthal integration mapping done in {:.5f} s with {} threads", duration.count(), az_int_mapping->GetNThreads()); plots.Setup(experiment, *az_int_mapping); diff --git a/tests/AzimuthalIntegrationTest.cpp b/tests/AzimuthalIntegrationTest.cpp index 9dd030db..ed48c14d 100644 --- a/tests/AzimuthalIntegrationTest.cpp +++ b/tests/AzimuthalIntegrationTest.cpp @@ -318,3 +318,99 @@ TEST_CASE("AzimuthalIntegrationProfile_GetResult1D","[AzimuthalIntegration]") { CHECK(result_1d[1] == Catch::Approx(21.0f)); CHECK(result_1d[2] == Catch::Approx(22.0f)); } + +template +static void RequireVectorsEqual(const std::vector &ref, + const std::vector &other, + const std::string &name, + int nthreads) { + INFO(name << ", threads=" << nthreads); + REQUIRE(ref.size() == other.size()); + CHECK(memcmp(ref.data(), other.data(), sizeof(T) * ref.size()) == 0); +} + +static void CheckAzimuthalIntegrationMappingThreadingExact(const DiffractionExperiment &experiment) { + PixelMask pixel_mask(experiment); + + AzimuthalIntegrationMapping mapping_1(experiment, pixel_mask, 1); + AzimuthalIntegrationMapping mapping_2(experiment, pixel_mask, 2); + AzimuthalIntegrationMapping mapping_16(experiment, pixel_mask, 16); + AzimuthalIntegrationMapping mapping_0(experiment, pixel_mask, 0); + + REQUIRE(mapping_1.GetBinNumber() == mapping_2.GetBinNumber()); + REQUIRE(mapping_1.GetBinNumber() == mapping_16.GetBinNumber()); + REQUIRE(mapping_1.GetBinNumber() == mapping_0.GetBinNumber()); + + REQUIRE(mapping_1.GetQBinCount() == mapping_2.GetQBinCount()); + REQUIRE(mapping_1.GetQBinCount() == mapping_16.GetQBinCount()); + REQUIRE(mapping_1.GetQBinCount() == mapping_0.GetQBinCount()); + + REQUIRE(mapping_1.GetAzimuthalBinCount() == mapping_2.GetAzimuthalBinCount()); + REQUIRE(mapping_1.GetAzimuthalBinCount() == mapping_16.GetAzimuthalBinCount()); + REQUIRE(mapping_1.GetAzimuthalBinCount() == mapping_0.GetAzimuthalBinCount()); + + RequireVectorsEqual(mapping_1.GetPixelToBin(), mapping_2.GetPixelToBin(), "pixel_to_bin", 2); + RequireVectorsEqual(mapping_1.GetPixelToBin(), mapping_16.GetPixelToBin(), "pixel_to_bin", 16); + RequireVectorsEqual(mapping_1.GetPixelToBin(), mapping_0.GetPixelToBin(), "pixel_to_bin", 0); + + RequireVectorsEqual(mapping_1.Resolution(), mapping_2.Resolution(), "resolution", 2); + RequireVectorsEqual(mapping_1.Resolution(), mapping_16.Resolution(), "resolution", 16); + RequireVectorsEqual(mapping_1.Resolution(), mapping_0.Resolution(), "resolution", 0); + + RequireVectorsEqual(mapping_1.Corrections(), mapping_2.Corrections(), "corrections", 2); + RequireVectorsEqual(mapping_1.Corrections(), mapping_16.Corrections(), "corrections", 16); + RequireVectorsEqual(mapping_1.Corrections(), mapping_0.Corrections(), "corrections", 0); + + RequireVectorsEqual(mapping_1.GetBinToQ(), mapping_2.GetBinToQ(), "bin_to_q", 2); + RequireVectorsEqual(mapping_1.GetBinToQ(), mapping_16.GetBinToQ(), "bin_to_q", 16); + RequireVectorsEqual(mapping_1.GetBinToQ(), mapping_0.GetBinToQ(), "bin_to_q", 0); + + RequireVectorsEqual(mapping_1.GetBinToD(), mapping_2.GetBinToD(), "bin_to_d", 2); + RequireVectorsEqual(mapping_1.GetBinToD(), mapping_16.GetBinToD(), "bin_to_d", 16); + RequireVectorsEqual(mapping_1.GetBinToD(), mapping_0.GetBinToD(), "bin_to_d", 0); + + RequireVectorsEqual(mapping_1.GetBinToTwoTheta(), mapping_2.GetBinToTwoTheta(), "bin_to_2theta", 2); + RequireVectorsEqual(mapping_1.GetBinToTwoTheta(), mapping_16.GetBinToTwoTheta(), "bin_to_2theta", 16); + RequireVectorsEqual(mapping_1.GetBinToTwoTheta(), mapping_0.GetBinToTwoTheta(), "bin_to_2theta", 0); + + RequireVectorsEqual(mapping_1.GetBinToPhi(), mapping_2.GetBinToPhi(), "bin_to_phi", 2); + RequireVectorsEqual(mapping_1.GetBinToPhi(), mapping_16.GetBinToPhi(), "bin_to_phi", 16); + RequireVectorsEqual(mapping_1.GetBinToPhi(), mapping_0.GetBinToPhi(), "bin_to_phi", 0); +} + +TEST_CASE("AzimuthalIntegrationMapping_Threading_FixedGeometry_2000x2000", "[AzimuthalIntegration]") { + DiffractionExperiment x(DetDECTRIS(2000, 2000, "E16M", "")); + x.DetectorDistance_mm(50).BeamX_pxl(1000).BeamY_pxl(1000); + x.QSpacingForAzimInt_recipA(0.1).QRangeForAzimInt_recipA(0.1, 10); + x.PolarizationFactor(0.99f); + + REQUIRE(x.IsGeometryTransformed()); + + CheckAzimuthalIntegrationMappingThreadingExact(x); +} + +TEST_CASE("AzimuthalIntegrationMapping_Threading_RawGeometry_18Modules", "[AzimuthalIntegration]") { + DiffractionExperiment x(DetJF9M()); + x.Raw(); + x.DetectorDistance_mm(100).BeamX_pxl(1500).BeamY_pxl(1500); + x.QSpacingForAzimInt_recipA(0.05).QRangeForAzimInt_recipA(0.1, 8.0); + x.PolarizationFactor(0.99f); + + REQUIRE(!x.IsGeometryTransformed()); + REQUIRE(x.GetModulesNum() == 18); + + CheckAzimuthalIntegrationMappingThreadingExact(x); +} + +TEST_CASE("AzimuthalIntegrationMapping_Threading_ConvertedGeometry_18Modules", "[AzimuthalIntegration]") { + DiffractionExperiment x(DetJF9M()); + x.Conversion(); + x.DetectorDistance_mm(100).BeamX_pxl(1500).BeamY_pxl(1500); + x.QSpacingForAzimInt_recipA(0.05).QRangeForAzimInt_recipA(0.1, 8.0); + x.PolarizationFactor(0.99f); + + REQUIRE(x.IsGeometryTransformed()); + REQUIRE(x.GetModulesNum() == 18); + + CheckAzimuthalIntegrationMappingThreadingExact(x); +} \ No newline at end of file -- 2.52.0 From 9770d86bb20b92386c4eed4794b50652d9f5c1e6 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Thu, 30 Apr 2026 11:18:39 +0200 Subject: [PATCH 5/7] AzimuthalIntegrationMapping: Parallel calculation of azimuthal integration mapping, reduces time especially for larger detectors --- docs/CHANGELOG.md | 5 +++++ tests/AzimuthalIntegrationTest.cpp | 10 ---------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 2cb97a08..24b7b1bd 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog ## 1.0.0 +### 1.0.0-rc.141 +This is an UNSTABLE release. The release has significant modifications and bug fixes, if things go wrong, it is better to revert to 1.0.0-rc.132. + +* jfjoch_broker: Azimuthal integration mapping is generated with parallel computations, significantly reducing setup times + ### 1.0.0-rc.140 This is an UNSTABLE release. The release has significant modifications and bug fixes, if things go wrong, it is better to revert to 1.0.0-rc.132. diff --git a/tests/AzimuthalIntegrationTest.cpp b/tests/AzimuthalIntegrationTest.cpp index ed48c14d..ac95a083 100644 --- a/tests/AzimuthalIntegrationTest.cpp +++ b/tests/AzimuthalIntegrationTest.cpp @@ -19,16 +19,6 @@ TEST_CASE("AzimuthalIntegrationMapping_Constructor","[AzimuthalIntegration]") { REQUIRE_NOTHROW(radial = std::make_unique(x, pixel_mask)); } -TEST_CASE("AzimuthalIntegrationMapping_Create_16M","[AzimuthalIntegration]") { - DiffractionExperiment x(DetDECTRIS(2000, 2000, "E16M", "")); - x.DetectorDistance_mm(50).BeamX_pxl(1000).BeamY_pxl(1000); - x.QSpacingForAzimInt_recipA(0.1).QRangeForAzimInt_recipA(0.1, 10); - - PixelMask pixel_mask(x); - AzimuthalIntegrationMapping mapping(x, pixel_mask); - REQUIRE(mapping.GetBinNumber() == 99); -} - TEST_CASE("AzimuthalIntegrationMapping_GetBinNumber","[AzimuthalIntegration]") { DiffractionExperiment x(DetJF4M()); x.DetectorDistance_mm(50).BeamX_pxl(1000).BeamY_pxl(1000); -- 2.52.0 From 9e7da70896b872e4ab945084312dc4fb4785e38f Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Thu, 30 Apr 2026 11:28:40 +0200 Subject: [PATCH 6/7] Frontend: Fix FFTW selection in frontend --- frontend/src/components/IndexingSettings.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/IndexingSettings.tsx b/frontend/src/components/IndexingSettings.tsx index 520063ba..25a14b04 100644 --- a/frontend/src/components/IndexingSettings.tsx +++ b/frontend/src/components/IndexingSettings.tsx @@ -148,8 +148,8 @@ class IndexingSettings extends Component { onChange={this.handleAlgorithmChange} > FFBIDX (known unit cell) - GPU - FFT (guess unit cell) - GPU - FFT (guess unit cell) - CPU + FFT (guess unit cell) - GPU with CuFFT library + FFT (guess unit cell) - CPU with FFTW library Auto (FFBIDX if unit cell provided, FFT otherwise) No indexing -- 2.52.0 From 3b03e9f3cb049cf520252e25416bd54b8d144579 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Thu, 30 Apr 2026 11:29:54 +0200 Subject: [PATCH 7/7] Frontend: fix --- docs/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 24b7b1bd..d5cfd0fc 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -4,6 +4,7 @@ This is an UNSTABLE release. The release has significant modifications and bug fixes, if things go wrong, it is better to revert to 1.0.0-rc.132. * jfjoch_broker: Azimuthal integration mapping is generated with parallel computations, significantly reducing setup times +* frontend: Fix selection of FFTW in indexing settings ### 1.0.0-rc.140 This is an UNSTABLE release. The release has significant modifications and bug fixes, if things go wrong, it is better to revert to 1.0.0-rc.132. -- 2.52.0