From 665f7e147cb402382338ba1632d962f4872a0355 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Wed, 17 Dec 2025 16:25:06 +0100 Subject: [PATCH 01/96] BraggIntegrate2D: predictions are calculated externally (to make it easier to make a more general 3D routine) --- image_analysis/IndexAndRefine.cpp | 12 +++- .../bragg_integration/BraggIntegrate2D.cpp | 64 +++++++------------ .../bragg_integration/BraggIntegrate2D.h | 7 +- 3 files changed, 36 insertions(+), 47 deletions(-) diff --git a/image_analysis/IndexAndRefine.cpp b/image_analysis/IndexAndRefine.cpp index 99e96df7..afd6c399 100644 --- a/image_analysis/IndexAndRefine.cpp +++ b/image_analysis/IndexAndRefine.cpp @@ -141,8 +141,16 @@ void IndexAndRefine::ProcessImage(DataMessage &msg, * 3.0f; if (spot_finding_settings.quick_integration) { - auto res = BraggIntegrate2D(experiment_copy, image, *lattice_candidate, - prediction, ewald_dist_cutoff, msg.number, symmetry.centering); + BraggPredictionSettings settings_prediction{ + .high_res_A = experiment.GetBraggIntegrationSettings().GetDMinLimit_A(), + .ewald_dist_cutoff = ewald_dist_cutoff, + .max_hkl = 100, + .centering = symmetry.centering + }; + + prediction.Calc(experiment, *lattice_candidate, settings_prediction); + + auto res = BraggIntegrate2D(experiment_copy, image, prediction.GetReflections(), msg.number); constexpr size_t kMaxReflections = 10000; if (res.size() > kMaxReflections) { diff --git a/image_analysis/bragg_integration/BraggIntegrate2D.cpp b/image_analysis/bragg_integration/BraggIntegrate2D.cpp index 1d643164..04d0e582 100644 --- a/image_analysis/bragg_integration/BraggIntegrate2D.cpp +++ b/image_analysis/bragg_integration/BraggIntegrate2D.cpp @@ -63,40 +63,30 @@ bool IntegrateReflection(Reflection &r, const T *image, size_t xpixel, size_t yp return false; } - template std::vector IntegrateInternal(const DiffractionExperiment &experiment, const CompressedImage &image, - const CrystalLattice &latt, - BraggPrediction &prediction, - float dist_from_ewald_sphere, + const std::vector &predicted, int64_t special_value, int64_t saturation, - int64_t image_number, - char centering) { + int64_t image_number) { auto settings = experiment.GetBraggIntegrationSettings(); auto geom = experiment.GetDiffractionGeometry(); std::vector buffer; auto ptr = reinterpret_cast(image.GetUncompressedPtr(buffer)); - BraggPredictionSettings settings_prediction{ - .high_res_A = settings.GetDMinLimit_A(), - .ewald_dist_cutoff = dist_from_ewald_sphere, - .max_hkl = 100, - .centering = centering - }; - - auto count = prediction.Calc(experiment, latt, settings_prediction); - std::vector ret; - float r_3 = settings.GetR3(); - float r_1_sq = settings.GetR1() * settings.GetR1(); - float r_2_sq = settings.GetR2() * settings.GetR2(); - float r_3_sq = settings.GetR3() * settings.GetR3(); + ret.reserve(predicted.size()); + + const float r_3 = settings.GetR3(); + const float r_1_sq = settings.GetR1() * settings.GetR1(); + const float r_2_sq = settings.GetR2() * settings.GetR2(); + const float r_3_sq = settings.GetR3() * settings.GetR3(); + + for (const auto &pred: predicted) { + Reflection r = pred; // copy, because we will write I/bkg/sigma/image_number - for (int i = 0; i < count; i++) { - Reflection r = prediction.GetReflections().at(i); if (IntegrateReflection(r, ptr, image.GetWidth(), image.GetHeight(), special_value, saturation, r_3, r_1_sq, r_2_sq, r_3_sq)) { if (experiment.GetPolarizationFactor()) { @@ -107,7 +97,10 @@ std::vector IntegrateInternal(const DiffractionExperiment &experimen r.sigma /= pol; } - r.image_number = static_cast(image_number); + // In mixed-mode, keep the prediction's angle_deg if it exists, + // but stamp which image produced the integrated contribution. + r.image_number = static_cast(image_number); + ret.push_back(r); } } @@ -117,33 +110,24 @@ std::vector IntegrateInternal(const DiffractionExperiment &experimen std::vector BraggIntegrate2D(const DiffractionExperiment &experiment, const CompressedImage &image, - const CrystalLattice &latt, - BraggPrediction &prediction, - float dist_from_ewald_sphere, - int64_t image_number, - char centering) { - if (image.GetCompressedSize() == 0) + const std::vector &predicted, + int64_t image_number) { + if (image.GetCompressedSize() == 0 || predicted.empty()) return {}; switch (image.GetMode()) { case CompressedImageMode::Int8: - return IntegrateInternal(experiment, image, latt, prediction, dist_from_ewald_sphere, INT8_MIN, - INT8_MAX, image_number, centering); + return IntegrateInternal(experiment, image, predicted, INT8_MIN, INT8_MAX, image_number); case CompressedImageMode::Int16: - return IntegrateInternal(experiment, image, latt, prediction, dist_from_ewald_sphere, INT16_MIN, - INT16_MAX, image_number, centering); + return IntegrateInternal(experiment, image, predicted, INT16_MIN, INT16_MAX, image_number); case CompressedImageMode::Int32: - return IntegrateInternal(experiment, image, latt, prediction, dist_from_ewald_sphere, INT32_MIN, - INT32_MAX, image_number, centering); + return IntegrateInternal(experiment, image, predicted, INT32_MIN, INT32_MAX, image_number); case CompressedImageMode::Uint8: - return IntegrateInternal(experiment, image, latt, prediction, dist_from_ewald_sphere, UINT8_MAX, - UINT8_MAX, image_number, centering); + return IntegrateInternal(experiment, image, predicted, UINT8_MAX, UINT8_MAX, image_number); case CompressedImageMode::Uint16: - return IntegrateInternal(experiment, image, latt, prediction, dist_from_ewald_sphere, UINT16_MAX, - UINT16_MAX, image_number, centering); + return IntegrateInternal(experiment, image, predicted, UINT16_MAX, UINT16_MAX, image_number); case CompressedImageMode::Uint32: - return IntegrateInternal(experiment, image, latt, prediction, dist_from_ewald_sphere, UINT32_MAX, - UINT32_MAX, image_number, centering); + return IntegrateInternal(experiment, image, predicted, UINT32_MAX, UINT32_MAX, image_number); default: throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Image mode not supported"); diff --git a/image_analysis/bragg_integration/BraggIntegrate2D.h b/image_analysis/bragg_integration/BraggIntegrate2D.h index 593bba6a..b557084f 100644 --- a/image_analysis/bragg_integration/BraggIntegrate2D.h +++ b/image_analysis/bragg_integration/BraggIntegrate2D.h @@ -12,10 +12,7 @@ std::vector BraggIntegrate2D(const DiffractionExperiment &experiment, const CompressedImage &image, - const CrystalLattice &latt, - BraggPrediction &prediction, - float dist_from_ewald_sphere, - int64_t image_number, - char centering = 'P'); + const std::vector &predicted, + int64_t image_number); #endif //JFJOCH_BRAGGINTEGRATE2D_H -- 2.49.1 From 71ea7a659c1df8c3b3997d04aa55f1bd22843a33 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Wed, 17 Dec 2025 16:28:06 +0100 Subject: [PATCH 02/96] IndexAndRefine: split into three functions --- image_analysis/IndexAndRefine.cpp | 275 ++++++++++++++++-------------- image_analysis/IndexAndRefine.h | 22 +++ 2 files changed, 171 insertions(+), 126 deletions(-) diff --git a/image_analysis/IndexAndRefine.cpp b/image_analysis/IndexAndRefine.cpp index afd6c399..4dbca205 100644 --- a/image_analysis/IndexAndRefine.cpp +++ b/image_analysis/IndexAndRefine.cpp @@ -24,6 +24,145 @@ void IndexAndRefine::SetLattice(const CrystalLattice &lattice) { rotation_indexer->SetLattice(lattice); } +IndexAndRefine::IndexingOutcome IndexAndRefine::DetermineLatticeAndSymmetry(DataMessage &msg) { + IndexingOutcome outcome(experiment); + + if (rotation_indexer) { + auto result = rotation_indexer->ProcessImage(msg.number, msg.spots); + if (result) { + outcome.lattice_candidate = result->lattice; + + outcome.experiment.BeamX_pxl(result->geom.GetBeamX_pxl()) + .BeamY_pxl(result->geom.GetBeamY_pxl()) + .DetectorDistance_mm(result->geom.GetDetectorDistance_mm()); + + outcome.symmetry.centering = result->search_result.centering; + outcome.symmetry.niggli_class = result->search_result.niggli_class; + outcome.symmetry.crystal_system = result->search_result.system; + } + return outcome; + } + + // Convert input spots to reciprocal space + std::vector recip; + recip.reserve(msg.spots.size()); + for (const auto &i: msg.spots) { + if (index_ice_rings || !i.ice_ring) + recip.push_back(i.ReciprocalCoord(geom_)); + } + + auto indexer_result = indexer_->Run(experiment, recip).get(); + msg.indexing_time_s = indexer_result.indexing_time_s; + + if (indexer_result.lattice.empty()) + return outcome; + + auto latt = indexer_result.lattice[0]; + auto sg = experiment.GetGemmiSpaceGroup(); + + // If space group provided => always enforce symmetry in refinement + // If space group not provided => guess symmetry + if (sg) { + // If space group provided but no unit cell fixed, it is better to keep triclinic for now + if (experiment.GetUnitCell()) { + outcome.symmetry = LatticeMessage{ + .centering = sg->centring_type(), + .niggli_class = 0, + .crystal_system = sg->crystal_system() + }; + } + outcome.lattice_candidate = latt; + } else { + auto sym_result = LatticeSearch(latt); + outcome.symmetry = LatticeMessage{ + .centering = sym_result.centering, + .niggli_class = sym_result.niggli_class, + .crystal_system = sym_result.system + }; + outcome.lattice_candidate = sym_result.conventional; + } + + return outcome; +} + +void IndexAndRefine::RefineGeometryIfNeeded(DataMessage &msg, IndexAndRefine::IndexingOutcome &outcome) { + if (!outcome.lattice_candidate) + return; + + XtalOptimizerData data{ + .geom = outcome.experiment.GetDiffractionGeometry(), + .latt = *outcome.lattice_candidate, + .crystal_system = outcome.symmetry.crystal_system, + .min_spots = experiment.GetIndexingSettings().GetViableCellMinSpots(), + .refine_beam_center = true, + .refine_distance_mm = false, + .max_time = 0.04 // 40 ms is max allowed time for the operation + }; + + if (outcome.symmetry.crystal_system == gemmi::CrystalSystem::Trigonal) + data.crystal_system = gemmi::CrystalSystem::Hexagonal; + + switch (experiment.GetIndexingSettings().GetGeomRefinementAlgorithm()) { + case GeomRefinementAlgorithmEnum::None: + break; + case GeomRefinementAlgorithmEnum::BeamCenter: + if (XtalOptimizer(data, msg.spots)) { + outcome.experiment.BeamX_pxl(data.geom.GetBeamX_pxl()) + .BeamY_pxl(data.geom.GetBeamY_pxl()); + outcome.beam_center_updated = true; + } + break; + } + + outcome.lattice_candidate = data.latt; + + if (outcome.beam_center_updated) { + msg.beam_corr_x = data.beam_corr_x; + msg.beam_corr_y = data.beam_corr_y; + } +} + +void IndexAndRefine::QuickPredictAndIntegrate(DataMessage &msg, + const SpotFindingSettings &spot_finding_settings, + const CompressedImage &image, + BraggPrediction &prediction, + const IndexAndRefine::IndexingOutcome &outcome) { + if (!spot_finding_settings.quick_integration) + return; + if (!outcome.lattice_candidate) + return; + + float ewald_dist_cutoff = 0.001f; + + if (msg.profile_radius) + ewald_dist_cutoff = msg.profile_radius.value() * 2.0f; + if (experiment.GetBraggIntegrationSettings().GetFixedProfileRadius_recipA()) + ewald_dist_cutoff = experiment.GetBraggIntegrationSettings().GetFixedProfileRadius_recipA().value() * 3.0f; + + BraggPredictionSettings settings_prediction{ + .high_res_A = experiment.GetBraggIntegrationSettings().GetDMinLimit_A(), + .ewald_dist_cutoff = ewald_dist_cutoff, + .max_hkl = 100, + .centering = outcome.symmetry.centering + }; + + prediction.Calc(experiment, *outcome.lattice_candidate, settings_prediction); + + // NOTE: this assumes you have the "from predictions" entry-point. + // If your build still uses the old BraggIntegrate2D signature, call that instead. + auto res = BraggIntegrate2D(outcome.experiment, image, prediction.GetReflections(), msg.number); + + constexpr size_t kMaxReflections = 10000; + if (res.size() > kMaxReflections) { + msg.reflections.assign(res.begin(), res.begin() + kMaxReflections); + } else { + msg.reflections = res; + } + + CalcISigma(msg); + CalcWilsonBFactor(msg); +} + void IndexAndRefine::ProcessImage(DataMessage &msg, const SpotFindingSettings &spot_finding_settings, const CompressedImage &image, @@ -32,137 +171,21 @@ void IndexAndRefine::ProcessImage(DataMessage &msg, return; msg.indexing_result = false; - std::optional lattice_candidate; - DiffractionExperiment experiment_copy(experiment); - LatticeMessage symmetry{ - .centering = 'P', - .niggli_class = 0, - .crystal_system = gemmi::CrystalSystem::Triclinic - }; + IndexingOutcome outcome = DetermineLatticeAndSymmetry(msg); + if (!outcome.lattice_candidate) + return; - bool beam_center_updated = false; + RefineGeometryIfNeeded(msg, outcome); + if (!outcome.lattice_candidate) + return; - if (rotation_indexer) { - auto result = rotation_indexer->ProcessImage(msg.number, msg.spots); - if (result) { - lattice_candidate = result->lattice; - experiment_copy.BeamX_pxl(result->geom.GetBeamX_pxl()) - .BeamY_pxl(result->geom.GetBeamY_pxl()) - .DetectorDistance_mm(result->geom.GetDetectorDistance_mm()); + if (!AnalyzeIndexing(msg, outcome.experiment, *outcome.lattice_candidate, outcome.experiment.GetGoniometer())) + return; - symmetry.centering = result->search_result.centering; - symmetry.niggli_class = result->search_result.niggli_class; - symmetry.crystal_system = result->search_result.system; - } - } else { - // Convert input spots to reciprocal space - std::vector recip; - recip.reserve(msg.spots.size()); - for (const auto &i: msg.spots) { - if (index_ice_rings || !i.ice_ring) - recip.push_back(i.ReciprocalCoord(geom_)); - } + msg.lattice_type = outcome.symmetry; - auto indexer_result = indexer_->Run(experiment, recip).get(); - msg.indexing_time_s = indexer_result.indexing_time_s; - - if (!indexer_result.lattice.empty()) { - auto latt = indexer_result.lattice[0]; - - auto sg = experiment.GetGemmiSpaceGroup(); - - // If space group provided => always enforce symmetry in refinement - // If space group not provided => guess symmetry - if (sg) { - // If space group provided but no unit cell fixed, it is better to keep triclinic for now - if (experiment.GetUnitCell()) { - symmetry = LatticeMessage{ - .centering = sg->centring_type(), - .niggli_class = 0, - .crystal_system = sg->crystal_system() - }; - } - lattice_candidate = latt; - } else { - auto sym_result = LatticeSearch(latt); - symmetry = LatticeMessage{ - .centering = sym_result.centering, - .niggli_class = sym_result.niggli_class, - .crystal_system = sym_result.system - }; - - lattice_candidate = sym_result.conventional; - } - } - } - - if (lattice_candidate) { - XtalOptimizerData data{ - .geom = experiment_copy.GetDiffractionGeometry(), - .latt = *lattice_candidate, - .crystal_system = symmetry.crystal_system, - .min_spots = experiment.GetIndexingSettings().GetViableCellMinSpots(), - .refine_beam_center = true, - .refine_distance_mm = false, - .max_time = 0.04 // 40 ms is max allowed time for the operation - }; - - if (symmetry.crystal_system == gemmi::CrystalSystem::Trigonal) - data.crystal_system = gemmi::CrystalSystem::Hexagonal; - - switch (experiment.GetIndexingSettings().GetGeomRefinementAlgorithm()) { - case GeomRefinementAlgorithmEnum::None: - break; - case GeomRefinementAlgorithmEnum::BeamCenter: - if (XtalOptimizer(data, msg.spots)) { - experiment_copy.BeamX_pxl(data.geom.GetBeamX_pxl()).BeamY_pxl(data.geom.GetBeamY_pxl()); - beam_center_updated = true; - } - break; - } - - lattice_candidate = data.latt; - - if (beam_center_updated) { - msg.beam_corr_x = data.beam_corr_x; - msg.beam_corr_y = data.beam_corr_y; - } - - if (AnalyzeIndexing(msg, experiment_copy, *lattice_candidate, experiment_copy.GetGoniometer())) { - msg.lattice_type = symmetry; - - float ewald_dist_cutoff = 0.001f; - - if (msg.profile_radius) - ewald_dist_cutoff = msg.profile_radius.value() * 2.0f; - if (experiment.GetBraggIntegrationSettings().GetFixedProfileRadius_recipA()) - ewald_dist_cutoff = experiment.GetBraggIntegrationSettings().GetFixedProfileRadius_recipA().value() - * 3.0f; - - if (spot_finding_settings.quick_integration) { - BraggPredictionSettings settings_prediction{ - .high_res_A = experiment.GetBraggIntegrationSettings().GetDMinLimit_A(), - .ewald_dist_cutoff = ewald_dist_cutoff, - .max_hkl = 100, - .centering = symmetry.centering - }; - - prediction.Calc(experiment, *lattice_candidate, settings_prediction); - - auto res = BraggIntegrate2D(experiment_copy, image, prediction.GetReflections(), msg.number); - - constexpr size_t kMaxReflections = 10000; - if (res.size() > kMaxReflections) { - msg.reflections.assign(res.begin(), res.begin() + kMaxReflections); - } else - msg.reflections = res; - - CalcISigma(msg); - CalcWilsonBFactor(msg); - } - } - } + QuickPredictAndIntegrate(msg, spot_finding_settings, image, prediction, outcome); } std::optional IndexAndRefine::Finalize() { diff --git a/image_analysis/IndexAndRefine.h b/image_analysis/IndexAndRefine.h index d2a7eeeb..2162dc2a 100644 --- a/image_analysis/IndexAndRefine.h +++ b/image_analysis/IndexAndRefine.h @@ -25,6 +25,28 @@ class IndexAndRefine { IndexerThreadPool *indexer_; std::unique_ptr rotation_indexer; + + struct IndexingOutcome { + std::optional lattice_candidate; + DiffractionExperiment experiment; + LatticeMessage symmetry{ + .centering = 'P', + .niggli_class = 0, + .crystal_system = gemmi::CrystalSystem::Triclinic + }; + bool beam_center_updated = false; + + explicit IndexingOutcome(const DiffractionExperiment& experiment_ref) + : experiment(experiment_ref) {} + }; + + IndexingOutcome DetermineLatticeAndSymmetry(DataMessage &msg); + void RefineGeometryIfNeeded(DataMessage &msg, IndexingOutcome &outcome); + void QuickPredictAndIntegrate(DataMessage &msg, + const SpotFindingSettings &spot_finding_settings, + const CompressedImage &image, + BraggPrediction &prediction, + const IndexingOutcome &outcome); public: IndexAndRefine(const DiffractionExperiment &x, IndexerThreadPool *indexer); void SetLattice(const CrystalLattice &lattice); -- 2.49.1 From 752a3323e6253fa3edf191b297c1b05bb308a616 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Wed, 17 Dec 2025 16:35:00 +0100 Subject: [PATCH 03/96] BraggPrediction: Split into a separate directory --- image_analysis/CMakeLists.txt | 2 +- image_analysis/MXAnalysisAfterFPGA.cpp | 2 +- image_analysis/MXAnalysisAfterFPGA.h | 2 +- image_analysis/MXAnalysisWithoutFPGA.cpp | 2 +- image_analysis/MXAnalysisWithoutFPGA.h | 2 +- .../bragg_integration/BraggIntegrate2D.cpp | 1 - .../bragg_integration/BraggIntegrate2D.h | 2 -- image_analysis/bragg_integration/CMakeLists.txt | 12 ------------ .../BraggPrediction.cpp | 4 ++-- .../BraggPrediction.h | 0 .../BraggPredictionFactory.cpp | 4 ++-- .../BraggPredictionFactory.h | 0 .../BraggPredictionGPU.cu | 2 +- .../BraggPredictionGPU.h | 0 .../BraggPredictionRotation.cpp | 4 ++-- .../BraggPredictionRotation.h | 0 image_analysis/bragg_prediction/CMakeLists.txt | 16 ++++++++++++++++ tests/CalcBraggPredictionTest.cpp | 4 ++-- tests/RotationIndexerTest.cpp | 2 +- tests/XtalOptimizerTest.cpp | 2 +- tools/jfjoch_indexing_test.cpp | 2 +- 21 files changed, 33 insertions(+), 32 deletions(-) rename image_analysis/{bragg_integration => bragg_prediction}/BraggPrediction.cpp (97%) rename image_analysis/{bragg_integration => bragg_prediction}/BraggPrediction.h (100%) rename image_analysis/{bragg_integration => bragg_prediction}/BraggPredictionFactory.cpp (81%) rename image_analysis/{bragg_integration => bragg_prediction}/BraggPredictionFactory.h (100%) rename image_analysis/{bragg_integration => bragg_prediction}/BraggPredictionGPU.cu (99%) rename image_analysis/{bragg_integration => bragg_prediction}/BraggPredictionGPU.h (100%) rename image_analysis/{bragg_integration => bragg_prediction}/BraggPredictionRotation.cpp (98%) rename image_analysis/{bragg_integration => bragg_prediction}/BraggPredictionRotation.h (100%) create mode 100644 image_analysis/bragg_prediction/CMakeLists.txt diff --git a/image_analysis/CMakeLists.txt b/image_analysis/CMakeLists.txt index 83e9bbda..59b31d69 100644 --- a/image_analysis/CMakeLists.txt +++ b/image_analysis/CMakeLists.txt @@ -18,4 +18,4 @@ ADD_SUBDIRECTORY(indexing) ADD_SUBDIRECTORY(geom_refinement) ADD_SUBDIRECTORY(lattice_search) -TARGET_LINK_LIBRARIES(JFJochImageAnalysis JFJochBraggIntegration JFJochLatticeSearch JFJochIndexing JFJochSpotFinding JFJochCommon JFJochGeomRefinement gemmi) +TARGET_LINK_LIBRARIES(JFJochImageAnalysis JFJochBraggPrediction JFJochBraggIntegration JFJochLatticeSearch JFJochIndexing JFJochSpotFinding JFJochCommon JFJochGeomRefinement gemmi) diff --git a/image_analysis/MXAnalysisAfterFPGA.cpp b/image_analysis/MXAnalysisAfterFPGA.cpp index a09a00d0..1d6e725e 100644 --- a/image_analysis/MXAnalysisAfterFPGA.cpp +++ b/image_analysis/MXAnalysisAfterFPGA.cpp @@ -5,7 +5,7 @@ #include "spot_finding/DetModuleSpotFinder_cpu.h" #include "../common/CUDAWrapper.h" #include "spot_finding/SpotUtils.h" -#include "bragg_integration/BraggPredictionFactory.h" +#include "bragg_prediction/BraggPredictionFactory.h" double stddev(const std::vector &v) { if (v.size() <= 1) diff --git a/image_analysis/MXAnalysisAfterFPGA.h b/image_analysis/MXAnalysisAfterFPGA.h index 33b521df..00c19f11 100644 --- a/image_analysis/MXAnalysisAfterFPGA.h +++ b/image_analysis/MXAnalysisAfterFPGA.h @@ -5,7 +5,7 @@ #define JUNGFRAUJOCH_MXANALYZER_H #include "../common/DiffractionExperiment.h" -#include "bragg_integration/BraggPrediction.h" +#include "bragg_prediction/BraggPrediction.h" #include "indexing/IndexerThreadPool.h" #include "spot_finding/StrongPixelSet.h" #include "IndexAndRefine.h" diff --git a/image_analysis/MXAnalysisWithoutFPGA.cpp b/image_analysis/MXAnalysisWithoutFPGA.cpp index 5dc2fa55..18c31c71 100644 --- a/image_analysis/MXAnalysisWithoutFPGA.cpp +++ b/image_analysis/MXAnalysisWithoutFPGA.cpp @@ -8,7 +8,7 @@ #include "spot_finding/SpotUtils.h" #include "spot_finding/ImageSpotFinderFactory.h" -#include "bragg_integration/BraggPredictionFactory.h" +#include "bragg_prediction/BraggPredictionFactory.h" MXAnalysisWithoutFPGA::MXAnalysisWithoutFPGA(const DiffractionExperiment &in_experiment, const AzimuthalIntegration &in_integration, diff --git a/image_analysis/MXAnalysisWithoutFPGA.h b/image_analysis/MXAnalysisWithoutFPGA.h index 205618b8..d0d82c12 100644 --- a/image_analysis/MXAnalysisWithoutFPGA.h +++ b/image_analysis/MXAnalysisWithoutFPGA.h @@ -11,7 +11,7 @@ #include "../common/AzimuthalIntegration.h" #include "../common/PixelMask.h" #include "../common/AzimuthalIntegrationProfile.h" -#include "bragg_integration/BraggPrediction.h" +#include "bragg_prediction/BraggPrediction.h" #include "spot_finding/ImageSpotFinder.h" #include "indexing/IndexerThreadPool.h" #include "IndexAndRefine.h" diff --git a/image_analysis/bragg_integration/BraggIntegrate2D.cpp b/image_analysis/bragg_integration/BraggIntegrate2D.cpp index 04d0e582..a5c68041 100644 --- a/image_analysis/bragg_integration/BraggIntegrate2D.cpp +++ b/image_analysis/bragg_integration/BraggIntegrate2D.cpp @@ -2,7 +2,6 @@ // SPDX-License-Identifier: GPL-3.0-only #include "BraggIntegrate2D.h" -#include "BraggPrediction.h" template bool IntegrateReflection(Reflection &r, const T *image, size_t xpixel, size_t ypixel, diff --git a/image_analysis/bragg_integration/BraggIntegrate2D.h b/image_analysis/bragg_integration/BraggIntegrate2D.h index b557084f..c92c6958 100644 --- a/image_analysis/bragg_integration/BraggIntegrate2D.h +++ b/image_analysis/bragg_integration/BraggIntegrate2D.h @@ -6,9 +6,7 @@ #include #include "../../common/DiffractionExperiment.h" -#include "../../common/CrystalLattice.h" #include "../../common/Reflection.h" -#include "BraggPrediction.h" std::vector BraggIntegrate2D(const DiffractionExperiment &experiment, const CompressedImage &image, diff --git a/image_analysis/bragg_integration/CMakeLists.txt b/image_analysis/bragg_integration/CMakeLists.txt index 09ea4b1d..00820ba4 100644 --- a/image_analysis/bragg_integration/CMakeLists.txt +++ b/image_analysis/bragg_integration/CMakeLists.txt @@ -1,22 +1,10 @@ ADD_LIBRARY(JFJochBraggIntegration STATIC BraggIntegrate2D.cpp BraggIntegrate2D.h - BraggPrediction.cpp - BraggPrediction.h Regression.h CalcISigma.cpp CalcISigma.h - BraggPredictionFactory.cpp - BraggPredictionFactory.h SystematicAbsence.h - BraggPredictionRotation.cpp - BraggPredictionRotation.h ) TARGET_LINK_LIBRARIES(JFJochBraggIntegration JFJochCommon) - -IF (JFJOCH_CUDA_AVAILABLE) - TARGET_SOURCES(JFJochBraggIntegration PRIVATE - ../indexing/CUDAMemHelpers.h - BraggPredictionGPU.cu BraggPredictionGPU.h) -ENDIF() diff --git a/image_analysis/bragg_integration/BraggPrediction.cpp b/image_analysis/bragg_prediction/BraggPrediction.cpp similarity index 97% rename from image_analysis/bragg_integration/BraggPrediction.cpp rename to image_analysis/bragg_prediction/BraggPrediction.cpp index 3f8ec9ad..f2ee7f36 100644 --- a/image_analysis/bragg_integration/BraggPrediction.cpp +++ b/image_analysis/bragg_prediction/BraggPrediction.cpp @@ -1,8 +1,8 @@ // SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only -#include "BraggPrediction.h" -#include "SystematicAbsence.h" +#include "../bragg_integration/BraggPrediction.h" +#include "../bragg_integration/SystematicAbsence.h" BraggPrediction::BraggPrediction(int max_reflections) : max_reflections(max_reflections), reflections(max_reflections) {} diff --git a/image_analysis/bragg_integration/BraggPrediction.h b/image_analysis/bragg_prediction/BraggPrediction.h similarity index 100% rename from image_analysis/bragg_integration/BraggPrediction.h rename to image_analysis/bragg_prediction/BraggPrediction.h diff --git a/image_analysis/bragg_integration/BraggPredictionFactory.cpp b/image_analysis/bragg_prediction/BraggPredictionFactory.cpp similarity index 81% rename from image_analysis/bragg_integration/BraggPredictionFactory.cpp rename to image_analysis/bragg_prediction/BraggPredictionFactory.cpp index cc1ae471..96788e8f 100644 --- a/image_analysis/bragg_integration/BraggPredictionFactory.cpp +++ b/image_analysis/bragg_prediction/BraggPredictionFactory.cpp @@ -1,11 +1,11 @@ // SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only -#include "BraggPredictionFactory.h" +#include "../bragg_integration/BraggPredictionFactory.h" #ifdef JFJOCH_USE_CUDA #include "../../common/CUDAWrapper.h" -#include "BraggPredictionGPU.h" +#include "../bragg_integration/BraggPredictionGPU.h" #endif std::unique_ptr CreateBraggPrediction(int max_reflections) { diff --git a/image_analysis/bragg_integration/BraggPredictionFactory.h b/image_analysis/bragg_prediction/BraggPredictionFactory.h similarity index 100% rename from image_analysis/bragg_integration/BraggPredictionFactory.h rename to image_analysis/bragg_prediction/BraggPredictionFactory.h diff --git a/image_analysis/bragg_integration/BraggPredictionGPU.cu b/image_analysis/bragg_prediction/BraggPredictionGPU.cu similarity index 99% rename from image_analysis/bragg_integration/BraggPredictionGPU.cu rename to image_analysis/bragg_prediction/BraggPredictionGPU.cu index 7ac8f1fb..6bad2804 100644 --- a/image_analysis/bragg_integration/BraggPredictionGPU.cu +++ b/image_analysis/bragg_prediction/BraggPredictionGPU.cu @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only -#include "BraggPredictionGPU.h" +#include "../bragg_integration/BraggPredictionGPU.h" #ifdef JFJOCH_USE_CUDA #include "../indexing/CUDAMemHelpers.h" diff --git a/image_analysis/bragg_integration/BraggPredictionGPU.h b/image_analysis/bragg_prediction/BraggPredictionGPU.h similarity index 100% rename from image_analysis/bragg_integration/BraggPredictionGPU.h rename to image_analysis/bragg_prediction/BraggPredictionGPU.h diff --git a/image_analysis/bragg_integration/BraggPredictionRotation.cpp b/image_analysis/bragg_prediction/BraggPredictionRotation.cpp similarity index 98% rename from image_analysis/bragg_integration/BraggPredictionRotation.cpp rename to image_analysis/bragg_prediction/BraggPredictionRotation.cpp index 2e91648d..ab04c9bf 100644 --- a/image_analysis/bragg_integration/BraggPredictionRotation.cpp +++ b/image_analysis/bragg_prediction/BraggPredictionRotation.cpp @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only -#include "BraggPredictionRotation.h" +#include "../bragg_integration/BraggPredictionRotation.h" #include #include @@ -9,7 +9,7 @@ #include "../../common/DiffractionGeometry.h" #include "../../common/GoniometerAxis.h" #include "../../common/JFJochException.h" -#include "SystematicAbsence.h" +#include "../bragg_integration/SystematicAbsence.h" namespace { inline float deg_to_rad(float deg) { diff --git a/image_analysis/bragg_integration/BraggPredictionRotation.h b/image_analysis/bragg_prediction/BraggPredictionRotation.h similarity index 100% rename from image_analysis/bragg_integration/BraggPredictionRotation.h rename to image_analysis/bragg_prediction/BraggPredictionRotation.h diff --git a/image_analysis/bragg_prediction/CMakeLists.txt b/image_analysis/bragg_prediction/CMakeLists.txt new file mode 100644 index 00000000..656dc783 --- /dev/null +++ b/image_analysis/bragg_prediction/CMakeLists.txt @@ -0,0 +1,16 @@ +ADD_LIBRARY(JFJochBraggPrediction STATIC + BraggPrediction.cpp + BraggPrediction.h + BraggPredictionFactory.cpp + BraggPredictionFactory.h + BraggPredictionRotation.cpp + BraggPredictionRotation.h +) + +TARGET_LINK_LIBRARIES(JFJochBraggPrediction JFJochCommon) + +IF (JFJOCH_CUDA_AVAILABLE) + TARGET_SOURCES(JFJochBraggPrediction PRIVATE + ../indexing/CUDAMemHelpers.h + BraggPredictionGPU.cu BraggPredictionGPU.h) +ENDIF() diff --git a/tests/CalcBraggPredictionTest.cpp b/tests/CalcBraggPredictionTest.cpp index 21fdf7be..fee29973 100644 --- a/tests/CalcBraggPredictionTest.cpp +++ b/tests/CalcBraggPredictionTest.cpp @@ -3,7 +3,7 @@ #include -#include "../image_analysis/bragg_integration/BraggPrediction.h" +#include "../image_analysis/bragg_prediction/BraggPrediction.h" #include TEST_CASE("BraggPrediction_11keV") { @@ -204,7 +204,7 @@ TEST_CASE("BraggPrediction_systematic_absences") { } #ifdef JFJOCH_USE_CUDA -#include "../image_analysis/bragg_integration/BraggPredictionGPU.h" +#include "../image_analysis/bragg_prediction/BraggPredictionGPU.h" TEST_CASE("BraggPredictionGPU") { DiffractionExperiment experiment(DetJF4M()); diff --git a/tests/RotationIndexerTest.cpp b/tests/RotationIndexerTest.cpp index aa4b1959..27d2be44 100644 --- a/tests/RotationIndexerTest.cpp +++ b/tests/RotationIndexerTest.cpp @@ -5,7 +5,7 @@ #include #include "../image_analysis/RotationIndexer.h" -#include "../image_analysis/bragg_integration/BraggPrediction.h" +#include "../image_analysis/bragg_prediction/BraggPrediction.h" TEST_CASE("RotationIndexer") { DiffractionExperiment exp_i; diff --git a/tests/XtalOptimizerTest.cpp b/tests/XtalOptimizerTest.cpp index 40007100..c5e07cf9 100644 --- a/tests/XtalOptimizerTest.cpp +++ b/tests/XtalOptimizerTest.cpp @@ -5,7 +5,7 @@ #include #include "../image_analysis/geom_refinement/XtalOptimizer.h" -#include "../image_analysis/bragg_integration/BraggPrediction.h" +#include "../image_analysis/bragg_prediction/BraggPrediction.h" TEST_CASE("XtalOptimizer") { DiffractionExperiment exp_i; diff --git a/tools/jfjoch_indexing_test.cpp b/tools/jfjoch_indexing_test.cpp index fcd1a6f9..01740474 100644 --- a/tools/jfjoch_indexing_test.cpp +++ b/tools/jfjoch_indexing_test.cpp @@ -5,7 +5,7 @@ #include "../image_analysis/indexing/IndexerFactory.h" #include "../common/Logger.h" #include "../image_analysis/IndexAndRefine.h" -#include "../image_analysis/bragg_integration/BraggPredictionFactory.h" +#include "../image_analysis/bragg_prediction/BraggPredictionFactory.h" #include "../writer/FileWriter.h" #include "../image_analysis/indexing/AnalyzeIndexing.h" -- 2.49.1 From 6bee56335622100803cf305a86159895218a1d96 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Wed, 17 Dec 2025 16:50:40 +0100 Subject: [PATCH 04/96] IndexAndRefine: Integration operates in place (prelude to general 3D routine) + fix a bit sorting --- common/Reflection.h | 1 + image_analysis/IndexAndRefine.cpp | 35 ++++++++++--- image_analysis/IndexAndRefine.h | 2 +- .../bragg_integration/BraggIntegrate2D.cpp | 51 ++++++++----------- .../bragg_integration/BraggIntegrate2D.h | 8 +-- .../bragg_integration/SystematicAbsence.h | 9 ++-- 6 files changed, 57 insertions(+), 49 deletions(-) diff --git a/common/Reflection.h b/common/Reflection.h index 434fb163..00b960dc 100644 --- a/common/Reflection.h +++ b/common/Reflection.h @@ -21,6 +21,7 @@ struct Reflection { float bkg; float sigma; float dist_ewald; + bool observed = false; }; #endif //JFJOCH_REFLECTION_H diff --git a/image_analysis/IndexAndRefine.cpp b/image_analysis/IndexAndRefine.cpp index 4dbca205..f3cc65bf 100644 --- a/image_analysis/IndexAndRefine.cpp +++ b/image_analysis/IndexAndRefine.cpp @@ -148,17 +148,36 @@ void IndexAndRefine::QuickPredictAndIntegrate(DataMessage &msg, prediction.Calc(experiment, *outcome.lattice_candidate, settings_prediction); - // NOTE: this assumes you have the "from predictions" entry-point. - // If your build still uses the old BraggIntegrate2D signature, call that instead. - auto res = BraggIntegrate2D(outcome.experiment, image, prediction.GetReflections(), msg.number); + auto refl = prediction.GetReflections(); - constexpr size_t kMaxReflections = 10000; - if (res.size() > kMaxReflections) { - msg.reflections.assign(res.begin(), res.begin() + kMaxReflections); - } else { - msg.reflections = res; + BraggIntegrate2D(outcome.experiment, image, refl, msg.number); + + std::vector refl_ret; + refl_ret.reserve(prediction.GetReflections().size()); + + for (const auto& r : prediction.GetReflections()) { + if (r.observed) + refl_ret.push_back(r); } + constexpr size_t kMaxReflections = 20000; + if (refl_ret.size() > kMaxReflections) { + // Keep only smallest d (highest resolution) + std::nth_element(refl_ret.begin(), + refl_ret.begin() + static_cast(kMaxReflections), + refl_ret.end(), + [](const Reflection& a, const Reflection& b) { + return a.d < b.d; + }); + refl_ret.resize(kMaxReflections); + + // Optional: make output ordered by d (nice for downstream / debugging) + std::sort(refl_ret.begin(), refl_ret.end(), + [](const Reflection& a, const Reflection& b) { return a.d < b.d; }); + } + + msg.reflections = std::move(refl_ret); + CalcISigma(msg); CalcWilsonBFactor(msg); } diff --git a/image_analysis/IndexAndRefine.h b/image_analysis/IndexAndRefine.h index 2162dc2a..36d3ba58 100644 --- a/image_analysis/IndexAndRefine.h +++ b/image_analysis/IndexAndRefine.h @@ -9,7 +9,7 @@ #include "../common/DiffractionSpot.h" #include "../common/DiffractionExperiment.h" -#include "bragg_integration/BraggPrediction.h" +#include "bragg_prediction/BraggPrediction.h" #include "indexing/IndexerThreadPool.h" #include "lattice_search/LatticeSearch.h" #include "RotationIndexer.h" diff --git a/image_analysis/bragg_integration/BraggIntegrate2D.cpp b/image_analysis/bragg_integration/BraggIntegrate2D.cpp index a5c68041..207fa59f 100644 --- a/image_analysis/bragg_integration/BraggIntegrate2D.cpp +++ b/image_analysis/bragg_integration/BraggIntegrate2D.cpp @@ -4,11 +4,9 @@ #include "BraggIntegrate2D.h" template -bool IntegrateReflection(Reflection &r, const T *image, size_t xpixel, size_t ypixel, +void IntegrateReflection(Reflection &r, const T *image, size_t xpixel, size_t ypixel, int64_t special_value, int64_t saturation, float r_3, float r_1_sq, float r_2_sq, float r_3_sq) { - r.I = 0; - r.bkg = 0; int64_t x0 = std::floor(r.predicted_x - r_3 - 1.0); int64_t x1 = std::ceil(r.predicted_x + r_3 + 1.0); @@ -57,15 +55,18 @@ bool IntegrateReflection(Reflection &r, const T *image, size_t xpixel, size_t yp r.sigma = std::sqrt(static_cast(I_sum)); else r.sigma = 1; - return true; + r.observed = true; + } else { + r.I = 0; + r.bkg = 0; + r.observed = false; } - return false; } template -std::vector IntegrateInternal(const DiffractionExperiment &experiment, +void IntegrateInternal(const DiffractionExperiment &experiment, const CompressedImage &image, - const std::vector &predicted, + std::vector &predicted, int64_t special_value, int64_t saturation, int64_t image_number) { @@ -75,19 +76,15 @@ std::vector IntegrateInternal(const DiffractionExperiment &experimen std::vector buffer; auto ptr = reinterpret_cast(image.GetUncompressedPtr(buffer)); - std::vector ret; - ret.reserve(predicted.size()); - const float r_3 = settings.GetR3(); const float r_1_sq = settings.GetR1() * settings.GetR1(); const float r_2_sq = settings.GetR2() * settings.GetR2(); const float r_3_sq = settings.GetR3() * settings.GetR3(); - for (const auto &pred: predicted) { - Reflection r = pred; // copy, because we will write I/bkg/sigma/image_number - - if (IntegrateReflection(r, ptr, image.GetWidth(), image.GetHeight(), special_value, saturation, - r_3, r_1_sq, r_2_sq, r_3_sq)) { + for (auto &r: predicted) { + IntegrateReflection(r, ptr, image.GetWidth(), image.GetHeight(), special_value, saturation, + r_3, r_1_sq, r_2_sq, r_3_sq); + if (r.observed) { if (experiment.GetPolarizationFactor()) { float pol = geom.CalcAzIntPolarizationCorr(r.predicted_x, r.predicted_y, experiment.GetPolarizationFactor().value()); @@ -96,37 +93,31 @@ std::vector IntegrateInternal(const DiffractionExperiment &experimen r.sigma /= pol; } - // In mixed-mode, keep the prediction's angle_deg if it exists, - // but stamp which image produced the integrated contribution. r.image_number = static_cast(image_number); - - ret.push_back(r); } } - - return ret; } -std::vector BraggIntegrate2D(const DiffractionExperiment &experiment, +void BraggIntegrate2D(const DiffractionExperiment &experiment, const CompressedImage &image, - const std::vector &predicted, + std::vector &predicted, int64_t image_number) { if (image.GetCompressedSize() == 0 || predicted.empty()) - return {}; + return; switch (image.GetMode()) { case CompressedImageMode::Int8: - return IntegrateInternal(experiment, image, predicted, INT8_MIN, INT8_MAX, image_number); + IntegrateInternal(experiment, image, predicted, INT8_MIN, INT8_MAX, image_number); case CompressedImageMode::Int16: - return IntegrateInternal(experiment, image, predicted, INT16_MIN, INT16_MAX, image_number); + IntegrateInternal(experiment, image, predicted, INT16_MIN, INT16_MAX, image_number); case CompressedImageMode::Int32: - return IntegrateInternal(experiment, image, predicted, INT32_MIN, INT32_MAX, image_number); + IntegrateInternal(experiment, image, predicted, INT32_MIN, INT32_MAX, image_number); case CompressedImageMode::Uint8: - return IntegrateInternal(experiment, image, predicted, UINT8_MAX, UINT8_MAX, image_number); + IntegrateInternal(experiment, image, predicted, UINT8_MAX, UINT8_MAX, image_number); case CompressedImageMode::Uint16: - return IntegrateInternal(experiment, image, predicted, UINT16_MAX, UINT16_MAX, image_number); + IntegrateInternal(experiment, image, predicted, UINT16_MAX, UINT16_MAX, image_number); case CompressedImageMode::Uint32: - return IntegrateInternal(experiment, image, predicted, UINT32_MAX, UINT32_MAX, image_number); + IntegrateInternal(experiment, image, predicted, UINT32_MAX, UINT32_MAX, image_number); default: throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Image mode not supported"); diff --git a/image_analysis/bragg_integration/BraggIntegrate2D.h b/image_analysis/bragg_integration/BraggIntegrate2D.h index c92c6958..c46bb894 100644 --- a/image_analysis/bragg_integration/BraggIntegrate2D.h +++ b/image_analysis/bragg_integration/BraggIntegrate2D.h @@ -8,9 +8,9 @@ #include "../../common/DiffractionExperiment.h" #include "../../common/Reflection.h" -std::vector BraggIntegrate2D(const DiffractionExperiment &experiment, - const CompressedImage &image, - const std::vector &predicted, - int64_t image_number); +void BraggIntegrate2D(const DiffractionExperiment &experiment, + const CompressedImage &image, + std::vector &predicted, + int64_t image_number); #endif //JFJOCH_BRAGGINTEGRATE2D_H diff --git a/image_analysis/bragg_integration/SystematicAbsence.h b/image_analysis/bragg_integration/SystematicAbsence.h index ea27ae32..48264dc2 100644 --- a/image_analysis/bragg_integration/SystematicAbsence.h +++ b/image_analysis/bragg_integration/SystematicAbsence.h @@ -1,12 +1,11 @@ // SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only -#ifndef JFJOCH_SYSTEMATICABSENCE_H -#define JFJOCH_SYSTEMATICABSENCE_H +#pragma once -static inline bool odd_int(int v) { return (v & 1) != 0; } +inline bool odd_int(int v) { return (v & 1) != 0; } -static inline bool systematic_absence(int h, int k, int l, char centering) { +inline bool systematic_absence(int h, int k, int l, char centering) { if (h == 0 && k == 0 && l == 0) return true; switch (centering) { case 'I': return odd_int(h + k + l); @@ -22,5 +21,3 @@ static inline bool systematic_absence(int h, int k, int l, char centering) { default: return false; // P } } - -#endif //JFJOCH_SYSTEMATICABSENCE_H \ No newline at end of file -- 2.49.1 From 734506ec6a9e29dfa91ab91bbe3ab9682c34b7c0 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Wed, 17 Dec 2025 18:06:19 +0100 Subject: [PATCH 05/96] Cmake: Add missing subdirectory --- image_analysis/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/image_analysis/CMakeLists.txt b/image_analysis/CMakeLists.txt index 59b31d69..b9d3f310 100644 --- a/image_analysis/CMakeLists.txt +++ b/image_analysis/CMakeLists.txt @@ -14,6 +14,7 @@ FIND_PACKAGE(Eigen3 3.4 REQUIRED NO_MODULE) # provides Eigen3::Eigen ADD_SUBDIRECTORY(spot_finding) ADD_SUBDIRECTORY(bragg_integration) +ADD_SUBDIRECTORY(bragg_prediction) ADD_SUBDIRECTORY(indexing) ADD_SUBDIRECTORY(geom_refinement) ADD_SUBDIRECTORY(lattice_search) -- 2.49.1 From 7162db87bda0facd916bcc3ac83a8d4e6d56d641 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Wed, 17 Dec 2025 18:21:15 +0100 Subject: [PATCH 06/96] BraggPrediction: Fix to path --- image_analysis/bragg_prediction/BraggPrediction.cpp | 2 +- image_analysis/bragg_prediction/BraggPredictionFactory.cpp | 4 ++-- image_analysis/bragg_prediction/BraggPredictionGPU.cu | 2 +- image_analysis/bragg_prediction/BraggPredictionRotation.cpp | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/image_analysis/bragg_prediction/BraggPrediction.cpp b/image_analysis/bragg_prediction/BraggPrediction.cpp index f2ee7f36..3a7ae4bb 100644 --- a/image_analysis/bragg_prediction/BraggPrediction.cpp +++ b/image_analysis/bragg_prediction/BraggPrediction.cpp @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only -#include "../bragg_integration/BraggPrediction.h" +#include "BraggPrediction.h" #include "../bragg_integration/SystematicAbsence.h" BraggPrediction::BraggPrediction(int max_reflections) diff --git a/image_analysis/bragg_prediction/BraggPredictionFactory.cpp b/image_analysis/bragg_prediction/BraggPredictionFactory.cpp index 96788e8f..cc1ae471 100644 --- a/image_analysis/bragg_prediction/BraggPredictionFactory.cpp +++ b/image_analysis/bragg_prediction/BraggPredictionFactory.cpp @@ -1,11 +1,11 @@ // SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only -#include "../bragg_integration/BraggPredictionFactory.h" +#include "BraggPredictionFactory.h" #ifdef JFJOCH_USE_CUDA #include "../../common/CUDAWrapper.h" -#include "../bragg_integration/BraggPredictionGPU.h" +#include "BraggPredictionGPU.h" #endif std::unique_ptr CreateBraggPrediction(int max_reflections) { diff --git a/image_analysis/bragg_prediction/BraggPredictionGPU.cu b/image_analysis/bragg_prediction/BraggPredictionGPU.cu index 6bad2804..7ac8f1fb 100644 --- a/image_analysis/bragg_prediction/BraggPredictionGPU.cu +++ b/image_analysis/bragg_prediction/BraggPredictionGPU.cu @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only -#include "../bragg_integration/BraggPredictionGPU.h" +#include "BraggPredictionGPU.h" #ifdef JFJOCH_USE_CUDA #include "../indexing/CUDAMemHelpers.h" diff --git a/image_analysis/bragg_prediction/BraggPredictionRotation.cpp b/image_analysis/bragg_prediction/BraggPredictionRotation.cpp index ab04c9bf..3c6f9bde 100644 --- a/image_analysis/bragg_prediction/BraggPredictionRotation.cpp +++ b/image_analysis/bragg_prediction/BraggPredictionRotation.cpp @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only -#include "../bragg_integration/BraggPredictionRotation.h" +#include "BraggPredictionRotation.h" #include #include -- 2.49.1 From a23fe329aa991b048ed35d24391142cfa46bf278 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Wed, 17 Dec 2025 19:54:22 +0100 Subject: [PATCH 07/96] BraggIntegrate2D: fix missing break in switch statement --- image_analysis/bragg_integration/BraggIntegrate2D.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/image_analysis/bragg_integration/BraggIntegrate2D.cpp b/image_analysis/bragg_integration/BraggIntegrate2D.cpp index 207fa59f..2206157b 100644 --- a/image_analysis/bragg_integration/BraggIntegrate2D.cpp +++ b/image_analysis/bragg_integration/BraggIntegrate2D.cpp @@ -108,16 +108,22 @@ void BraggIntegrate2D(const DiffractionExperiment &experiment, switch (image.GetMode()) { case CompressedImageMode::Int8: IntegrateInternal(experiment, image, predicted, INT8_MIN, INT8_MAX, image_number); + break; case CompressedImageMode::Int16: IntegrateInternal(experiment, image, predicted, INT16_MIN, INT16_MAX, image_number); + break; case CompressedImageMode::Int32: IntegrateInternal(experiment, image, predicted, INT32_MIN, INT32_MAX, image_number); + break; case CompressedImageMode::Uint8: IntegrateInternal(experiment, image, predicted, UINT8_MAX, UINT8_MAX, image_number); + break; case CompressedImageMode::Uint16: IntegrateInternal(experiment, image, predicted, UINT16_MAX, UINT16_MAX, image_number); + break; case CompressedImageMode::Uint32: IntegrateInternal(experiment, image, predicted, UINT32_MAX, UINT32_MAX, image_number); + break; default: throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Image mode not supported"); -- 2.49.1 From d5ba5fc3c43c7ee3ebf520fa4a47a06bd1568141 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Wed, 17 Dec 2025 20:24:58 +0100 Subject: [PATCH 08/96] AnalyzeIndexing: Handle ice rings in counting percentage of indexed spots --- image_analysis/indexing/AnalyzeIndexing.cpp | 27 ++++++++++++--------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/image_analysis/indexing/AnalyzeIndexing.cpp b/image_analysis/indexing/AnalyzeIndexing.cpp index e503c81f..74cdb170 100644 --- a/image_analysis/indexing/AnalyzeIndexing.cpp +++ b/image_analysis/indexing/AnalyzeIndexing.cpp @@ -6,6 +6,7 @@ #include "AnalyzeIndexing.h" #include "FitProfileRadius.h" +#include "spdlog/fmt/bundled/format.h" namespace { inline bool ok(float x) { @@ -122,10 +123,7 @@ bool AnalyzeIndexing(DataMessage &message, const DiffractionExperiment &experiment, const CrystalLattice &latt, const std::optional &rotation_axis) { - size_t nspots = message.spots.size(); - - uint64_t indexed_spot_count = 0; - std::vector indexed_spots(nspots); + std::vector indexed_spots(message.spots.size()); // Check spots const Coord a = latt.Vec0(); @@ -136,10 +134,15 @@ bool AnalyzeIndexing(DataMessage &message, const Coord bstar = latt.Bstar(); const Coord cstar = latt.Cstar(); + const bool index_ice_ring = experiment.GetIndexingSettings().GetIndexIceRings(); const auto geom = experiment.GetDiffractionGeometry(); const auto indexing_tolerance = experiment.GetIndexingSettings().GetTolerance(); + const auto indexing_tolerance_sq = indexing_tolerance * indexing_tolerance; const auto viable_cell_min_spots = experiment.GetIndexingSettings().GetViableCellMinSpots(); + size_t nspots_ref = 0; + size_t nspots_indexed = 0; + // identify indexed spots for (int i = 0; i < message.spots.size(); i++) { auto recip = message.spots[i].ReciprocalCoord(geom); @@ -157,22 +160,24 @@ bool AnalyzeIndexing(DataMessage &message, Coord recip_pred = std::round(h_fp) * astar + std::round(k_fp) * bstar + std::round(l_fp) * cstar; // See indexing_peak_check() in peaks.c in CrystFEL - if (norm_sq < indexing_tolerance * indexing_tolerance) { - indexed_spot_count++; + if (norm_sq < indexing_tolerance_sq) { + if (index_ice_ring || !message.spots[i].ice_ring) + nspots_indexed++; indexed_spots[i] = 1; message.spots[i].dist_ewald_sphere = geom.DistFromEwaldSphere(recip_pred); message.spots[i].h = std::lround(h_fp); message.spots[i].k = std::lround(k_fp); message.spots[i].l = std::lround(l_fp); } + if (index_ice_ring || !message.spots[i].ice_ring) + nspots_ref++; } - auto spot_count_threshold = std::max(viable_cell_min_spots, std::lround(min_percentage_spots * nspots)); - - if (indexed_spot_count >= spot_count_threshold) { + if (nspots_indexed >= viable_cell_min_spots + && nspots_indexed >= std::lround(min_percentage_spots * nspots_ref)) { auto uc = latt.GetUnitCell(); if (!ok(uc.a) || !ok(uc.b) || !ok(uc.c) || !ok(uc.alpha) || !ok(uc.beta) || !ok(uc.gamma)) - return {}; + return false; message.indexing_result = true; assert(indexed_spots.size() == message.spots.size()); @@ -180,7 +185,7 @@ bool AnalyzeIndexing(DataMessage &message, message.spots[i].indexed = indexed_spots[i]; message.profile_radius = FitProfileRadius(message.spots); - message.spot_count_indexed = indexed_spot_count; + message.spot_count_indexed = nspots_indexed; message.indexing_lattice = latt; message.indexing_unit_cell = latt.GetUnitCell(); -- 2.49.1 From 58cd091273f255b7973a8668830107ac50a53ba6 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Wed, 17 Dec 2025 20:26:03 +0100 Subject: [PATCH 09/96] Indexing: use squared norm to avoid sqrt() in checking indexing solution quality --- image_analysis/indexing/EigenRefine.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/image_analysis/indexing/EigenRefine.h b/image_analysis/indexing/EigenRefine.h index 4d549be2..de629a52 100644 --- a/image_analysis/indexing/EigenRefine.h +++ b/image_analysis/indexing/EigenRefine.h @@ -113,6 +113,8 @@ inline std::vector Refine(const std::vector &in_spots, float min_score = -1; int64_t id = -1; + const auto float indexing_tolerance_sq = p.indexing_tolerance * p.indexing_tolerance; + for (int i = 0; i < scores.size(); i++) { // Get cell vectors auto cell = oCell.block(3u * i, 0u, 3u, 3u); @@ -163,7 +165,7 @@ inline std::vector Refine(const std::vector &in_spots, const M3x miller = round(resid.array()); resid -= miller; - int64_t indexed_spot_count = (resid.rowwise().norm().array() < p.indexing_tolerance).count(); + int64_t indexed_spot_count = (resid.rowwise().squaredNorm().array() < indexing_tolerance_sq).count(); if (indexed_spot_count > max_indexed_spot_count) { max_indexed_spot_count = indexed_spot_count; min_score = scores(i); -- 2.49.1 From 88dba761e467e3d41f85e439b816046e514d43b8 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Wed, 17 Dec 2025 21:03:17 +0100 Subject: [PATCH 10/96] Indexing: fix indexing tolerance square data type --- image_analysis/indexing/EigenRefine.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/image_analysis/indexing/EigenRefine.h b/image_analysis/indexing/EigenRefine.h index de629a52..f319005e 100644 --- a/image_analysis/indexing/EigenRefine.h +++ b/image_analysis/indexing/EigenRefine.h @@ -113,7 +113,7 @@ inline std::vector Refine(const std::vector &in_spots, float min_score = -1; int64_t id = -1; - const auto float indexing_tolerance_sq = p.indexing_tolerance * p.indexing_tolerance; + const float indexing_tolerance_sq = p.indexing_tolerance * p.indexing_tolerance; for (int i = 0; i < scores.size(); i++) { // Get cell vectors -- 2.49.1 From a71e1f16e764e81ded5d9dcf0a7abe581b811f50 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Wed, 17 Dec 2025 21:11:01 +0100 Subject: [PATCH 11/96] Indexing: Fixes to better handling ice ring spots --- image_analysis/RotationIndexer.cpp | 1 + image_analysis/geom_refinement/XtalOptimizer.cpp | 7 +++++-- image_analysis/geom_refinement/XtalOptimizer.h | 2 ++ image_analysis/indexing/AnalyzeIndexing.cpp | 1 - 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/image_analysis/RotationIndexer.cpp b/image_analysis/RotationIndexer.cpp index fcacf5b0..ed46490a 100644 --- a/image_analysis/RotationIndexer.cpp +++ b/image_analysis/RotationIndexer.cpp @@ -90,6 +90,7 @@ void RotationIndexer::TryIndex() { .min_spots = experiment.GetIndexingSettings().GetViableCellMinSpots(), .refine_beam_center = true, .refine_distance_mm = false, + .index_ice_rings = experiment.GetIndexingSettings().GetIndexIceRings(), .axis = axis_ }; diff --git a/image_analysis/geom_refinement/XtalOptimizer.cpp b/image_analysis/geom_refinement/XtalOptimizer.cpp index 0dd5b482..736f412c 100644 --- a/image_analysis/geom_refinement/XtalOptimizer.cpp +++ b/image_analysis/geom_refinement/XtalOptimizer.cpp @@ -413,8 +413,12 @@ bool XtalOptimizerInternal(XtalOptimizerData &data, break; } + const float tolerance_sq = tolerance * tolerance; // Add residuals for each point for (const auto &pt: spots) { + if (!data.index_ice_rings && pt.ice_ring) + continue; + Eigen::Matrix3d gonio_back_rot = Eigen::Matrix3d::Identity(); Coord recip = data.geom.DetectorToRecip(pt.x, pt.y); @@ -442,10 +446,9 @@ bool XtalOptimizerInternal(XtalOptimizerData &data, double norm_sq = (h - h_fp) * (h - h_fp) + (k - k_fp) * (k - k_fp) + (l - l_fp) * (l - l_fp); - if (norm_sq > tolerance * tolerance) + if (norm_sq > tolerance_sq) continue; - problem.AddResidualBlock( new ceres::AutoDiffCostFunction( new XtalResidual(pt.x, pt.y, diff --git a/image_analysis/geom_refinement/XtalOptimizer.h b/image_analysis/geom_refinement/XtalOptimizer.h index 0a3cfcb2..38c53cd3 100644 --- a/image_analysis/geom_refinement/XtalOptimizer.h +++ b/image_analysis/geom_refinement/XtalOptimizer.h @@ -27,6 +27,8 @@ struct XtalOptimizerData { bool refine_distance_mm = false; bool refine_detector_angles = false; + bool index_ice_rings = true; + float max_time = 1.0; std::optional axis; diff --git a/image_analysis/indexing/AnalyzeIndexing.cpp b/image_analysis/indexing/AnalyzeIndexing.cpp index 74cdb170..14d95e3b 100644 --- a/image_analysis/indexing/AnalyzeIndexing.cpp +++ b/image_analysis/indexing/AnalyzeIndexing.cpp @@ -6,7 +6,6 @@ #include "AnalyzeIndexing.h" #include "FitProfileRadius.h" -#include "spdlog/fmt/bundled/format.h" namespace { inline bool ok(float x) { -- 2.49.1 From e27c09833e8c5eae27e53a11fd08eb04dfade63c Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Thu, 18 Dec 2025 10:18:31 +0100 Subject: [PATCH 12/96] IndexAndRefine: Fix wrong vector being used for predicted reflections --- image_analysis/IndexAndRefine.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/image_analysis/IndexAndRefine.cpp b/image_analysis/IndexAndRefine.cpp index f3cc65bf..ebe8f013 100644 --- a/image_analysis/IndexAndRefine.cpp +++ b/image_analysis/IndexAndRefine.cpp @@ -153,9 +153,9 @@ void IndexAndRefine::QuickPredictAndIntegrate(DataMessage &msg, BraggIntegrate2D(outcome.experiment, image, refl, msg.number); std::vector refl_ret; - refl_ret.reserve(prediction.GetReflections().size()); + refl_ret.reserve(refl.size()); - for (const auto& r : prediction.GetReflections()) { + for (const auto& r : refl) { if (r.observed) refl_ret.push_back(r); } -- 2.49.1 From 319aa0265ad193b7d83cbc9692db106c5c993b06 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Thu, 18 Dec 2025 11:23:02 +0100 Subject: [PATCH 13/96] BraggIntegrate2D: Take const vector of predictions and return new vector --- image_analysis/IndexAndRefine.cpp | 17 ++------- .../bragg_integration/BraggIntegrate2D.cpp | 38 ++++++++++--------- .../bragg_integration/BraggIntegrate2D.h | 9 +++-- 3 files changed, 28 insertions(+), 36 deletions(-) diff --git a/image_analysis/IndexAndRefine.cpp b/image_analysis/IndexAndRefine.cpp index ebe8f013..1851280e 100644 --- a/image_analysis/IndexAndRefine.cpp +++ b/image_analysis/IndexAndRefine.cpp @@ -146,21 +146,10 @@ void IndexAndRefine::QuickPredictAndIntegrate(DataMessage &msg, .centering = outcome.symmetry.centering }; - prediction.Calc(experiment, *outcome.lattice_candidate, settings_prediction); + auto nrefl = prediction.Calc(experiment, *outcome.lattice_candidate, settings_prediction); + auto refl_ret = BraggIntegrate2D(outcome.experiment, image, prediction.GetReflections(), nrefl, msg.number); - auto refl = prediction.GetReflections(); - - BraggIntegrate2D(outcome.experiment, image, refl, msg.number); - - std::vector refl_ret; - refl_ret.reserve(refl.size()); - - for (const auto& r : refl) { - if (r.observed) - refl_ret.push_back(r); - } - - constexpr size_t kMaxReflections = 20000; + constexpr size_t kMaxReflections = 10000; if (refl_ret.size() > kMaxReflections) { // Keep only smallest d (highest resolution) std::nth_element(refl_ret.begin(), diff --git a/image_analysis/bragg_integration/BraggIntegrate2D.cpp b/image_analysis/bragg_integration/BraggIntegrate2D.cpp index 2206157b..a511fc12 100644 --- a/image_analysis/bragg_integration/BraggIntegrate2D.cpp +++ b/image_analysis/bragg_integration/BraggIntegrate2D.cpp @@ -64,12 +64,17 @@ void IntegrateReflection(Reflection &r, const T *image, size_t xpixel, size_t yp } template -void IntegrateInternal(const DiffractionExperiment &experiment, +std::vector IntegrateInternal(const DiffractionExperiment &experiment, const CompressedImage &image, - std::vector &predicted, + const std::vector &predicted, + size_t npredicted, int64_t special_value, int64_t saturation, int64_t image_number) { + + std::vector ret; + ret.reserve(npredicted); + auto settings = experiment.GetBraggIntegrationSettings(); auto geom = experiment.GetDiffractionGeometry(); @@ -81,7 +86,8 @@ void IntegrateInternal(const DiffractionExperiment &experiment, const float r_2_sq = settings.GetR2() * settings.GetR2(); const float r_3_sq = settings.GetR3() * settings.GetR3(); - for (auto &r: predicted) { + for (int i = 0; i < npredicted; i++) { + auto r = predicted.at(i); IntegrateReflection(r, ptr, image.GetWidth(), image.GetHeight(), special_value, saturation, r_3, r_1_sq, r_2_sq, r_3_sq); if (r.observed) { @@ -94,36 +100,32 @@ void IntegrateInternal(const DiffractionExperiment &experiment, } r.image_number = static_cast(image_number); + ret.emplace_back(r); } } } -void BraggIntegrate2D(const DiffractionExperiment &experiment, +std::vector BraggIntegrate2D(const DiffractionExperiment &experiment, const CompressedImage &image, - std::vector &predicted, + const std::vector &predicted, + size_t npredicted, int64_t image_number) { if (image.GetCompressedSize() == 0 || predicted.empty()) - return; + return {}; switch (image.GetMode()) { case CompressedImageMode::Int8: - IntegrateInternal(experiment, image, predicted, INT8_MIN, INT8_MAX, image_number); - break; + return IntegrateInternal(experiment, image, predicted, npredicted, INT8_MIN, INT8_MAX, image_number); case CompressedImageMode::Int16: - IntegrateInternal(experiment, image, predicted, INT16_MIN, INT16_MAX, image_number); - break; + return IntegrateInternal(experiment, image, predicted, npredicted, INT16_MIN, INT16_MAX, image_number); case CompressedImageMode::Int32: - IntegrateInternal(experiment, image, predicted, INT32_MIN, INT32_MAX, image_number); - break; + return IntegrateInternal(experiment, image, predicted, npredicted, INT32_MIN, INT32_MAX, image_number); case CompressedImageMode::Uint8: - IntegrateInternal(experiment, image, predicted, UINT8_MAX, UINT8_MAX, image_number); - break; + return IntegrateInternal(experiment, image, predicted, npredicted, UINT8_MAX, UINT8_MAX, image_number); case CompressedImageMode::Uint16: - IntegrateInternal(experiment, image, predicted, UINT16_MAX, UINT16_MAX, image_number); - break; + return IntegrateInternal(experiment, image, predicted, npredicted, UINT16_MAX, UINT16_MAX, image_number); case CompressedImageMode::Uint32: - IntegrateInternal(experiment, image, predicted, UINT32_MAX, UINT32_MAX, image_number); - break; + return IntegrateInternal(experiment, image, predicted, npredicted, UINT32_MAX, UINT32_MAX, image_number); default: throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Image mode not supported"); diff --git a/image_analysis/bragg_integration/BraggIntegrate2D.h b/image_analysis/bragg_integration/BraggIntegrate2D.h index c46bb894..353757b5 100644 --- a/image_analysis/bragg_integration/BraggIntegrate2D.h +++ b/image_analysis/bragg_integration/BraggIntegrate2D.h @@ -8,9 +8,10 @@ #include "../../common/DiffractionExperiment.h" #include "../../common/Reflection.h" -void BraggIntegrate2D(const DiffractionExperiment &experiment, - const CompressedImage &image, - std::vector &predicted, - int64_t image_number); +std::vector BraggIntegrate2D(const DiffractionExperiment &experiment, + const CompressedImage &image, + const std::vector &predicted, + size_t npredicted, + int64_t image_number); #endif //JFJOCH_BRAGGINTEGRATE2D_H -- 2.49.1 From b3446736bde2e48c2b5d402b90a6589188390ded Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Thu, 18 Dec 2025 11:23:46 +0100 Subject: [PATCH 14/96] Reflection: Add partiality for prediction (set to one at the moment) --- common/Reflection.h | 1 + 1 file changed, 1 insertion(+) diff --git a/common/Reflection.h b/common/Reflection.h index 00b960dc..8b1ccb29 100644 --- a/common/Reflection.h +++ b/common/Reflection.h @@ -22,6 +22,7 @@ struct Reflection { float sigma; float dist_ewald; bool observed = false; + float partiality = 1.0; }; #endif //JFJOCH_REFLECTION_H -- 2.49.1 From 20224a01c34adb96da03b88aa0fc57d2855091f7 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Thu, 18 Dec 2025 11:41:00 +0100 Subject: [PATCH 15/96] BraggPrediction: Work in progress --- image_analysis/IndexAndRefine.cpp | 4 +- .../bragg_prediction/BraggPrediction.cpp | 18 +- .../bragg_prediction/BraggPrediction.h | 16 +- .../BraggPredictionRotation.cpp | 209 +++++++++--------- .../BraggPredictionRotation.h | 24 +- 5 files changed, 136 insertions(+), 135 deletions(-) diff --git a/image_analysis/IndexAndRefine.cpp b/image_analysis/IndexAndRefine.cpp index 1851280e..2bfd1989 100644 --- a/image_analysis/IndexAndRefine.cpp +++ b/image_analysis/IndexAndRefine.cpp @@ -141,9 +141,9 @@ void IndexAndRefine::QuickPredictAndIntegrate(DataMessage &msg, BraggPredictionSettings settings_prediction{ .high_res_A = experiment.GetBraggIntegrationSettings().GetDMinLimit_A(), - .ewald_dist_cutoff = ewald_dist_cutoff, .max_hkl = 100, - .centering = outcome.symmetry.centering + .centering = outcome.symmetry.centering, + .ewald_dist_cutoff = ewald_dist_cutoff, }; auto nrefl = prediction.Calc(experiment, *outcome.lattice_candidate, settings_prediction); diff --git a/image_analysis/bragg_prediction/BraggPrediction.cpp b/image_analysis/bragg_prediction/BraggPrediction.cpp index 3a7ae4bb..00f2389b 100644 --- a/image_analysis/bragg_prediction/BraggPrediction.cpp +++ b/image_analysis/bragg_prediction/BraggPrediction.cpp @@ -14,19 +14,19 @@ const std::vector &BraggPrediction::GetReflections() const { int BraggPrediction::Calc(const DiffractionExperiment &experiment, const CrystalLattice &lattice, const BraggPredictionSettings &settings) { - auto geom = experiment.GetDiffractionGeometry(); - auto det_width_pxl = static_cast(experiment.GetXPixelsNum()); - auto det_height_pxl = static_cast(experiment.GetYPixelsNum()); + const auto geom = experiment.GetDiffractionGeometry(); + const auto det_width_pxl = static_cast(experiment.GetXPixelsNum()); + const auto det_height_pxl = static_cast(experiment.GetYPixelsNum()); - float one_over_dmax = 1.0f / settings.high_res_A; - float one_over_dmax_sq = one_over_dmax * one_over_dmax; + const float one_over_dmax = 1.0f / settings.high_res_A; + const float one_over_dmax_sq = one_over_dmax * one_over_dmax; float one_over_wavelength = 1.0f / geom.GetWavelength_A(); - Coord Astar = lattice.Astar(); - Coord Bstar = lattice.Bstar(); - Coord Cstar = lattice.Cstar(); - Coord S0 = geom.GetScatteringVector(); + const Coord Astar = lattice.Astar(); + const Coord Bstar = lattice.Bstar(); + const Coord Cstar = lattice.Cstar(); + const Coord S0 = geom.GetScatteringVector(); std::vector rot = geom.GetPoniRotMatrix().transpose().arr(); diff --git a/image_analysis/bragg_prediction/BraggPrediction.h b/image_analysis/bragg_prediction/BraggPrediction.h index e616aa0f..cf067f01 100644 --- a/image_analysis/bragg_prediction/BraggPrediction.h +++ b/image_analysis/bragg_prediction/BraggPrediction.h @@ -12,9 +12,17 @@ struct BraggPredictionSettings { float high_res_A = 1.5; - float ewald_dist_cutoff = 0.0005; int max_hkl = 100; char centering = 'P'; + + // Still parameters + float ewald_dist_cutoff = 0.0005; + + // Rotation parameters + Coord rotation_axis = Coord(1, 0, 0); + int image_number = 0; + float wedge_size_deg = 0.1f; + float mosaicity_deg = 0.1f; }; class BraggPrediction { @@ -30,11 +38,5 @@ public: const std::vector &GetReflections() const; }; -std::vector CalcBraggPredictions(const DiffractionExperiment &experiment, - const CrystalLattice &lattice, - float high_res_A = 1.5, - float ewald_dist_cutoff = 0.0005, - int max_hkl = 100, - int max_reflections = 10000); #endif //JFJOCH_BRAGGPREDICTION_H diff --git a/image_analysis/bragg_prediction/BraggPredictionRotation.cpp b/image_analysis/bragg_prediction/BraggPredictionRotation.cpp index 3c6f9bde..94a849c3 100644 --- a/image_analysis/bragg_prediction/BraggPredictionRotation.cpp +++ b/image_analysis/bragg_prediction/BraggPredictionRotation.cpp @@ -11,6 +11,9 @@ #include "../../common/JFJochException.h" #include "../bragg_integration/SystematicAbsence.h" +BraggPredictionRotation::BraggPredictionRotation(int max_reflections) + : BraggPrediction(max_reflections) {} + namespace { inline float deg_to_rad(float deg) { return deg * (static_cast(M_PI) / 180.0f); @@ -63,12 +66,9 @@ namespace { } } // namespace -std::vector BraggPredictionRotation::Calc(const DiffractionExperiment& experiment, - const CrystalLattice& lattice, - const BraggPredictionRotationSettings& settings) const { - std::vector out; - out.reserve(200000); // tune - +int BraggPredictionRotation::Calc(const DiffractionExperiment &experiment, + const CrystalLattice &lattice, + const BraggPredictionSettings &settings) { const auto gon_opt = experiment.GetGoniometer(); if (!gon_opt.has_value()) throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, @@ -76,134 +76,145 @@ std::vector BraggPredictionRotation::Calc(const DiffractionExperimen const GoniometerAxis& gon = *gon_opt; const auto geom = experiment.GetDiffractionGeometry(); + const float det_width_pxl = static_cast(experiment.GetXPixelsNum()); + const float det_height_pxl = static_cast(experiment.GetYPixelsNum()); - // Determine prediction interval in spindle angle. - // We treat each image as [angle(image), angle(image)+wedge) - const float start_deg = gon.GetStart_deg(); - const float inc_deg = gon.GetIncrement_deg(); - const float wedge_deg = gon.GetWedge_deg(); - - float phi0_deg = gon.GetAngle_deg(static_cast(settings.image_first)); - float phi1_deg = gon.GetAngle_deg(static_cast(settings.image_last)) + wedge_deg; - - if (settings.pad_one_wedge) { - phi0_deg -= wedge_deg; - phi1_deg += wedge_deg; - } - - const float phi0 = deg_to_rad(phi0_deg); - const float phi1 = deg_to_rad(phi1_deg); - - // Resolution cutoff in reciprocal space const float one_over_dmax = 1.0f / settings.high_res_A; const float one_over_dmax_sq = one_over_dmax * one_over_dmax; - // S0 has length 1/lambda (your convention) - const Coord S0 = geom.GetScatteringVector(); - const float k2 = (S0 * S0); // (1/lambda)^2 - - // Rotation axis in lab frame (already normalized in ctor, but keep safe) - const Coord w = gon.GetAxis().Normalize(); + const float wavelength = geom.GetWavelength_A(); + const float one_over_wavelength = 1.0f / wavelength; + const float one_over_wavelength_sq = one_over_wavelength * one_over_wavelength; const Coord Astar = lattice.Astar(); const Coord Bstar = lattice.Bstar(); const Coord Cstar = lattice.Cstar(); + const Coord S0 = geom.GetScatteringVector(); - const float det_w = static_cast(experiment.GetXPixelsNum()); - const float det_h = static_cast(experiment.GetYPixelsNum()); + const std::vector rot = geom.GetPoniRotMatrix().transpose().arr(); + + // Precompute detector geometry constants + const float beam_x = geom.GetBeamX_pxl(); + const float beam_y = geom.GetBeamY_pxl(); + const float det_distance = geom.GetDetectorDistance_mm(); + const float pixel_size = geom.GetPixelSize_mm(); + const float coeff_const = det_distance / pixel_size; + + // Determine prediction interval in spindle angle. + const float start_deg = gon.GetStart_deg(); + const float inc_deg = gon.GetIncrement_deg(); + const float wedge_deg = gon.GetWedge_deg(); + + const float phi0_deg = gon.GetAngle_deg(static_cast(settings.image_number)); + const float phi1_deg = phi0_deg + wedge_deg; + + const float phi0 = deg_to_rad(phi0_deg); + const float phi1 = deg_to_rad(phi1_deg); + + const Coord w = gon.GetAxis().Normalize(); + + int i = 0; for (int h = -settings.max_hkl; h <= settings.max_hkl; ++h) { - const Coord Ah = Astar * static_cast(h); + const float Ah_x = Astar.x * h; + const float Ah_y = Astar.y * h; + const float Ah_z = Astar.z * h; for (int k = -settings.max_hkl; k <= settings.max_hkl; ++k) { - const Coord AhBk = Ah + Bstar * static_cast(k); + const float AhBk_x = Ah_x + Bstar.x * k; + const float AhBk_y = Ah_y + Bstar.y * k; + const float AhBk_z = Ah_z + Bstar.z * k; for (int l = -settings.max_hkl; l <= settings.max_hkl; ++l) { if (systematic_absence(h, k, l, settings.centering)) continue; - const Coord g0 = AhBk + Cstar * static_cast(l); - const float g02 = g0 * g0; - - if (!(g02 > 0.0f)) - continue; - if (g02 > one_over_dmax_sq) + if (i >= max_reflections) continue; - // g0 = g_par + g_perp wrt spindle axis - const float g_par_s = g0 * w; - const Coord g_par = w * g_par_s; - const Coord g_perp = g0 - g_par; + const float g0_x = AhBk_x + Cstar.x * l; + const float g0_y = AhBk_y + Cstar.y * l; + const float g0_z = AhBk_z + Cstar.z * l; + const float g02 = g0_x * g0_x + g0_y * g0_y + g0_z * g0_z; - const float g_perp2 = g_perp * g_perp; - if (g_perp2 < 1e-12f) { - // Rotation does not move this reciprocal vector: skip for now. - // (Could be handled by checking whether it satisfies Ewald at all.) + if (g02 <= 0.0f || g02 > one_over_dmax_sq) continue; - } - // Equation: |S0 + g(phi)|^2 = |S0|^2 - // g(phi) = g_par + cos(phi) g_perp + sin(phi) (w x g_perp) - const Coord p = S0 + g_par; - const Coord w_x_gperp = w % g_perp; + const float g_par_s = g0_x * w.x + g0_y * w.y + g0_z * w.z; + const float g_par_x = w.x * g_par_s; + const float g_par_y = w.y * g_par_s; + const float g_par_z = w.z * g_par_s; - const float A = 2.0f * (p * g_perp); - const float B = 2.0f * (p * w_x_gperp); - const float D = (p * p) + g_perp2 - k2; + const float g_perp_x = g0_x - g_par_x; + const float g_perp_y = g0_y - g_par_y; + const float g_perp_z = g0_z - g_par_z; + + const float g_perp2 = g_perp_x * g_perp_x + g_perp_y * g_perp_y + g_perp_z * g_perp_z; + if (g_perp2 < 1e-12f) + continue; + + const float p_x = S0.x + g_par_x; + const float p_y = S0.y + g_par_y; + const float p_z = S0.z + g_par_z; + + const float w_x_gperp_x = w.y * g_perp_z - w.z * g_perp_y; + const float w_x_gperp_y = w.z * g_perp_x - w.x * g_perp_z; + const float w_x_gperp_z = w.x * g_perp_y - w.y * g_perp_x; + + const float A_trig = 2.0f * (p_x * g_perp_x + p_y * g_perp_y + p_z * g_perp_z); + const float B_trig = 2.0f * (p_x * w_x_gperp_x + p_y * w_x_gperp_y + p_z * w_x_gperp_z); + const float D_trig = (p_x * p_x + p_y * p_y + p_z * p_z) + g_perp2 - one_over_wavelength_sq; float sols[2]{}; - const int nsol = solve_trig(A, B, D, phi0, phi1, sols); - if (nsol == 0) - continue; + const int nsol = solve_trig(A_trig, B_trig, D_trig, phi0, phi1, sols); for (int si = 0; si < nsol; ++si) { + if (i >= max_reflections) break; + const float phi = sols[si]; + const float cos_p = cosf(phi); + const float sin_p = sinf(phi); - // Rotate g0 by phi about w - const RotMatrix R(phi, w); - const Coord g = R * g0; - const Coord S = S0 + g; + // Rodrigues' rotation formula: g = g_par + cos(phi)*g_perp + sin(phi)*(w x g_perp) + const float g_x = g_par_x + cos_p * g_perp_x + sin_p * w_x_gperp_x; + const float g_y = g_par_y + cos_p * g_perp_y + sin_p * w_x_gperp_y; + const float g_z = g_par_z + cos_p * g_perp_z + sin_p * w_x_gperp_z; - // Project to detector using canonical geometry code - const auto [x, y] = geom.RecipToDector(g); - if (!std::isfinite(x) || !std::isfinite(y)) - continue; - if (x < 0.0f || x >= det_w || y < 0.0f || y >= det_h) + const float S_x = S0.x + g_x; + const float S_y = S0.y + g_y; + const float S_z = S0.z + g_z; + + // Inlined RecipToDector + const float S_rot_x = rot[0] * S_x + rot[1] * S_y + rot[2] * S_z; + const float S_rot_y = rot[3] * S_x + rot[4] * S_y + rot[5] * S_z; + const float S_rot_z = rot[6] * S_x + rot[7] * S_y + rot[8] * S_z; + + if (S_rot_z <= 0) continue; - // Convert phi to fractional image number + const float coeff = coeff_const / S_rot_z; + const float x = beam_x + S_rot_x * coeff; + const float y = beam_y + S_rot_y * coeff; + + if (x < 0.0f || x >= det_width_pxl || y < 0.0f || y >= det_height_pxl) + continue; + + float d = 1.0f / sqrtf(g02); const float phi_deg = rad_to_deg(phi); - - Reflection r{}; - r.h = h; - r.k = k; - r.l = l; - r.angle_deg = phi_deg; - r.image_number = phi_deg_to_image_number(phi_deg, start_deg, inc_deg); - r.predicted_x = x; - r.predicted_y = y; - r.d = 1.0f / std::sqrt(g02); - - // diagnostic: should be ~0 - r.dist_ewald = S.Length() - std::sqrt(k2); - - r.I = 0.0f; - r.bkg = 0.0f; - r.sigma = 0.0f; - - out.push_back(r); + reflections[i] = Reflection{ + .h = h, + .k = k, + .l = l, + .angle_deg = phi_deg, + .predicted_x = x, + .predicted_y = y, + .d = d, + .dist_ewald = sqrtf(S_x * S_x + S_y * S_y + S_z * S_z) - one_over_wavelength, + }; + ++i; } } } } - - std::sort(out.begin(), out.end(), [](const Reflection &a, const Reflection &b) { - if (a.angle_deg != b.angle_deg) - return a.angle_deg < b.angle_deg; - if (a.h != b.h) return a.h < b.h; - if (a.k != b.k) return a.k < b.k; - return a.l < b.l; - }); - - return out; -} + return i; +} \ No newline at end of file diff --git a/image_analysis/bragg_prediction/BraggPredictionRotation.h b/image_analysis/bragg_prediction/BraggPredictionRotation.h index 417f6ec1..6c4de590 100644 --- a/image_analysis/bragg_prediction/BraggPredictionRotation.h +++ b/image_analysis/bragg_prediction/BraggPredictionRotation.h @@ -10,28 +10,16 @@ #include "../../common/CrystalLattice.h" #include "../../common/DiffractionExperiment.h" #include "../../common/Reflection.h" +#include "BraggPrediction.h" -struct BraggPredictionRotationSettings { - float high_res_A = 1.5f; - int max_hkl = 100; - char centering = 'P'; - // Predict only in this image interval (inclusive) - int64_t image_first = 0; - int64_t image_last = 0; - - // If true, expands [phi_start, phi_end] by one wedge on each side - // (useful if you later want to model partials / edge effects). - bool pad_one_wedge = false; -}; - -class BraggPredictionRotation { +class BraggPredictionRotation : public BraggPrediction { public: - BraggPredictionRotation() = default; + BraggPredictionRotation(int max_reflections); - std::vector Calc(const DiffractionExperiment& experiment, - const CrystalLattice& lattice, - const BraggPredictionRotationSettings& settings) const; + int Calc(const DiffractionExperiment &experiment, + const CrystalLattice &lattice, + const BraggPredictionSettings &settings) override; }; -- 2.49.1 From 2ba69d37c58b110f9ae1b04d8e9b6f8c76463808 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Thu, 18 Dec 2025 11:57:58 +0100 Subject: [PATCH 16/96] BraggPredictionRotation: Work in progress --- .../BraggPredictionRotation.cpp | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/image_analysis/bragg_prediction/BraggPredictionRotation.cpp b/image_analysis/bragg_prediction/BraggPredictionRotation.cpp index 94a849c3..96ab3d55 100644 --- a/image_analysis/bragg_prediction/BraggPredictionRotation.cpp +++ b/image_analysis/bragg_prediction/BraggPredictionRotation.cpp @@ -111,6 +111,10 @@ int BraggPredictionRotation::Calc(const DiffractionExperiment &experiment, const float phi0 = deg_to_rad(phi0_deg); const float phi1 = deg_to_rad(phi1_deg); + // Convert mosaicity to radians (assumes settings has this field, or defaults to small value) + const float mosaicity_rad = deg_to_rad(settings.mosaicity_deg); + const float half_mosaicity = mosaicity_rad * 0.5f; + const Coord w = gon.GetAxis().Normalize(); int i = 0; @@ -166,12 +170,31 @@ int BraggPredictionRotation::Calc(const DiffractionExperiment &experiment, const float D_trig = (p_x * p_x + p_y * p_y + p_z * p_z) + g_perp2 - one_over_wavelength_sq; float sols[2]{}; - const int nsol = solve_trig(A_trig, B_trig, D_trig, phi0, phi1, sols); + const int nsol = solve_trig(A_trig, B_trig, D_trig, phi0 - half_mosaicity, phi1 + half_mosaicity, sols); for (int si = 0; si < nsol; ++si) { if (i >= max_reflections) break; const float phi = sols[si]; + + // Rossmann partiality model (geometric overlap) + // Reflection interval: [phi - half_mosaicity, phi + half_mosaicity] + // Image interval: [phi0, phi1] + float refl_start = phi - half_mosaicity; + float refl_end = phi + half_mosaicity; + + float overlap_start = std::max(refl_start, phi0); + float overlap_end = std::min(refl_end, phi1); + + if (overlap_end < overlap_start) + continue; // No physical overlap + + float partiality = 1.0f; + if (mosaicity_rad > 1e-6f) { + partiality = (overlap_end - overlap_start) / mosaicity_rad; + if (partiality > 1.0f) partiality = 1.0f; + } + const float cos_p = cosf(phi); const float sin_p = sinf(phi); @@ -210,6 +233,7 @@ int BraggPredictionRotation::Calc(const DiffractionExperiment &experiment, .predicted_y = y, .d = d, .dist_ewald = sqrtf(S_x * S_x + S_y * S_y + S_z * S_z) - one_over_wavelength, + .partiality = partiality }; ++i; } -- 2.49.1 From 84237d0e388f134ce6c14d1f70b9c777c888086f Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Thu, 18 Dec 2025 12:32:03 +0100 Subject: [PATCH 17/96] BraggPrediction: Work in progress --- common/Reflection.h | 1 - image_analysis/IndexAndRefine.cpp | 2 +- .../bragg_prediction/BraggPrediction.h | 4 +--- .../BraggPredictionRotation.cpp | 23 ++----------------- 4 files changed, 4 insertions(+), 26 deletions(-) diff --git a/common/Reflection.h b/common/Reflection.h index 8b1ccb29..00b960dc 100644 --- a/common/Reflection.h +++ b/common/Reflection.h @@ -22,7 +22,6 @@ struct Reflection { float sigma; float dist_ewald; bool observed = false; - float partiality = 1.0; }; #endif //JFJOCH_REFLECTION_H diff --git a/image_analysis/IndexAndRefine.cpp b/image_analysis/IndexAndRefine.cpp index 2bfd1989..dc8094d3 100644 --- a/image_analysis/IndexAndRefine.cpp +++ b/image_analysis/IndexAndRefine.cpp @@ -141,9 +141,9 @@ void IndexAndRefine::QuickPredictAndIntegrate(DataMessage &msg, BraggPredictionSettings settings_prediction{ .high_res_A = experiment.GetBraggIntegrationSettings().GetDMinLimit_A(), + .ewald_dist_cutoff = ewald_dist_cutoff, .max_hkl = 100, .centering = outcome.symmetry.centering, - .ewald_dist_cutoff = ewald_dist_cutoff, }; auto nrefl = prediction.Calc(experiment, *outcome.lattice_candidate, settings_prediction); diff --git a/image_analysis/bragg_prediction/BraggPrediction.h b/image_analysis/bragg_prediction/BraggPrediction.h index cf067f01..3c46bbff 100644 --- a/image_analysis/bragg_prediction/BraggPrediction.h +++ b/image_analysis/bragg_prediction/BraggPrediction.h @@ -12,12 +12,10 @@ struct BraggPredictionSettings { float high_res_A = 1.5; + float ewald_dist_cutoff = 0.0005; int max_hkl = 100; char centering = 'P'; - // Still parameters - float ewald_dist_cutoff = 0.0005; - // Rotation parameters Coord rotation_axis = Coord(1, 0, 0); int image_number = 0; diff --git a/image_analysis/bragg_prediction/BraggPredictionRotation.cpp b/image_analysis/bragg_prediction/BraggPredictionRotation.cpp index 96ab3d55..23315bba 100644 --- a/image_analysis/bragg_prediction/BraggPredictionRotation.cpp +++ b/image_analysis/bragg_prediction/BraggPredictionRotation.cpp @@ -176,25 +176,7 @@ int BraggPredictionRotation::Calc(const DiffractionExperiment &experiment, if (i >= max_reflections) break; const float phi = sols[si]; - - // Rossmann partiality model (geometric overlap) - // Reflection interval: [phi - half_mosaicity, phi + half_mosaicity] - // Image interval: [phi0, phi1] - float refl_start = phi - half_mosaicity; - float refl_end = phi + half_mosaicity; - - float overlap_start = std::max(refl_start, phi0); - float overlap_end = std::min(refl_end, phi1); - - if (overlap_end < overlap_start) - continue; // No physical overlap - - float partiality = 1.0f; - if (mosaicity_rad > 1e-6f) { - partiality = (overlap_end - overlap_start) / mosaicity_rad; - if (partiality > 1.0f) partiality = 1.0f; - } - + const float cos_p = cosf(phi); const float sin_p = sinf(phi); @@ -232,8 +214,7 @@ int BraggPredictionRotation::Calc(const DiffractionExperiment &experiment, .predicted_x = x, .predicted_y = y, .d = d, - .dist_ewald = sqrtf(S_x * S_x + S_y * S_y + S_z * S_z) - one_over_wavelength, - .partiality = partiality + .dist_ewald = sqrtf(S_x * S_x + S_y * S_y + S_z * S_z) - one_over_wavelength }; ++i; } -- 2.49.1 From 2971b20b8764e2e19cb56a8f1b2990ff05dbf82a Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Thu, 18 Dec 2025 12:39:19 +0100 Subject: [PATCH 18/96] AnalyzeIndexing: Move mosaicity to a dedicated function + for rotation indexing always consider as indexed --- image_analysis/IndexAndRefine.cpp | 3 +- image_analysis/indexing/AnalyzeIndexing.cpp | 98 +++++++++++---------- image_analysis/indexing/AnalyzeIndexing.h | 3 +- 3 files changed, 55 insertions(+), 49 deletions(-) diff --git a/image_analysis/IndexAndRefine.cpp b/image_analysis/IndexAndRefine.cpp index dc8094d3..8bc8b50a 100644 --- a/image_analysis/IndexAndRefine.cpp +++ b/image_analysis/IndexAndRefine.cpp @@ -188,7 +188,8 @@ void IndexAndRefine::ProcessImage(DataMessage &msg, if (!outcome.lattice_candidate) return; - if (!AnalyzeIndexing(msg, outcome.experiment, *outcome.lattice_candidate, outcome.experiment.GetGoniometer())) + if (!AnalyzeIndexing(msg, outcome.experiment, *outcome.lattice_candidate, + outcome.experiment.GetGoniometer(), rotation_indexer.get() != nullptr)) return; msg.lattice_type = outcome.symmetry; diff --git a/image_analysis/indexing/AnalyzeIndexing.cpp b/image_analysis/indexing/AnalyzeIndexing.cpp index 14d95e3b..2937dcad 100644 --- a/image_analysis/indexing/AnalyzeIndexing.cpp +++ b/image_analysis/indexing/AnalyzeIndexing.cpp @@ -116,12 +116,58 @@ namespace { return rad_to_deg(best_phi); } + + std::optional CalcMosaicity(const DiffractionExperiment& experiment, + const std::vector &spots, + const Coord &astar, const Coord &bstar, const Coord &cstar) { + const auto &axis = experiment.GetGoniometer(); + if (axis.has_value()) { + const Coord w = axis->GetAxis().Normalize(); + const Coord S0 = experiment.GetScatteringVector(); + const float wedge_deg = axis->GetWedge_deg(); + const float start_deg = axis->GetStart_deg(); + const float inc_deg = axis->GetIncrement_deg(); + + double sum_sq = 0.0; + int count = 0; + + for (const auto &s: spots) { + if (!s.indexed) + continue; + + // Observed angle: use frame center + const float image_center = static_cast(s.image) + 0.5f; + const float phi_obs_deg = start_deg + inc_deg * image_center; + + // g0 at phi=0 assumption + const Coord g0 = astar * static_cast(s.h) + + bstar * static_cast(s.k) + + cstar * static_cast(s.l); + + // Local solve window: +/- 1 wedge (easy/robust first try) + const auto phi_pred_deg_opt = predict_phi_deg_local(g0, S0, w, phi_obs_deg, wedge_deg); + if (!phi_pred_deg_opt.has_value()) + continue; + + float dphi = wrap_deg_pm180(phi_obs_deg - phi_pred_deg_opt.value()); + sum_sq += static_cast(dphi) * static_cast(dphi); + count++; + } + + if (count > 0) { + return static_cast(std::sqrt(sum_sq / static_cast(count))); + } + } + return std::nullopt; + } + } // namespace bool AnalyzeIndexing(DataMessage &message, const DiffractionExperiment &experiment, const CrystalLattice &latt, - const std::optional &rotation_axis) { + const std::optional &rotation_axis, + bool rotation_indexed) { std::vector indexed_spots(message.spots.size()); // Check spots @@ -172,8 +218,9 @@ bool AnalyzeIndexing(DataMessage &message, nspots_ref++; } - if (nspots_indexed >= viable_cell_min_spots - && nspots_indexed >= std::lround(min_percentage_spots * nspots_ref)) { + if (rotation_indexed + || (nspots_indexed >= viable_cell_min_spots + && nspots_indexed >= std::lround(min_percentage_spots * nspots_ref))) { auto uc = latt.GetUnitCell(); if (!ok(uc.a) || !ok(uc.b) || !ok(uc.c) || !ok(uc.alpha) || !ok(uc.beta) || !ok(uc.gamma)) return false; @@ -187,50 +234,7 @@ bool AnalyzeIndexing(DataMessage &message, message.spot_count_indexed = nspots_indexed; message.indexing_lattice = latt; message.indexing_unit_cell = latt.GetUnitCell(); - - message.mosaicity_deg = std::nullopt; - if (rotation_axis.has_value()) { - const auto gon_opt = experiment.GetGoniometer(); - if (gon_opt.has_value()) { - const auto &gon = *gon_opt; - - const Coord w = rotation_axis->GetAxis().Normalize(); - const Coord S0 = geom.GetScatteringVector(); - const float wedge_deg = gon.GetWedge_deg(); - const float start_deg = gon.GetStart_deg(); - const float inc_deg = gon.GetIncrement_deg(); - - double sum_sq = 0.0; - int count = 0; - - for (const auto &s: message.spots) { - if (!s.indexed) - continue; - - // Observed angle: use frame center - const float image_center = static_cast(s.image) + 0.5f; - const float phi_obs_deg = start_deg + inc_deg * image_center; - - // g0 at phi=0 assumption - const Coord g0 = astar * static_cast(s.h) - + bstar * static_cast(s.k) - + cstar * static_cast(s.l); - - // Local solve window: +/- 1 wedge (easy/robust first try) - const auto phi_pred_deg_opt = predict_phi_deg_local(g0, S0, w, phi_obs_deg, wedge_deg); - if (!phi_pred_deg_opt.has_value()) - continue; - - float dphi = wrap_deg_pm180(phi_obs_deg - phi_pred_deg_opt.value()); - sum_sq += static_cast(dphi) * static_cast(dphi); - count++; - } - - if (count > 0) { - message.mosaicity_deg = static_cast(std::sqrt(sum_sq / static_cast(count))); - } - } - } + message.mosaicity_deg = CalcMosaicity(experiment, message.spots, astar, bstar, cstar); return true; } diff --git a/image_analysis/indexing/AnalyzeIndexing.h b/image_analysis/indexing/AnalyzeIndexing.h index 6757f3be..deb2b335 100644 --- a/image_analysis/indexing/AnalyzeIndexing.h +++ b/image_analysis/indexing/AnalyzeIndexing.h @@ -13,7 +13,8 @@ constexpr static float min_percentage_spots = 0.20f; bool AnalyzeIndexing(DataMessage &message, const DiffractionExperiment &experiment, const CrystalLattice &latt, - const std::optional &rotation_axis); + const std::optional &rotation_axis, + bool rotation_indexed); #endif //JFJOCH_ANALYZEINDEXING_H \ No newline at end of file -- 2.49.1 From 25f068e11110adf12bf279d5b5196a45e682cd2c Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Thu, 18 Dec 2025 13:13:39 +0100 Subject: [PATCH 19/96] BraggIntegrate: Add Lorentz factor (1/sin(2*theta)) for rotation measurment --- .../bragg_integration/BraggIntegrate2D.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/image_analysis/bragg_integration/BraggIntegrate2D.cpp b/image_analysis/bragg_integration/BraggIntegrate2D.cpp index a511fc12..499f05d9 100644 --- a/image_analysis/bragg_integration/BraggIntegrate2D.cpp +++ b/image_analysis/bragg_integration/BraggIntegrate2D.cpp @@ -91,14 +91,18 @@ std::vector IntegrateInternal(const DiffractionExperiment &experimen IntegrateReflection(r, ptr, image.GetWidth(), image.GetHeight(), special_value, saturation, r_3, r_1_sq, r_2_sq, r_3_sq); if (r.observed) { - if (experiment.GetPolarizationFactor()) { - float pol = geom.CalcAzIntPolarizationCorr(r.predicted_x, r.predicted_y, + float corr = 1.0; + if (experiment.GetPolarizationFactor()) + corr /= geom.CalcAzIntPolarizationCorr(r.predicted_x, r.predicted_y, experiment.GetPolarizationFactor().value()); - r.I /= pol; - r.bkg /= pol; - r.sigma /= pol; - } + if (experiment.GetGoniometer().has_value()) { + float two_theta = geom.TwoTheta_rad(r.predicted_x, r.predicted_y); + corr *= std::sin(two_theta); + } + r.I *= corr; + r.bkg *= corr; + r.sigma *= corr; r.image_number = static_cast(image_number); ret.emplace_back(r); } -- 2.49.1 From 1926431f7cbc1f1d216d5d1d1ffb726525aeb875 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Thu, 18 Dec 2025 13:13:59 +0100 Subject: [PATCH 20/96] ScaleAndMerge: Add (very much work in progress) --- image_analysis/CMakeLists.txt | 21 ++ image_analysis/geom_refinement/CMakeLists.txt | 19 - image_analysis/scale_merge/CMakeLists.txt | 2 + image_analysis/scale_merge/ScaleAndMerge.cpp | 347 ++++++++++++++++++ image_analysis/scale_merge/ScaleAndMerge.h | 55 +++ 5 files changed, 425 insertions(+), 19 deletions(-) create mode 100644 image_analysis/scale_merge/CMakeLists.txt create mode 100644 image_analysis/scale_merge/ScaleAndMerge.cpp create mode 100644 image_analysis/scale_merge/ScaleAndMerge.h diff --git a/image_analysis/CMakeLists.txt b/image_analysis/CMakeLists.txt index b9d3f310..517844ec 100644 --- a/image_analysis/CMakeLists.txt +++ b/image_analysis/CMakeLists.txt @@ -1,3 +1,23 @@ +SET(MINIGLOG ON) +SET(PROVIDE_UNINSTALL_TARGET OFF) +SET(USE_CUDA OFF) +SET(EIGENSPARSE ON) +SET(LAPACK OFF) +SET(SUITESPARSE OFF) + +# Prevent MKL/BLAS/LAPACK from being found (guarantees no MKL) +SET(CMAKE_DISABLE_FIND_PACKAGE_MKL TRUE) +SET(CERES_THREADING_MODEL "OFF") + +FetchContent_Declare( + ceres + GIT_REPOSITORY https://github.com/ceres-solver/ceres-solver + GIT_TAG 0c70ed3 + EXCLUDE_FROM_ALL +) + +FetchContent_MakeAvailable(ceres) + ADD_LIBRARY(JFJochImageAnalysis STATIC MXAnalysisWithoutFPGA.cpp MXAnalysisWithoutFPGA.h @@ -18,5 +38,6 @@ ADD_SUBDIRECTORY(bragg_prediction) ADD_SUBDIRECTORY(indexing) ADD_SUBDIRECTORY(geom_refinement) ADD_SUBDIRECTORY(lattice_search) +ADD_SUBDIRECTORY(scale_merge) TARGET_LINK_LIBRARIES(JFJochImageAnalysis JFJochBraggPrediction JFJochBraggIntegration JFJochLatticeSearch JFJochIndexing JFJochSpotFinding JFJochCommon JFJochGeomRefinement gemmi) diff --git a/image_analysis/geom_refinement/CMakeLists.txt b/image_analysis/geom_refinement/CMakeLists.txt index e32becb5..a81b8b54 100644 --- a/image_analysis/geom_refinement/CMakeLists.txt +++ b/image_analysis/geom_refinement/CMakeLists.txt @@ -1,22 +1,3 @@ -SET(MINIGLOG ON) -SET(PROVIDE_UNINSTALL_TARGET OFF) -SET(USE_CUDA OFF) -SET(EIGENSPARSE ON) -SET(LAPACK OFF) -SET(SUITESPARSE OFF) - -# Prevent MKL/BLAS/LAPACK from being found (guarantees no MKL) -SET(CMAKE_DISABLE_FIND_PACKAGE_MKL TRUE) -SET(CERES_THREADING_MODEL "OFF") - -FetchContent_Declare( - ceres - GIT_REPOSITORY https://github.com/ceres-solver/ceres-solver - GIT_TAG 0c70ed3 - EXCLUDE_FROM_ALL -) - -FetchContent_MakeAvailable(ceres) ADD_LIBRARY(JFJochGeomRefinement STATIC RingOptimizer.cpp diff --git a/image_analysis/scale_merge/CMakeLists.txt b/image_analysis/scale_merge/CMakeLists.txt new file mode 100644 index 00000000..8b8b99d7 --- /dev/null +++ b/image_analysis/scale_merge/CMakeLists.txt @@ -0,0 +1,2 @@ +ADD_LIBRARY(JFJochScaleMerge ScaleAndMerge.cpp ScaleAndMerge.h) +TARGET_LINK_LIBRARIES(JFJochScaleMerge Ceres::ceres Eigen3::Eigen JFJochCommon) \ No newline at end of file diff --git a/image_analysis/scale_merge/ScaleAndMerge.cpp b/image_analysis/scale_merge/ScaleAndMerge.cpp new file mode 100644 index 00000000..9d134fd2 --- /dev/null +++ b/image_analysis/scale_merge/ScaleAndMerge.cpp @@ -0,0 +1,347 @@ +// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute +// SPDX-License-Identifier: GPL-3.0-only + +#include "ScaleAndMerge.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { + +struct HKLKey { + int64_t h = 0; + int64_t k = 0; + int64_t l = 0; + bool is_positive = true; // only relevant if opt.merge_friedel == false + + bool operator==(const HKLKey& o) const noexcept { + return h == o.h && k == o.k && l == o.l && is_positive == o.is_positive; + } +}; + +struct HKLKeyHash { + size_t operator()(const HKLKey& key) const noexcept { + auto mix = [](uint64_t x) { + x ^= x >> 33; + x *= 0xff51afd7ed558ccdULL; + x ^= x >> 33; + x *= 0xc4ceb9fe1a85ec53ULL; + x ^= x >> 33; + return x; + }; + const uint64_t a = static_cast(key.h); + const uint64_t b = static_cast(key.k); + const uint64_t c = static_cast(key.l); + const uint64_t d = static_cast(key.is_positive ? 1 : 0); + return static_cast(mix(a) ^ (mix(b) << 1) ^ (mix(c) << 2) ^ (mix(d) << 3)); + } +}; + +inline int RoundImageId(float image_number, double rounding_step) { + if (!(rounding_step > 0.0)) + rounding_step = 1.0; + const double x = static_cast(image_number) / rounding_step; + const double r = std::round(x) * rounding_step; + return static_cast(std::llround(r / rounding_step)); +} + +inline double SafeSigma(double s, double min_sigma) { + if (!std::isfinite(s) || s <= 0.0) + return min_sigma; + return std::max(s, min_sigma); +} + +inline double SafeD(double d) { + if (!std::isfinite(d) || d <= 0.0) + return std::numeric_limits::quiet_NaN(); + return d; +} + +inline int SafeToInt(int64_t x) { + if (x < std::numeric_limits::min() || x > std::numeric_limits::max()) + throw std::out_of_range("HKL index out of int range for Gemmi"); + return static_cast(x); +} + +// Canonicalize HKL according to Gemmi Reciprocal ASU if space group is provided. +// If merge_friedel==true -> Friedel mates collapse (key.is_positive always true). +// If merge_friedel==false -> keep I+ vs I- separate by key.is_positive. +inline HKLKey CanonicalizeHKLKey(const Reflection& r, const ScaleMergeOptions& opt) { + HKLKey key{}; + key.h = r.h; + key.k = r.k; + key.l = r.l; + key.is_positive = true; + + // If no SG provided, we can still optionally separate Friedel mates deterministically. + if (!opt.space_group.has_value()) { + if (!opt.merge_friedel) { + const HKLKey neg{-r.h, -r.k, -r.l, true}; + const bool pos = std::tie(key.h, key.k, key.l) >= std::tie(neg.h, neg.k, neg.l); + if (!pos) { + key.h = -key.h; + key.k = -key.k; + key.l = -key.l; + key.is_positive = false; + } + } + return key; + } + + const gemmi::SpaceGroup& sg = *opt.space_group; + const gemmi::GroupOps gops = sg.operations(); + const gemmi::ReciprocalAsu rasu(&sg); + + const gemmi::Op::Miller in{{SafeToInt(r.h), SafeToInt(r.k), SafeToInt(r.l)}}; + const auto [asu_hkl, sign_plus] = rasu.to_asu_sign(in, gops); + + key.h = asu_hkl[0]; + key.k = asu_hkl[1]; + key.l = asu_hkl[2]; + key.is_positive = opt.merge_friedel ? true : sign_plus; + return key; +} + +struct IntensityResidual { + IntensityResidual(double Iobs, double sigma, double s2, bool refine_b) + : Iobs_(Iobs), inv_sigma_(1.0 / sigma), s2_(s2), refine_b_(refine_b) {} + + template + bool operator()(const T* const log_k, + const T* const b, + const T* const log_Ihkl, + T* residual) const { + const T k = ceres::exp(log_k[0]); + const T Ihkl = ceres::exp(log_Ihkl[0]); + + T atten = T(1); + if (refine_b_) { + // I_pred = k * exp(-B*s^2) * I_hkl + atten = ceres::exp(-b[0] * T(s2_)); + } + + const T Ipred = k * atten * Ihkl; + residual[0] = (Ipred - T(Iobs_)) * T(inv_sigma_); + return true; + } + + double Iobs_; + double inv_sigma_; + double s2_; + bool refine_b_; +}; + +} // namespace + +ScaleMergeResult ScaleAndMergeReflectionsCeres(const std::vector& observations, + const ScaleMergeOptions& opt) { + ScaleMergeResult out; + + struct ObsRef { + const Reflection* r = nullptr; + int img_id = 0; // rounded/quantized image id + int img_slot = -1; // compact [0..nimg) + int hkl_slot = -1; // compact [0..nhkl) + double s2 = 0.0; + double sigma = 0.0; + }; + + std::vector obs; + obs.reserve(observations.size()); + + std::unordered_map imgIdToSlot; + imgIdToSlot.reserve(256); + + std::unordered_map hklToSlot; + hklToSlot.reserve(observations.size()); + + for (const auto& r : observations) { + const double d = SafeD(r.d); + if (!std::isfinite(d)) + continue; + if (!std::isfinite(r.I)) + continue; + + const double sigma = SafeSigma(static_cast(r.sigma), opt.min_sigma); + const double s2 = 1.0 / (d * d); + + const int img_id = RoundImageId(r.image_number, opt.image_number_rounding); + + int img_slot; + { + auto it = imgIdToSlot.find(img_id); + if (it == imgIdToSlot.end()) { + img_slot = static_cast(imgIdToSlot.size()); + imgIdToSlot.emplace(img_id, img_slot); + } else { + img_slot = it->second; + } + } + + int hkl_slot; + try { + const HKLKey key = CanonicalizeHKLKey(r, opt); + auto it = hklToSlot.find(key); + if (it == hklToSlot.end()) { + hkl_slot = static_cast(hklToSlot.size()); + hklToSlot.emplace(key, hkl_slot); + } else { + hkl_slot = it->second; + } + } catch (...) { + continue; // skip problematic HKL + } + + ObsRef o; + o.r = &r; + o.img_id = img_id; + o.img_slot = img_slot; + o.hkl_slot = hkl_slot; + o.s2 = s2; + o.sigma = sigma; + obs.push_back(o); + } + + const int nimg = static_cast(imgIdToSlot.size()); + const int nhkl = static_cast(hklToSlot.size()); + + out.image_scale_k.assign(nimg, 1.0); + out.image_b_factor.assign(nimg, 0.0); + out.image_ids.assign(nimg, 0); + + for (const auto& kv : imgIdToSlot) { + out.image_ids[kv.second] = kv.first; + } + + std::vector log_k(nimg, 0.0); + std::vector b(nimg, 0.0); + std::vector log_Ihkl(nhkl, 0.0); + + // Initialize Ihkl from per-HKL median of observed intensities. + { + std::vector> per_hkl_I(nhkl); + for (const auto& o : obs) { + per_hkl_I[o.hkl_slot].push_back(static_cast(o.r->I)); + } + for (int h = 0; h < nhkl; ++h) { + auto& v = per_hkl_I[h]; + if (v.empty()) { + log_Ihkl[h] = std::log(std::max(opt.min_sigma, 1e-6)); + continue; + } + std::nth_element(v.begin(), v.begin() + static_cast(v.size() / 2), v.end()); + double med = v[v.size() / 2]; + if (!std::isfinite(med) || med <= opt.min_sigma) + med = opt.min_sigma; + log_Ihkl[h] = std::log(med); + } + } + + ceres::Problem problem; + + std::unique_ptr loss; + if (opt.use_huber_loss) { + loss = std::make_unique(opt.huber_delta); + } + + for (const auto& o : obs) { + const double Iobs = static_cast(o.r->I); + + auto* cost = new ceres::AutoDiffCostFunction( + new IntensityResidual(Iobs, o.sigma, o.s2, opt.refine_b_factor)); + + problem.AddResidualBlock(cost, + loss.get(), + &log_k[o.img_slot], + &b[o.img_slot], + &log_Ihkl[o.hkl_slot]); + } + + // Fix gauge freedom: anchor first image scale to 1.0 + if (opt.fix_first_image_scale && nimg > 0) { + log_k[0] = 0.0; + problem.SetParameterBlockConstant(&log_k[0]); + } + + if (!opt.refine_b_factor) { + for (int i = 0; i < nimg; ++i) { + b[i] = 0.0; + problem.SetParameterBlockConstant(&b[i]); + } + } else { + for (int i = 0; i < nimg; ++i) { + if (opt.b_min) + problem.SetParameterLowerBound(&b[i], 0, *opt.b_min); + if (opt.b_max) + problem.SetParameterUpperBound(&b[i], 0, *opt.b_max); + } + } + + ceres::Solver::Options options; + options.linear_solver_type = ceres::SPARSE_NORMAL_CHOLESKY; + options.minimizer_progress_to_stdout = false; + options.logging_type = ceres::LoggingType::SILENT; + options.max_num_iterations = opt.max_num_iterations; + options.max_solver_time_in_seconds = opt.max_solver_time_s; + + ceres::Solver::Summary summary; + ceres::Solve(options, &problem, &summary); + + for (int i = 0; i < nimg; ++i) { + out.image_scale_k[i] = std::exp(log_k[i]); + out.image_b_factor[i] = opt.refine_b_factor ? b[i] : 0.0; + } + + // Reverse maps for merged output + std::vector slotToHKL(nhkl); + for (const auto& kv : hklToSlot) { + slotToHKL[kv.second] = kv.first; + } + + // crude sigma estimate from model residual scatter + std::vector n_per_hkl(nhkl, 0); + std::vector ss_per_hkl(nhkl, 0.0); + + for (const auto& o : obs) { + const int i = o.img_slot; + const int h = o.hkl_slot; + + const double k = std::exp(log_k[i]); + const double atten = opt.refine_b_factor ? std::exp(-b[i] * o.s2) : 1.0; + const double Ihkl = std::exp(log_Ihkl[h]); + + const double Ipred = k * atten * Ihkl; + const double r = (Ipred - static_cast(o.r->I)); + + n_per_hkl[h] += 1; + ss_per_hkl[h] += r * r; + } + + out.merged.reserve(nhkl); + for (int h = 0; h < nhkl; ++h) { + MergedReflection m{}; + m.h = slotToHKL[h].h; + m.k = slotToHKL[h].k; + m.l = slotToHKL[h].l; + m.I = static_cast(std::exp(log_Ihkl[h])); + + if (n_per_hkl[h] >= 2) { + const double rms = std::sqrt(ss_per_hkl[h] / static_cast(n_per_hkl[h] - 1)); + m.sigma = static_cast(rms / std::sqrt(static_cast(n_per_hkl[h]))); + } else { + m.sigma = std::numeric_limits::quiet_NaN(); + } + + out.merged.push_back(m); + } + + return out; +} \ No newline at end of file diff --git a/image_analysis/scale_merge/ScaleAndMerge.h b/image_analysis/scale_merge/ScaleAndMerge.h new file mode 100644 index 00000000..f14658df --- /dev/null +++ b/image_analysis/scale_merge/ScaleAndMerge.h @@ -0,0 +1,55 @@ +// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute +// SPDX-License-Identifier: GPL-3.0-only + +#pragma once + +#include +#include +#include + +#include "../../common/Reflection.h" +#include "gemmi/symmetry.hpp" + +struct ScaleMergeOptions { + bool refine_b_factor = true; + + bool use_huber_loss = true; + double huber_delta = 2.0; + + int max_num_iterations = 100; + double max_solver_time_s = 1.0; + + double image_number_rounding = 1.0; + double min_sigma = 1e-3; + + bool fix_first_image_scale = true; + + std::optional b_min = 0.0; + std::optional b_max = 200.0; + + // Symmetry canonicalization of HKL prior to merging/scaling. + // If not set, the routine uses raw HKL as-is. + std::optional space_group; + + // If true, treat Friedel mates as equivalent (merge anomalous pairs). + // If false, keep them separate by including a sign flag in the HKL key. + bool merge_friedel = true; +}; + +struct MergedReflection { + int h; + int k; + int l; + double I; + double sigma; +}; + +struct ScaleMergeResult { + std::vector merged; + std::vector image_scale_k; + std::vector image_b_factor; + std::vector image_ids; +}; + +ScaleMergeResult ScaleAndMergeReflectionsCeres(const std::vector& observations, + const ScaleMergeOptions& opt = {}); -- 2.49.1 From c2559ed51065a39b5d90de6f091a5e6184a2038c Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Sun, 21 Dec 2025 14:10:27 +0100 Subject: [PATCH 21/96] BraggIntegrate2D: Fix missing return statement --- image_analysis/bragg_integration/BraggIntegrate2D.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/image_analysis/bragg_integration/BraggIntegrate2D.cpp b/image_analysis/bragg_integration/BraggIntegrate2D.cpp index 499f05d9..fa6dc6b1 100644 --- a/image_analysis/bragg_integration/BraggIntegrate2D.cpp +++ b/image_analysis/bragg_integration/BraggIntegrate2D.cpp @@ -107,6 +107,7 @@ std::vector IntegrateInternal(const DiffractionExperiment &experimen ret.emplace_back(r); } } + return ret; } std::vector BraggIntegrate2D(const DiffractionExperiment &experiment, -- 2.49.1 From 68e99afc9ee44fd169c675c7e8b98d1ee5bb00cd Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Sat, 3 Jan 2026 14:50:10 +0100 Subject: [PATCH 22/96] BraggPredictionRotation: Guard for negative rotation direction --- image_analysis/bragg_prediction/BraggPredictionRotation.cpp | 2 ++ image_analysis/bragg_prediction/BraggPredictionRotation.h | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/image_analysis/bragg_prediction/BraggPredictionRotation.cpp b/image_analysis/bragg_prediction/BraggPredictionRotation.cpp index 23315bba..a1305e52 100644 --- a/image_analysis/bragg_prediction/BraggPredictionRotation.cpp +++ b/image_analysis/bragg_prediction/BraggPredictionRotation.cpp @@ -27,6 +27,8 @@ namespace { inline int solve_trig(float A, float B, float D, float phi0, float phi1, float out_phi[2]) { + if (phi1 < phi0) std::swap(phi0, phi1); + const float R = std::sqrt(A*A + B*B); if (!(R > 0.0f)) return 0; diff --git a/image_analysis/bragg_prediction/BraggPredictionRotation.h b/image_analysis/bragg_prediction/BraggPredictionRotation.h index 6c4de590..a411f3d5 100644 --- a/image_analysis/bragg_prediction/BraggPredictionRotation.h +++ b/image_analysis/bragg_prediction/BraggPredictionRotation.h @@ -15,7 +15,7 @@ class BraggPredictionRotation : public BraggPrediction { public: - BraggPredictionRotation(int max_reflections); + BraggPredictionRotation(int max_reflections = 200*200*200); int Calc(const DiffractionExperiment &experiment, const CrystalLattice &lattice, -- 2.49.1 From fae05a5cfebec279f47a7463a9813643ac08b11a Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Sat, 3 Jan 2026 15:02:26 +0100 Subject: [PATCH 23/96] BraggPrediction: Minor improvements - predict from -max_hkl to +max_hkl (incl. +max_hkl); small fixed in notation --- .../bragg_prediction/BraggPrediction.cpp | 12 +++++------ .../bragg_prediction/BraggPredictionGPU.cu | 20 +++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/image_analysis/bragg_prediction/BraggPrediction.cpp b/image_analysis/bragg_prediction/BraggPrediction.cpp index 00f2389b..ab7eb892 100644 --- a/image_analysis/bragg_prediction/BraggPrediction.cpp +++ b/image_analysis/bragg_prediction/BraggPrediction.cpp @@ -39,19 +39,19 @@ int BraggPrediction::Calc(const DiffractionExperiment &experiment, const Crystal int i = 0; - for (int h = -settings.max_hkl; h < settings.max_hkl; h++) { + for (int h = -settings.max_hkl; h <= settings.max_hkl; h++) { // Precompute A* h contribution const float Ah_x = Astar.x * h; const float Ah_y = Astar.y * h; const float Ah_z = Astar.z * h; - for (int k = -settings.max_hkl; k < settings.max_hkl; k++) { + for (int k = -settings.max_hkl; k <= settings.max_hkl; k++) { // Accumulate B* k contribution const float AhBk_x = Ah_x + Bstar.x * k; const float AhBk_y = Ah_y + Bstar.y * k; const float AhBk_z = Ah_z + Bstar.z * k; - for (int l = -settings.max_hkl; l < settings.max_hkl; l++) { + for (int l = -settings.max_hkl; l <= settings.max_hkl; l++) { if (systematic_absence(h, k, l, settings.centering)) continue; @@ -62,8 +62,8 @@ int BraggPrediction::Calc(const DiffractionExperiment &experiment, const Crystal float recip_y = AhBk_y + Cstar.y * l; float recip_z = AhBk_z + Cstar.z * l; - float dot = recip_x * recip_x + recip_y * recip_y + recip_z * recip_z; - if (dot > one_over_dmax_sq) + float recip_sq = recip_x * recip_x + recip_y * recip_y + recip_z * recip_z; + if (recip_sq > one_over_dmax_sq) continue; float S_x = recip_x + S0.x; @@ -90,7 +90,7 @@ int BraggPrediction::Calc(const DiffractionExperiment &experiment, const Crystal if ((x < 0) || (x >= det_width_pxl) || (y < 0) || (y >= det_height_pxl)) continue; - float d = 1.0f / sqrtf(dot); + float d = 1.0f / sqrtf(recip_sq); reflections[i] = Reflection{ .h = h, .k = k, diff --git a/image_analysis/bragg_prediction/BraggPredictionGPU.cu b/image_analysis/bragg_prediction/BraggPredictionGPU.cu index 7ac8f1fb..b80563d4 100644 --- a/image_analysis/bragg_prediction/BraggPredictionGPU.cu +++ b/image_analysis/bragg_prediction/BraggPredictionGPU.cu @@ -55,14 +55,14 @@ namespace { float AhBk_x = Ah_x + C.Bstar.x * k; float AhBk_y = Ah_y + C.Bstar.y * k; float AhBk_z = Ah_z + C.Bstar.z * k; - float rx = AhBk_x + C.Cstar.x * l; - float ry = AhBk_y + C.Cstar.y * l; - float rz = AhBk_z + C.Cstar.z * l; - float dot = rx * rx + ry * ry + rz * rz; - if (dot > C.one_over_dmax_sq) return false; - float Sx = rx + C.S0.x; - float Sy = ry + C.S0.y; - float Sz = rz + C.S0.z; + float recip_x = AhBk_x + C.Cstar.x * l; + float recip_y = AhBk_y + C.Cstar.y * l; + float recip_z = AhBk_z + C.Cstar.z * l; + float recip_sq = recip_x * recip_x + recip_y * recip_y + recip_z * recip_z; + if (recip_sq > C.one_over_dmax_sq) return false; + float Sx = recip_x + C.S0.x; + float Sy = recip_y + C.S0.y; + float Sz = recip_z + C.S0.z; float S_len = sqrtf(Sx * Sx + Sy * Sy + Sz * Sz); float dist_ewald = fabsf(S_len - C.one_over_wavelength); if (dist_ewald > C.ewald_cutoff) return false; @@ -79,7 +79,7 @@ namespace { out.l = l; out.predicted_x = x; out.predicted_y = y; - out.d = 1.0f / sqrtf(dot); + out.d = 1.0f / sqrtf(recip_sq); out.dist_ewald = dist_ewald; return true; } @@ -89,7 +89,7 @@ namespace { int max_reflections, Reflection *__restrict__ out, int *__restrict__ counter) { - int range = 2 * max_hkl; + int range = 2 * max_hkl + 1; int hi = blockIdx.x * blockDim.x + threadIdx.x; int ki = blockIdx.y * blockDim.y + threadIdx.y; int li = blockIdx.z * blockDim.z + threadIdx.z; -- 2.49.1 From ffb4fa3b29188308a677e8f5a294afffc50088fc Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Sat, 3 Jan 2026 15:04:35 +0100 Subject: [PATCH 24/96] BraggPredictionRotation: Minor fixes to improve readability --- .../BraggPredictionRotation.cpp | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/image_analysis/bragg_prediction/BraggPredictionRotation.cpp b/image_analysis/bragg_prediction/BraggPredictionRotation.cpp index a1305e52..40b90114 100644 --- a/image_analysis/bragg_prediction/BraggPredictionRotation.cpp +++ b/image_analysis/bragg_prediction/BraggPredictionRotation.cpp @@ -138,22 +138,22 @@ int BraggPredictionRotation::Calc(const DiffractionExperiment &experiment, if (i >= max_reflections) continue; - const float g0_x = AhBk_x + Cstar.x * l; - const float g0_y = AhBk_y + Cstar.y * l; - const float g0_z = AhBk_z + Cstar.z * l; - const float g02 = g0_x * g0_x + g0_y * g0_y + g0_z * g0_z; + const float recip_x = AhBk_x + Cstar.x * l; + const float recip_y = AhBk_y + Cstar.y * l; + const float recip_z = AhBk_z + Cstar.z * l; + const float recip_sq = recip_x * recip_x + recip_y * recip_y + recip_z * recip_z; - if (g02 <= 0.0f || g02 > one_over_dmax_sq) + if (recip_sq <= 0.0f || recip_sq > one_over_dmax_sq) continue; - const float g_par_s = g0_x * w.x + g0_y * w.y + g0_z * w.z; + const float g_par_s = recip_x * w.x + recip_y * w.y + recip_z * w.z; const float g_par_x = w.x * g_par_s; const float g_par_y = w.y * g_par_s; const float g_par_z = w.z * g_par_s; - const float g_perp_x = g0_x - g_par_x; - const float g_perp_y = g0_y - g_par_y; - const float g_perp_z = g0_z - g_par_z; + const float g_perp_x = recip_x - g_par_x; + const float g_perp_y = recip_y - g_par_y; + const float g_perp_z = recip_z - g_par_z; const float g_perp2 = g_perp_x * g_perp_x + g_perp_y * g_perp_y + g_perp_z * g_perp_z; if (g_perp2 < 1e-12f) @@ -205,8 +205,8 @@ int BraggPredictionRotation::Calc(const DiffractionExperiment &experiment, if (x < 0.0f || x >= det_width_pxl || y < 0.0f || y >= det_height_pxl) continue; - - float d = 1.0f / sqrtf(g02); + float dist_ewald_sphere = std::fabs(sqrtf(S_x * S_x + S_y * S_y + S_z * S_z) - one_over_wavelength); + float d = 1.0f / sqrtf(recip_sq); const float phi_deg = rad_to_deg(phi); reflections[i] = Reflection{ .h = h, @@ -216,7 +216,7 @@ int BraggPredictionRotation::Calc(const DiffractionExperiment &experiment, .predicted_x = x, .predicted_y = y, .d = d, - .dist_ewald = sqrtf(S_x * S_x + S_y * S_y + S_z * S_z) - one_over_wavelength + .dist_ewald = dist_ewald_sphere }; ++i; } -- 2.49.1 From 80f893de3b10aecbc1718bfab948ec879762707b Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Sun, 11 Jan 2026 15:06:27 +0100 Subject: [PATCH 25/96] jfjoch_process: First iteration --- tools/CMakeLists.txt | 4 + tools/jfjoch_process.cpp | 328 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 332 insertions(+) create mode 100644 tools/jfjoch_process.cpp diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index eeb04752..424ec962 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -43,4 +43,8 @@ ADD_EXECUTABLE(jfjoch_extract_hkl jfjoch_extract_hkl.cpp) TARGET_LINK_LIBRARIES(jfjoch_extract_hkl JFJochReader) INSTALL(TARGETS jfjoch_extract_hkl RUNTIME COMPONENT viewer) +ADD_EXECUTABLE(jfjoch_process jfjoch_process.cpp) +TARGET_LINK_LIBRARIES(jfjoch_process JFJochReader JFJochImageAnalysis JFJochWriter JFJochReceiver) +INSTALL(TARGETS jfjoch_process RUNTIME COMPONENT viewer) + ADD_SUBDIRECTORY(xbflash.qspi) diff --git a/tools/jfjoch_process.cpp b/tools/jfjoch_process.cpp new file mode 100644 index 00000000..0b891fd3 --- /dev/null +++ b/tools/jfjoch_process.cpp @@ -0,0 +1,328 @@ +// SPDX-FileCopyrightText: 2024 Filip Leonarski, Paul Scherrer Institute +// SPDX-License-Identifier: GPL-3.0-only + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../reader/JFJochHDF5Reader.h" +#include "../common/Logger.h" +#include "../common/DiffractionExperiment.h" +#include "../common/PixelMask.h" +#include "../common/AzimuthalIntegration.h" +#include "../common/time_utc.h" +#include "../common/print_license.h" +#include "../image_analysis/MXAnalysisWithoutFPGA.h" +#include "../image_analysis/indexing/IndexerFactory.h" +#include "../writer/FileWriter.h" +#include "../image_analysis/IndexAndRefine.h" +#include "../receiver/JFJochReceiverPlots.h" + +void print_usage(Logger &logger) { + logger.Info("Usage ./jfjoch_analysis {} "); + logger.Info("Options:"); + logger.Info(" -o Output file prefix (default: output)"); + logger.Info(" -N Number of threads (default: 1)"); + logger.Info(" -s Start image number (default: 0)"); + logger.Info(" -e End image number (default: all)"); + logger.Info(" -v Verbose output"); +} + +int main(int argc, char **argv) { + print_license("jfjoch_analysis"); + + Logger logger("jfjoch_analysis"); + + std::string input_file; + std::string output_prefix = "output"; + int nthreads = 1; + int start_image = 0; + int end_image = -1; // -1 indicates process until end + bool verbose = false; + + if (argc == 1) { + print_usage(logger); + exit(EXIT_FAILURE); + } + + int opt; + while ((opt = getopt(argc, argv, "o:N:s:e:v")) != -1) { + switch (opt) { + case 'o': + output_prefix = optarg; + break; + case 'N': + nthreads = atoi(optarg); + break; + case 's': + start_image = atoi(optarg); + break; + case 'e': + end_image = atoi(optarg); + break; + case 'v': + verbose = true; + break; + default: + print_usage(logger); + exit(EXIT_FAILURE); + } + } + + if (optind != argc - 1) { + logger.Error("Input file not specified"); + print_usage(logger); + exit(EXIT_FAILURE); + } + + input_file = argv[optind]; + logger.Verbose(verbose); + + // 1. Read Input File + JFJochHDF5Reader reader; + try { + reader.ReadFile(input_file); + } catch (const std::exception &e) { + logger.Error("Error reading input file: {}", e.what()); + exit(EXIT_FAILURE); + } + + const auto dataset = reader.GetDataset(); + if (!dataset) { + logger.Error("No experiment dataset found in the input file"); + exit(EXIT_FAILURE); + } + + logger.Info("Loaded dataset from {}", input_file); + + // 2. Setup Experiment & Components + DiffractionExperiment experiment(dataset->experiment); + experiment.FilePrefix(output_prefix); + experiment.Mode(DetectorMode::Standard); // Ensure full image analysis + + // Configure Indexing + IndexingSettings indexing_settings; + indexing_settings.Algorithm(IndexingAlgorithmEnum::FFT); + indexing_settings.RotationIndexing(true); + indexing_settings.GeomRefinementAlgorithm(GeomRefinementAlgorithmEnum::BeamCenter); + experiment.ImportIndexingSettings(indexing_settings); + + SpotFindingSettings spot_settings; + spot_settings.enable = true; + spot_settings.indexing = true; + + // Initialize Analysis Components + // Note: dataset->pixel_mask might need conversion depending on type, assuming it fits constructor + PixelMask pixel_mask(experiment); + // 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); + IndexerThreadPool indexer_pool(experiment.GetIndexingSettings()); + + // Statistics collector + JFJochReceiverPlots plots; + plots.Setup(experiment, mapping); + + // 3. Setup FileWriter + StartMessage start_message; + experiment.FillMessage(start_message); + start_message.arm_date = dataset->arm_date; // Use original arm date + start_message.az_int_bin_to_q = mapping.GetBinToQ(); + start_message.az_int_q_bin_count = mapping.GetQBinCount(); + + std::unique_ptr writer; + try { + writer = std::make_unique(start_message); + } catch (const std::exception &e) { + logger.Error("Failed to initialize file writer: {}", e.what()); + exit(EXIT_FAILURE); + } + + // 4. Processing Setup + int total_images_in_file = reader.GetNumberOfImages(); + if (end_image < 0 || end_image > total_images_in_file) + end_image = total_images_in_file; + + int images_to_process = end_image - start_image; + + if (images_to_process <= 0) { + logger.Warning("No images to process (Start: {}, End: {}, Total: {})", start_image, end_image, total_images_in_file); + return 0; + } + + logger.Info("Starting analysis of {} images (range {}-{}) using {} threads", + images_to_process, start_image, end_image, nthreads); + + std::mutex reader_mutex; + std::mutex plots_mutex; // Protect shared plot/stats updates if they aren't thread-safe + + std::atomic processed_count = 0; + std::atomic total_uncompressed_bytes = 0; + std::atomic max_image_number_sent = 0; + + // Mimic JFJochReceiver lattice handling (IndexAndRefine handles the logic per thread, + // but we need a central accumulator or use the pool's functionality if IndexAndRefine wraps it) + // Here we will use per-thread IndexAndRefine which uses the shared thread pool. + + auto start_time = std::chrono::steady_clock::now(); + + auto worker = [&](int thread_id) { + // Thread-local analysis resources + IndexAndRefine indexer(experiment, &indexer_pool); + MXAnalysisWithoutFPGA analysis(experiment, mapping, pixel_mask, indexer); + + std::vector decomp_buffer; + AzimuthalIntegrationProfile profile(mapping); + + while (true) { + int current_idx_offset = processed_count.fetch_add(1); + int image_idx = start_image + current_idx_offset; + + if (image_idx >= end_image) break; + + // Load Image + std::shared_ptr img; + { + std::lock_guard lock(reader_mutex); + try { + img = reader.LoadImage(image_idx); + } catch (const std::exception& e) { + logger.Error("Failed to load image {}: {}", image_idx, e.what()); + continue; + } + } + + if (!img) continue; + + DataMessage msg = img->ImageData(); + total_uncompressed_bytes += msg.image.GetUncompressedSize(); + + auto image_start_time = std::chrono::high_resolution_clock::now(); + + // Analyze + try { + analysis.Analyze(msg, decomp_buffer, profile, spot_settings); + } catch (const std::exception& e) { + logger.Error("Error analyzing image {}: {}", image_idx, e.what()); + continue; + } + + auto image_end_time = std::chrono::high_resolution_clock::now(); + std::chrono::duration image_duration = image_end_time - image_start_time; + + // Mimic DataMessage stats from Receiver + msg.processing_time_s = image_duration.count(); + msg.original_number = msg.number; + msg.run_number = experiment.GetRunNumber(); + msg.run_name = experiment.GetRunName(); + // msg.receiver_free_send_buf <- Not relevant for file analysis + // msg.receiver_aq_dev_delay <- Not relevant for file analysis + + // Update Plots/Stats (Thread safe update needed) + { + std::lock_guard lock(plots_mutex); + plots.Add(msg, profile); + } + + // Write Result + writer->Write(msg); + + // Update max sent tracking + uint64_t current_max = max_image_number_sent.load(); + while (static_cast(msg.number) > current_max) { + if (max_image_number_sent.compare_exchange_weak(current_max, static_cast(msg.number))) + break; + } + + // Progress log + if (current_idx_offset > 0 && current_idx_offset % 100 == 0) + logger.Info("Processed {} / {} images", current_idx_offset, images_to_process); + } + + // Finalize per-thread indexing (if any per-thread aggregation is needed, though pool handles most) + // IndexAndRefine doesn't have a per-thread finalize that returns a lattice, + // the main lattice determination is usually done on the aggregated results in the pool or main thread + }; + + // Launch threads + std::vector> futures; + futures.reserve(nthreads); + for (int i = 0; i < nthreads; ++i) { + futures.push_back(std::async(std::launch::async, worker, i)); + } + + // Wait for completion + for (auto &f : futures) { + f.get(); + } + + auto end_time = std::chrono::steady_clock::now(); + + // 5. Finalize Statistics and Write EndMessage + EndMessage end_msg; + end_msg.max_image_number = max_image_number_sent; + end_msg.images_collected_count = images_to_process; + end_msg.images_sent_to_write_count = images_to_process; + end_msg.end_date = time_UTC(std::chrono::system_clock::now()); + end_msg.run_number = experiment.GetRunNumber(); + end_msg.run_name = experiment.GetRunName(); + + // Gather statistics from plots + end_msg.bkg_estimate = plots.GetBkgEstimate(); + end_msg.indexing_rate = plots.GetIndexingRate(); + end_msg.az_int_result["dataset"] = plots.GetAzIntProfile(); + + // Finalize Indexing (Global) to get rotation lattice + // We create a temporary IndexAndRefine to call Finalize() which aggregates pool results + IndexAndRefine global_indexer(experiment, &indexer_pool); + const auto rotation_indexer_ret = global_indexer.Finalize(); + + if (rotation_indexer_ret.has_value()) { + end_msg.rotation_lattice = rotation_indexer_ret->lattice; + end_msg.rotation_lattice_type = LatticeMessage{ + .centering = rotation_indexer_ret->search_result.centering, + .niggli_class = rotation_indexer_ret->search_result.niggli_class, + .crystal_system = rotation_indexer_ret->search_result.system + }; + logger.Info("Rotation Indexing found lattice"); + } + + // Write End Message + writer->WriteHDF5(end_msg); + auto stats = writer->Finalize(); + + // 6. Report Statistics to Console + double processing_time = std::chrono::duration(end_time - start_time).count(); + double throughput_MBs = static_cast(total_uncompressed_bytes) / (processing_time * 1e6); + double frame_rate = static_cast(images_to_process) / processing_time; + + logger.Info(""); + logger.Info("Processing time: {:.2f} s", processing_time); + logger.Info("Frame rate: {:.2f} Hz", frame_rate); + logger.Info("Total throughput:{:.2f} MB/s", throughput_MBs); + logger.Info("Images written: {}", stats.size()); + + // Print extended stats similar to Receiver + if (!end_msg.indexing_rate.has_value()) { + logger.Info("Indexing rate: {:.2f}%", end_msg.indexing_rate.value() * 100.0); + } + if (rotation_indexer_ret.has_value()) { + auto uc = rotation_indexer_ret->lattice.GetUnitCell(); + logger.Info("Lattice: a={:.2f} b={:.2f} c={:.2f} alpha={:.2f} beta={:.2f} gamma={:.2f}", + uc.a, uc.b, uc.c, uc.alpha, uc.beta, uc.gamma); + } + + if (stats.empty()) { + logger.Info("Analysis finished with warnings (no files written)"); + exit(EXIT_FAILURE); + } else { + logger.Info("Analysis successfully finished"); + exit(EXIT_SUCCESS); + } +} -- 2.49.1 From 36b32c31dba35826e954c9489874c520f9ffdd8b Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Mon, 19 Jan 2026 11:34:44 +0100 Subject: [PATCH 26/96] jfjoch_process: Handle pixel mask correctly in jfjoch_process --- tools/jfjoch_process.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tools/jfjoch_process.cpp b/tools/jfjoch_process.cpp index 0b891fd3..91da1b70 100644 --- a/tools/jfjoch_process.cpp +++ b/tools/jfjoch_process.cpp @@ -104,6 +104,7 @@ int main(int argc, char **argv) { DiffractionExperiment experiment(dataset->experiment); experiment.FilePrefix(output_prefix); experiment.Mode(DetectorMode::Standard); // Ensure full image analysis + experiment.PixelSigned(false); // Configure Indexing IndexingSettings indexing_settings; @@ -117,8 +118,8 @@ int main(int argc, char **argv) { spot_settings.indexing = true; // Initialize Analysis Components - // Note: dataset->pixel_mask might need conversion depending on type, assuming it fits constructor - PixelMask pixel_mask(experiment); + PixelMask pixel_mask = dataset->pixel_mask; + // 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, ...); @@ -135,6 +136,11 @@ int main(int argc, char **argv) { start_message.arm_date = dataset->arm_date; // Use original arm date start_message.az_int_bin_to_q = mapping.GetBinToQ(); start_message.az_int_q_bin_count = mapping.GetQBinCount(); + if (mapping.GetAzimuthalBinCount() > 1) + start_message.az_int_bin_to_phi = mapping.GetBinToPhi(); + + start_message.pixel_mask["default"] = pixel_mask.GetMask(experiment); + start_message.max_spot_count = experiment.GetMaxSpotCount(); std::unique_ptr writer; try { -- 2.49.1 From e96b04eb3add744c9220aaaa7fe9be6097605dd6 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Mon, 19 Jan 2026 11:56:43 +0100 Subject: [PATCH 27/96] jfjoch_process: Overwrite output files --- tools/jfjoch_process.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/jfjoch_process.cpp b/tools/jfjoch_process.cpp index 91da1b70..26e82518 100644 --- a/tools/jfjoch_process.cpp +++ b/tools/jfjoch_process.cpp @@ -105,6 +105,7 @@ int main(int argc, char **argv) { experiment.FilePrefix(output_prefix); experiment.Mode(DetectorMode::Standard); // Ensure full image analysis experiment.PixelSigned(false); + experiment.OverwriteExistingFiles(true); // Configure Indexing IndexingSettings indexing_settings; -- 2.49.1 From af2ec340dba4617b948c8a3c521f7e7dfdb78f69 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Mon, 19 Jan 2026 11:57:16 +0100 Subject: [PATCH 28/96] DiffractionExperiment: Add option to check if rotation indexing is enabled (goniometer present + rotation indexing) --- common/DiffractionExperiment.cpp | 4 ++++ common/DiffractionExperiment.h | 2 ++ 2 files changed, 6 insertions(+) diff --git a/common/DiffractionExperiment.cpp b/common/DiffractionExperiment.cpp index ca2f4c46..bfeda9a2 100644 --- a/common/DiffractionExperiment.cpp +++ b/common/DiffractionExperiment.cpp @@ -1642,3 +1642,7 @@ int64_t DiffractionExperiment::GetDarkMaskNumberOfFrames() const { return GetDarkMaskSettings().GetNumberOfFrames(); return 0; } + +bool DiffractionExperiment::IsRotationIndexing() const { + return GetGoniometer().has_value() && indexing.GetRotationIndexing(); +} diff --git a/common/DiffractionExperiment.h b/common/DiffractionExperiment.h index ab35096f..ffd2149e 100644 --- a/common/DiffractionExperiment.h +++ b/common/DiffractionExperiment.h @@ -404,6 +404,8 @@ public: bool IsDetectIceRings() const; int64_t GetDarkMaskNumberOfFrames() const; + + bool IsRotationIndexing() const; }; #endif //DIFFRACTIONEXPERIMENT_H -- 2.49.1 From 05da6bc2ddeebb004dfebe5c795bd9e36e882f77 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Mon, 19 Jan 2026 12:09:40 +0100 Subject: [PATCH 29/96] jfjoch_process: Clean previous image information (to be optimized) + option to run rotation indexing --- tools/jfjoch_process.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/tools/jfjoch_process.cpp b/tools/jfjoch_process.cpp index 26e82518..b1585eec 100644 --- a/tools/jfjoch_process.cpp +++ b/tools/jfjoch_process.cpp @@ -44,6 +44,7 @@ int main(int argc, char **argv) { int start_image = 0; int end_image = -1; // -1 indicates process until end bool verbose = false; + bool rotation_index = false; if (argc == 1) { print_usage(logger); @@ -51,7 +52,7 @@ int main(int argc, char **argv) { } int opt; - while ((opt = getopt(argc, argv, "o:N:s:e:v")) != -1) { + while ((opt = getopt(argc, argv, "o:N:s:e:vR")) != -1) { switch (opt) { case 'o': output_prefix = optarg; @@ -68,6 +69,9 @@ int main(int argc, char **argv) { case 'v': verbose = true; break; + case 'R': + rotation_index = true; + break; default: print_usage(logger); exit(EXIT_FAILURE); @@ -110,7 +114,7 @@ int main(int argc, char **argv) { // Configure Indexing IndexingSettings indexing_settings; indexing_settings.Algorithm(IndexingAlgorithmEnum::FFT); - indexing_settings.RotationIndexing(true); + indexing_settings.RotationIndexing(rotation_index); indexing_settings.GeomRefinementAlgorithm(GeomRefinementAlgorithmEnum::BeamCenter); experiment.ImportIndexingSettings(indexing_settings); @@ -207,7 +211,15 @@ int main(int argc, char **argv) { if (!img) continue; - DataMessage msg = img->ImageData(); + DataMessage msg; + + msg.image = img->ImageData().image; + msg.number = img->ImageData().number; + msg.error_pixel_count = img->ImageData().error_pixel_count; + msg.image_collection_efficiency = img->ImageData().image_collection_efficiency; + msg.storage_cell = img->ImageData().storage_cell; + msg.user_data = img->ImageData().user_data; + total_uncompressed_bytes += msg.image.GetUncompressedSize(); auto image_start_time = std::chrono::high_resolution_clock::now(); -- 2.49.1 From 1353748a2e3931dc2e80aa2fd85689745d63e67c Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Mon, 19 Jan 2026 12:10:08 +0100 Subject: [PATCH 30/96] MXAnalysis: Generate rotation prediction properly --- image_analysis/MXAnalysisAfterFPGA.cpp | 6 +++--- image_analysis/MXAnalysisWithoutFPGA.cpp | 2 +- image_analysis/bragg_prediction/BraggPredictionFactory.cpp | 5 ++++- image_analysis/bragg_prediction/BraggPredictionFactory.h | 3 ++- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/image_analysis/MXAnalysisAfterFPGA.cpp b/image_analysis/MXAnalysisAfterFPGA.cpp index 1d6e725e..9d815999 100644 --- a/image_analysis/MXAnalysisAfterFPGA.cpp +++ b/image_analysis/MXAnalysisAfterFPGA.cpp @@ -26,11 +26,11 @@ double stddev(const std::vector &v) { MXAnalysisAfterFPGA::MXAnalysisAfterFPGA(const DiffractionExperiment &in_experiment, IndexAndRefine &indexer) -: experiment(in_experiment), indexer(indexer) { + : experiment(in_experiment), + indexer(indexer), + prediction(CreateBraggPrediction(in_experiment.IsRotationIndexing())) { if (experiment.IsSpotFindingEnabled()) find_spots = true; - - prediction = CreateBraggPrediction(); } void MXAnalysisAfterFPGA::ReadFromFPGA(const DeviceOutput *output, const SpotFindingSettings &settings, size_t module_number) { diff --git a/image_analysis/MXAnalysisWithoutFPGA.cpp b/image_analysis/MXAnalysisWithoutFPGA.cpp index 18c31c71..5ac206ad 100644 --- a/image_analysis/MXAnalysisWithoutFPGA.cpp +++ b/image_analysis/MXAnalysisWithoutFPGA.cpp @@ -24,7 +24,7 @@ MXAnalysisWithoutFPGA::MXAnalysisWithoutFPGA(const DiffractionExperiment &in_exp mask_1bit(npixels, false), spotFinder(CreateImageSpotFinder(experiment.GetXPixelsNum(), experiment.GetYPixelsNum())), indexer(in_indexer), - prediction(CreateBraggPrediction()), + prediction(CreateBraggPrediction(in_experiment.IsRotationIndexing())), updated_image(spotFinder->GetInputBuffer()), azint_bins(in_integration.GetBinNumber()), saturation_limit(experiment.GetSaturationLimit()), diff --git a/image_analysis/bragg_prediction/BraggPredictionFactory.cpp b/image_analysis/bragg_prediction/BraggPredictionFactory.cpp index cc1ae471..abee4820 100644 --- a/image_analysis/bragg_prediction/BraggPredictionFactory.cpp +++ b/image_analysis/bragg_prediction/BraggPredictionFactory.cpp @@ -2,13 +2,16 @@ // SPDX-License-Identifier: GPL-3.0-only #include "BraggPredictionFactory.h" +#include "BraggPredictionRotation.h" #ifdef JFJOCH_USE_CUDA #include "../../common/CUDAWrapper.h" #include "BraggPredictionGPU.h" #endif -std::unique_ptr CreateBraggPrediction(int max_reflections) { +std::unique_ptr CreateBraggPrediction(bool rotation_indexing, int max_reflections) { + if (rotation_indexing) + return std::make_unique(max_reflections); #ifdef JFJOCH_USE_CUDA if (get_gpu_count() > 0) return std::make_unique(max_reflections); diff --git a/image_analysis/bragg_prediction/BraggPredictionFactory.h b/image_analysis/bragg_prediction/BraggPredictionFactory.h index fb3070c3..136597e3 100644 --- a/image_analysis/bragg_prediction/BraggPredictionFactory.h +++ b/image_analysis/bragg_prediction/BraggPredictionFactory.h @@ -6,6 +6,7 @@ #include "BraggPrediction.h" -std::unique_ptr CreateBraggPrediction(int max_reflections = 10000); +std::unique_ptr CreateBraggPrediction(bool rotation_indexing, + int max_reflections = 10000); #endif //JFJOCH_BRAGGPREDICTIONFACTORY_H \ No newline at end of file -- 2.49.1 From 69cd7b551d3953d63dfcb0e9fea2e9b1a5078118 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Mon, 19 Jan 2026 13:06:23 +0100 Subject: [PATCH 31/96] IndexAndRefine: Use "standard predictor", just with rotated axis --- image_analysis/IndexAndRefine.cpp | 20 ++++++++++++++++--- .../BraggPredictionFactory.cpp | 2 -- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/image_analysis/IndexAndRefine.cpp b/image_analysis/IndexAndRefine.cpp index 8bc8b50a..8a297d72 100644 --- a/image_analysis/IndexAndRefine.cpp +++ b/image_analysis/IndexAndRefine.cpp @@ -10,18 +10,22 @@ #include "indexing/FFTIndexer.h" #include "lattice_search/LatticeSearch.h" + IndexAndRefine::IndexAndRefine(const DiffractionExperiment &x, IndexerThreadPool *indexer) : index_ice_rings(x.GetIndexingSettings().GetIndexIceRings()), experiment(x), geom_(x.GetDiffractionGeometry()), indexer_(indexer) { - if (indexer && x.GetGoniometer() && x.GetIndexingSettings().GetRotationIndexing()) + if (indexer && x.IsRotationIndexing()) rotation_indexer = std::make_unique(x, *indexer); } +#include void IndexAndRefine::SetLattice(const CrystalLattice &lattice) { - if (rotation_indexer) + if (rotation_indexer) { rotation_indexer->SetLattice(lattice); + std::cout << "Set lattice for rotation indexing" << std::endl; + } } IndexAndRefine::IndexingOutcome IndexAndRefine::DetermineLatticeAndSymmetry(DataMessage &msg) { @@ -144,9 +148,19 @@ void IndexAndRefine::QuickPredictAndIntegrate(DataMessage &msg, .ewald_dist_cutoff = ewald_dist_cutoff, .max_hkl = 100, .centering = outcome.symmetry.centering, + .image_number = static_cast(msg.number) }; - auto nrefl = prediction.Calc(experiment, *outcome.lattice_candidate, settings_prediction); + CrystalLattice latt = outcome.lattice_candidate.value(); + + if (rotation_indexer) { + // Rotate lattice_candidate to the current image angle + auto gon = experiment.GetGoniometer(); + if (gon) + latt = outcome.lattice_candidate->Multiply(gon->GetTransformation(-msg.number)); + } + + auto nrefl = prediction.Calc(experiment, latt, settings_prediction); auto refl_ret = BraggIntegrate2D(outcome.experiment, image, prediction.GetReflections(), nrefl, msg.number); constexpr size_t kMaxReflections = 10000; diff --git a/image_analysis/bragg_prediction/BraggPredictionFactory.cpp b/image_analysis/bragg_prediction/BraggPredictionFactory.cpp index abee4820..9c6dde50 100644 --- a/image_analysis/bragg_prediction/BraggPredictionFactory.cpp +++ b/image_analysis/bragg_prediction/BraggPredictionFactory.cpp @@ -10,8 +10,6 @@ #endif std::unique_ptr CreateBraggPrediction(bool rotation_indexing, int max_reflections) { - if (rotation_indexing) - return std::make_unique(max_reflections); #ifdef JFJOCH_USE_CUDA if (get_gpu_count() > 0) return std::make_unique(max_reflections); -- 2.49.1 From af81601103a905763945c6dc58263a8b43d396c2 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Mon, 19 Jan 2026 13:55:30 +0100 Subject: [PATCH 32/96] jfjoch_process: Use single IndexAndRefine instance --- tools/jfjoch_process.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/jfjoch_process.cpp b/tools/jfjoch_process.cpp index b1585eec..eb40d120 100644 --- a/tools/jfjoch_process.cpp +++ b/tools/jfjoch_process.cpp @@ -183,9 +183,10 @@ int main(int argc, char **argv) { auto start_time = std::chrono::steady_clock::now(); + IndexAndRefine indexer(experiment, &indexer_pool); + auto worker = [&](int thread_id) { // Thread-local analysis resources - IndexAndRefine indexer(experiment, &indexer_pool); MXAnalysisWithoutFPGA analysis(experiment, mapping, pixel_mask, indexer); std::vector decomp_buffer; -- 2.49.1 From 71f85b294d67971ac967d1be30d2f00ebd5da0e7 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Mon, 19 Jan 2026 13:56:28 +0100 Subject: [PATCH 33/96] RotationIndexer: Remove SetLattice() - not sure why it was necessary in the first place --- image_analysis/IndexAndRefine.cpp | 8 -------- image_analysis/IndexAndRefine.h | 1 - image_analysis/RotationIndexer.cpp | 13 +++++++------ image_analysis/RotationIndexer.h | 1 - 4 files changed, 7 insertions(+), 16 deletions(-) diff --git a/image_analysis/IndexAndRefine.cpp b/image_analysis/IndexAndRefine.cpp index 8a297d72..3db59d91 100644 --- a/image_analysis/IndexAndRefine.cpp +++ b/image_analysis/IndexAndRefine.cpp @@ -19,14 +19,6 @@ IndexAndRefine::IndexAndRefine(const DiffractionExperiment &x, IndexerThreadPool if (indexer && x.IsRotationIndexing()) rotation_indexer = std::make_unique(x, *indexer); } -#include - -void IndexAndRefine::SetLattice(const CrystalLattice &lattice) { - if (rotation_indexer) { - rotation_indexer->SetLattice(lattice); - std::cout << "Set lattice for rotation indexing" << std::endl; - } -} IndexAndRefine::IndexingOutcome IndexAndRefine::DetermineLatticeAndSymmetry(DataMessage &msg) { IndexingOutcome outcome(experiment); diff --git a/image_analysis/IndexAndRefine.h b/image_analysis/IndexAndRefine.h index 36d3ba58..8582da59 100644 --- a/image_analysis/IndexAndRefine.h +++ b/image_analysis/IndexAndRefine.h @@ -49,7 +49,6 @@ class IndexAndRefine { const IndexingOutcome &outcome); public: IndexAndRefine(const DiffractionExperiment &x, IndexerThreadPool *indexer); - void SetLattice(const CrystalLattice &lattice); void ProcessImage(DataMessage &msg, const SpotFindingSettings &settings, const CompressedImage &image, BraggPrediction &prediction); std::optional Finalize(); }; diff --git a/image_analysis/RotationIndexer.cpp b/image_analysis/RotationIndexer.cpp index ed46490a..564e5584 100644 --- a/image_analysis/RotationIndexer.cpp +++ b/image_analysis/RotationIndexer.cpp @@ -35,11 +35,6 @@ RotationIndexer::RotationIndexer(const DiffractionExperiment &x, IndexerThreadPo } } -void RotationIndexer::SetLattice(const CrystalLattice &lattice) { - std::unique_lock ul(m); - indexed_lattice = lattice; -} - void RotationIndexer::TryIndex() { indexing_tried = true; @@ -130,7 +125,13 @@ std::optional RotationIndexer::ProcessImage(int64_t image if (accumulated_images >= min_images_for_indexing && image >= first_image_to_try_indexing) TryIndex(); } - + if (!indexed_lattice) + return {}; + return RotationIndexerResult{ + .lattice = indexed_lattice.value(), + .search_result = search_result_, + .geom = updated_geom_ + }; return GetLattice(); } diff --git a/image_analysis/RotationIndexer.h b/image_analysis/RotationIndexer.h index 437281ee..be6fde20 100644 --- a/image_analysis/RotationIndexer.h +++ b/image_analysis/RotationIndexer.h @@ -54,7 +54,6 @@ class RotationIndexer { void TryIndex(); public: RotationIndexer(const DiffractionExperiment& x, IndexerThreadPool& indexer); - void SetLattice(const CrystalLattice &lattice); std::optional ProcessImage(int64_t image, const std::vector& spots); std::optional GetLattice(); }; -- 2.49.1 From 0a19acb90005f88baca83944e2ee08ea31b3b1c5 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Mon, 19 Jan 2026 13:56:42 +0100 Subject: [PATCH 34/96] IndexAndRefine: Generate predictions based on refined geometry --- image_analysis/IndexAndRefine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/image_analysis/IndexAndRefine.cpp b/image_analysis/IndexAndRefine.cpp index 3db59d91..781b42a8 100644 --- a/image_analysis/IndexAndRefine.cpp +++ b/image_analysis/IndexAndRefine.cpp @@ -152,7 +152,7 @@ void IndexAndRefine::QuickPredictAndIntegrate(DataMessage &msg, latt = outcome.lattice_candidate->Multiply(gon->GetTransformation(-msg.number)); } - auto nrefl = prediction.Calc(experiment, latt, settings_prediction); + auto nrefl = prediction.Calc(outcome.experiment, latt, settings_prediction); auto refl_ret = BraggIntegrate2D(outcome.experiment, image, prediction.GetReflections(), nrefl, msg.number); constexpr size_t kMaxReflections = 10000; -- 2.49.1 From a31065f6aee6b8a3b5cdec7d35b1ca4388b0840e Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Mon, 19 Jan 2026 14:00:02 +0100 Subject: [PATCH 35/96] CreateBraggPrediction: No rotation for now --- image_analysis/MXAnalysisAfterFPGA.cpp | 2 +- image_analysis/MXAnalysisWithoutFPGA.cpp | 2 +- image_analysis/bragg_prediction/BraggPredictionFactory.cpp | 2 +- image_analysis/bragg_prediction/BraggPredictionFactory.h | 3 +-- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/image_analysis/MXAnalysisAfterFPGA.cpp b/image_analysis/MXAnalysisAfterFPGA.cpp index 9d815999..64a09c85 100644 --- a/image_analysis/MXAnalysisAfterFPGA.cpp +++ b/image_analysis/MXAnalysisAfterFPGA.cpp @@ -28,7 +28,7 @@ double stddev(const std::vector &v) { MXAnalysisAfterFPGA::MXAnalysisAfterFPGA(const DiffractionExperiment &in_experiment, IndexAndRefine &indexer) : experiment(in_experiment), indexer(indexer), - prediction(CreateBraggPrediction(in_experiment.IsRotationIndexing())) { + prediction(CreateBraggPrediction()) { if (experiment.IsSpotFindingEnabled()) find_spots = true; } diff --git a/image_analysis/MXAnalysisWithoutFPGA.cpp b/image_analysis/MXAnalysisWithoutFPGA.cpp index 5ac206ad..18c31c71 100644 --- a/image_analysis/MXAnalysisWithoutFPGA.cpp +++ b/image_analysis/MXAnalysisWithoutFPGA.cpp @@ -24,7 +24,7 @@ MXAnalysisWithoutFPGA::MXAnalysisWithoutFPGA(const DiffractionExperiment &in_exp mask_1bit(npixels, false), spotFinder(CreateImageSpotFinder(experiment.GetXPixelsNum(), experiment.GetYPixelsNum())), indexer(in_indexer), - prediction(CreateBraggPrediction(in_experiment.IsRotationIndexing())), + prediction(CreateBraggPrediction()), updated_image(spotFinder->GetInputBuffer()), azint_bins(in_integration.GetBinNumber()), saturation_limit(experiment.GetSaturationLimit()), diff --git a/image_analysis/bragg_prediction/BraggPredictionFactory.cpp b/image_analysis/bragg_prediction/BraggPredictionFactory.cpp index 9c6dde50..12c03182 100644 --- a/image_analysis/bragg_prediction/BraggPredictionFactory.cpp +++ b/image_analysis/bragg_prediction/BraggPredictionFactory.cpp @@ -9,7 +9,7 @@ #include "BraggPredictionGPU.h" #endif -std::unique_ptr CreateBraggPrediction(bool rotation_indexing, int max_reflections) { +std::unique_ptr CreateBraggPrediction(int max_reflections) { #ifdef JFJOCH_USE_CUDA if (get_gpu_count() > 0) return std::make_unique(max_reflections); diff --git a/image_analysis/bragg_prediction/BraggPredictionFactory.h b/image_analysis/bragg_prediction/BraggPredictionFactory.h index 136597e3..fb3070c3 100644 --- a/image_analysis/bragg_prediction/BraggPredictionFactory.h +++ b/image_analysis/bragg_prediction/BraggPredictionFactory.h @@ -6,7 +6,6 @@ #include "BraggPrediction.h" -std::unique_ptr CreateBraggPrediction(bool rotation_indexing, - int max_reflections = 10000); +std::unique_ptr CreateBraggPrediction(int max_reflections = 10000); #endif //JFJOCH_BRAGGPREDICTIONFACTORY_H \ No newline at end of file -- 2.49.1 From 2de263c3f585b0226414491e3e4d4a58c84abc17 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Mon, 19 Jan 2026 21:21:47 +0100 Subject: [PATCH 36/96] jfjoch_process: Add compression --- tools/jfjoch_process.cpp | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/tools/jfjoch_process.cpp b/tools/jfjoch_process.cpp index eb40d120..873312a2 100644 --- a/tools/jfjoch_process.cpp +++ b/tools/jfjoch_process.cpp @@ -22,6 +22,7 @@ #include "../writer/FileWriter.h" #include "../image_analysis/IndexAndRefine.h" #include "../receiver/JFJochReceiverPlots.h" +#include "../compression/JFJochCompressor.h" void print_usage(Logger &logger) { logger.Info("Usage ./jfjoch_analysis {} "); @@ -34,6 +35,8 @@ void print_usage(Logger &logger) { } int main(int argc, char **argv) { + RegisterHDF5Filter(); + print_license("jfjoch_analysis"); Logger logger("jfjoch_analysis"); @@ -106,9 +109,10 @@ int main(int argc, char **argv) { // 2. Setup Experiment & Components DiffractionExperiment experiment(dataset->experiment); + experiment.BitDepthImage(32).Compression(CompressionAlgorithm::BSHUF_LZ4); experiment.FilePrefix(output_prefix); experiment.Mode(DetectorMode::Standard); // Ensure full image analysis - experiment.PixelSigned(false); + experiment.PixelSigned(true); experiment.OverwriteExistingFiles(true); // Configure Indexing @@ -186,6 +190,13 @@ int main(int argc, char **argv) { IndexAndRefine indexer(experiment, &indexer_pool); auto worker = [&](int thread_id) { + JFJochBitShuffleCompressor compressor(experiment.GetCompressionAlgorithm()); + std::vector compressed_buffer; + + compressed_buffer.resize(MaxCompressedSize(experiment.GetCompressionAlgorithm(), + experiment.GetPixelsNum(), + experiment.GetByteDepthImage())); + // Thread-local analysis resources MXAnalysisWithoutFPGA analysis(experiment, mapping, pixel_mask, indexer); @@ -236,6 +247,17 @@ int main(int argc, char **argv) { auto image_end_time = std::chrono::high_resolution_clock::now(); std::chrono::duration image_duration = image_end_time - image_start_time; + auto size = compressor.Compress(compressed_buffer.data(), + img->Image().data(), + experiment.GetPixelsNum(), + sizeof(int32_t)); + + msg.image = CompressedImage(compressed_buffer.data(), + size, experiment.GetXPixelsNum(), + experiment.GetYPixelsNum(), + CompressedImageMode::Int32, + experiment.GetCompressionAlgorithm()); + // Mimic DataMessage stats from Receiver msg.processing_time_s = image_duration.count(); msg.original_number = msg.number; @@ -248,11 +270,10 @@ int main(int argc, char **argv) { { std::lock_guard lock(plots_mutex); plots.Add(msg, profile); + // Write Result + writer->Write(msg); } - // Write Result - writer->Write(msg); - // Update max sent tracking uint64_t current_max = max_image_number_sent.load(); while (static_cast(msg.number) > current_max) { -- 2.49.1 From 05bb18f6f7f48bd3a0a0eb6f18096825fa6cf3fc Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Mon, 19 Jan 2026 21:34:05 +0100 Subject: [PATCH 37/96] jfjoch_process: A bit more options --- tools/jfjoch_process.cpp | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/tools/jfjoch_process.cpp b/tools/jfjoch_process.cpp index 873312a2..d15276ae 100644 --- a/tools/jfjoch_process.cpp +++ b/tools/jfjoch_process.cpp @@ -32,6 +32,9 @@ void print_usage(Logger &logger) { logger.Info(" -s Start image number (default: 0)"); logger.Info(" -e End image number (default: all)"); logger.Info(" -v Verbose output"); + logger.Info(" -R[num] Rotation indexing (optional: min angular range deg)"); + logger.Info(" -F Use FFT indexing algorithm (default: Auto)"); + logger.Info(" -x No least-square beam center refinement"); } int main(int argc, char **argv) { @@ -47,7 +50,10 @@ int main(int argc, char **argv) { int start_image = 0; int end_image = -1; // -1 indicates process until end bool verbose = false; - bool rotation_index = false; + bool rotation_indexing = false; + std::optional rotation_indexing_range; + bool use_fft = false; + bool refine_beam_center = true; if (argc == 1) { print_usage(logger); @@ -55,7 +61,7 @@ int main(int argc, char **argv) { } int opt; - while ((opt = getopt(argc, argv, "o:N:s:e:vR")) != -1) { + while ((opt = getopt(argc, argv, "o:N:s:e:vR::Fx")) != -1) { switch (opt) { case 'o': output_prefix = optarg; @@ -73,7 +79,14 @@ int main(int argc, char **argv) { verbose = true; break; case 'R': - rotation_index = true; + rotation_indexing = true; + if (optarg) rotation_indexing_range = atof(optarg); + break; + case 'F': + use_fft = true; + break; + case 'x': + refine_beam_center = false; break; default: print_usage(logger); @@ -117,9 +130,19 @@ int main(int argc, char **argv) { // Configure Indexing IndexingSettings indexing_settings; - indexing_settings.Algorithm(IndexingAlgorithmEnum::FFT); - indexing_settings.RotationIndexing(rotation_index); - indexing_settings.GeomRefinementAlgorithm(GeomRefinementAlgorithmEnum::BeamCenter); + if (use_fft) + indexing_settings.Algorithm(IndexingAlgorithmEnum::FFT); + else + indexing_settings.Algorithm(IndexingAlgorithmEnum::Auto); + + indexing_settings.RotationIndexing(rotation_indexing); + if (rotation_indexing_range.has_value()) + indexing_settings.RotationIndexingMinAngularRange_deg(rotation_indexing_range.value()); + + if (refine_beam_center) + indexing_settings.GeomRefinementAlgorithm(GeomRefinementAlgorithmEnum::BeamCenter); + else + indexing_settings.GeomRefinementAlgorithm(GeomRefinementAlgorithmEnum::None); experiment.ImportIndexingSettings(indexing_settings); SpotFindingSettings spot_settings; -- 2.49.1 From 11b1857a3528a84dc8012c5a837e014841b8bf62 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Tue, 20 Jan 2026 08:58:26 +0100 Subject: [PATCH 38/96] XtalOptimizer: Use robust loss function (Cauchy) for least squares --- image_analysis/geom_refinement/XtalOptimizer.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/image_analysis/geom_refinement/XtalOptimizer.cpp b/image_analysis/geom_refinement/XtalOptimizer.cpp index 736f412c..54fe8d3a 100644 --- a/image_analysis/geom_refinement/XtalOptimizer.cpp +++ b/image_analysis/geom_refinement/XtalOptimizer.cpp @@ -126,9 +126,10 @@ struct XtalResidual { auto e_pred_hkl = e_latt.transpose() * e_obs_recip; - residual[0] = exp_h - e_pred_hkl[0]; - residual[1] = exp_k - e_pred_hkl[1]; - residual[2] = exp_l - e_pred_hkl[2]; + T dh = exp_h - e_pred_hkl[0]; + T dk = exp_k - e_pred_hkl[1]; + T dl = exp_l - e_pred_hkl[2]; + residual[0] = ceres::sqrt(dh * dh + dk * dk + dl * dl); return true; } @@ -414,6 +415,11 @@ bool XtalOptimizerInternal(XtalOptimizerData &data, } const float tolerance_sq = tolerance * tolerance; + + // Choose robust loss function + // Cauchy is excellent for crystallography - handles both small errors and gross outliers + const double loss_scale = tolerance / 3; // Tune based on typical residual magnitude + // Add residuals for each point for (const auto &pt: spots) { if (!data.index_ice_rings && pt.ice_ring) @@ -450,14 +456,14 @@ bool XtalOptimizerInternal(XtalOptimizerData &data, continue; problem.AddResidualBlock( - new ceres::AutoDiffCostFunction( + new ceres::AutoDiffCostFunction( new XtalResidual(pt.x, pt.y, data.geom.GetWavelength_A(), data.geom.GetPixelSize_mm(), gonio_back_rot, h, k, l, data.crystal_system)), - nullptr, + new ceres::CauchyLoss(loss_scale), &beam_x, &beam_y, &distance_mm, -- 2.49.1 From 30783d4849a5573e36b307264b7c9d955c2c220f Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Tue, 20 Jan 2026 08:58:54 +0100 Subject: [PATCH 39/96] RotationIndexer: Refine detector angles --- image_analysis/IndexAndRefine.cpp | 7 +++++-- image_analysis/RotationIndexer.cpp | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/image_analysis/IndexAndRefine.cpp b/image_analysis/IndexAndRefine.cpp index 781b42a8..71afcc99 100644 --- a/image_analysis/IndexAndRefine.cpp +++ b/image_analysis/IndexAndRefine.cpp @@ -20,6 +20,8 @@ IndexAndRefine::IndexAndRefine(const DiffractionExperiment &x, IndexerThreadPool rotation_indexer = std::make_unique(x, *indexer); } +#include + IndexAndRefine::IndexingOutcome IndexAndRefine::DetermineLatticeAndSymmetry(DataMessage &msg) { IndexingOutcome outcome(experiment); @@ -30,8 +32,9 @@ IndexAndRefine::IndexingOutcome IndexAndRefine::DetermineLatticeAndSymmetry(Data outcome.experiment.BeamX_pxl(result->geom.GetBeamX_pxl()) .BeamY_pxl(result->geom.GetBeamY_pxl()) - .DetectorDistance_mm(result->geom.GetDetectorDistance_mm()); - + .DetectorDistance_mm(result->geom.GetDetectorDistance_mm()) + .PoniRot1_rad(result->geom.GetPoniRot1_rad()) + .PoniRot2_rad(result->geom.GetPoniRot2_rad()); outcome.symmetry.centering = result->search_result.centering; outcome.symmetry.niggli_class = result->search_result.niggli_class; outcome.symmetry.crystal_system = result->search_result.system; diff --git a/image_analysis/RotationIndexer.cpp b/image_analysis/RotationIndexer.cpp index 564e5584..90177995 100644 --- a/image_analysis/RotationIndexer.cpp +++ b/image_analysis/RotationIndexer.cpp @@ -85,6 +85,7 @@ void RotationIndexer::TryIndex() { .min_spots = experiment.GetIndexingSettings().GetViableCellMinSpots(), .refine_beam_center = true, .refine_distance_mm = false, + .refine_detector_angles = true, .index_ice_rings = experiment.GetIndexingSettings().GetIndexIceRings(), .axis = axis_ }; -- 2.49.1 From 8c4282b9e651acc2192b6c18f7c21ef28568d758 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Tue, 20 Jan 2026 09:08:01 +0100 Subject: [PATCH 40/96] jfjoch_process: Add resolution --- tools/jfjoch_process.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tools/jfjoch_process.cpp b/tools/jfjoch_process.cpp index d15276ae..acc3f91c 100644 --- a/tools/jfjoch_process.cpp +++ b/tools/jfjoch_process.cpp @@ -35,6 +35,7 @@ void print_usage(Logger &logger) { logger.Info(" -R[num] Rotation indexing (optional: min angular range deg)"); logger.Info(" -F Use FFT indexing algorithm (default: Auto)"); logger.Info(" -x No least-square beam center refinement"); + logger.Info(" -d High resolution limit for spot finding (default: 1.5)"); } int main(int argc, char **argv) { @@ -55,13 +56,15 @@ int main(int argc, char **argv) { bool use_fft = false; bool refine_beam_center = true; + float d_high = 1.5; + if (argc == 1) { print_usage(logger); exit(EXIT_FAILURE); } int opt; - while ((opt = getopt(argc, argv, "o:N:s:e:vR::Fx")) != -1) { + while ((opt = getopt(argc, argv, "o:N:s:e:vR::Fxd:")) != -1) { switch (opt) { case 'o': output_prefix = optarg; @@ -88,6 +91,9 @@ int main(int argc, char **argv) { case 'x': refine_beam_center = false; break; + case 'd': + d_high = atof(optarg); + break; default: print_usage(logger); exit(EXIT_FAILURE); @@ -148,6 +154,7 @@ int main(int argc, char **argv) { SpotFindingSettings spot_settings; spot_settings.enable = true; spot_settings.indexing = true; + spot_settings.high_resolution_limit = d_high; // Initialize Analysis Components PixelMask pixel_mask = dataset->pixel_mask; -- 2.49.1 From 0b9463cb0d2dc27cad4692a12b047c3bba78ee50 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Tue, 20 Jan 2026 10:34:32 +0100 Subject: [PATCH 41/96] jfjoch_test: Adjust expected precision - changed way of calculating residual - will work worse on "ideal" data, but should be more outlier safe. To be seen. --- tests/XtalOptimizerTest.cpp | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/tests/XtalOptimizerTest.cpp b/tests/XtalOptimizerTest.cpp index c5e07cf9..031716c8 100644 --- a/tests/XtalOptimizerTest.cpp +++ b/tests/XtalOptimizerTest.cpp @@ -203,15 +203,15 @@ TEST_CASE("XtalOptimizer_triclinic") { std::cout << "Beam center: " << xtal_opt.geom.GetBeamX_pxl() << " " << xtal_opt.geom.GetBeamY_pxl() << std::endl; std::cout << "Unit cell: " << uc_o.a << " " << uc_o.b << " " << uc_o.c << std::endl; - CHECK(fabsf(xtal_opt.geom.GetBeamX_pxl() - exp_i.GetBeamX_pxl()) < 0.1); - CHECK(fabsf(xtal_opt.geom.GetBeamY_pxl() - exp_i.GetBeamY_pxl()) < 0.1); + CHECK(fabsf(xtal_opt.geom.GetBeamX_pxl() - exp_i.GetBeamX_pxl()) < 0.2); + CHECK(fabsf(xtal_opt.geom.GetBeamY_pxl() - exp_i.GetBeamY_pxl()) < 0.2); CHECK(fabsf(uc_i.a - uc_o.a) < 0.1); CHECK(fabsf(uc_i.b - uc_o.b) < 0.1); CHECK(fabsf(uc_i.c - uc_o.c) < 0.5); - CHECK(fabsf(uc_i.alpha - uc_o.alpha) < 0.05); - CHECK(fabsf(uc_i.beta - uc_o.beta) < 0.05); - CHECK(fabsf(uc_i.gamma - uc_o.gamma) < 0.05); + CHECK(fabsf(uc_i.alpha - uc_o.alpha) < 0.1); + CHECK(fabsf(uc_i.beta - uc_o.beta) < 0.1); + CHECK(fabsf(uc_i.gamma - uc_o.gamma) < 0.1); } @@ -361,15 +361,15 @@ TEST_CASE("XtalOptimizer_hexagonal_unconstrained") { std::cout << "Unit cell: " << uc_o.a << " " << uc_o.b << " " << uc_o.c << " " << uc_o.alpha << " " << uc_o.beta << " " << uc_o.gamma << std::endl; - CHECK(fabsf(xtal_opt.geom.GetBeamX_pxl() - exp_i.GetBeamX_pxl()) < 0.1); - CHECK(fabsf(xtal_opt.geom.GetBeamY_pxl() - exp_i.GetBeamY_pxl()) < 0.1); + CHECK(fabsf(xtal_opt.geom.GetBeamX_pxl() - exp_i.GetBeamX_pxl()) < 0.3); + CHECK(fabsf(xtal_opt.geom.GetBeamY_pxl() - exp_i.GetBeamY_pxl()) < 0.3); CHECK(fabsf(uc_i.a - uc_o.a) < 0.1); CHECK(fabsf(uc_i.b - uc_o.b) < 0.1); CHECK(fabsf(uc_i.c - uc_o.c) < 0.2); - CHECK(fabs(uc_o.alpha - 90) < 0.02); - CHECK(fabs(uc_o.beta - 90) < 0.01); - CHECK(fabs(uc_o.gamma - 120) < 0.01); + CHECK(fabs(uc_o.alpha - 90) < 0.1); + CHECK(fabs(uc_o.beta - 90) < 0.1); + CHECK(fabs(uc_o.gamma - 120) < 0.1); } TEST_CASE("XtalOptimizer_cubic") { @@ -469,15 +469,15 @@ TEST_CASE("XtalOptimizer_monoclinic") { std::cout << "Beam center: " << xtal_opt.geom.GetBeamX_pxl() << " " << xtal_opt.geom.GetBeamY_pxl() << std::endl; std::cout << "Unit cell: " << uc_o.a << " " << uc_o.b << " " << uc_o.c << " " << uc_o.alpha << " " << uc_o.beta << " " << uc_o.gamma << std::endl; - CHECK(fabsf(xtal_opt.geom.GetBeamX_pxl() - exp_i.GetBeamX_pxl()) < 0.1); - CHECK(fabsf(xtal_opt.geom.GetBeamY_pxl() - exp_i.GetBeamY_pxl()) < 0.1); + CHECK(fabsf(xtal_opt.geom.GetBeamX_pxl() - exp_i.GetBeamX_pxl()) < 0.2); + CHECK(fabsf(xtal_opt.geom.GetBeamY_pxl() - exp_i.GetBeamY_pxl()) < 0.2); CHECK(fabsf(uc_i.a - uc_o.a) < 0.1); CHECK(fabsf(uc_i.b - uc_o.b) < 0.1); CHECK(fabsf(uc_i.c - uc_o.c) < 0.2); - CHECK(fabs(uc_o.alpha - 90) < 0.02); - CHECK(fabs(uc_o.beta - uc_i.beta) < 0.02); - CHECK(fabs(uc_o.gamma - 90) < 0.02); + CHECK(fabs(uc_o.alpha - 90) < 0.05); + CHECK(fabs(uc_o.beta - uc_i.beta) < 0.05); + CHECK(fabs(uc_o.gamma - 90) < 0.05); } TEST_CASE("LatticeToRodrigues") { -- 2.49.1 From 9c5a3f5c121d10524888d15d0a2c1978c910e080 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Tue, 20 Jan 2026 11:20:35 +0100 Subject: [PATCH 42/96] IndexAndRefine: Stabilize profile radius and mosaicity, by using moving average --- image_analysis/CMakeLists.txt | 4 +++- image_analysis/IndexAndRefine.cpp | 32 +++++++++++++++++---------- image_analysis/IndexAndRefine.h | 3 +++ image_analysis/RotationParameters.cpp | 27 ++++++++++++++++++++++ image_analysis/RotationParameters.h | 20 +++++++++++++++++ 5 files changed, 73 insertions(+), 13 deletions(-) create mode 100644 image_analysis/RotationParameters.cpp create mode 100644 image_analysis/RotationParameters.h diff --git a/image_analysis/CMakeLists.txt b/image_analysis/CMakeLists.txt index 517844ec..1720f70f 100644 --- a/image_analysis/CMakeLists.txt +++ b/image_analysis/CMakeLists.txt @@ -28,7 +28,9 @@ ADD_LIBRARY(JFJochImageAnalysis STATIC dark_mask_analysis/DarkMaskAnalysis.cpp dark_mask_analysis/DarkMaskAnalysis.h RotationIndexer.cpp - RotationIndexer.h) + RotationIndexer.h + RotationParameters.cpp + RotationParameters.h) FIND_PACKAGE(Eigen3 3.4 REQUIRED NO_MODULE) # provides Eigen3::Eigen diff --git a/image_analysis/IndexAndRefine.cpp b/image_analysis/IndexAndRefine.cpp index 71afcc99..294c17f0 100644 --- a/image_analysis/IndexAndRefine.cpp +++ b/image_analysis/IndexAndRefine.cpp @@ -20,8 +20,6 @@ IndexAndRefine::IndexAndRefine(const DiffractionExperiment &x, IndexerThreadPool rotation_indexer = std::make_unique(x, *indexer); } -#include - IndexAndRefine::IndexingOutcome IndexAndRefine::DetermineLatticeAndSymmetry(DataMessage &msg) { IndexingOutcome outcome(experiment); @@ -131,13 +129,32 @@ void IndexAndRefine::QuickPredictAndIntegrate(DataMessage &msg, if (!outcome.lattice_candidate) return; - float ewald_dist_cutoff = 0.001f; + CrystalLattice latt = outcome.lattice_candidate.value(); + if (rotation_indexer) { + // Rotate lattice_candidate to the current image angle + auto gon = experiment.GetGoniometer(); + if (gon) + latt = outcome.lattice_candidate->Multiply(gon->GetTransformation(-msg.number)); + // Use moving average for mosaicity and profile_radius (also add beam center later) + if (msg.mosaicity_deg) + msg.mosaicity_deg = rotation_parameters.Mosaicity(msg.mosaicity_deg.value()); + if (msg.profile_radius) { + msg.profile_radius = rotation_parameters.ProfileRadius(msg.profile_radius.value()); + } + } + + float ewald_dist_cutoff = 0.001f; if (msg.profile_radius) ewald_dist_cutoff = msg.profile_radius.value() * 2.0f; + if (experiment.GetBraggIntegrationSettings().GetFixedProfileRadius_recipA()) ewald_dist_cutoff = experiment.GetBraggIntegrationSettings().GetFixedProfileRadius_recipA().value() * 3.0f; + + + + BraggPredictionSettings settings_prediction{ .high_res_A = experiment.GetBraggIntegrationSettings().GetDMinLimit_A(), .ewald_dist_cutoff = ewald_dist_cutoff, @@ -146,15 +163,6 @@ void IndexAndRefine::QuickPredictAndIntegrate(DataMessage &msg, .image_number = static_cast(msg.number) }; - CrystalLattice latt = outcome.lattice_candidate.value(); - - if (rotation_indexer) { - // Rotate lattice_candidate to the current image angle - auto gon = experiment.GetGoniometer(); - if (gon) - latt = outcome.lattice_candidate->Multiply(gon->GetTransformation(-msg.number)); - } - auto nrefl = prediction.Calc(outcome.experiment, latt, settings_prediction); auto refl_ret = BraggIntegrate2D(outcome.experiment, image, prediction.GetReflections(), nrefl, msg.number); diff --git a/image_analysis/IndexAndRefine.h b/image_analysis/IndexAndRefine.h index 8582da59..0c4005b0 100644 --- a/image_analysis/IndexAndRefine.h +++ b/image_analysis/IndexAndRefine.h @@ -13,6 +13,7 @@ #include "indexing/IndexerThreadPool.h" #include "lattice_search/LatticeSearch.h" #include "RotationIndexer.h" +#include "RotationParameters.h" class IndexAndRefine { const bool index_ice_rings; @@ -26,6 +27,8 @@ class IndexAndRefine { IndexerThreadPool *indexer_; std::unique_ptr rotation_indexer; + RotationParameters rotation_parameters; + struct IndexingOutcome { std::optional lattice_candidate; DiffractionExperiment experiment; diff --git a/image_analysis/RotationParameters.cpp b/image_analysis/RotationParameters.cpp new file mode 100644 index 00000000..5b259155 --- /dev/null +++ b/image_analysis/RotationParameters.cpp @@ -0,0 +1,27 @@ +// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute +// SPDX-License-Identifier: GPL-3.0-only + +#include "RotationParameters.h" + +RotationParameters::RotationParameters() + : profile_radius(100), beam_x(100), beam_y(100), mosaicity(100) {} + +float RotationParameters::ProfileRadius(float input) { + profile_radius.Add(input); + return profile_radius.Read().value_or(input); +} + +float RotationParameters::Mosaicity(float input) { + mosaicity.Add(input); + return mosaicity.Read().value_or(input); +} + +float RotationParameters::BeamX(float input) { + beam_x.Add(input); + return beam_x.Read().value_or(input); +} + +float RotationParameters::BeamY(float input) { + beam_y.Add(input); + return beam_y.Read().value_or(input); +} diff --git a/image_analysis/RotationParameters.h b/image_analysis/RotationParameters.h new file mode 100644 index 00000000..2c91e39b --- /dev/null +++ b/image_analysis/RotationParameters.h @@ -0,0 +1,20 @@ +// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute +// SPDX-License-Identifier: GPL-3.0-only + +#ifndef JFJOCH_ROTATIONPARAMETERS_H +#define JFJOCH_ROTATIONPARAMETERS_H + +#include "../common/MovingAverage.h" + +class RotationParameters { + MovingAverage profile_radius, beam_x, beam_y, mosaicity; +public: + RotationParameters(); + float ProfileRadius(float input); + float Mosaicity(float input); + float BeamX(float input); + float BeamY(float input); +}; + + +#endif //JFJOCH_ROTATIONPARAMETERS_H \ No newline at end of file -- 2.49.1 From 7a1355df23b07ff222207836e07e98127d120040 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Tue, 20 Jan 2026 13:07:14 +0100 Subject: [PATCH 43/96] BraggPredictionRotation: Work in progress --- .../BraggPredictionRotation.cpp | 66 +++++++++---------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/image_analysis/bragg_prediction/BraggPredictionRotation.cpp b/image_analysis/bragg_prediction/BraggPredictionRotation.cpp index 40b90114..5c55ded4 100644 --- a/image_analysis/bragg_prediction/BraggPredictionRotation.cpp +++ b/image_analysis/bragg_prediction/BraggPredictionRotation.cpp @@ -103,8 +103,6 @@ int BraggPredictionRotation::Calc(const DiffractionExperiment &experiment, const float coeff_const = det_distance / pixel_size; // Determine prediction interval in spindle angle. - const float start_deg = gon.GetStart_deg(); - const float inc_deg = gon.GetIncrement_deg(); const float wedge_deg = gon.GetWedge_deg(); const float phi0_deg = gon.GetAngle_deg(static_cast(settings.image_number)); @@ -117,7 +115,7 @@ int BraggPredictionRotation::Calc(const DiffractionExperiment &experiment, const float mosaicity_rad = deg_to_rad(settings.mosaicity_deg); const float half_mosaicity = mosaicity_rad * 0.5f; - const Coord w = gon.GetAxis().Normalize(); + const Coord m2 = gon.GetAxis().Normalize(); int i = 0; @@ -138,38 +136,40 @@ int BraggPredictionRotation::Calc(const DiffractionExperiment &experiment, if (i >= max_reflections) continue; - const float recip_x = AhBk_x + Cstar.x * l; - const float recip_y = AhBk_y + Cstar.y * l; - const float recip_z = AhBk_z + Cstar.z * l; - const float recip_sq = recip_x * recip_x + recip_y * recip_y + recip_z * recip_z; + const float p0_x = AhBk_x + Cstar.x * l; + const float p0_y = AhBk_y + Cstar.y * l; + const float p0_z = AhBk_z + Cstar.z * l; + const float p0_sq = p0_x * p0_x + p0_y * p0_y + p0_z * p0_z; - if (recip_sq <= 0.0f || recip_sq > one_over_dmax_sq) + if (p0_sq <= 0.0f || p0_sq > one_over_dmax_sq) continue; - const float g_par_s = recip_x * w.x + recip_y * w.y + recip_z * w.z; - const float g_par_x = w.x * g_par_s; - const float g_par_y = w.y * g_par_s; - const float g_par_z = w.z * g_par_s; + const float p0_par_s = p0_x * m2.x + p0_y * m2.y + p0_z * m2.z; + const float p0_par_x = m2.x * p0_par_s; + const float p0_par_y = m2.y * p0_par_s; + const float p0_par_z = m2.z * p0_par_s; - const float g_perp_x = recip_x - g_par_x; - const float g_perp_y = recip_y - g_par_y; - const float g_perp_z = recip_z - g_par_z; + const float p0_perp_x = p0_x - p0_par_x; + const float p0_perp_y = p0_y - p0_par_y; + const float p0_perp_z = p0_z - p0_par_z; - const float g_perp2 = g_perp_x * g_perp_x + g_perp_y * g_perp_y + g_perp_z * g_perp_z; - if (g_perp2 < 1e-12f) + const float p0_perp_sq = p0_perp_x * p0_perp_x + p0_perp_y * p0_perp_y + p0_perp_z * p0_perp_z; + if (p0_perp_sq < 1e-12f) continue; - const float p_x = S0.x + g_par_x; - const float p_y = S0.y + g_par_y; - const float p_z = S0.z + g_par_z; + const float p_x = S0.x + p0_par_x; + const float p_y = S0.y + p0_par_y; + const float p_z = S0.z + p0_par_z; - const float w_x_gperp_x = w.y * g_perp_z - w.z * g_perp_y; - const float w_x_gperp_y = w.z * g_perp_x - w.x * g_perp_z; - const float w_x_gperp_z = w.x * g_perp_y - w.y * g_perp_x; + const float m2_x_gperp_x = m2.y * p0_perp_z - m2.z * p0_perp_y; + const float m2_x_gperp_y = m2.z * p0_perp_x - m2.x * p0_perp_z; + const float m2_x_gperp_z = m2.x * p0_perp_y - m2.y * p0_perp_x; - const float A_trig = 2.0f * (p_x * g_perp_x + p_y * g_perp_y + p_z * g_perp_z); - const float B_trig = 2.0f * (p_x * w_x_gperp_x + p_y * w_x_gperp_y + p_z * w_x_gperp_z); - const float D_trig = (p_x * p_x + p_y * p_y + p_z * p_z) + g_perp2 - one_over_wavelength_sq; + // Trig equation coefficients for solving the Laue condition in φ: + // A cosφ + B sinφ + D = 0 + const float A_trig = 2.0f * (p_x * p0_perp_x + p_y * p0_perp_y + p_z * p0_perp_z); + const float B_trig = 2.0f * (p_x * m2_x_gperp_x + p_y * m2_x_gperp_y + p_z * m2_x_gperp_z); + const float D_trig = (p_x * p_x + p_y * p_y + p_z * p_z) + p0_perp_sq - one_over_wavelength_sq; float sols[2]{}; const int nsol = solve_trig(A_trig, B_trig, D_trig, phi0 - half_mosaicity, phi1 + half_mosaicity, sols); @@ -183,13 +183,13 @@ int BraggPredictionRotation::Calc(const DiffractionExperiment &experiment, const float sin_p = sinf(phi); // Rodrigues' rotation formula: g = g_par + cos(phi)*g_perp + sin(phi)*(w x g_perp) - const float g_x = g_par_x + cos_p * g_perp_x + sin_p * w_x_gperp_x; - const float g_y = g_par_y + cos_p * g_perp_y + sin_p * w_x_gperp_y; - const float g_z = g_par_z + cos_p * g_perp_z + sin_p * w_x_gperp_z; + const float p_star_x = p0_par_x + cos_p * p0_perp_x + sin_p * m2_x_gperp_x; + const float p_star_y = p0_par_y + cos_p * p0_perp_y + sin_p * m2_x_gperp_y; + const float p_star_z = p0_par_z + cos_p * p0_perp_z + sin_p * m2_x_gperp_z; - const float S_x = S0.x + g_x; - const float S_y = S0.y + g_y; - const float S_z = S0.z + g_z; + const float S_x = S0.x + p_star_x; + const float S_y = S0.y + p_star_y; + const float S_z = S0.z + p_star_z; // Inlined RecipToDector const float S_rot_x = rot[0] * S_x + rot[1] * S_y + rot[2] * S_z; @@ -206,7 +206,7 @@ int BraggPredictionRotation::Calc(const DiffractionExperiment &experiment, if (x < 0.0f || x >= det_width_pxl || y < 0.0f || y >= det_height_pxl) continue; float dist_ewald_sphere = std::fabs(sqrtf(S_x * S_x + S_y * S_y + S_z * S_z) - one_over_wavelength); - float d = 1.0f / sqrtf(recip_sq); + float d = 1.0f / sqrtf(p0_sq); const float phi_deg = rad_to_deg(phi); reflections[i] = Reflection{ .h = h, -- 2.49.1 From 3e721dc476168529263397740d934c2cd2d7fc09 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Tue, 20 Jan 2026 13:08:13 +0100 Subject: [PATCH 44/96] IndexAndRefine: Minor change in sign...tbd how it should go --- image_analysis/IndexAndRefine.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/image_analysis/IndexAndRefine.cpp b/image_analysis/IndexAndRefine.cpp index 294c17f0..378a6079 100644 --- a/image_analysis/IndexAndRefine.cpp +++ b/image_analysis/IndexAndRefine.cpp @@ -151,16 +151,12 @@ void IndexAndRefine::QuickPredictAndIntegrate(DataMessage &msg, if (experiment.GetBraggIntegrationSettings().GetFixedProfileRadius_recipA()) ewald_dist_cutoff = experiment.GetBraggIntegrationSettings().GetFixedProfileRadius_recipA().value() * 3.0f; - - - - BraggPredictionSettings settings_prediction{ .high_res_A = experiment.GetBraggIntegrationSettings().GetDMinLimit_A(), .ewald_dist_cutoff = ewald_dist_cutoff, .max_hkl = 100, .centering = outcome.symmetry.centering, - .image_number = static_cast(msg.number) + .image_number = static_cast(-msg.number) }; auto nrefl = prediction.Calc(outcome.experiment, latt, settings_prediction); -- 2.49.1 From 7da28b5c9abc0a12e89f0920913e8b5df8d40cbd Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Tue, 20 Jan 2026 13:28:42 +0100 Subject: [PATCH 45/96] IndexAndRefine: Fix using lattice at zero deg for refinement --- image_analysis/IndexAndRefine.cpp | 13 ++++++------- image_analysis/RotationIndexer.cpp | 1 - image_analysis/indexing/AnalyzeIndexing.cpp | 8 ++------ image_analysis/indexing/AnalyzeIndexing.h | 4 +--- 4 files changed, 9 insertions(+), 17 deletions(-) diff --git a/image_analysis/IndexAndRefine.cpp b/image_analysis/IndexAndRefine.cpp index 378a6079..4cb80433 100644 --- a/image_analysis/IndexAndRefine.cpp +++ b/image_analysis/IndexAndRefine.cpp @@ -26,7 +26,11 @@ IndexAndRefine::IndexingOutcome IndexAndRefine::DetermineLatticeAndSymmetry(Data if (rotation_indexer) { auto result = rotation_indexer->ProcessImage(msg.number, msg.spots); if (result) { - outcome.lattice_candidate = result->lattice; + + // get rotated lattice + auto gon = experiment.GetGoniometer(); + if (gon) + outcome.lattice_candidate = result->lattice.Multiply(gon->GetTransformation(-msg.number)); outcome.experiment.BeamX_pxl(result->geom.GetBeamX_pxl()) .BeamY_pxl(result->geom.GetBeamY_pxl()) @@ -132,10 +136,6 @@ void IndexAndRefine::QuickPredictAndIntegrate(DataMessage &msg, CrystalLattice latt = outcome.lattice_candidate.value(); if (rotation_indexer) { - // Rotate lattice_candidate to the current image angle - auto gon = experiment.GetGoniometer(); - if (gon) - latt = outcome.lattice_candidate->Multiply(gon->GetTransformation(-msg.number)); // Use moving average for mosaicity and profile_radius (also add beam center later) if (msg.mosaicity_deg) msg.mosaicity_deg = rotation_parameters.Mosaicity(msg.mosaicity_deg.value()); @@ -201,8 +201,7 @@ void IndexAndRefine::ProcessImage(DataMessage &msg, if (!outcome.lattice_candidate) return; - if (!AnalyzeIndexing(msg, outcome.experiment, *outcome.lattice_candidate, - outcome.experiment.GetGoniometer(), rotation_indexer.get() != nullptr)) + if (!AnalyzeIndexing(msg, outcome.experiment, *outcome.lattice_candidate)) return; msg.lattice_type = outcome.symmetry; diff --git a/image_analysis/RotationIndexer.cpp b/image_analysis/RotationIndexer.cpp index 90177995..ba0ad0a6 100644 --- a/image_analysis/RotationIndexer.cpp +++ b/image_analysis/RotationIndexer.cpp @@ -133,7 +133,6 @@ std::optional RotationIndexer::ProcessImage(int64_t image .search_result = search_result_, .geom = updated_geom_ }; - return GetLattice(); } std::optional RotationIndexer::GetLattice() { diff --git a/image_analysis/indexing/AnalyzeIndexing.cpp b/image_analysis/indexing/AnalyzeIndexing.cpp index 2937dcad..3fa42078 100644 --- a/image_analysis/indexing/AnalyzeIndexing.cpp +++ b/image_analysis/indexing/AnalyzeIndexing.cpp @@ -165,9 +165,7 @@ namespace { bool AnalyzeIndexing(DataMessage &message, const DiffractionExperiment &experiment, - const CrystalLattice &latt, - const std::optional &rotation_axis, - bool rotation_indexed) { + const CrystalLattice &latt) { std::vector indexed_spots(message.spots.size()); // Check spots @@ -218,9 +216,7 @@ bool AnalyzeIndexing(DataMessage &message, nspots_ref++; } - if (rotation_indexed - || (nspots_indexed >= viable_cell_min_spots - && nspots_indexed >= std::lround(min_percentage_spots * nspots_ref))) { + if (nspots_indexed >= viable_cell_min_spots && nspots_indexed >= std::lround(min_percentage_spots * nspots_ref)) { auto uc = latt.GetUnitCell(); if (!ok(uc.a) || !ok(uc.b) || !ok(uc.c) || !ok(uc.alpha) || !ok(uc.beta) || !ok(uc.gamma)) return false; diff --git a/image_analysis/indexing/AnalyzeIndexing.h b/image_analysis/indexing/AnalyzeIndexing.h index deb2b335..0644bb6b 100644 --- a/image_analysis/indexing/AnalyzeIndexing.h +++ b/image_analysis/indexing/AnalyzeIndexing.h @@ -12,9 +12,7 @@ constexpr static float min_percentage_spots = 0.20f; bool AnalyzeIndexing(DataMessage &message, const DiffractionExperiment &experiment, - const CrystalLattice &latt, - const std::optional &rotation_axis, - bool rotation_indexed); + const CrystalLattice &latt); #endif //JFJOCH_ANALYZEINDEXING_H \ No newline at end of file -- 2.49.1 From f14eca977d658b107038be8f7d7bb544031e6273 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Wed, 21 Jan 2026 09:39:44 +0100 Subject: [PATCH 46/96] jfjoch_extract_hkl: Simple summation of reflections for rotation scan --- tools/jfjoch_extract_hkl.cpp | 98 ++++++++++++++++++++++++++++-------- 1 file changed, 77 insertions(+), 21 deletions(-) diff --git a/tools/jfjoch_extract_hkl.cpp b/tools/jfjoch_extract_hkl.cpp index be3a1786..c6dd9865 100644 --- a/tools/jfjoch_extract_hkl.cpp +++ b/tools/jfjoch_extract_hkl.cpp @@ -14,12 +14,27 @@ void print_usage(Logger &logger) { logger.Info(" -I Number of images"); logger.Info(" -o Output filename"); logger.Info(" -x Max dist from Ewald sphere"); + logger.Info(" -R Sum same HKL across neighboring images (image +/- 1)"); } -int main(int argc, char **argv) { +uint64_t hkl_key_16(int64_t h, int64_t k, int64_t l) { + const uint16_t bias = 512; // maps -512..512 -> 0..1024 + uint64_t uh = static_cast(std::clamp(h + bias, int64_t(0), int64_t(1024))); + uint64_t uk = static_cast(std::clamp(k + bias, int64_t(0), int64_t(1024))); + uint64_t ul = static_cast(std::clamp(l + bias, int64_t(0), int64_t(1024))); + return uh | (uk << 16) | (ul << 32); +} +struct HKLData { + double I_sum = 0.0; + float first_image = 0; + int64_t h ,k,l; +}; + +int main(int argc, char **argv) { int64_t image_number = 0; float max_dist_ewald_sphere = 1.0; + bool sum_neighboring = false; std::string output_filename = "out.hkl"; @@ -28,7 +43,7 @@ int main(int argc, char **argv) { Logger logger("jfjoch_extract_hkl"); logger.Verbose(true); int opt; - while ((opt = getopt(argc, argv, "I:x:o:")) != -1) { + while ((opt = getopt(argc, argv, "I:x:o:R")) != -1) { switch (opt) { case 'I': image_number = atol(optarg); @@ -39,6 +54,9 @@ int main(int argc, char **argv) { case 'o': output_filename = optarg; break; + case 'R': + sum_neighboring = true; + break; default: /* '?' */ print_usage(logger); exit(EXIT_FAILURE); @@ -56,28 +74,66 @@ int main(int argc, char **argv) { auto dataset = reader.LoadImage(image_number); if (dataset) { - auto geom = dataset->Dataset().experiment.GetDiffractionGeometry(); + if (sum_neighboring) { + std::unordered_map agg; + int64_t total_images = reader.GetNumberOfImages(); + auto geom = dataset->Dataset().experiment.GetDiffractionGeometry(); - std::fstream f(output_filename, std::ios::out); - if (dataset->ImageData().indexing_lattice) { - auto latt = dataset->ImageData().indexing_lattice.value(); + for (int i = 0; i < total_images; ++i) { + auto dataset = reader.LoadImage(i); + if (!dataset) continue; + for (const auto &r: dataset->ImageData().reflections) { + int64_t key = hkl_key_16(r.h, r.k, r.l); - Coord astar = latt.Astar(); - Coord bstar = latt.Bstar(); - Coord cstar = latt.Cstar(); - auto uc = latt.GetUnitCell(); - logger.Info("Cell {} {} {} {} {} {}",uc.a, uc.b, uc.c, uc.alpha, uc.beta, uc.gamma); - logger.Info("A {} {} {}", astar.x, astar.y, astar.z); - logger.Info("B {} {} {}", bstar.x, bstar.y, bstar.z); - logger.Info("C {} {} {}", cstar.x, cstar.y, cstar.z); + if (agg.find(key) == agg.end()) { + agg[key] = HKLData{ + .I_sum = r.I, + .first_image = r.image_number, + .h = r.h, .k = r.k, .l = r.l + }; + } else { + // Handle situation of too many images apart + if (std::fabs(agg[key].first_image - r.image_number) > 30.0) + continue; - logger.Info("{} reflections identified", dataset->ImageData().reflections.size()); - for (const auto &r: dataset->ImageData().reflections) { - auto recip = astar * r.h + bstar * r.k + cstar * r.l; - auto dist = geom.DistFromEwaldSphere(recip); - if (dist < max_dist_ewald_sphere) - f << r.l << " " << r.k << " " << r.h << " " << r.I << " " << r.sigma << " " << dist << std::endl; + agg[key].I_sum += r.I; + } + } + } + + std::fstream f(output_filename, std::ios::out); + for (const auto &val: agg | std::views::values) { + double I = val.I_sum; + + f << val.h << " " << val.k << " " << val.l << " " << I << std::endl; + } + } else { + auto geom = dataset->Dataset().experiment.GetDiffractionGeometry(); + + std::fstream f(output_filename, std::ios::out); + if (dataset->ImageData().indexing_lattice) { + auto latt = dataset->ImageData().indexing_lattice.value(); + + Coord astar = latt.Astar(); + Coord bstar = latt.Bstar(); + Coord cstar = latt.Cstar(); + auto uc = latt.GetUnitCell(); + logger.Info("Cell {} {} {} {} {} {}", uc.a, uc.b, uc.c, uc.alpha, uc.beta, uc.gamma); + logger.Info("A {} {} {}", astar.x, astar.y, astar.z); + logger.Info("B {} {} {}", bstar.x, bstar.y, bstar.z); + logger.Info("C {} {} {}", cstar.x, cstar.y, cstar.z); + + logger.Info("{} reflections identified", dataset->ImageData().reflections.size()); + for (const auto &r: dataset->ImageData().reflections) { + auto recip = astar * r.h + bstar * r.k + cstar * r.l; + auto dist = geom.DistFromEwaldSphere(recip); + if (dist < max_dist_ewald_sphere) + f << r.l << " " << r.k << " " << r.h << " " + << r.I << " " << r.sigma << " " << dist << " " + << r.predicted_x << " " << r.predicted_y << " " << r.angle_deg + << std::endl; + } } } } -} \ No newline at end of file +} -- 2.49.1 From 2000affffa0206b946a94ba2b59ed2933684767e Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Wed, 21 Jan 2026 10:17:37 +0100 Subject: [PATCH 47/96] jfjoch_extract_hkl: Work in progress (early) --- tools/CMakeLists.txt | 4 +- tools/XdsIntegrateParser.cpp | 48 +++++++++++++++++++++ tools/XdsIntegrateParser.h | 31 ++++++++++++++ tools/jfjoch_extract_hkl.cpp | 81 +++++++++++++++++++----------------- 4 files changed, 125 insertions(+), 39 deletions(-) create mode 100644 tools/XdsIntegrateParser.cpp create mode 100644 tools/XdsIntegrateParser.h diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 424ec962..f43016e3 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -39,7 +39,9 @@ ADD_EXECUTABLE(jfjoch_indexing_test jfjoch_indexing_test.cpp) TARGET_LINK_LIBRARIES(jfjoch_indexing_test JFJochReader JFJochImageAnalysis JFJochWriter) INSTALL(TARGETS jfjoch_indexing_test RUNTIME COMPONENT jfjoch) -ADD_EXECUTABLE(jfjoch_extract_hkl jfjoch_extract_hkl.cpp) +ADD_EXECUTABLE(jfjoch_extract_hkl jfjoch_extract_hkl.cpp + XdsIntegrateParser.cpp + XdsIntegrateParser.h) TARGET_LINK_LIBRARIES(jfjoch_extract_hkl JFJochReader) INSTALL(TARGETS jfjoch_extract_hkl RUNTIME COMPONENT viewer) diff --git a/tools/XdsIntegrateParser.cpp b/tools/XdsIntegrateParser.cpp new file mode 100644 index 00000000..8d94dbdb --- /dev/null +++ b/tools/XdsIntegrateParser.cpp @@ -0,0 +1,48 @@ +// SPDX-FileCopyrightText: 2024 Filip Leonarski, Paul Scherrer Institute +// SPDX-License-Identifier: GPL-3.0-only + +#include "XdsIntegrateParser.h" + +#include +#include +#include + +IntegrateMap ParseXdsIntegrateHkl(const std::string& filename) { + std::ifstream in(filename); + if (!in.is_open()) { + throw std::runtime_error("Failed to open INTEGRATE.HKL file: " + filename); + } + + IntegrateMap result; + std::string line; + + while (std::getline(in, line)) { + if (line.empty()) continue; + char c0 = line.front(); + if (c0 == '!' || c0 == '#') continue; + + std::istringstream iss(line); + int32_t h, k, l; + double I, sigma; + + if (!(iss >> h >> k >> l >> I >> sigma)) { + continue; + } + + HKLData entry; + entry.h = h; + entry.k = k; + entry.l = l; + entry.I = I; + entry.sigma = sigma; + + double v = 0.0; + while (iss >> v) { + entry.tail.push_back(v); + } + + result[hkl_key_16(h, k, l)].push_back(std::move(entry)); + } + + return result; +} \ No newline at end of file diff --git a/tools/XdsIntegrateParser.h b/tools/XdsIntegrateParser.h new file mode 100644 index 00000000..1d5e4c7e --- /dev/null +++ b/tools/XdsIntegrateParser.h @@ -0,0 +1,31 @@ +// SPDX-FileCopyrightText: 2024 Filip Leonarski, Paul Scherrer Institute +// SPDX-License-Identifier: GPL-3.0-only + + +#pragma once + +#include +#include +#include +#include +#include + +inline uint64_t hkl_key_16(int64_t h, int64_t k, int64_t l) { + const uint16_t bias = 512; // maps -512..512 -> 0..1024 + uint64_t uh = static_cast(std::clamp(h + bias, int64_t(0), int64_t(1024))); + uint64_t uk = static_cast(std::clamp(k + bias, int64_t(0), int64_t(1024))); + uint64_t ul = static_cast(std::clamp(l + bias, int64_t(0), int64_t(1024))); + return uh | (uk << 16) | (ul << 32); +} + +struct HKLData { + int64_t h ,k,l; + double I = 0.0; + double sigma = 0.0; + float last_image = 0; + std::vector tail; // any remaining numeric columns +}; + +using IntegrateMap = std::unordered_map>; + +IntegrateMap ParseXdsIntegrateHkl(const std::string& filename); \ No newline at end of file diff --git a/tools/jfjoch_extract_hkl.cpp b/tools/jfjoch_extract_hkl.cpp index c6dd9865..126db9fc 100644 --- a/tools/jfjoch_extract_hkl.cpp +++ b/tools/jfjoch_extract_hkl.cpp @@ -3,38 +3,27 @@ #include +#include "XdsIntegrateParser.h" #include "../reader/JFJochHDF5Reader.h" #include "../common/print_license.h" #include "../common/Logger.h" - +#include "XdsIntegrateParser.h" void print_usage(Logger &logger) { logger.Info("Usage ./jfjoch_extract_hkl {} "); logger.Info("Options:"); - logger.Info(" -I Number of images"); - logger.Info(" -o Output filename"); - logger.Info(" -x Max dist from Ewald sphere"); - logger.Info(" -R Sum same HKL across neighboring images (image +/- 1)"); + logger.Info(" -I Number of images"); + logger.Info(" -o Output filename"); + logger.Info(" -x Max dist from Ewald sphere"); + logger.Info(" -R{} Sum same HKL across neighboring images (image +/- 1) - optional reference INTEGRATE.HKL file name"); } -uint64_t hkl_key_16(int64_t h, int64_t k, int64_t l) { - const uint16_t bias = 512; // maps -512..512 -> 0..1024 - uint64_t uh = static_cast(std::clamp(h + bias, int64_t(0), int64_t(1024))); - uint64_t uk = static_cast(std::clamp(k + bias, int64_t(0), int64_t(1024))); - uint64_t ul = static_cast(std::clamp(l + bias, int64_t(0), int64_t(1024))); - return uh | (uk << 16) | (ul << 32); -} - -struct HKLData { - double I_sum = 0.0; - float first_image = 0; - int64_t h ,k,l; -}; int main(int argc, char **argv) { int64_t image_number = 0; float max_dist_ewald_sphere = 1.0; bool sum_neighboring = false; + std::string ref_file; std::string output_filename = "out.hkl"; @@ -43,7 +32,7 @@ int main(int argc, char **argv) { Logger logger("jfjoch_extract_hkl"); logger.Verbose(true); int opt; - while ((opt = getopt(argc, argv, "I:x:o:R")) != -1) { + while ((opt = getopt(argc, argv, "I:x:o:R::")) != -1) { switch (opt) { case 'I': image_number = atol(optarg); @@ -56,6 +45,8 @@ int main(int argc, char **argv) { break; case 'R': sum_neighboring = true; + if (optarg) + ref_file = std::string(optarg); break; default: /* '?' */ print_usage(logger); @@ -75,37 +66,51 @@ int main(int argc, char **argv) { if (dataset) { if (sum_neighboring) { - std::unordered_map agg; + IntegrateMap agg; int64_t total_images = reader.GetNumberOfImages(); - auto geom = dataset->Dataset().experiment.GetDiffractionGeometry(); + + IntegrateMap xds_result; + if (!ref_file.empty()) + xds_result = ParseXdsIntegrateHkl(ref_file); for (int i = 0; i < total_images; ++i) { auto dataset = reader.LoadImage(i); if (!dataset) continue; for (const auto &r: dataset->ImageData().reflections) { int64_t key = hkl_key_16(r.h, r.k, r.l); - - if (agg.find(key) == agg.end()) { - agg[key] = HKLData{ - .I_sum = r.I, - .first_image = r.image_number, - .h = r.h, .k = r.k, .l = r.l - }; - } else { - // Handle situation of too many images apart - if (std::fabs(agg[key].first_image - r.image_number) > 30.0) - continue; - - agg[key].I_sum += r.I; + auto it = agg.find(key); + HKLData data{ + .h = r.h, + .k = r.k, + .l = r.l, + .I = r.I, + .last_image = r.image_number + }; + bool found = false; + if (it != agg.end()) { + for (auto &val: it->second) { + if (val.last_image == r.image_number - 1) { + val.I += r.I; + val.last_image = r.image_number; + found = true; + break; + } + } } + if (!found) + agg[key].push_back(data); } } std::fstream f(output_filename, std::ios::out); - for (const auto &val: agg | std::views::values) { - double I = val.I_sum; - - f << val.h << " " << val.k << " " << val.l << " " << I << std::endl; + for (const auto &[key, val]: agg) { + if (!val.empty()) { + f << val[0].h << " " << val[0].k << " " << val[0].l << " " << val[0].I; + auto xds_it = xds_result.find(key); + if (xds_it != xds_result.end() && !xds_it->second.empty()) + f << " " << xds_it->second[0].I; + f << std::endl; + } } } else { auto geom = dataset->Dataset().experiment.GetDiffractionGeometry(); -- 2.49.1 From 0e4e5dc8f112f3b1c763ee7e67f8c2e02895eb13 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Wed, 21 Jan 2026 13:47:56 +0100 Subject: [PATCH 48/96] jfjoch_extract_hkl: Work in progress -- CC calculation --- tools/XdsIntegrateParser.cpp | 89 +++++++++++++++++++++++++++++++++++- tools/XdsIntegrateParser.h | 19 +++++++- tools/jfjoch_extract_hkl.cpp | 9 +++- 3 files changed, 114 insertions(+), 3 deletions(-) diff --git a/tools/XdsIntegrateParser.cpp b/tools/XdsIntegrateParser.cpp index 8d94dbdb..41a908aa 100644 --- a/tools/XdsIntegrateParser.cpp +++ b/tools/XdsIntegrateParser.cpp @@ -7,6 +7,8 @@ #include #include +#include "../common/ResolutionShells.h" + IntegrateMap ParseXdsIntegrateHkl(const std::string& filename) { std::ifstream in(filename); if (!in.is_open()) { @@ -25,7 +27,7 @@ IntegrateMap ParseXdsIntegrateHkl(const std::string& filename) { int32_t h, k, l; double I, sigma; - if (!(iss >> h >> k >> l >> I >> sigma)) { + if (!(iss >> l >> k >> h >> I >> sigma)) { continue; } @@ -44,5 +46,90 @@ IntegrateMap ParseXdsIntegrateHkl(const std::string& filename) { result[hkl_key_16(h, k, l)].push_back(std::move(entry)); } + return result; +} + + +namespace { +double SumIntensity(const std::vector& v) { + double s = 0.0; + for (const auto& e : v) + s += e.I; + return s; +} +} // namespace + +CcHalfByResolutionResult ComputeCcByResolution( + const CrystalLattice& lattice, + const IntegrateMap& ours, + const IntegrateMap& xds, + float d_min, + float d_max, + int32_t nshells) { + + ResolutionShells shells(d_min, d_max, nshells); + + std::vector sum_x(nshells, 0.0); + std::vector sum_y(nshells, 0.0); + std::vector sum_x2(nshells, 0.0); + std::vector sum_y2(nshells, 0.0); + std::vector sum_xy(nshells, 0.0); + std::vector n(nshells, 0); + + const Coord astar = lattice.Astar(); + const Coord bstar = lattice.Bstar(); + const Coord cstar = lattice.Cstar(); + + for (const auto& [key, ours_list] : ours) { + auto it = xds.find(key); + if (it == xds.end()) + continue; + + const auto& xds_list = it->second; + + double i_ours = SumIntensity(ours_list); + double i_xds = SumIntensity(xds_list); + + int64_t h = ours_list.front().h; + int64_t k = ours_list.front().k; + int64_t l = ours_list.front().l; + + Coord recip = astar * h + bstar * k + cstar * l; + double recip_len = std::sqrt(recip.x * recip.x + recip.y * recip.y + recip.z * recip.z); + if (recip_len <= 0.0) + continue; + + float d = static_cast(1.0 / recip_len); + auto shell = shells.GetShell(d); + if (!shell) + continue; + + int idx = shell.value(); + n[idx] += 1; + sum_x[idx] += i_ours; + sum_y[idx] += i_xds; + sum_x2[idx] += i_ours * i_ours; + sum_y2[idx] += i_xds * i_xds; + sum_xy[idx] += i_ours * i_xds; + } + + CcHalfByResolutionResult result; + result.cc.resize(nshells, std::numeric_limits::quiet_NaN()); + result.pairs = n; + result.shell_mean_one_over_d2 = shells.GetShellMeanOneOverResSq(); + + for (int i = 0; i < nshells; ++i) { + if (n[i] < 2) + continue; + + double denom_x = n[i] * sum_x2[i] - sum_x[i] * sum_x[i]; + double denom_y = n[i] * sum_y2[i] - sum_y[i] * sum_y[i]; + double denom = std::sqrt(denom_x * denom_y); + if (denom <= 0.0) + continue; + + result.cc[i] = (n[i] * sum_xy[i] - sum_x[i] * sum_y[i]) / denom; + } + return result; } \ No newline at end of file diff --git a/tools/XdsIntegrateParser.h b/tools/XdsIntegrateParser.h index 1d5e4c7e..eab0cef1 100644 --- a/tools/XdsIntegrateParser.h +++ b/tools/XdsIntegrateParser.h @@ -10,6 +10,15 @@ #include #include +#include "../common/CrystalLattice.h" + + +struct CcHalfByResolutionResult { + std::vector cc; + std::vector pairs; + std::vector shell_mean_one_over_d2; +}; + inline uint64_t hkl_key_16(int64_t h, int64_t k, int64_t l) { const uint16_t bias = 512; // maps -512..512 -> 0..1024 uint64_t uh = static_cast(std::clamp(h + bias, int64_t(0), int64_t(1024))); @@ -28,4 +37,12 @@ struct HKLData { using IntegrateMap = std::unordered_map>; -IntegrateMap ParseXdsIntegrateHkl(const std::string& filename); \ No newline at end of file +IntegrateMap ParseXdsIntegrateHkl(const std::string& filename); + +CcHalfByResolutionResult ComputeCcByResolution( + const CrystalLattice& lattice, + const IntegrateMap& ours, + const IntegrateMap& xds, + float d_min, + float d_max, + int32_t nshells); diff --git a/tools/jfjoch_extract_hkl.cpp b/tools/jfjoch_extract_hkl.cpp index 126db9fc..61310e24 100644 --- a/tools/jfjoch_extract_hkl.cpp +++ b/tools/jfjoch_extract_hkl.cpp @@ -7,7 +7,6 @@ #include "../reader/JFJochHDF5Reader.h" #include "../common/print_license.h" #include "../common/Logger.h" -#include "XdsIntegrateParser.h" void print_usage(Logger &logger) { logger.Info("Usage ./jfjoch_extract_hkl {} "); @@ -66,6 +65,7 @@ int main(int argc, char **argv) { if (dataset) { if (sum_neighboring) { + CrystalLattice latt; IntegrateMap agg; int64_t total_images = reader.GetNumberOfImages(); @@ -76,6 +76,8 @@ int main(int argc, char **argv) { for (int i = 0; i < total_images; ++i) { auto dataset = reader.LoadImage(i); if (!dataset) continue; + if (dataset->ImageData().indexing_lattice) + latt = dataset->ImageData().indexing_lattice.value(); for (const auto &r: dataset->ImageData().reflections) { int64_t key = hkl_key_16(r.h, r.k, r.l); auto it = agg.find(key); @@ -112,6 +114,11 @@ int main(int argc, char **argv) { f << std::endl; } } + + auto cc_result = ComputeCcByResolution(latt, agg,xds_result, 1.2, 50.0, 20); + for (int i = 0; i < cc_result.cc.size(); ++i) + std::cout << 1/ std::sqrt(cc_result.shell_mean_one_over_d2[i]) << " " << cc_result.cc[i]* 100.0 << " " << cc_result.pairs[i] << std::endl; + } else { auto geom = dataset->Dataset().experiment.GetDiffractionGeometry(); -- 2.49.1 From 4a6085c721ad6c74ea399da989676d355a778c3d Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Wed, 21 Jan 2026 16:34:10 +0100 Subject: [PATCH 49/96] CBOR/HDF5: Save Lorentz-Polarization correction for reflections --- common/Reflection.h | 1 + docs/CBOR.md | 1 + frame_serialize/CBORStream2Deserializer.cpp | 2 ++ frame_serialize/CBORStream2Serializer.cpp | 1 + image_analysis/bragg_integration/BraggIntegrate2D.cpp | 3 +++ reader/JFJochHDF5Reader.cpp | 6 +++++- writer/HDF5DataFilePluginReflection.cpp | 4 +++- 7 files changed, 16 insertions(+), 2 deletions(-) diff --git a/common/Reflection.h b/common/Reflection.h index 00b960dc..de877218 100644 --- a/common/Reflection.h +++ b/common/Reflection.h @@ -21,6 +21,7 @@ struct Reflection { float bkg; float sigma; float dist_ewald; + float lp; bool observed = false; }; diff --git a/docs/CBOR.md b/docs/CBOR.md index 68f86fab..c489bd63 100644 --- a/docs/CBOR.md +++ b/docs/CBOR.md @@ -146,6 +146,7 @@ See [DECTRIS documentation](https://github.com/dectris/documentation/tree/main/s | - sigma | float | standard deviation, estimated from counting statistics (photons) | | | | - image | float | image number (present for each spot) | | | | - dist_ewald | float | distance to Ewald sphere (present only for indexed spots) | | | +| - lp | float | Lorentz and polarization corrections | | | | spot_count | uint64 | Spot count | | | | spot_count_ice_rings | uint64 | Number of spots within identified rings (experimental) | | | | spot_count_low_res | uint64 | Number of spots in low resolution (prior to filtering) | | | diff --git a/frame_serialize/CBORStream2Deserializer.cpp b/frame_serialize/CBORStream2Deserializer.cpp index 1419c302..28695a5d 100644 --- a/frame_serialize/CBORStream2Deserializer.cpp +++ b/frame_serialize/CBORStream2Deserializer.cpp @@ -463,6 +463,8 @@ namespace { r.sigma = GetCBORFloat(map_value); else if (key == "image") r.image_number = GetCBORFloat(map_value); + else if (key == "rlp") + r.lp = GetCBORFloat(map_value); else if (key == "rp") r.dist_ewald = GetCBORFloat(map_value); else diff --git a/frame_serialize/CBORStream2Serializer.cpp b/frame_serialize/CBORStream2Serializer.cpp index 2a1012b9..dd26989d 100644 --- a/frame_serialize/CBORStream2Serializer.cpp +++ b/frame_serialize/CBORStream2Serializer.cpp @@ -243,6 +243,7 @@ inline void CBOR_ENC(CborEncoder &encoder, const Reflection& r) { CBOR_ENC(mapEncoder, "sigma", r.sigma); CBOR_ENC(mapEncoder, "image", r.image_number); CBOR_ENC(mapEncoder, "rp", r.dist_ewald); + CBOR_ENC(mapEncoder, "lp", r.lp); cborErr(cbor_encoder_close_container(&encoder, &mapEncoder)); } diff --git a/image_analysis/bragg_integration/BraggIntegrate2D.cpp b/image_analysis/bragg_integration/BraggIntegrate2D.cpp index fa6dc6b1..ad174b7a 100644 --- a/image_analysis/bragg_integration/BraggIntegrate2D.cpp +++ b/image_analysis/bragg_integration/BraggIntegrate2D.cpp @@ -63,6 +63,8 @@ void IntegrateReflection(Reflection &r, const T *image, size_t xpixel, size_t yp } } +#include + template std::vector IntegrateInternal(const DiffractionExperiment &experiment, const CompressedImage &image, @@ -100,6 +102,7 @@ std::vector IntegrateInternal(const DiffractionExperiment &experimen float two_theta = geom.TwoTheta_rad(r.predicted_x, r.predicted_y); corr *= std::sin(two_theta); } + r.lp = 1.0f / corr; r.I *= corr; r.bkg *= corr; r.sigma *= corr; diff --git a/reader/JFJochHDF5Reader.cpp b/reader/JFJochHDF5Reader.cpp index 9acbc39a..06546cbd 100644 --- a/reader/JFJochHDF5Reader.cpp +++ b/reader/JFJochHDF5Reader.cpp @@ -680,6 +680,7 @@ bool JFJochHDF5Reader::LoadImage_i(std::shared_ptr &dataset auto int_sum = source_file->ReadOptVector(image_group_name + "/int_sum"); auto int_err = source_file->ReadOptVector(image_group_name + "/int_err"); auto bkg = source_file->ReadOptVector(image_group_name + "/background_mean"); + auto lp = source_file->ReadOptVector(image_group_name + "/lp"); if (h.size() != l.size() || h.size() != k.size() || h.size() != d.size() || h.size() != predicted_x.size() || h.size() != predicted_y.size() @@ -687,6 +688,8 @@ bool JFJochHDF5Reader::LoadImage_i(std::shared_ptr &dataset throw JFJochException(JFJochExceptionCategory::HDF5, "Wrong size of reflections dataset"); for (size_t i = 0; i < h.size(); i++) { + float lp_val = 0.0; + if (lp.size() > i) lp_val = lp.at(i); Reflection r{ .h = h.at(i), .k = k.at(i), @@ -696,7 +699,8 @@ bool JFJochHDF5Reader::LoadImage_i(std::shared_ptr &dataset .d = d.at(i), .I = int_sum.at(i), .bkg = bkg.at(i), - .sigma = int_err.at(i) + .sigma = int_err.at(i), + .lp = lp_val }; message.reflections.emplace_back(r); } diff --git a/writer/HDF5DataFilePluginReflection.cpp b/writer/HDF5DataFilePluginReflection.cpp index fe9b24ca..ba6aa4d4 100644 --- a/writer/HDF5DataFilePluginReflection.cpp +++ b/writer/HDF5DataFilePluginReflection.cpp @@ -16,7 +16,7 @@ void HDF5DataFilePluginReflection::Write(const DataMessage &msg, uint64_t image_ return; std::vector h, k, l; - std::vector I, sigma, d; + std::vector I, sigma, d, lp; std::vector image, pred_x, pred_y, bkg; for (const auto &refl : msg.reflections) { @@ -30,6 +30,7 @@ void HDF5DataFilePluginReflection::Write(const DataMessage &msg, uint64_t image_ pred_x.emplace_back(refl.predicted_x); pred_y.emplace_back(refl.predicted_y); bkg.emplace_back(refl.bkg); + lp.emplace_back(refl.lp); } std::string image_group_name = fmt::format("image_{:06d}", image_number); @@ -45,6 +46,7 @@ void HDF5DataFilePluginReflection::Write(const DataMessage &msg, uint64_t image_ image_group.SaveVector("int_err", sigma); image_group.SaveVector("background_mean", bkg); image_group.SaveVector("observed_frame", image); + image_group.SaveVector("lp", lp); } void HDF5DataFilePluginReflection::WriteFinal(HDF5File &data_file) { -- 2.49.1 From c0fa5c946789f556ee67ac90462acc8d41f2df18 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Thu, 22 Jan 2026 10:06:15 +0100 Subject: [PATCH 50/96] BraggIntegrate: Lorentz-Polarization correction consistent (roughly) with XDS --- common/Reflection.h | 1 + .../bragg_integration/BraggIntegrate2D.cpp | 12 ++++++++---- .../bragg_prediction/BraggPrediction.cpp | 14 +++++++++----- .../bragg_prediction/BraggPredictionGPU.cu | 3 +++ tools/jfjoch_process.cpp | 1 + 5 files changed, 22 insertions(+), 9 deletions(-) diff --git a/common/Reflection.h b/common/Reflection.h index de877218..b15a70fe 100644 --- a/common/Reflection.h +++ b/common/Reflection.h @@ -23,6 +23,7 @@ struct Reflection { float dist_ewald; float lp; bool observed = false; + float S_x, S_y, S_z; }; #endif //JFJOCH_REFLECTION_H diff --git a/image_analysis/bragg_integration/BraggIntegrate2D.cpp b/image_analysis/bragg_integration/BraggIntegrate2D.cpp index ad174b7a..b1624dea 100644 --- a/image_analysis/bragg_integration/BraggIntegrate2D.cpp +++ b/image_analysis/bragg_integration/BraggIntegrate2D.cpp @@ -88,6 +88,11 @@ std::vector IntegrateInternal(const DiffractionExperiment &experimen const float r_2_sq = settings.GetR2() * settings.GetR2(); const float r_3_sq = settings.GetR3() * settings.GetR3(); + const Coord S0 = geom.GetScatteringVector(); + Coord m2 = Coord(0,0,0); // zero vector + if (experiment.GetGoniometer().has_value()) + m2 = experiment.GetGoniometer()->GetAxis().Normalize(); + for (int i = 0; i < npredicted; i++) { auto r = predicted.at(i); IntegrateReflection(r, ptr, image.GetWidth(), image.GetHeight(), special_value, saturation, @@ -97,11 +102,10 @@ std::vector IntegrateInternal(const DiffractionExperiment &experimen if (experiment.GetPolarizationFactor()) corr /= geom.CalcAzIntPolarizationCorr(r.predicted_x, r.predicted_y, experiment.GetPolarizationFactor().value()); + Coord S{r.S_x, r.S_y, r.S_z}; + if (experiment.GetGoniometer().has_value()) + corr *= std::fabs(m2 * (S % S0)) / (S * S0); - if (experiment.GetGoniometer().has_value()) { - float two_theta = geom.TwoTheta_rad(r.predicted_x, r.predicted_y); - corr *= std::sin(two_theta); - } r.lp = 1.0f / corr; r.I *= corr; r.bkg *= corr; diff --git a/image_analysis/bragg_prediction/BraggPrediction.cpp b/image_analysis/bragg_prediction/BraggPrediction.cpp index ab7eb892..dbc70fa0 100644 --- a/image_analysis/bragg_prediction/BraggPrediction.cpp +++ b/image_analysis/bragg_prediction/BraggPrediction.cpp @@ -35,10 +35,11 @@ int BraggPrediction::Calc(const DiffractionExperiment &experiment, const Crystal float beam_y = geom.GetBeamY_pxl(); float det_distance = geom.GetDetectorDistance_mm(); float pixel_size = geom.GetPixelSize_mm(); - float coeff_const = det_distance / pixel_size; + float F = det_distance / pixel_size; int i = 0; + for (int h = -settings.max_hkl; h <= settings.max_hkl; h++) { // Precompute A* h contribution const float Ah_x = Astar.x * h; @@ -83,9 +84,9 @@ int BraggPrediction::Calc(const DiffractionExperiment &experiment, const Crystal continue; // Project to detector coordinates - float coeff = coeff_const / S_rot_z; - float x = beam_x + S_rot_x * coeff; - float y = beam_y + S_rot_y * coeff; + // Assume detector is along x,y,z coordinates after rotation + float x = beam_x + F * S_rot_x / S_rot_z; + float y = beam_y + F * S_rot_y / S_rot_z; if ((x < 0) || (x >= det_width_pxl) || (y < 0) || (y >= det_height_pxl)) continue; @@ -98,7 +99,10 @@ int BraggPrediction::Calc(const DiffractionExperiment &experiment, const Crystal .predicted_x = x, .predicted_y = y, .d = d, - .dist_ewald = dist_ewald_sphere + .dist_ewald = dist_ewald_sphere, + .S_x = S_x, + .S_y = S_y, + .S_z = S_z }; ++i; } diff --git a/image_analysis/bragg_prediction/BraggPredictionGPU.cu b/image_analysis/bragg_prediction/BraggPredictionGPU.cu index b80563d4..0bd61286 100644 --- a/image_analysis/bragg_prediction/BraggPredictionGPU.cu +++ b/image_analysis/bragg_prediction/BraggPredictionGPU.cu @@ -81,6 +81,9 @@ namespace { out.predicted_y = y; out.d = 1.0f / sqrtf(recip_sq); out.dist_ewald = dist_ewald; + out.S_x = Sx; + out.S_y = Sy; + out.S_z = Sz; return true; } diff --git a/tools/jfjoch_process.cpp b/tools/jfjoch_process.cpp index acc3f91c..5d3634b5 100644 --- a/tools/jfjoch_process.cpp +++ b/tools/jfjoch_process.cpp @@ -133,6 +133,7 @@ int main(int argc, char **argv) { experiment.Mode(DetectorMode::Standard); // Ensure full image analysis experiment.PixelSigned(true); experiment.OverwriteExistingFiles(true); + experiment.PolarizationFactor(0.0); // Configure Indexing IndexingSettings indexing_settings; -- 2.49.1 From 6f653866e3815af70669efd2755d8aa1213febe0 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Thu, 22 Jan 2026 11:53:58 +0100 Subject: [PATCH 51/96] jfjoch_extract_hkl: Work in progress --- tools/XdsIntegrateParser.cpp | 54 +++++++++++++++++++++--------------- tools/XdsIntegrateParser.h | 6 +++- tools/jfjoch_extract_hkl.cpp | 32 +++++++++++++++------ 3 files changed, 59 insertions(+), 33 deletions(-) diff --git a/tools/XdsIntegrateParser.cpp b/tools/XdsIntegrateParser.cpp index 41a908aa..7db549be 100644 --- a/tools/XdsIntegrateParser.cpp +++ b/tools/XdsIntegrateParser.cpp @@ -26,24 +26,28 @@ IntegrateMap ParseXdsIntegrateHkl(const std::string& filename) { std::istringstream iss(line); int32_t h, k, l; double I, sigma; + double xcal, ycal, zcal, rlp, peak, corr; + int32_t maxc; - if (!(iss >> l >> k >> h >> I >> sigma)) { + if (!(iss >> l >> k >> h >> I >> sigma >> xcal >> ycal >> zcal >> rlp >> peak >> corr >> maxc)) { continue; } HKLData entry; - entry.h = h; + entry.h = -h; entry.k = k; entry.l = l; entry.I = I; entry.sigma = sigma; + entry.rlp = rlp; + entry.image_number = zcal; double v = 0.0; while (iss >> v) { entry.tail.push_back(v); } - result[hkl_key_16(h, k, l)].push_back(std::move(entry)); + result[hkl_key_16(-h, k, l)].push_back(std::move(entry)); } return result; @@ -87,30 +91,34 @@ CcHalfByResolutionResult ComputeCcByResolution( const auto& xds_list = it->second; - double i_ours = SumIntensity(ours_list); - double i_xds = SumIntensity(xds_list); + for (const auto &i_x: xds_list) { + for (const auto &i_o: ours_list) { + if (std::fabs(i_x.image_number - i_o.image_number) > 30.0) + continue; - int64_t h = ours_list.front().h; - int64_t k = ours_list.front().k; - int64_t l = ours_list.front().l; + int64_t h = i_x.h; + int64_t k = i_x.k; + int64_t l = i_x.l; - Coord recip = astar * h + bstar * k + cstar * l; - double recip_len = std::sqrt(recip.x * recip.x + recip.y * recip.y + recip.z * recip.z); - if (recip_len <= 0.0) - continue; + Coord recip = astar * h + bstar * k + cstar * l; + double recip_len = std::sqrt(recip.x * recip.x + recip.y * recip.y + recip.z * recip.z); + if (recip_len <= 0.0) + continue; - float d = static_cast(1.0 / recip_len); - auto shell = shells.GetShell(d); - if (!shell) - continue; + float d = static_cast(1.0 / recip_len); + auto shell = shells.GetShell(d); + if (!shell) + continue; - int idx = shell.value(); - n[idx] += 1; - sum_x[idx] += i_ours; - sum_y[idx] += i_xds; - sum_x2[idx] += i_ours * i_ours; - sum_y2[idx] += i_xds * i_xds; - sum_xy[idx] += i_ours * i_xds; + int idx = shell.value(); + n[idx] += 1; + sum_x[idx] += i_o.I; + sum_y[idx] += i_x.I; + sum_x2[idx] += i_o.I * i_o.I; + sum_y2[idx] += i_x.I * i_x.I; + sum_xy[idx] += i_o.I * i_x.I; + } + } } CcHalfByResolutionResult result; diff --git a/tools/XdsIntegrateParser.h b/tools/XdsIntegrateParser.h index eab0cef1..776e220b 100644 --- a/tools/XdsIntegrateParser.h +++ b/tools/XdsIntegrateParser.h @@ -31,7 +31,11 @@ struct HKLData { int64_t h ,k,l; double I = 0.0; double sigma = 0.0; - float last_image = 0; + int32_t last_image = 0; + int32_t count = 0; + float rlp = 0.0; + float image_number = -100; + std::vector tail; // any remaining numeric columns }; diff --git a/tools/jfjoch_extract_hkl.cpp b/tools/jfjoch_extract_hkl.cpp index 61310e24..da1cad4f 100644 --- a/tools/jfjoch_extract_hkl.cpp +++ b/tools/jfjoch_extract_hkl.cpp @@ -86,14 +86,18 @@ int main(int argc, char **argv) { .k = r.k, .l = r.l, .I = r.I, - .last_image = r.image_number + .last_image = i, + .count = 1, + .rlp = r.lp, + .image_number = r.image_number }; bool found = false; if (it != agg.end()) { for (auto &val: it->second) { - if (val.last_image == r.image_number - 1) { + if (val.last_image == i - 1) { val.I += r.I; - val.last_image = r.image_number; + val.last_image = i; + val.count++; found = true; break; } @@ -107,15 +111,25 @@ int main(int argc, char **argv) { std::fstream f(output_filename, std::ios::out); for (const auto &[key, val]: agg) { if (!val.empty()) { - f << val[0].h << " " << val[0].k << " " << val[0].l << " " << val[0].I; - auto xds_it = xds_result.find(key); - if (xds_it != xds_result.end() && !xds_it->second.empty()) - f << " " << xds_it->second[0].I; - f << std::endl; + + if (xds_result.empty()) { + f << val[0].h << " " << val[0].k << " " << val[0].l << " " << val[0].I; + f << std::endl; + } else { + auto xds_it = xds_result.find(key); + if (xds_it != xds_result.end() && !xds_it->second.empty()) { + f << val[0].h << " " << val[0].k << " " << val[0].l << " " << val[0].I; + + f << " " << xds_it->second[0].I << " " << 1.0/val[0].rlp << " " << xds_it->second[0].rlp; + f << std::endl; + } + } + + } } - auto cc_result = ComputeCcByResolution(latt, agg,xds_result, 1.2, 50.0, 20); + auto cc_result = ComputeCcByResolution(latt, agg,xds_result, 1.0, 50.0, 25); for (int i = 0; i < cc_result.cc.size(); ++i) std::cout << 1/ std::sqrt(cc_result.shell_mean_one_over_d2[i]) << " " << cc_result.cc[i]* 100.0 << " " << cc_result.pairs[i] << std::endl; -- 2.49.1 From 8c7bf61fa72dcb1804381ce2e4e6bb86e604608f Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Thu, 22 Jan 2026 12:03:46 +0100 Subject: [PATCH 52/96] hkl_key: Dedicated header --- common/CMakeLists.txt | 1 + common/hkl_key.h | 39 +++++++++++++++++++++++++++++++++++ tests/CMakeLists.txt | 1 + tests/HKLKeyTest.cpp | 40 ++++++++++++++++++++++++++++++++++++ tools/XdsIntegrateParser.cpp | 3 ++- tools/XdsIntegrateParser.h | 9 -------- 6 files changed, 83 insertions(+), 10 deletions(-) create mode 100644 common/hkl_key.h create mode 100644 tests/HKLKeyTest.cpp diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 6af20bf7..171cbfb4 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -121,6 +121,7 @@ ADD_LIBRARY(JFJochCommon STATIC DarkMaskSettings.h TopPixels.cpp TopPixels.h + hkl_key.h ) TARGET_LINK_LIBRARIES(JFJochCommon JFJochLogger Compression JFCalibration gemmi Threads::Threads -lrt ) diff --git a/common/hkl_key.h b/common/hkl_key.h new file mode 100644 index 00000000..fdfd4e36 --- /dev/null +++ b/common/hkl_key.h @@ -0,0 +1,39 @@ +// SPDX-FileCopyrightText: 2024 Filip Leonarski, Paul Scherrer Institute +// SPDX-License-Identifier: GPL-3.0-only + +# pragma once + +#include +#include "JFJochException.h" + +constexpr int64_t bias = 512; + +inline uint64_t encode(int64_t v) { + const int64_t tmp = v + bias; + if (tmp < 0 || tmp >= 2 * bias) + throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Value out of range"); + return static_cast(tmp); +} + +inline uint64_t hkl_key(const int64_t h, const int64_t k, const int64_t l) { + const uint64_t uh = encode(h); + const uint64_t uk = encode(k); + const uint64_t ul = encode(l); + return uh | (uk << 11) | (ul << 22); +} + +inline int64_t decode(uint64_t v) { + if (v >= 2 * bias) + throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Value out of range"); + return static_cast(v) - bias; +} + +inline void hkl_from_key(uint64_t key, int64_t& h, int64_t& k, int64_t& l) { + constexpr uint64_t mask = (1ULL << 11) - 1; + const uint64_t uh = (key >> 0) & mask; + const uint64_t uk = (key >> 11) & mask; + const uint64_t ul = (key >> 22) & mask; + h = decode(uh); + k = decode(uk); + l = decode(ul); +} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 41156158..248d7dac 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -63,6 +63,7 @@ ADD_EXECUTABLE(jfjoch_test TimeTest.cpp RotationIndexerTest.cpp TopPixelsTest.cpp + HKLKeyTest.cpp ) target_link_libraries(jfjoch_test Catch2WithMain JFJochBroker JFJochReceiver JFJochReader JFJochWriter JFJochImageAnalysis JFJochCommon JFJochHLSSimulation JFJochPreview) diff --git a/tests/HKLKeyTest.cpp b/tests/HKLKeyTest.cpp new file mode 100644 index 00000000..c147bd5e --- /dev/null +++ b/tests/HKLKeyTest.cpp @@ -0,0 +1,40 @@ +// SPDX-FileCopyrightText: 2024 Filip Leonarski, Paul Scherrer Institute +// SPDX-License-Identifier: GPL-3.0-only + +#include + +#include "../common/hkl_key.h" + +TEST_CASE("HKL key round-trip", "[hkl_key]") { + struct Case { int64_t h, k, l; }; + const Case cases[] = { + {0, 0, 0}, + {1, -2, 3}, + {-511, 0, 511}, + {512 - 1, -(512 - 1), 7}, + {-128, 255, -7} + }; + + for (const auto& c : cases) { + const uint64_t key = hkl_key(c.h, c.k, c.l); + int64_t h = 0, k = 0, l = 0; + hkl_from_key(key, h, k, l); + + CHECK(h == c.h); + CHECK(k == c.k); + CHECK(l == c.l); + } +} + +TEST_CASE("HKL key boundaries", "[hkl_key]") { + const int64_t min = -512; + const int64_t max = 511; + + const uint64_t key = hkl_key(min, 0, max); + int64_t h = 0, k = 0, l = 0; + hkl_from_key(key, h, k, l); + + CHECK(h == min); + CHECK(k == 0); + CHECK(l == max); +} \ No newline at end of file diff --git a/tools/XdsIntegrateParser.cpp b/tools/XdsIntegrateParser.cpp index 7db549be..f5f7f363 100644 --- a/tools/XdsIntegrateParser.cpp +++ b/tools/XdsIntegrateParser.cpp @@ -8,6 +8,7 @@ #include #include "../common/ResolutionShells.h" +#include "../common/hkl_key.h" IntegrateMap ParseXdsIntegrateHkl(const std::string& filename) { std::ifstream in(filename); @@ -47,7 +48,7 @@ IntegrateMap ParseXdsIntegrateHkl(const std::string& filename) { entry.tail.push_back(v); } - result[hkl_key_16(-h, k, l)].push_back(std::move(entry)); + result[hkl_key(-h, k, l)].push_back(std::move(entry)); } return result; diff --git a/tools/XdsIntegrateParser.h b/tools/XdsIntegrateParser.h index 776e220b..ea5c19f0 100644 --- a/tools/XdsIntegrateParser.h +++ b/tools/XdsIntegrateParser.h @@ -12,21 +12,12 @@ #include "../common/CrystalLattice.h" - struct CcHalfByResolutionResult { std::vector cc; std::vector pairs; std::vector shell_mean_one_over_d2; }; -inline uint64_t hkl_key_16(int64_t h, int64_t k, int64_t l) { - const uint16_t bias = 512; // maps -512..512 -> 0..1024 - uint64_t uh = static_cast(std::clamp(h + bias, int64_t(0), int64_t(1024))); - uint64_t uk = static_cast(std::clamp(k + bias, int64_t(0), int64_t(1024))); - uint64_t ul = static_cast(std::clamp(l + bias, int64_t(0), int64_t(1024))); - return uh | (uk << 16) | (ul << 32); -} - struct HKLData { int64_t h ,k,l; double I = 0.0; -- 2.49.1 From d3f311dc97c38cfcb2a3b4ef7d68b05a71e6d08e Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Thu, 22 Jan 2026 13:03:00 +0100 Subject: [PATCH 53/96] BraggPrediction: Rotation settings removed from BraggPredictionSettings --- image_analysis/IndexAndRefine.cpp | 3 +-- image_analysis/bragg_prediction/BraggPrediction.h | 6 ------ 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/image_analysis/IndexAndRefine.cpp b/image_analysis/IndexAndRefine.cpp index 4cb80433..1585685e 100644 --- a/image_analysis/IndexAndRefine.cpp +++ b/image_analysis/IndexAndRefine.cpp @@ -155,8 +155,7 @@ void IndexAndRefine::QuickPredictAndIntegrate(DataMessage &msg, .high_res_A = experiment.GetBraggIntegrationSettings().GetDMinLimit_A(), .ewald_dist_cutoff = ewald_dist_cutoff, .max_hkl = 100, - .centering = outcome.symmetry.centering, - .image_number = static_cast(-msg.number) + .centering = outcome.symmetry.centering }; auto nrefl = prediction.Calc(outcome.experiment, latt, settings_prediction); diff --git a/image_analysis/bragg_prediction/BraggPrediction.h b/image_analysis/bragg_prediction/BraggPrediction.h index 3c46bbff..75eb7116 100644 --- a/image_analysis/bragg_prediction/BraggPrediction.h +++ b/image_analysis/bragg_prediction/BraggPrediction.h @@ -15,12 +15,6 @@ struct BraggPredictionSettings { float ewald_dist_cutoff = 0.0005; int max_hkl = 100; char centering = 'P'; - - // Rotation parameters - Coord rotation_axis = Coord(1, 0, 0); - int image_number = 0; - float wedge_size_deg = 0.1f; - float mosaicity_deg = 0.1f; }; class BraggPrediction { -- 2.49.1 From 45ca48cc014dd4646beee0c2123b349d90bad518 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Thu, 22 Jan 2026 14:13:52 +0100 Subject: [PATCH 54/96] BraggPredictionRotation: New implementation - looks OK, but accuracy is terrible (+/- 10 images wrong) --- image_analysis/RotationIndexer.cpp | 13 +- image_analysis/RotationIndexer.h | 4 + .../BraggPredictionRotation.cpp | 202 +++++------------- .../BraggPredictionRotation.h | 23 +- 4 files changed, 87 insertions(+), 155 deletions(-) diff --git a/image_analysis/RotationIndexer.cpp b/image_analysis/RotationIndexer.cpp index ba0ad0a6..f3ff9372 100644 --- a/image_analysis/RotationIndexer.cpp +++ b/image_analysis/RotationIndexer.cpp @@ -6,6 +6,7 @@ #include "geom_refinement/XtalOptimizer.h" #include "indexing/FFTIndexer.h" #include "lattice_search/LatticeSearch.h" +#include RotationIndexer::RotationIndexer(const DiffractionExperiment &x, IndexerThreadPool &indexer) : experiment(x), @@ -15,7 +16,7 @@ RotationIndexer::RotationIndexer(const DiffractionExperiment &x, IndexerThreadPo updated_geom_(geom_), indexer_(indexer) { if (axis_) { - float angle_norm_deg = std::fabs(axis_->GetIncrement_deg()); + angle_norm_deg = std::fabs(axis_->GetIncrement_deg()); if (angle_norm_deg < 1e-6) { // Guard against rotation close to zero axis_ = std::nullopt; @@ -97,6 +98,12 @@ void RotationIndexer::TryIndex() { indexed_lattice = data.latt; updated_geom_ = data.geom; } + PredictionRotationSettings pred_settings{ + .high_res_A = 1.0, + .max_hkl = 100, + .centering = search_result_.centering + }; + predictions = PredictRotationHKLs(experiment, data.latt, pred_settings); } } @@ -144,3 +151,7 @@ std::optional RotationIndexer::GetLattice() { .geom = updated_geom_ }; } + +const std::vector &RotationIndexer::GetPredictions() const { + return predictions; +} diff --git a/image_analysis/RotationIndexer.h b/image_analysis/RotationIndexer.h index be6fde20..14b2efd5 100644 --- a/image_analysis/RotationIndexer.h +++ b/image_analysis/RotationIndexer.h @@ -11,6 +11,7 @@ #include "../common/DiffractionExperiment.h" #include "indexing/IndexerThreadPool.h" #include "lattice_search/LatticeSearch.h" +#include "bragg_prediction/BraggPredictionRotation.h" // RotationIndexer works as following: // 1. First accumulates spot results from rotation images (only images within a certain stride are included) @@ -33,6 +34,7 @@ class RotationIndexer { const bool index_ice_rings; bool indexing_tried = false; + float angle_norm_deg = 1.0f; std::vector v_; std::vector coords_; @@ -51,11 +53,13 @@ class RotationIndexer { std::optional indexed_lattice; + std::vector predictions; void TryIndex(); public: RotationIndexer(const DiffractionExperiment& x, IndexerThreadPool& indexer); std::optional ProcessImage(int64_t image, const std::vector& spots); std::optional GetLattice(); + const std::vector &GetPredictions() const; }; #endif //JFJOCH_ROTATIONINDEXER_H \ No newline at end of file diff --git a/image_analysis/bragg_prediction/BraggPredictionRotation.cpp b/image_analysis/bragg_prediction/BraggPredictionRotation.cpp index 5c55ded4..8ad41404 100644 --- a/image_analysis/bragg_prediction/BraggPredictionRotation.cpp +++ b/image_analysis/bragg_prediction/BraggPredictionRotation.cpp @@ -11,66 +11,11 @@ #include "../../common/JFJochException.h" #include "../bragg_integration/SystematicAbsence.h" -BraggPredictionRotation::BraggPredictionRotation(int max_reflections) - : BraggPrediction(max_reflections) {} +std::vector PredictRotationHKLs(const DiffractionExperiment &experiment, + const CrystalLattice &lattice, + const PredictionRotationSettings &settings) { + std::vector ret; -namespace { - inline float deg_to_rad(float deg) { - return deg * (static_cast(M_PI) / 180.0f); - } - inline float rad_to_deg(float rad) { - return rad * (180.0f / static_cast(M_PI)); - } - - // Solve A cos(phi) + B sin(phi) + D = 0, return solutions in [phi0, phi1] - // Returns 0..2 solutions. - inline int solve_trig(float A, float B, float D, - float phi0, float phi1, - float out_phi[2]) { - if (phi1 < phi0) std::swap(phi0, phi1); - - const float R = std::sqrt(A*A + B*B); - if (!(R > 0.0f)) - return 0; - - const float rhs = -D / R; - if (rhs < -1.0f || rhs > 1.0f) - return 0; - - const float phi_ref = std::atan2(B, A); - const float delta = std::acos(rhs); - - float s1 = phi_ref + delta; - float s2 = phi_ref - delta; - - // Shift candidates by +/- 2*pi so they land near the interval. - const float two_pi = 2.0f * static_cast(M_PI); - auto shift_near = [&](float x) { - while (x < phi0 - two_pi) x += two_pi; - while (x > phi1 + two_pi) x -= two_pi; - return x; - }; - - s1 = shift_near(s1); - s2 = shift_near(s2); - - int n = 0; - if (s1 >= phi0 && s1 <= phi1) out_phi[n++] = s1; - if (s2 >= phi0 && s2 <= phi1) { - if (n == 0 || std::fabs(s2 - out_phi[0]) > 1e-6f) out_phi[n++] = s2; - } - return n; - } - - // Convert angle to fractional image_number using goniometer start/increment - inline float phi_deg_to_image_number(float phi_deg, float start_deg, float increment_deg) { - return (phi_deg - start_deg) / increment_deg; - } -} // namespace - -int BraggPredictionRotation::Calc(const DiffractionExperiment &experiment, - const CrystalLattice &lattice, - const BraggPredictionSettings &settings) { const auto gon_opt = experiment.GetGoniometer(); if (!gon_opt.has_value()) throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, @@ -78,15 +23,12 @@ int BraggPredictionRotation::Calc(const DiffractionExperiment &experiment, const GoniometerAxis& gon = *gon_opt; const auto geom = experiment.GetDiffractionGeometry(); - const float det_width_pxl = static_cast(experiment.GetXPixelsNum()); - const float det_height_pxl = static_cast(experiment.GetYPixelsNum()); const float one_over_dmax = 1.0f / settings.high_res_A; const float one_over_dmax_sq = one_over_dmax * one_over_dmax; const float wavelength = geom.GetWavelength_A(); const float one_over_wavelength = 1.0f / wavelength; - const float one_over_wavelength_sq = one_over_wavelength * one_over_wavelength; const Coord Astar = lattice.Astar(); const Coord Bstar = lattice.Bstar(); @@ -100,128 +42,96 @@ int BraggPredictionRotation::Calc(const DiffractionExperiment &experiment, const float beam_y = geom.GetBeamY_pxl(); const float det_distance = geom.GetDetectorDistance_mm(); const float pixel_size = geom.GetPixelSize_mm(); - const float coeff_const = det_distance / pixel_size; - - // Determine prediction interval in spindle angle. - const float wedge_deg = gon.GetWedge_deg(); - - const float phi0_deg = gon.GetAngle_deg(static_cast(settings.image_number)); - const float phi1_deg = phi0_deg + wedge_deg; - - const float phi0 = deg_to_rad(phi0_deg); - const float phi1 = deg_to_rad(phi1_deg); - - // Convert mosaicity to radians (assumes settings has this field, or defaults to small value) - const float mosaicity_rad = deg_to_rad(settings.mosaicity_deg); - const float half_mosaicity = mosaicity_rad * 0.5f; + const float F = det_distance / pixel_size; const Coord m2 = gon.GetAxis().Normalize(); + const Coord m1 = (m2 % S0).Normalize(); + const Coord m3 = (m1 % m2).Normalize(); + + const float m2_S0 = m2 * S0; + const float m3_S0 = m3 * S0; int i = 0; - for (int h = -settings.max_hkl; h <= settings.max_hkl; ++h) { + for (int32_t h = -settings.max_hkl; h <= settings.max_hkl; ++h) { const float Ah_x = Astar.x * h; const float Ah_y = Astar.y * h; const float Ah_z = Astar.z * h; - for (int k = -settings.max_hkl; k <= settings.max_hkl; ++k) { + for (int32_t k = -settings.max_hkl; k <= settings.max_hkl; ++k) { const float AhBk_x = Ah_x + Bstar.x * k; const float AhBk_y = Ah_y + Bstar.y * k; const float AhBk_z = Ah_z + Bstar.z * k; - for (int l = -settings.max_hkl; l <= settings.max_hkl; ++l) { + for (int32_t l = -settings.max_hkl; l <= settings.max_hkl; ++l) { if (systematic_absence(h, k, l, settings.centering)) continue; - if (i >= max_reflections) - continue; - const float p0_x = AhBk_x + Cstar.x * l; const float p0_y = AhBk_y + Cstar.y * l; const float p0_z = AhBk_z + Cstar.z * l; - const float p0_sq = p0_x * p0_x + p0_y * p0_y + p0_z * p0_z; + const Coord p0{p0_x, p0_y, p0_z}; + + const float p0_sq = p0 * p0; if (p0_sq <= 0.0f || p0_sq > one_over_dmax_sq) continue; - const float p0_par_s = p0_x * m2.x + p0_y * m2.y + p0_z * m2.z; - const float p0_par_x = m2.x * p0_par_s; - const float p0_par_y = m2.y * p0_par_s; - const float p0_par_z = m2.z * p0_par_s; + const float p0_m1 = p0 * m1; + const float p0_m2 = p0 * m2; + const float p0_m3 = p0 * m3; - const float p0_perp_x = p0_x - p0_par_x; - const float p0_perp_y = p0_y - p0_par_y; - const float p0_perp_z = p0_z - p0_par_z; + const float rho_sq = p0_sq - (p0_m2 * p0_m2); - const float p0_perp_sq = p0_perp_x * p0_perp_x + p0_perp_y * p0_perp_y + p0_perp_z * p0_perp_z; - if (p0_perp_sq < 1e-12f) + const float p_m3 = (- p0_sq / 2 - p0_m2 * m2_S0) / m3_S0; + const float p_m2 = p0_m2; + const float p_m1_opt[2] = { + std::sqrt(rho_sq - p_m3 * p_m3), + -std::sqrt(rho_sq - p_m3 * p_m3) + }; + + // No solution for Laue equations + if ((rho_sq < p_m3 * p_m3) || (p0_sq > 4 * S0 * S0)) continue; - const float p_x = S0.x + p0_par_x; - const float p_y = S0.y + p0_par_y; - const float p_z = S0.z + p0_par_z; + for (const auto& p_m1 : p_m1_opt) { + const float cosphi = (p_m1 * p0_m1 + p_m3 * p0_m3) / rho_sq; + const float sinphi = (p_m1 * p0_m3 - p_m3 * p0_m1) / rho_sq; + Coord S = S0 + m1 * p_m1 + m2 * p_m2 + m3 * p_m3; - const float m2_x_gperp_x = m2.y * p0_perp_z - m2.z * p0_perp_y; - const float m2_x_gperp_y = m2.z * p0_perp_x - m2.x * p0_perp_z; - const float m2_x_gperp_z = m2.x * p0_perp_y - m2.y * p0_perp_x; + float phi = -1.0f * std::atan2(sinphi, cosphi) * 180.0f / M_PI; + if (phi < 0.0f) phi += 360.0f; + const float lorentz_reciprocal = std::fabs(m2 * (S % S0))/(S*S0); - // Trig equation coefficients for solving the Laue condition in φ: - // A cosφ + B sinφ + D = 0 - const float A_trig = 2.0f * (p_x * p0_perp_x + p_y * p0_perp_y + p_z * p0_perp_z); - const float B_trig = 2.0f * (p_x * m2_x_gperp_x + p_y * m2_x_gperp_y + p_z * m2_x_gperp_z); - const float D_trig = (p_x * p_x + p_y * p_y + p_z * p_z) + p0_perp_sq - one_over_wavelength_sq; - - float sols[2]{}; - const int nsol = solve_trig(A_trig, B_trig, D_trig, phi0 - half_mosaicity, phi1 + half_mosaicity, sols); - - for (int si = 0; si < nsol; ++si) { - if (i >= max_reflections) break; - - const float phi = sols[si]; - - const float cos_p = cosf(phi); - const float sin_p = sinf(phi); - - // Rodrigues' rotation formula: g = g_par + cos(phi)*g_perp + sin(phi)*(w x g_perp) - const float p_star_x = p0_par_x + cos_p * p0_perp_x + sin_p * m2_x_gperp_x; - const float p_star_y = p0_par_y + cos_p * p0_perp_y + sin_p * m2_x_gperp_y; - const float p_star_z = p0_par_z + cos_p * p0_perp_z + sin_p * m2_x_gperp_z; - - const float S_x = S0.x + p_star_x; - const float S_y = S0.y + p_star_y; - const float S_z = S0.z + p_star_z; - - // Inlined RecipToDector - const float S_rot_x = rot[0] * S_x + rot[1] * S_y + rot[2] * S_z; - const float S_rot_y = rot[3] * S_x + rot[4] * S_y + rot[5] * S_z; - const float S_rot_z = rot[6] * S_x + rot[7] * S_y + rot[8] * S_z; + // Inlined RecipToDector with rot1 and rot2 (rot3 = 0) + // Apply rotation matrix transpose + float S_rot_x = rot[0] * S.x + rot[1] * S.y + rot[2] * S.z; + float S_rot_y = rot[3] * S.x + rot[4] * S.y + rot[5] * S.z; + float S_rot_z = rot[6] * S.x + rot[7] * S.y + rot[8] * S.z; if (S_rot_z <= 0) continue; - const float coeff = coeff_const / S_rot_z; - const float x = beam_x + S_rot_x * coeff; - const float y = beam_y + S_rot_y * coeff; + float x = beam_x + F * S_rot_x / S_rot_z; + float y = beam_y + F * S_rot_y / S_rot_z; - if (x < 0.0f || x >= det_width_pxl || y < 0.0f || y >= det_height_pxl) - continue; - float dist_ewald_sphere = std::fabs(sqrtf(S_x * S_x + S_y * S_y + S_z * S_z) - one_over_wavelength); - float d = 1.0f / sqrtf(p0_sq); - const float phi_deg = rad_to_deg(phi); - reflections[i] = Reflection{ + ret.emplace_back(PredictionRotationResult{ + .angle_deg = phi, + .lorentz_reciprocal = lorentz_reciprocal, .h = h, .k = k, .l = l, - .angle_deg = phi_deg, - .predicted_x = x, - .predicted_y = y, - .d = d, - .dist_ewald = dist_ewald_sphere - }; - ++i; + .x = x, + .y = y + }); } } } } - return i; -} \ No newline at end of file + + std::ranges::sort(ret, + [](const PredictionRotationResult& a, const PredictionRotationResult& b) { + return a.angle_deg < b.angle_deg; + }); + return ret; +} diff --git a/image_analysis/bragg_prediction/BraggPredictionRotation.h b/image_analysis/bragg_prediction/BraggPredictionRotation.h index a411f3d5..40b9a607 100644 --- a/image_analysis/bragg_prediction/BraggPredictionRotation.h +++ b/image_analysis/bragg_prediction/BraggPredictionRotation.h @@ -12,15 +12,22 @@ #include "../../common/Reflection.h" #include "BraggPrediction.h" - -class BraggPredictionRotation : public BraggPrediction { -public: - BraggPredictionRotation(int max_reflections = 200*200*200); - - int Calc(const DiffractionExperiment &experiment, - const CrystalLattice &lattice, - const BraggPredictionSettings &settings) override; +struct PredictionRotationSettings { + float high_res_A; + int32_t max_hkl = 100; + char centering = 'P'; }; +struct PredictionRotationResult { + float angle_deg; + float lorentz_reciprocal; + int32_t h,k,l; + float x,y; +}; + +std::vector PredictRotationHKLs(const DiffractionExperiment &experiment, + const CrystalLattice &lattice, + const PredictionRotationSettings &settings); + #endif //JFJOCH_BRAGGPREDICTIONROTATION_H \ No newline at end of file -- 2.49.1 From 06e50b85a372a74fafad4361ac6a85183bd11e5d Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Thu, 22 Jan 2026 14:38:07 +0100 Subject: [PATCH 55/96] jfjoch_extract_hkl: Fix key --- tools/jfjoch_extract_hkl.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/jfjoch_extract_hkl.cpp b/tools/jfjoch_extract_hkl.cpp index da1cad4f..8eef84f6 100644 --- a/tools/jfjoch_extract_hkl.cpp +++ b/tools/jfjoch_extract_hkl.cpp @@ -7,6 +7,7 @@ #include "../reader/JFJochHDF5Reader.h" #include "../common/print_license.h" #include "../common/Logger.h" +#include "../common/hkl_key.h" void print_usage(Logger &logger) { logger.Info("Usage ./jfjoch_extract_hkl {} "); @@ -79,7 +80,7 @@ int main(int argc, char **argv) { if (dataset->ImageData().indexing_lattice) latt = dataset->ImageData().indexing_lattice.value(); for (const auto &r: dataset->ImageData().reflections) { - int64_t key = hkl_key_16(r.h, r.k, r.l); + int64_t key = hkl_key(r.h, r.k, r.l); auto it = agg.find(key); HKLData data{ .h = r.h, -- 2.49.1 From af3fea3e6672fb3e1d4d3b605c7722123e1c741b Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Thu, 22 Jan 2026 16:33:29 +0100 Subject: [PATCH 56/96] XtalOptimizer: Bring back standard loss function for least squares --- image_analysis/geom_refinement/XtalOptimizer.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/image_analysis/geom_refinement/XtalOptimizer.cpp b/image_analysis/geom_refinement/XtalOptimizer.cpp index 54fe8d3a..a3e6ac39 100644 --- a/image_analysis/geom_refinement/XtalOptimizer.cpp +++ b/image_analysis/geom_refinement/XtalOptimizer.cpp @@ -126,10 +126,9 @@ struct XtalResidual { auto e_pred_hkl = e_latt.transpose() * e_obs_recip; - T dh = exp_h - e_pred_hkl[0]; - T dk = exp_k - e_pred_hkl[1]; - T dl = exp_l - e_pred_hkl[2]; - residual[0] = ceres::sqrt(dh * dh + dk * dk + dl * dl); + residual[0] = exp_h - e_pred_hkl[0]; + residual[1] = exp_k - e_pred_hkl[1]; + residual[2] = exp_l - e_pred_hkl[2]; return true; } @@ -456,14 +455,14 @@ bool XtalOptimizerInternal(XtalOptimizerData &data, continue; problem.AddResidualBlock( - new ceres::AutoDiffCostFunction( + new ceres::AutoDiffCostFunction( new XtalResidual(pt.x, pt.y, data.geom.GetWavelength_A(), data.geom.GetPixelSize_mm(), gonio_back_rot, h, k, l, data.crystal_system)), - new ceres::CauchyLoss(loss_scale), + nullptr, &beam_x, &beam_y, &distance_mm, @@ -608,5 +607,6 @@ bool XtalOptimizerInternal(XtalOptimizerData &data, bool XtalOptimizer(XtalOptimizerData &data, const std::vector &spots) { if (!XtalOptimizerInternal(data, spots, 0.3)) return false; + XtalOptimizerInternal(data, spots, 0.2); return XtalOptimizerInternal(data, spots, 0.1); } -- 2.49.1 From bb87ed2df46601ea7bec15cd33ee65b948cab4ae Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Thu, 22 Jan 2026 21:20:20 +0100 Subject: [PATCH 57/96] BraggPredictionRot: Work in progress --- .../bragg_prediction/BraggPrediction.h | 1 + .../bragg_prediction/BraggPredictionRot.cpp | 140 +++++++++ .../bragg_prediction/BraggPredictionRot.h | 12 + .../bragg_prediction/BraggPredictionRotGPU.cu | 272 ++++++++++++++++++ .../bragg_prediction/BraggPredictionRotGPU.h | 48 ++++ .../bragg_prediction/CMakeLists.txt | 5 + 6 files changed, 478 insertions(+) create mode 100644 image_analysis/bragg_prediction/BraggPredictionRot.cpp create mode 100644 image_analysis/bragg_prediction/BraggPredictionRot.h create mode 100644 image_analysis/bragg_prediction/BraggPredictionRotGPU.cu create mode 100644 image_analysis/bragg_prediction/BraggPredictionRotGPU.h diff --git a/image_analysis/bragg_prediction/BraggPrediction.h b/image_analysis/bragg_prediction/BraggPrediction.h index 75eb7116..e6d54deb 100644 --- a/image_analysis/bragg_prediction/BraggPrediction.h +++ b/image_analysis/bragg_prediction/BraggPrediction.h @@ -15,6 +15,7 @@ struct BraggPredictionSettings { float ewald_dist_cutoff = 0.0005; int max_hkl = 100; char centering = 'P'; + float max_angle = 0.2f; }; class BraggPrediction { diff --git a/image_analysis/bragg_prediction/BraggPredictionRot.cpp b/image_analysis/bragg_prediction/BraggPredictionRot.cpp new file mode 100644 index 00000000..f8982c9d --- /dev/null +++ b/image_analysis/bragg_prediction/BraggPredictionRot.cpp @@ -0,0 +1,140 @@ +// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute +// SPDX-License-Identifier: GPL-3.0-only + +#include "BraggPredictionRot.h" +#include "../bragg_integration/SystematicAbsence.h" + + +int BraggPredictionRot::Calc(const DiffractionExperiment &experiment, const CrystalLattice &lattice, + const BraggPredictionSettings &settings) { + + const auto geom = experiment.GetDiffractionGeometry(); + const auto det_width_pxl = static_cast(experiment.GetXPixelsNum()); + const auto det_height_pxl = static_cast(experiment.GetYPixelsNum()); + + const float one_over_dmax = 1.0f / settings.high_res_A; + const float one_over_dmax_sq = one_over_dmax * one_over_dmax; + + float one_over_wavelength = 1.0f / geom.GetWavelength_A(); + + const Coord Astar = lattice.Astar(); + const Coord Bstar = lattice.Bstar(); + const Coord Cstar = lattice.Cstar(); + const Coord S0 = geom.GetScatteringVector(); + + std::vector rot = geom.GetPoniRotMatrix().transpose().arr(); + + // Precompute detector geometry constants + float beam_x = geom.GetBeamX_pxl(); + float beam_y = geom.GetBeamY_pxl(); + float det_distance = geom.GetDetectorDistance_mm(); + float pixel_size = geom.GetPixelSize_mm(); + float F = det_distance / pixel_size; + + const auto gon_opt = experiment.GetGoniometer(); + if (!gon_opt.has_value()) + throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, + "BraggPredictionRotationCPU requires a goniometer axis"); + const GoniometerAxis& gon = *gon_opt; + + const Coord m2 = gon.GetAxis().Normalize(); + const Coord m1 = (m2 % S0).Normalize(); + const Coord m3 = (m1 % m2).Normalize(); + + const float m2_S0 = m2 * S0; + const float m3_S0 = m3 * S0; + + int i = 0; + const float max_angle_rad = settings.max_angle * static_cast(M_PI) / 180.f; + + for (int h = -settings.max_hkl; h <= settings.max_hkl; h++) { + // Precompute A* h contribution + + for (int k = -settings.max_hkl; k <= settings.max_hkl; k++) { + // Accumulate B* k contribution + + for (int l = -settings.max_hkl; l <= settings.max_hkl; l++) { + if (systematic_absence(h, k, l, settings.centering)) + continue; + + if (i >= max_reflections) + continue; + Coord p0 = Astar * h + Bstar * k + Cstar * l; + + float p0_sq = p0 * p0; + if (p0_sq <= 0.0f || p0_sq > one_over_dmax_sq) + continue; + + const float p0_m1 = p0 * m1; + const float p0_m2 = p0 * m2; + const float p0_m3 = p0 * m3; + + const float rho_sq = p0_sq - (p0_m2 * p0_m2); + + const float p_m3 = (- p0_sq / 2 - p0_m2 * m2_S0) / m3_S0; + const float p_m2 = p0_m2; + const float p_m1_opt[2] = { + std::sqrt(rho_sq - p_m3 * p_m3), + -std::sqrt(rho_sq - p_m3 * p_m3) + }; + + // No solution for Laue equations + if ((rho_sq < p_m3 * p_m3) || (p0_sq > 4 * S0 * S0)) + continue; + + for (const auto& p_m1 : p_m1_opt) { + if (i >= max_reflections) + continue; + + const float cosphi = (p_m1 * p0_m1 + p_m3 * p0_m3) / rho_sq; + const float sinphi = (p_m1 * p0_m3 - p_m3 * p0_m1) / rho_sq; + Coord p = m1 * p_m1 + m2 * p_m2 + m3 * p_m3; // p0 vector "rotated" to diffracting condition + Coord S = S0 + p; + + float phi = -1.0f * std::atan2(sinphi, cosphi) * 180.0f / static_cast(M_PI); + + if (phi > max_angle_rad || phi < -max_angle_rad) + continue; + + const float lorentz_reciprocal = std::fabs(m2 * (S % S0))/(S*S0); + + Coord S_local = S0 + p0; + + // Inlined RecipToDector with rot1 and rot2 (rot3 = 0) + // Apply rotation matrix transpose + float S_rot_x = rot[0] * S_local.x + rot[1] * S_local.y + rot[2] * S_local.z; + float S_rot_y = rot[3] * S_local.x + rot[4] * S_local.y + rot[5] * S_local.z; + float S_rot_z = rot[6] * S_local.x + rot[7] * S_local.y + rot[8] * S_local.z; + + if (S_rot_z <= 0) + continue; + + float x = beam_x + F * S_rot_x / S_rot_z; + float y = beam_y + F * S_rot_y / S_rot_z; + + if ((x < 0) || (x >= det_width_pxl) || (y < 0) || (y >= det_height_pxl)) + continue; + + float dist_ewald_sphere = std::fabs(p0_sq - one_over_wavelength); + + float d = 1.0f / sqrtf(p0_sq); + reflections[i] = Reflection{ + .h = h, + .k = k, + .l = l, + .predicted_x = x, + .predicted_y = y, + .d = d, + .dist_ewald = dist_ewald_sphere, + .lp = lorentz_reciprocal, + .S_x = S.x, + .S_y = S.y, + .S_z = S.z + }; + i++; + } + } + } + } + return i; +} diff --git a/image_analysis/bragg_prediction/BraggPredictionRot.h b/image_analysis/bragg_prediction/BraggPredictionRot.h new file mode 100644 index 00000000..2973e76c --- /dev/null +++ b/image_analysis/bragg_prediction/BraggPredictionRot.h @@ -0,0 +1,12 @@ +// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute +// SPDX-License-Identifier: GPL-3.0-only + +#pragma once + +#include "BraggPrediction.h" + +class BraggPredictionRot : public BraggPrediction { + int Calc(const DiffractionExperiment &experiment, + const CrystalLattice &lattice, + const BraggPredictionSettings &settings) override; +}; diff --git a/image_analysis/bragg_prediction/BraggPredictionRotGPU.cu b/image_analysis/bragg_prediction/BraggPredictionRotGPU.cu new file mode 100644 index 00000000..25cfec18 --- /dev/null +++ b/image_analysis/bragg_prediction/BraggPredictionRotGPU.cu @@ -0,0 +1,272 @@ +// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute +// SPDX-License-Identifier: GPL-3.0-only + +#include "BraggPredictionRotGPU.h" + +#ifdef JFJOCH_USE_CUDA +#include "../indexing/CUDAMemHelpers.h" +#include +#include + +namespace { + __device__ inline bool is_odd(int v) { return (v & 1) != 0; } + + __device__ inline void cross3(float ax, float ay, float az, + float bx, float by, float bz, + float &cx, float &cy, float &cz) { + cx = ay * bz - az * by; + cy = az * bx - ax * bz; + cz = ax * by - ay * bx; + } + + __device__ inline float dot3(float ax, float ay, float az, + float bx, float by, float bz) { + return ax * bx + ay * by + az * bz; + } + + __device__ inline void normalize3(float &x, float &y, float &z) { + float len = sqrtf(x * x + y * y + z * z); + if (len < 1e-12f) { x = 0.0f; y = 0.0f; z = 0.0f; return; } + float inv = 1.0f / len; + x *= inv; y *= inv; z *= inv; + } + + __device__ inline bool compute_reflection_rot(const KernelConstsRot &C, int h, int k, int l, Reflection &out) { + if (h == 0 && k == 0 && l == 0) + return false; + + switch (C.centering) { + case 'I': + if (is_odd(h + k + l)) return false; + break; + case 'A': + if (is_odd(k + l)) return false; + break; + case 'B': + if (is_odd(h + l)) return false; + break; + case 'C': + if (is_odd(h + k)) return false; + break; + case 'F': + if (is_odd(h + k) || is_odd(h + l) || is_odd(k + l)) return false; + break; + case 'R': { + int mod = (-h + k + l) % 3; + if (mod < 0) mod += 3; + if (mod != 0) return false; + break; + } + default: + break; + } + + // p0 = A* h + B* k + C* l + float p0x = C.Astar.x * h + C.Bstar.x * k + C.Cstar.x * l; + float p0y = C.Astar.y * h + C.Bstar.y * k + C.Cstar.y * l; + float p0z = C.Astar.z * h + C.Bstar.z * k + C.Cstar.z * l; + + float p0_sq = p0x * p0x + p0y * p0y + p0z * p0z; + if (p0_sq <= 0.0f || p0_sq > C.one_over_dmax_sq) + return false; + + float p0_m1 = p0x * C.m1.x + p0y * C.m1.y + p0z * C.m1.z; + float p0_m2 = p0x * C.m2.x + p0y * C.m2.y + p0z * C.m2.z; + float p0_m3 = p0x * C.m3.x + p0y * C.m3.y + p0z * C.m3.z; + + float rho_sq = p0_sq - (p0_m2 * p0_m2); + float p_m3 = (-p0_sq / 2.0f - p0_m2 * C.m2_S0) / C.m3_S0; + float p_m2 = p0_m2; + + if (rho_sq < p_m3 * p_m3) return false; + if (p0_sq > 4.0f * dot3(C.S0.x, C.S0.y, C.S0.z, C.S0.x, C.S0.y, C.S0.z)) return false; + + float p_m1_pos = sqrtf(rho_sq - p_m3 * p_m3); + float p_m1_neg = -p_m1_pos; + + float p_m1_arr[2] = {p_m1_pos, p_m1_neg}; + + for (int idx = 0; idx < 2; ++idx) { + float p_m1 = p_m1_arr[idx]; + + float cosphi = (p_m1 * p0_m1 + p_m3 * p0_m3) / rho_sq; + float sinphi = (p_m1 * p0_m3 - p_m3 * p0_m1) / rho_sq; + + // p = m1*p_m1 + m2*p_m2 + m3*p_m3 + float px = C.m1.x * p_m1 + C.m2.x * p_m2 + C.m3.x * p_m3; + float py = C.m1.y * p_m1 + C.m2.y * p_m2 + C.m3.y * p_m3; + float pz = C.m1.z * p_m1 + C.m2.z * p_m2 + C.m3.z * p_m3; + + float Sx = C.S0.x + px; + float Sy = C.S0.y + py; + float Sz = C.S0.z + pz; + + float phi = -1.0f * atan2f(sinphi, cosphi) * 180.0f / static_cast(M_PI); + if (phi > C.max_angle_rad || phi < -C.max_angle_rad) + continue; + + // lorentz = |m2 . (S x S0)| / (S . S0) + float cx, cy, cz; + cross3(Sx, Sy, Sz, C.S0.x, C.S0.y, C.S0.z, cx, cy, cz); + float lorentz = fabsf(dot3(C.m2.x, C.m2.y, C.m2.z, cx, cy, cz)) / + dot3(Sx, Sy, Sz, C.S0.x, C.S0.y, C.S0.z); + + // S_local = S0 + p0 (note: p0, not p) + float Slx = C.S0.x + p0x; + float Sly = C.S0.y + p0y; + float Slz = C.S0.z + p0z; + + // Rotate to detector + float Srx = C.rot[0] * Slx + C.rot[1] * Sly + C.rot[2] * Slz; + float Sry = C.rot[3] * Slx + C.rot[4] * Sly + C.rot[5] * Slz; + float Srz = C.rot[6] * Slx + C.rot[7] * Sly + C.rot[8] * Slz; + + if (Srz <= 0.0f) continue; + + float coeff = C.coeff_const / Srz; + float x = C.beam_x + Srx * coeff; + float y = C.beam_y + Sry * coeff; + + if (x < 0.0f || x >= C.det_width_pxl || y < 0.0f || y >= C.det_height_pxl) + continue; + + float dist_ewald = fabsf(p0_sq - C.one_over_wavelength); + + out.h = h; + out.k = k; + out.l = l; + out.predicted_x = x; + out.predicted_y = y; + out.d = 1.0f / sqrtf(p0_sq); + out.dist_ewald = dist_ewald; + out.lp = lorentz; + out.S_x = Sx; + out.S_y = Sy; + out.S_z = Sz; + return true; + } + + return false; + } + + __global__ void bragg_rot_kernel_3d(const KernelConstsRot *__restrict__ kc, + int max_hkl, + int max_reflections, + Reflection *__restrict__ out, + int *__restrict__ counter) { + int range = 2 * max_hkl + 1; + int hi = blockIdx.x * blockDim.x + threadIdx.x; + int ki = blockIdx.y * blockDim.y + threadIdx.y; + int li = blockIdx.z * blockDim.z + threadIdx.z; + if (hi >= range || ki >= range || li >= range) return; + int h = hi - max_hkl; + int k = ki - max_hkl; + int l = li - max_hkl; + + Reflection r{}; + if (!compute_reflection_rot(*kc, h, k, l, r)) return; + + int pos = atomicAdd(counter, 1); + if (pos < max_reflections) out[pos] = r; + else atomicSub(counter, 1); + } + + inline KernelConstsRot BuildKernelConstsRot(const DiffractionExperiment &experiment, + const CrystalLattice &lattice, + float high_res_A, + float max_angle_deg, + char centering) { + KernelConstsRot kc{}; + auto geom = experiment.GetDiffractionGeometry(); + + kc.det_width_pxl = static_cast(experiment.GetXPixelsNum()); + kc.det_height_pxl = static_cast(experiment.GetYPixelsNum()); + kc.beam_x = geom.GetBeamX_pxl(); + kc.beam_y = geom.GetBeamY_pxl(); + kc.coeff_const = geom.GetDetectorDistance_mm() / geom.GetPixelSize_mm(); + + float one_over_dmax = 1.0f / high_res_A; + kc.one_over_dmax_sq = one_over_dmax * one_over_dmax; + kc.one_over_wavelength = 1.0f / geom.GetWavelength_A(); + kc.max_angle_rad = max_angle_deg * static_cast(M_PI) / 180.0f; + + kc.Astar = lattice.Astar(); + kc.Bstar = lattice.Bstar(); + kc.Cstar = lattice.Cstar(); + kc.S0 = geom.GetScatteringVector(); + + auto rotT = geom.GetPoniRotMatrix().transpose().arr(); + for (int i = 0; i < 9; ++i) kc.rot[i] = rotT[i]; + + kc.centering = centering; + return kc; + } + + inline void BuildGoniometerBasis(const DiffractionExperiment &experiment, KernelConstsRot &kc) { + const auto gon_opt = experiment.GetGoniometer(); + if (!gon_opt.has_value()) + throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, + "BraggPredictionRotationGPU requires a goniometer axis"); + const GoniometerAxis &gon = *gon_opt; + + // m2 = normalize(axis) + float m2x = gon.GetAxis().x; + float m2y = gon.GetAxis().y; + float m2z = gon.GetAxis().z; + normalize3(m2x, m2y, m2z); + + // m1 = normalize(m2 x S0) + float m1x, m1y, m1z; + cross3(m2x, m2y, m2z, kc.S0.x, kc.S0.y, kc.S0.z, m1x, m1y, m1z); + normalize3(m1x, m1y, m1z); + + // m3 = normalize(m1 x m2) + float m3x, m3y, m3z; + cross3(m1x, m1y, m1z, m2x, m2y, m2z, m3x, m3y, m3z); + normalize3(m3x, m3y, m3z); + + kc.m1 = Coord(m1x, m1y, m1z); + kc.m2 = Coord(m2x, m2y, m2z); + kc.m3 = Coord(m3x, m3y, m3z); + kc.m2_S0 = dot3(m2x, m2y, m2z, kc.S0.x, kc.S0.y, kc.S0.z); + kc.m3_S0 = dot3(m3x, m3y, m3z, kc.S0.x, kc.S0.y, kc.S0.z); + } +} // namespace + +BraggPredictionRotGPU::BraggPredictionRotGPU(int max_reflections) + : BraggPrediction(max_reflections), + reg_out(reflections), d_out(max_reflections), + dK(1), d_count(1), h_count(1) { +} + +int BraggPredictionRotGPU::Calc(const DiffractionExperiment &experiment, + const CrystalLattice &lattice, + const BraggPredictionSettings &settings) { + KernelConstsRot hK = BuildKernelConstsRot(experiment, lattice, settings.high_res_A, settings.max_angle, settings.centering); + BuildGoniometerBasis(experiment, hK); + + cudaMemcpyAsync(dK, &hK, sizeof(KernelConstsRot), cudaMemcpyHostToDevice, stream); + cudaMemsetAsync(d_count, 0, sizeof(int), stream); + + const int range = 2 * settings.max_hkl; + dim3 block(8, 8, 8); + dim3 grid((range + block.x - 1) / block.x, + (range + block.y - 1) / block.y, + (range + block.z - 1) / block.z); + + bragg_rot_kernel_3d<<>>(dK, settings.max_hkl, max_reflections, d_out, d_count); + + cudaMemcpyAsync(h_count, d_count, sizeof(int), cudaMemcpyDeviceToHost, stream); + cudaStreamSynchronize(stream); + + int count = *h_count.get(); + if (count > max_reflections) count = max_reflections; + if (count == 0) return 0; + + cudaMemcpyAsync(reflections.data(), d_out, sizeof(Reflection) * count, cudaMemcpyDeviceToHost, stream); + cudaStreamSynchronize(stream); + + return count; +} + +#endif \ No newline at end of file diff --git a/image_analysis/bragg_prediction/BraggPredictionRotGPU.h b/image_analysis/bragg_prediction/BraggPredictionRotGPU.h new file mode 100644 index 00000000..179a7869 --- /dev/null +++ b/image_analysis/bragg_prediction/BraggPredictionRotGPU.h @@ -0,0 +1,48 @@ +// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute +// SPDX-License-Identifier: GPL-3.0-only + + +#pragma once + +#include +#include "BraggPrediction.h" +#include "../indexing/CUDAMemHelpers.h" + +struct KernelConstsRot { + float det_width_pxl; + float det_height_pxl; + float beam_x; + float beam_y; + float coeff_const; + float one_over_wavelength; + float one_over_dmax_sq; + float max_angle_rad; + Coord Astar, Bstar, Cstar, S0; + Coord m1, m2, m3; + float m2_S0; + float m3_S0; + float rot[9]; + char centering; +}; + +class BraggPredictionRotGPU : public BraggPrediction { + CudaRegisteredVector reg_out; // requires stable storage + CudaDevicePtr d_out; + + // Dedicated stream + CudaStream stream; + + // Device allocations via helpers + CudaDevicePtr dK; + CudaDevicePtr d_count; + + // Host pinned buffer for async download (optional but faster) + CudaHostPtr h_count; + +public: + explicit BraggPredictionRotGPU(int max_reflections = 10000); + + int Calc(const DiffractionExperiment &experiment, + const CrystalLattice &lattice, + const BraggPredictionSettings &settings) override; +}; diff --git a/image_analysis/bragg_prediction/CMakeLists.txt b/image_analysis/bragg_prediction/CMakeLists.txt index 656dc783..7528ed73 100644 --- a/image_analysis/bragg_prediction/CMakeLists.txt +++ b/image_analysis/bragg_prediction/CMakeLists.txt @@ -5,6 +5,9 @@ ADD_LIBRARY(JFJochBraggPrediction STATIC BraggPredictionFactory.h BraggPredictionRotation.cpp BraggPredictionRotation.h + BraggPredictionRot.cpp + BraggPredictionRot.h + ) TARGET_LINK_LIBRARIES(JFJochBraggPrediction JFJochCommon) @@ -12,5 +15,7 @@ TARGET_LINK_LIBRARIES(JFJochBraggPrediction JFJochCommon) IF (JFJOCH_CUDA_AVAILABLE) TARGET_SOURCES(JFJochBraggPrediction PRIVATE ../indexing/CUDAMemHelpers.h + BraggPredictionRotGPU.cu + BraggPredictionRotGPU.h BraggPredictionGPU.cu BraggPredictionGPU.h) ENDIF() -- 2.49.1 From 7693b95008c6fd728008e1aa0d4dbfe50c5f6659 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Fri, 23 Jan 2026 09:38:44 +0100 Subject: [PATCH 58/96] Remove BraggPredictionRotGPU from CMake for now --- image_analysis/bragg_prediction/CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/image_analysis/bragg_prediction/CMakeLists.txt b/image_analysis/bragg_prediction/CMakeLists.txt index 7528ed73..451b55ab 100644 --- a/image_analysis/bragg_prediction/CMakeLists.txt +++ b/image_analysis/bragg_prediction/CMakeLists.txt @@ -15,7 +15,5 @@ TARGET_LINK_LIBRARIES(JFJochBraggPrediction JFJochCommon) IF (JFJOCH_CUDA_AVAILABLE) TARGET_SOURCES(JFJochBraggPrediction PRIVATE ../indexing/CUDAMemHelpers.h - BraggPredictionRotGPU.cu - BraggPredictionRotGPU.h BraggPredictionGPU.cu BraggPredictionGPU.h) ENDIF() -- 2.49.1 From b7b38b8e7d005b893793424e76ba58ce41dad088 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Fri, 23 Jan 2026 09:54:45 +0100 Subject: [PATCH 59/96] GoniometerAxis: Transformation is based on angle, not image number --- common/GoniometerAxis.cpp | 6 ++---- common/GoniometerAxis.h | 2 +- image_analysis/IndexAndRefine.cpp | 6 ++++-- image_analysis/RotationIndexer.cpp | 3 ++- image_analysis/geom_refinement/XtalOptimizer.cpp | 3 ++- tests/RotationIndexerTest.cpp | 3 ++- tests/XtalOptimizerTest.cpp | 3 ++- 7 files changed, 15 insertions(+), 11 deletions(-) diff --git a/common/GoniometerAxis.cpp b/common/GoniometerAxis.cpp index 09467618..b88d8e51 100644 --- a/common/GoniometerAxis.cpp +++ b/common/GoniometerAxis.cpp @@ -120,9 +120,7 @@ std::vector GoniometerAxis::GetAngleContainerEnd(int64_t max_image_numbe return angle_container; } -RotMatrix GoniometerAxis::GetTransformation(int64_t image_number) const { - // Transformation goes back from rotated to "start" - auto angle_deg = GetAngle_deg(image_number); +RotMatrix GoniometerAxis::GetTransformationAngle(float angle_deg) const { auto angle_rad = angle_deg / 180.0f * static_cast(M_PI); return {angle_rad, axis}; -} +} \ No newline at end of file diff --git a/common/GoniometerAxis.h b/common/GoniometerAxis.h index 9d19abeb..f644a40f 100644 --- a/common/GoniometerAxis.h +++ b/common/GoniometerAxis.h @@ -44,7 +44,7 @@ public: [[nodiscard]] std::vector GetAxisVector() const; - [[nodiscard]] RotMatrix GetTransformation(int64_t image_number) const; + [[nodiscard]] RotMatrix GetTransformationAngle(float angle_deg) const; }; diff --git a/image_analysis/IndexAndRefine.cpp b/image_analysis/IndexAndRefine.cpp index 1585685e..891c9e17 100644 --- a/image_analysis/IndexAndRefine.cpp +++ b/image_analysis/IndexAndRefine.cpp @@ -29,8 +29,10 @@ IndexAndRefine::IndexingOutcome IndexAndRefine::DetermineLatticeAndSymmetry(Data // get rotated lattice auto gon = experiment.GetGoniometer(); - if (gon) - outcome.lattice_candidate = result->lattice.Multiply(gon->GetTransformation(-msg.number)); + if (gon) { + const float angle_deg = gon->GetAngle_deg(msg.number) + gon->GetWedge_deg() / 2.0f; + outcome.lattice_candidate = result->lattice.Multiply(gon->GetTransformationAngle(-angle_deg)); + } outcome.experiment.BeamX_pxl(result->geom.GetBeamX_pxl()) .BeamY_pxl(result->geom.GetBeamY_pxl()) diff --git a/image_analysis/RotationIndexer.cpp b/image_analysis/RotationIndexer.cpp index f3ff9372..dc2c1254 100644 --- a/image_analysis/RotationIndexer.cpp +++ b/image_analysis/RotationIndexer.cpp @@ -114,7 +114,8 @@ std::optional RotationIndexer::ProcessImage(int64_t image if (!axis_) return {}; - const auto rot = axis_->GetTransformation(image); + const float angle_deg = axis_->GetAngle_deg(image) + axis_->GetWedge_deg() / 2.0f; + const auto rot = axis_->GetTransformationAngle(angle_deg); if (!indexing_tried && image >= last_accumulated_image + image_stride) { v_.reserve(v_.size() + spots.size()); diff --git a/image_analysis/geom_refinement/XtalOptimizer.cpp b/image_analysis/geom_refinement/XtalOptimizer.cpp index a3e6ac39..f1e775df 100644 --- a/image_analysis/geom_refinement/XtalOptimizer.cpp +++ b/image_analysis/geom_refinement/XtalOptimizer.cpp @@ -429,7 +429,8 @@ bool XtalOptimizerInternal(XtalOptimizerData &data, Coord recip = data.geom.DetectorToRecip(pt.x, pt.y); if (data.axis) { - auto rot = data.axis->GetTransformation(pt.image); + const float angle_deg = data.axis->GetAngle_deg(pt.image) + data.axis->GetWedge_deg() / 2.0f; + auto rot = data.axis->GetTransformationAngle(angle_deg); recip = rot * recip; Eigen::Matrix3d Rg; diff --git a/tests/RotationIndexerTest.cpp b/tests/RotationIndexerTest.cpp index 27d2be44..87f0d7b7 100644 --- a/tests/RotationIndexerTest.cpp +++ b/tests/RotationIndexerTest.cpp @@ -53,7 +53,8 @@ TEST_CASE("RotationIndexer") { for (int img = 0; img < 50; ++img) { std::vector spots; // For a rotated image, per-image lattice is obtained as Multiply(rot.transpose()) - const RotMatrix rot = axis.GetTransformation(img); + const float angle_deg = axis.GetAngle_deg(img) + axis.GetWedge_deg() / 2.0f; + const RotMatrix rot = axis.GetTransformationAngle(angle_deg); const CrystalLattice latt_img = latt_base.Multiply(rot.transpose()); const auto n = prediction.Calc(exp_i, latt_img, prediction_settings); diff --git a/tests/XtalOptimizerTest.cpp b/tests/XtalOptimizerTest.cpp index 031716c8..8503c8b0 100644 --- a/tests/XtalOptimizerTest.cpp +++ b/tests/XtalOptimizerTest.cpp @@ -576,7 +576,8 @@ TEST_CASE("XtalOptimizer_rotation") { // Predict reflections for images at 0-30 deg. for (int img = 0; img < 10; ++img) { // For a rotated image, per-image lattice is obtained as Multiply(rot.transpose()) - const RotMatrix rot = axis.GetTransformation(img); + const float angle_deg = axis.GetAngle_deg(img) + axis.GetWedge_deg() / 2.0f; + const RotMatrix rot = axis.GetTransformationAngle(angle_deg); const CrystalLattice latt_img = latt_base.Multiply(rot.transpose()); const auto n = prediction.Calc(exp_i, latt_img, prediction_settings); -- 2.49.1 From 626f7abc30d9036951e82b1dc7c9a3863ded4e63 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Tue, 27 Jan 2026 10:17:10 +0100 Subject: [PATCH 60/96] IndexAndRefine: Work in progress to understand why rotation indexing doesn't work --- image_analysis/IndexAndRefine.cpp | 12 ++++++++---- tools/jfjoch_process.cpp | 1 - 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/image_analysis/IndexAndRefine.cpp b/image_analysis/IndexAndRefine.cpp index 891c9e17..c7259e1f 100644 --- a/image_analysis/IndexAndRefine.cpp +++ b/image_analysis/IndexAndRefine.cpp @@ -35,10 +35,10 @@ IndexAndRefine::IndexingOutcome IndexAndRefine::DetermineLatticeAndSymmetry(Data } outcome.experiment.BeamX_pxl(result->geom.GetBeamX_pxl()) - .BeamY_pxl(result->geom.GetBeamY_pxl()) - .DetectorDistance_mm(result->geom.GetDetectorDistance_mm()) - .PoniRot1_rad(result->geom.GetPoniRot1_rad()) - .PoniRot2_rad(result->geom.GetPoniRot2_rad()); + .BeamY_pxl(result->geom.GetBeamY_pxl()) + .DetectorDistance_mm(result->geom.GetDetectorDistance_mm()) + .PoniRot1_rad(result->geom.GetPoniRot1_rad()) + .PoniRot2_rad(result->geom.GetPoniRot2_rad()); outcome.symmetry.centering = result->search_result.centering; outcome.symmetry.niggli_class = result->search_result.niggli_class; outcome.symmetry.crystal_system = result->search_result.system; @@ -99,9 +99,13 @@ void IndexAndRefine::RefineGeometryIfNeeded(DataMessage &msg, IndexAndRefine::In .min_spots = experiment.GetIndexingSettings().GetViableCellMinSpots(), .refine_beam_center = true, .refine_distance_mm = false, + .refine_detector_angles = false, .max_time = 0.04 // 40 ms is max allowed time for the operation }; + if (experiment.IsRotationIndexing()) + data.refine_beam_center = false; + if (outcome.symmetry.crystal_system == gemmi::CrystalSystem::Trigonal) data.crystal_system = gemmi::CrystalSystem::Hexagonal; diff --git a/tools/jfjoch_process.cpp b/tools/jfjoch_process.cpp index 5d3634b5..acc3f91c 100644 --- a/tools/jfjoch_process.cpp +++ b/tools/jfjoch_process.cpp @@ -133,7 +133,6 @@ int main(int argc, char **argv) { experiment.Mode(DetectorMode::Standard); // Ensure full image analysis experiment.PixelSigned(true); experiment.OverwriteExistingFiles(true); - experiment.PolarizationFactor(0.0); // Configure Indexing IndexingSettings indexing_settings; -- 2.49.1 From 52c3c3f91ac4cdae58361a5e1b6e679be70fbfaa Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Tue, 27 Jan 2026 14:57:29 +0100 Subject: [PATCH 61/96] XtalOptimizer: Option to refine unit cell --- .../geom_refinement/XtalOptimizer.cpp | 47 ++++++++++++------- .../geom_refinement/XtalOptimizer.h | 1 + 2 files changed, 30 insertions(+), 18 deletions(-) diff --git a/image_analysis/geom_refinement/XtalOptimizer.cpp b/image_analysis/geom_refinement/XtalOptimizer.cpp index f1e775df..ccf2eecc 100644 --- a/image_analysis/geom_refinement/XtalOptimizer.cpp +++ b/image_analysis/geom_refinement/XtalOptimizer.cpp @@ -500,25 +500,30 @@ bool XtalOptimizerInternal(XtalOptimizerData &data, } } - // Parameter bounds - // Lengths - for (int i = 0; i < 3; ++i) { - problem.SetParameterLowerBound(latt_vec1, i, data.min_length_A); - problem.SetParameterUpperBound(latt_vec1, i, data.max_length_A); - } - - if (data.crystal_system == gemmi::CrystalSystem::Monoclinic) { - const double beta_lo = std::max(1e-6, M_PI * (data.min_angle_deg / 180.0)); - const double beta_hi = std::min(M_PI - 1e-6, M_PI * (data.max_angle_deg / 180.0)); - problem.SetParameterLowerBound(latt_vec2, 0, beta_lo); - problem.SetParameterUpperBound(latt_vec2, 0, beta_hi); - } else if (data.crystal_system == gemmi::CrystalSystem::Triclinic) { - // α, β, γ bounds (radians) - const double alo = M_PI * (data.min_angle_deg / 180.0); - const double ahi = M_PI * (data.max_angle_deg / 180.0); + if (!data.refine_unit_cell) { + problem.SetParameterBlockConstant(latt_vec1); + problem.SetParameterBlockConstant(latt_vec2); + } else { + // Parameter bounds + // Lengths for (int i = 0; i < 3; ++i) { - problem.SetParameterLowerBound(latt_vec2, i, alo); - problem.SetParameterUpperBound(latt_vec2, i, ahi); + problem.SetParameterLowerBound(latt_vec1, i, data.min_length_A); + problem.SetParameterUpperBound(latt_vec1, i, data.max_length_A); + } + + if (data.crystal_system == gemmi::CrystalSystem::Monoclinic) { + const double beta_lo = std::max(1e-6, M_PI * (data.min_angle_deg / 180.0)); + const double beta_hi = std::min(M_PI - 1e-6, M_PI * (data.max_angle_deg / 180.0)); + problem.SetParameterLowerBound(latt_vec2, 0, beta_lo); + problem.SetParameterUpperBound(latt_vec2, 0, beta_hi); + } else if (data.crystal_system == gemmi::CrystalSystem::Triclinic) { + // α, β, γ bounds (radians) + const double alo = M_PI * (data.min_angle_deg / 180.0); + const double ahi = M_PI * (data.max_angle_deg / 180.0); + for (int i = 0; i < 3; ++i) { + problem.SetParameterLowerBound(latt_vec2, i, alo); + problem.SetParameterUpperBound(latt_vec2, i, ahi); + } } } @@ -545,6 +550,12 @@ bool XtalOptimizerInternal(XtalOptimizerData &data, if (data.refine_detector_angles) data.geom.PoniRot1_rad(detector_rot[0]).PoniRot2_rad(detector_rot[1]); + if (!data.refine_unit_cell) { + Coord rot_vector{static_cast(latt_vec0[0]), static_cast(latt_vec0[1]), static_cast(latt_vec0[2])}; + Coord rot_vector_norm = rot_vector.Normalize(); + std::cout << "X " << rot_vector.Length() * 180.0 / M_PI << " " << rot_vector_norm << std::endl; + } + if (data.crystal_system == gemmi::CrystalSystem::Orthorhombic) data.latt = AngleAxisAndLengthsToLattice(latt_vec0, latt_vec1, false); else if (data.crystal_system == gemmi::CrystalSystem::Tetragonal) { diff --git a/image_analysis/geom_refinement/XtalOptimizer.h b/image_analysis/geom_refinement/XtalOptimizer.h index 38c53cd3..1854459c 100644 --- a/image_analysis/geom_refinement/XtalOptimizer.h +++ b/image_analysis/geom_refinement/XtalOptimizer.h @@ -26,6 +26,7 @@ struct XtalOptimizerData { bool refine_beam_center = true; bool refine_distance_mm = false; bool refine_detector_angles = false; + bool refine_unit_cell = true; // This refines unit cell size + angles - orientation is always refined bool index_ice_rings = true; -- 2.49.1 From d1a114aa5114d6b230e49197c073ce2c1a3208a4 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Tue, 27 Jan 2026 14:57:55 +0100 Subject: [PATCH 62/96] IndexAndRefine: Don't refine unit cell when optimizing rotation result --- image_analysis/IndexAndRefine.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/image_analysis/IndexAndRefine.cpp b/image_analysis/IndexAndRefine.cpp index c7259e1f..7ce56467 100644 --- a/image_analysis/IndexAndRefine.cpp +++ b/image_analysis/IndexAndRefine.cpp @@ -103,8 +103,10 @@ void IndexAndRefine::RefineGeometryIfNeeded(DataMessage &msg, IndexAndRefine::In .max_time = 0.04 // 40 ms is max allowed time for the operation }; - if (experiment.IsRotationIndexing()) + if (experiment.IsRotationIndexing()) { data.refine_beam_center = false; + data.refine_unit_cell = false; + } if (outcome.symmetry.crystal_system == gemmi::CrystalSystem::Trigonal) data.crystal_system = gemmi::CrystalSystem::Hexagonal; -- 2.49.1 From 475ba92d011c263eb01002a872254241e800a9e9 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Tue, 27 Jan 2026 15:32:44 +0100 Subject: [PATCH 63/96] XtalOptimizer: Remove Cauchy leftovers --- image_analysis/geom_refinement/XtalOptimizer.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/image_analysis/geom_refinement/XtalOptimizer.cpp b/image_analysis/geom_refinement/XtalOptimizer.cpp index ccf2eecc..97bc986d 100644 --- a/image_analysis/geom_refinement/XtalOptimizer.cpp +++ b/image_analysis/geom_refinement/XtalOptimizer.cpp @@ -415,10 +415,6 @@ bool XtalOptimizerInternal(XtalOptimizerData &data, const float tolerance_sq = tolerance * tolerance; - // Choose robust loss function - // Cauchy is excellent for crystallography - handles both small errors and gross outliers - const double loss_scale = tolerance / 3; // Tune based on typical residual magnitude - // Add residuals for each point for (const auto &pt: spots) { if (!data.index_ice_rings && pt.ice_ring) -- 2.49.1 From a4ac885d1c3deab39c477cc7975efe5b06100c0c Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Tue, 27 Jan 2026 16:12:17 +0100 Subject: [PATCH 64/96] XtalOptimizer: Include explicit rotation axis --- .../geom_refinement/XtalOptimizer.cpp | 40 ++++++++++++------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/image_analysis/geom_refinement/XtalOptimizer.cpp b/image_analysis/geom_refinement/XtalOptimizer.cpp index 97bc986d..3ffa8b23 100644 --- a/image_analysis/geom_refinement/XtalOptimizer.cpp +++ b/image_analysis/geom_refinement/XtalOptimizer.cpp @@ -9,7 +9,8 @@ struct XtalResidual { XtalResidual(double x, double y, double lambda, double pixel_size, - const Eigen::Matrix3d &gonio_back_rot, + Coord rot_axis, + double angle_rad, double exp_h, double exp_k, double exp_l, gemmi::CrystalSystem symmetry) @@ -19,7 +20,8 @@ struct XtalResidual { exp_h(exp_h), exp_k(exp_k), exp_l(exp_l), - gonio_back_rot_(gonio_back_rot), + rot_axis(rot_axis), + angle_rad(angle_rad), symmetry(symmetry) { } @@ -59,7 +61,15 @@ struct XtalResidual { // Apply goniometer "back-to-start" rotation: // brings observed reciprocal from image orientation into reference crystal frame - Eigen::Matrix R_gonio_back = gonio_back_rot_.cast(); + T a[3]; + a[0] = T(angle_rad*rot_axis.x); + a[1] = T(angle_rad*rot_axis.y); + a[2] = T(angle_rad*rot_axis.z); + + T rot_arr[9]; + ceres::AngleAxisToRotationMatrix(a, rot_arr); + + Eigen::Matrix R_gonio_back(rot_arr); Eigen::Matrix e_obs_recip = R_gonio_back * e_obs_recip_raw; Eigen::Matrix e_pred; @@ -139,7 +149,8 @@ struct XtalResidual { const double exp_h; const double exp_k; const double exp_l; - const Eigen::Matrix3d gonio_back_rot_; + const Coord rot_axis; + const double angle_rad; gemmi::CrystalSystem symmetry; }; @@ -419,9 +430,12 @@ bool XtalOptimizerInternal(XtalOptimizerData &data, for (const auto &pt: spots) { if (!data.index_ice_rings && pt.ice_ring) continue; - + Eigen::Matrix3d gonio_back_rot = Eigen::Matrix3d::Identity(); + Coord axis = Coord(1,0,0); + float angle_rad = 0.0; + Coord recip = data.geom.DetectorToRecip(pt.x, pt.y); if (data.axis) { @@ -429,13 +443,8 @@ bool XtalOptimizerInternal(XtalOptimizerData &data, auto rot = data.axis->GetTransformationAngle(angle_deg); recip = rot * recip; - Eigen::Matrix3d Rg; - for (int i = 0; i < 3; ++i) { - for (int j = 0; j < 3; ++j) { - Rg(i, j) = static_cast(rot.arr()[i + j * 3]); - } - } - gonio_back_rot = Rg.transpose(); + angle_rad = angle_deg * M_PI / 180.0; + axis = data.axis->GetAxis(); } double h_fp = recip * vec0; @@ -456,7 +465,8 @@ bool XtalOptimizerInternal(XtalOptimizerData &data, new XtalResidual(pt.x, pt.y, data.geom.GetWavelength_A(), data.geom.GetPixelSize_mm(), - gonio_back_rot, + axis, + angle_rad, h, k, l, data.crystal_system)), nullptr, @@ -547,7 +557,9 @@ bool XtalOptimizerInternal(XtalOptimizerData &data, data.geom.PoniRot1_rad(detector_rot[0]).PoniRot2_rad(detector_rot[1]); if (!data.refine_unit_cell) { - Coord rot_vector{static_cast(latt_vec0[0]), static_cast(latt_vec0[1]), static_cast(latt_vec0[2])}; + Coord rot_vector{ + static_cast(latt_vec0[0]), static_cast(latt_vec0[1]), static_cast(latt_vec0[2]) + }; Coord rot_vector_norm = rot_vector.Normalize(); std::cout << "X " << rot_vector.Length() * 180.0 / M_PI << " " << rot_vector_norm << std::endl; } -- 2.49.1 From 5d7bc6339ac2a4f49c3838b55511bbcca88448c6 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Tue, 27 Jan 2026 16:29:44 +0100 Subject: [PATCH 65/96] XtalOptimizer: Refine rotation axis --- common/GoniometerAxis.cpp | 19 ++-- common/GoniometerAxis.h | 1 + .../geom_refinement/XtalOptimizer.cpp | 37 +++++--- .../geom_refinement/XtalOptimizer.h | 1 + tests/XtalOptimizerTest.cpp | 86 +++++++++++++++++++ 5 files changed, 127 insertions(+), 17 deletions(-) diff --git a/common/GoniometerAxis.cpp b/common/GoniometerAxis.cpp index b88d8e51..163316d9 100644 --- a/common/GoniometerAxis.cpp +++ b/common/GoniometerAxis.cpp @@ -31,6 +31,20 @@ GoniometerAxis::GoniometerAxis(const std::string& in_name, helical_step = in_helical_step; } +GoniometerAxis &GoniometerAxis::ScreeningWedge(const std::optional &input) { + screening_wedge = input; + return *this; +} + +GoniometerAxis &GoniometerAxis::Axis(const Coord &input) { + if (input.Length() == 0.0f) + throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, + "Rotation axis cannot have 0 length"); + + axis = input.Normalize(); + return *this; +} + std::string GoniometerAxis::GetName() const { return name; } @@ -97,11 +111,6 @@ std::vector GoniometerAxis::GetAngleContainer(int64_t max_image_number) return angle_container; } -GoniometerAxis &GoniometerAxis::ScreeningWedge(const std::optional &input) { - screening_wedge = input; - return *this; -} - std::optional GoniometerAxis::GetScreeningWedge() const { return screening_wedge; } diff --git a/common/GoniometerAxis.h b/common/GoniometerAxis.h index f644a40f..ecda91df 100644 --- a/common/GoniometerAxis.h +++ b/common/GoniometerAxis.h @@ -23,6 +23,7 @@ public: const Coord &axis, const std::optional &helical_step); + GoniometerAxis& Axis(const Coord &input); GoniometerAxis& ScreeningWedge(const std::optional& input); [[nodiscard]] std::string GetName() const; diff --git a/image_analysis/geom_refinement/XtalOptimizer.cpp b/image_analysis/geom_refinement/XtalOptimizer.cpp index 3ffa8b23..5e000cbd 100644 --- a/image_analysis/geom_refinement/XtalOptimizer.cpp +++ b/image_analysis/geom_refinement/XtalOptimizer.cpp @@ -9,7 +9,6 @@ struct XtalResidual { XtalResidual(double x, double y, double lambda, double pixel_size, - Coord rot_axis, double angle_rad, double exp_h, double exp_k, double exp_l, @@ -20,7 +19,6 @@ struct XtalResidual { exp_h(exp_h), exp_k(exp_k), exp_l(exp_l), - rot_axis(rot_axis), angle_rad(angle_rad), symmetry(symmetry) { } @@ -30,6 +28,7 @@ struct XtalResidual { const T *const beam_y, const T *const distance_mm, const T *const detector_rot, + const T *const rotation_axis, const T *const p0, const T *const p1, const T *const p2, @@ -61,13 +60,11 @@ struct XtalResidual { // Apply goniometer "back-to-start" rotation: // brings observed reciprocal from image orientation into reference crystal frame - T a[3]; - a[0] = T(angle_rad*rot_axis.x); - a[1] = T(angle_rad*rot_axis.y); - a[2] = T(angle_rad*rot_axis.z); - - T rot_arr[9]; - ceres::AngleAxisToRotationMatrix(a, rot_arr); + T v[3], rot_arr[9]; + v[0] = T(angle_rad) * rotation_axis[0]; + v[1] = T(angle_rad) * rotation_axis[1]; + v[2] = T(angle_rad) * rotation_axis[2]; + ceres::AngleAxisToRotationMatrix(v, rot_arr); Eigen::Matrix R_gonio_back(rot_arr); Eigen::Matrix e_obs_recip = R_gonio_back * e_obs_recip_raw; @@ -149,7 +146,6 @@ struct XtalResidual { const double exp_h; const double exp_k; const double exp_l; - const Coord rot_axis; const double angle_rad; gemmi::CrystalSystem symmetry; }; @@ -393,6 +389,8 @@ bool XtalOptimizerInternal(XtalOptimizerData &data, double latt_vec0[3], latt_vec1[3], latt_vec2[3]; + double rot_vec[3] = {1, 0, 0}; + switch (data.crystal_system) { case gemmi::CrystalSystem::Orthorhombic: LatticeToRodriguesAndLengths_GS(data.latt, latt_vec0, latt_vec1); @@ -424,6 +422,12 @@ bool XtalOptimizerInternal(XtalOptimizerData &data, break; } + if (data.axis) { + rot_vec[0] = data.axis->GetAxis().x; + rot_vec[1] = data.axis->GetAxis().y; + rot_vec[2] = data.axis->GetAxis().z; + } + const float tolerance_sq = tolerance * tolerance; // Add residuals for each point @@ -461,11 +465,10 @@ bool XtalOptimizerInternal(XtalOptimizerData &data, continue; problem.AddResidualBlock( - new ceres::AutoDiffCostFunction( + new ceres::AutoDiffCostFunction( new XtalResidual(pt.x, pt.y, data.geom.GetWavelength_A(), data.geom.GetPixelSize_mm(), - axis, angle_rad, h, k, l, data.crystal_system)), @@ -474,6 +477,7 @@ bool XtalOptimizerInternal(XtalOptimizerData &data, &beam_y, &distance_mm, detector_rot, + rot_vec, latt_vec0, latt_vec1, latt_vec2 @@ -506,6 +510,10 @@ bool XtalOptimizerInternal(XtalOptimizerData &data, } } + if (!data.refine_rotation_axis) { + problem.SetParameterBlockConstant(rot_vec); + } + if (!data.refine_unit_cell) { problem.SetParameterBlockConstant(latt_vec1); problem.SetParameterBlockConstant(latt_vec2); @@ -564,6 +572,11 @@ bool XtalOptimizerInternal(XtalOptimizerData &data, std::cout << "X " << rot_vector.Length() * 180.0 / M_PI << " " << rot_vector_norm << std::endl; } + if (data.axis && data.refine_rotation_axis) { + data.axis.value().Axis(Coord(rot_vec[0], rot_vec[1], rot_vec[2])); + std::cout << "Refined rotation axis " << rot_vec[0] << " " << rot_vec[1] << " " << rot_vec[2] << std::endl; + } + if (data.crystal_system == gemmi::CrystalSystem::Orthorhombic) data.latt = AngleAxisAndLengthsToLattice(latt_vec0, latt_vec1, false); else if (data.crystal_system == gemmi::CrystalSystem::Tetragonal) { diff --git a/image_analysis/geom_refinement/XtalOptimizer.h b/image_analysis/geom_refinement/XtalOptimizer.h index 1854459c..c78ff96f 100644 --- a/image_analysis/geom_refinement/XtalOptimizer.h +++ b/image_analysis/geom_refinement/XtalOptimizer.h @@ -27,6 +27,7 @@ struct XtalOptimizerData { bool refine_distance_mm = false; bool refine_detector_angles = false; bool refine_unit_cell = true; // This refines unit cell size + angles - orientation is always refined + bool refine_rotation_axis = false; bool index_ice_rings = true; diff --git a/tests/XtalOptimizerTest.cpp b/tests/XtalOptimizerTest.cpp index 8503c8b0..96bc42ee 100644 --- a/tests/XtalOptimizerTest.cpp +++ b/tests/XtalOptimizerTest.cpp @@ -627,3 +627,89 @@ TEST_CASE("XtalOptimizer_rotation") { CHECK(fabsf(uc_ref.beta - uc_out.beta) < 0.2f); CHECK(fabsf(uc_ref.gamma - uc_out.gamma) < 0.2f); } + +TEST_CASE("XtalOptimizer_refine_rotation_axis") { + // Geometry + DiffractionExperiment exp_i; + exp_i.IncidentEnergy_keV(WVL_1A_IN_KEV) + .BeamX_pxl(1000) + .BeamY_pxl(1000) + .PoniRot1_rad(0.01) + .PoniRot2_rad(0.02) + .DetectorDistance_mm(200); + + // Base lattice (non-pathological) + CrystalLattice latt_base(40, 50, 80, 90, 95, 90); + auto uc_ref = latt_base.GetUnitCell(); + + // Rotation axis: around X with 3 deg per image + GoniometerAxis axis("omega", 0.0f, 3.0f, Coord(1,0,0), std::nullopt); + + BraggPredictionSettings prediction_settings{ + .high_res_A = 1.5, + .ewald_dist_cutoff = 0.002 + }; + + std::vector spots; + BraggPrediction prediction; + + // Predict reflections for images at 0-30 deg. + for (int img = 0; img < 10; ++img) { + // For a rotated image, per-image lattice is obtained as Multiply(rot.transpose()) + const float angle_deg = axis.GetAngle_deg(img) + axis.GetWedge_deg() / 2.0f; + const RotMatrix rot = axis.GetTransformationAngle(angle_deg); + const CrystalLattice latt_img = latt_base.Multiply(rot.transpose()); + + const auto n = prediction.Calc(exp_i, latt_img, prediction_settings); + for (int i = 0; i < n; ++i) { + const auto& r = prediction.GetReflections().at(i); + SpotToSave s{}; + s.x = r.predicted_x; + s.y = r.predicted_y; + s.image = img; // provide image index for rotation-aware refinement + s.intensity = 1.0f; // minimal positive value + s.ice_ring = false; + s.indexed = true; + spots.push_back(s); + } + } + + // Seed slightly perturbed geometry and lattice; provide rotation axis for refinement + XtalOptimizerData xtal_opt; + xtal_opt.latt = CrystalLattice(39.7f, 50.6f, 79.6f, 90.0f, 94.5f, 90.5f); + xtal_opt.geom.BeamX_pxl(1003).BeamY_pxl(997).DetectorDistance_mm(200.0) + .PoniRot1_rad(0.01).PoniRot2_rad(0.02); + xtal_opt.crystal_system = gemmi::CrystalSystem::Monoclinic; + xtal_opt.axis = GoniometerAxis("omega", 0.0f, 3.0f, + Coord(0.8, 0.05, 0.05).Normalize(), + std::nullopt); + xtal_opt.min_spots = 200; + xtal_opt.refine_beam_center = true; + xtal_opt.refine_distance_mm = false; + xtal_opt.refine_detector_angles = false; + xtal_opt.refine_rotation_axis = true; + + auto t0 = std::chrono::high_resolution_clock::now(); + REQUIRE(XtalOptimizer(xtal_opt, spots)); + auto t1 = std::chrono::high_resolution_clock::now(); + std::cout << "XtalOptimizer (rotation 4 images) took " + << std::chrono::duration_cast(t1 - t0).count() + << " microseconds" << std::endl; + + const auto uc_out = xtal_opt.latt.GetUnitCell(); + + // Geometry checks + CHECK(fabsf(xtal_opt.geom.GetBeamX_pxl() - exp_i.GetBeamX_pxl()) < 0.2f); + CHECK(fabsf(xtal_opt.geom.GetBeamY_pxl() - exp_i.GetBeamY_pxl()) < 0.2f); + + // Lattice checks + CHECK(fabsf(uc_ref.a - uc_out.a) < 0.2f); + CHECK(fabsf(uc_ref.b - uc_out.b) < 0.2f); + CHECK(fabsf(uc_ref.c - uc_out.c) < 0.3f); + CHECK(fabsf(uc_ref.alpha - uc_out.alpha) < 0.2f); + CHECK(fabsf(uc_ref.beta - uc_out.beta) < 0.2f); + CHECK(fabsf(uc_ref.gamma - uc_out.gamma) < 0.2f); + CHECK(fabsf(xtal_opt.axis->GetAxis().x - 1.0) < 0.01f); + CHECK(fabsf(xtal_opt.axis->GetAxis().y) < 0.01f); + CHECK(fabsf(xtal_opt.axis->GetAxis().z) < 0.01f); +} \ No newline at end of file -- 2.49.1 From a3ea378494e81f2926dc5678c537c6d65abe54f1 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Tue, 27 Jan 2026 17:50:56 +0100 Subject: [PATCH 66/96] XtalOptimizer: Work in progress to find out what is wrong with rotation axis --- common/GoniometerAxis.cpp | 5 +++-- image_analysis/IndexAndRefine.cpp | 3 ++- image_analysis/RotationIndexer.cpp | 8 ++++++-- image_analysis/RotationIndexer.h | 1 + image_analysis/geom_refinement/XtalOptimizer.cpp | 12 +----------- 5 files changed, 13 insertions(+), 16 deletions(-) diff --git a/common/GoniometerAxis.cpp b/common/GoniometerAxis.cpp index 163316d9..f2e95ad7 100644 --- a/common/GoniometerAxis.cpp +++ b/common/GoniometerAxis.cpp @@ -37,10 +37,11 @@ GoniometerAxis &GoniometerAxis::ScreeningWedge(const std::optional &input } GoniometerAxis &GoniometerAxis::Axis(const Coord &input) { - if (input.Length() == 0.0f) + float len = input.Length(); + if (len == 0.0f) throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Rotation axis cannot have 0 length"); - + // increment *= len; axis = input.Normalize(); return *this; } diff --git a/image_analysis/IndexAndRefine.cpp b/image_analysis/IndexAndRefine.cpp index 7ce56467..66d57c39 100644 --- a/image_analysis/IndexAndRefine.cpp +++ b/image_analysis/IndexAndRefine.cpp @@ -38,7 +38,8 @@ IndexAndRefine::IndexingOutcome IndexAndRefine::DetermineLatticeAndSymmetry(Data .BeamY_pxl(result->geom.GetBeamY_pxl()) .DetectorDistance_mm(result->geom.GetDetectorDistance_mm()) .PoniRot1_rad(result->geom.GetPoniRot1_rad()) - .PoniRot2_rad(result->geom.GetPoniRot2_rad()); + .PoniRot2_rad(result->geom.GetPoniRot2_rad()) + .Goniometer(result->axis); outcome.symmetry.centering = result->search_result.centering; outcome.symmetry.niggli_class = result->search_result.niggli_class; outcome.symmetry.crystal_system = result->search_result.system; diff --git a/image_analysis/RotationIndexer.cpp b/image_analysis/RotationIndexer.cpp index dc2c1254..7affc00d 100644 --- a/image_analysis/RotationIndexer.cpp +++ b/image_analysis/RotationIndexer.cpp @@ -87,6 +87,7 @@ void RotationIndexer::TryIndex() { .refine_beam_center = true, .refine_distance_mm = false, .refine_detector_angles = true, + .refine_rotation_axis = true, .index_ice_rings = experiment.GetIndexingSettings().GetIndexIceRings(), .axis = axis_ }; @@ -97,6 +98,7 @@ void RotationIndexer::TryIndex() { if (XtalOptimizer(data, v_sel)) { indexed_lattice = data.latt; updated_geom_ = data.geom; + axis_ = data.axis; } PredictionRotationSettings pred_settings{ .high_res_A = 1.0, @@ -139,7 +141,8 @@ std::optional RotationIndexer::ProcessImage(int64_t image return RotationIndexerResult{ .lattice = indexed_lattice.value(), .search_result = search_result_, - .geom = updated_geom_ + .geom = updated_geom_, + .axis = axis_ }; } @@ -149,7 +152,8 @@ std::optional RotationIndexer::GetLattice() { return RotationIndexerResult{ .lattice = indexed_lattice.value(), .search_result = search_result_, - .geom = updated_geom_ + .geom = updated_geom_, + .axis = axis_ }; } diff --git a/image_analysis/RotationIndexer.h b/image_analysis/RotationIndexer.h index 14b2efd5..56d55768 100644 --- a/image_analysis/RotationIndexer.h +++ b/image_analysis/RotationIndexer.h @@ -23,6 +23,7 @@ struct RotationIndexerResult { CrystalLattice lattice; LatticeSearchResult search_result; DiffractionGeometry geom; + std::optional axis; }; class RotationIndexer { diff --git a/image_analysis/geom_refinement/XtalOptimizer.cpp b/image_analysis/geom_refinement/XtalOptimizer.cpp index 5e000cbd..c2d9b1ba 100644 --- a/image_analysis/geom_refinement/XtalOptimizer.cpp +++ b/image_analysis/geom_refinement/XtalOptimizer.cpp @@ -564,18 +564,8 @@ bool XtalOptimizerInternal(XtalOptimizerData &data, if (data.refine_detector_angles) data.geom.PoniRot1_rad(detector_rot[0]).PoniRot2_rad(detector_rot[1]); - if (!data.refine_unit_cell) { - Coord rot_vector{ - static_cast(latt_vec0[0]), static_cast(latt_vec0[1]), static_cast(latt_vec0[2]) - }; - Coord rot_vector_norm = rot_vector.Normalize(); - std::cout << "X " << rot_vector.Length() * 180.0 / M_PI << " " << rot_vector_norm << std::endl; - } - - if (data.axis && data.refine_rotation_axis) { + if (data.axis && data.refine_rotation_axis) data.axis.value().Axis(Coord(rot_vec[0], rot_vec[1], rot_vec[2])); - std::cout << "Refined rotation axis " << rot_vec[0] << " " << rot_vec[1] << " " << rot_vec[2] << std::endl; - } if (data.crystal_system == gemmi::CrystalSystem::Orthorhombic) data.latt = AngleAxisAndLengthsToLattice(latt_vec0, latt_vec1, false); -- 2.49.1 From b9f05b7bc498778f1b879f9a16275c43fde96fa6 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Tue, 27 Jan 2026 19:17:28 +0100 Subject: [PATCH 67/96] IndexAndRefine: Use optimized goniometer axis --- image_analysis/IndexAndRefine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/image_analysis/IndexAndRefine.cpp b/image_analysis/IndexAndRefine.cpp index 66d57c39..c0f9b933 100644 --- a/image_analysis/IndexAndRefine.cpp +++ b/image_analysis/IndexAndRefine.cpp @@ -28,7 +28,7 @@ IndexAndRefine::IndexingOutcome IndexAndRefine::DetermineLatticeAndSymmetry(Data if (result) { // get rotated lattice - auto gon = experiment.GetGoniometer(); + auto gon = result->axis; if (gon) { const float angle_deg = gon->GetAngle_deg(msg.number) + gon->GetWedge_deg() / 2.0f; outcome.lattice_candidate = result->lattice.Multiply(gon->GetTransformationAngle(-angle_deg)); -- 2.49.1 From 52339a7f85a16844d4a28fe391db0a1b90807a1b Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Tue, 27 Jan 2026 22:12:29 +0100 Subject: [PATCH 68/96] SimpleRotXtalOptimizer: Work in progress --- image_analysis/geom_refinement/CMakeLists.txt | 2 + .../SimpleRotXtalOptimizer.cpp | 94 +++++++++++++++++++ .../geom_refinement/SimpleRotXtalOptimizer.h | 24 +++++ 3 files changed, 120 insertions(+) create mode 100644 image_analysis/geom_refinement/SimpleRotXtalOptimizer.cpp create mode 100644 image_analysis/geom_refinement/SimpleRotXtalOptimizer.h diff --git a/image_analysis/geom_refinement/CMakeLists.txt b/image_analysis/geom_refinement/CMakeLists.txt index a81b8b54..0143b49a 100644 --- a/image_analysis/geom_refinement/CMakeLists.txt +++ b/image_analysis/geom_refinement/CMakeLists.txt @@ -6,6 +6,8 @@ ADD_LIBRARY(JFJochGeomRefinement STATIC AssignSpotsToRings.h XtalOptimizer.cpp XtalOptimizer.h + RotOptimizer.cpp + RotOptimizer.h ) TARGET_LINK_LIBRARIES(JFJochGeomRefinement Ceres::ceres Eigen3::Eigen JFJochCommon) diff --git a/image_analysis/geom_refinement/SimpleRotXtalOptimizer.cpp b/image_analysis/geom_refinement/SimpleRotXtalOptimizer.cpp new file mode 100644 index 00000000..6dfc47f4 --- /dev/null +++ b/image_analysis/geom_refinement/SimpleRotXtalOptimizer.cpp @@ -0,0 +1,94 @@ +// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute +// SPDX-License-Identifier: GPL-3.0-only + +#include "SimpleRotXtalOptimizer.h" + +#include + +static bool SimpleRotXtalOptimizerInternal( + SimpleRotXtalOptimizerData &data, + const std::vector &spots, + float tolerance) +{ + Coord vec0 = data.latt.Vec0(); + Coord vec1 = data.latt.Vec1(); + Coord vec2 = data.latt.Vec2(); + + const double tol_sq = tolerance * tolerance; + + std::vector obs; + std::vector exp; + + // Collect reflections + for (const auto &pt : spots) { + if (!data.index_ice_rings && pt.ice_ring) + continue; + + Coord recip = data.geom.DetectorToRecip(pt.x, pt.y); + + double h_fp = recip * vec0; + double k_fp = recip * vec1; + double l_fp = recip * vec2; + + double h = std::round(h_fp); + double k = std::round(k_fp); + double l = std::round(l_fp); + + double d2 = + (h - h_fp)*(h - h_fp) + + (k - k_fp)*(k - k_fp) + + (l - l_fp)*(l - l_fp); + + if (d2 > tol_sq) + continue; + + obs.emplace_back(h_fp, k_fp, l_fp); + exp.emplace_back(h, k, l); + } + + if (obs.size() < data.min_spots) + return false; + + const int N = static_cast(obs.size()); + + // Build linear system A * omega = b + Eigen::MatrixXd A(3*N, 3); + Eigen::VectorXd b(3*N); + + for (int i = 0; i < N; i++) { + const auto &h = obs[i]; + const auto &e = exp[i]; + + // Cross-product matrix of h_obs + A.row(3*i + 0) << 0.0, -h.z(), h.y(); + A.row(3*i + 1) << h.z(), 0.0, -h.x(); + A.row(3*i + 2) << -h.y(), h.x(), 0.0; + + b.segment<3>(3*i) = e - h; + } + + // Solve least squares + Eigen::Vector3d omega = A.colPivHouseholderQr().solve(b); + + // Optional sanity check + if (!omega.allFinite()) + return false; + + if (omega.norm() > 0.05) { + return false; + // > ~3 degrees — warn or reject + } + + // Apply small-angle rotation to lattice + // TODO: data.latt.RotateSmallAngle(omega); + + return true; +} + +bool SimpleRotXtalOptimizer(SimpleRotXtalOptimizerData &data, const std::vector &spots) { + + if (!SimpleRotXtalOptimizerInternal(data, spots, 0.3)) + return false; + SimpleRotXtalOptimizerInternal(data, spots, 0.2); + return SimpleRotXtalOptimizerInternal(data, spots, 0.1); +} diff --git a/image_analysis/geom_refinement/SimpleRotXtalOptimizer.h b/image_analysis/geom_refinement/SimpleRotXtalOptimizer.h new file mode 100644 index 00000000..2587e0cb --- /dev/null +++ b/image_analysis/geom_refinement/SimpleRotXtalOptimizer.h @@ -0,0 +1,24 @@ +// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute +// SPDX-License-Identifier: GPL-3.0-only + +#ifndef JFJOCH_ROTOPTIMIZER_H +#define JFJOCH_ROTOPTIMIZER_H + +#include +#include "../common/SpotToSave.h" +#include "../common/CrystalLattice.h" +#include "../common/GoniometerAxis.h" + +struct SimpleRotXtalOptimizerData { + DiffractionGeometry geom; + CrystalLattice latt; + int64_t min_spots = 8; + + bool index_ice_rings = true; + float max_time = 1.0; + double rotation[3] = {0,0,0}; +}; + +bool SimpleRotXtalOptimizer(SimpleRotXtalOptimizerData &data, const std::vector &spots); + +#endif //JFJOCH_ROTOPTIMIZER_H \ No newline at end of file -- 2.49.1 From a5e582574e6fa3459c9dbaa1e80c4c8609b89b82 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Fri, 30 Jan 2026 14:44:54 +0100 Subject: [PATCH 69/96] IndexAndRefine: Use small angle approximation for optimizing rotation data --- image_analysis/IndexAndRefine.cpp | 71 ++++++++++--------- image_analysis/geom_refinement/CMakeLists.txt | 4 +- .../SimpleRotXtalOptimizer.cpp | 56 +++++++++++---- .../geom_refinement/SimpleRotXtalOptimizer.h | 2 +- 4 files changed, 84 insertions(+), 49 deletions(-) diff --git a/image_analysis/IndexAndRefine.cpp b/image_analysis/IndexAndRefine.cpp index c0f9b933..7b182fdf 100644 --- a/image_analysis/IndexAndRefine.cpp +++ b/image_analysis/IndexAndRefine.cpp @@ -9,7 +9,7 @@ #include "indexing/AnalyzeIndexing.h" #include "indexing/FFTIndexer.h" #include "lattice_search/LatticeSearch.h" - +#include "geom_refinement/SimpleRotXtalOptimizer.h" IndexAndRefine::IndexAndRefine(const DiffractionExperiment &x, IndexerThreadPool *indexer) : index_ice_rings(x.GetIndexingSettings().GetIndexIceRings()), @@ -93,42 +93,49 @@ void IndexAndRefine::RefineGeometryIfNeeded(DataMessage &msg, IndexAndRefine::In if (!outcome.lattice_candidate) return; - XtalOptimizerData data{ - .geom = outcome.experiment.GetDiffractionGeometry(), - .latt = *outcome.lattice_candidate, - .crystal_system = outcome.symmetry.crystal_system, - .min_spots = experiment.GetIndexingSettings().GetViableCellMinSpots(), - .refine_beam_center = true, - .refine_distance_mm = false, - .refine_detector_angles = false, - .max_time = 0.04 // 40 ms is max allowed time for the operation - }; - if (experiment.IsRotationIndexing()) { - data.refine_beam_center = false; - data.refine_unit_cell = false; - } + SimpleRotXtalOptimizerData data{ + .geom = outcome.experiment.GetDiffractionGeometry(), + .latt = *outcome.lattice_candidate, + .min_spots = experiment.GetIndexingSettings().GetViableCellMinSpots(), + }; + if (SimpleRotXtalOptimizer(data, msg.spots)) { + outcome.lattice_candidate = data.latt; + } + } else { + XtalOptimizerData data{ + .geom = outcome.experiment.GetDiffractionGeometry(), + .latt = *outcome.lattice_candidate, + .crystal_system = outcome.symmetry.crystal_system, + .min_spots = experiment.GetIndexingSettings().GetViableCellMinSpots(), + .refine_beam_center = true, + .refine_distance_mm = false, + .refine_detector_angles = false, + .max_time = 0.04 // 40 ms is max allowed time for the operation + }; - if (outcome.symmetry.crystal_system == gemmi::CrystalSystem::Trigonal) - data.crystal_system = gemmi::CrystalSystem::Hexagonal; - switch (experiment.GetIndexingSettings().GetGeomRefinementAlgorithm()) { - case GeomRefinementAlgorithmEnum::None: - break; - case GeomRefinementAlgorithmEnum::BeamCenter: - if (XtalOptimizer(data, msg.spots)) { - outcome.experiment.BeamX_pxl(data.geom.GetBeamX_pxl()) - .BeamY_pxl(data.geom.GetBeamY_pxl()); - outcome.beam_center_updated = true; - } - break; - } + if (outcome.symmetry.crystal_system == gemmi::CrystalSystem::Trigonal) + data.crystal_system = gemmi::CrystalSystem::Hexagonal; - outcome.lattice_candidate = data.latt; + switch (experiment.GetIndexingSettings().GetGeomRefinementAlgorithm()) { + case GeomRefinementAlgorithmEnum::None: + break; + case GeomRefinementAlgorithmEnum::BeamCenter: + if (XtalOptimizer(data, msg.spots)) { + outcome.experiment.BeamX_pxl(data.geom.GetBeamX_pxl()) + .BeamY_pxl(data.geom.GetBeamY_pxl()); + outcome.beam_center_updated = true; + } + break; + } - if (outcome.beam_center_updated) { - msg.beam_corr_x = data.beam_corr_x; - msg.beam_corr_y = data.beam_corr_y; + outcome.lattice_candidate = data.latt; + + if (outcome.beam_center_updated) { + msg.beam_corr_x = data.beam_corr_x; + msg.beam_corr_y = data.beam_corr_y; + } } } diff --git a/image_analysis/geom_refinement/CMakeLists.txt b/image_analysis/geom_refinement/CMakeLists.txt index 0143b49a..71bdd41e 100644 --- a/image_analysis/geom_refinement/CMakeLists.txt +++ b/image_analysis/geom_refinement/CMakeLists.txt @@ -6,8 +6,8 @@ ADD_LIBRARY(JFJochGeomRefinement STATIC AssignSpotsToRings.h XtalOptimizer.cpp XtalOptimizer.h - RotOptimizer.cpp - RotOptimizer.h + SimpleRotXtalOptimizer.cpp + SimpleRotXtalOptimizer.h ) TARGET_LINK_LIBRARIES(JFJochGeomRefinement Ceres::ceres Eigen3::Eigen JFJochCommon) diff --git a/image_analysis/geom_refinement/SimpleRotXtalOptimizer.cpp b/image_analysis/geom_refinement/SimpleRotXtalOptimizer.cpp index 6dfc47f4..2b7cc017 100644 --- a/image_analysis/geom_refinement/SimpleRotXtalOptimizer.cpp +++ b/image_analysis/geom_refinement/SimpleRotXtalOptimizer.cpp @@ -8,7 +8,8 @@ static bool SimpleRotXtalOptimizerInternal( SimpleRotXtalOptimizerData &data, const std::vector &spots, - float tolerance) + float tolerance, + Eigen::Matrix3d &r_total) { Coord vec0 = data.latt.Vec0(); Coord vec1 = data.latt.Vec1(); @@ -59,10 +60,11 @@ static bool SimpleRotXtalOptimizerInternal( const auto &h = obs[i]; const auto &e = exp[i]; - // Cross-product matrix of h_obs - A.row(3*i + 0) << 0.0, -h.z(), h.y(); - A.row(3*i + 1) << h.z(), 0.0, -h.x(); - A.row(3*i + 2) << -h.y(), h.x(), 0.0; + // Cross-product matrix of h_obs: [h]× such that [h]× · ω = h × ω + // But we need ω × h = -h × ω, so use -[h]× + A.row(3*i + 0) << 0.0, h.z(), -h.y(); + A.row(3*i + 1) << -h.z(), 0.0, h.x(); + A.row(3*i + 2) << h.y(), -h.x(), 0.0; b.segment<3>(3*i) = e - h; } @@ -74,21 +76,47 @@ static bool SimpleRotXtalOptimizerInternal( if (!omega.allFinite()) return false; - if (omega.norm() > 0.05) { - return false; - // > ~3 degrees — warn or reject - } + // Apply incremental rotation and accumulate it + const double angle = omega.norm(); + Eigen::Matrix3d r_inc = Eigen::Matrix3d::Identity(); + if (angle > 0.0) + r_inc = Eigen::AngleAxisd(angle, omega / angle).toRotationMatrix(); - // Apply small-angle rotation to lattice - // TODO: data.latt.RotateSmallAngle(omega); + r_total = r_inc * r_total; + + if (angle > 0.0) { + // Build the current lattice matrix (columns = a, b, c) + Eigen::Matrix3d L; + L.col(0) = Eigen::Vector3d(vec0.x, vec0.y, vec0.z); + L.col(1) = Eigen::Vector3d(vec1.x, vec1.y, vec1.z); + L.col(2) = Eigen::Vector3d(vec2.x, vec2.y, vec2.z); + + // The HKL-space rotation R transforms: h_new = R * h_old + // This corresponds to: L_new = L_old * R^T (real-space lattice) + Eigen::Matrix3d L_new = L * r_inc.transpose(); + + data.latt = CrystalLattice( + Coord(L_new(0,0), L_new(1,0), L_new(2,0)), + Coord(L_new(0,1), L_new(1,1), L_new(2,1)), + Coord(L_new(0,2), L_new(1,2), L_new(2,2)) + ); + } return true; } bool SimpleRotXtalOptimizer(SimpleRotXtalOptimizerData &data, const std::vector &spots) { + Eigen::Matrix3d r_total = Eigen::Matrix3d::Identity(); - if (!SimpleRotXtalOptimizerInternal(data, spots, 0.3)) + if (!SimpleRotXtalOptimizerInternal(data, spots, 0.3, r_total)) return false; - SimpleRotXtalOptimizerInternal(data, spots, 0.2); - return SimpleRotXtalOptimizerInternal(data, spots, 0.1); + SimpleRotXtalOptimizerInternal(data, spots, 0.2, r_total); + const bool ok = SimpleRotXtalOptimizerInternal(data, spots, 0.1, r_total); + + Eigen::AngleAxisd aa(r_total); + data.rotation[0] = aa.axis().x(); + data.rotation[1] = aa.axis().y(); + data.rotation[2] = aa.axis().z(); + data.angle = aa.angle() * 180.0 / M_PI; + return ok; } diff --git a/image_analysis/geom_refinement/SimpleRotXtalOptimizer.h b/image_analysis/geom_refinement/SimpleRotXtalOptimizer.h index 2587e0cb..b158f8e6 100644 --- a/image_analysis/geom_refinement/SimpleRotXtalOptimizer.h +++ b/image_analysis/geom_refinement/SimpleRotXtalOptimizer.h @@ -15,8 +15,8 @@ struct SimpleRotXtalOptimizerData { int64_t min_spots = 8; bool index_ice_rings = true; - float max_time = 1.0; double rotation[3] = {0,0,0}; + double angle = 0.0; }; bool SimpleRotXtalOptimizer(SimpleRotXtalOptimizerData &data, const std::vector &spots); -- 2.49.1 From b338f8ea99276305cf294ed9936118904048e50e Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Fri, 30 Jan 2026 14:57:13 +0100 Subject: [PATCH 70/96] jfjoch_writer: Save mosaicity properly --- writer/HDF5DataFilePluginMX.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/writer/HDF5DataFilePluginMX.cpp b/writer/HDF5DataFilePluginMX.cpp index 150c9147..b5e403fd 100644 --- a/writer/HDF5DataFilePluginMX.cpp +++ b/writer/HDF5DataFilePluginMX.cpp @@ -204,7 +204,7 @@ void HDF5DataFilePluginMX::WriteFinal(HDF5File &data_file) { if (!profile_radius.empty()) data_file.SaveVector("/entry/MX/profileRadius", profile_radius.vec())->Units("Angstrom^-1"); if (!mosaicity_deg.empty()) - data_file.SaveVector("/entry/MX/mosaicity", profile_radius.vec())->Units("deg"); + data_file.SaveVector("/entry/MX/mosaicity", mosaicity_deg.vec())->Units("deg"); if (!b_factor.empty()) data_file.SaveVector("/entry/MX/bFactor", b_factor.vec())->Units("Angstrom^2"); -- 2.49.1 From e0355f356fa517838e606df52c64a5c8dbbdd1ad Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Fri, 30 Jan 2026 15:03:21 +0100 Subject: [PATCH 71/96] AnalyzeIndexing: Fix mosaicity calculation --- image_analysis/indexing/AnalyzeIndexing.cpp | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/image_analysis/indexing/AnalyzeIndexing.cpp b/image_analysis/indexing/AnalyzeIndexing.cpp index 3fa42078..51e884ff 100644 --- a/image_analysis/indexing/AnalyzeIndexing.cpp +++ b/image_analysis/indexing/AnalyzeIndexing.cpp @@ -125,8 +125,6 @@ namespace { const Coord w = axis->GetAxis().Normalize(); const Coord S0 = experiment.GetScatteringVector(); const float wedge_deg = axis->GetWedge_deg(); - const float start_deg = axis->GetStart_deg(); - const float inc_deg = axis->GetIncrement_deg(); double sum_sq = 0.0; int count = 0; @@ -135,21 +133,14 @@ namespace { if (!s.indexed) continue; - // Observed angle: use frame center - const float image_center = static_cast(s.image) + 0.5f; - const float phi_obs_deg = start_deg + inc_deg * image_center; - - // g0 at phi=0 assumption - const Coord g0 = astar * static_cast(s.h) - + bstar * static_cast(s.k) - + cstar * static_cast(s.l); + const Coord pstar = astar * static_cast(s.h) + bstar * static_cast(s.k) + cstar * static_cast(s.l); // Local solve window: +/- 1 wedge (easy/robust first try) - const auto phi_pred_deg_opt = predict_phi_deg_local(g0, S0, w, phi_obs_deg, wedge_deg); + const auto phi_pred_deg_opt = predict_phi_deg_local(pstar, S0, w, 0.0, wedge_deg); if (!phi_pred_deg_opt.has_value()) continue; - float dphi = wrap_deg_pm180(phi_obs_deg - phi_pred_deg_opt.value()); + float dphi = wrap_deg_pm180(phi_pred_deg_opt.value()); sum_sq += static_cast(dphi) * static_cast(dphi); count++; } -- 2.49.1 From 1e507c678d7d19e75059f4588a61dbd753df38be Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Fri, 30 Jan 2026 15:05:09 +0100 Subject: [PATCH 72/96] jfjoch_viewer: Display mosaicity in dataset info --- viewer/JFJochViewerDatasetInfo.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/viewer/JFJochViewerDatasetInfo.cpp b/viewer/JFJochViewerDatasetInfo.cpp index 5cb4a0e0..516cf33d 100644 --- a/viewer/JFJochViewerDatasetInfo.cpp +++ b/viewer/JFJochViewerDatasetInfo.cpp @@ -87,6 +87,7 @@ void JFJochViewerDatasetInfo::UpdateLabels() { combo_box->addItem("Indexing result", 5); combo_box->addItem("Profile radius", 6); combo_box->addItem("B-factor", 8); + combo_box->addItem("Mosaicity", 9); } for (int i = 0; i < this->dataset->roi.size(); i++) { @@ -164,6 +165,8 @@ void JFJochViewerDatasetInfo::UpdatePlot() { one_over_d2 = true; } else if (val == 8) { data = dataset->b_factor; + } else if (val == 9) { + data = dataset->mosaicity_deg; } else if (val >= 100) { int roi_index = (val - 100) / 4; -- 2.49.1 From e0ddbfa644943a2997a56f9661aa752b7f9f23d4 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Fri, 30 Jan 2026 16:16:17 +0100 Subject: [PATCH 73/96] IndexAndRefine: Use rotation method prediction for reflections --- image_analysis/IndexAndRefine.cpp | 12 +- image_analysis/MXAnalysisAfterFPGA.cpp | 2 +- image_analysis/MXAnalysisWithoutFPGA.cpp | 2 +- .../bragg_prediction/BraggPrediction.h | 2 +- .../BraggPredictionFactory.cpp | 12 +- .../bragg_prediction/BraggPredictionFactory.h | 3 +- .../bragg_prediction/BraggPredictionRot.cpp | 14 +-- .../bragg_prediction/BraggPredictionRot.h | 3 + .../bragg_prediction/BraggPredictionRotGPU.cu | 116 +++++++----------- .../bragg_prediction/BraggPredictionRotGPU.h | 2 +- .../bragg_prediction/CMakeLists.txt | 4 +- 11 files changed, 81 insertions(+), 91 deletions(-) diff --git a/image_analysis/IndexAndRefine.cpp b/image_analysis/IndexAndRefine.cpp index 7b182fdf..3a9896a1 100644 --- a/image_analysis/IndexAndRefine.cpp +++ b/image_analysis/IndexAndRefine.cpp @@ -167,11 +167,19 @@ void IndexAndRefine::QuickPredictAndIntegrate(DataMessage &msg, if (experiment.GetBraggIntegrationSettings().GetFixedProfileRadius_recipA()) ewald_dist_cutoff = experiment.GetBraggIntegrationSettings().GetFixedProfileRadius_recipA().value() * 3.0f; - BraggPredictionSettings settings_prediction{ + float max_angle_deg = 0.2f; + if (experiment.GetGoniometer().has_value()) { + max_angle_deg = experiment.GetGoniometer()->GetWedge_deg() / 2.0; + if (msg.mosaicity_deg) + max_angle_deg += msg.mosaicity_deg.value(); + } + + const BraggPredictionSettings settings_prediction{ .high_res_A = experiment.GetBraggIntegrationSettings().GetDMinLimit_A(), .ewald_dist_cutoff = ewald_dist_cutoff, .max_hkl = 100, - .centering = outcome.symmetry.centering + .centering = outcome.symmetry.centering, + .max_angle_deg = max_angle_deg }; auto nrefl = prediction.Calc(outcome.experiment, latt, settings_prediction); diff --git a/image_analysis/MXAnalysisAfterFPGA.cpp b/image_analysis/MXAnalysisAfterFPGA.cpp index 64a09c85..0d417269 100644 --- a/image_analysis/MXAnalysisAfterFPGA.cpp +++ b/image_analysis/MXAnalysisAfterFPGA.cpp @@ -28,7 +28,7 @@ double stddev(const std::vector &v) { MXAnalysisAfterFPGA::MXAnalysisAfterFPGA(const DiffractionExperiment &in_experiment, IndexAndRefine &indexer) : experiment(in_experiment), indexer(indexer), - prediction(CreateBraggPrediction()) { + prediction(CreateBraggPrediction(experiment.IsRotationIndexing())) { if (experiment.IsSpotFindingEnabled()) find_spots = true; } diff --git a/image_analysis/MXAnalysisWithoutFPGA.cpp b/image_analysis/MXAnalysisWithoutFPGA.cpp index 18c31c71..dcd9d2ac 100644 --- a/image_analysis/MXAnalysisWithoutFPGA.cpp +++ b/image_analysis/MXAnalysisWithoutFPGA.cpp @@ -24,7 +24,7 @@ MXAnalysisWithoutFPGA::MXAnalysisWithoutFPGA(const DiffractionExperiment &in_exp mask_1bit(npixels, false), spotFinder(CreateImageSpotFinder(experiment.GetXPixelsNum(), experiment.GetYPixelsNum())), indexer(in_indexer), - prediction(CreateBraggPrediction()), + prediction(CreateBraggPrediction(experiment.IsRotationIndexing())), updated_image(spotFinder->GetInputBuffer()), azint_bins(in_integration.GetBinNumber()), saturation_limit(experiment.GetSaturationLimit()), diff --git a/image_analysis/bragg_prediction/BraggPrediction.h b/image_analysis/bragg_prediction/BraggPrediction.h index e6d54deb..75d2e8a1 100644 --- a/image_analysis/bragg_prediction/BraggPrediction.h +++ b/image_analysis/bragg_prediction/BraggPrediction.h @@ -15,7 +15,7 @@ struct BraggPredictionSettings { float ewald_dist_cutoff = 0.0005; int max_hkl = 100; char centering = 'P'; - float max_angle = 0.2f; + float max_angle_deg = 0.2f; }; class BraggPrediction { diff --git a/image_analysis/bragg_prediction/BraggPredictionFactory.cpp b/image_analysis/bragg_prediction/BraggPredictionFactory.cpp index 12c03182..e908c0b9 100644 --- a/image_analysis/bragg_prediction/BraggPredictionFactory.cpp +++ b/image_analysis/bragg_prediction/BraggPredictionFactory.cpp @@ -2,17 +2,25 @@ // SPDX-License-Identifier: GPL-3.0-only #include "BraggPredictionFactory.h" + +#include "BraggPredictionRot.h" #include "BraggPredictionRotation.h" +#include "BraggPredictionRotGPU.h" #ifdef JFJOCH_USE_CUDA #include "../../common/CUDAWrapper.h" #include "BraggPredictionGPU.h" #endif -std::unique_ptr CreateBraggPrediction(int max_reflections) { +std::unique_ptr CreateBraggPrediction(bool rotation_indexing, int max_reflections) { #ifdef JFJOCH_USE_CUDA - if (get_gpu_count() > 0) + if (get_gpu_count() > 0) { + if (rotation_indexing) + return std::make_unique(max_reflections); return std::make_unique(max_reflections); + } #endif + if (rotation_indexing) + return std::make_unique(max_reflections); return std::make_unique(max_reflections); } diff --git a/image_analysis/bragg_prediction/BraggPredictionFactory.h b/image_analysis/bragg_prediction/BraggPredictionFactory.h index fb3070c3..8c5954cc 100644 --- a/image_analysis/bragg_prediction/BraggPredictionFactory.h +++ b/image_analysis/bragg_prediction/BraggPredictionFactory.h @@ -6,6 +6,7 @@ #include "BraggPrediction.h" -std::unique_ptr CreateBraggPrediction(int max_reflections = 10000); +std::unique_ptr CreateBraggPrediction(bool rotation_indexing = false, + int max_reflections = 10000); #endif //JFJOCH_BRAGGPREDICTIONFACTORY_H \ No newline at end of file diff --git a/image_analysis/bragg_prediction/BraggPredictionRot.cpp b/image_analysis/bragg_prediction/BraggPredictionRot.cpp index f8982c9d..b202efaf 100644 --- a/image_analysis/bragg_prediction/BraggPredictionRot.cpp +++ b/image_analysis/bragg_prediction/BraggPredictionRot.cpp @@ -45,7 +45,7 @@ int BraggPredictionRot::Calc(const DiffractionExperiment &experiment, const Crys const float m3_S0 = m3 * S0; int i = 0; - const float max_angle_rad = settings.max_angle * static_cast(M_PI) / 180.f; + const float max_angle_rad = settings.max_angle_deg * static_cast(M_PI) / 180.f; for (int h = -settings.max_hkl; h <= settings.max_hkl; h++) { // Precompute A* h contribution @@ -91,20 +91,18 @@ int BraggPredictionRot::Calc(const DiffractionExperiment &experiment, const Crys Coord p = m1 * p_m1 + m2 * p_m2 + m3 * p_m3; // p0 vector "rotated" to diffracting condition Coord S = S0 + p; - float phi = -1.0f * std::atan2(sinphi, cosphi) * 180.0f / static_cast(M_PI); + float phi = -1.0f * std::atan2(sinphi, cosphi); if (phi > max_angle_rad || phi < -max_angle_rad) continue; const float lorentz_reciprocal = std::fabs(m2 * (S % S0))/(S*S0); - Coord S_local = S0 + p0; - // Inlined RecipToDector with rot1 and rot2 (rot3 = 0) // Apply rotation matrix transpose - float S_rot_x = rot[0] * S_local.x + rot[1] * S_local.y + rot[2] * S_local.z; - float S_rot_y = rot[3] * S_local.x + rot[4] * S_local.y + rot[5] * S_local.z; - float S_rot_z = rot[6] * S_local.x + rot[7] * S_local.y + rot[8] * S_local.z; + float S_rot_x = rot[0] * S.x + rot[1] * S.y + rot[2] * S.z; + float S_rot_y = rot[3] * S.x + rot[4] * S.y + rot[5] * S.z; + float S_rot_z = rot[6] * S.x + rot[7] * S.y + rot[8] * S.z; if (S_rot_z <= 0) continue; @@ -115,7 +113,7 @@ int BraggPredictionRot::Calc(const DiffractionExperiment &experiment, const Crys if ((x < 0) || (x >= det_width_pxl) || (y < 0) || (y >= det_height_pxl)) continue; - float dist_ewald_sphere = std::fabs(p0_sq - one_over_wavelength); + float dist_ewald_sphere = std::fabs(S.Length() - one_over_wavelength); float d = 1.0f / sqrtf(p0_sq); reflections[i] = Reflection{ diff --git a/image_analysis/bragg_prediction/BraggPredictionRot.h b/image_analysis/bragg_prediction/BraggPredictionRot.h index 2973e76c..9f4e36ae 100644 --- a/image_analysis/bragg_prediction/BraggPredictionRot.h +++ b/image_analysis/bragg_prediction/BraggPredictionRot.h @@ -6,6 +6,9 @@ #include "BraggPrediction.h" class BraggPredictionRot : public BraggPrediction { +public: + explicit BraggPredictionRot(int max_reflections = 10000) : BraggPrediction(max_reflections) {} + int Calc(const DiffractionExperiment &experiment, const CrystalLattice &lattice, const BraggPredictionSettings &settings) override; diff --git a/image_analysis/bragg_prediction/BraggPredictionRotGPU.cu b/image_analysis/bragg_prediction/BraggPredictionRotGPU.cu index 25cfec18..b9850b44 100644 --- a/image_analysis/bragg_prediction/BraggPredictionRotGPU.cu +++ b/image_analysis/bragg_prediction/BraggPredictionRotGPU.cu @@ -9,9 +9,9 @@ #include namespace { - __device__ inline bool is_odd(int v) { return (v & 1) != 0; } + __host__ __device__ inline bool is_odd(int v) { return (v & 1) != 0; } - __device__ inline void cross3(float ax, float ay, float az, + __host__ __device__ inline void cross3(float ax, float ay, float az, float bx, float by, float bz, float &cx, float &cy, float &cz) { cx = ay * bz - az * by; @@ -19,47 +19,23 @@ namespace { cz = ax * by - ay * bx; } - __device__ inline float dot3(float ax, float ay, float az, + __host__ __device__ inline float dot3(float ax, float ay, float az, float bx, float by, float bz) { return ax * bx + ay * by + az * bz; } - __device__ inline void normalize3(float &x, float &y, float &z) { + __host__ __device__ inline void normalize3(float &x, float &y, float &z) { float len = sqrtf(x * x + y * y + z * z); if (len < 1e-12f) { x = 0.0f; y = 0.0f; z = 0.0f; return; } float inv = 1.0f / len; x *= inv; y *= inv; z *= inv; } - __device__ inline bool compute_reflection_rot(const KernelConstsRot &C, int h, int k, int l, Reflection &out) { + __device__ inline int compute_reflections_rot(const KernelConstsRot &C, int h, int k, int l, Reflection out[2]) { if (h == 0 && k == 0 && l == 0) - return false; + return 0; - switch (C.centering) { - case 'I': - if (is_odd(h + k + l)) return false; - break; - case 'A': - if (is_odd(k + l)) return false; - break; - case 'B': - if (is_odd(h + l)) return false; - break; - case 'C': - if (is_odd(h + k)) return false; - break; - case 'F': - if (is_odd(h + k) || is_odd(h + l) || is_odd(k + l)) return false; - break; - case 'R': { - int mod = (-h + k + l) % 3; - if (mod < 0) mod += 3; - if (mod != 0) return false; - break; - } - default: - break; - } + // ... systematic absences unchanged ... // p0 = A* h + B* k + C* l float p0x = C.Astar.x * h + C.Bstar.x * k + C.Cstar.x * l; @@ -68,7 +44,7 @@ namespace { float p0_sq = p0x * p0x + p0y * p0y + p0z * p0z; if (p0_sq <= 0.0f || p0_sq > C.one_over_dmax_sq) - return false; + return 0; float p0_m1 = p0x * C.m1.x + p0y * C.m1.y + p0z * C.m1.z; float p0_m2 = p0x * C.m2.x + p0y * C.m2.y + p0z * C.m2.z; @@ -78,21 +54,19 @@ namespace { float p_m3 = (-p0_sq / 2.0f - p0_m2 * C.m2_S0) / C.m3_S0; float p_m2 = p0_m2; - if (rho_sq < p_m3 * p_m3) return false; - if (p0_sq > 4.0f * dot3(C.S0.x, C.S0.y, C.S0.z, C.S0.x, C.S0.y, C.S0.z)) return false; + if (rho_sq < p_m3 * p_m3) return 0; + if (p0_sq > 4.0f * dot3(C.S0.x, C.S0.y, C.S0.z, C.S0.x, C.S0.y, C.S0.z)) return 0; float p_m1_pos = sqrtf(rho_sq - p_m3 * p_m3); - float p_m1_neg = -p_m1_pos; - - float p_m1_arr[2] = {p_m1_pos, p_m1_neg}; + float p_m1_arr[2] = {p_m1_pos, -p_m1_pos}; + int count = 0; for (int idx = 0; idx < 2; ++idx) { float p_m1 = p_m1_arr[idx]; float cosphi = (p_m1 * p0_m1 + p_m3 * p0_m3) / rho_sq; float sinphi = (p_m1 * p0_m3 - p_m3 * p0_m1) / rho_sq; - // p = m1*p_m1 + m2*p_m2 + m3*p_m3 float px = C.m1.x * p_m1 + C.m2.x * p_m2 + C.m3.x * p_m3; float py = C.m1.y * p_m1 + C.m2.y * p_m2 + C.m3.y * p_m3; float pz = C.m1.z * p_m1 + C.m2.z * p_m2 + C.m3.z * p_m3; @@ -102,24 +76,18 @@ namespace { float Sz = C.S0.z + pz; float phi = -1.0f * atan2f(sinphi, cosphi) * 180.0f / static_cast(M_PI); - if (phi > C.max_angle_rad || phi < -C.max_angle_rad) + if (phi > C.max_angle_deg || phi < -C.max_angle_deg) continue; - // lorentz = |m2 . (S x S0)| / (S . S0) float cx, cy, cz; cross3(Sx, Sy, Sz, C.S0.x, C.S0.y, C.S0.z, cx, cy, cz); float lorentz = fabsf(dot3(C.m2.x, C.m2.y, C.m2.z, cx, cy, cz)) / dot3(Sx, Sy, Sz, C.S0.x, C.S0.y, C.S0.z); - // S_local = S0 + p0 (note: p0, not p) - float Slx = C.S0.x + p0x; - float Sly = C.S0.y + p0y; - float Slz = C.S0.z + p0z; - - // Rotate to detector - float Srx = C.rot[0] * Slx + C.rot[1] * Sly + C.rot[2] * Slz; - float Sry = C.rot[3] * Slx + C.rot[4] * Sly + C.rot[5] * Slz; - float Srz = C.rot[6] * Slx + C.rot[7] * Sly + C.rot[8] * Slz; + // Use S (rotated) for projection + float Srx = C.rot[0] * Sx + C.rot[1] * Sy + C.rot[2] * Sz; + float Sry = C.rot[3] * Sx + C.rot[4] * Sy + C.rot[5] * Sz; + float Srz = C.rot[6] * Sx + C.rot[7] * Sy + C.rot[8] * Sz; if (Srz <= 0.0f) continue; @@ -130,23 +98,22 @@ namespace { if (x < 0.0f || x >= C.det_width_pxl || y < 0.0f || y >= C.det_height_pxl) continue; - float dist_ewald = fabsf(p0_sq - C.one_over_wavelength); + float dist_ewald = fabsf(sqrtf(Sx * Sx + Sy * Sy + Sz * Sz) - C.one_over_wavelength); - out.h = h; - out.k = k; - out.l = l; - out.predicted_x = x; - out.predicted_y = y; - out.d = 1.0f / sqrtf(p0_sq); - out.dist_ewald = dist_ewald; - out.lp = lorentz; - out.S_x = Sx; - out.S_y = Sy; - out.S_z = Sz; - return true; + out[count].h = h; + out[count].k = k; + out[count].l = l; + out[count].predicted_x = x; + out[count].predicted_y = y; + out[count].d = 1.0f / sqrtf(p0_sq); + out[count].dist_ewald = dist_ewald; + out[count].lp = lorentz; + out[count].S_x = Sx; + out[count].S_y = Sy; + out[count].S_z = Sz; + count++; } - - return false; + return count; } __global__ void bragg_rot_kernel_3d(const KernelConstsRot *__restrict__ kc, @@ -163,12 +130,16 @@ namespace { int k = ki - max_hkl; int l = li - max_hkl; - Reflection r{}; - if (!compute_reflection_rot(*kc, h, k, l, r)) return; + Reflection r[2]; + int n = compute_reflections_rot(*kc, h, k, l, r); - int pos = atomicAdd(counter, 1); - if (pos < max_reflections) out[pos] = r; - else atomicSub(counter, 1); + for (int i = 0; i < n; ++i) { + int pos = atomicAdd(counter, 1); + if (pos < max_reflections) + out[pos] = r[i]; + else + atomicSub(counter, 1); + } } inline KernelConstsRot BuildKernelConstsRot(const DiffractionExperiment &experiment, @@ -188,7 +159,7 @@ namespace { float one_over_dmax = 1.0f / high_res_A; kc.one_over_dmax_sq = one_over_dmax * one_over_dmax; kc.one_over_wavelength = 1.0f / geom.GetWavelength_A(); - kc.max_angle_rad = max_angle_deg * static_cast(M_PI) / 180.0f; + kc.max_angle_deg = max_angle_deg; kc.Astar = lattice.Astar(); kc.Bstar = lattice.Bstar(); @@ -242,7 +213,8 @@ BraggPredictionRotGPU::BraggPredictionRotGPU(int max_reflections) int BraggPredictionRotGPU::Calc(const DiffractionExperiment &experiment, const CrystalLattice &lattice, const BraggPredictionSettings &settings) { - KernelConstsRot hK = BuildKernelConstsRot(experiment, lattice, settings.high_res_A, settings.max_angle, settings.centering); + KernelConstsRot hK = BuildKernelConstsRot(experiment, lattice, settings.high_res_A, settings.max_angle_deg, + settings.centering); BuildGoniometerBasis(experiment, hK); cudaMemcpyAsync(dK, &hK, sizeof(KernelConstsRot), cudaMemcpyHostToDevice, stream); @@ -269,4 +241,4 @@ int BraggPredictionRotGPU::Calc(const DiffractionExperiment &experiment, return count; } -#endif \ No newline at end of file +#endif diff --git a/image_analysis/bragg_prediction/BraggPredictionRotGPU.h b/image_analysis/bragg_prediction/BraggPredictionRotGPU.h index 179a7869..77656de4 100644 --- a/image_analysis/bragg_prediction/BraggPredictionRotGPU.h +++ b/image_analysis/bragg_prediction/BraggPredictionRotGPU.h @@ -16,7 +16,7 @@ struct KernelConstsRot { float coeff_const; float one_over_wavelength; float one_over_dmax_sq; - float max_angle_rad; + float max_angle_deg; Coord Astar, Bstar, Cstar, S0; Coord m1, m2, m3; float m2_S0; diff --git a/image_analysis/bragg_prediction/CMakeLists.txt b/image_analysis/bragg_prediction/CMakeLists.txt index 451b55ab..105db943 100644 --- a/image_analysis/bragg_prediction/CMakeLists.txt +++ b/image_analysis/bragg_prediction/CMakeLists.txt @@ -7,7 +7,6 @@ ADD_LIBRARY(JFJochBraggPrediction STATIC BraggPredictionRotation.h BraggPredictionRot.cpp BraggPredictionRot.h - ) TARGET_LINK_LIBRARIES(JFJochBraggPrediction JFJochCommon) @@ -15,5 +14,6 @@ TARGET_LINK_LIBRARIES(JFJochBraggPrediction JFJochCommon) IF (JFJOCH_CUDA_AVAILABLE) TARGET_SOURCES(JFJochBraggPrediction PRIVATE ../indexing/CUDAMemHelpers.h - BraggPredictionGPU.cu BraggPredictionGPU.h) + BraggPredictionGPU.cu BraggPredictionGPU.h + BraggPredictionRotGPU.cu BraggPredictionRotGPU.h) ENDIF() -- 2.49.1 From 297e210d88b204f6bb2cdaccc3e0740dbd37231c Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Fri, 30 Jan 2026 18:44:11 +0100 Subject: [PATCH 74/96] BraggPredictionFactory: Fix CUDA includes --- image_analysis/bragg_prediction/BraggPredictionFactory.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/image_analysis/bragg_prediction/BraggPredictionFactory.cpp b/image_analysis/bragg_prediction/BraggPredictionFactory.cpp index e908c0b9..fd1a75c9 100644 --- a/image_analysis/bragg_prediction/BraggPredictionFactory.cpp +++ b/image_analysis/bragg_prediction/BraggPredictionFactory.cpp @@ -5,11 +5,11 @@ #include "BraggPredictionRot.h" #include "BraggPredictionRotation.h" -#include "BraggPredictionRotGPU.h" #ifdef JFJOCH_USE_CUDA #include "../../common/CUDAWrapper.h" #include "BraggPredictionGPU.h" +#include "BraggPredictionRotGPU.h" #endif std::unique_ptr CreateBraggPrediction(bool rotation_indexing, int max_reflections) { -- 2.49.1 From b33cc2a54d58130ef1befdf057ab7f287f579975 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Fri, 30 Jan 2026 19:26:00 +0100 Subject: [PATCH 75/96] Remove BraggPredictionRotation --- image_analysis/RotationIndexer.cpp | 10 -- image_analysis/RotationIndexer.h | 4 - .../BraggPredictionFactory.cpp | 1 - .../BraggPredictionRotation.cpp | 137 ------------------ .../BraggPredictionRotation.h | 33 ----- .../bragg_prediction/CMakeLists.txt | 2 - 6 files changed, 187 deletions(-) delete mode 100644 image_analysis/bragg_prediction/BraggPredictionRotation.cpp delete mode 100644 image_analysis/bragg_prediction/BraggPredictionRotation.h diff --git a/image_analysis/RotationIndexer.cpp b/image_analysis/RotationIndexer.cpp index 7affc00d..23747008 100644 --- a/image_analysis/RotationIndexer.cpp +++ b/image_analysis/RotationIndexer.cpp @@ -100,12 +100,6 @@ void RotationIndexer::TryIndex() { updated_geom_ = data.geom; axis_ = data.axis; } - PredictionRotationSettings pred_settings{ - .high_res_A = 1.0, - .max_hkl = 100, - .centering = search_result_.centering - }; - predictions = PredictRotationHKLs(experiment, data.latt, pred_settings); } } @@ -156,7 +150,3 @@ std::optional RotationIndexer::GetLattice() { .axis = axis_ }; } - -const std::vector &RotationIndexer::GetPredictions() const { - return predictions; -} diff --git a/image_analysis/RotationIndexer.h b/image_analysis/RotationIndexer.h index 56d55768..7259496f 100644 --- a/image_analysis/RotationIndexer.h +++ b/image_analysis/RotationIndexer.h @@ -11,7 +11,6 @@ #include "../common/DiffractionExperiment.h" #include "indexing/IndexerThreadPool.h" #include "lattice_search/LatticeSearch.h" -#include "bragg_prediction/BraggPredictionRotation.h" // RotationIndexer works as following: // 1. First accumulates spot results from rotation images (only images within a certain stride are included) @@ -53,14 +52,11 @@ class RotationIndexer { int64_t first_image_to_try_indexing; std::optional indexed_lattice; - - std::vector predictions; void TryIndex(); public: RotationIndexer(const DiffractionExperiment& x, IndexerThreadPool& indexer); std::optional ProcessImage(int64_t image, const std::vector& spots); std::optional GetLattice(); - const std::vector &GetPredictions() const; }; #endif //JFJOCH_ROTATIONINDEXER_H \ No newline at end of file diff --git a/image_analysis/bragg_prediction/BraggPredictionFactory.cpp b/image_analysis/bragg_prediction/BraggPredictionFactory.cpp index fd1a75c9..d7acd8b6 100644 --- a/image_analysis/bragg_prediction/BraggPredictionFactory.cpp +++ b/image_analysis/bragg_prediction/BraggPredictionFactory.cpp @@ -4,7 +4,6 @@ #include "BraggPredictionFactory.h" #include "BraggPredictionRot.h" -#include "BraggPredictionRotation.h" #ifdef JFJOCH_USE_CUDA #include "../../common/CUDAWrapper.h" diff --git a/image_analysis/bragg_prediction/BraggPredictionRotation.cpp b/image_analysis/bragg_prediction/BraggPredictionRotation.cpp deleted file mode 100644 index 8ad41404..00000000 --- a/image_analysis/bragg_prediction/BraggPredictionRotation.cpp +++ /dev/null @@ -1,137 +0,0 @@ -// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-only - -#include "BraggPredictionRotation.h" - -#include -#include - -#include "../../common/DiffractionGeometry.h" -#include "../../common/GoniometerAxis.h" -#include "../../common/JFJochException.h" -#include "../bragg_integration/SystematicAbsence.h" - -std::vector PredictRotationHKLs(const DiffractionExperiment &experiment, - const CrystalLattice &lattice, - const PredictionRotationSettings &settings) { - std::vector ret; - - const auto gon_opt = experiment.GetGoniometer(); - if (!gon_opt.has_value()) - throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, - "BraggPredictionRotationCPU requires a goniometer axis"); - - const GoniometerAxis& gon = *gon_opt; - const auto geom = experiment.GetDiffractionGeometry(); - - const float one_over_dmax = 1.0f / settings.high_res_A; - const float one_over_dmax_sq = one_over_dmax * one_over_dmax; - - const float wavelength = geom.GetWavelength_A(); - const float one_over_wavelength = 1.0f / wavelength; - - const Coord Astar = lattice.Astar(); - const Coord Bstar = lattice.Bstar(); - const Coord Cstar = lattice.Cstar(); - const Coord S0 = geom.GetScatteringVector(); - - const std::vector rot = geom.GetPoniRotMatrix().transpose().arr(); - - // Precompute detector geometry constants - const float beam_x = geom.GetBeamX_pxl(); - const float beam_y = geom.GetBeamY_pxl(); - const float det_distance = geom.GetDetectorDistance_mm(); - const float pixel_size = geom.GetPixelSize_mm(); - const float F = det_distance / pixel_size; - - const Coord m2 = gon.GetAxis().Normalize(); - const Coord m1 = (m2 % S0).Normalize(); - const Coord m3 = (m1 % m2).Normalize(); - - const float m2_S0 = m2 * S0; - const float m3_S0 = m3 * S0; - - int i = 0; - - for (int32_t h = -settings.max_hkl; h <= settings.max_hkl; ++h) { - const float Ah_x = Astar.x * h; - const float Ah_y = Astar.y * h; - const float Ah_z = Astar.z * h; - - for (int32_t k = -settings.max_hkl; k <= settings.max_hkl; ++k) { - const float AhBk_x = Ah_x + Bstar.x * k; - const float AhBk_y = Ah_y + Bstar.y * k; - const float AhBk_z = Ah_z + Bstar.z * k; - - for (int32_t l = -settings.max_hkl; l <= settings.max_hkl; ++l) { - if (systematic_absence(h, k, l, settings.centering)) - continue; - - const float p0_x = AhBk_x + Cstar.x * l; - const float p0_y = AhBk_y + Cstar.y * l; - const float p0_z = AhBk_z + Cstar.z * l; - const Coord p0{p0_x, p0_y, p0_z}; - - const float p0_sq = p0 * p0; - - if (p0_sq <= 0.0f || p0_sq > one_over_dmax_sq) - continue; - - const float p0_m1 = p0 * m1; - const float p0_m2 = p0 * m2; - const float p0_m3 = p0 * m3; - - const float rho_sq = p0_sq - (p0_m2 * p0_m2); - - const float p_m3 = (- p0_sq / 2 - p0_m2 * m2_S0) / m3_S0; - const float p_m2 = p0_m2; - const float p_m1_opt[2] = { - std::sqrt(rho_sq - p_m3 * p_m3), - -std::sqrt(rho_sq - p_m3 * p_m3) - }; - - // No solution for Laue equations - if ((rho_sq < p_m3 * p_m3) || (p0_sq > 4 * S0 * S0)) - continue; - - for (const auto& p_m1 : p_m1_opt) { - const float cosphi = (p_m1 * p0_m1 + p_m3 * p0_m3) / rho_sq; - const float sinphi = (p_m1 * p0_m3 - p_m3 * p0_m1) / rho_sq; - Coord S = S0 + m1 * p_m1 + m2 * p_m2 + m3 * p_m3; - - float phi = -1.0f * std::atan2(sinphi, cosphi) * 180.0f / M_PI; - if (phi < 0.0f) phi += 360.0f; - const float lorentz_reciprocal = std::fabs(m2 * (S % S0))/(S*S0); - - // Inlined RecipToDector with rot1 and rot2 (rot3 = 0) - // Apply rotation matrix transpose - float S_rot_x = rot[0] * S.x + rot[1] * S.y + rot[2] * S.z; - float S_rot_y = rot[3] * S.x + rot[4] * S.y + rot[5] * S.z; - float S_rot_z = rot[6] * S.x + rot[7] * S.y + rot[8] * S.z; - - if (S_rot_z <= 0) - continue; - - float x = beam_x + F * S_rot_x / S_rot_z; - float y = beam_y + F * S_rot_y / S_rot_z; - - ret.emplace_back(PredictionRotationResult{ - .angle_deg = phi, - .lorentz_reciprocal = lorentz_reciprocal, - .h = h, - .k = k, - .l = l, - .x = x, - .y = y - }); - } - } - } - } - - std::ranges::sort(ret, - [](const PredictionRotationResult& a, const PredictionRotationResult& b) { - return a.angle_deg < b.angle_deg; - }); - return ret; -} diff --git a/image_analysis/bragg_prediction/BraggPredictionRotation.h b/image_analysis/bragg_prediction/BraggPredictionRotation.h deleted file mode 100644 index 40b9a607..00000000 --- a/image_analysis/bragg_prediction/BraggPredictionRotation.h +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-only - -#ifndef JFJOCH_BRAGGPREDICTIONROTATION_H -#define JFJOCH_BRAGGPREDICTIONROTATION_H - -#include -#include - -#include "../../common/CrystalLattice.h" -#include "../../common/DiffractionExperiment.h" -#include "../../common/Reflection.h" -#include "BraggPrediction.h" - -struct PredictionRotationSettings { - float high_res_A; - int32_t max_hkl = 100; - char centering = 'P'; -}; - -struct PredictionRotationResult { - float angle_deg; - float lorentz_reciprocal; - int32_t h,k,l; - float x,y; -}; - -std::vector PredictRotationHKLs(const DiffractionExperiment &experiment, - const CrystalLattice &lattice, - const PredictionRotationSettings &settings); - - -#endif //JFJOCH_BRAGGPREDICTIONROTATION_H \ No newline at end of file diff --git a/image_analysis/bragg_prediction/CMakeLists.txt b/image_analysis/bragg_prediction/CMakeLists.txt index 105db943..a6b166a0 100644 --- a/image_analysis/bragg_prediction/CMakeLists.txt +++ b/image_analysis/bragg_prediction/CMakeLists.txt @@ -3,8 +3,6 @@ ADD_LIBRARY(JFJochBraggPrediction STATIC BraggPrediction.h BraggPredictionFactory.cpp BraggPredictionFactory.h - BraggPredictionRotation.cpp - BraggPredictionRotation.h BraggPredictionRot.cpp BraggPredictionRot.h ) -- 2.49.1 From a8ef78fe9ff51b4081c53e1519b0f9e273859ff0 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Fri, 30 Jan 2026 20:31:09 +0100 Subject: [PATCH 76/96] BraggPredictionRotGPU: Fix systematic absences --- .../bragg_prediction/BraggPredictionRotGPU.cu | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/image_analysis/bragg_prediction/BraggPredictionRotGPU.cu b/image_analysis/bragg_prediction/BraggPredictionRotGPU.cu index b9850b44..b77e598e 100644 --- a/image_analysis/bragg_prediction/BraggPredictionRotGPU.cu +++ b/image_analysis/bragg_prediction/BraggPredictionRotGPU.cu @@ -35,7 +35,31 @@ namespace { if (h == 0 && k == 0 && l == 0) return 0; - // ... systematic absences unchanged ... + switch (C.centering) { + case 'I': + if (is_odd(h + k + l)) return false; + break; + case 'A': + if (is_odd(k + l)) return false; + break; + case 'B': + if (is_odd(h + l)) return false; + break; + case 'C': + if (is_odd(h + k)) return false; + break; + case 'F': + if (is_odd(h + k) || is_odd(h + l) || is_odd(k + l)) return false; + break; + case 'R': { + int mod = (-h + k + l) % 3; + if (mod < 0) mod += 3; + if (mod != 0) return false; + break; + } + default: + break; + } // p0 = A* h + B* k + C* l float p0x = C.Astar.x * h + C.Bstar.x * k + C.Cstar.x * l; -- 2.49.1 From c75507aced1a5d41ee6313462588d1ed2882e2e6 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Fri, 30 Jan 2026 20:38:58 +0100 Subject: [PATCH 77/96] jfjoch_extract_hkl: print RPL --- tools/jfjoch_extract_hkl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/jfjoch_extract_hkl.cpp b/tools/jfjoch_extract_hkl.cpp index 8eef84f6..1968f742 100644 --- a/tools/jfjoch_extract_hkl.cpp +++ b/tools/jfjoch_extract_hkl.cpp @@ -121,7 +121,7 @@ int main(int argc, char **argv) { if (xds_it != xds_result.end() && !xds_it->second.empty()) { f << val[0].h << " " << val[0].k << " " << val[0].l << " " << val[0].I; - f << " " << xds_it->second[0].I << " " << 1.0/val[0].rlp << " " << xds_it->second[0].rlp; + f << " " << xds_it->second[0].I << " " << val[0].rlp << " " << xds_it->second[0].rlp; f << std::endl; } } -- 2.49.1 From 0956e59b9c7452dad974b29954f59ed21f28fb6c Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Fri, 30 Jan 2026 20:39:26 +0100 Subject: [PATCH 78/96] BraggPrediction: Set Lorentz-polarization correction properly --- .../bragg_integration/BraggIntegrate2D.cpp | 14 ++++---------- .../bragg_prediction/BraggPrediction.cpp | 1 + .../bragg_prediction/BraggPredictionGPU.cu | 1 + 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/image_analysis/bragg_integration/BraggIntegrate2D.cpp b/image_analysis/bragg_integration/BraggIntegrate2D.cpp index b1624dea..0e5bd116 100644 --- a/image_analysis/bragg_integration/BraggIntegrate2D.cpp +++ b/image_analysis/bragg_integration/BraggIntegrate2D.cpp @@ -98,18 +98,12 @@ std::vector IntegrateInternal(const DiffractionExperiment &experimen IntegrateReflection(r, ptr, image.GetWidth(), image.GetHeight(), special_value, saturation, r_3, r_1_sq, r_2_sq, r_3_sq); if (r.observed) { - float corr = 1.0; if (experiment.GetPolarizationFactor()) - corr /= geom.CalcAzIntPolarizationCorr(r.predicted_x, r.predicted_y, + r.lp *= geom.CalcAzIntPolarizationCorr(r.predicted_x, r.predicted_y, experiment.GetPolarizationFactor().value()); - Coord S{r.S_x, r.S_y, r.S_z}; - if (experiment.GetGoniometer().has_value()) - corr *= std::fabs(m2 * (S % S0)) / (S * S0); - - r.lp = 1.0f / corr; - r.I *= corr; - r.bkg *= corr; - r.sigma *= corr; + r.I *= r.lp; + r.bkg *= r.lp; + r.sigma *= r.lp; r.image_number = static_cast(image_number); ret.emplace_back(r); } diff --git a/image_analysis/bragg_prediction/BraggPrediction.cpp b/image_analysis/bragg_prediction/BraggPrediction.cpp index dbc70fa0..483c2d85 100644 --- a/image_analysis/bragg_prediction/BraggPrediction.cpp +++ b/image_analysis/bragg_prediction/BraggPrediction.cpp @@ -100,6 +100,7 @@ int BraggPrediction::Calc(const DiffractionExperiment &experiment, const Crystal .predicted_y = y, .d = d, .dist_ewald = dist_ewald_sphere, + .lp = 1.0, .S_x = S_x, .S_y = S_y, .S_z = S_z diff --git a/image_analysis/bragg_prediction/BraggPredictionGPU.cu b/image_analysis/bragg_prediction/BraggPredictionGPU.cu index 0bd61286..aae6a5ed 100644 --- a/image_analysis/bragg_prediction/BraggPredictionGPU.cu +++ b/image_analysis/bragg_prediction/BraggPredictionGPU.cu @@ -84,6 +84,7 @@ namespace { out.S_x = Sx; out.S_y = Sy; out.S_z = Sz; + out.lp = 1.0f; return true; } -- 2.49.1 From f5bd76db055e135b0f7ecd29072a6e816e955fc9 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Fri, 30 Jan 2026 20:49:07 +0100 Subject: [PATCH 79/96] BraggPrediction: Set Lorentz-polarization correction properly --- common/Reflection.h | 2 +- docs/CBOR.md | 2 +- frame_serialize/CBORStream2Deserializer.cpp | 2 +- frame_serialize/CBORStream2Serializer.cpp | 2 +- image_analysis/bragg_integration/BraggIntegrate2D.cpp | 8 ++++---- image_analysis/bragg_prediction/BraggPrediction.cpp | 2 +- image_analysis/bragg_prediction/BraggPredictionGPU.cu | 2 +- image_analysis/bragg_prediction/BraggPredictionRot.cpp | 2 +- image_analysis/bragg_prediction/BraggPredictionRotGPU.cu | 2 +- reader/JFJochHDF5Reader.cpp | 5 +++-- tools/jfjoch_extract_hkl.cpp | 2 +- writer/HDF5DataFilePluginReflection.cpp | 2 +- 12 files changed, 17 insertions(+), 16 deletions(-) diff --git a/common/Reflection.h b/common/Reflection.h index b15a70fe..2682087e 100644 --- a/common/Reflection.h +++ b/common/Reflection.h @@ -21,7 +21,7 @@ struct Reflection { float bkg; float sigma; float dist_ewald; - float lp; + float rlp; bool observed = false; float S_x, S_y, S_z; }; diff --git a/docs/CBOR.md b/docs/CBOR.md index c489bd63..3a6344d9 100644 --- a/docs/CBOR.md +++ b/docs/CBOR.md @@ -146,7 +146,7 @@ See [DECTRIS documentation](https://github.com/dectris/documentation/tree/main/s | - sigma | float | standard deviation, estimated from counting statistics (photons) | | | | - image | float | image number (present for each spot) | | | | - dist_ewald | float | distance to Ewald sphere (present only for indexed spots) | | | -| - lp | float | Lorentz and polarization corrections | | | +| - rlp | float | Reciprocal Lorentz and polarization corrections | | | | spot_count | uint64 | Spot count | | | | spot_count_ice_rings | uint64 | Number of spots within identified rings (experimental) | | | | spot_count_low_res | uint64 | Number of spots in low resolution (prior to filtering) | | | diff --git a/frame_serialize/CBORStream2Deserializer.cpp b/frame_serialize/CBORStream2Deserializer.cpp index 28695a5d..d56ffc9b 100644 --- a/frame_serialize/CBORStream2Deserializer.cpp +++ b/frame_serialize/CBORStream2Deserializer.cpp @@ -464,7 +464,7 @@ namespace { else if (key == "image") r.image_number = GetCBORFloat(map_value); else if (key == "rlp") - r.lp = GetCBORFloat(map_value); + r.rlp = GetCBORFloat(map_value); else if (key == "rp") r.dist_ewald = GetCBORFloat(map_value); else diff --git a/frame_serialize/CBORStream2Serializer.cpp b/frame_serialize/CBORStream2Serializer.cpp index dd26989d..06027d43 100644 --- a/frame_serialize/CBORStream2Serializer.cpp +++ b/frame_serialize/CBORStream2Serializer.cpp @@ -243,7 +243,7 @@ inline void CBOR_ENC(CborEncoder &encoder, const Reflection& r) { CBOR_ENC(mapEncoder, "sigma", r.sigma); CBOR_ENC(mapEncoder, "image", r.image_number); CBOR_ENC(mapEncoder, "rp", r.dist_ewald); - CBOR_ENC(mapEncoder, "lp", r.lp); + CBOR_ENC(mapEncoder, "rlp", r.rlp); cborErr(cbor_encoder_close_container(&encoder, &mapEncoder)); } diff --git a/image_analysis/bragg_integration/BraggIntegrate2D.cpp b/image_analysis/bragg_integration/BraggIntegrate2D.cpp index 0e5bd116..77622f64 100644 --- a/image_analysis/bragg_integration/BraggIntegrate2D.cpp +++ b/image_analysis/bragg_integration/BraggIntegrate2D.cpp @@ -99,11 +99,11 @@ std::vector IntegrateInternal(const DiffractionExperiment &experimen r_3, r_1_sq, r_2_sq, r_3_sq); if (r.observed) { if (experiment.GetPolarizationFactor()) - r.lp *= geom.CalcAzIntPolarizationCorr(r.predicted_x, r.predicted_y, + r.rlp *= geom.CalcAzIntPolarizationCorr(r.predicted_x, r.predicted_y, experiment.GetPolarizationFactor().value()); - r.I *= r.lp; - r.bkg *= r.lp; - r.sigma *= r.lp; + r.I *= r.rlp; + r.bkg *= r.rlp; + r.sigma *= r.rlp; r.image_number = static_cast(image_number); ret.emplace_back(r); } diff --git a/image_analysis/bragg_prediction/BraggPrediction.cpp b/image_analysis/bragg_prediction/BraggPrediction.cpp index 483c2d85..df9d180b 100644 --- a/image_analysis/bragg_prediction/BraggPrediction.cpp +++ b/image_analysis/bragg_prediction/BraggPrediction.cpp @@ -100,7 +100,7 @@ int BraggPrediction::Calc(const DiffractionExperiment &experiment, const Crystal .predicted_y = y, .d = d, .dist_ewald = dist_ewald_sphere, - .lp = 1.0, + .rlp = 1.0, .S_x = S_x, .S_y = S_y, .S_z = S_z diff --git a/image_analysis/bragg_prediction/BraggPredictionGPU.cu b/image_analysis/bragg_prediction/BraggPredictionGPU.cu index aae6a5ed..b71ecb5c 100644 --- a/image_analysis/bragg_prediction/BraggPredictionGPU.cu +++ b/image_analysis/bragg_prediction/BraggPredictionGPU.cu @@ -84,7 +84,7 @@ namespace { out.S_x = Sx; out.S_y = Sy; out.S_z = Sz; - out.lp = 1.0f; + out.rlp = 1.0f; return true; } diff --git a/image_analysis/bragg_prediction/BraggPredictionRot.cpp b/image_analysis/bragg_prediction/BraggPredictionRot.cpp index b202efaf..94a1d437 100644 --- a/image_analysis/bragg_prediction/BraggPredictionRot.cpp +++ b/image_analysis/bragg_prediction/BraggPredictionRot.cpp @@ -124,7 +124,7 @@ int BraggPredictionRot::Calc(const DiffractionExperiment &experiment, const Crys .predicted_y = y, .d = d, .dist_ewald = dist_ewald_sphere, - .lp = lorentz_reciprocal, + .rlp = lorentz_reciprocal, .S_x = S.x, .S_y = S.y, .S_z = S.z diff --git a/image_analysis/bragg_prediction/BraggPredictionRotGPU.cu b/image_analysis/bragg_prediction/BraggPredictionRotGPU.cu index b77e598e..7c764123 100644 --- a/image_analysis/bragg_prediction/BraggPredictionRotGPU.cu +++ b/image_analysis/bragg_prediction/BraggPredictionRotGPU.cu @@ -131,7 +131,7 @@ namespace { out[count].predicted_y = y; out[count].d = 1.0f / sqrtf(p0_sq); out[count].dist_ewald = dist_ewald; - out[count].lp = lorentz; + out[count].rlp = lorentz; out[count].S_x = Sx; out[count].S_y = Sy; out[count].S_z = Sz; diff --git a/reader/JFJochHDF5Reader.cpp b/reader/JFJochHDF5Reader.cpp index 06546cbd..e017a77e 100644 --- a/reader/JFJochHDF5Reader.cpp +++ b/reader/JFJochHDF5Reader.cpp @@ -689,7 +689,8 @@ bool JFJochHDF5Reader::LoadImage_i(std::shared_ptr &dataset for (size_t i = 0; i < h.size(); i++) { float lp_val = 0.0; - if (lp.size() > i) lp_val = lp.at(i); + if (lp.size() > i && lp[i] != 0.0f) + lp_val = 1.0f / lp[i]; Reflection r{ .h = h.at(i), .k = k.at(i), @@ -700,7 +701,7 @@ bool JFJochHDF5Reader::LoadImage_i(std::shared_ptr &dataset .I = int_sum.at(i), .bkg = bkg.at(i), .sigma = int_err.at(i), - .lp = lp_val + .rlp = lp_val }; message.reflections.emplace_back(r); } diff --git a/tools/jfjoch_extract_hkl.cpp b/tools/jfjoch_extract_hkl.cpp index 1968f742..f12412e7 100644 --- a/tools/jfjoch_extract_hkl.cpp +++ b/tools/jfjoch_extract_hkl.cpp @@ -89,7 +89,7 @@ int main(int argc, char **argv) { .I = r.I, .last_image = i, .count = 1, - .rlp = r.lp, + .rlp = r.rlp, .image_number = r.image_number }; bool found = false; diff --git a/writer/HDF5DataFilePluginReflection.cpp b/writer/HDF5DataFilePluginReflection.cpp index ba6aa4d4..2b9fc2e5 100644 --- a/writer/HDF5DataFilePluginReflection.cpp +++ b/writer/HDF5DataFilePluginReflection.cpp @@ -30,7 +30,7 @@ void HDF5DataFilePluginReflection::Write(const DataMessage &msg, uint64_t image_ pred_x.emplace_back(refl.predicted_x); pred_y.emplace_back(refl.predicted_y); bkg.emplace_back(refl.bkg); - lp.emplace_back(refl.lp); + lp.emplace_back(1.0/refl.rlp); } std::string image_group_name = fmt::format("image_{:06d}", image_number); -- 2.49.1 From 6db9a8b2eb76f43170788ff3739f8d2ddf07a3c2 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Sat, 31 Jan 2026 09:23:06 +0100 Subject: [PATCH 80/96] CHANGELOG --- docs/CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index e137c47e..d172f4cf 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog ## 1.0.0 +### 1.0.0-rc.124 +This is an UNSTABLE release. This version significantly rewrites code to predict reflection position and integrate them, +especially in case of rotation crystallography. If things go wrong with analysis, it is better to revert to 1.0.0-rc.123. + +* jfjoch_broker: Improve refection position prediction and Bragg integration code. +* jfjoch_broker: Align with XDS way of calculating Lorentz correction and general notation. +* jfjoch_writer: Fix saving mosaicity properly in HDF5 file. + ### 1.0.0-rc.123 This is an UNSTABLE release. -- 2.49.1 From 89713b6689b5897c30aad0d42b94f685da9c9817 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Sat, 31 Jan 2026 09:24:10 +0100 Subject: [PATCH 81/96] VERSION: 1.0.0-rc.124 --- VERSION | 2 +- broker/gen/api/ApiBase.h | 2 +- broker/gen/api/DefaultApi.cpp | 2 +- broker/gen/api/DefaultApi.h | 4 ++-- broker/gen/model/Azim_int_settings.cpp | 2 +- broker/gen/model/Azim_int_settings.h | 2 +- broker/gen/model/Broker_status.cpp | 2 +- broker/gen/model/Broker_status.h | 2 +- broker/gen/model/Calibration_statistics_inner.cpp | 2 +- broker/gen/model/Calibration_statistics_inner.h | 2 +- broker/gen/model/Dark_mask_settings.cpp | 2 +- broker/gen/model/Dark_mask_settings.h | 2 +- broker/gen/model/Dataset_settings.cpp | 2 +- broker/gen/model/Dataset_settings.h | 2 +- .../model/Dataset_settings_xray_fluorescence_spectrum.cpp | 2 +- .../model/Dataset_settings_xray_fluorescence_spectrum.h | 2 +- broker/gen/model/Detector.cpp | 2 +- broker/gen/model/Detector.h | 2 +- broker/gen/model/Detector_list.cpp | 2 +- broker/gen/model/Detector_list.h | 2 +- broker/gen/model/Detector_list_element.cpp | 2 +- broker/gen/model/Detector_list_element.h | 2 +- broker/gen/model/Detector_module.cpp | 2 +- broker/gen/model/Detector_module.h | 2 +- broker/gen/model/Detector_module_direction.cpp | 2 +- broker/gen/model/Detector_module_direction.h | 2 +- broker/gen/model/Detector_power_state.cpp | 2 +- broker/gen/model/Detector_power_state.h | 2 +- broker/gen/model/Detector_selection.cpp | 2 +- broker/gen/model/Detector_selection.h | 2 +- broker/gen/model/Detector_settings.cpp | 2 +- broker/gen/model/Detector_settings.h | 2 +- broker/gen/model/Detector_state.cpp | 2 +- broker/gen/model/Detector_state.h | 2 +- broker/gen/model/Detector_status.cpp | 2 +- broker/gen/model/Detector_status.h | 2 +- broker/gen/model/Detector_timing.cpp | 2 +- broker/gen/model/Detector_timing.h | 2 +- broker/gen/model/Detector_type.cpp | 2 +- broker/gen/model/Detector_type.h | 2 +- broker/gen/model/Error_message.cpp | 2 +- broker/gen/model/Error_message.h | 2 +- broker/gen/model/File_writer_format.cpp | 2 +- broker/gen/model/File_writer_format.h | 2 +- broker/gen/model/File_writer_settings.cpp | 2 +- broker/gen/model/File_writer_settings.h | 2 +- broker/gen/model/Fpga_status_inner.cpp | 2 +- broker/gen/model/Fpga_status_inner.h | 2 +- broker/gen/model/Geom_refinement_algorithm.cpp | 2 +- broker/gen/model/Geom_refinement_algorithm.h | 2 +- broker/gen/model/Grid_scan.cpp | 2 +- broker/gen/model/Grid_scan.h | 2 +- broker/gen/model/Helpers.cpp | 2 +- broker/gen/model/Helpers.h | 2 +- broker/gen/model/Image_buffer_status.cpp | 2 +- broker/gen/model/Image_buffer_status.h | 2 +- broker/gen/model/Image_format_settings.cpp | 2 +- broker/gen/model/Image_format_settings.h | 2 +- broker/gen/model/Image_pusher_type.cpp | 2 +- broker/gen/model/Image_pusher_type.h | 2 +- broker/gen/model/Indexing_algorithm.cpp | 2 +- broker/gen/model/Indexing_algorithm.h | 2 +- broker/gen/model/Indexing_settings.cpp | 2 +- broker/gen/model/Indexing_settings.h | 2 +- broker/gen/model/Instrument_metadata.cpp | 2 +- broker/gen/model/Instrument_metadata.h | 2 +- broker/gen/model/Jfjoch_settings.cpp | 2 +- broker/gen/model/Jfjoch_settings.h | 2 +- broker/gen/model/Jfjoch_settings_ssl.cpp | 2 +- broker/gen/model/Jfjoch_settings_ssl.h | 2 +- broker/gen/model/Jfjoch_statistics.cpp | 2 +- broker/gen/model/Jfjoch_statistics.h | 2 +- broker/gen/model/Measurement_statistics.cpp | 2 +- broker/gen/model/Measurement_statistics.h | 2 +- broker/gen/model/Pcie_devices_inner.cpp | 2 +- broker/gen/model/Pcie_devices_inner.h | 2 +- broker/gen/model/Pixel_mask_statistics.cpp | 2 +- broker/gen/model/Pixel_mask_statistics.h | 2 +- broker/gen/model/Plot.cpp | 2 +- broker/gen/model/Plot.h | 2 +- broker/gen/model/Plot_unit_x.cpp | 2 +- broker/gen/model/Plot_unit_x.h | 2 +- broker/gen/model/Plots.cpp | 2 +- broker/gen/model/Plots.h | 2 +- broker/gen/model/Roi_azim_list.cpp | 2 +- broker/gen/model/Roi_azim_list.h | 2 +- broker/gen/model/Roi_azimuthal.cpp | 2 +- broker/gen/model/Roi_azimuthal.h | 2 +- broker/gen/model/Roi_box.cpp | 2 +- broker/gen/model/Roi_box.h | 2 +- broker/gen/model/Roi_box_list.cpp | 2 +- broker/gen/model/Roi_box_list.h | 2 +- broker/gen/model/Roi_circle.cpp | 2 +- broker/gen/model/Roi_circle.h | 2 +- broker/gen/model/Roi_circle_list.cpp | 2 +- broker/gen/model/Roi_circle_list.h | 2 +- broker/gen/model/Roi_definitions.cpp | 2 +- broker/gen/model/Roi_definitions.h | 2 +- broker/gen/model/Rotation_axis.cpp | 2 +- broker/gen/model/Rotation_axis.h | 2 +- broker/gen/model/Scan_result.cpp | 2 +- broker/gen/model/Scan_result.h | 2 +- broker/gen/model/Scan_result_images_inner.cpp | 2 +- broker/gen/model/Scan_result_images_inner.h | 2 +- broker/gen/model/Spot_finding_settings.cpp | 2 +- broker/gen/model/Spot_finding_settings.h | 2 +- broker/gen/model/Standard_detector_geometry.cpp | 2 +- broker/gen/model/Standard_detector_geometry.h | 2 +- broker/gen/model/Unit_cell.cpp | 2 +- broker/gen/model/Unit_cell.h | 2 +- broker/gen/model/Zeromq_metadata_settings.cpp | 2 +- broker/gen/model/Zeromq_metadata_settings.h | 2 +- broker/gen/model/Zeromq_preview_settings.cpp | 2 +- broker/gen/model/Zeromq_preview_settings.h | 2 +- broker/gen/model/Zeromq_settings.cpp | 2 +- broker/gen/model/Zeromq_settings.h | 2 +- broker/jfjoch_api.yaml | 2 +- broker/redoc-static.html | 8 ++++---- docs/conf.py | 2 +- docs/python_client/README.md | 4 ++-- docs/python_client/docs/DefaultApi.md | 4 ++-- fpga/hdl/action_config.v | 2 +- fpga/pcie_driver/dkms.conf | 2 +- fpga/pcie_driver/install_dkms.sh | 2 +- fpga/pcie_driver/jfjoch_drv.c | 2 +- fpga/pcie_driver/postinstall.sh | 2 +- fpga/pcie_driver/preuninstall.sh | 2 +- frontend/package.json | 2 +- frontend/src/openapi/core/OpenAPI.ts | 2 +- frontend/src/openapi/models/color_scale.ts | 2 +- frontend/src/openapi/services/DefaultService.ts | 2 +- frontend/src/version.ts | 2 +- 132 files changed, 138 insertions(+), 138 deletions(-) diff --git a/VERSION b/VERSION index 621012f7..00dfc992 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.0-rc.123 +1.0.0-rc.124 diff --git a/broker/gen/api/ApiBase.h b/broker/gen/api/ApiBase.h index 5fb0a6b5..53a9c26f 100644 --- a/broker/gen/api/ApiBase.h +++ b/broker/gen/api/ApiBase.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/api/DefaultApi.cpp b/broker/gen/api/DefaultApi.cpp index 939f41c3..2d3adb69 100644 --- a/broker/gen/api/DefaultApi.cpp +++ b/broker/gen/api/DefaultApi.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/api/DefaultApi.h b/broker/gen/api/DefaultApi.h index a3101e70..e37dfcda 100644 --- a/broker/gen/api/DefaultApi.h +++ b/broker/gen/api/DefaultApi.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). @@ -466,7 +466,7 @@ private: /// Saturation value to set contrast in the preview image; if not provided, then autocontrast procedure is used (optional, default to 0.0f) /// Quality of JPEG image (100 - highest; 0 - lowest) (optional, default to 100L) /// Show resolution ring, provided in Angstrom (optional, default to 0.1f) - /// Color scale for preview image: 0 - indigo, 1 - viridis, 2 - B/W, 3 - heat (optional, default to "indigo") + /// Color scale for preview image (optional, default to "indigo") /// Show resolution estimation as a ring (optional, default to false) virtual void image_buffer_image_jpeg_get(const std::optional &id, const std::optional &showUserMask, const std::optional &showRoi, const std::optional &showSpots, const std::optional &showBeamCenter, const std::optional &saturation, const std::optional &jpegQuality, const std::optional &showResRing, const std::optional &color, const std::optional &showResEst, Pistache::Http::ResponseWriter &response) = 0; /// diff --git a/broker/gen/model/Azim_int_settings.cpp b/broker/gen/model/Azim_int_settings.cpp index 3c5ce942..0f7990f6 100644 --- a/broker/gen/model/Azim_int_settings.cpp +++ b/broker/gen/model/Azim_int_settings.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Azim_int_settings.h b/broker/gen/model/Azim_int_settings.h index 723625e1..f2713c35 100644 --- a/broker/gen/model/Azim_int_settings.h +++ b/broker/gen/model/Azim_int_settings.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Broker_status.cpp b/broker/gen/model/Broker_status.cpp index b8b50b20..2b845274 100644 --- a/broker/gen/model/Broker_status.cpp +++ b/broker/gen/model/Broker_status.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Broker_status.h b/broker/gen/model/Broker_status.h index 5d0ce3f9..8c03a071 100644 --- a/broker/gen/model/Broker_status.h +++ b/broker/gen/model/Broker_status.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Calibration_statistics_inner.cpp b/broker/gen/model/Calibration_statistics_inner.cpp index cd9cffc0..0ae44b96 100644 --- a/broker/gen/model/Calibration_statistics_inner.cpp +++ b/broker/gen/model/Calibration_statistics_inner.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Calibration_statistics_inner.h b/broker/gen/model/Calibration_statistics_inner.h index 89d8399e..590a55a6 100644 --- a/broker/gen/model/Calibration_statistics_inner.h +++ b/broker/gen/model/Calibration_statistics_inner.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Dark_mask_settings.cpp b/broker/gen/model/Dark_mask_settings.cpp index 78deb760..923f0a9a 100644 --- a/broker/gen/model/Dark_mask_settings.cpp +++ b/broker/gen/model/Dark_mask_settings.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Dark_mask_settings.h b/broker/gen/model/Dark_mask_settings.h index cf01671e..93a398ab 100644 --- a/broker/gen/model/Dark_mask_settings.h +++ b/broker/gen/model/Dark_mask_settings.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Dataset_settings.cpp b/broker/gen/model/Dataset_settings.cpp index e572bbbd..5ee4000a 100644 --- a/broker/gen/model/Dataset_settings.cpp +++ b/broker/gen/model/Dataset_settings.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Dataset_settings.h b/broker/gen/model/Dataset_settings.h index 8ffd3673..7951acbd 100644 --- a/broker/gen/model/Dataset_settings.h +++ b/broker/gen/model/Dataset_settings.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Dataset_settings_xray_fluorescence_spectrum.cpp b/broker/gen/model/Dataset_settings_xray_fluorescence_spectrum.cpp index fe8e1020..5cb0d2fb 100644 --- a/broker/gen/model/Dataset_settings_xray_fluorescence_spectrum.cpp +++ b/broker/gen/model/Dataset_settings_xray_fluorescence_spectrum.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Dataset_settings_xray_fluorescence_spectrum.h b/broker/gen/model/Dataset_settings_xray_fluorescence_spectrum.h index 950495c4..5e942ecc 100644 --- a/broker/gen/model/Dataset_settings_xray_fluorescence_spectrum.h +++ b/broker/gen/model/Dataset_settings_xray_fluorescence_spectrum.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Detector.cpp b/broker/gen/model/Detector.cpp index 94365a7c..98d2dd7a 100644 --- a/broker/gen/model/Detector.cpp +++ b/broker/gen/model/Detector.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Detector.h b/broker/gen/model/Detector.h index 13d9cb88..2a96221d 100644 --- a/broker/gen/model/Detector.h +++ b/broker/gen/model/Detector.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Detector_list.cpp b/broker/gen/model/Detector_list.cpp index ce628990..1d9dcc36 100644 --- a/broker/gen/model/Detector_list.cpp +++ b/broker/gen/model/Detector_list.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Detector_list.h b/broker/gen/model/Detector_list.h index 00e076bd..5ec2793f 100644 --- a/broker/gen/model/Detector_list.h +++ b/broker/gen/model/Detector_list.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Detector_list_element.cpp b/broker/gen/model/Detector_list_element.cpp index 3785063b..a44d047b 100644 --- a/broker/gen/model/Detector_list_element.cpp +++ b/broker/gen/model/Detector_list_element.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Detector_list_element.h b/broker/gen/model/Detector_list_element.h index 6fd04ef5..f217a34c 100644 --- a/broker/gen/model/Detector_list_element.h +++ b/broker/gen/model/Detector_list_element.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Detector_module.cpp b/broker/gen/model/Detector_module.cpp index 2c847e5e..8a5a9120 100644 --- a/broker/gen/model/Detector_module.cpp +++ b/broker/gen/model/Detector_module.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Detector_module.h b/broker/gen/model/Detector_module.h index e69d23b1..0889e97a 100644 --- a/broker/gen/model/Detector_module.h +++ b/broker/gen/model/Detector_module.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Detector_module_direction.cpp b/broker/gen/model/Detector_module_direction.cpp index 98a03d42..3d45485b 100644 --- a/broker/gen/model/Detector_module_direction.cpp +++ b/broker/gen/model/Detector_module_direction.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Detector_module_direction.h b/broker/gen/model/Detector_module_direction.h index cfc99bec..74ec9914 100644 --- a/broker/gen/model/Detector_module_direction.h +++ b/broker/gen/model/Detector_module_direction.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Detector_power_state.cpp b/broker/gen/model/Detector_power_state.cpp index 8a81689a..e153f3b8 100644 --- a/broker/gen/model/Detector_power_state.cpp +++ b/broker/gen/model/Detector_power_state.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Detector_power_state.h b/broker/gen/model/Detector_power_state.h index fd6669ea..10e7596b 100644 --- a/broker/gen/model/Detector_power_state.h +++ b/broker/gen/model/Detector_power_state.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Detector_selection.cpp b/broker/gen/model/Detector_selection.cpp index b68e888d..0ab420a1 100644 --- a/broker/gen/model/Detector_selection.cpp +++ b/broker/gen/model/Detector_selection.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Detector_selection.h b/broker/gen/model/Detector_selection.h index 804665e3..aafa816f 100644 --- a/broker/gen/model/Detector_selection.h +++ b/broker/gen/model/Detector_selection.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Detector_settings.cpp b/broker/gen/model/Detector_settings.cpp index 549d209f..841a229e 100644 --- a/broker/gen/model/Detector_settings.cpp +++ b/broker/gen/model/Detector_settings.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Detector_settings.h b/broker/gen/model/Detector_settings.h index 61a57fa8..02a8c4a0 100644 --- a/broker/gen/model/Detector_settings.h +++ b/broker/gen/model/Detector_settings.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Detector_state.cpp b/broker/gen/model/Detector_state.cpp index f6be058b..7fdc6a2e 100644 --- a/broker/gen/model/Detector_state.cpp +++ b/broker/gen/model/Detector_state.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Detector_state.h b/broker/gen/model/Detector_state.h index 2fed27df..1baa9161 100644 --- a/broker/gen/model/Detector_state.h +++ b/broker/gen/model/Detector_state.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Detector_status.cpp b/broker/gen/model/Detector_status.cpp index e3e4a392..6734a7d7 100644 --- a/broker/gen/model/Detector_status.cpp +++ b/broker/gen/model/Detector_status.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Detector_status.h b/broker/gen/model/Detector_status.h index d6b75c0b..3c05c956 100644 --- a/broker/gen/model/Detector_status.h +++ b/broker/gen/model/Detector_status.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Detector_timing.cpp b/broker/gen/model/Detector_timing.cpp index ed12795a..db9c94e0 100644 --- a/broker/gen/model/Detector_timing.cpp +++ b/broker/gen/model/Detector_timing.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Detector_timing.h b/broker/gen/model/Detector_timing.h index f85627e9..49bb54bc 100644 --- a/broker/gen/model/Detector_timing.h +++ b/broker/gen/model/Detector_timing.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Detector_type.cpp b/broker/gen/model/Detector_type.cpp index 8b9ef305..3844da99 100644 --- a/broker/gen/model/Detector_type.cpp +++ b/broker/gen/model/Detector_type.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Detector_type.h b/broker/gen/model/Detector_type.h index 2ac1f4f9..dfdd5cb9 100644 --- a/broker/gen/model/Detector_type.h +++ b/broker/gen/model/Detector_type.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Error_message.cpp b/broker/gen/model/Error_message.cpp index 1e96b326..43195ce8 100644 --- a/broker/gen/model/Error_message.cpp +++ b/broker/gen/model/Error_message.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Error_message.h b/broker/gen/model/Error_message.h index b2ab38e3..a7170f64 100644 --- a/broker/gen/model/Error_message.h +++ b/broker/gen/model/Error_message.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/File_writer_format.cpp b/broker/gen/model/File_writer_format.cpp index bb1de708..69c92d71 100644 --- a/broker/gen/model/File_writer_format.cpp +++ b/broker/gen/model/File_writer_format.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/File_writer_format.h b/broker/gen/model/File_writer_format.h index 2695da0c..2f7efe6f 100644 --- a/broker/gen/model/File_writer_format.h +++ b/broker/gen/model/File_writer_format.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/File_writer_settings.cpp b/broker/gen/model/File_writer_settings.cpp index aafa8f1b..51e129e4 100644 --- a/broker/gen/model/File_writer_settings.cpp +++ b/broker/gen/model/File_writer_settings.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/File_writer_settings.h b/broker/gen/model/File_writer_settings.h index 813ef07a..2c5029af 100644 --- a/broker/gen/model/File_writer_settings.h +++ b/broker/gen/model/File_writer_settings.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Fpga_status_inner.cpp b/broker/gen/model/Fpga_status_inner.cpp index 6734943a..1a0c1977 100644 --- a/broker/gen/model/Fpga_status_inner.cpp +++ b/broker/gen/model/Fpga_status_inner.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Fpga_status_inner.h b/broker/gen/model/Fpga_status_inner.h index 508d2d3f..826b3b2b 100644 --- a/broker/gen/model/Fpga_status_inner.h +++ b/broker/gen/model/Fpga_status_inner.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Geom_refinement_algorithm.cpp b/broker/gen/model/Geom_refinement_algorithm.cpp index d5d7a15f..c232e2b0 100644 --- a/broker/gen/model/Geom_refinement_algorithm.cpp +++ b/broker/gen/model/Geom_refinement_algorithm.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Geom_refinement_algorithm.h b/broker/gen/model/Geom_refinement_algorithm.h index 2cbe8997..2cd18857 100644 --- a/broker/gen/model/Geom_refinement_algorithm.h +++ b/broker/gen/model/Geom_refinement_algorithm.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Grid_scan.cpp b/broker/gen/model/Grid_scan.cpp index 239e4f18..ab812a68 100644 --- a/broker/gen/model/Grid_scan.cpp +++ b/broker/gen/model/Grid_scan.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Grid_scan.h b/broker/gen/model/Grid_scan.h index 6b3c3b49..1635a6f2 100644 --- a/broker/gen/model/Grid_scan.h +++ b/broker/gen/model/Grid_scan.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Helpers.cpp b/broker/gen/model/Helpers.cpp index eb8d9c6e..0bd7cecc 100644 --- a/broker/gen/model/Helpers.cpp +++ b/broker/gen/model/Helpers.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Helpers.h b/broker/gen/model/Helpers.h index 24660de1..7fe6abfb 100644 --- a/broker/gen/model/Helpers.h +++ b/broker/gen/model/Helpers.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Image_buffer_status.cpp b/broker/gen/model/Image_buffer_status.cpp index 3261696c..5ee8e454 100644 --- a/broker/gen/model/Image_buffer_status.cpp +++ b/broker/gen/model/Image_buffer_status.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Image_buffer_status.h b/broker/gen/model/Image_buffer_status.h index de0e1a94..a23ac9e3 100644 --- a/broker/gen/model/Image_buffer_status.h +++ b/broker/gen/model/Image_buffer_status.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Image_format_settings.cpp b/broker/gen/model/Image_format_settings.cpp index 1a690bb0..47668373 100644 --- a/broker/gen/model/Image_format_settings.cpp +++ b/broker/gen/model/Image_format_settings.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Image_format_settings.h b/broker/gen/model/Image_format_settings.h index accdfaba..233a6103 100644 --- a/broker/gen/model/Image_format_settings.h +++ b/broker/gen/model/Image_format_settings.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Image_pusher_type.cpp b/broker/gen/model/Image_pusher_type.cpp index 2236e98f..68accbcd 100644 --- a/broker/gen/model/Image_pusher_type.cpp +++ b/broker/gen/model/Image_pusher_type.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Image_pusher_type.h b/broker/gen/model/Image_pusher_type.h index fbc71b81..10567246 100644 --- a/broker/gen/model/Image_pusher_type.h +++ b/broker/gen/model/Image_pusher_type.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Indexing_algorithm.cpp b/broker/gen/model/Indexing_algorithm.cpp index 1553b636..7b2f0e2c 100644 --- a/broker/gen/model/Indexing_algorithm.cpp +++ b/broker/gen/model/Indexing_algorithm.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Indexing_algorithm.h b/broker/gen/model/Indexing_algorithm.h index a91aa31d..174847c8 100644 --- a/broker/gen/model/Indexing_algorithm.h +++ b/broker/gen/model/Indexing_algorithm.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Indexing_settings.cpp b/broker/gen/model/Indexing_settings.cpp index c24a3505..afe96daf 100644 --- a/broker/gen/model/Indexing_settings.cpp +++ b/broker/gen/model/Indexing_settings.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Indexing_settings.h b/broker/gen/model/Indexing_settings.h index eb719399..814517f6 100644 --- a/broker/gen/model/Indexing_settings.h +++ b/broker/gen/model/Indexing_settings.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Instrument_metadata.cpp b/broker/gen/model/Instrument_metadata.cpp index 1ccbd045..b002398f 100644 --- a/broker/gen/model/Instrument_metadata.cpp +++ b/broker/gen/model/Instrument_metadata.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Instrument_metadata.h b/broker/gen/model/Instrument_metadata.h index 1fc7de6b..d115af3b 100644 --- a/broker/gen/model/Instrument_metadata.h +++ b/broker/gen/model/Instrument_metadata.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Jfjoch_settings.cpp b/broker/gen/model/Jfjoch_settings.cpp index 0e0465e8..1dfa1b53 100644 --- a/broker/gen/model/Jfjoch_settings.cpp +++ b/broker/gen/model/Jfjoch_settings.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Jfjoch_settings.h b/broker/gen/model/Jfjoch_settings.h index ab9e12ad..dad14cdd 100644 --- a/broker/gen/model/Jfjoch_settings.h +++ b/broker/gen/model/Jfjoch_settings.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Jfjoch_settings_ssl.cpp b/broker/gen/model/Jfjoch_settings_ssl.cpp index ffadb85b..0d06e0f2 100644 --- a/broker/gen/model/Jfjoch_settings_ssl.cpp +++ b/broker/gen/model/Jfjoch_settings_ssl.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Jfjoch_settings_ssl.h b/broker/gen/model/Jfjoch_settings_ssl.h index afb37ce1..82be7695 100644 --- a/broker/gen/model/Jfjoch_settings_ssl.h +++ b/broker/gen/model/Jfjoch_settings_ssl.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Jfjoch_statistics.cpp b/broker/gen/model/Jfjoch_statistics.cpp index f790568e..d63624d5 100644 --- a/broker/gen/model/Jfjoch_statistics.cpp +++ b/broker/gen/model/Jfjoch_statistics.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Jfjoch_statistics.h b/broker/gen/model/Jfjoch_statistics.h index 217eaac2..3108d0ad 100644 --- a/broker/gen/model/Jfjoch_statistics.h +++ b/broker/gen/model/Jfjoch_statistics.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Measurement_statistics.cpp b/broker/gen/model/Measurement_statistics.cpp index 19531203..f122290e 100644 --- a/broker/gen/model/Measurement_statistics.cpp +++ b/broker/gen/model/Measurement_statistics.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Measurement_statistics.h b/broker/gen/model/Measurement_statistics.h index 53101b00..44a8fea6 100644 --- a/broker/gen/model/Measurement_statistics.h +++ b/broker/gen/model/Measurement_statistics.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Pcie_devices_inner.cpp b/broker/gen/model/Pcie_devices_inner.cpp index 29affa8c..1a830308 100644 --- a/broker/gen/model/Pcie_devices_inner.cpp +++ b/broker/gen/model/Pcie_devices_inner.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Pcie_devices_inner.h b/broker/gen/model/Pcie_devices_inner.h index 58e36c7f..93b465d8 100644 --- a/broker/gen/model/Pcie_devices_inner.h +++ b/broker/gen/model/Pcie_devices_inner.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Pixel_mask_statistics.cpp b/broker/gen/model/Pixel_mask_statistics.cpp index 529fbc1b..3fb53d62 100644 --- a/broker/gen/model/Pixel_mask_statistics.cpp +++ b/broker/gen/model/Pixel_mask_statistics.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Pixel_mask_statistics.h b/broker/gen/model/Pixel_mask_statistics.h index dbfe510b..6ce18107 100644 --- a/broker/gen/model/Pixel_mask_statistics.h +++ b/broker/gen/model/Pixel_mask_statistics.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Plot.cpp b/broker/gen/model/Plot.cpp index 47c423e0..5711ed92 100644 --- a/broker/gen/model/Plot.cpp +++ b/broker/gen/model/Plot.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Plot.h b/broker/gen/model/Plot.h index 3e17c33b..97856aa5 100644 --- a/broker/gen/model/Plot.h +++ b/broker/gen/model/Plot.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Plot_unit_x.cpp b/broker/gen/model/Plot_unit_x.cpp index 6b66e1c4..3d72fd6e 100644 --- a/broker/gen/model/Plot_unit_x.cpp +++ b/broker/gen/model/Plot_unit_x.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Plot_unit_x.h b/broker/gen/model/Plot_unit_x.h index 51e0cf3a..de8f4172 100644 --- a/broker/gen/model/Plot_unit_x.h +++ b/broker/gen/model/Plot_unit_x.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Plots.cpp b/broker/gen/model/Plots.cpp index 9dc4bb2e..5cbad676 100644 --- a/broker/gen/model/Plots.cpp +++ b/broker/gen/model/Plots.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Plots.h b/broker/gen/model/Plots.h index 057180f2..71c9c05c 100644 --- a/broker/gen/model/Plots.h +++ b/broker/gen/model/Plots.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Roi_azim_list.cpp b/broker/gen/model/Roi_azim_list.cpp index 5d744d80..e2ee20ae 100644 --- a/broker/gen/model/Roi_azim_list.cpp +++ b/broker/gen/model/Roi_azim_list.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Roi_azim_list.h b/broker/gen/model/Roi_azim_list.h index 420335db..03f436e3 100644 --- a/broker/gen/model/Roi_azim_list.h +++ b/broker/gen/model/Roi_azim_list.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Roi_azimuthal.cpp b/broker/gen/model/Roi_azimuthal.cpp index 2023a549..5c903e0b 100644 --- a/broker/gen/model/Roi_azimuthal.cpp +++ b/broker/gen/model/Roi_azimuthal.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Roi_azimuthal.h b/broker/gen/model/Roi_azimuthal.h index e3389f02..943a6f77 100644 --- a/broker/gen/model/Roi_azimuthal.h +++ b/broker/gen/model/Roi_azimuthal.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Roi_box.cpp b/broker/gen/model/Roi_box.cpp index b543e30c..b1664b7d 100644 --- a/broker/gen/model/Roi_box.cpp +++ b/broker/gen/model/Roi_box.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Roi_box.h b/broker/gen/model/Roi_box.h index 3e55497d..3bc1b72f 100644 --- a/broker/gen/model/Roi_box.h +++ b/broker/gen/model/Roi_box.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Roi_box_list.cpp b/broker/gen/model/Roi_box_list.cpp index 62900421..36460062 100644 --- a/broker/gen/model/Roi_box_list.cpp +++ b/broker/gen/model/Roi_box_list.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Roi_box_list.h b/broker/gen/model/Roi_box_list.h index 39311d2d..81117e51 100644 --- a/broker/gen/model/Roi_box_list.h +++ b/broker/gen/model/Roi_box_list.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Roi_circle.cpp b/broker/gen/model/Roi_circle.cpp index a94a8f06..75666ff1 100644 --- a/broker/gen/model/Roi_circle.cpp +++ b/broker/gen/model/Roi_circle.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Roi_circle.h b/broker/gen/model/Roi_circle.h index a35ad1d0..486530ef 100644 --- a/broker/gen/model/Roi_circle.h +++ b/broker/gen/model/Roi_circle.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Roi_circle_list.cpp b/broker/gen/model/Roi_circle_list.cpp index 1ed887f3..e256becf 100644 --- a/broker/gen/model/Roi_circle_list.cpp +++ b/broker/gen/model/Roi_circle_list.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Roi_circle_list.h b/broker/gen/model/Roi_circle_list.h index e7feedaa..3e336566 100644 --- a/broker/gen/model/Roi_circle_list.h +++ b/broker/gen/model/Roi_circle_list.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Roi_definitions.cpp b/broker/gen/model/Roi_definitions.cpp index 2bf0a7db..a08ed980 100644 --- a/broker/gen/model/Roi_definitions.cpp +++ b/broker/gen/model/Roi_definitions.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Roi_definitions.h b/broker/gen/model/Roi_definitions.h index 2d9f7e23..2a5dd498 100644 --- a/broker/gen/model/Roi_definitions.h +++ b/broker/gen/model/Roi_definitions.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Rotation_axis.cpp b/broker/gen/model/Rotation_axis.cpp index eaae1ebf..cddb5981 100644 --- a/broker/gen/model/Rotation_axis.cpp +++ b/broker/gen/model/Rotation_axis.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Rotation_axis.h b/broker/gen/model/Rotation_axis.h index f17bcaec..f31fec6f 100644 --- a/broker/gen/model/Rotation_axis.h +++ b/broker/gen/model/Rotation_axis.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Scan_result.cpp b/broker/gen/model/Scan_result.cpp index f79bba3a..b2061adc 100644 --- a/broker/gen/model/Scan_result.cpp +++ b/broker/gen/model/Scan_result.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Scan_result.h b/broker/gen/model/Scan_result.h index 8df8107a..96be9c34 100644 --- a/broker/gen/model/Scan_result.h +++ b/broker/gen/model/Scan_result.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Scan_result_images_inner.cpp b/broker/gen/model/Scan_result_images_inner.cpp index 5237e9ac..918225ed 100644 --- a/broker/gen/model/Scan_result_images_inner.cpp +++ b/broker/gen/model/Scan_result_images_inner.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Scan_result_images_inner.h b/broker/gen/model/Scan_result_images_inner.h index e3bc29aa..d52c7d0e 100644 --- a/broker/gen/model/Scan_result_images_inner.h +++ b/broker/gen/model/Scan_result_images_inner.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Spot_finding_settings.cpp b/broker/gen/model/Spot_finding_settings.cpp index 659956d8..5ecb3efb 100644 --- a/broker/gen/model/Spot_finding_settings.cpp +++ b/broker/gen/model/Spot_finding_settings.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Spot_finding_settings.h b/broker/gen/model/Spot_finding_settings.h index 0723eab0..0a9fee6c 100644 --- a/broker/gen/model/Spot_finding_settings.h +++ b/broker/gen/model/Spot_finding_settings.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Standard_detector_geometry.cpp b/broker/gen/model/Standard_detector_geometry.cpp index 601f648f..b07099e7 100644 --- a/broker/gen/model/Standard_detector_geometry.cpp +++ b/broker/gen/model/Standard_detector_geometry.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Standard_detector_geometry.h b/broker/gen/model/Standard_detector_geometry.h index 23da4684..0f60f7a4 100644 --- a/broker/gen/model/Standard_detector_geometry.h +++ b/broker/gen/model/Standard_detector_geometry.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Unit_cell.cpp b/broker/gen/model/Unit_cell.cpp index c41aad18..9e9a2550 100644 --- a/broker/gen/model/Unit_cell.cpp +++ b/broker/gen/model/Unit_cell.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Unit_cell.h b/broker/gen/model/Unit_cell.h index 1b94ae0e..cf0be3ba 100644 --- a/broker/gen/model/Unit_cell.h +++ b/broker/gen/model/Unit_cell.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Zeromq_metadata_settings.cpp b/broker/gen/model/Zeromq_metadata_settings.cpp index b82150cb..205da034 100644 --- a/broker/gen/model/Zeromq_metadata_settings.cpp +++ b/broker/gen/model/Zeromq_metadata_settings.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Zeromq_metadata_settings.h b/broker/gen/model/Zeromq_metadata_settings.h index 246f9a3d..2f35ccc0 100644 --- a/broker/gen/model/Zeromq_metadata_settings.h +++ b/broker/gen/model/Zeromq_metadata_settings.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Zeromq_preview_settings.cpp b/broker/gen/model/Zeromq_preview_settings.cpp index a7fc5b3b..38d65781 100644 --- a/broker/gen/model/Zeromq_preview_settings.cpp +++ b/broker/gen/model/Zeromq_preview_settings.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Zeromq_preview_settings.h b/broker/gen/model/Zeromq_preview_settings.h index ae970276..27a2eb48 100644 --- a/broker/gen/model/Zeromq_preview_settings.h +++ b/broker/gen/model/Zeromq_preview_settings.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Zeromq_settings.cpp b/broker/gen/model/Zeromq_settings.cpp index c0ac5002..96361b6c 100644 --- a/broker/gen/model/Zeromq_settings.cpp +++ b/broker/gen/model/Zeromq_settings.cpp @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Zeromq_settings.h b/broker/gen/model/Zeromq_settings.h index 93dccbac..b674ba2a 100644 --- a/broker/gen/model/Zeromq_settings.h +++ b/broker/gen/model/Zeromq_settings.h @@ -2,7 +2,7 @@ * 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.123 +* The version of the OpenAPI document: 1.0.0-rc.124 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/jfjoch_api.yaml b/broker/jfjoch_api.yaml index 57b1445c..07dba754 100644 --- a/broker/jfjoch_api.yaml +++ b/broker/jfjoch_api.yaml @@ -22,7 +22,7 @@ info: requirements on applications that merely interact with the API, regardless of whether they communicate through network calls or other mechanisms. - version: 1.0.0-rc.123 + version: 1.0.0-rc.124 contact: name: Filip Leonarski (Paul Scherrer Institute) email: filip.leonarski@psi.ch diff --git a/broker/redoc-static.html b/broker/redoc-static.html index 426aa7e7..61880b22 100644 --- a/broker/redoc-static.html +++ b/broker/redoc-static.html @@ -411,7 +411,7 @@ This format doesn't transmit information about X-axis, only values, so it i 55.627 l 55.6165,55.627 -231.245496,231.24803 c -127.185,127.1864 -231.5279,231.248 -231.873,231.248 -0.3451,0 -104.688, -104.0616 -231.873,-231.248 z - " fill="currentColor">

Jungfraujoch (1.0.0-rc.123)

Download OpenAPI specification:

Filip Leonarski (Paul Scherrer Institute): filip.leonarski@psi.ch License: GPL-3.0

Jungfraujoch (1.0.0-rc.124)

Download OpenAPI specification:

Filip Leonarski (Paul Scherrer Institute): filip.leonarski@psi.ch License: GPL-3.0

API to control Jungfraujoch developed by the Paul Scherrer Institute (Switzerland). @@ -1376,8 +1376,8 @@ This format doesn't transmit information about X-axis, only values, so it i " class="sc-eVqvcJ sc-fszimp kIppRw drqpJr">

Quality of JPEG image (100 - highest; 0 - lowest)

show_res_ring
number <float> [ 0.1 .. 100 ]
Default: 0.1

Show resolution ring, provided in Angstrom

-
color
string
Default: "indigo"
Enum: "indigo" "viridis" "bw" "wb" "green" "heat" "magma" "inferno"

Color scale for preview image: 0 - indigo, 1 - viridis, 2 - B/W, 3 - heat

+
color
string
Default: "indigo"
Enum: "indigo" "viridis" "bw" "wb" "green" "heat" "magma" "inferno"

Color scale for preview image

show_res_est
boolean
Default: false

Show resolution estimation as a ring

Responses