From 56764a948bd4246b2d067634a544fa20e7075806 Mon Sep 17 00:00:00 2001 From: leonarski_f Date: Thu, 28 May 2026 21:54:58 +0200 Subject: [PATCH 01/27] JFJochHDF5Reader: Read spots for one image --- reader/JFJochHDF5Reader.cpp | 391 ++++++++++++++++++++---------------- reader/JFJochHDF5Reader.h | 10 +- tests/JFJochReaderTest.cpp | 335 ++++++++++++++++++++++++++++++ 3 files changed, 559 insertions(+), 177 deletions(-) diff --git a/reader/JFJochHDF5Reader.cpp b/reader/JFJochHDF5Reader.cpp index 6a5f4f05..66cb9a2a 100644 --- a/reader/JFJochHDF5Reader.cpp +++ b/reader/JFJochHDF5Reader.cpp @@ -604,10 +604,10 @@ void JFJochHDF5Reader::ReadFile(const std::string &filename) { ); if (mask_tmp.empty()) mask_tmp = master_file->ReadOptVector( - "/entry/instrument/detector/detectorSpecific/pixel_mask", - {0, 0}, - {image_size_y, image_size_x} - ); + "/entry/instrument/detector/detectorSpecific/pixel_mask", + {0, 0}, + {image_size_y, image_size_x} + ); if (mask_tmp.empty()) mask_tmp = std::vector(image_size_x * image_size_y); dataset->pixel_mask = PixelMask(mask_tmp); @@ -714,6 +714,123 @@ std::shared_ptr JFJochHDF5Reader::GetRawImage(int64_t imag return ret; } +// Reads spot data for a single image from the appropriate HDF5 source. +// master_image / source_image are the logical indices within master_file and +// source_file respectively (identical for NXmxVDS contiguous / integrated; +// differ for NXmxLegacy and NXmxVDS virtual layouts). +// Appends assembled SpotToSave entries to message.spots and fills the +// spot_count* fields; does NOT touch the image pixel data. +static void ReadSpotsFromFiles(HDF5Object &master_file, + HDF5Object &source_file, + hsize_t master_image, + hsize_t source_image, + int64_t image_number, + const DiffractionGeometry &geom, + DataMessage &message) { + auto spot_count_opt = ReadElementMasterFirst(master_file, + source_file, + "/entry/MX/nPeaks", + master_image, + source_image); + if (!spot_count_opt.has_value() || spot_count_opt.value() == 0) + return; + + const size_t spot_count = spot_count_opt.value(); + + auto spot_x = ReadVectorMasterFirst( + master_file, source_file, + "/entry/MX/peakXPosRaw", + {master_image, 0}, {source_image, 0}, {1, spot_count} + ); + auto spot_y = ReadVectorMasterFirst( + master_file, source_file, + "/entry/MX/peakYPosRaw", + {master_image, 0}, {source_image, 0}, {1, spot_count} + ); + auto spot_intensity = ReadVectorMasterFirst( + master_file, source_file, + "/entry/MX/peakTotalIntensity", + {master_image, 0}, {source_image, 0}, {1, spot_count} + ); + + if (spot_x.size() < spot_count || spot_y.size() < spot_count || spot_intensity.size() < spot_count) + throw JFJochException(JFJochExceptionCategory::HDF5, "Wrong size of spot dataset"); + + auto spot_indexed = ReadVectorMasterFirst( + master_file, source_file, + "/entry/MX/peakIndexed", + {master_image, 0}, {source_image, 0}, {1, spot_count} + ); + auto spot_ice = ReadVectorMasterFirst( + master_file, source_file, + "/entry/MX/peakIceRingRes", + {master_image, 0}, {source_image, 0}, {1, spot_count} + ); + auto spot_h = ReadVectorMasterFirst( + master_file, source_file, + "/entry/MX/peakH", + {master_image, 0}, {source_image, 0}, {1, spot_count} + ); + auto spot_k = ReadVectorMasterFirst( + master_file, source_file, + "/entry/MX/peakK", + {master_image, 0}, {source_image, 0}, {1, spot_count} + ); + auto spot_l = ReadVectorMasterFirst( + master_file, source_file, + "/entry/MX/peakL", + {master_image, 0}, {source_image, 0}, {1, spot_count} + ); + auto spot_dist_ewald_sphere = ReadVectorMasterFirst( + master_file, source_file, + "/entry/MX/peakDistEwaldSphere", + {master_image, 0}, {source_image, 0}, {1, spot_count} + ); + + message.spots.reserve(message.spots.size() + spot_count); + for (size_t i = 0; i < spot_count; i++) { + const auto x = spot_x.at(i); + const auto y = spot_y.at(i); + + SpotToSave s{ + .x = x, + .y = y, + .intensity = spot_intensity.at(i), + .d_A = geom.PxlToRes(x, y), + .image = image_number + }; + if (spot_indexed.size() > i) + s.indexed = (spot_indexed.at(i) != 0); + if (spot_h.size() > i) + s.h = spot_h.at(i); + if (spot_k.size() > i) + s.k = spot_k.at(i); + if (spot_l.size() > i) + s.l = spot_l.at(i); + if (spot_dist_ewald_sphere.size() > i) + s.dist_ewald_sphere = spot_dist_ewald_sphere.at(i); + if (spot_ice.size() > i) + s.ice_ring = (spot_ice.at(i) != 0); + message.spots.emplace_back(s); + } + + if (auto v = ReadElementMasterFirst(master_file, source_file, + "/entry/MX/peakCountUnfiltered", + master_image, source_image); v) + message.spot_count = v; + else + message.spot_count = spot_count_opt; + + message.spot_count_ice_rings = ReadElementMasterFirst( + master_file, source_file, "/entry/MX/peakCountIceRingRes", master_image, source_image); + message.spot_count_low_res = ReadElementMasterFirst( + master_file, source_file, "/entry/MX/peakCountLowRes", master_image, source_image); + message.spot_count_indexed = ReadElementMasterFirst( + master_file, source_file, "/entry/MX/peakCountIndexed", master_image, source_image); + + GenerateSpotPlot(message, 1.5); +} + bool JFJochHDF5Reader::LoadImage_i(std::shared_ptr &dataset, DataMessage &message, std::vector &buffer, @@ -736,165 +853,33 @@ bool JFJochHDF5Reader::LoadImage_i(std::shared_ptr &dataset const auto master_image = static_cast(image_number); const auto source_image = static_cast(image_id); - auto spot_count_opt = ReadElementMasterFirst(*master_file, - *source_file, - "/entry/MX/nPeaks", - master_image, - source_image); - - if (spot_count_opt.has_value() && spot_count_opt.value() > 0) { - size_t spot_count = spot_count_opt.value(); - - auto spot_x = ReadVectorMasterFirst( - *master_file, - *source_file, - "/entry/MX/peakXPosRaw", - {master_image, 0}, - {source_image, 0}, - {1, spot_count} - ); - auto spot_y = ReadVectorMasterFirst( - *master_file, - *source_file, - "/entry/MX/peakYPosRaw", - {master_image, 0}, - {source_image, 0}, - {1, spot_count} - ); - auto spot_intensity = ReadVectorMasterFirst( - *master_file, - *source_file, - "/entry/MX/peakTotalIntensity", - {master_image, 0}, - {source_image, 0}, - {1, spot_count} - ); - - if (spot_x.size() < spot_count || spot_y.size() < spot_count || spot_intensity.size() < spot_count) - throw JFJochException(JFJochExceptionCategory::HDF5, "Wrong size of spot dataset"); - - auto spot_indexed = ReadVectorMasterFirst( - *master_file, - *source_file, - "/entry/MX/peakIndexed", - {master_image, 0}, - {source_image, 0}, - {1, spot_count} - ); - - auto spot_ice = ReadVectorMasterFirst( - *master_file, - *source_file, - "/entry/MX/peakIceRingRes", - {master_image, 0}, - {source_image, 0}, - {1, spot_count} - ); - - auto spot_h = ReadVectorMasterFirst( - *master_file, - *source_file, - "/entry/MX/peakH", - {master_image, 0}, - {source_image, 0}, - {1, spot_count} - ); - - auto spot_k = ReadVectorMasterFirst( - *master_file, - *source_file, - "/entry/MX/peakK", - {master_image, 0}, - {source_image, 0}, - {1, spot_count} - ); - - auto spot_l = ReadVectorMasterFirst( - *master_file, - *source_file, - "/entry/MX/peakL", - {master_image, 0}, - {source_image, 0}, - {1, spot_count} - ); - - auto spot_dist_ewald_sphere = ReadVectorMasterFirst( - *master_file, - *source_file, - "/entry/MX/peakDistEwaldSphere", - {master_image, 0}, - {source_image, 0}, - {1, spot_count} - ); - - auto geom = dataset->experiment.GetDiffractionGeometry(); - for (int i = 0; i < spot_count; i++) { - auto x = spot_x.at(i); - auto y = spot_y.at(i); - auto d = geom.PxlToRes(x, y); - - SpotToSave s{ - .x = x, - .y = y, - .intensity = spot_intensity.at(i), - .d_A = d, - .image = image_number - }; - if (spot_indexed.size() > i) - s.indexed = (spot_indexed.at(i) != 0); - if (spot_h.size() > i) - s.h = spot_h.at(i); - if (spot_k.size() > i) - s.k = spot_k.at(i); - if (spot_l.size() > i) - s.l = spot_l.at(i); - if (spot_dist_ewald_sphere.size() > i) - s.dist_ewald_sphere = spot_dist_ewald_sphere.at(i); - if (spot_ice.size() > i) - s.ice_ring = (spot_ice.at(i) != 0); - message.spots.emplace_back(s); - } - - if (auto v = ReadElementMasterFirst(*master_file, *source_file, - "/entry/MX/peakCountUnfiltered", - master_image, source_image); v) - message.spot_count = v; - else - message.spot_count = spot_count_opt; - - message.spot_count_ice_rings = ReadElementMasterFirst( - *master_file, *source_file, "/entry/MX/peakCountIceRingRes", master_image, source_image); - message.spot_count_low_res = ReadElementMasterFirst( - *master_file, *source_file, "/entry/MX/peakCountLowRes", master_image, source_image); - message.spot_count_indexed = ReadElementMasterFirst( - *master_file, *source_file, "/entry/MX/peakCountIndexed", master_image, source_image); - - GenerateSpotPlot(message, 1.5); - } + ReadSpotsFromFiles(*master_file, *source_file, master_image, source_image, + image_number, dataset->experiment.GetDiffractionGeometry(), message); if (!dataset->az_int_bin_to_q.empty()) { if (dataset->azimuthal_bins == 0) { message.az_int_profile = ReadVectorMasterFirst( - *master_file, - *source_file, - "/entry/azint/image", - {master_image, 0}, - {source_image, 0}, - {1, dataset->az_int_bin_to_q.size()} + *master_file, + *source_file, + "/entry/azint/image", + {master_image, 0}, + {source_image, 0}, + {1, dataset->az_int_bin_to_q.size()} ); } else { message.az_int_profile = ReadVectorMasterFirst( - *master_file, - *source_file, - "/entry/azint/image", - {master_image, 0, 0}, - {source_image, 0, 0}, - {1, dataset->azimuthal_bins, dataset->q_bins} + *master_file, + *source_file, + "/entry/azint/image", + {master_image, 0, 0}, + {source_image, 0, 0}, + {1, dataset->azimuthal_bins, dataset->q_bins} ); } } if (dataset->integrated_reflections.size() > image_number) - message.integrated_reflections = static_cast(std::lround(dataset->integrated_reflections.at(image_number))); + message.integrated_reflections = static_cast(std::lround( + dataset->integrated_reflections.at(image_number))); if (dataset->resolution_estimate.size() > image_number) message.resolution_estimate = dataset->resolution_estimate[image_number]; if (dataset->indexing_result.size() > image_number) @@ -918,13 +903,13 @@ bool JFJochHDF5Reader::LoadImage_i(std::shared_ptr &dataset && (master_file->Exists("/entry/MX/latticeIndexed") || source_file->Exists("/entry/MX/latticeIndexed"))) { std::vector tmp = ReadVectorMasterFirst( - *master_file, - *source_file, - "/entry/MX/latticeIndexed", - {master_image, 0}, - {source_image, 0}, - {1, 9} - ); + *master_file, + *source_file, + "/entry/MX/latticeIndexed", + {master_image, 0}, + {source_image, 0}, + {1, 9} + ); if (tmp.size() == 9) message.indexing_lattice = CrystalLattice(tmp); @@ -1055,7 +1040,7 @@ void AppendOrExtendSourceMapping(std::vector &ret, && last.virtual_first_image + last.image_count == virtual_first_image) { last.image_count += image_count; return; - } + } } ret.push_back(HDF5DataSourceMessage{ @@ -1067,10 +1052,8 @@ void AppendOrExtendSourceMapping(std::vector &ret, }); }; -std::vector JFJochHDF5Reader::GetHDF5DataSource( - uint64_t first_image, - std::optional image_count -) const { +std::vector JFJochHDF5Reader::GetHDF5DataSource(uint64_t first_image, + std::optional image_count) const { std::unique_lock ul(hdf5_mutex); if (!master_file) @@ -1164,7 +1147,8 @@ std::vector JFJochHDF5Reader::GetHDF5DataSource( } -std::vector JFJochHDF5Reader::ReadReflections(size_t start_image, std::optional end_image) const { +std::vector JFJochHDF5Reader::ReadReflections(size_t start_image, + std::optional end_image) const { std::unique_lock ul(hdf5_mutex); if (start_image >= number_of_images) @@ -1187,7 +1171,7 @@ std::vector JFJochHDF5Reader::ReadReflections(size_t start_i // Cache of data files opened during this call (keyed by path) to avoid // re-opening the same file for every image in a multi-image batch. - std::map> open_files; + std::map > open_files; auto get_data_file = [&](const std::string &path) -> std::shared_ptr { auto it = open_files.find(path); @@ -1233,22 +1217,87 @@ std::vector JFJochHDF5Reader::ReadReflections(size_t start_i if (meta_file->Exists("/entry/MX/mosaicity")) { try { outcome.mosaicity_deg = - meta_file->ReadElement("/entry/MX/mosaicity", meta_image_id); - } catch (...) {} + meta_file->ReadElement("/entry/MX/mosaicity", meta_image_id); + } catch (...) { + } } // ── indexed lattice (stored as 9-element row-major matrix) ──────────── if (meta_file->Exists("/entry/MX/latticeIndexed")) { try { auto lattice_vec = meta_file->ReadOptVector( - "/entry/MX/latticeIndexed",{meta_image_id, 0}, {1, 9}); + "/entry/MX/latticeIndexed", {meta_image_id, 0}, {1, 9}); if (lattice_vec.size() == 9) outcome.latt = CrystalLattice(lattice_vec); - } catch (...) {} + } catch (...) { + } } ret.push_back(std::move(outcome)); } return ret; -} \ No newline at end of file +} + +std::vector JFJochHDF5Reader::ReadSpots(size_t image) const { + std::unique_lock ul(hdf5_mutex); + + if (image >= number_of_images) + throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, + "image must be less than number_of_images"); + + if (!master_file) + throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, + "Cannot read spots if file not loaded"); + + // Cache of data files opened during this call (keyed by path) to avoid + // re-opening the same file for every image in a multi-image batch. + std::map > open_files; + + auto get_data_file = [&](const std::string &path) -> std::shared_ptr { + auto it = open_files.find(path); + if (it != open_files.end()) + return it->second; + auto f = std::make_shared(path); + open_files[path] = f; + return f; + }; + + std::vector ret; + + // Resolve which HDF5 file and local image index hold the MX spot data. + // Uses the same logic as LoadImage_i / ReadReflections so all three + // code paths stay in sync. + HDF5Object *meta_file = master_file.get(); + size_t meta_image_id = image; + + std::shared_ptr owned_source; + + if (format == FileWriterFormat::NXmxLegacy) { + const size_t file_id = image / images_per_file; + meta_image_id = image % images_per_file; + owned_source = get_data_file(legacy_format_files.at(file_id)); + meta_file = owned_source.get(); + } else if (format == FileWriterFormat::NXmxVDS && data_layout == HDF5DataSetLayout::VIRTUAL) { + for (const auto &mapping: vds_data_mappings) { + if (!mapping.ContainsVirtualImage(image)) + continue; + meta_image_id = mapping.SourceImage(image); + owned_source = get_data_file(ResolveRelativeToMaster(master_file_directory, mapping.filename)); + meta_file = owned_source.get(); + break; + } + } + // NXmxVDS contiguous / NXmxIntegrated: master_file with global index — + // the defaults set above are already correct. + DataMessage tmp_message; + tmp_message.number = static_cast(image); + + ReadSpotsFromFiles(*master_file, *meta_file, + image, meta_image_id, + static_cast(image), + cached_geom, + tmp_message); + + return tmp_message.spots; +} diff --git a/reader/JFJochHDF5Reader.h b/reader/JFJochHDF5Reader.h index f952462a..f517f17c 100644 --- a/reader/JFJochHDF5Reader.h +++ b/reader/JFJochHDF5Reader.h @@ -1,8 +1,7 @@ // SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only -#ifndef JFJOCHHDF5IMAGEREADER_H -#define JFJOCHHDF5IMAGEREADER_H +#pragma once #include "JFJochReader.h" #include "../writer/HDF5Objects.h" @@ -57,10 +56,9 @@ public: std::vector ReadReflections(size_t start_image = 0, std::optional end_image = {}) const; + std::vector ReadSpots(size_t image) const; + CompressedImage ReadCalibration(std::vector &tmp, const std::string &name) const; std::shared_ptr GetRawImage(int64_t image_number) override; -}; - - -#endif //JFJOCHHDF5IMAGEREADER_H \ No newline at end of file +}; \ No newline at end of file diff --git a/tests/JFJochReaderTest.cpp b/tests/JFJochReaderTest.cpp index 332e4bf9..cd7e556f 100644 --- a/tests/JFJochReaderTest.cpp +++ b/tests/JFJochReaderTest.cpp @@ -2042,5 +2042,340 @@ TEST_CASE("JFJochReader_ReadReflections_VDS", "[HDF5][Full]") { remove("read_reflections_vds_data_000003.h5"); remove("read_reflections_vds_data_000004.h5"); + REQUIRE(H5Fget_obj_count(H5F_OBJ_ALL, H5F_OBJ_ALL) == 0); +} + +static std::vector MakeTestSpots(int i) { + return { + SpotToSave{ + .x = 1, .y = 2, .intensity = 376, + .ice_ring = true, + .indexed = true, + .h = 11, .k = -3, .l = -5, + .dist_ewald_sphere = 0.1234f + }, + SpotToSave{ + .x = 7, .y = static_cast(-3 - i), .intensity = 0.156f, + .ice_ring = false, + .indexed = false, + } + }; +} + +// Assert the full field set on spots[0] and the per-image variation on +// spots[1].y, which is the only field that differs across images. +static void CheckSpotFields(const SpotToSave &s0, const SpotToSave &s1, int i) { + CHECK(s0.x == 1); + CHECK(s0.y == 2); + CHECK(s0.intensity == Catch::Approx(376)); + CHECK(s0.ice_ring == true); + CHECK(s0.indexed == true); + CHECK(s0.h == 11); + CHECK(s0.k == -3); + CHECK(s0.l == -5); + CHECK(s0.dist_ewald_sphere == Catch::Approx(0.1234f)); + CHECK(s0.image == i); + + CHECK(s1.x == Catch::Approx(7)); + CHECK(s1.y == Catch::Approx(static_cast(-3 - i))); + CHECK(s1.intensity == Catch::Approx(0.156f)); + CHECK(s1.ice_ring == false); + CHECK(s1.indexed == false); + CHECK(s1.image == i); +} + +TEST_CASE("JFJochReader_ReadSpots_Legacy", "[HDF5][Full]") { + DiffractionExperiment x(DetJF(1)); + + x.FilePrefix("read_spots_legacy") + .ImagesPerTrigger(4) + .ImagesPerFile(1) + .OverwriteExistingFiles(true) + .BitDepthImage(16) + .PixelSigned(true) + .SetFileWriterFormat(FileWriterFormat::NXmxLegacy) + .IndexingAlgorithm(IndexingAlgorithmEnum::FFT) + .Compression(CompressionAlgorithm::NO_COMPRESSION); + + std::vector image(x.GetPixelsNum(), 0); + + RegisterHDF5Filter(); + { + StartMessage start_message; + x.FillMessage(start_message); + FileWriter file_set(start_message); + + for (int i = 0; i < x.GetImageNum(); i++) { + DataMessage message{}; + message.image = CompressedImage(image, x.GetXPixelsNum(), x.GetYPixelsNum()); + message.number = i; + message.spots = MakeTestSpots(i); + message.spot_count = 72 + i; + message.spot_count_ice_rings = 45 + 2 * i; + message.spot_count_low_res = 12 + 3 * i; + message.spot_count_indexed = 15 + 4 * i; + REQUIRE_NOTHROW(file_set.WriteHDF5(message)); + } + + EndMessage end_message; + end_message.max_image_number = x.GetImageNum(); + file_set.WriteHDF5(end_message); + file_set.Finalize(); + } + + // All images, one at a time + { + JFJochHDF5Reader reader; + REQUIRE_NOTHROW(reader.ReadFile("read_spots_legacy_master.h5")); + + for (int i = 0; i < 4; i++) { + std::vector spots; + REQUIRE_NOTHROW(spots = reader.ReadSpots(i)); + REQUIRE(spots.size() == 2); + CheckSpotFields(spots[0], spots[1], i); + } + } + + // Out-of-range must throw + { + JFJochHDF5Reader reader; + REQUIRE_NOTHROW(reader.ReadFile("read_spots_legacy_master.h5")); + REQUIRE_THROWS(reader.ReadSpots(4)); + } + + remove("read_spots_legacy_master.h5"); + remove("read_spots_legacy_data_000001.h5"); + remove("read_spots_legacy_data_000002.h5"); + remove("read_spots_legacy_data_000003.h5"); + remove("read_spots_legacy_data_000004.h5"); + + REQUIRE(H5Fget_obj_count(H5F_OBJ_ALL, H5F_OBJ_ALL) == 0); +} + +TEST_CASE("JFJochReader_ReadSpots_VDS", "[HDF5][Full]") { + DiffractionExperiment x(DetJF(1)); + + x.FilePrefix("read_spots_vds") + .ImagesPerTrigger(4) + .ImagesPerFile(1) + .OverwriteExistingFiles(true) + .BitDepthImage(16) + .PixelSigned(true) + .SetFileWriterFormat(FileWriterFormat::NXmxVDS) + .IndexingAlgorithm(IndexingAlgorithmEnum::FFT) + .Compression(CompressionAlgorithm::NO_COMPRESSION); + + std::vector image(x.GetPixelsNum(), 0); + + RegisterHDF5Filter(); + { + StartMessage start_message; + x.FillMessage(start_message); + FileWriter file_set(start_message); + + for (int i = 0; i < x.GetImageNum(); i++) { + DataMessage message{}; + message.image = CompressedImage(image, x.GetXPixelsNum(), x.GetYPixelsNum()); + message.number = i; + message.spots = MakeTestSpots(i); + message.spot_count = 72 + i; + message.spot_count_ice_rings = 45 + 2 * i; + message.spot_count_low_res = 12 + 3 * i; + message.spot_count_indexed = 15 + 4 * i; + REQUIRE_NOTHROW(file_set.WriteHDF5(message)); + } + + EndMessage end_message; + end_message.max_image_number = x.GetImageNum(); + file_set.WriteHDF5(end_message); + file_set.Finalize(); + } + + // All images, one at a time — also verifies that .image carries the + // correct global index across the virtual-to-source remapping. + { + JFJochHDF5Reader reader; + REQUIRE_NOTHROW(reader.ReadFile("read_spots_vds_master.h5")); + + for (int i = 0; i < 4; i++) { + std::vector spots; + REQUIRE_NOTHROW(spots = reader.ReadSpots(i)); + REQUIRE(spots.size() == 2); + CheckSpotFields(spots[0], spots[1], i); + } + } + + // Out-of-range must throw + { + JFJochHDF5Reader reader; + REQUIRE_NOTHROW(reader.ReadFile("read_spots_vds_master.h5")); + REQUIRE_THROWS(reader.ReadSpots(4)); + } + + // Image with no spots returns an empty vector + { + JFJochHDF5Reader reader; + REQUIRE_NOTHROW(reader.ReadFile("read_spots_vds_master.h5")); + + // Write a separate 2-image VDS file where only image 0 has spots. + DiffractionExperiment y(DetJF(1)); + y.FilePrefix("read_spots_vds_sparse") + .ImagesPerTrigger(2) + .ImagesPerFile(1) + .OverwriteExistingFiles(true) + .BitDepthImage(16) + .PixelSigned(true) + .SetFileWriterFormat(FileWriterFormat::NXmxVDS) + .IndexingAlgorithm(IndexingAlgorithmEnum::FFT) + .Compression(CompressionAlgorithm::NO_COMPRESSION); + + { + StartMessage start_message; + y.FillMessage(start_message); + FileWriter file_set(start_message); + + for (int i = 0; i < 2; i++) { + DataMessage message{}; + message.image = CompressedImage(image, y.GetXPixelsNum(), y.GetYPixelsNum()); + message.number = i; + if (i == 0) + message.spots = MakeTestSpots(i); + REQUIRE_NOTHROW(file_set.WriteHDF5(message)); + } + + EndMessage end_message; + end_message.max_image_number = 2; + file_set.WriteHDF5(end_message); + file_set.Finalize(); + } + + JFJochHDF5Reader sparse_reader; + REQUIRE_NOTHROW(sparse_reader.ReadFile("read_spots_vds_sparse_master.h5")); + + std::vector spots_0, spots_1; + REQUIRE_NOTHROW(spots_0 = sparse_reader.ReadSpots(0)); + REQUIRE_NOTHROW(spots_1 = sparse_reader.ReadSpots(1)); + + REQUIRE(spots_0.size() == 2); + CHECK(spots_0[0].image == 0); + CHECK(spots_1.empty()); + + remove("read_spots_vds_sparse_master.h5"); + remove("read_spots_vds_sparse_data_000001.h5"); + remove("read_spots_vds_sparse_data_000002.h5"); + } + + remove("read_spots_vds_master.h5"); + remove("read_spots_vds_data_000001.h5"); + remove("read_spots_vds_data_000002.h5"); + remove("read_spots_vds_data_000003.h5"); + remove("read_spots_vds_data_000004.h5"); + + REQUIRE(H5Fget_obj_count(H5F_OBJ_ALL, H5F_OBJ_ALL) == 0); +} + +TEST_CASE("JFJochReader_ReadSpots_Integrated", "[HDF5][Full]") { + DiffractionExperiment x(DetJF(1)); + + x.FilePrefix("read_spots_integrated") + .ImagesPerTrigger(4) + .OverwriteExistingFiles(true) + .BitDepthImage(16) + .PixelSigned(true) + .SetFileWriterFormat(FileWriterFormat::NXmxIntegrated) + .IndexingAlgorithm(IndexingAlgorithmEnum::FFT) + .Compression(CompressionAlgorithm::NO_COMPRESSION); + + std::vector image(x.GetPixelsNum(), 0); + + RegisterHDF5Filter(); + { + StartMessage start_message; + x.FillMessage(start_message); + FileWriter file_set(start_message); + + for (int i = 0; i < x.GetImageNum(); i++) { + DataMessage message{}; + message.image = CompressedImage(image, x.GetXPixelsNum(), x.GetYPixelsNum()); + message.number = i; + message.spots = MakeTestSpots(i); + message.spot_count = 72 + i; + message.spot_count_ice_rings = 45 + 2 * i; + message.spot_count_low_res = 12 + 3 * i; + message.spot_count_indexed = 15 + 4 * i; + REQUIRE_NOTHROW(file_set.WriteHDF5(message)); + } + + EndMessage end_message; + end_message.max_image_number = x.GetImageNum(); + file_set.WriteHDF5(end_message); + file_set.Finalize(); + } + + // All images, one at a time + { + JFJochHDF5Reader reader; + REQUIRE_NOTHROW(reader.ReadFile("read_spots_integrated_master.h5")); + + for (int i = 0; i < 4; i++) { + std::vector spots; + REQUIRE_NOTHROW(spots = reader.ReadSpots(i)); + REQUIRE(spots.size() == 2); + CheckSpotFields(spots[0], spots[1], i); + } + } + + // Out-of-range must throw + { + JFJochHDF5Reader reader; + REQUIRE_NOTHROW(reader.ReadFile("read_spots_integrated_master.h5")); + REQUIRE_THROWS(reader.ReadSpots(4)); + } + + // Image with no spots returns an empty vector + { + DiffractionExperiment y(DetJF(1)); + y.FilePrefix("read_spots_integrated_sparse") + .ImagesPerTrigger(3) + .OverwriteExistingFiles(true) + .BitDepthImage(16) + .PixelSigned(true) + .SetFileWriterFormat(FileWriterFormat::NXmxIntegrated) + .IndexingAlgorithm(IndexingAlgorithmEnum::FFT) + .Compression(CompressionAlgorithm::NO_COMPRESSION); + + { + StartMessage start_message; + y.FillMessage(start_message); + FileWriter file_set(start_message); + + for (int i = 0; i < 3; i++) { + DataMessage message{}; + message.image = CompressedImage(image, y.GetXPixelsNum(), y.GetYPixelsNum()); + message.number = i; + if (i == 1) + message.spots = MakeTestSpots(i); + REQUIRE_NOTHROW(file_set.WriteHDF5(message)); + } + + EndMessage end_message; + end_message.max_image_number = 3; + file_set.WriteHDF5(end_message); + file_set.Finalize(); + } + + JFJochHDF5Reader reader; + REQUIRE_NOTHROW(reader.ReadFile("read_spots_integrated_sparse_master.h5")); + + CHECK(reader.ReadSpots(0).empty()); + REQUIRE(reader.ReadSpots(1).size() == 2); + CheckSpotFields(reader.ReadSpots(1)[0], reader.ReadSpots(1)[1], 1); + CHECK(reader.ReadSpots(2).empty()); + + remove("read_spots_integrated_sparse_master.h5"); + } + + remove("read_spots_integrated_master.h5"); + REQUIRE(H5Fget_obj_count(H5F_OBJ_ALL, H5F_OBJ_ALL) == 0); } \ No newline at end of file -- 2.52.0 From b44b0a56fbaa15d154db5ca1f2fb243199530b99 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Fri, 29 May 2026 12:01:58 +0200 Subject: [PATCH 02/27] RotationIndexer: For fixed space group, set explicitly lattice type and centering for refinement --- image_analysis/RotationIndexer.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/image_analysis/RotationIndexer.cpp b/image_analysis/RotationIndexer.cpp index cd7a04ea..8ed00d83 100644 --- a/image_analysis/RotationIndexer.cpp +++ b/image_analysis/RotationIndexer.cpp @@ -73,9 +73,19 @@ void RotationIndexer::TryIndex() { } auto indexer_result = indexer_.Run(experiment, coords_sel); - if (!indexer_result.lattice.empty()) { - // Find lattice type - search_result_ = LatticeSearch(indexer_result.lattice[0]); + if (!indexer_result.lattice.empty() && indexer_result.lattice[0].CalcVolume() > 1.0) { + auto sg = experiment.GetGemmiSpaceGroup(); + if (sg) { + search_result_ = LatticeSearchResult{ + .niggli_class = 0, // Since Niggli class was not searched for, we don't know which one + .conventional = indexer_result.lattice[0], // If lattice provided, it is for now primitive == conventional + .system = sg->crystal_system(), + .centering = sg->centring_type(), + }; + } else { + // Find lattice type based on cell + search_result_ = LatticeSearch(indexer_result.lattice[0]); + } // Run refinement DiffractionExperiment experiment_copy(experiment); @@ -97,6 +107,7 @@ void RotationIndexer::TryIndex() { if (data.crystal_system == gemmi::CrystalSystem::Monoclinic) data.latt.ReorderMonoclinic(); + if (XtalOptimizer(data, v_sel)) { indexed_lattice = data.latt; updated_geom_ = data.geom; -- 2.52.0 From 8660558341be487707036eaceefb2968248e341c Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Fri, 29 May 2026 12:23:26 +0200 Subject: [PATCH 03/27] JFJochHDF5Reader: Use lattice, and not Niggli class, to decode symmetry (if symmetry is imposed, then lattice search returns niggli class 0 --- reader/JFJochHDF5Reader.cpp | 106 ++++++++++++++++++++---------------- tests/JFJochReaderTest.cpp | 73 +++++++++++++++++++++++++ writer/HDF5Objects.h | 100 ++++++++++++++++++++++++++-------- 3 files changed, 208 insertions(+), 71 deletions(-) diff --git a/reader/JFJochHDF5Reader.cpp b/reader/JFJochHDF5Reader.cpp index 66cb9a2a..723a70a0 100644 --- a/reader/JFJochHDF5Reader.cpp +++ b/reader/JFJochHDF5Reader.cpp @@ -2,58 +2,62 @@ // SPDX-License-Identifier: GPL-3.0-only #include +#include + #include "JFJochHDF5Reader.h" #include "spdlog/fmt/fmt.h" #include "../image_analysis/bragg_integration/CalcISigma.h" #include "../image_analysis/spot_finding/SpotUtils.h" #include "../common/GridScanSettings.h" -inline std::pair parse_niggli_class(int64_t val) { - switch (val) { - case 1: return {gemmi::CrystalSystem::Cubic, 'F'}; - case 2: return {gemmi::CrystalSystem::Trigonal, 'R'}; - case 3: return {gemmi::CrystalSystem::Cubic, 'P'}; - case 5: return {gemmi::CrystalSystem::Cubic, 'I'}; - case 4: return {gemmi::CrystalSystem::Trigonal, 'R'}; - case 6: return {gemmi::CrystalSystem::Tetragonal, 'I'}; - case 7: return {gemmi::CrystalSystem::Tetragonal, 'I'}; - case 9: return {gemmi::CrystalSystem::Trigonal, 'R'}; - case 10: return {gemmi::CrystalSystem::Monoclinic, 'C'}; - case 11: return {gemmi::CrystalSystem::Tetragonal, 'P'}; - case 12: return {gemmi::CrystalSystem::Hexagonal, 'P'}; - case 13: return {gemmi::CrystalSystem::Orthorhombic, 'C'}; - case 15: return {gemmi::CrystalSystem::Tetragonal, 'I'}; - case 16: return {gemmi::CrystalSystem::Orthorhombic, 'F'}; - case 14: return {gemmi::CrystalSystem::Monoclinic, 'C'}; - case 17: return {gemmi::CrystalSystem::Monoclinic, 'C'}; - case 18: return {gemmi::CrystalSystem::Tetragonal, 'I'}; - case 19: return {gemmi::CrystalSystem::Orthorhombic, 'I'}; - case 20: return {gemmi::CrystalSystem::Monoclinic, 'C'}; - case 21: return {gemmi::CrystalSystem::Tetragonal, 'P'}; - case 22: return {gemmi::CrystalSystem::Hexagonal, 'P'}; - case 23: return {gemmi::CrystalSystem::Orthorhombic, 'C'}; - case 24: return {gemmi::CrystalSystem::Trigonal, 'R'}; - case 25: return {gemmi::CrystalSystem::Monoclinic, 'C'}; - case 26: return {gemmi::CrystalSystem::Orthorhombic, 'F'}; - case 27: return {gemmi::CrystalSystem::Monoclinic, 'C'}; - case 28: return {gemmi::CrystalSystem::Monoclinic, 'C'}; - case 29: return {gemmi::CrystalSystem::Monoclinic, 'C'}; - case 30: return {gemmi::CrystalSystem::Monoclinic, 'C'}; - case 31: return {gemmi::CrystalSystem::Triclinic, 'P'}; - case 32: return {gemmi::CrystalSystem::Orthorhombic, 'P'}; - case 40: return {gemmi::CrystalSystem::Orthorhombic, 'C'}; - case 35: return {gemmi::CrystalSystem::Monoclinic, 'P'}; - case 36: return {gemmi::CrystalSystem::Orthorhombic, 'C'}; - case 33: return {gemmi::CrystalSystem::Monoclinic, 'P'}; - case 38: return {gemmi::CrystalSystem::Orthorhombic, 'C'}; - case 34: return {gemmi::CrystalSystem::Monoclinic, 'P'}; - case 42: return {gemmi::CrystalSystem::Orthorhombic, 'I'}; - case 41: return {gemmi::CrystalSystem::Monoclinic, 'C'}; - case 37: return {gemmi::CrystalSystem::Monoclinic, 'C'}; - case 39: return {gemmi::CrystalSystem::Monoclinic, 'C'}; - case 44: return {gemmi::CrystalSystem::Triclinic, 'P'}; - default: return {gemmi::CrystalSystem::Triclinic, 'P'}; +inline std::pair parse_bravais_lattice(const std::string &val) { + if (val.empty()) + return {gemmi::CrystalSystem::Triclinic, 'P'}; + + if (val.size() != 2) + throw JFJochException(JFJochExceptionCategory::HDF5, "Wrong Bravais lattice encoding"); + + gemmi::CrystalSystem cs; + char centering = val[1]; + std::set allowed_centering; + + switch (val[0]) { + case 'a': + cs = gemmi::CrystalSystem::Triclinic; + allowed_centering = {'P'}; + break; + case 'm': + cs = gemmi::CrystalSystem::Monoclinic; + allowed_centering = {'P', 'A', 'B', 'C'}; + break; + case 'o': + cs = gemmi::CrystalSystem::Orthorhombic; + allowed_centering = {'P', 'A', 'B', 'C', 'I', 'F'}; + break; + case 't': + cs = gemmi::CrystalSystem::Tetragonal; + allowed_centering = {'P', 'I'}; + break; + case 'h': + if (centering == 'P') + cs = gemmi::CrystalSystem::Hexagonal; + else if (centering == 'R') + cs = gemmi::CrystalSystem::Trigonal; + allowed_centering = {'P', 'R'}; + break; + case 'c': + cs = gemmi::CrystalSystem::Cubic; + allowed_centering = {'P', 'F', 'I'}; + break; + default: + // allowed_centering is empty and exception will be always thrown + break; } + + if (!allowed_centering.contains(centering)) + throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Invalid lattice encoding " + val); + + return {cs, centering}; } std::vector GetDimension(HDF5Object &object, const std::string &path) { @@ -914,6 +918,12 @@ bool JFJochHDF5Reader::LoadImage_i(std::shared_ptr &dataset if (tmp.size() == 9) message.indexing_lattice = CrystalLattice(tmp); + std::optional lattice; + if (master_file->Exists("/entry/MX/bravaisLattice")) + lattice = master_file->ReadElement("/entry/MX/bravaisLattice", image_number); + else + lattice = source_file->ReadElement("/entry/MX/bravaisLattice", image_id); + std::optional niggli_opt; if (master_file->Exists("/entry/MX/niggli_class")) niggli_opt = master_file->ReadElement("/entry/MX/niggli_class", image_number); @@ -924,12 +934,12 @@ bool JFJochHDF5Reader::LoadImage_i(std::shared_ptr &dataset else if (source_file->Exists("/entry/MX/niggliClass")) niggli_opt = source_file->ReadElement("/entry/MX/niggliClass", image_id); - if (niggli_opt) { - auto symm_info = parse_niggli_class(niggli_opt.value()); + if (lattice && !lattice->empty()) { + auto symm_info = parse_bravais_lattice(lattice.value()); message.lattice_type = LatticeMessage{ .centering = symm_info.second, - .niggli_class = static_cast(niggli_opt.value()), + .niggli_class = static_cast(niggli_opt.value_or(0)), .crystal_system = symm_info.first, }; } diff --git a/tests/JFJochReaderTest.cpp b/tests/JFJochReaderTest.cpp index cd7e556f..d7635940 100644 --- a/tests/JFJochReaderTest.cpp +++ b/tests/JFJochReaderTest.cpp @@ -1038,6 +1038,79 @@ TEST_CASE("JFJochReader_NiggliClass", "[HDF5][Full]") { REQUIRE(H5Fget_obj_count(H5F_OBJ_ALL, H5F_OBJ_ALL) == 0); } +TEST_CASE("JFJochReader_NiggliClass_VDS", "[HDF5][Full]") { + DiffractionExperiment x(DetJF(1)); + x.FilePrefix("test95").ImagesPerTrigger(4).OverwriteExistingFiles(true); + x.BitDepthImage(16).ImagesPerFile(1).SetFileWriterFormat(FileWriterFormat::NXmxVDS).PixelSigned(true) + .IndexingAlgorithm(IndexingAlgorithmEnum::FFT); + x.Compression(CompressionAlgorithm::NO_COMPRESSION); + + std::vector image(x.GetPixelsNum()); + + RegisterHDF5Filter(); + { + StartMessage start_message; + x.FillMessage(start_message); + FileWriter file_set(start_message); + + LatticeMessage lm{ + .centering = 'F', + .niggli_class = 1, + .crystal_system = gemmi::CrystalSystem::Cubic, + }; + + DataMessage message{}; + message.number = 0; + message.image = CompressedImage(image, x.GetXPixelsNum(), x.GetYPixelsNum()); + message.indexing_result = true; + message.indexing_lattice = CrystalLattice(40, 50, 60, 90, 90, 90); + message.lattice_type = lm; + REQUIRE_NOTHROW(file_set.WriteHDF5(message)); + + message.number = 1; + message.indexing_result = false; + message.indexing_lattice = std::nullopt; + REQUIRE_NOTHROW(file_set.WriteHDF5(message)); + + EndMessage end_message; + end_message.max_image_number = 2; + file_set.WriteHDF5(end_message); + file_set.Finalize(); + } + { + JFJochHDF5Reader reader; + REQUIRE_NOTHROW(reader.ReadFile("test95_master.h5")); + auto dataset = reader.GetDataset(); + CHECK(dataset->experiment.GetImageNum() == 2); + + std::shared_ptr reader_image, reader_image_2; + + REQUIRE_NOTHROW(reader_image = reader.LoadImage(0)); + + REQUIRE(reader_image); + CHECK(reader_image->ImageData().indexing_result.value() == true); + REQUIRE(reader_image->ImageData().indexing_lattice); + REQUIRE(reader_image->ImageData().lattice_type); + CHECK(reader_image->ImageData().lattice_type->centering == 'F'); + CHECK(reader_image->ImageData().lattice_type->niggli_class == 1); + CHECK(reader_image->ImageData().lattice_type->crystal_system == gemmi::CrystalSystem::Cubic); + + REQUIRE_NOTHROW(reader_image_2 = reader.LoadImage(1)); + + REQUIRE(reader_image_2); + CHECK(!reader_image_2->ImageData().indexing_result.value()); + REQUIRE(!reader_image_2->ImageData().indexing_lattice); + REQUIRE(!reader_image_2->ImageData().lattice_type); + } + remove("test95_master.h5"); + remove("test95_data_000001.h5"); + remove("test95_data_000002.h5"); + + // No leftover HDF5 objects + REQUIRE(H5Fget_obj_count(H5F_OBJ_ALL, H5F_OBJ_ALL) == 0); +} + + TEST_CASE("JFJochReader_MissingEntries", "[HDF5][Full]") { DiffractionExperiment x(DetJF(1)); x.FilePrefix("test96").ImagesPerTrigger(4).OverwriteExistingFiles(true); diff --git a/writer/HDF5Objects.h b/writer/HDF5Objects.h index bd0b170d..c2fe512b 100644 --- a/writer/HDF5Objects.h +++ b/writer/HDF5Objects.h @@ -329,27 +329,7 @@ public: } template - std::optional ReadElement(size_t n) const { - HDF5DataSpace file_space(*this); - auto dims = file_space.GetDimensions(); - // Allow scalar (0-D) to be read with n==0 as a convenience. - if (file_space.GetNumOfDimensions() == 0) { - if (n != 0) return std::nullopt; - return ReadScalar(); - } - if (file_space.GetNumOfDimensions() != 1) - throw JFJochException(JFJochExceptionCategory::HDF5, "ReadNth requires a 1D dataset"); - if (n >= dims[0]) - return std::nullopt; - - // Select a single-element hyperslab at position n. - file_space.SelectHyperslab({static_cast(n)}, {1}); - HDF5DataSpace mem_space({1}); - T out{}; - if (H5Dread(id, HDF5DataType(out).GetID(), mem_space.GetID(), file_space.GetID(), H5P_DEFAULT, &out) < 0) - throw JFJochException(JFJochExceptionCategory::HDF5, "ReadNth unsuccessful"); - return out; - } + std::optional ReadElement(size_t n) const; std::string ReadString() const; void Close(); @@ -437,8 +417,81 @@ std::optional HDF5Object::ReadElement(const std::string &name, size_t n) cons return std::nullopt; } +template +std::optional HDF5DataSet::ReadElement(size_t n) const { + HDF5DataSpace file_space(*this); + auto dims = file_space.GetDimensions(); + // Allow scalar (0-D) to be read with n==0 as a convenience. + if (file_space.GetNumOfDimensions() == 0) { + if (n != 0) return std::nullopt; + return ReadScalar(); + } + if (file_space.GetNumOfDimensions() != 1) + throw JFJochException(JFJochExceptionCategory::HDF5, "ReadElement requires a 1D dataset"); + if (n >= dims[0]) + return std::nullopt; -template std::unique_ptr SaveVector(const HDF5Object& parent, const std::string &name, const std::vector &val, + // Select a single-element hyperslab at position n. + file_space.SelectHyperslab({static_cast(n)}, {1}); + HDF5DataSpace mem_space({1}); + T out{}; + if (H5Dread(id, HDF5DataType(out).GetID(), mem_space.GetID(), file_space.GetID(), H5P_DEFAULT, &out) < 0) + throw JFJochException(JFJochExceptionCategory::HDF5, "ReadElement unsuccessful"); + return out; +} + +template<> +inline std::optional HDF5DataSet::ReadElement(size_t n) const { + HDF5DataSpace file_space(*this); + auto dims = file_space.GetDimensions(); + + if (file_space.GetNumOfDimensions() == 0) { + if (n != 0) return std::nullopt; + return ReadString(); + } + + if (file_space.GetNumOfDimensions() != 1) + throw JFJochException(JFJochExceptionCategory::HDF5, "ReadElement requires a 1D dataset"); + + if (n >= dims[0]) + return std::nullopt; + + file_space.SelectHyperslab({static_cast(n)}, {1}); + + HDF5DataType file_type(*this); + if (H5Tget_class(file_type.GetID()) != H5T_STRING) + throw JFJochException(JFJochExceptionCategory::HDF5, "ReadElement: dataset is not a string type"); + + // Variable-length string + if (H5Tis_variable_str(file_type.GetID()) > 0) { + HDF5DataSpace mem_space({1}); + char *tmp = nullptr; + + if (H5Dread(id, file_type.GetID(), mem_space.GetID(), file_space.GetID(), H5P_DEFAULT, &tmp) < 0) + throw JFJochException(JFJochExceptionCategory::HDF5, "ReadElement unsuccessful"); + + std::string out = (tmp != nullptr) ? std::string(tmp) : std::string{}; + if (tmp != nullptr) + H5free_memory(tmp); + return out; + } + + // Fixed-length string + const size_t elem_size = file_type.GetElemSize(); + if (elem_size == 0) + return std::string{}; + + std::vector buffer(elem_size + 1, '\0'); + HDF5DataSpace mem_space({1}); + + if (H5Dread(id, file_type.GetID(), mem_space.GetID(), file_space.GetID(), H5P_DEFAULT, buffer.data()) < 0) + throw JFJochException(JFJochExceptionCategory::HDF5, "ReadElement unsuccessful"); + + return std::string(buffer.data()); +} + +template +std::unique_ptr SaveVector(const HDF5Object& parent, const std::string &name, const std::vector &val, std::vector dims = {}, CompressionAlgorithm algorithm = CompressionAlgorithm::NO_COMPRESSION) { if (dims.empty()) dims = {val.size()}; @@ -459,7 +512,8 @@ template std::unique_ptr SaveVector(const HDF5Object& par return dataset; } -template std::unique_ptr HDF5Object::SaveVector(const std::string &name, const std::vector &val, +template +std::unique_ptr HDF5Object::SaveVector(const std::string &name, const std::vector &val, std::vector dims, CompressionAlgorithm algorithm) { if (val.empty()) throw JFJochException(JFJochExceptionCategory::HDF5, "Cannot write empty vector"); -- 2.52.0 From 07d7174eff02d2b84dec94bfda7c04f91c72b2e4 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Fri, 29 May 2026 14:19:47 +0200 Subject: [PATCH 04/27] XtalOptimizer: Accept std::vector> for spots input, to distinguish spots between different images --- image_analysis/IndexAndRefine.cpp | 2 +- image_analysis/RotationIndexer.cpp | 40 ++------- image_analysis/RotationIndexer.h | 2 +- .../geom_refinement/XtalOptimizer.cpp | 82 +++++++++++-------- .../geom_refinement/XtalOptimizer.h | 2 +- tests/XtalOptimizerTest.cpp | 35 ++++---- 6 files changed, 74 insertions(+), 89 deletions(-) diff --git a/image_analysis/IndexAndRefine.cpp b/image_analysis/IndexAndRefine.cpp index f888528e..bffaf3c9 100644 --- a/image_analysis/IndexAndRefine.cpp +++ b/image_analysis/IndexAndRefine.cpp @@ -134,7 +134,7 @@ void IndexAndRefine::RefineGeometryIfNeeded(DataMessage &msg, IndexAndRefine::In XtalOptimizerRotationOnly(data, msg.spots, 0.05); break; case GeomRefinementAlgorithmEnum::BeamCenter: - if (XtalOptimizer(data, msg.spots)) { + if (XtalOptimizer(data, {msg.spots})) { outcome.experiment.BeamX_pxl(data.geom.GetBeamX_pxl()) .BeamY_pxl(data.geom.GetBeamY_pxl()); outcome.beam_center_updated = true; diff --git a/image_analysis/RotationIndexer.cpp b/image_analysis/RotationIndexer.cpp index 8ed00d83..38e9a10f 100644 --- a/image_analysis/RotationIndexer.cpp +++ b/image_analysis/RotationIndexer.cpp @@ -11,6 +11,7 @@ RotationIndexer::RotationIndexer(const DiffractionExperiment &x, IndexerThreadPool &indexer) : experiment(x), index_ice_rings(x.GetIndexingSettings().GetIndexIceRings()), + v_(experiment.GetImageNum()), axis_(x.GetGoniometer()), geom_(x.GetDiffractionGeometry()), updated_geom_(geom_), @@ -40,39 +41,8 @@ RotationIndexer::RotationIndexer(const DiffractionExperiment &x, IndexerThreadPo void RotationIndexer::TryIndex() { // Index - std::vector v_sel; - std::vector coords_sel; - if (coords_.size() > max_spots) { - - // Indices into v_ / coords_ - std::vector idx(coords_.size()); - std::iota(idx.begin(), idx.end(), std::size_t{0}); - - // Sort indices by descending intensity - std::partial_sort( - idx.begin(), - idx.begin() + max_spots, - idx.end(), - [this](std::size_t a, std::size_t b) { - return v_[a].intensity > v_[b].intensity; - } - ); - - v_sel.reserve(max_spots); - coords_sel.reserve(max_spots); - - for (std::size_t i = 0; i < max_spots; ++i) { - const std::size_t k = idx[i]; - v_sel.emplace_back(v_[k]); - coords_sel.emplace_back(coords_[k]); - } - } else { - v_sel = v_; - coords_sel = coords_; - } - - auto indexer_result = indexer_.Run(experiment, coords_sel); + auto indexer_result = indexer_.Run(experiment, coords_); if (!indexer_result.lattice.empty() && indexer_result.lattice[0].CalcVolume() > 1.0) { auto sg = experiment.GetGemmiSpaceGroup(); if (sg) { @@ -108,7 +78,7 @@ void RotationIndexer::TryIndex() { if (data.crystal_system == gemmi::CrystalSystem::Monoclinic) data.latt.ReorderMonoclinic(); - if (XtalOptimizer(data, v_sel)) { + if (XtalOptimizer(data, v_)) { indexed_lattice = data.latt; updated_geom_ = data.geom; axis_ = data.axis; @@ -135,12 +105,12 @@ std::optional RotationIndexer::ProcessImage(int64_t image const auto rot = axis_->GetTransformationAngle(angle_deg); if (!indexed_lattice && image >= last_accumulated_image + image_stride) { - v_.reserve(v_.size() + spots.size()); + v_[image].reserve(spots.size()); coords_.reserve(coords_.size() + spots.size()); for (const auto &s: spots) { if (index_ice_rings || !s.ice_ring) { - v_.emplace_back(s); + v_[image].emplace_back(s); coords_.emplace_back(rot * s.ReciprocalCoord(geom_)); } } diff --git a/image_analysis/RotationIndexer.h b/image_analysis/RotationIndexer.h index facda160..2acb2792 100644 --- a/image_analysis/RotationIndexer.h +++ b/image_analysis/RotationIndexer.h @@ -36,7 +36,7 @@ class RotationIndexer { const bool index_ice_rings; float angle_norm_deg = 1.0f; - std::vector v_; + std::vector> v_; std::vector coords_; std::optional axis_; const DiffractionGeometry geom_; diff --git a/image_analysis/geom_refinement/XtalOptimizer.cpp b/image_analysis/geom_refinement/XtalOptimizer.cpp index 4df7a6ae..cefb24cc 100644 --- a/image_analysis/geom_refinement/XtalOptimizer.cpp +++ b/image_analysis/geom_refinement/XtalOptimizer.cpp @@ -504,7 +504,7 @@ CrystalLattice AngleAxisAndLengthsToLattice(const double rod[3], const double le } bool XtalOptimizerInternal(XtalOptimizerData &data, - const std::vector &spots, + const std::vector> &spots, const float tolerance) { try { Coord vec0 = data.latt.Vec0(); @@ -565,50 +565,60 @@ bool XtalOptimizerInternal(XtalOptimizerData &data, const float tolerance_sq = tolerance * tolerance; - // Add residuals for each point - for (const auto &pt: spots) { - if (!data.index_ice_rings && pt.ice_ring) + for (int i = 0; i < spots.size(); i++) { + if (spots[i].empty()) continue; - float angle_rad = 0.0; - - Coord recip = pt.ReciprocalCoord(data.geom); + double angle_rad = 0.0; + std::optional rot_matr; if (data.axis) { - recip = data.axis->GetTransformationAngle(pt.phi) * recip; - angle_rad = pt.phi * M_PI / 180.0; + const float angle_deg = data.axis->GetAngle_deg(i) + data.axis->GetWedge_deg() / 2.0; + angle_rad = angle_deg * M_PI / 180.0; + rot_matr = data.axis->GetTransformationAngle(angle_deg); } - double h_fp = recip * vec0; - double k_fp = recip * vec1; - double l_fp = recip * vec2; + // Add residuals for each point + for (const auto &pt: spots[i]) { + if (!data.index_ice_rings && pt.ice_ring) + continue; - double h = std::round(h_fp); - double k = std::round(k_fp); - double l = std::round(l_fp); + Coord recip = pt.ReciprocalCoord(data.geom); - double norm_sq = (h - h_fp) * (h - h_fp) + (k - k_fp) * (k - k_fp) + (l - l_fp) * (l - l_fp); + if (rot_matr) + recip = rot_matr.value() * recip; - if (norm_sq > tolerance_sq) - continue; + double h_fp = recip * vec0; + double k_fp = recip * vec1; + double l_fp = recip * vec2; - problem.AddResidualBlock( - new ceres::AutoDiffCostFunction( - new XtalResidual(pt.x, pt.y, - data.geom.GetWavelength_A(), - data.geom.GetPixelSize_mm(), - angle_rad, - h, k, l, - data.crystal_system)), - nullptr, - beam, - &distance_mm, - detector_rot, - rot_vec, - latt_vec0, - latt_vec1, - latt_vec2 - ); + double h = std::round(h_fp); + double k = std::round(k_fp); + double l = std::round(l_fp); + + 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_sq) + continue; + + problem.AddResidualBlock( + new ceres::AutoDiffCostFunction( + new XtalResidual(pt.x, pt.y, + data.geom.GetWavelength_A(), + data.geom.GetPixelSize_mm(), + angle_rad, + h, k, l, + data.crystal_system)), + nullptr, + beam, + &distance_mm, + detector_rot, + rot_vec, + latt_vec0, + latt_vec1, + latt_vec2 + ); + } } if (problem.NumResidualBlocks() < data.min_spots) @@ -722,7 +732,7 @@ bool XtalOptimizerInternal(XtalOptimizerData &data, } } -bool XtalOptimizer(XtalOptimizerData &data, const std::vector &spots) { +bool XtalOptimizer(XtalOptimizerData &data, const std::vector> &spots) { if (!XtalOptimizerInternal(data, spots, 0.3)) return false; XtalOptimizerInternal(data, spots, 0.2); diff --git a/image_analysis/geom_refinement/XtalOptimizer.h b/image_analysis/geom_refinement/XtalOptimizer.h index 9ca306dd..1c0c67dd 100644 --- a/image_analysis/geom_refinement/XtalOptimizer.h +++ b/image_analysis/geom_refinement/XtalOptimizer.h @@ -57,7 +57,7 @@ CrystalLattice AngleAxisAndCellToLattice(const double rod[3], double beta_rad, double gamma_rad); -bool XtalOptimizer(XtalOptimizerData &data, const std::vector &spots); +bool XtalOptimizer(XtalOptimizerData &data, const std::vector> &spots); bool XtalOptimizerRotationOnly(XtalOptimizerData &data, const std::vector &spots, float tolerance); #endif //JFJOCH_XTALOPTIMIZER_H diff --git a/tests/XtalOptimizerTest.cpp b/tests/XtalOptimizerTest.cpp index 1399f0c0..8b90983b 100644 --- a/tests/XtalOptimizerTest.cpp +++ b/tests/XtalOptimizerTest.cpp @@ -39,7 +39,7 @@ TEST_CASE("XtalOptimizer") { xtal_opt.crystal_system = gemmi::CrystalSystem::Triclinic; auto start = std::chrono::high_resolution_clock::now(); - REQUIRE(XtalOptimizer(xtal_opt, spots)); + REQUIRE(XtalOptimizer(xtal_opt, {spots})); auto end = std::chrono::high_resolution_clock::now(); std::cout << "XtalOptimizer took " << std::chrono::duration_cast(end - start).count() << " microseconds" << std::endl; @@ -94,7 +94,7 @@ TEST_CASE("XtalOptimizer_NoBeamCenter") { xtal_opt.max_time = 30.0; auto start = std::chrono::high_resolution_clock::now(); - REQUIRE(XtalOptimizer(xtal_opt, spots)); + REQUIRE(XtalOptimizer(xtal_opt, {spots})); auto end = std::chrono::high_resolution_clock::now(); std::cout << "XtalOptimizer took " << std::chrono::duration_cast(end - start).count() << " microseconds" << std::endl; @@ -145,7 +145,7 @@ TEST_CASE("XtalOptimizer_orthorombic") { xtal_opt.max_time = 30.0; xtal_opt.crystal_system = gemmi::CrystalSystem::Orthorhombic; auto start = std::chrono::high_resolution_clock::now(); - REQUIRE(XtalOptimizer(xtal_opt, spots)); + REQUIRE(XtalOptimizer(xtal_opt, {spots})); auto end = std::chrono::high_resolution_clock::now(); std::cout << "XtalOptimizer took " << std::chrono::duration_cast(end - start).count() << " microseconds" << std::endl; @@ -197,7 +197,7 @@ TEST_CASE("XtalOptimizer_triclinic") { xtal_opt.crystal_system = gemmi::CrystalSystem::Triclinic; xtal_opt.max_time = 36.0; auto start = std::chrono::high_resolution_clock::now(); - REQUIRE(XtalOptimizer(xtal_opt, spots)); + REQUIRE(XtalOptimizer(xtal_opt, {spots})); auto end = std::chrono::high_resolution_clock::now(); std::cout << "XtalOptimizer took " << std::chrono::duration_cast(end - start).count() << " microseconds" << std::endl; @@ -250,7 +250,7 @@ TEST_CASE("XtalOptimizer_tetragonal") { xtal_opt.crystal_system = gemmi::CrystalSystem::Tetragonal; xtal_opt.max_time = 30.0; auto start = std::chrono::high_resolution_clock::now(); - REQUIRE(XtalOptimizer(xtal_opt, spots)); + REQUIRE(XtalOptimizer(xtal_opt, {spots})); auto end = std::chrono::high_resolution_clock::now(); std::cout << "XtalOptimizer took " << std::chrono::duration_cast(end - start).count() << " microseconds" << std::endl; @@ -302,7 +302,7 @@ TEST_CASE("XtalOptimizer_hexagonal") { xtal_opt.crystal_system = gemmi::CrystalSystem::Hexagonal; xtal_opt.max_time = 60.0; auto start = std::chrono::high_resolution_clock::now(); - bool ret = XtalOptimizer(xtal_opt, spots); + bool ret = XtalOptimizer(xtal_opt, {spots}); auto end = std::chrono::high_resolution_clock::now(); std::cout << "XtalOptimizer took " << std::chrono::duration_cast(end - start).count() << " microseconds" << std::endl; @@ -356,7 +356,7 @@ TEST_CASE("XtalOptimizer_hexagonal_unconstrained") { xtal_opt.crystal_system = gemmi::CrystalSystem::Triclinic; xtal_opt.max_time = 30.0; auto start = std::chrono::high_resolution_clock::now(); - REQUIRE(XtalOptimizer(xtal_opt, spots)); + REQUIRE(XtalOptimizer(xtal_opt, {spots})); auto end = std::chrono::high_resolution_clock::now(); std::cout << "XtalOptimizer took " << std::chrono::duration_cast(end - start).count() << " microseconds" << std::endl; @@ -415,7 +415,7 @@ TEST_CASE("XtalOptimizer_cubic") { xtal_opt.crystal_system = gemmi::CrystalSystem::Cubic; xtal_opt.max_time = 30.0; auto start = std::chrono::high_resolution_clock::now(); - REQUIRE(XtalOptimizer(xtal_opt, spots)); + REQUIRE(XtalOptimizer(xtal_opt, {spots})); auto end = std::chrono::high_resolution_clock::now(); std::cout << "XtalOptimizer took " << std::chrono::duration_cast(end - start).count() << " microseconds" << std::endl; @@ -469,7 +469,7 @@ TEST_CASE("XtalOptimizer_monoclinic") { xtal_opt.crystal_system = gemmi::CrystalSystem::Monoclinic; xtal_opt.max_time = 30.0; auto start = std::chrono::high_resolution_clock::now(); - REQUIRE(XtalOptimizer(xtal_opt, spots)); + REQUIRE(XtalOptimizer(xtal_opt, {spots})); auto end = std::chrono::high_resolution_clock::now(); std::cout << "XtalOptimizer took " << std::chrono::duration_cast(end - start).count() << " microseconds" << std::endl; @@ -578,11 +578,13 @@ TEST_CASE("XtalOptimizer_rotation") { .ewald_dist_cutoff = 0.002 }; - std::vector spots; + size_t nimages = 10; + + std::vector> spots(nimages); BraggPrediction prediction; // Predict reflections for images at 0-30 deg. - for (int img = 0; img < 10; ++img) { + for (int img = 0; img < nimages; ++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); @@ -599,7 +601,7 @@ TEST_CASE("XtalOptimizer_rotation") { s.intensity = 1.0f; // minimal positive value s.ice_ring = false; s.indexed = true; - spots.push_back(s); + spots[img].push_back(s); } } @@ -663,11 +665,14 @@ TEST_CASE("XtalOptimizer_refine_rotation_axis") { .ewald_dist_cutoff = 0.002 }; - std::vector spots; + BraggPrediction prediction; + const size_t nimages = 10; + std::vector> spots(nimages); + // Predict reflections for images at 0-30 deg. - for (int img = 0; img < 10; ++img) { + for (int img = 0; img < nimages; ++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); @@ -684,7 +689,7 @@ TEST_CASE("XtalOptimizer_refine_rotation_axis") { s.phi = angle_deg; s.ice_ring = false; s.indexed = true; - spots.push_back(s); + spots.at(img).push_back(s); } } -- 2.52.0 From a6f61b0d8a257dce57710d12b68eba9e48b0780d Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Fri, 29 May 2026 14:20:10 +0200 Subject: [PATCH 05/27] CMake: In debug mode JFJochVersion needs to be explicitly PIC to link with the plugin --- common/CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 14c2d364..53dd9333 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -28,9 +28,14 @@ CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/GitInfo.cpp.in" "${CMAKE_CURRENT_BIN ADD_LIBRARY(JFJochVersion STATIC ${CMAKE_CURRENT_BINARY_DIR}/GitInfo.cpp GitInfo.h) +set_target_properties(JFJochVersion PROPERTIES + POSITION_INDEPENDENT_CODE ON +) + ADD_LIBRARY(JFJochLogger STATIC Logger.cpp Logger.h ) + TARGET_LINK_LIBRARIES(JFJochLogger PUBLIC spdlog::spdlog JFJochVersion) ADD_LIBRARY(JFJochZMQ STATIC ZMQWrappers.cpp ZMQWrappers.h) -- 2.52.0 From 4b609a6e06173c2c4ed72ddb717bcf4dbdef2f5a Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Fri, 29 May 2026 14:58:53 +0200 Subject: [PATCH 06/27] RotationIndexer: Separate ProcessImage and GetLattice --- image_analysis/IndexAndRefine.cpp | 3 +- image_analysis/RotationIndexer.cpp | 45 +++++++++++++++--------------- image_analysis/RotationIndexer.h | 8 ++++-- tests/RotationIndexerTest.cpp | 12 +++++--- 4 files changed, 38 insertions(+), 30 deletions(-) diff --git a/image_analysis/IndexAndRefine.cpp b/image_analysis/IndexAndRefine.cpp index bffaf3c9..9c1ba7d3 100644 --- a/image_analysis/IndexAndRefine.cpp +++ b/image_analysis/IndexAndRefine.cpp @@ -28,7 +28,8 @@ IndexAndRefine::IndexAndRefine(const DiffractionExperiment &x, IndexerThreadPool IndexAndRefine::IndexingOutcome IndexAndRefine::DetermineLatticeAndSymmetryRotation(DataMessage &msg) { IndexingOutcome outcome(experiment); - auto result = rotation_indexer->ProcessImage(msg.number, msg.spots); + rotation_indexer->ProcessImage(msg.number, msg.spots); + auto result = rotation_indexer->GetLattice(); if (result) { // For rotation indexing, indexing rate is calculated only for frames, where "global" rotation indexing solution was found msg.indexing_result = false; diff --git a/image_analysis/RotationIndexer.cpp b/image_analysis/RotationIndexer.cpp index 38e9a10f..1d04eb51 100644 --- a/image_analysis/RotationIndexer.cpp +++ b/image_analysis/RotationIndexer.cpp @@ -39,10 +39,24 @@ RotationIndexer::RotationIndexer(const DiffractionExperiment &x, IndexerThreadPo } } -void RotationIndexer::TryIndex() { - // Index +IndexerResult RotationIndexer::RunIndexing() const { + std::vector coords; + coords.reserve(max_spots); + + for (int i = 0; i < v_.size(); i++) { + const float angle_deg = axis_->GetAngle_deg(i) + axis_->GetWedge_deg() / 2.0f; + const auto rot = axis_->GetTransformationAngle(angle_deg); + + for (const auto &s: v_[i]) + coords.emplace_back(rot * s.ReciprocalCoord(geom_)); + } + + return indexer_.Run(experiment, coords); +} + +void RotationIndexer::TryIndex() { + auto indexer_result = RunIndexing(); - auto indexer_result = indexer_.Run(experiment, coords_); if (!indexer_result.lattice.empty() && indexer_result.lattice[0].CalcVolume() > 1.0) { auto sg = experiment.GetGemmiSpaceGroup(); if (sg) { @@ -94,25 +108,19 @@ void RotationIndexer::TryIndex() { } } -std::optional RotationIndexer::ProcessImage(int64_t image, const std::vector &spots) { +void RotationIndexer::ProcessImage(int64_t image, const std::vector &spots) { std::unique_lock ul(m); // For non-rotation just ignore the whole procedure if (!axis_) - return {}; - - const float angle_deg = axis_->GetAngle_deg(image) + axis_->GetWedge_deg() / 2.0f; - const auto rot = axis_->GetTransformationAngle(angle_deg); + return; if (!indexed_lattice && image >= last_accumulated_image + image_stride) { v_[image].reserve(spots.size()); - coords_.reserve(coords_.size() + spots.size()); for (const auto &s: spots) { - if (index_ice_rings || !s.ice_ring) { + if (index_ice_rings || !s.ice_ring) v_[image].emplace_back(s); - coords_.emplace_back(rot * s.ReciprocalCoord(geom_)); - } } accumulated_images++; @@ -126,18 +134,11 @@ std::optional RotationIndexer::ProcessImage(int64_t image image >= next_image_to_try_indexing) TryIndex(); } - if (!indexed_lattice) - return {}; - - return RotationIndexerResult{ - .lattice = indexed_lattice.value(), - .search_result = search_result_, - .geom = updated_geom_, - .axis = axis_ - }; } -std::optional RotationIndexer::GetLattice() { +std::optional RotationIndexer::GetLattice() const { + std::unique_lock ul(m); + if (!indexed_lattice) return {}; return RotationIndexerResult{ diff --git a/image_analysis/RotationIndexer.h b/image_analysis/RotationIndexer.h index 2acb2792..1829a7ad 100644 --- a/image_analysis/RotationIndexer.h +++ b/image_analysis/RotationIndexer.h @@ -37,7 +37,7 @@ class RotationIndexer { float angle_norm_deg = 1.0f; std::vector> v_; - std::vector coords_; + std::optional axis_; const DiffractionGeometry geom_; DiffractionGeometry updated_geom_; @@ -54,11 +54,13 @@ class RotationIndexer { int64_t indexing_range_multiplier = 1; std::optional indexed_lattice; + IndexerResult RunIndexing() const; + void TryIndex(); public: RotationIndexer(const DiffractionExperiment& x, IndexerThreadPool& indexer); - std::optional ProcessImage(int64_t image, const std::vector& spots); - std::optional GetLattice(); + void ProcessImage(int64_t image, const std::vector& spots); + std::optional GetLattice() const; }; #endif //JFJOCH_ROTATIONINDEXER_H \ No newline at end of file diff --git a/tests/RotationIndexerTest.cpp b/tests/RotationIndexerTest.cpp index 2b4ea0e3..029dbac7 100644 --- a/tests/RotationIndexerTest.cpp +++ b/tests/RotationIndexerTest.cpp @@ -70,7 +70,9 @@ TEST_CASE("RotationIndexer") { s.indexed = true; spots.push_back(s); } - if (indexer.ProcessImage(img, spots).has_value()) + indexer.ProcessImage(img, spots); + auto result = indexer.GetLattice(); + if (result.has_value()) cnt++; } @@ -147,8 +149,9 @@ TEST_CASE("RotationIndexer short scan indexes only at the end") { s.indexed = true; spots.push_back(s); } - - CHECK_FALSE(indexer.ProcessImage(img, spots).has_value()); + indexer.ProcessImage(img, spots); + auto result = indexer.GetLattice(); + CHECK_FALSE(result.has_value()); } std::vector last_spots; @@ -171,7 +174,8 @@ TEST_CASE("RotationIndexer short scan indexes only at the end") { last_spots.push_back(s); } - auto ret_last = indexer.ProcessImage(last_img, last_spots); + indexer.ProcessImage(last_img, last_spots); + auto ret_last = indexer.GetLattice(); REQUIRE(ret_last.has_value()); auto ret = indexer.GetLattice(); -- 2.52.0 From 4674aff2021f34b948b1a65707de02003071f063 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Fri, 29 May 2026 15:03:58 +0200 Subject: [PATCH 07/27] jfjoch_test: Fix JFJochReader_NiggliClass_VDS --- tests/JFJochReaderTest.cpp | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/tests/JFJochReaderTest.cpp b/tests/JFJochReaderTest.cpp index d7635940..7294d301 100644 --- a/tests/JFJochReaderTest.cpp +++ b/tests/JFJochReaderTest.cpp @@ -1059,21 +1059,24 @@ TEST_CASE("JFJochReader_NiggliClass_VDS", "[HDF5][Full]") { .crystal_system = gemmi::CrystalSystem::Cubic, }; - DataMessage message{}; - message.number = 0; - message.image = CompressedImage(image, x.GetXPixelsNum(), x.GetYPixelsNum()); - message.indexing_result = true; - message.indexing_lattice = CrystalLattice(40, 50, 60, 90, 90, 90); - message.lattice_type = lm; - REQUIRE_NOTHROW(file_set.WriteHDF5(message)); + DataMessage message_0{}; + message_0.number = 0; + message_0.image = CompressedImage(image, x.GetXPixelsNum(), x.GetYPixelsNum()); + message_0.indexing_result = true; + message_0.indexing_lattice = CrystalLattice(40, 50, 60, 90, 90, 90); + message_0.lattice_type = lm; + REQUIRE_NOTHROW(file_set.WriteHDF5(message_0)); - message.number = 1; - message.indexing_result = false; - message.indexing_lattice = std::nullopt; - REQUIRE_NOTHROW(file_set.WriteHDF5(message)); + DataMessage message_1{}; + message_1.number = 1; + message_1.indexing_result = false; + message_1.indexing_lattice = std::nullopt; + REQUIRE_NOTHROW(file_set.WriteHDF5(message_1)); EndMessage end_message; end_message.max_image_number = 2; + end_message.image_indexed = {true, false}; + file_set.WriteHDF5(end_message); file_set.Finalize(); } @@ -1088,9 +1091,10 @@ TEST_CASE("JFJochReader_NiggliClass_VDS", "[HDF5][Full]") { REQUIRE_NOTHROW(reader_image = reader.LoadImage(0)); REQUIRE(reader_image); + REQUIRE(reader_image->ImageData().indexing_result.has_value()); CHECK(reader_image->ImageData().indexing_result.value() == true); - REQUIRE(reader_image->ImageData().indexing_lattice); - REQUIRE(reader_image->ImageData().lattice_type); + REQUIRE(reader_image->ImageData().indexing_lattice.has_value()); + REQUIRE(reader_image->ImageData().lattice_type.has_value()); CHECK(reader_image->ImageData().lattice_type->centering == 'F'); CHECK(reader_image->ImageData().lattice_type->niggli_class == 1); CHECK(reader_image->ImageData().lattice_type->crystal_system == gemmi::CrystalSystem::Cubic); -- 2.52.0 From 0e4d80acd6648c31c175231996c665e68909366b Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Fri, 29 May 2026 15:22:40 +0200 Subject: [PATCH 08/27] RotationIndexer: Add limit on spot count per image (not global), to enable fair-share of images + limit maximum number of images (there is no real benefit of going above 100 images in this model) --- image_analysis/RotationIndexer.cpp | 63 +++++++++++++++++++----------- image_analysis/RotationIndexer.h | 3 +- 2 files changed, 42 insertions(+), 24 deletions(-) diff --git a/image_analysis/RotationIndexer.cpp b/image_analysis/RotationIndexer.cpp index 1d04eb51..56b0130b 100644 --- a/image_analysis/RotationIndexer.cpp +++ b/image_analysis/RotationIndexer.cpp @@ -41,7 +41,7 @@ RotationIndexer::RotationIndexer(const DiffractionExperiment &x, IndexerThreadPo IndexerResult RotationIndexer::RunIndexing() const { std::vector coords; - coords.reserve(max_spots); + coords.reserve(max_spots_per_image * v_.size()); for (int i = 0; i < v_.size(); i++) { const float angle_deg = axis_->GetAngle_deg(i) + axis_->GetWedge_deg() / 2.0f; @@ -55,9 +55,8 @@ IndexerResult RotationIndexer::RunIndexing() const { } void RotationIndexer::TryIndex() { - auto indexer_result = RunIndexing(); - - if (!indexer_result.lattice.empty() && indexer_result.lattice[0].CalcVolume() > 1.0) { + if (auto indexer_result = RunIndexing(); + !indexer_result.lattice.empty() && indexer_result.lattice[0].CalcVolume() > 1.0) { auto sg = experiment.GetGemmiSpaceGroup(); if (sg) { search_result_ = LatticeSearchResult{ @@ -96,15 +95,16 @@ void RotationIndexer::TryIndex() { indexed_lattice = data.latt; updated_geom_ = data.geom; axis_ = data.axis; - return; } } - if (indexing_range_multiplier < max_indexing_range_multiplier) { - indexing_range_multiplier++; - next_image_to_try_indexing = first_image_to_try_indexing * indexing_range_multiplier; - } else { - next_image_to_try_indexing = INT64_MAX; + if (!indexed_lattice) { + if (indexing_range_multiplier < max_indexing_range_multiplier) { + indexing_range_multiplier++; + next_image_to_try_indexing = first_image_to_try_indexing * indexing_range_multiplier; + } else { + next_image_to_try_indexing = INT64_MAX; + } } } @@ -115,25 +115,42 @@ void RotationIndexer::ProcessImage(int64_t image, const std::vector if (!axis_) return; - if (!indexed_lattice && image >= last_accumulated_image + image_stride) { - v_[image].reserve(spots.size()); + if (accumulated_images >= max_images_for_indexing) + return; - for (const auto &s: spots) { - if (index_ice_rings || !s.ice_ring) - v_[image].emplace_back(s); - } + if (indexed_lattice) + return; - accumulated_images++; - last_accumulated_image = image; + if (image < last_accumulated_image + image_stride) + return; - const bool short_scan_last_image = + v_[image].reserve(spots.size()); + + for (const auto &s: spots) { + if (index_ice_rings || !s.ice_ring) + v_[image].emplace_back(s); + } + + if (v_[image].size() > max_spots_per_image) { + std::ranges::nth_element(v_[image], v_[image].begin() + max_spots_per_image, + [](const SpotToSave &a, const SpotToSave &b) { + return a.intensity > b.intensity; + } + ); + + v_[image].resize(max_spots_per_image); + } + + accumulated_images++; + last_accumulated_image = image; + + const bool short_scan_last_image = (experiment.GetImageNum() < min_images_for_indexing) && (image >= experiment.GetImageNum() - 1); - if ((accumulated_images >= min_images_for_indexing || short_scan_last_image) && - image >= next_image_to_try_indexing) - TryIndex(); - } + if ((accumulated_images >= min_images_for_indexing || short_scan_last_image) && + image >= next_image_to_try_indexing) + TryIndex(); } std::optional RotationIndexer::GetLattice() const { diff --git a/image_analysis/RotationIndexer.h b/image_analysis/RotationIndexer.h index 1829a7ad..c500b2a3 100644 --- a/image_analysis/RotationIndexer.h +++ b/image_analysis/RotationIndexer.h @@ -29,7 +29,8 @@ class RotationIndexer { mutable std::mutex m; const DiffractionExperiment& experiment; - constexpr static int64_t max_spots = 10000; + constexpr static int64_t max_spots_per_image = 200; + constexpr static int64_t max_images_for_indexing = 100; constexpr static int64_t min_images_for_indexing = 10; constexpr static int64_t max_indexing_range_multiplier = 3; -- 2.52.0 From e3924a08dd6960b8079440de994a2d381c8cf818 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Fri, 29 May 2026 16:09:35 +0200 Subject: [PATCH 09/27] RotationIndexer: Add GetAccumulatedImages() - though not sure if really useful --- image_analysis/RotationIndexer.cpp | 6 +++++- image_analysis/RotationIndexer.h | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/image_analysis/RotationIndexer.cpp b/image_analysis/RotationIndexer.cpp index 56b0130b..9904b0b1 100644 --- a/image_analysis/RotationIndexer.cpp +++ b/image_analysis/RotationIndexer.cpp @@ -164,4 +164,8 @@ std::optional RotationIndexer::GetLattice() const { .geom = updated_geom_, .axis = axis_ }; -} \ No newline at end of file +} + +int64_t RotationIndexer::GetAccumulatedImages() const { + return accumulated_images; +} diff --git a/image_analysis/RotationIndexer.h b/image_analysis/RotationIndexer.h index c500b2a3..ccaca1b9 100644 --- a/image_analysis/RotationIndexer.h +++ b/image_analysis/RotationIndexer.h @@ -62,6 +62,8 @@ public: RotationIndexer(const DiffractionExperiment& x, IndexerThreadPool& indexer); void ProcessImage(int64_t image, const std::vector& spots); std::optional GetLattice() const; + + int64_t GetAccumulatedImages() const; }; #endif //JFJOCH_ROTATIONINDEXER_H \ No newline at end of file -- 2.52.0 From 7b20eedcbde5570732f87e9b1592625f73fad5dc Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Fri, 29 May 2026 16:27:22 +0200 Subject: [PATCH 10/27] RotationIndexer: Remove logic controlling image accumulation --- image_analysis/IndexAndRefine.cpp | 11 ++- image_analysis/RotationIndexer.cpp | 70 ++++-------------- image_analysis/RotationIndexer.h | 32 ++------- tests/RotationIndexerTest.cpp | 110 ++--------------------------- 4 files changed, 34 insertions(+), 189 deletions(-) diff --git a/image_analysis/IndexAndRefine.cpp b/image_analysis/IndexAndRefine.cpp index 9c1ba7d3..21dda4a2 100644 --- a/image_analysis/IndexAndRefine.cpp +++ b/image_analysis/IndexAndRefine.cpp @@ -26,10 +26,10 @@ IndexAndRefine::IndexAndRefine(const DiffractionExperiment &x, IndexerThreadPool } IndexAndRefine::IndexingOutcome IndexAndRefine::DetermineLatticeAndSymmetryRotation(DataMessage &msg) { + const auto result = rotation_indexer->GetLattice(); + IndexingOutcome outcome(experiment); - rotation_indexer->ProcessImage(msg.number, msg.spots); - auto result = rotation_indexer->GetLattice(); if (result) { // For rotation indexing, indexing rate is calculated only for frames, where "global" rotation indexing solution was found msg.indexing_result = false; @@ -292,8 +292,13 @@ void IndexAndRefine::ProcessImage(DataMessage &msg, } std::optional IndexAndRefine::Finalize() { - if (rotation_indexer) + if (rotation_indexer) { + if (const auto latt = rotation_indexer->GetLattice()) + return latt; + + rotation_indexer->RunIndexing(); return rotation_indexer->GetLattice(); + } return {}; } diff --git a/image_analysis/RotationIndexer.cpp b/image_analysis/RotationIndexer.cpp index 9904b0b1..6abe30d2 100644 --- a/image_analysis/RotationIndexer.cpp +++ b/image_analysis/RotationIndexer.cpp @@ -16,30 +16,11 @@ RotationIndexer::RotationIndexer(const DiffractionExperiment &x, IndexerThreadPo geom_(x.GetDiffractionGeometry()), updated_geom_(geom_), indexer_(indexer) { - if (axis_) { - angle_norm_deg = std::fabs(axis_->GetIncrement_deg()); - if (angle_norm_deg < 1e-6) { - // Guard against rotation close to zero - axis_ = std::nullopt; - } else { - if (x.GetImageNum() < min_images_for_indexing) { - // For short measurements - only indexing at the end - first_image_to_try_indexing = std::max(0, x.GetImageNum() - 1); - next_image_to_try_indexing = first_image_to_try_indexing; - image_stride = 1; - } else { - first_image_to_try_indexing = std::max(min_images_for_indexing, - x.GetIndexingSettings().GetRotationIndexingMinAngularRange_deg() / angle_norm_deg); - next_image_to_try_indexing = first_image_to_try_indexing; - image_stride = std::ceil(x.GetIndexingSettings().GetRotationIndexingAngularStride_deg() / angle_norm_deg); - if (image_stride == 0) - image_stride = 1; - } - } - } } -IndexerResult RotationIndexer::RunIndexing() const { +void RotationIndexer::RunIndexing() { + std::unique_lock ul(m); + std::vector coords; coords.reserve(max_spots_per_image * v_.size()); @@ -50,13 +31,9 @@ IndexerResult RotationIndexer::RunIndexing() const { for (const auto &s: v_[i]) coords.emplace_back(rot * s.ReciprocalCoord(geom_)); } + const auto indexer_result = indexer_.Run(experiment, coords); - return indexer_.Run(experiment, coords); -} - -void RotationIndexer::TryIndex() { - if (auto indexer_result = RunIndexing(); - !indexer_result.lattice.empty() && indexer_result.lattice[0].CalcVolume() > 1.0) { + if (!indexer_result.lattice.empty() && indexer_result.lattice[0].CalcVolume() > 1.0) { auto sg = experiment.GetGemmiSpaceGroup(); if (sg) { search_result_ = LatticeSearchResult{ @@ -97,15 +74,6 @@ void RotationIndexer::TryIndex() { axis_ = data.axis; } } - - if (!indexed_lattice) { - if (indexing_range_multiplier < max_indexing_range_multiplier) { - indexing_range_multiplier++; - next_image_to_try_indexing = first_image_to_try_indexing * indexing_range_multiplier; - } else { - next_image_to_try_indexing = INT64_MAX; - } - } } void RotationIndexer::ProcessImage(int64_t image, const std::vector &spots) { @@ -115,15 +83,12 @@ void RotationIndexer::ProcessImage(int64_t image, const std::vector if (!axis_) return; - if (accumulated_images >= max_images_for_indexing) + if (accumulated_spots >= max_spots) return; if (indexed_lattice) return; - if (image < last_accumulated_image + image_stride) - return; - v_[image].reserve(spots.size()); for (const auto &s: spots) { @@ -131,26 +96,20 @@ void RotationIndexer::ProcessImage(int64_t image, const std::vector v_[image].emplace_back(s); } - if (v_[image].size() > max_spots_per_image) { - std::ranges::nth_element(v_[image], v_[image].begin() + max_spots_per_image, + // truncate spots, so we don't get above max_spots (total) and max_spots_per_image (for this image) + size_t max_spots_limit = std::min(max_spots_per_image, max_spots - accumulated_spots); + + if (v_[image].size() > max_spots_limit) { + std::ranges::nth_element(v_[image], v_[image].begin() + max_spots_limit, [](const SpotToSave &a, const SpotToSave &b) { return a.intensity > b.intensity; } ); - v_[image].resize(max_spots_per_image); + v_[image].resize(max_spots_limit); } - accumulated_images++; - last_accumulated_image = image; - - const bool short_scan_last_image = - (experiment.GetImageNum() < min_images_for_indexing) && - (image >= experiment.GetImageNum() - 1); - - if ((accumulated_images >= min_images_for_indexing || short_scan_last_image) && - image >= next_image_to_try_indexing) - TryIndex(); + accumulated_spots += v_[image].size(); } std::optional RotationIndexer::GetLattice() const { @@ -166,6 +125,3 @@ std::optional RotationIndexer::GetLattice() const { }; } -int64_t RotationIndexer::GetAccumulatedImages() const { - return accumulated_images; -} diff --git a/image_analysis/RotationIndexer.h b/image_analysis/RotationIndexer.h index ccaca1b9..61dd947f 100644 --- a/image_analysis/RotationIndexer.h +++ b/image_analysis/RotationIndexer.h @@ -1,8 +1,7 @@ // SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only -#ifndef JFJOCH_ROTATIONINDEXER_H -#define JFJOCH_ROTATIONINDEXER_H +#pragma once #include #include @@ -12,12 +11,6 @@ #include "indexing/IndexerThreadPool.h" #include "lattice_search/LatticeSearch.h" -// RotationIndexer works as following: -// 1. First accumulates spot results from rotation images (only images within a certain stride are included) -// 2. When a minimum number of images is reached (at least 10 images AND at least 10 deg), indexing is attempted -// 3. If indexing is successful - lattice is provided that is used by subsequent images -// 4. If indexing is not-successful - accumulation procedure is continued - struct RotationIndexerResult { CrystalLattice lattice; LatticeSearchResult search_result; @@ -29,13 +22,10 @@ class RotationIndexer { mutable std::mutex m; const DiffractionExperiment& experiment; - constexpr static int64_t max_spots_per_image = 200; - constexpr static int64_t max_images_for_indexing = 100; - constexpr static int64_t min_images_for_indexing = 10; - constexpr static int64_t max_indexing_range_multiplier = 3; + constexpr static size_t max_spots = 10000; + constexpr static size_t max_spots_per_image = 200; const bool index_ice_rings; - float angle_norm_deg = 1.0f; std::vector> v_; @@ -46,24 +36,14 @@ class RotationIndexer { IndexerThreadPool &indexer_; - int64_t last_accumulated_image = -1; - int64_t accumulated_images = 0; - - int64_t image_stride = 1; - int64_t first_image_to_try_indexing = INT64_MAX; - int64_t next_image_to_try_indexing = INT64_MAX; - int64_t indexing_range_multiplier = 1; + size_t accumulated_spots = 0; std::optional indexed_lattice; - IndexerResult RunIndexing() const; - - void TryIndex(); public: RotationIndexer(const DiffractionExperiment& x, IndexerThreadPool& indexer); void ProcessImage(int64_t image, const std::vector& spots); + void RunIndexing(); std::optional GetLattice() const; - int64_t GetAccumulatedImages() const; + size_t GetAccumulatedImages() const; }; - -#endif //JFJOCH_ROTATIONINDEXER_H \ No newline at end of file diff --git a/tests/RotationIndexerTest.cpp b/tests/RotationIndexerTest.cpp index 029dbac7..c6634290 100644 --- a/tests/RotationIndexerTest.cpp +++ b/tests/RotationIndexerTest.cpp @@ -70,7 +70,11 @@ TEST_CASE("RotationIndexer") { s.indexed = true; spots.push_back(s); } + indexer.ProcessImage(img, spots); + if (img == 30) + indexer.RunIndexing(); + auto result = indexer.GetLattice(); if (result.has_value()) cnt++; @@ -82,112 +86,12 @@ TEST_CASE("RotationIndexer") { REQUIRE(ret.has_value()); auto uc = ret->lattice.GetUnitCell(); auto uc_ref = latt_base.GetUnitCell(); - REQUIRE(std::fabs(uc.a - uc_ref.a) < 0.02 ); - REQUIRE(std::fabs(uc.b - uc_ref.b) < 0.02 ); - REQUIRE(std::fabs(uc.c - uc_ref.c) < 0.02 ); + REQUIRE(std::fabs(uc.a - uc_ref.a) < 0.1); + REQUIRE(std::fabs(uc.b - uc_ref.b) < 0.1); + REQUIRE(std::fabs(uc.c - uc_ref.c) < 0.1); REQUIRE(std::fabs(uc.alpha - uc_ref.alpha) < 0.1); REQUIRE(std::fabs(uc.beta - uc_ref.beta) < 0.1); REQUIRE(std::fabs(uc.gamma - uc_ref.gamma) < 0.1); CHECK(ret->search_result.centering == 'P'); CHECK(ret->search_result.system == gemmi::CrystalSystem::Orthorhombic); } - -TEST_CASE("RotationIndexer short scan indexes only at the end") { - 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) - .ImagesPerTrigger(6); - - IndexingSettings settings; -#ifdef JFJOCH_USE_CUDA - settings.Algorithm(IndexingAlgorithmEnum::FFT); -#elif JFJOCH_USE_FFTW - settings.Algorithm(IndexingAlgorithmEnum::FFTW); -#else - return; -#endif - - settings.RotationIndexing(true).RotationIndexingAngularStride_deg(1.0).RotationIndexingMinAngularRange_deg(30.0); - exp_i.ImportIndexingSettings(settings); - - CrystalLattice latt_base(40, 50, 80, 90, 90, 90); - latt_base = latt_base.Multiply(RotMatrix(2.0, Coord(sqrt(3)/3,sqrt(3)/3,sqrt(3)/3))); - - GoniometerAxis axis("omega", 0.0f, 30.0f, Coord(1,0,0), std::nullopt); - exp_i.Goniometer(axis); - - BraggPredictionSettings prediction_settings{ - .high_res_A = 1.3, - .ewald_dist_cutoff = 0.002 - }; - - IndexerThreadPool indexer_thread_pool(exp_i.GetIndexingSettings()); - RotationIndexer indexer(exp_i, indexer_thread_pool); - - BraggPrediction prediction; - - for (int img = 0; img < 5; ++img) { - std::vector spots; - 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; - s.intensity = 1.0f; - s.phi = angle_deg; - s.ice_ring = false; - s.indexed = true; - spots.push_back(s); - } - indexer.ProcessImage(img, spots); - auto result = indexer.GetLattice(); - CHECK_FALSE(result.has_value()); - } - - std::vector last_spots; - const int last_img = 5; - const float angle_deg = axis.GetAngle_deg(last_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 = last_img; - s.intensity = 1.0f; - s.phi = angle_deg; - s.ice_ring = false; - s.indexed = true; - last_spots.push_back(s); - } - - indexer.ProcessImage(last_img, last_spots); - auto ret_last = indexer.GetLattice(); - REQUIRE(ret_last.has_value()); - - auto ret = indexer.GetLattice(); - REQUIRE(ret.has_value()); - auto uc = ret->lattice.GetUnitCell(); - auto uc_ref = latt_base.GetUnitCell(); - REQUIRE(std::fabs(uc.a - uc_ref.a) < 0.02 ); - REQUIRE(std::fabs(uc.b - uc_ref.b) < 0.02 ); - REQUIRE(std::fabs(uc.c - uc_ref.c) < 0.02 ); - REQUIRE(std::fabs(uc.alpha - uc_ref.alpha) < 0.1); - REQUIRE(std::fabs(uc.beta - uc_ref.beta) < 0.1); - REQUIRE(std::fabs(uc.gamma - uc_ref.gamma) < 0.1); - CHECK(ret->search_result.centering == 'P'); - CHECK(ret->search_result.system == gemmi::CrystalSystem::Orthorhombic); -} \ No newline at end of file -- 2.52.0 From caa38a97326846e595289149b0d29a8705a26701 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Fri, 29 May 2026 16:54:00 +0200 Subject: [PATCH 11/27] RotationIndexerCounter: Implement rotation indexing counting logic --- image_analysis/CMakeLists.txt | 8 ++-- image_analysis/IndexAndRefine.cpp | 16 +++++-- image_analysis/IndexAndRefine.h | 5 ++- .../RotationIndexer.cpp | 8 ++-- .../{ => rotation_indexer}/RotationIndexer.h | 10 ++--- .../RotationIndexerCounter.cpp | 45 +++++++++++++++++++ .../rotation_indexer/RotationIndexerCounter.h | 24 ++++++++++ tests/RotationIndexerTest.cpp | 2 +- 8 files changed, 99 insertions(+), 19 deletions(-) rename image_analysis/{ => rotation_indexer}/RotationIndexer.cpp (97%) rename image_analysis/{ => rotation_indexer}/RotationIndexer.h (84%) create mode 100644 image_analysis/rotation_indexer/RotationIndexerCounter.cpp create mode 100644 image_analysis/rotation_indexer/RotationIndexerCounter.h diff --git a/image_analysis/CMakeLists.txt b/image_analysis/CMakeLists.txt index f6a66733..9572d0b0 100644 --- a/image_analysis/CMakeLists.txt +++ b/image_analysis/CMakeLists.txt @@ -25,8 +25,8 @@ ADD_LIBRARY(JFJochImageAnalysis STATIC IndexAndRefine.h dark_mask_analysis/DarkMaskAnalysis.cpp dark_mask_analysis/DarkMaskAnalysis.h - RotationIndexer.cpp - RotationIndexer.h + rotation_indexer/RotationIndexer.cpp + rotation_indexer/RotationIndexer.h RotationParameters.cpp RotationParameters.h WriteReflections.cpp @@ -35,7 +35,9 @@ ADD_LIBRARY(JFJochImageAnalysis STATIC LoadFCalcFromMtz.h UpdateReflectionResolution.cpp UpdateReflectionResolution.h - IntegrationOutcome.h) + IntegrationOutcome.h + rotation_indexer/RotationIndexerCounter.cpp + rotation_indexer/RotationIndexerCounter.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 21dda4a2..7112016e 100644 --- a/image_analysis/IndexAndRefine.cpp +++ b/image_analysis/IndexAndRefine.cpp @@ -15,7 +15,8 @@ IndexAndRefine::IndexAndRefine(const DiffractionExperiment &x, IndexerThreadPool : index_ice_rings(x.GetIndexingSettings().GetIndexIceRings()), experiment(x), geom_(x.GetDiffractionGeometry()), - indexer_(indexer) { + indexer_(indexer), + rotation_indexer_counter(x) { if (indexer && x.IsRotationIndexing()) rotation_indexer = std::make_unique(x, *indexer); integration_outcome.resize(x.GetImageNum()); @@ -26,11 +27,20 @@ IndexAndRefine::IndexAndRefine(const DiffractionExperiment &x, IndexerThreadPool } IndexAndRefine::IndexingOutcome IndexAndRefine::DetermineLatticeAndSymmetryRotation(DataMessage &msg) { - const auto result = rotation_indexer->GetLattice(); + auto result = rotation_indexer->GetLattice(); IndexingOutcome outcome(experiment); - if (result) { + if (!result.has_value()) { + auto rot_cnt = rotation_indexer_counter.Process(msg.number); + if (rot_cnt.first) + rotation_indexer->ProcessImage(msg.number, msg.spots); + if (rot_cnt.second) + rotation_indexer->RunIndexing(); + result = rotation_indexer->GetLattice(); + } + + if (result.has_value()) { // For rotation indexing, indexing rate is calculated only for frames, where "global" rotation indexing solution was found msg.indexing_result = false; diff --git a/image_analysis/IndexAndRefine.h b/image_analysis/IndexAndRefine.h index 2b29fb7b..eae44e80 100644 --- a/image_analysis/IndexAndRefine.h +++ b/image_analysis/IndexAndRefine.h @@ -11,8 +11,8 @@ #include "bragg_prediction/BraggPrediction.h" #include "indexing/IndexerThreadPool.h" #include "lattice_search/LatticeSearch.h" -#include "scale_merge/Merge.h" -#include "RotationIndexer.h" +#include "rotation_indexer/RotationIndexer.h" +#include "rotation_indexer/RotationIndexerCounter.h" #include "RotationParameters.h" #include "scale_merge/ScaleOnTheFly.h" #include "scale_merge/ScalingResult.h" @@ -29,6 +29,7 @@ class IndexAndRefine { IndexerThreadPool *indexer_; std::unique_ptr rotation_indexer; + RotationIndexerCounter rotation_indexer_counter; RotationParameters rotation_parameters; diff --git a/image_analysis/RotationIndexer.cpp b/image_analysis/rotation_indexer/RotationIndexer.cpp similarity index 97% rename from image_analysis/RotationIndexer.cpp rename to image_analysis/rotation_indexer/RotationIndexer.cpp index 6abe30d2..b8fe2886 100644 --- a/image_analysis/RotationIndexer.cpp +++ b/image_analysis/rotation_indexer/RotationIndexer.cpp @@ -3,9 +3,9 @@ #include "RotationIndexer.h" -#include "geom_refinement/XtalOptimizer.h" -#include "indexing/FFTIndexer.h" -#include "lattice_search/LatticeSearch.h" +#include "../geom_refinement/XtalOptimizer.h" +#include "../indexing/FFTIndexer.h" +#include "../lattice_search/LatticeSearch.h" #include RotationIndexer::RotationIndexer(const DiffractionExperiment &x, IndexerThreadPool &indexer) @@ -20,7 +20,7 @@ RotationIndexer::RotationIndexer(const DiffractionExperiment &x, IndexerThreadPo void RotationIndexer::RunIndexing() { std::unique_lock ul(m); - + std::vector coords; coords.reserve(max_spots_per_image * v_.size()); diff --git a/image_analysis/RotationIndexer.h b/image_analysis/rotation_indexer/RotationIndexer.h similarity index 84% rename from image_analysis/RotationIndexer.h rename to image_analysis/rotation_indexer/RotationIndexer.h index 61dd947f..585af5ab 100644 --- a/image_analysis/RotationIndexer.h +++ b/image_analysis/rotation_indexer/RotationIndexer.h @@ -6,10 +6,10 @@ #include #include -#include "../common/DiffractionSpot.h" -#include "../common/DiffractionExperiment.h" -#include "indexing/IndexerThreadPool.h" -#include "lattice_search/LatticeSearch.h" +#include "../../common/DiffractionSpot.h" +#include "../../common/DiffractionExperiment.h" +#include "../indexing/IndexerThreadPool.h" +#include "../lattice_search/LatticeSearch.h" struct RotationIndexerResult { CrystalLattice lattice; @@ -44,6 +44,4 @@ public: void ProcessImage(int64_t image, const std::vector& spots); void RunIndexing(); std::optional GetLattice() const; - - size_t GetAccumulatedImages() const; }; diff --git a/image_analysis/rotation_indexer/RotationIndexerCounter.cpp b/image_analysis/rotation_indexer/RotationIndexerCounter.cpp new file mode 100644 index 00000000..21bce4bc --- /dev/null +++ b/image_analysis/rotation_indexer/RotationIndexerCounter.cpp @@ -0,0 +1,45 @@ +// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute +// SPDX-License-Identifier: GPL-3.0-only + +#include "RotationIndexerCounter.h" + +RotationIndexerCounter::RotationIndexerCounter(const DiffractionExperiment &x) { + const auto axis = x.GetGoniometer(); + + if (x.IsRotationIndexing() && axis.has_value()) { + float angle_norm_deg = std::fabs(axis->GetIncrement_deg()); + if (angle_norm_deg >= 1e-6) { + if (x.GetImageNum() < min_images_for_indexing) { + // For short measurements - no trying to index during the measurement + image_to_try_indexing = x.GetImageNum(); + image_stride = 1; + } else { + image_to_try_indexing = std::max(min_images_for_indexing, + x.GetIndexingSettings(). + GetRotationIndexingMinAngularRange_deg() / angle_norm_deg); + image_stride = std::ceil( + x.GetIndexingSettings().GetRotationIndexingAngularStride_deg() / angle_norm_deg); + if (image_stride == 0) + image_stride = 1; + } + } + } +} + +std::pair RotationIndexerCounter::Process(int64_t image) { + std::unique_lock ul(m); + + std::pair ret = {false, false}; + + if (image_stride == 0) + return ret; + + accumulated_images++; + ret.first = (image_stride == 1) || (image % image_stride == 0); + if (accumulated_images > image_to_try_indexing) { + image_to_try_indexing += 10; + ret.second = true; + } + + return ret; +} diff --git a/image_analysis/rotation_indexer/RotationIndexerCounter.h b/image_analysis/rotation_indexer/RotationIndexerCounter.h new file mode 100644 index 00000000..b8dc6ecb --- /dev/null +++ b/image_analysis/rotation_indexer/RotationIndexerCounter.h @@ -0,0 +1,24 @@ +// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute +// SPDX-License-Identifier: GPL-3.0-only + +#pragma once + +#include +#include + +#include "../common/DiffractionExperiment.h" + +class RotationIndexerCounter { + mutable std::mutex m; + + int64_t image_stride = 0; + int64_t image_to_try_indexing = INT64_MAX; + int64_t indexing_range_multiplier = 1; + + size_t accumulated_images = 0; + + constexpr static int64_t min_images_for_indexing = 10; +public: + RotationIndexerCounter(const DiffractionExperiment &experiment); + std::pair Process(int64_t image); // Should you add image to a pile? Should you try indexing? +}; diff --git a/tests/RotationIndexerTest.cpp b/tests/RotationIndexerTest.cpp index c6634290..dec42359 100644 --- a/tests/RotationIndexerTest.cpp +++ b/tests/RotationIndexerTest.cpp @@ -4,7 +4,7 @@ #include #include -#include "../image_analysis/RotationIndexer.h" +#include "../image_analysis/rotation_indexer/RotationIndexer.h" #include "../image_analysis/bragg_prediction/BraggPrediction.h" TEST_CASE("RotationIndexer") { -- 2.52.0 From 40ae325995bf048edff43caa55a430b264123bf1 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Fri, 29 May 2026 16:56:18 +0200 Subject: [PATCH 12/27] IndexAndRefine: Dedicated function to add image to rotation indexer --- image_analysis/IndexAndRefine.cpp | 14 +++++++++++--- image_analysis/IndexAndRefine.h | 4 +++- receiver/JFJochReceiver.cpp | 2 +- tools/jfjoch_process.cpp | 2 +- 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/image_analysis/IndexAndRefine.cpp b/image_analysis/IndexAndRefine.cpp index 7112016e..18a58e1b 100644 --- a/image_analysis/IndexAndRefine.cpp +++ b/image_analysis/IndexAndRefine.cpp @@ -26,11 +26,19 @@ IndexAndRefine::IndexAndRefine(const DiffractionExperiment &x, IndexerThreadPool unit_cells.resize(x.GetImageNum()); } -IndexAndRefine::IndexingOutcome IndexAndRefine::DetermineLatticeAndSymmetryRotation(DataMessage &msg) { - auto result = rotation_indexer->GetLattice(); +void IndexAndRefine::AddImageToRotationIndexer(DataMessage &msg) { + if (rotation_indexer) + rotation_indexer->ProcessImage(msg.number, msg.spots); +} +IndexAndRefine::IndexingOutcome IndexAndRefine::DetermineLatticeAndSymmetryRotation(DataMessage &msg) { IndexingOutcome outcome(experiment); + if (!rotation_indexer) + return outcome; + + auto result = rotation_indexer->GetLattice(); + if (!result.has_value()) { auto rot_cnt = rotation_indexer_counter.Process(msg.number); if (rot_cnt.first) @@ -301,7 +309,7 @@ void IndexAndRefine::ProcessImage(DataMessage &msg, QuickPredictAndIntegrate(msg, spot_finding_settings, image, prediction, outcome); } -std::optional IndexAndRefine::Finalize() { +std::optional IndexAndRefine::FinalizeRotationIndexing() { if (rotation_indexer) { if (const auto latt = rotation_indexer->GetLattice()) return latt; diff --git a/image_analysis/IndexAndRefine.h b/image_analysis/IndexAndRefine.h index eae44e80..ac4d7cd7 100644 --- a/image_analysis/IndexAndRefine.h +++ b/image_analysis/IndexAndRefine.h @@ -66,12 +66,14 @@ class IndexAndRefine { void ScaleImage(DataMessage &msg, IntegrationOutcome& outcome); public: IndexAndRefine(const DiffractionExperiment &x, IndexerThreadPool *indexer); + + void AddImageToRotationIndexer(DataMessage &msg); void ProcessImage(DataMessage &msg, const SpotFindingSettings &settings, const CompressedImage &image, BraggPrediction &prediction); IndexAndRefine& ReferenceIntensities(std::vector &reference); ScalingResult ScaleAllImages(const std::vector &reference, size_t nthreads = 0); - std::optional Finalize(); + std::optional FinalizeRotationIndexing(); std::optional GetConsensusUnitCell() const; diff --git a/receiver/JFJochReceiver.cpp b/receiver/JFJochReceiver.cpp index 8997ef9e..ba6d05f4 100644 --- a/receiver/JFJochReceiver.cpp +++ b/receiver/JFJochReceiver.cpp @@ -161,7 +161,7 @@ void JFJochReceiver::SendEndMessage() { message.az_int_result["dataset"] = plots.GetAzIntProfile(); - const auto rotation_indexer_ret = indexer.Finalize(); + const auto rotation_indexer_ret = indexer.FinalizeRotationIndexing(); if (rotation_indexer_ret.has_value()) { message.rotation_lattice = rotation_indexer_ret->lattice; message.rotation_lattice_type = LatticeMessage{ diff --git a/tools/jfjoch_process.cpp b/tools/jfjoch_process.cpp index a03c263b..4c9dec13 100644 --- a/tools/jfjoch_process.cpp +++ b/tools/jfjoch_process.cpp @@ -683,7 +683,7 @@ int main(int argc, char **argv) { // Finalize Indexing (Global) to get rotation lattice // We create a temporary IndexAndRefine to call Finalize() which aggregates pool results - const auto rotation_indexer_ret = indexer.Finalize(); + const auto rotation_indexer_ret = indexer.FinalizeRotationIndexing(); if (rotation_indexer_ret.has_value()) { end_msg.rotation_lattice = rotation_indexer_ret->lattice; -- 2.52.0 From 6c8b2d4ddd1eae75b4ae83b6784ff0b3bbe07074 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Fri, 29 May 2026 17:15:13 +0200 Subject: [PATCH 13/27] jfjoch_process: Enable two-pass algorithm --- .../rotation_indexer/RotationIndexer.cpp | 2 + .../RotationIndexerCounter.cpp | 2 +- tools/jfjoch_process.cpp | 144 ++++++++++++++++-- 3 files changed, 135 insertions(+), 13 deletions(-) diff --git a/image_analysis/rotation_indexer/RotationIndexer.cpp b/image_analysis/rotation_indexer/RotationIndexer.cpp index b8fe2886..3f588a4f 100644 --- a/image_analysis/rotation_indexer/RotationIndexer.cpp +++ b/image_analysis/rotation_indexer/RotationIndexer.cpp @@ -20,6 +20,8 @@ RotationIndexer::RotationIndexer(const DiffractionExperiment &x, IndexerThreadPo void RotationIndexer::RunIndexing() { std::unique_lock ul(m); + if (!axis_) + return; std::vector coords; coords.reserve(max_spots_per_image * v_.size()); diff --git a/image_analysis/rotation_indexer/RotationIndexerCounter.cpp b/image_analysis/rotation_indexer/RotationIndexerCounter.cpp index 21bce4bc..79bc7efe 100644 --- a/image_analysis/rotation_indexer/RotationIndexerCounter.cpp +++ b/image_analysis/rotation_indexer/RotationIndexerCounter.cpp @@ -36,7 +36,7 @@ std::pair RotationIndexerCounter::Process(int64_t image) { accumulated_images++; ret.first = (image_stride == 1) || (image % image_stride == 0); - if (accumulated_images > image_to_try_indexing) { + if (accumulated_images >= image_to_try_indexing) { image_to_try_indexing += 10; ret.second = true; } diff --git a/tools/jfjoch_process.cpp b/tools/jfjoch_process.cpp index 4c9dec13..f3b35425 100644 --- a/tools/jfjoch_process.cpp +++ b/tools/jfjoch_process.cpp @@ -51,7 +51,9 @@ void print_usage() { std::cout << std::endl; std::cout << " Indexing" << std::endl; - std::cout << " -R, --rotation-indexing[=num] Rotation indexing (optional: min angular range deg)" << std::endl; + std::cout << " -R, --two-pass-rotation[=num] Two-pass offline rotation indexing (optional: number of images, default: 30)" << std::endl; + std::cout << " --single-pass-rotation[=num] Use online-like single-pass rotation indexing (optional: min angular range deg)" << std::endl; + std::cout << " --redo-rotation-spots Redo spot finding for two-pass rotation indexing" << std::endl; std::cout << " -X, --indexing-algorithm Indexing algorithm (FFBIDX|FFT|FFTW|Auto|None)" << std::endl; std::cout << " -S, --space-group Space group number - used for both indexing and scaling" << std::endl; std::cout << " -C, --unit-cell Fix reference unit cell: \"a,b,c,alpha,beta,gamma\"" << std::endl; @@ -81,7 +83,9 @@ enum { OPT_MIN_IMAGE_CC, OPT_SCALING_ITERATIONS, OPT_SCALING_HIGH_RESOLUTION, - OPT_SCALING_OUTPUT + OPT_SCALING_OUTPUT, + OPT_SINGLE_PASS_ROTATION, + OPT_REDO_ROTATION_SPOTS }; static option long_options[] = { @@ -91,7 +95,6 @@ static option long_options[] = { {"start-image", required_argument, nullptr, 's'}, {"end-image", required_argument, nullptr, 'e'}, {"stride", required_argument, nullptr, 't'}, - {"rotation-indexing", optional_argument, nullptr, 'R'}, {"indexing-algorithm", required_argument, nullptr, 'X'}, {"unit-cell", required_argument, nullptr, 'C'}, {"reference-mtz", required_argument, nullptr, 'z'}, @@ -103,6 +106,10 @@ static option long_options[] = { {"scale-merge", no_argument, nullptr, 'M'}, {"refine", required_argument, nullptr, 'r'}, + {"two-pass-rotation", optional_argument, nullptr, 'R'}, + {"single-pass-rotation", optional_argument, nullptr, OPT_SINGLE_PASS_ROTATION}, + {"redo-rotation-spots", no_argument, nullptr, OPT_REDO_ROTATION_SPOTS}, + {"spot-sigma", required_argument, nullptr, OPT_SPOT_SIGMA}, {"spot-threshold", required_argument, nullptr, OPT_SPOT_THRESHOLD}, {"spot-high-resolution", required_argument, nullptr, OPT_SPOT_RESOLUTION}, @@ -115,7 +122,6 @@ static option long_options[] = { {nullptr, 0, nullptr, 0} }; - void trim_in_place(std::string &t) { size_t b = 0; while (b < t.size() && std::isspace(static_cast(t[b]))) b++; @@ -173,7 +179,34 @@ std::optional parse_unit_cell_arg(const char *arg) { if (!parse_float_strict(parts[5], uc.gamma)) return std::nullopt; return uc; -}; +} + +std::vector select_equally_spaced_image_ordinals(int images_to_process, int requested_images) { + std::vector ret; + + if (images_to_process <= 0 || requested_images <= 0) + return ret; + + const int n = std::min(images_to_process, requested_images); + ret.reserve(n); + + if (n == 1) { + ret.push_back(0); + return ret; + } + + std::set unique_ordinals; + for (int i = 0; i < n; i++) { + const auto ordinal = static_cast( + std::llround(static_cast(i) * static_cast(images_to_process - 1) / + static_cast(n - 1)) + ); + unique_ordinals.insert(ordinal); + } + + ret.assign(unique_ordinals.begin(), unique_ordinals.end()); + return ret; +} int main(int argc, char **argv) { for (int i = 0; i < argc; i++) { @@ -197,6 +230,9 @@ int main(int argc, char **argv) { bool verbose = false; bool rotation_indexing = false; + bool two_pass_rotation = true; + bool reuse_rotation_spots = true; + int rotation_indexing_image_count = 30; std::optional rotation_indexing_range; bool run_scaling = false; bool anomalous_mode = false; @@ -252,8 +288,29 @@ int main(int argc, char **argv) { image_stride = atoi(optarg); break; case 'R': + if (rotation_indexing) { + logger.Error("Rotation indexing already enabled"); + exit(EXIT_FAILURE); + } rotation_indexing = true; - if (optarg) rotation_indexing_range = atof(optarg); + two_pass_rotation = true; + if (optarg) + rotation_indexing_image_count = atoi(optarg); + + break; + case OPT_SINGLE_PASS_ROTATION: + if (rotation_indexing) { + logger.Error("Rotation indexing already enabled"); + exit(EXIT_FAILURE); + } + rotation_indexing = true; + two_pass_rotation = false; + + if (optarg) + rotation_indexing_range = atof(optarg); + break; + case OPT_REDO_ROTATION_SPOTS: + reuse_rotation_spots = false; break; case 'X': { std::string alg = optarg ? optarg : ""; @@ -434,6 +491,11 @@ int main(int argc, char **argv) { exit(EXIT_FAILURE); } + if (rotation_indexing_image_count <= 0) { + logger.Error("Invalid number of rotation indexing images: {}", rotation_indexing_image_count); + exit(EXIT_FAILURE); + } + logger.Info("Loaded dataset from {}", input_file); std::vector reference_data; @@ -451,6 +513,11 @@ int main(int argc, char **argv) { exit(EXIT_FAILURE); } + if (image_stride == 0) { + logger.Error("Image stride cannot be zero"); + exit(EXIT_FAILURE); + } + int images_to_process = (end_image - start_image) / image_stride; if (images_to_process <= 0) { @@ -568,6 +635,59 @@ int main(int argc, char **argv) { if (!reference_data.empty()) indexer.ReferenceIntensities(reference_data); + if (rotation_indexing && two_pass_rotation) { + const auto selected_ordinals = select_equally_spaced_image_ordinals( + images_to_process, rotation_indexing_image_count); + + logger.Info("Running first pass rotation indexing using {} equally-spaced images{}", + selected_ordinals.size(), + reuse_rotation_spots ? " and stored spots" : ""); + + for (const auto image_ordinal: selected_ordinals) { + const int image_idx = start_image + image_ordinal * image_stride; + + DataMessage msg{}; + msg.number = image_ordinal; + msg.original_number = image_idx; + + try { + if (reuse_rotation_spots) { + msg.spots = reader.ReadSpots(image_idx); + } else { + auto img = reader.GetRawImage(image_idx); + if (!img) + continue; + + MXAnalysisWithoutFPGA analysis(experiment, mapping, pixel_mask, indexer); + AzimuthalIntegrationProfile profile(mapping); + + auto first_pass_spot_settings = spot_settings; + first_pass_spot_settings.indexing = false; + first_pass_spot_settings.quick_integration = false; + + msg.image = img->image; + if (dataset->efficiency.size() > image_idx) + msg.image_collection_efficiency = dataset->efficiency[image_idx]; + + analysis.Analyze(msg, profile, first_pass_spot_settings); + } + + indexer.AddImageToRotationIndexer(msg); + } catch (const std::exception &e) { + logger.Warning("Failed to add image {} to first-pass rotation indexing: {}", image_idx, e.what()); + } + } + + const auto rotation_indexing_result = indexer.FinalizeRotationIndexing(); + + if (!rotation_indexing_result.has_value()) { + logger.Error("Two-pass rotation indexing failed - stopping without processing images"); + return EXIT_FAILURE; + } + + logger.Info("Two-pass rotation indexing found lattice"); + } + std::atomic finished_count = 0; auto worker = [&](int thread_id) { @@ -577,8 +697,8 @@ int main(int argc, char **argv) { AzimuthalIntegrationProfile profile(mapping); while (true) { - int current_idx_offset = processed_count.fetch_add(image_stride); - int image_idx = start_image + current_idx_offset; + int image_ordinal = processed_count.fetch_add(1); + int image_idx = start_image + image_ordinal * image_stride; if (image_idx >= end_image) break; @@ -596,7 +716,7 @@ int main(int argc, char **argv) { DataMessage msg{}; msg.image = img->image; - msg.number = current_idx_offset; + msg.number = image_ordinal; msg.original_number = image_idx; if (dataset->efficiency.size() > image_idx) msg.image_collection_efficiency = dataset->efficiency[image_idx]; @@ -627,7 +747,7 @@ int main(int argc, char **argv) { finished_count.fetch_add(1); // Progress log - if (current_idx_offset > 0 && current_idx_offset % 100 == 0) { + if (image_ordinal > 0 && image_ordinal % 100 == 0) { std::optional indexing_rate = plots.GetIndexingRate(); const auto now = std::chrono::steady_clock::now(); @@ -637,12 +757,12 @@ int main(int argc, char **argv) { if (indexing_rate.has_value()) { logger.Info("Processed {} / {} images ({:.2f} Hz, indexing rate {:.1f}%)", - current_idx_offset, images_to_process, + image_ordinal, images_to_process, frame_rate_hz, indexing_rate.value() * 100.0f); } else { logger.Info("Processed {} / {} images ({:.2f} Hz, indexing rate N/A)", - current_idx_offset, images_to_process, + image_ordinal, images_to_process, frame_rate_hz); } } -- 2.52.0 From 33e9a368f63cb9fdc56adb1d1a72e8f582de6362 Mon Sep 17 00:00:00 2001 From: leonarski_f Date: Fri, 29 May 2026 19:50:50 +0200 Subject: [PATCH 14/27] jfjoch_tests: Fix lattice test with VDS HDF5 --- tests/JFJochReaderTest.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/JFJochReaderTest.cpp b/tests/JFJochReaderTest.cpp index 7294d301..01596948 100644 --- a/tests/JFJochReaderTest.cpp +++ b/tests/JFJochReaderTest.cpp @@ -1069,6 +1069,7 @@ TEST_CASE("JFJochReader_NiggliClass_VDS", "[HDF5][Full]") { DataMessage message_1{}; message_1.number = 1; + message_1.image = CompressedImage(image, x.GetXPixelsNum(), x.GetYPixelsNum()); message_1.indexing_result = false; message_1.indexing_lattice = std::nullopt; REQUIRE_NOTHROW(file_set.WriteHDF5(message_1)); -- 2.52.0 From 2251a44b1bec268f3cd7f92830098ff37d0ccd92 Mon Sep 17 00:00:00 2001 From: leonarski_f Date: Fri, 29 May 2026 20:27:13 +0200 Subject: [PATCH 15/27] jfjoch_process: Works (more or less) --- tools/jfjoch_process.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tools/jfjoch_process.cpp b/tools/jfjoch_process.cpp index f3b35425..b2d16722 100644 --- a/tools/jfjoch_process.cpp +++ b/tools/jfjoch_process.cpp @@ -647,7 +647,7 @@ int main(int argc, char **argv) { const int image_idx = start_image + image_ordinal * image_stride; DataMessage msg{}; - msg.number = image_ordinal; + msg.number = image_idx; msg.original_number = image_idx; try { @@ -671,8 +671,7 @@ int main(int argc, char **argv) { analysis.Analyze(msg, profile, first_pass_spot_settings); } - - indexer.AddImageToRotationIndexer(msg); + indexer.AddImageToRotationIndexer(msg); } catch (const std::exception &e) { logger.Warning("Failed to add image {} to first-pass rotation indexing: {}", image_idx, e.what()); } @@ -831,7 +830,9 @@ int main(int argc, char **argv) { logger.Info("Consensus unit cell not found - calculation tool {:.2f} ms", consensus_duration * 1e3); end_msg.unit_cell = consensus_cell; - if (run_scaling || !reference_data.empty()) { + if (end_msg.indexing_rate.has_value() + && end_msg.indexing_rate > 0 + && (run_scaling || !reference_data.empty())) { logger.Info("Running scaling (mosaicity refinement) ..."); if (reference_data.empty()) { -- 2.52.0 From 7d1fa6401cdd191c0386152b228680a3e5b376b5 Mon Sep 17 00:00:00 2001 From: leonarski_f Date: Sat, 30 May 2026 08:47:52 +0200 Subject: [PATCH 16/27] jfjoch_viewer: Cleaning user mask not dependent on selected ROI --- viewer/JFJochImageReadingWorker.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/viewer/JFJochImageReadingWorker.cpp b/viewer/JFJochImageReadingWorker.cpp index 67062c67..549e51b5 100644 --- a/viewer/JFJochImageReadingWorker.cpp +++ b/viewer/JFJochImageReadingWorker.cpp @@ -601,7 +601,7 @@ void JFJochImageReadingWorker::SubtractROIFromUserMask() { void JFJochImageReadingWorker::ClearUserMask() { QMutexLocker locker(&m); - if (!roi || !current_image_ptr) + if (!current_image_ptr) return; auto user_mask = std::vector(current_image_ptr->Dataset().experiment.GetXPixelsNum() * current_image_ptr->Dataset().experiment.GetYPixelsNum(), 0); -- 2.52.0 From 487ee4d25b19a05c97f61ec0b5c84e5f1d278588 Mon Sep 17 00:00:00 2001 From: leonarski_f Date: Sat, 30 May 2026 13:13:53 +0200 Subject: [PATCH 17/27] jfjoch_viewer: Reciprocal space viewer, first edition --- viewer/CMakeLists.txt | 5 +- viewer/JFJochViewerWindow.cpp | 14 + .../JFJochViewerReciprocalSpaceWindow.cpp | 401 ++++++++++++++++++ .../JFJochViewerReciprocalSpaceWindow.h | 85 ++++ 4 files changed, 504 insertions(+), 1 deletion(-) create mode 100644 viewer/windows/JFJochViewerReciprocalSpaceWindow.cpp create mode 100644 viewer/windows/JFJochViewerReciprocalSpaceWindow.h diff --git a/viewer/CMakeLists.txt b/viewer/CMakeLists.txt index 103f53f4..c8f90ef8 100644 --- a/viewer/CMakeLists.txt +++ b/viewer/CMakeLists.txt @@ -5,7 +5,7 @@ SET(CMAKE_AUTOMOC ON) SET(CMAKE_AUTORCC ON) SET(CMAKE_AUTOUIC ON) -FIND_PACKAGE(Qt6 COMPONENTS Core Gui Widgets Charts DBus Concurrent REQUIRED) +FIND_PACKAGE(Qt6 COMPONENTS Core Gui Widgets Charts DBus Concurrent 3DCore 3DRender 3DExtras 3DInput REQUIRED) QT_ADD_RESOURCES(APP_RESOURCES resources/resources.qrc) @@ -84,9 +84,12 @@ ADD_EXECUTABLE(jfjoch_viewer jfjoch_viewer.cpp JFJochViewerWindow.cpp JFJochView widgets/PowderCalibrationWidget.cpp widgets/PowderCalibrationWidget.h ${APP_RESOURCES} + windows/JFJochViewerReciprocalSpaceWindow.cpp + windows/JFJochViewerReciprocalSpaceWindow.h ) TARGET_LINK_LIBRARIES(jfjoch_viewer Qt6::Core Qt6::Gui Qt6::Widgets Qt6::Charts Qt6::DBus Qt6::Concurrent + Qt6::3DCore Qt6::3DRender Qt6::3DExtras Qt6::3DInput JFJochReader JFJochLogger JFJochCommon JFJochWriter JFJochImageAnalysis) INSTALL(TARGETS jfjoch_viewer RUNTIME COMPONENT viewer) diff --git a/viewer/JFJochViewerWindow.cpp b/viewer/JFJochViewerWindow.cpp index 3a618c91..7feeb8d9 100644 --- a/viewer/JFJochViewerWindow.cpp +++ b/viewer/JFJochViewerWindow.cpp @@ -20,6 +20,7 @@ #include "windows/JFJochViewerSpotListWindow.h" #include "windows/JFJochViewerReflectionListWindow.h" #include "windows/JFJochCalibrationWindow.h" +#include "windows/JFJochViewerReciprocalSpaceWindow.h" #include "toolbar/JFJochViewerToolbarDisplay.h" #include "toolbar/JFJochViewerToolbarImage.h" #include "windows/JFJoch2DAzintImageWindow.h" @@ -98,6 +99,8 @@ JFJochViewerWindow::JFJochViewerWindow(QWidget *parent, bool dbus, const QString auto reflectionWindow = new JFJochViewerReflectionListWindow(this); auto processingWindow = new JFJochViewerProcessingWindow(spot_finding_settings, indexing_settings, this); auto calibrationWindow = new JFJochCalibrationWindow(this); + auto reciprocalWindow = new JFJochViewerReciprocalSpaceWindow(this); + auto azintWindow = new JFJochAzIntWindow(experiment.GetAzimuthalIntegrationSettings(), this); auto azintImageWindow = new JFJoch2DAzintImageWindow(this); @@ -107,6 +110,7 @@ JFJochViewerWindow::JFJochViewerWindow(QWidget *parent, bool dbus, const QString menuBar->AddWindowEntry(metadataWindow, "Image metadata"); menuBar->AddWindowEntry(processingWindow, "Image processing settings"); menuBar->AddWindowEntry(calibrationWindow, "Calibration image viewer"); + menuBar->AddWindowEntry(reciprocalWindow, "Reciprocal space viewer"); menuBar->AddWindowEntry(azintWindow, "Azimuthal integration settings"); menuBar->AddWindowEntry(azintImageWindow, "Azimuthal integration 2D image"); @@ -305,6 +309,16 @@ JFJochViewerWindow::JFJochViewerWindow(QWidget *parent, bool dbus, const QString connect(reading_worker, &JFJochImageReadingWorker::simpleImageLoaded, calibrationWindow, &JFJochCalibrationWindow::calibrationLoaded); + connect(reading_worker, &JFJochImageReadingWorker::datasetLoaded, + reciprocalWindow, &JFJochViewerReciprocalSpaceWindow::datasetLoaded); + connect(reading_worker, &JFJochImageReadingWorker::imageLoaded, + reciprocalWindow, &JFJochViewerReciprocalSpaceWindow::imageLoaded); + + connect(side_panel, &JFJochViewerSidePanel::setSpotColor, + reciprocalWindow, &JFJochViewerReciprocalSpaceWindow::setSpotColor); + connect(side_panel, &JFJochViewerSidePanel::setFeatureColor, + reciprocalWindow, &JFJochViewerReciprocalSpaceWindow::setFeatureColor); + connect(azintWindow, &JFJochAzIntWindow::settingsChanged, reading_worker, &JFJochImageReadingWorker::UpdateAzintSettings); diff --git a/viewer/windows/JFJochViewerReciprocalSpaceWindow.cpp b/viewer/windows/JFJochViewerReciprocalSpaceWindow.cpp new file mode 100644 index 00000000..bcf52d92 --- /dev/null +++ b/viewer/windows/JFJochViewerReciprocalSpaceWindow.cpp @@ -0,0 +1,401 @@ +// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute +// SPDX-License-Identifier: GPL-3.0-only + +#include "JFJochViewerReciprocalSpaceWindow.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../common/CrystalLattice.h" + +namespace { + // Custom material: per-vertex colored points with a fixed on-screen size. + // Needed because Qt6's QPerVertexColorMaterial doesn't let us control point size, + // and QPointSize must live inside the material's render pass to take effect. + Qt3DRender::QMaterial *MakePointMaterial(Qt3DCore::QNode *parent, float point_size) { + auto *material = new Qt3DRender::QMaterial(parent); + auto *effect = new Qt3DRender::QEffect(material); + auto *technique = new Qt3DRender::QTechnique(effect); + + technique->graphicsApiFilter()->setApi(Qt3DRender::QGraphicsApiFilter::OpenGL); + technique->graphicsApiFilter()->setProfile(Qt3DRender::QGraphicsApiFilter::CoreProfile); + technique->graphicsApiFilter()->setMajorVersion(3); + technique->graphicsApiFilter()->setMinorVersion(3); + + auto *filterKey = new Qt3DRender::QFilterKey(technique); + filterKey->setName(QStringLiteral("renderingStyle")); + filterKey->setValue(QStringLiteral("forward")); + technique->addFilterKey(filterKey); + + const char *vertexShader = R"( + #version 330 core + in vec3 vertexPosition; + in vec3 vertexColor; + out vec3 fColor; + uniform mat4 modelViewProjection; + void main() { + fColor = vertexColor; + gl_Position = modelViewProjection * vec4(vertexPosition, 1.0); + gl_PointSize = 6.0; + } + )"; + + const char *fragmentShader = R"( + #version 330 core + in vec3 fColor; + out vec4 outColor; + void main() { outColor = vec4(fColor, 1.0); } + )"; + + auto *shader = new Qt3DRender::QShaderProgram(material); + shader->setVertexShaderCode(QByteArray(vertexShader)); + shader->setFragmentShaderCode(QByteArray(fragmentShader)); + + auto *pass = new Qt3DRender::QRenderPass(technique); + pass->setShaderProgram(shader); + + auto *ps = new Qt3DRender::QPointSize(pass); + ps->setSizeMode(Qt3DRender::QPointSize::Fixed); + ps->setValue(point_size); + pass->addRenderState(ps); + + technique->addRenderPass(pass); + effect->addTechnique(technique); + material->setEffect(effect); + return material; + } + + // Draw a cylinder from origin along the given (already scaled) vector. + Qt3DCore::QEntity *MakeVector(Qt3DCore::QEntity *parent, + const QVector3D &vec, + const QColor &color, + float thickness) { + auto *entity = new Qt3DCore::QEntity(parent); + + const float length = vec.length(); + if (length < 1e-6f) + return entity; + + auto *mesh = new Qt3DExtras::QCylinderMesh(); + mesh->setRadius(thickness); + mesh->setLength(length); + + auto *material = new Qt3DExtras::QPhongMaterial(); + material->setDiffuse(color); + + auto *transform = new Qt3DCore::QTransform(); + // QCylinderMesh is oriented along +Y by default; rotate +Y to vec direction. + const QVector3D yAxis(0, 1, 0); + const QVector3D dir = vec.normalized(); + const QQuaternion rot = QQuaternion::rotationTo(yAxis, dir); + transform->setRotation(rot); + transform->setTranslation(vec * 0.5f); // cylinder centered at its midpoint + + entity->addComponent(mesh); + entity->addComponent(material); + entity->addComponent(transform); + return entity; + } +} + +JFJochViewerReciprocalSpaceWindow::JFJochViewerReciprocalSpaceWindow(QWidget *parent) + : JFJochHelperWindow(parent) { + setWindowTitle("Reciprocal space"); + resize(800, 800); + + auto *central = new QWidget(this); + auto *layout = new QVBoxLayout(central); + + // 3D view embedded in a QWidget container + view = new Qt3DExtras::Qt3DWindow(); + view->defaultFrameGraph()->setClearColor(QColor(20, 20, 25)); + QWidget *container = QWidget::createWindowContainer(view, central); + container->setMinimumSize(400, 400); + container->setFocusPolicy(Qt::StrongFocus); + layout->addWidget(container, 1); + + // Controls + auto *controls = new QHBoxLayout(); + crystalFrameCheck = new QCheckBox("Crystal frame (angle = 0)", central); + crystalFrameCheck->setChecked(false); + crystalFrameCheck->setEnabled(false); // only for rotation data + showCellCheck = new QCheckBox("Show reciprocal cell", central); + showCellCheck->setChecked(true); + accumulateCheck = new QCheckBox("Accumulate", central); + accumulateCheck->setChecked(false); + auto *clearButton = new QPushButton("Clear accumulated", central); + + controls->addWidget(crystalFrameCheck); + controls->addWidget(showCellCheck); + controls->addWidget(accumulateCheck); + controls->addStretch(1); + controls->addWidget(clearButton); + layout->addLayout(controls); + + setCentralWidget(central); + + connect(crystalFrameCheck, &QCheckBox::toggled, this, + &JFJochViewerReciprocalSpaceWindow::rebuildSpots); // frame change → reposition points only + connect(showCellCheck, &QCheckBox::toggled, this, + &JFJochViewerReciprocalSpaceWindow::rebuildScene); // cell vectors only + connect(clearButton, &QPushButton::clicked, this, [this] { + spots_.clear(); + rebuildSpots(); + }); + + // Root entity + camera + root = new Qt3DCore::QEntity(); + + auto *camera = view->camera(); + camera->lens()->setPerspectiveProjection(45.0f, 1.0f, 0.1f, 10000.0f); + camera->setPosition(QVector3D(0, 0, 80)); + camera->setViewCenter(QVector3D(0, 0, 0)); + + auto *lightEntity = new Qt3DCore::QEntity(root); + auto *light = new Qt3DRender::QPointLight(lightEntity); + light->setIntensity(1.0f); + auto *lightTransform = new Qt3DCore::QTransform(lightEntity); + lightTransform->setTranslation(QVector3D(0, 0, 200)); + lightEntity->addComponent(light); + lightEntity->addComponent(lightTransform); + + camController = new Qt3DExtras::QOrbitCameraController(root); + camController->setCamera(camera); + + // --- Persistent point-cloud entity for spots (one draw call for all spots) --- + spotEntity = new Qt3DCore::QEntity(root); + + auto *geometry = new Qt3DCore::QGeometry(spotEntity); + + spotPosBuffer = new Qt3DCore::QBuffer(geometry); + spotColorBuffer = new Qt3DCore::QBuffer(geometry); + + spotPosAttr = new Qt3DCore::QAttribute(geometry); + spotPosAttr->setName(Qt3DCore::QAttribute::defaultPositionAttributeName()); + spotPosAttr->setVertexBaseType(Qt3DCore::QAttribute::Float); + spotPosAttr->setVertexSize(3); + spotPosAttr->setAttributeType(Qt3DCore::QAttribute::VertexAttribute); + spotPosAttr->setBuffer(spotPosBuffer); + spotPosAttr->setByteStride(3 * sizeof(float)); + geometry->addAttribute(spotPosAttr); + + spotColorAttr = new Qt3DCore::QAttribute(geometry); + spotColorAttr->setName(Qt3DCore::QAttribute::defaultColorAttributeName()); + spotColorAttr->setVertexBaseType(Qt3DCore::QAttribute::Float); + spotColorAttr->setVertexSize(3); + spotColorAttr->setAttributeType(Qt3DCore::QAttribute::VertexAttribute); + spotColorAttr->setBuffer(spotColorBuffer); + spotColorAttr->setByteStride(3 * sizeof(float)); + geometry->addAttribute(spotColorAttr); + + spotRenderer = new Qt3DRender::QGeometryRenderer(spotEntity); + spotRenderer->setGeometry(geometry); + spotRenderer->setPrimitiveType(Qt3DRender::QGeometryRenderer::Points); + + // Reuse Qt's working per-vertex-color material, but inject a QPointSize render + // state into its existing render pass so the points are large enough to see. + auto *spotMaterial = new Qt3DExtras::QPerVertexColorMaterial(spotEntity); + if (auto *effect = spotMaterial->effect()) { + const auto techniques = effect->techniques(); + for (auto *technique : techniques) { + const auto passes = technique->renderPasses(); + for (auto *pass : passes) { + auto *ps = new Qt3DRender::QPointSize(pass); + ps->setSizeMode(Qt3DRender::QPointSize::Fixed); + ps->setValue(8.0f); + pass->addRenderState(ps); + } + } + } + spotEntity->addComponent(spotRenderer); + spotEntity->addComponent(spotMaterial); + + view->setRootEntity(root); + + rebuildSpots(); + rebuildScene(); // builds axes + cell vectors +} + +QColor JFJochViewerReciprocalSpaceWindow::SpotColorFor(bool indexed, bool ice_ring) const { + if (indexed) + return indexed_color; + if (ice_ring) + return ice_ring_color; + return spot_color; +} + +void JFJochViewerReciprocalSpaceWindow::datasetLoaded(std::shared_ptr in_dataset) { + // New dataset: clean things (metadata update handled separately, later) + spots_.clear(); + indexed_lattice_.reset(); + has_rotation_ = false; + + if (in_dataset) + has_rotation_ = in_dataset->experiment.GetGoniometer().has_value(); + + crystalFrameCheck->setEnabled(has_rotation_); + if (!has_rotation_) + crystalFrameCheck->setChecked(false); + + rebuildScene(); +} + +void JFJochViewerReciprocalSpaceWindow::imageLoaded(std::shared_ptr image) { + if (!accumulateCheck->isChecked()) { + spots_.clear(); + indexed_lattice_.reset(); + } + + if (!image) { + rebuildScene(); + return; + } + + const auto &dataset = image->Dataset(); + const auto geom = dataset.experiment.GetDiffractionGeometry(); + const auto axis = dataset.experiment.GetGoniometer(); + const int64_t image_number = image->ImageData().number; + + // Goniometer back-rotation to bring the image into the angle = 0 crystal frame, + // same convention as RotationIndexer / XtalOptimizer. + std::optional back_rot; + if (axis) { + const float angle_deg = axis->GetAngle_deg(static_cast(image_number)) + + axis->GetWedge_deg() / 2.0f; + back_rot = axis->GetTransformationAngle(angle_deg); + } + + spots_.reserve(spots_.size() + image->ImageData().spots.size()); + for (const auto &s : image->ImageData().spots) { + AccumulatedSpot acc; + acc.recip_lab = s.ReciprocalCoord(geom); + acc.recip_crystal = back_rot ? (back_rot.value() * acc.recip_lab) : acc.recip_lab; + acc.indexed = s.indexed; + acc.ice_ring = s.ice_ring; + spots_.emplace_back(acc); + } + + // Soft cap so a long accumulation doesn't grow unbounded + constexpr size_t max_accumulated = 200000; + if (spots_.size() > max_accumulated) + spots_.erase(spots_.begin(), + spots_.begin() + static_cast(spots_.size() - max_accumulated)); + + // Keep the latest indexed lattice, if available + if (image->ImageData().indexing_lattice) + indexed_lattice_ = image->ImageData().indexing_lattice; + + rebuildSpots(); + rebuildScene(); // in case the cell/lattice changed +} + +void JFJochViewerReciprocalSpaceWindow::clearScene() { + if (vectorContent) { + vectorContent->setParent(static_cast(nullptr)); + vectorContent->deleteLater(); + vectorContent = nullptr; + } +} + +void JFJochViewerReciprocalSpaceWindow::rebuildScene() { + // Only rebuilds the (few) axis + reciprocal-cell vectors. + clearScene(); + vectorContent = new Qt3DCore::QEntity(root); + + addAxes(); + if (showCellCheck->isChecked() && indexed_lattice_) + addCellVectors(); +} + +void JFJochViewerReciprocalSpaceWindow::addCellVectors() { + if (!indexed_lattice_) + return; + + const Coord astar = indexed_lattice_->Astar(); + const Coord bstar = indexed_lattice_->Bstar(); + const Coord cstar = indexed_lattice_->Cstar(); + + const float thickness = 0.15f; + MakeVector(vectorContent, + QVector3D(astar.x, astar.y, astar.z) * scene_scale_, + Qt::red, thickness); + MakeVector(vectorContent, + QVector3D(bstar.x, bstar.y, bstar.z) * scene_scale_, + Qt::green, thickness); + MakeVector(vectorContent, + QVector3D(cstar.x, cstar.y, cstar.z) * scene_scale_, + Qt::blue, thickness); +} + +void JFJochViewerReciprocalSpaceWindow::addAxes() { + // Faint reference axes (lab frame X/Y/Z) for orientation + const float len = 10.0f; + const float thickness = 0.05f; + MakeVector(vectorContent, QVector3D(len, 0, 0), QColor(120, 60, 60), thickness); + MakeVector(vectorContent, QVector3D(0, len, 0), QColor(60, 120, 60), thickness); + MakeVector(vectorContent, QVector3D(0, 0, len), QColor(60, 60, 120), thickness); +} + +void JFJochViewerReciprocalSpaceWindow::setSpotColor(QColor input) { + if (!input.isValid()) + return; + spot_color = input; + rebuildSpots(); +} + +void JFJochViewerReciprocalSpaceWindow::setFeatureColor(QColor input) { + if (!input.isValid()) + return; + // Matches JFJochDiffractionImage: indexed spots use the feature color + indexed_color = input; + rebuildSpots(); +} + +void JFJochViewerReciprocalSpaceWindow::rebuildSpots() { + const bool crystal_frame = crystalFrameCheck->isChecked() && has_rotation_; + + QByteArray posData; + QByteArray colData; + posData.resize(static_cast(spots_.size() * 3 * sizeof(float))); + colData.resize(static_cast(spots_.size() * 3 * sizeof(float))); + + auto *pos = reinterpret_cast(posData.data()); + auto *col = reinterpret_cast(colData.data()); + + for (size_t i = 0; i < spots_.size(); i++) { + const Coord &c = crystal_frame ? spots_[i].recip_crystal : spots_[i].recip_lab; + pos[3 * i + 0] = c.x * scene_scale_; + pos[3 * i + 1] = c.y * scene_scale_; + pos[3 * i + 2] = c.z * scene_scale_; + + const QColor qc = SpotColorFor(spots_[i].indexed, spots_[i].ice_ring); + col[3 * i + 0] = static_cast(qc.redF()); + col[3 * i + 1] = static_cast(qc.greenF()); + col[3 * i + 2] = static_cast(qc.blueF()); + } + + spotPosBuffer->setData(posData); + spotColorBuffer->setData(colData); + + spotPosAttr->setCount(static_cast(spots_.size())); + spotColorAttr->setCount(static_cast(spots_.size())); + spotRenderer->setVertexCount(static_cast(spots_.size())); +} \ No newline at end of file diff --git a/viewer/windows/JFJochViewerReciprocalSpaceWindow.h b/viewer/windows/JFJochViewerReciprocalSpaceWindow.h new file mode 100644 index 00000000..0bced010 --- /dev/null +++ b/viewer/windows/JFJochViewerReciprocalSpaceWindow.h @@ -0,0 +1,85 @@ +// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute +// SPDX-License-Identifier: GPL-3.0-only + +#pragma once + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "JFJochHelperWindow.h" +#include "../../common/Coord.h" + +class JFJochViewerReciprocalSpaceWindow : public JFJochHelperWindow { + Q_OBJECT +public: + explicit JFJochViewerReciprocalSpaceWindow(QWidget *parent = nullptr); + +public slots: + // Keep 3D colors in sync with the 2D image + void setSpotColor(QColor input); + void setFeatureColor(QColor input); + + // Reset everything (called on new dataset) + void datasetLoaded(std::shared_ptr in_dataset) override; + // Add spots from currently open image (accumulating) + void imageLoaded(std::shared_ptr image) override; + +private slots: + void rebuildScene(); + +private: + struct AccumulatedSpot { + Coord recip_lab; // reciprocal coord in lab frame at the image's angle + Coord recip_crystal; // reciprocal coord rotated back to angle = 0 + bool indexed = false; + bool ice_ring = false; + }; + + void clearScene(); + void rebuildSpots(); // refresh the point-cloud buffers + void addCellVectors(); + void addAxes(); + + QColor SpotColorFor(bool indexed, bool ice_ring) const; + + Qt3DExtras::Qt3DWindow *view = nullptr; + Qt3DCore::QEntity *root = nullptr; + Qt3DCore::QEntity *vectorContent = nullptr; // re-created when cell/frame changes + + // Persistent point-cloud entity for spots + Qt3DCore::QEntity *spotEntity = nullptr; + Qt3DCore::QBuffer *spotPosBuffer = nullptr; + Qt3DCore::QBuffer *spotColorBuffer = nullptr; + Qt3DCore::QAttribute *spotPosAttr = nullptr; + Qt3DCore::QAttribute *spotColorAttr = nullptr; + Qt3DRender::QGeometryRenderer *spotRenderer = nullptr; + QCheckBox *accumulateCheck = nullptr; + + Qt3DExtras::QOrbitCameraController *camController = nullptr; + + std::vector spots_; + std::optional indexed_lattice_; + bool has_rotation_ = false; + + // UI options + QCheckBox *crystalFrameCheck = nullptr; // angle=0 frame vs current + QCheckBox *showCellCheck = nullptr; + + // Colors matching the diffraction image + QColor spot_color = Qt::green; + QColor indexed_color = Qt::magenta; // feature_color in image + QColor ice_ring_color = Qt::cyan; + + float scene_scale_ = 100.0f; // recip Å^-1 are small; scale up for rendering +}; \ No newline at end of file -- 2.52.0 From b66fa9e5c6b37493da68079c60abbbea9789e611 Mon Sep 17 00:00:00 2001 From: leonarski_f Date: Sun, 31 May 2026 19:48:21 +0200 Subject: [PATCH 18/27] JFJochViewerReciprocalSpaceWindow: Works, but is very slow --- .../JFJochViewerReciprocalSpaceWindow.cpp | 403 ++++++------------ .../JFJochViewerReciprocalSpaceWindow.h | 16 +- 2 files changed, 143 insertions(+), 276 deletions(-) diff --git a/viewer/windows/JFJochViewerReciprocalSpaceWindow.cpp b/viewer/windows/JFJochViewerReciprocalSpaceWindow.cpp index bcf52d92..31adc600 100644 --- a/viewer/windows/JFJochViewerReciprocalSpaceWindow.cpp +++ b/viewer/windows/JFJochViewerReciprocalSpaceWindow.cpp @@ -7,136 +7,92 @@ #include #include #include -#include +#include #include +#include +#include +#include #include #include -#include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include + #include "../../common/CrystalLattice.h" namespace { - // Custom material: per-vertex colored points with a fixed on-screen size. - // Needed because Qt6's QPerVertexColorMaterial doesn't let us control point size, - // and QPointSize must live inside the material's render pass to take effect. - Qt3DRender::QMaterial *MakePointMaterial(Qt3DCore::QNode *parent, float point_size) { - auto *material = new Qt3DRender::QMaterial(parent); - auto *effect = new Qt3DRender::QEffect(material); - auto *technique = new Qt3DRender::QTechnique(effect); - technique->graphicsApiFilter()->setApi(Qt3DRender::QGraphicsApiFilter::OpenGL); - technique->graphicsApiFilter()->setProfile(Qt3DRender::QGraphicsApiFilter::CoreProfile); - technique->graphicsApiFilter()->setMajorVersion(3); - technique->graphicsApiFilter()->setMinorVersion(3); +// Add a small sphere at the given position with the given color. +void AddBall(Qt3DCore::QEntity *parent, const QVector3D &pos, const QColor &color) { + auto *entity = new Qt3DCore::QEntity(parent); + auto *mesh = new Qt3DExtras::QSphereMesh(entity); + auto *material = new Qt3DExtras::QPhongMaterial(entity); + auto *transform = new Qt3DCore::QTransform(entity); - auto *filterKey = new Qt3DRender::QFilterKey(technique); - filterKey->setName(QStringLiteral("renderingStyle")); - filterKey->setValue(QStringLiteral("forward")); - technique->addFilterKey(filterKey); + mesh->setRadius(0.4f); + mesh->setRings(6); // low-poly: plenty for a tiny spot + mesh->setSlices(6); + material->setDiffuse(color); + material->setAmbient(color.darker(150)); + transform->setTranslation(pos); - const char *vertexShader = R"( - #version 330 core - in vec3 vertexPosition; - in vec3 vertexColor; - out vec3 fColor; - uniform mat4 modelViewProjection; - void main() { - fColor = vertexColor; - gl_Position = modelViewProjection * vec4(vertexPosition, 1.0); - gl_PointSize = 6.0; - } - )"; - - const char *fragmentShader = R"( - #version 330 core - in vec3 fColor; - out vec4 outColor; - void main() { outColor = vec4(fColor, 1.0); } - )"; - - auto *shader = new Qt3DRender::QShaderProgram(material); - shader->setVertexShaderCode(QByteArray(vertexShader)); - shader->setFragmentShaderCode(QByteArray(fragmentShader)); - - auto *pass = new Qt3DRender::QRenderPass(technique); - pass->setShaderProgram(shader); - - auto *ps = new Qt3DRender::QPointSize(pass); - ps->setSizeMode(Qt3DRender::QPointSize::Fixed); - ps->setValue(point_size); - pass->addRenderState(ps); - - technique->addRenderPass(pass); - effect->addTechnique(technique); - material->setEffect(effect); - return material; - } - - // Draw a cylinder from origin along the given (already scaled) vector. - Qt3DCore::QEntity *MakeVector(Qt3DCore::QEntity *parent, - const QVector3D &vec, - const QColor &color, - float thickness) { - auto *entity = new Qt3DCore::QEntity(parent); - - const float length = vec.length(); - if (length < 1e-6f) - return entity; - - auto *mesh = new Qt3DExtras::QCylinderMesh(); - mesh->setRadius(thickness); - mesh->setLength(length); - - auto *material = new Qt3DExtras::QPhongMaterial(); - material->setDiffuse(color); - - auto *transform = new Qt3DCore::QTransform(); - // QCylinderMesh is oriented along +Y by default; rotate +Y to vec direction. - const QVector3D yAxis(0, 1, 0); - const QVector3D dir = vec.normalized(); - const QQuaternion rot = QQuaternion::rotationTo(yAxis, dir); - transform->setRotation(rot); - transform->setTranslation(vec * 0.5f); // cylinder centered at its midpoint - - entity->addComponent(mesh); - entity->addComponent(material); - entity->addComponent(transform); - return entity; - } + entity->addComponent(mesh); + entity->addComponent(material); + entity->addComponent(transform); } +// Draw a cylinder from the origin along the given (already scaled) vector. +void AddVector(Qt3DCore::QEntity *parent, const QVector3D &vec, + const QColor &color, float thickness) { + const float length = vec.length(); + if (length < 1e-6f) + return; + + auto *entity = new Qt3DCore::QEntity(parent); + auto *mesh = new Qt3DExtras::QCylinderMesh(entity); + auto *material = new Qt3DExtras::QPhongMaterial(entity); + auto *transform = new Qt3DCore::QTransform(entity); + + mesh->setRadius(thickness); + mesh->setLength(length); + material->setDiffuse(color); + + // QCylinderMesh points along +Y; rotate to match vec direction. + const QQuaternion rot = QQuaternion::rotationTo(QVector3D(0, 1, 0), vec.normalized()); + transform->setRotation(rot); + transform->setTranslation(vec * 0.5f); + + entity->addComponent(mesh); + entity->addComponent(material); + entity->addComponent(transform); +} + +} // namespace + +// --------------------------------------------------------------------------- + JFJochViewerReciprocalSpaceWindow::JFJochViewerReciprocalSpaceWindow(QWidget *parent) - : JFJochHelperWindow(parent) { + : JFJochHelperWindow(parent) +{ setWindowTitle("Reciprocal space"); resize(800, 800); - auto *central = new QWidget(this); - auto *layout = new QVBoxLayout(central); + // --- Widget layout ------------------------------------------------------- + auto *central = new QWidget(this); + auto *layout = new QVBoxLayout(central); - // 3D view embedded in a QWidget container - view = new Qt3DExtras::Qt3DWindow(); - view->defaultFrameGraph()->setClearColor(QColor(20, 20, 25)); - QWidget *container = QWidget::createWindowContainer(view, central); + view_ = new Qt3DExtras::Qt3DWindow(); + view_->defaultFrameGraph()->setClearColor(QColor(20, 20, 25)); + QWidget *container = QWidget::createWindowContainer(view_, central); container->setMinimumSize(400, 400); container->setFocusPolicy(Qt::StrongFocus); layout->addWidget(container, 1); - // Controls auto *controls = new QHBoxLayout(); crystalFrameCheck = new QCheckBox("Crystal frame (angle = 0)", central); crystalFrameCheck->setChecked(false); - crystalFrameCheck->setEnabled(false); // only for rotation data + crystalFrameCheck->setEnabled(false); showCellCheck = new QCheckBox("Show reciprocal cell", central); showCellCheck->setChecked(true); accumulateCheck = new QCheckBox("Accumulate", central); @@ -149,101 +105,48 @@ JFJochViewerReciprocalSpaceWindow::JFJochViewerReciprocalSpaceWindow(QWidget *pa controls->addStretch(1); controls->addWidget(clearButton); layout->addLayout(controls); - setCentralWidget(central); - connect(crystalFrameCheck, &QCheckBox::toggled, this, - &JFJochViewerReciprocalSpaceWindow::rebuildSpots); // frame change → reposition points only - connect(showCellCheck, &QCheckBox::toggled, this, - &JFJochViewerReciprocalSpaceWindow::rebuildScene); // cell vectors only + connect(crystalFrameCheck, &QCheckBox::toggled, + this, &JFJochViewerReciprocalSpaceWindow::rebuildScene); + connect(showCellCheck, &QCheckBox::toggled, + this, &JFJochViewerReciprocalSpaceWindow::rebuildScene); connect(clearButton, &QPushButton::clicked, this, [this] { spots_.clear(); - rebuildSpots(); + rebuildScene(); }); - // Root entity + camera - root = new Qt3DCore::QEntity(); + // --- Qt3D scene ---------------------------------------------------------- + root_ = new Qt3DCore::QEntity(); - auto *camera = view->camera(); + auto *camera = view_->camera(); camera->lens()->setPerspectiveProjection(45.0f, 1.0f, 0.1f, 10000.0f); camera->setPosition(QVector3D(0, 0, 80)); camera->setViewCenter(QVector3D(0, 0, 0)); - auto *lightEntity = new Qt3DCore::QEntity(root); - auto *light = new Qt3DRender::QPointLight(lightEntity); + auto *lightEntity = new Qt3DCore::QEntity(root_); + auto *light = new Qt3DRender::QPointLight(lightEntity); light->setIntensity(1.0f); auto *lightTransform = new Qt3DCore::QTransform(lightEntity); lightTransform->setTranslation(QVector3D(0, 0, 200)); lightEntity->addComponent(light); lightEntity->addComponent(lightTransform); - camController = new Qt3DExtras::QOrbitCameraController(root); + auto *camController = new Qt3DExtras::QOrbitCameraController(root_); camController->setCamera(camera); - // --- Persistent point-cloud entity for spots (one draw call for all spots) --- - spotEntity = new Qt3DCore::QEntity(root); + view_->setRootEntity(root_); - auto *geometry = new Qt3DCore::QGeometry(spotEntity); - - spotPosBuffer = new Qt3DCore::QBuffer(geometry); - spotColorBuffer = new Qt3DCore::QBuffer(geometry); - - spotPosAttr = new Qt3DCore::QAttribute(geometry); - spotPosAttr->setName(Qt3DCore::QAttribute::defaultPositionAttributeName()); - spotPosAttr->setVertexBaseType(Qt3DCore::QAttribute::Float); - spotPosAttr->setVertexSize(3); - spotPosAttr->setAttributeType(Qt3DCore::QAttribute::VertexAttribute); - spotPosAttr->setBuffer(spotPosBuffer); - spotPosAttr->setByteStride(3 * sizeof(float)); - geometry->addAttribute(spotPosAttr); - - spotColorAttr = new Qt3DCore::QAttribute(geometry); - spotColorAttr->setName(Qt3DCore::QAttribute::defaultColorAttributeName()); - spotColorAttr->setVertexBaseType(Qt3DCore::QAttribute::Float); - spotColorAttr->setVertexSize(3); - spotColorAttr->setAttributeType(Qt3DCore::QAttribute::VertexAttribute); - spotColorAttr->setBuffer(spotColorBuffer); - spotColorAttr->setByteStride(3 * sizeof(float)); - geometry->addAttribute(spotColorAttr); - - spotRenderer = new Qt3DRender::QGeometryRenderer(spotEntity); - spotRenderer->setGeometry(geometry); - spotRenderer->setPrimitiveType(Qt3DRender::QGeometryRenderer::Points); - - // Reuse Qt's working per-vertex-color material, but inject a QPointSize render - // state into its existing render pass so the points are large enough to see. - auto *spotMaterial = new Qt3DExtras::QPerVertexColorMaterial(spotEntity); - if (auto *effect = spotMaterial->effect()) { - const auto techniques = effect->techniques(); - for (auto *technique : techniques) { - const auto passes = technique->renderPasses(); - for (auto *pass : passes) { - auto *ps = new Qt3DRender::QPointSize(pass); - ps->setSizeMode(Qt3DRender::QPointSize::Fixed); - ps->setValue(8.0f); - pass->addRenderState(ps); - } - } - } - spotEntity->addComponent(spotRenderer); - spotEntity->addComponent(spotMaterial); - - view->setRootEntity(root); - - rebuildSpots(); - rebuildScene(); // builds axes + cell vectors + rebuildScene(); } -QColor JFJochViewerReciprocalSpaceWindow::SpotColorFor(bool indexed, bool ice_ring) const { - if (indexed) - return indexed_color; - if (ice_ring) - return ice_ring_color; - return spot_color; -} +// --------------------------------------------------------------------------- +// Public slots +// --------------------------------------------------------------------------- -void JFJochViewerReciprocalSpaceWindow::datasetLoaded(std::shared_ptr in_dataset) { - // New dataset: clean things (metadata update handled separately, later) +void JFJochViewerReciprocalSpaceWindow::datasetLoaded( + std::shared_ptr in_dataset) +{ spots_.clear(); indexed_lattice_.reset(); has_rotation_ = false; @@ -258,7 +161,8 @@ void JFJochViewerReciprocalSpaceWindow::datasetLoaded(std::shared_ptr image) { +void JFJochViewerReciprocalSpaceWindow::imageLoaded(std::shared_ptr image) +{ if (!accumulateCheck->isChecked()) { spots_.clear(); indexed_lattice_.reset(); @@ -269,13 +173,11 @@ void JFJochViewerReciprocalSpaceWindow::imageLoaded(std::shared_ptrDataset(); - const auto geom = dataset.experiment.GetDiffractionGeometry(); - const auto axis = dataset.experiment.GetGoniometer(); + const auto &dataset = image->Dataset(); + const auto geom = dataset.experiment.GetDiffractionGeometry(); + const auto axis = dataset.experiment.GetGoniometer(); const int64_t image_number = image->ImageData().number; - // Goniometer back-rotation to bring the image into the angle = 0 crystal frame, - // same convention as RotationIndexer / XtalOptimizer. std::optional back_rot; if (axis) { const float angle_deg = axis->GetAngle_deg(static_cast(image_number)) @@ -286,116 +188,87 @@ void JFJochViewerReciprocalSpaceWindow::imageLoaded(std::shared_ptrImageData().spots.size()); for (const auto &s : image->ImageData().spots) { AccumulatedSpot acc; - acc.recip_lab = s.ReciprocalCoord(geom); - acc.recip_crystal = back_rot ? (back_rot.value() * acc.recip_lab) : acc.recip_lab; - acc.indexed = s.indexed; - acc.ice_ring = s.ice_ring; + acc.recip_lab = s.ReciprocalCoord(geom); + acc.recip_crystal = back_rot ? (*back_rot * acc.recip_lab) : acc.recip_lab; + acc.indexed = s.indexed; + acc.ice_ring = s.ice_ring; spots_.emplace_back(acc); } - // Soft cap so a long accumulation doesn't grow unbounded - constexpr size_t max_accumulated = 200000; - if (spots_.size() > max_accumulated) - spots_.erase(spots_.begin(), - spots_.begin() + static_cast(spots_.size() - max_accumulated)); + // Soft cap: drop oldest when accumulation grows too large. + constexpr size_t max_accumulated = 5000; // sphere-per-spot: keep this sane + while (spots_.size() > max_accumulated) + spots_.erase(spots_.begin()); - // Keep the latest indexed lattice, if available if (image->ImageData().indexing_lattice) indexed_lattice_ = image->ImageData().indexing_lattice; - rebuildSpots(); - rebuildScene(); // in case the cell/lattice changed + rebuildScene(); } -void JFJochViewerReciprocalSpaceWindow::clearScene() { - if (vectorContent) { - vectorContent->setParent(static_cast(nullptr)); - vectorContent->deleteLater(); - vectorContent = nullptr; - } +void JFJochViewerReciprocalSpaceWindow::setSpotColor(QColor input) { + if (!input.isValid()) return; + spot_color = input; + rebuildScene(); +} + +void JFJochViewerReciprocalSpaceWindow::setFeatureColor(QColor input) { + if (!input.isValid()) return; + indexed_color = input; + rebuildScene(); +} + +// --------------------------------------------------------------------------- +// Private helpers +// --------------------------------------------------------------------------- + +QColor JFJochViewerReciprocalSpaceWindow::spotColorFor(bool indexed, bool ice_ring) const { + if (indexed) return indexed_color; + if (ice_ring) return ice_ring_color; + return spot_color; } void JFJochViewerReciprocalSpaceWindow::rebuildScene() { - // Only rebuilds the (few) axis + reciprocal-cell vectors. - clearScene(); - vectorContent = new Qt3DCore::QEntity(root); + // Delete the previous scene content (axes, cell vectors, all spot balls). + // root_ itself stays alive — only its dynamic child is replaced. + if (sceneContent_) { + delete sceneContent_; // Qt parent-child: also deletes all children + sceneContent_ = nullptr; + } + + sceneContent_ = new Qt3DCore::QEntity(root_); addAxes(); if (showCellCheck->isChecked() && indexed_lattice_) addCellVectors(); + addSpots(); +} + +void JFJochViewerReciprocalSpaceWindow::addAxes() { + const float len = 10.0f; + const float thickness = 0.05f; + AddVector(sceneContent_, QVector3D(len, 0, 0), QColor(120, 60, 60), thickness); + AddVector(sceneContent_, QVector3D(0, len, 0), QColor(60, 120, 60), thickness); + AddVector(sceneContent_, QVector3D(0, 0, len), QColor(60, 60, 120), thickness); } void JFJochViewerReciprocalSpaceWindow::addCellVectors() { - if (!indexed_lattice_) - return; - const Coord astar = indexed_lattice_->Astar(); const Coord bstar = indexed_lattice_->Bstar(); const Coord cstar = indexed_lattice_->Cstar(); const float thickness = 0.15f; - MakeVector(vectorContent, - QVector3D(astar.x, astar.y, astar.z) * scene_scale_, - Qt::red, thickness); - MakeVector(vectorContent, - QVector3D(bstar.x, bstar.y, bstar.z) * scene_scale_, - Qt::green, thickness); - MakeVector(vectorContent, - QVector3D(cstar.x, cstar.y, cstar.z) * scene_scale_, - Qt::blue, thickness); + AddVector(sceneContent_, QVector3D(astar.x, astar.y, astar.z) * scene_scale_, Qt::red, thickness); + AddVector(sceneContent_, QVector3D(bstar.x, bstar.y, bstar.z) * scene_scale_, Qt::green, thickness); + AddVector(sceneContent_, QVector3D(cstar.x, cstar.y, cstar.z) * scene_scale_, Qt::blue, thickness); } -void JFJochViewerReciprocalSpaceWindow::addAxes() { - // Faint reference axes (lab frame X/Y/Z) for orientation - const float len = 10.0f; - const float thickness = 0.05f; - MakeVector(vectorContent, QVector3D(len, 0, 0), QColor(120, 60, 60), thickness); - MakeVector(vectorContent, QVector3D(0, len, 0), QColor(60, 120, 60), thickness); - MakeVector(vectorContent, QVector3D(0, 0, len), QColor(60, 60, 120), thickness); -} - -void JFJochViewerReciprocalSpaceWindow::setSpotColor(QColor input) { - if (!input.isValid()) - return; - spot_color = input; - rebuildSpots(); -} - -void JFJochViewerReciprocalSpaceWindow::setFeatureColor(QColor input) { - if (!input.isValid()) - return; - // Matches JFJochDiffractionImage: indexed spots use the feature color - indexed_color = input; - rebuildSpots(); -} - -void JFJochViewerReciprocalSpaceWindow::rebuildSpots() { +void JFJochViewerReciprocalSpaceWindow::addSpots() { const bool crystal_frame = crystalFrameCheck->isChecked() && has_rotation_; - QByteArray posData; - QByteArray colData; - posData.resize(static_cast(spots_.size() * 3 * sizeof(float))); - colData.resize(static_cast(spots_.size() * 3 * sizeof(float))); - - auto *pos = reinterpret_cast(posData.data()); - auto *col = reinterpret_cast(colData.data()); - - for (size_t i = 0; i < spots_.size(); i++) { - const Coord &c = crystal_frame ? spots_[i].recip_crystal : spots_[i].recip_lab; - pos[3 * i + 0] = c.x * scene_scale_; - pos[3 * i + 1] = c.y * scene_scale_; - pos[3 * i + 2] = c.z * scene_scale_; - - const QColor qc = SpotColorFor(spots_[i].indexed, spots_[i].ice_ring); - col[3 * i + 0] = static_cast(qc.redF()); - col[3 * i + 1] = static_cast(qc.greenF()); - col[3 * i + 2] = static_cast(qc.blueF()); + for (const auto &spot : spots_) { + const Coord &c = crystal_frame ? spot.recip_crystal : spot.recip_lab; + const QVector3D pos(c.x * scene_scale_, c.y * scene_scale_, c.z * scene_scale_); + AddBall(sceneContent_, pos, spotColorFor(spot.indexed, spot.ice_ring)); } - - spotPosBuffer->setData(posData); - spotColorBuffer->setData(colData); - - spotPosAttr->setCount(static_cast(spots_.size())); - spotColorAttr->setCount(static_cast(spots_.size())); - spotRenderer->setVertexCount(static_cast(spots_.size())); } \ No newline at end of file diff --git a/viewer/windows/JFJochViewerReciprocalSpaceWindow.h b/viewer/windows/JFJochViewerReciprocalSpaceWindow.h index 0bced010..6654358f 100644 --- a/viewer/windows/JFJochViewerReciprocalSpaceWindow.h +++ b/viewer/windows/JFJochViewerReciprocalSpaceWindow.h @@ -51,19 +51,12 @@ private: void addCellVectors(); void addAxes(); - QColor SpotColorFor(bool indexed, bool ice_ring) const; + QColor spotColorFor(bool indexed, bool ice_ring) const; - Qt3DExtras::Qt3DWindow *view = nullptr; - Qt3DCore::QEntity *root = nullptr; - Qt3DCore::QEntity *vectorContent = nullptr; // re-created when cell/frame changes + Qt3DExtras::Qt3DWindow *view_ = nullptr; + Qt3DCore::QEntity *root_ = nullptr; + Qt3DCore::QEntity *sceneContent_ = nullptr; // re-created when cell/frame changes - // Persistent point-cloud entity for spots - Qt3DCore::QEntity *spotEntity = nullptr; - Qt3DCore::QBuffer *spotPosBuffer = nullptr; - Qt3DCore::QBuffer *spotColorBuffer = nullptr; - Qt3DCore::QAttribute *spotPosAttr = nullptr; - Qt3DCore::QAttribute *spotColorAttr = nullptr; - Qt3DRender::QGeometryRenderer *spotRenderer = nullptr; QCheckBox *accumulateCheck = nullptr; Qt3DExtras::QOrbitCameraController *camController = nullptr; @@ -82,4 +75,5 @@ private: QColor ice_ring_color = Qt::cyan; float scene_scale_ = 100.0f; // recip Å^-1 are small; scale up for rendering + void addSpots(); }; \ No newline at end of file -- 2.52.0 From baeef1960e88cf7e8ba904cae0eb0cbe056ab28d Mon Sep 17 00:00:00 2001 From: leonarski_f Date: Sun, 31 May 2026 19:59:13 +0200 Subject: [PATCH 19/27] JFJochViewerReciprocalSpaceWindow: OpenGL version, seems to work well --- viewer/CMakeLists.txt | 4 +- .../JFJochViewerReciprocalSpaceWindow.cpp | 413 ++++++++++++------ .../JFJochViewerReciprocalSpaceWindow.h | 141 +++--- 3 files changed, 364 insertions(+), 194 deletions(-) diff --git a/viewer/CMakeLists.txt b/viewer/CMakeLists.txt index c8f90ef8..0db42e76 100644 --- a/viewer/CMakeLists.txt +++ b/viewer/CMakeLists.txt @@ -5,7 +5,7 @@ SET(CMAKE_AUTOMOC ON) SET(CMAKE_AUTORCC ON) SET(CMAKE_AUTOUIC ON) -FIND_PACKAGE(Qt6 COMPONENTS Core Gui Widgets Charts DBus Concurrent 3DCore 3DRender 3DExtras 3DInput REQUIRED) +FIND_PACKAGE(Qt6 COMPONENTS Core Gui Widgets Charts DBus Concurrent OpenGL OpenGLWidgets REQUIRED) QT_ADD_RESOURCES(APP_RESOURCES resources/resources.qrc) @@ -89,7 +89,7 @@ ADD_EXECUTABLE(jfjoch_viewer jfjoch_viewer.cpp JFJochViewerWindow.cpp JFJochView ) TARGET_LINK_LIBRARIES(jfjoch_viewer Qt6::Core Qt6::Gui Qt6::Widgets Qt6::Charts Qt6::DBus Qt6::Concurrent - Qt6::3DCore Qt6::3DRender Qt6::3DExtras Qt6::3DInput + Qt6::OpenGL Qt6::OpenGLWidgets JFJochReader JFJochLogger JFJochCommon JFJochWriter JFJochImageAnalysis) INSTALL(TARGETS jfjoch_viewer RUNTIME COMPONENT viewer) diff --git a/viewer/windows/JFJochViewerReciprocalSpaceWindow.cpp b/viewer/windows/JFJochViewerReciprocalSpaceWindow.cpp index 31adc600..c2403cf0 100644 --- a/viewer/windows/JFJochViewerReciprocalSpaceWindow.cpp +++ b/viewer/windows/JFJochViewerReciprocalSpaceWindow.cpp @@ -3,91 +3,222 @@ #include "JFJochViewerReciprocalSpaceWindow.h" -#include #include #include #include +#include +#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +// ============================================================================ +// Shaders +// ============================================================================ -#include "../../common/CrystalLattice.h" +// One shader handles both spots (GL_POINTS) and lines (GL_LINES). +// Per-vertex color comes straight from the VBO; MVP is a single uniform. -namespace { +static const char *kVertSrc = R"( + #version 330 core + layout(location = 0) in vec3 aPos; + layout(location = 1) in vec3 aColor; + out vec3 vColor; + uniform mat4 uMVP; + void main() { + vColor = aColor; + gl_Position = uMVP * vec4(aPos, 1.0); + gl_PointSize = 6.0; + } +)"; -// Add a small sphere at the given position with the given color. -void AddBall(Qt3DCore::QEntity *parent, const QVector3D &pos, const QColor &color) { - auto *entity = new Qt3DCore::QEntity(parent); - auto *mesh = new Qt3DExtras::QSphereMesh(entity); - auto *material = new Qt3DExtras::QPhongMaterial(entity); - auto *transform = new Qt3DCore::QTransform(entity); +static const char *kFragSrc = R"( + #version 330 core + in vec3 vColor; + out vec4 fragColor; + void main() { + // Discard corners to draw a circle instead of a square point. + vec2 c = gl_PointCoord - vec2(0.5); + if (dot(c, c) > 0.25) discard; + fragColor = vec4(vColor, 1.0); + } +)"; - mesh->setRadius(0.4f); - mesh->setRings(6); // low-poly: plenty for a tiny spot - mesh->setSlices(6); - material->setDiffuse(color); - material->setAmbient(color.darker(150)); - transform->setTranslation(pos); +// ============================================================================ +// ReciprocalSpaceGLView +// ============================================================================ - entity->addComponent(mesh); - entity->addComponent(material); - entity->addComponent(transform); +ReciprocalSpaceGLView::ReciprocalSpaceGLView(QWidget *parent) + : QOpenGLWidget(parent) + , spotsVBO_(QOpenGLBuffer::VertexBuffer) + , linesVBO_(QOpenGLBuffer::VertexBuffer) +{ + // Request OpenGL 3.3 Core Profile (Linux/NVIDIA, Mesa, macOS all support this) + QSurfaceFormat fmt; + fmt.setVersion(3, 3); + fmt.setProfile(QSurfaceFormat::CoreProfile); + fmt.setDepthBufferSize(24); + setFormat(fmt); + setFocusPolicy(Qt::StrongFocus); } -// Draw a cylinder from the origin along the given (already scaled) vector. -void AddVector(Qt3DCore::QEntity *parent, const QVector3D &vec, - const QColor &color, float thickness) { - const float length = vec.length(); - if (length < 1e-6f) - return; - - auto *entity = new Qt3DCore::QEntity(parent); - auto *mesh = new Qt3DExtras::QCylinderMesh(entity); - auto *material = new Qt3DExtras::QPhongMaterial(entity); - auto *transform = new Qt3DCore::QTransform(entity); - - mesh->setRadius(thickness); - mesh->setLength(length); - material->setDiffuse(color); - - // QCylinderMesh points along +Y; rotate to match vec direction. - const QQuaternion rot = QQuaternion::rotationTo(QVector3D(0, 1, 0), vec.normalized()); - transform->setRotation(rot); - transform->setTranslation(vec * 0.5f); - - entity->addComponent(mesh); - entity->addComponent(material); - entity->addComponent(transform); +ReciprocalSpaceGLView::~ReciprocalSpaceGLView() { + makeCurrent(); + spotsVAO_.destroy(); + spotsVBO_.destroy(); + linesVAO_.destroy(); + linesVBO_.destroy(); + doneCurrent(); } -} // namespace +void ReciprocalSpaceGLView::initializeGL() { + initializeOpenGLFunctions(); + + glClearColor(20.f/255, 20.f/255, 25.f/255, 1.0f); + glEnable(GL_DEPTH_TEST); + glEnable(GL_PROGRAM_POINT_SIZE); // lets the vertex shader set gl_PointSize + + shader_.addShaderFromSourceCode(QOpenGLShader::Vertex, kVertSrc); + shader_.addShaderFromSourceCode(QOpenGLShader::Fragment, kFragSrc); + shader_.link(); + + // Create empty VAO/VBOs so they are valid before the first data arrives. + setupVAO(spotsVAO_, spotsVBO_); + setupVAO(linesVAO_, linesVBO_); +} + +void ReciprocalSpaceGLView::resizeGL(int w, int h) { + proj_.setToIdentity(); + proj_.perspective(45.0f, float(w) / float(h ? h : 1), 0.1f, 10000.0f); +} + +void ReciprocalSpaceGLView::paintGL() { + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + // Build view matrix from orbit camera state. + QMatrix4x4 view; + view.translate(0, 0, -zoom_); + view.rotate(pitch_, 1, 0, 0); + view.rotate(yaw_, 0, 1, 0); + + const QMatrix4x4 mvp = proj_ * view; + + shader_.bind(); + shader_.setUniformValue("uMVP", mvp); + + // Draw axes + cell vectors + if (linesCount_ > 0) { + linesVAO_.bind(); + glDrawArrays(GL_LINES, 0, linesCount_); + linesVAO_.release(); + } + + // Draw spots + if (spotsCount_ > 0) { + spotsVAO_.bind(); + glDrawArrays(GL_POINTS, 0, spotsCount_); + spotsVAO_.release(); + } + + shader_.release(); +} // --------------------------------------------------------------------------- +void ReciprocalSpaceGLView::setSpots(const std::vector &spots) { + makeCurrent(); + uploadBuffer(spotsVBO_, spotsVAO_, spots); + spotsCount_ = static_cast(spots.size()); + doneCurrent(); + update(); +} + +void ReciprocalSpaceGLView::setLines(const std::vector &lines) { + makeCurrent(); + uploadBuffer(linesVBO_, linesVAO_, lines); + linesCount_ = static_cast(lines.size()); + doneCurrent(); + update(); +} + +// --------------------------------------------------------------------------- + +void ReciprocalSpaceGLView::setupVAO(QOpenGLVertexArrayObject &vao, + QOpenGLBuffer &vbo) { + vao.create(); + vao.bind(); + vbo.create(); + vbo.bind(); + + // location 0: position (xyz) + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, + sizeof(Vertex), + reinterpret_cast(offsetof(Vertex, x))); + // location 1: color (rgb) + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, + sizeof(Vertex), + reinterpret_cast(offsetof(Vertex, r))); + + vbo.release(); + vao.release(); +} + +void ReciprocalSpaceGLView::uploadBuffer(QOpenGLBuffer &vbo, + QOpenGLVertexArrayObject &vao, + const std::vector &data) { + vao.bind(); + vbo.bind(); + if (data.empty()) { + vbo.allocate(nullptr, 0); + } else { + vbo.allocate(data.data(), + static_cast(data.size() * sizeof(Vertex))); + } + vbo.release(); + vao.release(); +} + +// --------------------------------------------------------------------------- +// Mouse / wheel -> orbit camera +// --------------------------------------------------------------------------- + +void ReciprocalSpaceGLView::mousePressEvent(QMouseEvent *e) { + lastMousePos_ = e->pos(); +} + +void ReciprocalSpaceGLView::mouseMoveEvent(QMouseEvent *e) { + const QPoint delta = e->pos() - lastMousePos_; + lastMousePos_ = e->pos(); + + if (e->buttons() & Qt::LeftButton) { + yaw_ += delta.x() * 0.5f; + pitch_ += delta.y() * 0.5f; + pitch_ = qBound(-89.0f, pitch_, 89.0f); + update(); + } +} + +void ReciprocalSpaceGLView::wheelEvent(QWheelEvent *e) { + zoom_ *= (e->angleDelta().y() > 0) ? 0.9f : 1.1f; + zoom_ = qBound(1.0f, zoom_, 5000.0f); + update(); +} + +// ============================================================================ +// JFJochViewerReciprocalSpaceWindow +// ============================================================================ + JFJochViewerReciprocalSpaceWindow::JFJochViewerReciprocalSpaceWindow(QWidget *parent) : JFJochHelperWindow(parent) { setWindowTitle("Reciprocal space"); resize(800, 800); - // --- Widget layout ------------------------------------------------------- - auto *central = new QWidget(this); - auto *layout = new QVBoxLayout(central); + auto *central = new QWidget(this); + auto *layout = new QVBoxLayout(central); - view_ = new Qt3DExtras::Qt3DWindow(); - view_->defaultFrameGraph()->setClearColor(QColor(20, 20, 25)); - QWidget *container = QWidget::createWindowContainer(view_, central); - container->setMinimumSize(400, 400); - container->setFocusPolicy(Qt::StrongFocus); - layout->addWidget(container, 1); + glView_ = new ReciprocalSpaceGLView(central); + glView_->setMinimumSize(400, 400); + layout->addWidget(glView_, 1); auto *controls = new QHBoxLayout(); crystalFrameCheck = new QCheckBox("Crystal frame (angle = 0)", central); @@ -108,36 +239,15 @@ JFJochViewerReciprocalSpaceWindow::JFJochViewerReciprocalSpaceWindow(QWidget *pa setCentralWidget(central); connect(crystalFrameCheck, &QCheckBox::toggled, - this, &JFJochViewerReciprocalSpaceWindow::rebuildScene); + this, &JFJochViewerReciprocalSpaceWindow::rebuildGL); connect(showCellCheck, &QCheckBox::toggled, - this, &JFJochViewerReciprocalSpaceWindow::rebuildScene); + this, &JFJochViewerReciprocalSpaceWindow::rebuildGL); connect(clearButton, &QPushButton::clicked, this, [this] { spots_.clear(); - rebuildScene(); + rebuildGL(); }); - // --- Qt3D scene ---------------------------------------------------------- - root_ = new Qt3DCore::QEntity(); - - auto *camera = view_->camera(); - camera->lens()->setPerspectiveProjection(45.0f, 1.0f, 0.1f, 10000.0f); - camera->setPosition(QVector3D(0, 0, 80)); - camera->setViewCenter(QVector3D(0, 0, 0)); - - auto *lightEntity = new Qt3DCore::QEntity(root_); - auto *light = new Qt3DRender::QPointLight(lightEntity); - light->setIntensity(1.0f); - auto *lightTransform = new Qt3DCore::QTransform(lightEntity); - lightTransform->setTranslation(QVector3D(0, 0, 200)); - lightEntity->addComponent(light); - lightEntity->addComponent(lightTransform); - - auto *camController = new Qt3DExtras::QOrbitCameraController(root_); - camController->setCamera(camera); - - view_->setRootEntity(root_); - - rebuildScene(); + rebuildGL(); } // --------------------------------------------------------------------------- @@ -158,10 +268,11 @@ void JFJochViewerReciprocalSpaceWindow::datasetLoaded( if (!has_rotation_) crystalFrameCheck->setChecked(false); - rebuildScene(); + rebuildGL(); } -void JFJochViewerReciprocalSpaceWindow::imageLoaded(std::shared_ptr image) +void JFJochViewerReciprocalSpaceWindow::imageLoaded( + std::shared_ptr image) { if (!accumulateCheck->isChecked()) { spots_.clear(); @@ -169,13 +280,13 @@ void JFJochViewerReciprocalSpaceWindow::imageLoaded(std::shared_ptrDataset(); - const auto geom = dataset.experiment.GetDiffractionGeometry(); - const auto axis = dataset.experiment.GetGoniometer(); + const auto &dataset = image->Dataset(); + const auto geom = dataset.experiment.GetDiffractionGeometry(); + const auto axis = dataset.experiment.GetGoniometer(); const int64_t image_number = image->ImageData().number; std::optional back_rot; @@ -195,80 +306,102 @@ void JFJochViewerReciprocalSpaceWindow::imageLoaded(std::shared_ptr max_accumulated) - spots_.erase(spots_.begin()); + // Soft cap: no per-spot Qt objects here, so 200k is fine. + constexpr size_t max_accumulated = 200000; + if (spots_.size() > max_accumulated) + spots_.erase(spots_.begin(), + spots_.begin() + + static_cast(spots_.size() - max_accumulated)); if (image->ImageData().indexing_lattice) indexed_lattice_ = image->ImageData().indexing_lattice; - rebuildScene(); + rebuildGL(); } void JFJochViewerReciprocalSpaceWindow::setSpotColor(QColor input) { if (!input.isValid()) return; spot_color = input; - rebuildScene(); + rebuildGL(); } void JFJochViewerReciprocalSpaceWindow::setFeatureColor(QColor input) { if (!input.isValid()) return; indexed_color = input; - rebuildScene(); + rebuildGL(); } // --------------------------------------------------------------------------- -// Private helpers +// Private // --------------------------------------------------------------------------- -QColor JFJochViewerReciprocalSpaceWindow::spotColorFor(bool indexed, bool ice_ring) const { +QColor JFJochViewerReciprocalSpaceWindow::spotColorFor(bool indexed, + bool ice_ring) const { if (indexed) return indexed_color; if (ice_ring) return ice_ring_color; return spot_color; } -void JFJochViewerReciprocalSpaceWindow::rebuildScene() { - // Delete the previous scene content (axes, cell vectors, all spot balls). - // root_ itself stays alive — only its dynamic child is replaced. - if (sceneContent_) { - delete sceneContent_; // Qt parent-child: also deletes all children - sceneContent_ = nullptr; - } - - sceneContent_ = new Qt3DCore::QEntity(root_); - - addAxes(); - if (showCellCheck->isChecked() && indexed_lattice_) - addCellVectors(); - addSpots(); -} - -void JFJochViewerReciprocalSpaceWindow::addAxes() { - const float len = 10.0f; - const float thickness = 0.05f; - AddVector(sceneContent_, QVector3D(len, 0, 0), QColor(120, 60, 60), thickness); - AddVector(sceneContent_, QVector3D(0, len, 0), QColor(60, 120, 60), thickness); - AddVector(sceneContent_, QVector3D(0, 0, len), QColor(60, 60, 120), thickness); -} - -void JFJochViewerReciprocalSpaceWindow::addCellVectors() { - const Coord astar = indexed_lattice_->Astar(); - const Coord bstar = indexed_lattice_->Bstar(); - const Coord cstar = indexed_lattice_->Cstar(); - - const float thickness = 0.15f; - AddVector(sceneContent_, QVector3D(astar.x, astar.y, astar.z) * scene_scale_, Qt::red, thickness); - AddVector(sceneContent_, QVector3D(bstar.x, bstar.y, bstar.z) * scene_scale_, Qt::green, thickness); - AddVector(sceneContent_, QVector3D(cstar.x, cstar.y, cstar.z) * scene_scale_, Qt::blue, thickness); -} - -void JFJochViewerReciprocalSpaceWindow::addSpots() { +void JFJochViewerReciprocalSpaceWindow::rebuildGL() { const bool crystal_frame = crystalFrameCheck->isChecked() && has_rotation_; + // --- Spots --------------------------------------------------------------- + std::vector spotVerts; + spotVerts.reserve(spots_.size()); + + // Precompute the three possible colors as floats — avoids QColor in the loop. + auto toF = [](const QColor &c, float &r, float &g, float &b) { + r = float(c.redF()); g = float(c.greenF()); b = float(c.blueF()); + }; + float sr, sg, sb, ir, ig, ib, xr, xg, xb; + toF(spot_color, sr, sg, sb); + toF(indexed_color, ir, ig, ib); + toF(ice_ring_color, xr, xg, xb); + for (const auto &spot : spots_) { const Coord &c = crystal_frame ? spot.recip_crystal : spot.recip_lab; - const QVector3D pos(c.x * scene_scale_, c.y * scene_scale_, c.z * scene_scale_); - AddBall(sceneContent_, pos, spotColorFor(spot.indexed, spot.ice_ring)); + float r, g, b; + if (spot.indexed) { r = ir; g = ig; b = ib; } + else if (spot.ice_ring) { r = xr; g = xg; b = xb; } + else { r = sr; g = sg; b = sb; } + spotVerts.push_back({ c.x * scene_scale_, + c.y * scene_scale_, + c.z * scene_scale_, + r, g, b }); } + + // --- Lines: axes + optional cell vectors --------------------------------- + // Each segment = 2 vertices (GL_LINES draws pairs). + std::vector lineVerts; + + auto addLine = [&](QVector3D a, QVector3D b, QColor col) { + const float r = float(col.redF()), + g = float(col.greenF()), + bv = float(col.blueF()); + lineVerts.push_back({ a.x(), a.y(), a.z(), r, g, bv }); + lineVerts.push_back({ b.x(), b.y(), b.z(), r, g, bv }); + }; + + // Reference axes + const float len = 10.0f; + addLine({0,0,0}, {len,0,0}, QColor(180, 60, 60)); + addLine({0,0,0}, {0,len,0}, QColor(60, 180, 60)); + addLine({0,0,0}, {0,0,len}, QColor(60, 60, 180)); + + // Reciprocal cell vectors + if (showCellCheck->isChecked() && indexed_lattice_) { + auto addCell = [&](const Coord &v, QColor col) { + addLine({0, 0, 0}, + { v.x * scene_scale_, + v.y * scene_scale_, + v.z * scene_scale_ }, + col); + }; + addCell(indexed_lattice_->Astar(), Qt::red); + addCell(indexed_lattice_->Bstar(), Qt::green); + addCell(indexed_lattice_->Cstar(), Qt::blue); + } + + glView_->setSpots(spotVerts); + glView_->setLines(lineVerts); } \ No newline at end of file diff --git a/viewer/windows/JFJochViewerReciprocalSpaceWindow.h b/viewer/windows/JFJochViewerReciprocalSpaceWindow.h index 6654358f..06e9da28 100644 --- a/viewer/windows/JFJochViewerReciprocalSpaceWindow.h +++ b/viewer/windows/JFJochViewerReciprocalSpaceWindow.h @@ -1,79 +1,116 @@ // SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only - #pragma once +#include #include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include + #include +#include +#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "JFJochHelperWindow.h" // your existing base class +#include "../../common/CrystalLattice.h" // Coord, RotMatrix, etc. -#include "JFJochHelperWindow.h" -#include "../../common/Coord.h" +// Forward declarations from your codebase +class JFJochReaderDataset; +class JFJochReaderImage; +// --------------------------------------------------------------------------- +// ReciprocalSpaceGLView – the actual OpenGL viewport +// --------------------------------------------------------------------------- +class ReciprocalSpaceGLView : public QOpenGLWidget, + protected QOpenGLFunctions_3_3_Core { + Q_OBJECT +public: + explicit ReciprocalSpaceGLView(QWidget *parent = nullptr); + ~ReciprocalSpaceGLView() override; + + struct Vertex { float x, y, z, r, g, b; }; + + // Called by the outer window whenever data changes. + void setSpots(const std::vector &spots); + void setLines(const std::vector &lines); // axes + cell vectors + +protected: + void initializeGL() override; + void resizeGL(int w, int h) override; + void paintGL() override; + + void mousePressEvent(QMouseEvent *e) override; + void mouseMoveEvent(QMouseEvent *e) override; + void wheelEvent(QWheelEvent *e) override; + +private: + void uploadBuffer(QOpenGLBuffer &vbo, QOpenGLVertexArrayObject &vao, + const std::vector &data); + void setupVAO(QOpenGLVertexArrayObject &vao, QOpenGLBuffer &vbo); + + QOpenGLShaderProgram shader_; + + QOpenGLVertexArrayObject spotsVAO_; + QOpenGLBuffer spotsVBO_; + int spotsCount_ = 0; + + QOpenGLVertexArrayObject linesVAO_; + QOpenGLBuffer linesVBO_; + int linesCount_ = 0; + + // Camera state + QMatrix4x4 proj_; + float yaw_ = 0.0f; // degrees + float pitch_ = 20.0f; // degrees + float zoom_ = 80.0f; // distance from origin + QPoint lastMousePos_; +}; + +// --------------------------------------------------------------------------- +// JFJochViewerReciprocalSpaceWindow – the outer QMainWindow (unchanged API) +// --------------------------------------------------------------------------- class JFJochViewerReciprocalSpaceWindow : public JFJochHelperWindow { Q_OBJECT public: explicit JFJochViewerReciprocalSpaceWindow(QWidget *parent = nullptr); public slots: - // Keep 3D colors in sync with the 2D image - void setSpotColor(QColor input); - void setFeatureColor(QColor input); - - // Reset everything (called on new dataset) - void datasetLoaded(std::shared_ptr in_dataset) override; - // Add spots from currently open image (accumulating) - void imageLoaded(std::shared_ptr image) override; - -private slots: - void rebuildScene(); + void datasetLoaded(std::shared_ptr dataset); + void imageLoaded(std::shared_ptr image); + void setSpotColor(QColor color); + void setFeatureColor(QColor color); private: struct AccumulatedSpot { - Coord recip_lab; // reciprocal coord in lab frame at the image's angle - Coord recip_crystal; // reciprocal coord rotated back to angle = 0 - bool indexed = false; - bool ice_ring = false; + Coord recip_lab; + Coord recip_crystal; + bool indexed = false; + bool ice_ring = false; }; - void clearScene(); - void rebuildSpots(); // refresh the point-cloud buffers - void addCellVectors(); - void addAxes(); - QColor spotColorFor(bool indexed, bool ice_ring) const; + void rebuildGL(); // rebuilds both spot and line vertex data - Qt3DExtras::Qt3DWindow *view_ = nullptr; - Qt3DCore::QEntity *root_ = nullptr; - Qt3DCore::QEntity *sceneContent_ = nullptr; // re-created when cell/frame changes + // UI + ReciprocalSpaceGLView *glView_ = nullptr; + QCheckBox *crystalFrameCheck = nullptr; + QCheckBox *showCellCheck = nullptr; + QCheckBox *accumulateCheck = nullptr; - QCheckBox *accumulateCheck = nullptr; + // Data + std::vector spots_; + std::optional indexed_lattice_; + bool has_rotation_ = false; + float scene_scale_ = 100.0f; - Qt3DExtras::QOrbitCameraController *camController = nullptr; - - std::vector spots_; - std::optional indexed_lattice_; - bool has_rotation_ = false; - - // UI options - QCheckBox *crystalFrameCheck = nullptr; // angle=0 frame vs current - QCheckBox *showCellCheck = nullptr; - - // Colors matching the diffraction image + // Colors QColor spot_color = Qt::green; QColor indexed_color = Qt::magenta; // feature_color in image QColor ice_ring_color = Qt::cyan; - - float scene_scale_ = 100.0f; // recip Å^-1 are small; scale up for rendering - void addSpots(); -}; \ No newline at end of file +}; -- 2.52.0 From a2fd0a433f9335a7061a7b00473a121ca2cde8bb Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Mon, 1 Jun 2026 11:00:46 +0200 Subject: [PATCH 20/27] jfjoch_viewer: Work in progress on reciprocal space viewer --- .../JFJochViewerReciprocalSpaceWindow.cpp | 144 +++++++++++++++--- .../JFJochViewerReciprocalSpaceWindow.h | 11 +- 2 files changed, 130 insertions(+), 25 deletions(-) diff --git a/viewer/windows/JFJochViewerReciprocalSpaceWindow.cpp b/viewer/windows/JFJochViewerReciprocalSpaceWindow.cpp index c2403cf0..20d420f7 100644 --- a/viewer/windows/JFJochViewerReciprocalSpaceWindow.cpp +++ b/viewer/windows/JFJochViewerReciprocalSpaceWindow.cpp @@ -8,6 +8,7 @@ #include #include #include +#include // ============================================================================ // Shaders @@ -33,10 +34,13 @@ static const char *kFragSrc = R"( #version 330 core in vec3 vColor; out vec4 fragColor; + uniform bool uPointShape; void main() { - // Discard corners to draw a circle instead of a square point. - vec2 c = gl_PointCoord - vec2(0.5); - if (dot(c, c) > 0.25) discard; + if (uPointShape) { + // Discard corners to draw a circle instead of a square point. + vec2 c = gl_PointCoord - vec2(0.5); + if (dot(c, c) > 0.25) discard; + } fragColor = vec4(vColor, 1.0); } )"; @@ -82,6 +86,14 @@ void ReciprocalSpaceGLView::initializeGL() { // Create empty VAO/VBOs so they are valid before the first data arrives. setupVAO(spotsVAO_, spotsVBO_); setupVAO(linesVAO_, linesVBO_); + + glReady_ = true; + + uploadBuffer(spotsVBO_, spotsVAO_, pendingSpots_); + spotsCount_ = static_cast(pendingSpots_.size()); + + uploadBuffer(linesVBO_, linesVAO_, pendingLines_); + linesCount_ = static_cast(pendingLines_.size()); } void ReciprocalSpaceGLView::resizeGL(int w, int h) { @@ -89,22 +101,30 @@ void ReciprocalSpaceGLView::resizeGL(int w, int h) { proj_.perspective(45.0f, float(w) / float(h ? h : 1), 0.1f, 10000.0f); } -void ReciprocalSpaceGLView::paintGL() { - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - // Build view matrix from orbit camera state. +QMatrix4x4 ReciprocalSpaceGLView::currentViewMatrix() const { QMatrix4x4 view; view.translate(0, 0, -zoom_); view.rotate(pitch_, 1, 0, 0); view.rotate(yaw_, 0, 1, 0); + view.translate(-target_); + return view; +} - const QMatrix4x4 mvp = proj_ * view; +QMatrix4x4 ReciprocalSpaceGLView::currentMvpMatrix() const { + return proj_ * currentViewMatrix(); +} + +void ReciprocalSpaceGLView::paintGL() { + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + const QMatrix4x4 mvp = currentMvpMatrix(); shader_.bind(); shader_.setUniformValue("uMVP", mvp); // Draw axes + cell vectors if (linesCount_ > 0) { + shader_.setUniformValue("uPointShape", false); linesVAO_.bind(); glDrawArrays(GL_LINES, 0, linesCount_); linesVAO_.release(); @@ -112,6 +132,7 @@ void ReciprocalSpaceGLView::paintGL() { // Draw spots if (spotsCount_ > 0) { + shader_.setUniformValue("uPointShape", true); spotsVAO_.bind(); glDrawArrays(GL_POINTS, 0, spotsCount_); spotsVAO_.release(); @@ -123,18 +144,28 @@ void ReciprocalSpaceGLView::paintGL() { // --------------------------------------------------------------------------- void ReciprocalSpaceGLView::setSpots(const std::vector &spots) { - makeCurrent(); - uploadBuffer(spotsVBO_, spotsVAO_, spots); - spotsCount_ = static_cast(spots.size()); - doneCurrent(); + pendingSpots_ = spots; + spotsCount_ = static_cast(pendingSpots_.size()); + + if (glReady_) { + makeCurrent(); + uploadBuffer(spotsVBO_, spotsVAO_, pendingSpots_); + doneCurrent(); + } + update(); } void ReciprocalSpaceGLView::setLines(const std::vector &lines) { - makeCurrent(); - uploadBuffer(linesVBO_, linesVAO_, lines); - linesCount_ = static_cast(lines.size()); - doneCurrent(); + pendingLines_ = lines; + linesCount_ = static_cast(pendingLines_.size()); + + if (glReady_) { + makeCurrent(); + uploadBuffer(linesVBO_, linesVAO_, pendingLines_); + doneCurrent(); + } + update(); } @@ -185,6 +216,15 @@ void ReciprocalSpaceGLView::mousePressEvent(QMouseEvent *e) { lastMousePos_ = e->pos(); } +void ReciprocalSpaceGLView::mouseDoubleClickEvent(QMouseEvent *e) { + if (e->button() == Qt::LeftButton && focusNearestSpot(e->pos())) { + e->accept(); + return; + } + + QOpenGLWidget::mouseDoubleClickEvent(e); +} + void ReciprocalSpaceGLView::mouseMoveEvent(QMouseEvent *e) { const QPoint delta = e->pos() - lastMousePos_; lastMousePos_ = e->pos(); @@ -194,6 +234,19 @@ void ReciprocalSpaceGLView::mouseMoveEvent(QMouseEvent *e) { pitch_ += delta.y() * 0.5f; pitch_ = qBound(-89.0f, pitch_, 89.0f); update(); + } else if (e->buttons() & Qt::MiddleButton) { + const float panScale = zoom_ * 0.0015f; + + QMatrix4x4 rot; + rot.rotate(pitch_, 1, 0, 0); + rot.rotate(yaw_, 0, 1, 0); + + const QVector3D right = rot.inverted().mapVector(QVector3D(1, 0, 0)); + const QVector3D up = rot.inverted().mapVector(QVector3D(0, 1, 0)); + + target_ -= right * float(delta.x()) * panScale; + target_ += up * float(delta.y()) * panScale; + update(); } } @@ -203,6 +256,49 @@ void ReciprocalSpaceGLView::wheelEvent(QWheelEvent *e) { update(); } +bool ReciprocalSpaceGLView::focusNearestSpot(const QPoint &screenPos) { + if (pendingSpots_.empty() || width() <= 0 || height() <= 0) + return false; + + const QMatrix4x4 mvp = currentMvpMatrix(); + + float bestDist2 = std::numeric_limits::max(); + QVector3D bestPos; + bool found = false; + + for (const auto &v : pendingSpots_) { + const QVector4D clip = mvp * QVector4D(v.x, v.y, v.z, 1.0f); + if (clip.w() <= 0.0f) + continue; + + const QVector3D ndc = clip.toVector3DAffine(); + if (ndc.z() < -1.0f || ndc.z() > 1.0f) + continue; + + const float sx = (ndc.x() * 0.5f + 0.5f) * float(width()); + const float sy = (0.5f - ndc.y() * 0.5f) * float(height()); + + const float dx = sx - float(screenPos.x()); + const float dy = sy - float(screenPos.y()); + const float dist2 = dx * dx + dy * dy; + + if (dist2 < bestDist2) { + bestDist2 = dist2; + bestPos = QVector3D(v.x, v.y, v.z); + found = true; + } + } + + // Roughly 15 px picking radius. + if (!found || bestDist2 > 15.0f * 15.0f) + return false; + + target_ = bestPos; + zoom_ = qMax(5.0f, zoom_ * 0.35f); + update(); + return true; +} + // ============================================================================ // JFJochViewerReciprocalSpaceWindow // ============================================================================ @@ -271,9 +367,7 @@ void JFJochViewerReciprocalSpaceWindow::datasetLoaded( rebuildGL(); } -void JFJochViewerReciprocalSpaceWindow::imageLoaded( - std::shared_ptr image) -{ +void JFJochViewerReciprocalSpaceWindow::imageLoaded(std::shared_ptr image) { if (!accumulateCheck->isChecked()) { spots_.clear(); indexed_lattice_.reset(); @@ -347,7 +441,7 @@ void JFJochViewerReciprocalSpaceWindow::rebuildGL() { // --- Spots --------------------------------------------------------------- std::vector spotVerts; - spotVerts.reserve(spots_.size()); + spotVerts.reserve(spots_.size() + 1); // Precompute the three possible colors as floats — avoids QColor in the loop. auto toF = [](const QColor &c, float &r, float &g, float &b) { @@ -370,6 +464,8 @@ void JFJochViewerReciprocalSpaceWindow::rebuildGL() { r, g, b }); } + spotVerts.push_back({ 0, 0, 0, 1.0, 1.0, 1.0 }); + // --- Lines: axes + optional cell vectors --------------------------------- // Each segment = 2 vertices (GL_LINES draws pairs). std::vector lineVerts; @@ -383,10 +479,10 @@ void JFJochViewerReciprocalSpaceWindow::rebuildGL() { }; // Reference axes - const float len = 10.0f; - addLine({0,0,0}, {len,0,0}, QColor(180, 60, 60)); - addLine({0,0,0}, {0,len,0}, QColor(60, 180, 60)); - addLine({0,0,0}, {0,0,len}, QColor(60, 60, 180)); + const float len = 20.0f; + addLine({0,0,0}, {len,0,0}, QColor(255, 60, 60)); + addLine({0,0,0}, {0,len,0}, QColor(60, 255, 60)); + addLine({0,0,0}, {0,0,len}, QColor(60, 60, 255)); // Reciprocal cell vectors if (showCellCheck->isChecked() && indexed_lattice_) { diff --git a/viewer/windows/JFJochViewerReciprocalSpaceWindow.h b/viewer/windows/JFJochViewerReciprocalSpaceWindow.h index 06e9da28..d73d7a3a 100644 --- a/viewer/windows/JFJochViewerReciprocalSpaceWindow.h +++ b/viewer/windows/JFJochViewerReciprocalSpaceWindow.h @@ -46,6 +46,7 @@ protected: void paintGL() override; void mousePressEvent(QMouseEvent *e) override; + void mouseDoubleClickEvent(QMouseEvent *e) override; void mouseMoveEvent(QMouseEvent *e) override; void wheelEvent(QWheelEvent *e) override; @@ -54,21 +55,29 @@ private: const std::vector &data); void setupVAO(QOpenGLVertexArrayObject &vao, QOpenGLBuffer &vbo); + QMatrix4x4 currentViewMatrix() const; + QMatrix4x4 currentMvpMatrix() const; + bool focusNearestSpot(const QPoint &screenPos); + QOpenGLShaderProgram shader_; + bool glReady_ = false; QOpenGLVertexArrayObject spotsVAO_; QOpenGLBuffer spotsVBO_; int spotsCount_ = 0; + std::vector pendingSpots_; QOpenGLVertexArrayObject linesVAO_; QOpenGLBuffer linesVBO_; int linesCount_ = 0; + std::vector pendingLines_; // Camera state QMatrix4x4 proj_; float yaw_ = 0.0f; // degrees float pitch_ = 20.0f; // degrees - float zoom_ = 80.0f; // distance from origin + float zoom_ = 80.0f; // distance from camera target + QVector3D target_{0.0f, 0.0f, 0.0f}; QPoint lastMousePos_; }; -- 2.52.0 From bf94864af8960b89ccf3c60253c0b507440f09a4 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Mon, 1 Jun 2026 13:18:41 +0200 Subject: [PATCH 21/27] jfjoch_viewer: Work in progress reciprocal space viewer --- viewer/JFJochViewerWindow.cpp | 3 + .../JFJochViewerReciprocalSpaceWindow.cpp | 374 +++++++++++++----- .../JFJochViewerReciprocalSpaceWindow.h | 44 ++- 3 files changed, 322 insertions(+), 99 deletions(-) diff --git a/viewer/JFJochViewerWindow.cpp b/viewer/JFJochViewerWindow.cpp index 7feeb8d9..e0ceed12 100644 --- a/viewer/JFJochViewerWindow.cpp +++ b/viewer/JFJochViewerWindow.cpp @@ -314,6 +314,9 @@ JFJochViewerWindow::JFJochViewerWindow(QWidget *parent, bool dbus, const QString connect(reading_worker, &JFJochImageReadingWorker::imageLoaded, reciprocalWindow, &JFJochViewerReciprocalSpaceWindow::imageLoaded); + connect(reciprocalWindow, &JFJochHelperWindow::zoom, + viewer, &JFJochDiffractionImage::centerOnSpot); + connect(side_panel, &JFJochViewerSidePanel::setSpotColor, reciprocalWindow, &JFJochViewerReciprocalSpaceWindow::setSpotColor); connect(side_panel, &JFJochViewerSidePanel::setFeatureColor, diff --git a/viewer/windows/JFJochViewerReciprocalSpaceWindow.cpp b/viewer/windows/JFJochViewerReciprocalSpaceWindow.cpp index 20d420f7..faf4302e 100644 --- a/viewer/windows/JFJochViewerReciprocalSpaceWindow.cpp +++ b/viewer/windows/JFJochViewerReciprocalSpaceWindow.cpp @@ -5,10 +5,12 @@ #include #include -#include #include #include + #include +#include +#include // ============================================================================ // Shaders @@ -20,8 +22,8 @@ static const char *kVertSrc = R"( #version 330 core layout(location = 0) in vec3 aPos; - layout(location = 1) in vec3 aColor; - out vec3 vColor; + layout(location = 1) in vec4 aColor; + out vec4 vColor; uniform mat4 uMVP; void main() { vColor = aColor; @@ -32,7 +34,7 @@ static const char *kVertSrc = R"( static const char *kFragSrc = R"( #version 330 core - in vec3 vColor; + in vec4 vColor; out vec4 fragColor; uniform bool uPointShape; void main() { @@ -41,7 +43,7 @@ static const char *kFragSrc = R"( vec2 c = gl_PointCoord - vec2(0.5); if (dot(c, c) > 0.25) discard; } - fragColor = vec4(vColor, 1.0); + fragColor = vColor; } )"; @@ -54,7 +56,7 @@ ReciprocalSpaceGLView::ReciprocalSpaceGLView(QWidget *parent) , spotsVBO_(QOpenGLBuffer::VertexBuffer) , linesVBO_(QOpenGLBuffer::VertexBuffer) { - // Request OpenGL 3.3 Core Profile (Linux/NVIDIA, Mesa, macOS all support this) + // Request OpenGL 3.3 Core Profile. QSurfaceFormat fmt; fmt.setVersion(3, 3); fmt.setProfile(QSurfaceFormat::CoreProfile); @@ -75,9 +77,11 @@ ReciprocalSpaceGLView::~ReciprocalSpaceGLView() { void ReciprocalSpaceGLView::initializeGL() { initializeOpenGLFunctions(); - glClearColor(20.f/255, 20.f/255, 25.f/255, 1.0f); + glClearColor(20.f / 255.f, 20.f / 255.f, 25.f / 255.f, 1.0f); glEnable(GL_DEPTH_TEST); - glEnable(GL_PROGRAM_POINT_SIZE); // lets the vertex shader set gl_PointSize + glEnable(GL_PROGRAM_POINT_SIZE); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); shader_.addShaderFromSourceCode(QOpenGLShader::Vertex, kVertSrc); shader_.addShaderFromSourceCode(QOpenGLShader::Fragment, kFragSrc); @@ -122,15 +126,30 @@ void ReciprocalSpaceGLView::paintGL() { shader_.bind(); shader_.setUniformValue("uMVP", mvp); - // Draw axes + cell vectors + // Draw axes + cell vectors. + // Convention: first 6 line vertices are XYZ reference axes, + // remaining line vertices are reciprocal-cell vectors. if (linesCount_ > 0) { shader_.setUniformValue("uPointShape", false); linesVAO_.bind(); - glDrawArrays(GL_LINES, 0, linesCount_); + + const int axesVertexCount = std::min(linesCount_, 6); + if (axesVertexCount > 0) { + glLineWidth(1.0f); + glDrawArrays(GL_LINES, 0, axesVertexCount); + } + + if (linesCount_ > axesVertexCount) { + // Note: on some OpenGL core-profile drivers wide lines may be clamped to 1 px. + glLineWidth(3.0f); + glDrawArrays(GL_LINES, axesVertexCount, linesCount_ - axesVertexCount); + glLineWidth(1.0f); + } + linesVAO_.release(); } - // Draw spots + // Draw observed spots + predicted nodes + explicit 000 marker. if (spotsCount_ > 0) { shader_.setUniformValue("uPointShape", true); spotsVAO_.bind(); @@ -175,17 +194,25 @@ void ReciprocalSpaceGLView::setupVAO(QOpenGLVertexArrayObject &vao, QOpenGLBuffer &vbo) { vao.create(); vao.bind(); + vbo.create(); vbo.bind(); - // location 0: position (xyz) + // location 0: position xyz glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, + glVertexAttribPointer(0, + 3, + GL_FLOAT, + GL_FALSE, sizeof(Vertex), reinterpret_cast(offsetof(Vertex, x))); - // location 1: color (rgb) + + // location 1: color rgba glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, + glVertexAttribPointer(1, + 4, + GL_FLOAT, + GL_FALSE, sizeof(Vertex), reinterpret_cast(offsetof(Vertex, r))); @@ -198,18 +225,20 @@ void ReciprocalSpaceGLView::uploadBuffer(QOpenGLBuffer &vbo, const std::vector &data) { vao.bind(); vbo.bind(); + if (data.empty()) { vbo.allocate(nullptr, 0); } else { vbo.allocate(data.data(), static_cast(data.size() * sizeof(Vertex))); } + vbo.release(); vao.release(); } // --------------------------------------------------------------------------- -// Mouse / wheel -> orbit camera +// Mouse / wheel -> orbit camera + picking // --------------------------------------------------------------------------- void ReciprocalSpaceGLView::mousePressEvent(QMouseEvent *e) { @@ -217,7 +246,7 @@ void ReciprocalSpaceGLView::mousePressEvent(QMouseEvent *e) { } void ReciprocalSpaceGLView::mouseDoubleClickEvent(QMouseEvent *e) { - if (e->button() == Qt::LeftButton && focusNearestSpot(e->pos())) { + if (e->button() == Qt::LeftButton && emitNearestSpot(e->pos())) { e->accept(); return; } @@ -246,6 +275,7 @@ void ReciprocalSpaceGLView::mouseMoveEvent(QMouseEvent *e) { target_ -= right * float(delta.x()) * panScale; target_ += up * float(delta.y()) * panScale; + update(); } } @@ -256,17 +286,20 @@ void ReciprocalSpaceGLView::wheelEvent(QWheelEvent *e) { update(); } -bool ReciprocalSpaceGLView::focusNearestSpot(const QPoint &screenPos) { +bool ReciprocalSpaceGLView::emitNearestSpot(const QPoint &screenPos) { if (pendingSpots_.empty() || width() <= 0 || height() <= 0) return false; const QMatrix4x4 mvp = currentMvpMatrix(); float bestDist2 = std::numeric_limits::max(); - QVector3D bestPos; + QPointF bestImagePos; bool found = false; for (const auto &v : pendingSpots_) { + if (v.pickable <= 0.5f) + continue; + const QVector4D clip = mvp * QVector4D(v.x, v.y, v.z, 1.0f); if (clip.w() <= 0.0f) continue; @@ -284,7 +317,7 @@ bool ReciprocalSpaceGLView::focusNearestSpot(const QPoint &screenPos) { if (dist2 < bestDist2) { bestDist2 = dist2; - bestPos = QVector3D(v.x, v.y, v.z); + bestImagePos = QPointF(v.image_x, v.image_y); found = true; } } @@ -293,9 +326,7 @@ bool ReciprocalSpaceGLView::focusNearestSpot(const QPoint &screenPos) { if (!found || bestDist2 > 15.0f * 15.0f) return false; - target_ = bestPos; - zoom_ = qMax(5.0f, zoom_ * 0.35f); - update(); + emit spotDoubleClicked(bestImagePos); return true; } @@ -317,20 +348,22 @@ JFJochViewerReciprocalSpaceWindow::JFJochViewerReciprocalSpaceWindow(QWidget *pa layout->addWidget(glView_, 1); auto *controls = new QHBoxLayout(); + crystalFrameCheck = new QCheckBox("Crystal frame (angle = 0)", central); crystalFrameCheck->setChecked(false); crystalFrameCheck->setEnabled(false); + showCellCheck = new QCheckBox("Show reciprocal cell", central); showCellCheck->setChecked(true); - accumulateCheck = new QCheckBox("Accumulate", central); - accumulateCheck->setChecked(false); - auto *clearButton = new QPushButton("Clear accumulated", central); + + showPredictedCheck = new QCheckBox("Show predicted nodes", central); + showPredictedCheck->setChecked(true); controls->addWidget(crystalFrameCheck); controls->addWidget(showCellCheck); - controls->addWidget(accumulateCheck); + controls->addWidget(showPredictedCheck); controls->addStretch(1); - controls->addWidget(clearButton); + layout->addLayout(controls); setCentralWidget(central); @@ -338,10 +371,13 @@ JFJochViewerReciprocalSpaceWindow::JFJochViewerReciprocalSpaceWindow(QWidget *pa this, &JFJochViewerReciprocalSpaceWindow::rebuildGL); connect(showCellCheck, &QCheckBox::toggled, this, &JFJochViewerReciprocalSpaceWindow::rebuildGL); - connect(clearButton, &QPushButton::clicked, this, [this] { - spots_.clear(); - rebuildGL(); - }); + connect(showPredictedCheck, &QCheckBox::toggled, + this, &JFJochViewerReciprocalSpaceWindow::rebuildGL); + + // Reuse the existing helper-window zoom signal. The main window should connect + // this to JFJochDiffractionImage::centerOnSpot, like the spot/reflection lists. + connect(glView_, &ReciprocalSpaceGLView::spotDoubleClicked, + this, &JFJochHelperWindow::zoom); rebuildGL(); } @@ -354,7 +390,9 @@ void JFJochViewerReciprocalSpaceWindow::datasetLoaded( std::shared_ptr in_dataset) { spots_.clear(); + reflections_.clear(); indexed_lattice_.reset(); + current_back_rot_.reset(); has_rotation_ = false; if (in_dataset) @@ -368,10 +406,10 @@ void JFJochViewerReciprocalSpaceWindow::datasetLoaded( } void JFJochViewerReciprocalSpaceWindow::imageLoaded(std::shared_ptr image) { - if (!accumulateCheck->isChecked()) { - spots_.clear(); - indexed_lattice_.reset(); - } + spots_.clear(); + reflections_.clear(); + indexed_lattice_.reset(); + current_back_rot_.reset(); if (!image) { rebuildGL(); @@ -383,29 +421,36 @@ void JFJochViewerReciprocalSpaceWindow::imageLoaded(std::shared_ptrImageData().number; - std::optional back_rot; if (axis) { const float angle_deg = axis->GetAngle_deg(static_cast(image_number)) + axis->GetWedge_deg() / 2.0f; - back_rot = axis->GetTransformationAngle(angle_deg); + current_back_rot_ = axis->GetTransformationAngle(angle_deg); } - spots_.reserve(spots_.size() + image->ImageData().spots.size()); + spots_.reserve(image->ImageData().spots.size()); + for (const auto &s : image->ImageData().spots) { - AccumulatedSpot acc; - acc.recip_lab = s.ReciprocalCoord(geom); - acc.recip_crystal = back_rot ? (*back_rot * acc.recip_lab) : acc.recip_lab; - acc.indexed = s.indexed; - acc.ice_ring = s.ice_ring; - spots_.emplace_back(acc); + CurrentSpot spot; + spot.recip_lab = s.ReciprocalCoord(geom); + spot.recip_crystal = current_back_rot_ ? (*current_back_rot_ * spot.recip_lab) : spot.recip_lab; + spot.image_x = s.x; + spot.image_y = s.y; + spot.h = static_cast(s.h); + spot.k = static_cast(s.k); + spot.l = static_cast(s.l); + spot.indexed = s.indexed; + spot.ice_ring = s.ice_ring; + spots_.emplace_back(spot); } - // Soft cap: no per-spot Qt objects here, so 200k is fine. - constexpr size_t max_accumulated = 200000; - if (spots_.size() > max_accumulated) - spots_.erase(spots_.begin(), - spots_.begin() + - static_cast(spots_.size() - max_accumulated)); + reflections_.reserve(image->ImageData().reflections.size()); + for (const auto &r : image->ImageData().reflections) { + reflections_.push_back({ + .h = r.h, + .k = r.k, + .l = r.l + }); + } if (image->ImageData().indexing_lattice) indexed_lattice_ = image->ImageData().indexing_lattice; @@ -414,88 +459,239 @@ void JFJochViewerReciprocalSpaceWindow::imageLoaded(std::shared_ptrisChecked() && has_rotation_; + std::optional plot_lattice; + if (indexed_lattice_) { + plot_lattice = indexed_lattice_.value(); + + // If spots are brought back to angle zero, bring the lattice back too. + // After this, q = h*Astar + k*Bstar + l*Cstar is in the same frame as the plotted spots. + if (crystal_frame && current_back_rot_) + plot_lattice = plot_lattice->Multiply(*current_back_rot_); + } + // --- Spots --------------------------------------------------------------- std::vector spotVerts; spotVerts.reserve(spots_.size() + 1); - // Precompute the three possible colors as floats — avoids QColor in the loop. auto toF = [](const QColor &c, float &r, float &g, float &b) { - r = float(c.redF()); g = float(c.greenF()); b = float(c.blueF()); + r = float(c.redF()); + g = float(c.greenF()); + b = float(c.blueF()); }; - float sr, sg, sb, ir, ig, ib, xr, xg, xb; - toF(spot_color, sr, sg, sb); - toF(indexed_color, ir, ig, ib); - toF(ice_ring_color, xr, xg, xb); + + float sr, sg, sb; + float ir, ig, ib; + float xr, xg, xb; + float pr, pg, pb; + + toF(spot_color, sr, sg, sb); + toF(indexed_color, ir, ig, ib); + toF(ice_ring_color, xr, xg, xb); + toF(prediction_color, pr, pg, pb); + + int hMax = 0; + int kMax = 0; + int lMax = 0; for (const auto &spot : spots_) { const Coord &c = crystal_frame ? spot.recip_crystal : spot.recip_lab; + float r, g, b; - if (spot.indexed) { r = ir; g = ig; b = ib; } - else if (spot.ice_ring) { r = xr; g = xg; b = xb; } - else { r = sr; g = sg; b = sb; } - spotVerts.push_back({ c.x * scene_scale_, - c.y * scene_scale_, - c.z * scene_scale_, - r, g, b }); + if (spot.indexed) { + r = ir; + g = ig; + b = ib; + } else if (spot.ice_ring) { + r = xr; + g = xg; + b = xb; + } else { + r = sr; + g = sg; + b = sb; + } + + spotVerts.push_back({ + c.x * scene_scale_, + c.y * scene_scale_, + c.z * scene_scale_, + r, g, b, 1.0f, + spot.image_x, + spot.image_y, + 1.0f + }); + + if (spot.indexed) { + hMax = std::max(hMax, std::abs(spot.h)); + kMax = std::max(kMax, std::abs(spot.k)); + lMax = std::max(lMax, std::abs(spot.l)); + } } - spotVerts.push_back({ 0, 0, 0, 1.0, 1.0, 1.0 }); + /* + // Also include predicted-reflection HKLs in the plotting range. + for (const auto &r : reflections_) { + hMax = std::max(hMax, std::abs(r.h)); + kMax = std::max(kMax, std::abs(r.k)); + lMax = std::max(lMax, std::abs(r.l)); + } */ + + // Explicit 000 reflection marker. + spotVerts.push_back({ + 0.0f, 0.0f, 0.0f, + 1.0f, 1.0f, 1.0f, 1.0f, + 0.0f, 0.0f, + 0.0f + }); + + // Predicted reciprocal-lattice nodes: + // q = h*Astar + k*Bstar + l*Cstar, in the currently plotted frame. + if (showPredictedCheck->isChecked() && plot_lattice && hMax > 0 && kMax > 0 && lMax > 0) { + const Coord a = plot_lattice->Astar(); + const Coord b = plot_lattice->Bstar(); + const Coord c = plot_lattice->Cstar(); + + for (int h = -hMax; h <= hMax; ++h) { + for (int k = -kMax; k <= kMax; ++k) { + for (int l = -lMax; l <= lMax; ++l) { + if (h == 0 && k == 0 && l == 0) + continue; + + bool observedIndexed = false; + for (const auto &spot : spots_) { + if (spot.indexed && spot.h == h && spot.k == k && spot.l == l) { + observedIndexed = true; + break; + } + } + + if (observedIndexed) + continue; + + bool predictedForImage = false; + for (const auto &r : reflections_) { + if (r.h == h && r.k == k && r.l == l) { + predictedForImage = true; + break; + } + } + + const Coord node{ + h * a.x + k * b.x + l * c.x, + h * a.y + k * b.y + l * c.y, + h * a.z + k * b.z + l * c.z + }; + + if (predictedForImage) { + // Highlight nodes that are actual predictions for this image. + spotVerts.push_back({ + node.x * scene_scale_, + node.y * scene_scale_, + node.z * scene_scale_, + pr, pg, pb, 0.85f, + 0.0f, 0.0f, + 0.0f + }); + } else { + // Faint full reciprocal grid node. + spotVerts.push_back({ + node.x * scene_scale_, + node.y * scene_scale_, + node.z * scene_scale_, + pr, pg, pb, 0.5f, + 0.0f, 0.0f, + 0.0f + }); + } + } + } + } + } // --- Lines: axes + optional cell vectors --------------------------------- - // Each segment = 2 vertices (GL_LINES draws pairs). std::vector lineVerts; - auto addLine = [&](QVector3D a, QVector3D b, QColor col) { - const float r = float(col.redF()), - g = float(col.greenF()), - bv = float(col.blueF()); - lineVerts.push_back({ a.x(), a.y(), a.z(), r, g, bv }); - lineVerts.push_back({ b.x(), b.y(), b.z(), r, g, bv }); + auto addLine = [&](QVector3D a, QVector3D b, QColor col, float alpha = 1.0f) { + const float r = float(col.redF()); + const float g = float(col.greenF()); + const float bv = float(col.blueF()); + + lineVerts.push_back({ + a.x(), a.y(), a.z(), + r, g, bv, alpha, + 0.0f, 0.0f, + 0.0f + }); + + lineVerts.push_back({ + b.x(), b.y(), b.z(), + r, g, bv, alpha, + 0.0f, 0.0f, + 0.0f + }); }; - // Reference axes + // Reference coordinate axes: short and white. const float len = 20.0f; - addLine({0,0,0}, {len,0,0}, QColor(255, 60, 60)); - addLine({0,0,0}, {0,len,0}, QColor(60, 255, 60)); - addLine({0,0,0}, {0,0,len}, QColor(60, 60, 255)); + addLine({0, 0, 0}, {len, 0, 0}, Qt::white, 0.75f); + addLine({0, 0, 0}, {0, len, 0}, Qt::white, 0.75f); + addLine({0, 0, 0}, {0, 0, len}, Qt::white, 0.75f); - // Reciprocal cell vectors - if (showCellCheck->isChecked() && indexed_lattice_) { + // Reciprocal cell vectors, using the same plotted lattice frame as predicted nodes. + if (showCellCheck->isChecked() && plot_lattice) { auto addCell = [&](const Coord &v, QColor col) { addLine({0, 0, 0}, - { v.x * scene_scale_, - v.y * scene_scale_, - v.z * scene_scale_ }, - col); + { + v.x * scene_scale_, + v.y * scene_scale_, + v.z * scene_scale_ + }, + col, + 1.0f); }; - addCell(indexed_lattice_->Astar(), Qt::red); - addCell(indexed_lattice_->Bstar(), Qt::green); - addCell(indexed_lattice_->Cstar(), Qt::blue); + + addCell(plot_lattice->Astar(), Qt::red); + addCell(plot_lattice->Bstar(), Qt::green); + addCell(plot_lattice->Cstar(), Qt::blue); } glView_->setSpots(spotVerts); diff --git a/viewer/windows/JFJochViewerReciprocalSpaceWindow.h b/viewer/windows/JFJochViewerReciprocalSpaceWindow.h index d73d7a3a..b45cfd06 100644 --- a/viewer/windows/JFJochViewerReciprocalSpaceWindow.h +++ b/viewer/windows/JFJochViewerReciprocalSpaceWindow.h @@ -34,12 +34,21 @@ public: explicit ReciprocalSpaceGLView(QWidget *parent = nullptr); ~ReciprocalSpaceGLView() override; - struct Vertex { float x, y, z, r, g, b; }; + struct Vertex { + float x, y, z; + float r, g, b, a; + float image_x = 0.0f; + float image_y = 0.0f; + float pickable = 0.0f; + }; // Called by the outer window whenever data changes. void setSpots(const std::vector &spots); void setLines(const std::vector &lines); // axes + cell vectors +signals: + void spotDoubleClicked(QPointF imagePos); + protected: void initializeGL() override; void resizeGL(int w, int h) override; @@ -57,7 +66,7 @@ private: QMatrix4x4 currentViewMatrix() const; QMatrix4x4 currentMvpMatrix() const; - bool focusNearestSpot(const QPoint &screenPos); + bool emitNearestSpot(const QPoint &screenPos); QOpenGLShaderProgram shader_; bool glReady_ = false; @@ -82,7 +91,7 @@ private: }; // --------------------------------------------------------------------------- -// JFJochViewerReciprocalSpaceWindow – the outer QMainWindow (unchanged API) +// JFJochViewerReciprocalSpaceWindow – the outer QMainWindow // --------------------------------------------------------------------------- class JFJochViewerReciprocalSpaceWindow : public JFJochHelperWindow { Q_OBJECT @@ -94,32 +103,47 @@ public slots: void imageLoaded(std::shared_ptr image); void setSpotColor(QColor color); void setFeatureColor(QColor color); + void setPredictionColor(QColor color); private: - struct AccumulatedSpot { + struct CurrentSpot { Coord recip_lab; Coord recip_crystal; + float image_x = 0.0f; + float image_y = 0.0f; + int32_t h = 0; + int32_t k = 0; + int32_t l = 0; bool indexed = false; bool ice_ring = false; }; + struct CurrentReflection { + int32_t h = 0; + int32_t k = 0; + int32_t l = 0; + }; + QColor spotColorFor(bool indexed, bool ice_ring) const; void rebuildGL(); // rebuilds both spot and line vertex data // UI - ReciprocalSpaceGLView *glView_ = nullptr; - QCheckBox *crystalFrameCheck = nullptr; - QCheckBox *showCellCheck = nullptr; - QCheckBox *accumulateCheck = nullptr; + ReciprocalSpaceGLView *glView_ = nullptr; + QCheckBox *crystalFrameCheck = nullptr; + QCheckBox *showCellCheck = nullptr; + QCheckBox *showPredictedCheck = nullptr; // Data - std::vector spots_; - std::optional indexed_lattice_; + std::vector spots_; + std::vector reflections_; + std::optional indexed_lattice_; + std::optional current_back_rot_; bool has_rotation_ = false; float scene_scale_ = 100.0f; // Colors QColor spot_color = Qt::green; QColor indexed_color = Qt::magenta; // feature_color in image + QColor prediction_color = Qt::darkRed; QColor ice_ring_color = Qt::cyan; }; -- 2.52.0 From 60d0daabc277dc190a294bce566b4e1d4760ea2b Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Mon, 1 Jun 2026 13:22:19 +0200 Subject: [PATCH 22/27] jfjoch_viewer: Orthoscopic perspective to better see grid pattern --- .../JFJochViewerReciprocalSpaceWindow.cpp | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/viewer/windows/JFJochViewerReciprocalSpaceWindow.cpp b/viewer/windows/JFJochViewerReciprocalSpaceWindow.cpp index faf4302e..d3b62f45 100644 --- a/viewer/windows/JFJochViewerReciprocalSpaceWindow.cpp +++ b/viewer/windows/JFJochViewerReciprocalSpaceWindow.cpp @@ -101,8 +101,14 @@ void ReciprocalSpaceGLView::initializeGL() { } void ReciprocalSpaceGLView::resizeGL(int w, int h) { + const float aspect = float(w) / float(h ? h : 1); + const float halfHeight = zoom_; + const float halfWidth = halfHeight * aspect; + proj_.setToIdentity(); - proj_.perspective(45.0f, float(w) / float(h ? h : 1), 0.1f, 10000.0f); + proj_.ortho(-halfWidth, halfWidth, + -halfHeight, halfHeight, + -10000.0f, 10000.0f); } QMatrix4x4 ReciprocalSpaceGLView::currentViewMatrix() const { @@ -283,6 +289,7 @@ void ReciprocalSpaceGLView::mouseMoveEvent(QMouseEvent *e) { void ReciprocalSpaceGLView::wheelEvent(QWheelEvent *e) { zoom_ *= (e->angleDelta().y() > 0) ? 0.9f : 1.1f; zoom_ = qBound(1.0f, zoom_, 5000.0f); + resizeGL(width(), height()); update(); } @@ -631,16 +638,6 @@ void JFJochViewerReciprocalSpaceWindow::rebuildGL() { 0.0f, 0.0f, 0.0f }); - } else { - // Faint full reciprocal grid node. - spotVerts.push_back({ - node.x * scene_scale_, - node.y * scene_scale_, - node.z * scene_scale_, - pr, pg, pb, 0.5f, - 0.0f, 0.0f, - 0.0f - }); } } } -- 2.52.0 From 55b65381db80160156813e8c4bb0edca43402fa0 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Mon, 1 Jun 2026 13:28:16 +0200 Subject: [PATCH 23/27] jfjoch_viewer: Pan with right click + center 000 button --- .../windows/JFJochViewerReciprocalSpaceWindow.cpp | 13 ++++++++++++- viewer/windows/JFJochViewerReciprocalSpaceWindow.h | 2 ++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/viewer/windows/JFJochViewerReciprocalSpaceWindow.cpp b/viewer/windows/JFJochViewerReciprocalSpaceWindow.cpp index d3b62f45..cc4507d9 100644 --- a/viewer/windows/JFJochViewerReciprocalSpaceWindow.cpp +++ b/viewer/windows/JFJochViewerReciprocalSpaceWindow.cpp @@ -11,6 +11,7 @@ #include #include #include +#include // ============================================================================ // Shaders @@ -194,6 +195,11 @@ void ReciprocalSpaceGLView::setLines(const std::vector &lines) { update(); } +void ReciprocalSpaceGLView::resetTarget() { + target_ = QVector3D(0.0f, 0.0f, 0.0f); + update(); +} + // --------------------------------------------------------------------------- void ReciprocalSpaceGLView::setupVAO(QOpenGLVertexArrayObject &vao, @@ -269,7 +275,7 @@ void ReciprocalSpaceGLView::mouseMoveEvent(QMouseEvent *e) { pitch_ += delta.y() * 0.5f; pitch_ = qBound(-89.0f, pitch_, 89.0f); update(); - } else if (e->buttons() & Qt::MiddleButton) { + } else if (e->buttons() & Qt::RightButton) { const float panScale = zoom_ * 0.0015f; QMatrix4x4 rot; @@ -366,10 +372,13 @@ JFJochViewerReciprocalSpaceWindow::JFJochViewerReciprocalSpaceWindow(QWidget *pa showPredictedCheck = new QCheckBox("Show predicted nodes", central); showPredictedCheck->setChecked(true); + auto *centerOriginButton = new QPushButton("Center 000", central); + controls->addWidget(crystalFrameCheck); controls->addWidget(showCellCheck); controls->addWidget(showPredictedCheck); controls->addStretch(1); + controls->addWidget(centerOriginButton); layout->addLayout(controls); setCentralWidget(central); @@ -380,6 +389,8 @@ JFJochViewerReciprocalSpaceWindow::JFJochViewerReciprocalSpaceWindow(QWidget *pa this, &JFJochViewerReciprocalSpaceWindow::rebuildGL); connect(showPredictedCheck, &QCheckBox::toggled, this, &JFJochViewerReciprocalSpaceWindow::rebuildGL); + connect(centerOriginButton, &QPushButton::clicked, + glView_, &ReciprocalSpaceGLView::resetTarget); // Reuse the existing helper-window zoom signal. The main window should connect // this to JFJochDiffractionImage::centerOnSpot, like the spot/reflection lists. diff --git a/viewer/windows/JFJochViewerReciprocalSpaceWindow.h b/viewer/windows/JFJochViewerReciprocalSpaceWindow.h index b45cfd06..9923715b 100644 --- a/viewer/windows/JFJochViewerReciprocalSpaceWindow.h +++ b/viewer/windows/JFJochViewerReciprocalSpaceWindow.h @@ -42,6 +42,8 @@ public: float pickable = 0.0f; }; + void resetTarget(); + // Called by the outer window whenever data changes. void setSpots(const std::vector &spots); void setLines(const std::vector &lines); // axes + cell vectors -- 2.52.0 From 527d239d53cecaa1cd76e929accc46a18edec18e Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Tue, 2 Jun 2026 09:39:26 +0200 Subject: [PATCH 24/27] JFJOchReader: Add ReadAllSpots option to handle reading just spot finding result --- reader/CMakeLists.txt | 1 + reader/JFJochHDF5Reader.cpp | 5 ++- reader/JFJochHDF5Reader.h | 3 +- reader/JFJochHttpReader.cpp | 28 ++++++++++++++ reader/JFJochHttpReader.h | 1 + reader/JFJochReader.cpp | 27 +++++++++++++ reader/JFJochReader.h | 4 ++ reader/JFJochReaderSpots.h | 12 ++++++ tests/JFJochReaderTest.cpp | 76 +++++++++++++++++++++++++++++++++++++ 9 files changed, 155 insertions(+), 2 deletions(-) create mode 100644 reader/JFJochReaderSpots.h diff --git a/reader/CMakeLists.txt b/reader/CMakeLists.txt index 15d65b73..75ee565e 100644 --- a/reader/CMakeLists.txt +++ b/reader/CMakeLists.txt @@ -8,6 +8,7 @@ ADD_LIBRARY(JFJochReader STATIC JFJochReaderDataset.h JFJochHttpReader.cpp JFJochHttpReader.h + JFJochReaderSpots.h ) TARGET_LINK_LIBRARIES(JFJochReader JFJochImageAnalysis JFJochAPI JFJochCommon JFJochZMQ JFJochLogger diff --git a/reader/JFJochHDF5Reader.cpp b/reader/JFJochHDF5Reader.cpp index 723a70a0..0a4e4dce 100644 --- a/reader/JFJochHDF5Reader.cpp +++ b/reader/JFJochHDF5Reader.cpp @@ -1249,9 +1249,12 @@ std::vector JFJochHDF5Reader::ReadReflections(size_t start_i return ret; } -std::vector JFJochHDF5Reader::ReadSpots(size_t image) const { +std::vector JFJochHDF5Reader::ReadSpots(int64_t image) const { std::unique_lock ul(hdf5_mutex); + if (image < 0) + throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, + "image number must be non-negative"); if (image >= number_of_images) throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "image must be less than number_of_images"); diff --git a/reader/JFJochHDF5Reader.h b/reader/JFJochHDF5Reader.h index f517f17c..25f59255 100644 --- a/reader/JFJochHDF5Reader.h +++ b/reader/JFJochHDF5Reader.h @@ -4,6 +4,7 @@ #pragma once #include "JFJochReader.h" +#include "JFJochReaderSpots.h" #include "../writer/HDF5Objects.h" #include "../image_analysis/IntegrationOutcome.h" @@ -56,7 +57,7 @@ public: std::vector ReadReflections(size_t start_image = 0, std::optional end_image = {}) const; - std::vector ReadSpots(size_t image) const; + std::vector ReadSpots(int64_t image) const override; CompressedImage ReadCalibration(std::vector &tmp, const std::string &name) const; diff --git a/reader/JFJochHttpReader.cpp b/reader/JFJochHttpReader.cpp index c3fb1732..45c8d45a 100644 --- a/reader/JFJochHttpReader.cpp +++ b/reader/JFJochHttpReader.cpp @@ -374,3 +374,31 @@ void JFJochHttpReader::UploadUserMask(const std::vector& mask) { throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Server rejected user mask upload"); } + +std::vector JFJochHttpReader::ReadSpots(int64_t image) const { + std::unique_lock ul(http_mutex); + + if (image < 0) + throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, + "Image number must be non-negative"); + + if (addr.empty()) + return {}; + + httplib::Client cli_cmd(addr); + auto res = cli_cmd.Get("/image_buffer/image.cbor?id=" + std::to_string(image)); + + if (!res || res->status != httplib::StatusCode::OK_200 || res->body.empty()) + return {}; + + try { + auto msg = CBORStream2Deserialize(res->body); + + if (msg->msg_type != CBORImageType::IMAGE) + return {}; + + return msg->data_message->spots; + } catch (std::exception &e) { + return {}; + } +} diff --git a/reader/JFJochHttpReader.h b/reader/JFJochHttpReader.h index 1e4dfb77..dcbc955a 100644 --- a/reader/JFJochHttpReader.h +++ b/reader/JFJochHttpReader.h @@ -36,6 +36,7 @@ public: BrokerStatus GetBrokerStatus() const; std::shared_ptr GetRawImage(int64_t image_number) override; + std::vector ReadSpots(int64_t image) const override; }; diff --git a/reader/JFJochReader.cpp b/reader/JFJochReader.cpp index 91d23222..06a0f7b3 100644 --- a/reader/JFJochReader.cpp +++ b/reader/JFJochReader.cpp @@ -98,3 +98,30 @@ void JFJochReader::UpdateUserMask(const std::vector &mask) { new_dataset->pixel_mask.LoadUserMask(dataset->experiment, mask); dataset = new_dataset; } + +std::shared_ptr JFJochReader::ReadAllSpots(int64_t start_image, int64_t end_image, + int64_t stride) const { + + if (start_image < 0) + throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, + "Start image must be non-negative"); + + if (start_image > end_image) + throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, + "Start image number is greater than end image number"); + + if (stride == 0) + throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, + "Stride cannot be zero"); + + size_t nelems = (end_image - start_image) / stride + 1; + + auto ret = std::make_shared(); + ret->start_image = static_cast(start_image); + ret->stride = static_cast(stride); + ret->spots.reserve(nelems); + + for (int i = 0; i < nelems; i++) + ret->spots.emplace_back(ReadSpots(start_image + i * stride)); + return ret; +} diff --git a/reader/JFJochReader.h b/reader/JFJochReader.h index 4c4ec5cd..39de784d 100644 --- a/reader/JFJochReader.h +++ b/reader/JFJochReader.h @@ -14,6 +14,7 @@ #include "../common/DiffractionExperiment.h" #include "JFJochReaderDataset.h" #include "JFJochReaderImage.h" +#include "JFJochReaderSpots.h" class JFJochReader { mutable std::mutex m; @@ -49,6 +50,9 @@ public: void UpdateUserMask(const std::vector& mask); virtual std::shared_ptr GetRawImage(int64_t image_number) = 0; + + virtual std::vector ReadSpots(int64_t image) const = 0; + std::shared_ptr ReadAllSpots(int64_t start_image, int64_t end_image, int64_t stride = 1) const; }; #endif //JFJOCHIMAGEREADER_H diff --git a/reader/JFJochReaderSpots.h b/reader/JFJochReaderSpots.h new file mode 100644 index 00000000..a66f8f13 --- /dev/null +++ b/reader/JFJochReaderSpots.h @@ -0,0 +1,12 @@ +// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute +// SPDX-License-Identifier: GPL-3.0-only + +#pragma once + +#include "../common/SpotToSave.h" + +struct JFJochReaderSpots { + int64_t start_image; + int64_t stride; + std::vector> spots; +}; diff --git a/tests/JFJochReaderTest.cpp b/tests/JFJochReaderTest.cpp index 01596948..7da8584e 100644 --- a/tests/JFJochReaderTest.cpp +++ b/tests/JFJochReaderTest.cpp @@ -2352,6 +2352,82 @@ TEST_CASE("JFJochReader_ReadSpots_VDS", "[HDF5][Full]") { REQUIRE(H5Fget_obj_count(H5F_OBJ_ALL, H5F_OBJ_ALL) == 0); } +TEST_CASE("JFJochReader_ReadAllSpots_VDS", "[HDF5][Full]") { + DiffractionExperiment x(DetJF(1)); + + x.FilePrefix("read_spots_vds") + .ImagesPerTrigger(20) + .ImagesPerFile(3) + .OverwriteExistingFiles(true) + .BitDepthImage(16) + .PixelSigned(true) + .SetFileWriterFormat(FileWriterFormat::NXmxVDS) + .IndexingAlgorithm(IndexingAlgorithmEnum::FFT) + .Compression(CompressionAlgorithm::NO_COMPRESSION); + + std::vector image(x.GetPixelsNum(), 0); + + RegisterHDF5Filter(); + { + StartMessage start_message; + x.FillMessage(start_message); + FileWriter file_set(start_message); + + for (int i = 0; i < x.GetImageNum(); i++) { + DataMessage message{}; + message.image = CompressedImage(image, x.GetXPixelsNum(), x.GetYPixelsNum()); + message.number = i; + message.spots = MakeTestSpots(i); + message.spot_count = 72 + i; + message.spot_count_ice_rings = 45 + 2 * i; + message.spot_count_low_res = 12 + 3 * i; + message.spot_count_indexed = 15 + 4 * i; + REQUIRE_NOTHROW(file_set.WriteHDF5(message)); + } + + EndMessage end_message; + end_message.max_image_number = x.GetImageNum(); + file_set.WriteHDF5(end_message); + file_set.Finalize(); + } + + { + JFJochHDF5Reader reader; + REQUIRE_NOTHROW(reader.ReadFile("read_spots_vds_master.h5")); + + std::shared_ptr ret; + REQUIRE_NOTHROW(ret = reader.ReadAllSpots(1, 15, 2)); + + // 1,3,5,7,9,11,13,15 + REQUIRE(ret); + REQUIRE(ret->start_image == 1); + REQUIRE(ret->stride == 2); + REQUIRE(ret->spots.size() == 8); + + for (int i = 0; i < ret->spots.size(); i++) { + REQUIRE(ret->spots[i].size() == 2); + CheckSpotFields(ret->spots[i][0], ret->spots[i][1], 2 * i + 1); + } + } + + { + JFJochHDF5Reader reader; + REQUIRE_NOTHROW(reader.ReadFile("read_spots_vds_master.h5")); + REQUIRE_THROWS(reader.ReadAllSpots(-5,0)); + REQUIRE_THROWS(reader.ReadAllSpots(5,0)); + } + + remove("read_spots_vds_master.h5"); + remove("read_spots_vds_data_000001.h5"); + remove("read_spots_vds_data_000002.h5"); + remove("read_spots_vds_data_000003.h5"); + remove("read_spots_vds_data_000004.h5"); + + REQUIRE(H5Fget_obj_count(H5F_OBJ_ALL, H5F_OBJ_ALL) == 0); +} + + + TEST_CASE("JFJochReader_ReadSpots_Integrated", "[HDF5][Full]") { DiffractionExperiment x(DetJF(1)); -- 2.52.0 From aa9f5b1d1ec8c1356b7e1979998589aa1b0a5aba Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Tue, 2 Jun 2026 10:11:09 +0200 Subject: [PATCH 25/27] jfjoch_viewer: Reciprocal space viewer allows to digest the whole dataset. --- viewer/JFJochImageReadingWorker.cpp | 10 + viewer/JFJochImageReadingWorker.h | 5 + viewer/JFJochViewerWindow.cpp | 5 + .../JFJochViewerReciprocalSpaceWindow.cpp | 256 +++++++++++------- .../JFJochViewerReciprocalSpaceWindow.h | 27 +- 5 files changed, 210 insertions(+), 93 deletions(-) diff --git a/viewer/JFJochImageReadingWorker.cpp b/viewer/JFJochImageReadingWorker.cpp index 549e51b5..6d7cf8c7 100644 --- a/viewer/JFJochImageReadingWorker.cpp +++ b/viewer/JFJochImageReadingWorker.cpp @@ -695,3 +695,13 @@ void JFJochImageReadingWorker::setAutoLoadJump(int64_t val) { if (val > 0) jump_value = val; } + +void JFJochImageReadingWorker::LoadSpots(int64_t start_image, int64_t end_image, int64_t stride) { + QMutexLocker ul(&m); + std::shared_ptr result; + if (http_mode) + result = http_reader.ReadAllSpots(start_image, end_image, stride); + else + result = file_reader.ReadAllSpots(start_image, end_image, stride); + emit spotsLoaded(result); +} diff --git a/viewer/JFJochImageReadingWorker.h b/viewer/JFJochImageReadingWorker.h index 8bb57ae5..17e6d2cb 100644 --- a/viewer/JFJochImageReadingWorker.h +++ b/viewer/JFJochImageReadingWorker.h @@ -21,6 +21,8 @@ Q_DECLARE_METATYPE(std::shared_ptr) Q_DECLARE_METATYPE(std::shared_ptr) +Q_DECLARE_METATYPE(std::shared_ptr) + Q_DECLARE_METATYPE(DiffractionExperiment) Q_DECLARE_METATYPE(SpotFindingSettings) Q_DECLARE_METATYPE(IndexingSettings) @@ -107,6 +109,7 @@ private: signals: void datasetLoaded(std::shared_ptr); void imageLoaded(std::shared_ptr); + void spotsLoaded(std::shared_ptr); void imageStatsUpdated(std::shared_ptr); void imageNumberChanged(int64_t total_images, int64_t current_image); void setRings(const QVector &v); @@ -127,6 +130,8 @@ public slots: void LoadFile(const QString &filename, qint64 image_number, qint64 summation, bool retry); void CloseFile(); void LoadImage(int64_t image_number, int64_t summation); + void LoadSpots(int64_t start_image, int64_t end_image, int64_t stride); + void SetROIBox(QRect box); void SetROICircle(double x, double y, double radius); diff --git a/viewer/JFJochViewerWindow.cpp b/viewer/JFJochViewerWindow.cpp index e0ceed12..e43fcc76 100644 --- a/viewer/JFJochViewerWindow.cpp +++ b/viewer/JFJochViewerWindow.cpp @@ -314,6 +314,11 @@ JFJochViewerWindow::JFJochViewerWindow(QWidget *parent, bool dbus, const QString connect(reading_worker, &JFJochImageReadingWorker::imageLoaded, reciprocalWindow, &JFJochViewerReciprocalSpaceWindow::imageLoaded); + connect(reciprocalWindow, &JFJochViewerReciprocalSpaceWindow::loadSpotsRequest, + reading_worker, &JFJochImageReadingWorker::LoadSpots); + connect(reading_worker, &JFJochImageReadingWorker::spotsLoaded, + reciprocalWindow, &JFJochViewerReciprocalSpaceWindow::spotsLoaded); + connect(reciprocalWindow, &JFJochHelperWindow::zoom, viewer, &JFJochDiffractionImage::centerOnSpot); diff --git a/viewer/windows/JFJochViewerReciprocalSpaceWindow.cpp b/viewer/windows/JFJochViewerReciprocalSpaceWindow.cpp index cc4507d9..0eb41f23 100644 --- a/viewer/windows/JFJochViewerReciprocalSpaceWindow.cpp +++ b/viewer/windows/JFJochViewerReciprocalSpaceWindow.cpp @@ -6,12 +6,15 @@ #include #include #include +#include +#include #include #include #include #include -#include + +#include "../../reader/JFJochReaderSpots.h" // ============================================================================ // Shaders @@ -348,9 +351,8 @@ bool ReciprocalSpaceGLView::emitNearestSpot(const QPoint &screenPos) { // ============================================================================ JFJochViewerReciprocalSpaceWindow::JFJochViewerReciprocalSpaceWindow(QWidget *parent) - : JFJochHelperWindow(parent) -{ - setWindowTitle("Reciprocal space"); + : JFJochHelperWindow(parent) { + setWindowTitle("Reciprocal space"); resize(800, 800); auto *central = new QWidget(this); @@ -369,14 +371,29 @@ JFJochViewerReciprocalSpaceWindow::JFJochViewerReciprocalSpaceWindow(QWidget *pa showCellCheck = new QCheckBox("Show reciprocal cell", central); showCellCheck->setChecked(true); - showPredictedCheck = new QCheckBox("Show predicted nodes", central); - showPredictedCheck->setChecked(true); + showPredictedCheck = new QCheckBox("Show predicted reflections", central); + showPredictedCheck->setChecked(false); + strideCombo = new QComboBox(central); + strideCombo->addItem("1", 1); + strideCombo->addItem("2", 2); + strideCombo->addItem("5", 5); + strideCombo->addItem("10", 10); + strideCombo->addItem("100", 100); + strideCombo->setCurrentIndex(0); + + auto *loadFullDatasetButton = new QPushButton("Load full dataset", central); + auto *loadCurrentImageButton = new QPushButton("Load only current image", central); auto *centerOriginButton = new QPushButton("Center 000", central); controls->addWidget(crystalFrameCheck); controls->addWidget(showCellCheck); controls->addWidget(showPredictedCheck); + controls->addSpacing(12); + controls->addWidget(new QLabel("Stride:", central)); + controls->addWidget(strideCombo); + controls->addWidget(loadFullDatasetButton); + controls->addWidget(loadCurrentImageButton); controls->addStretch(1); controls->addWidget(centerOriginButton); @@ -389,11 +406,32 @@ JFJochViewerReciprocalSpaceWindow::JFJochViewerReciprocalSpaceWindow(QWidget *pa this, &JFJochViewerReciprocalSpaceWindow::rebuildGL); connect(showPredictedCheck, &QCheckBox::toggled, this, &JFJochViewerReciprocalSpaceWindow::rebuildGL); + + connect(loadFullDatasetButton, &QPushButton::clicked, this, [this] { + if (!current_dataset_) + return; + + const int64_t nimages = current_dataset_->experiment.GetImageNum(); + if (nimages <= 0) + return; + + const int64_t stride = strideCombo ? strideCombo->currentData().toLongLong() : 1; + + full_dataset_mode_ = true; + emit loadSpotsRequest(0, nimages - 1, stride); + }); + + connect(loadCurrentImageButton, &QPushButton::clicked, this, [this] { + full_dataset_mode_ = false; + loadCurrentImageSpots(current_image_); + rebuildGL(); + }); + connect(centerOriginButton, &QPushButton::clicked, glView_, &ReciprocalSpaceGLView::resetTarget); - // Reuse the existing helper-window zoom signal. The main window should connect - // this to JFJochDiffractionImage::centerOnSpot, like the spot/reflection lists. + // Reuse the existing helper-window zoom signal. For full-dataset mode we will + // later want image-number-aware picking, but current image mode can use this now. connect(glView_, &ReciprocalSpaceGLView::spotDoubleClicked, this, &JFJochHelperWindow::zoom); @@ -407,14 +445,18 @@ JFJochViewerReciprocalSpaceWindow::JFJochViewerReciprocalSpaceWindow(QWidget *pa void JFJochViewerReciprocalSpaceWindow::datasetLoaded( std::shared_ptr in_dataset) { + current_dataset_ = std::move(in_dataset); + current_image_.reset(); + spots_.clear(); reflections_.clear(); indexed_lattice_.reset(); current_back_rot_.reset(); + full_dataset_mode_ = false; has_rotation_ = false; - if (in_dataset) - has_rotation_ = in_dataset->experiment.GetGoniometer().has_value(); + if (current_dataset_) + has_rotation_ = current_dataset_->experiment.GetGoniometer().has_value(); crystalFrameCheck->setEnabled(has_rotation_); if (!has_rotation_) @@ -424,15 +466,31 @@ void JFJochViewerReciprocalSpaceWindow::datasetLoaded( } void JFJochViewerReciprocalSpaceWindow::imageLoaded(std::shared_ptr image) { + current_image_ = std::move(image); + + // In full-dataset mode, normal image updates should not replace the range view. + if (full_dataset_mode_) + return; + + loadCurrentImageSpots(current_image_); + rebuildGL(); +} + +void JFJochViewerReciprocalSpaceWindow::loadCurrentImageSpots( + std::shared_ptr image) +{ spots_.clear(); reflections_.clear(); indexed_lattice_.reset(); current_back_rot_.reset(); - if (!image) { - rebuildGL(); + if (!image) return; - } + + current_dataset_ = std::shared_ptr( + image, + &image->Dataset() + ); const auto &dataset = image->Dataset(); const auto geom = dataset.experiment.GetDiffractionGeometry(); @@ -447,31 +505,78 @@ void JFJochViewerReciprocalSpaceWindow::imageLoaded(std::shared_ptrImageData().spots.size()); - for (const auto &s : image->ImageData().spots) { - CurrentSpot spot; - spot.recip_lab = s.ReciprocalCoord(geom); - spot.recip_crystal = current_back_rot_ ? (*current_back_rot_ * spot.recip_lab) : spot.recip_lab; - spot.image_x = s.x; - spot.image_y = s.y; - spot.h = static_cast(s.h); - spot.k = static_cast(s.k); - spot.l = static_cast(s.l); - spot.indexed = s.indexed; - spot.ice_ring = s.ice_ring; - spots_.emplace_back(spot); - } + for (const auto &s : image->ImageData().spots) + addSpot(s, geom, axis, image_number); reflections_.reserve(image->ImageData().reflections.size()); for (const auto &r : image->ImageData().reflections) { reflections_.push_back({ .h = r.h, .k = r.k, - .l = r.l + .l = r.l, + .image_x = r.predicted_x, + .image_y = r.predicted_y }); } if (image->ImageData().indexing_lattice) indexed_lattice_ = image->ImageData().indexing_lattice; +} + +void JFJochViewerReciprocalSpaceWindow::addSpot(const SpotToSave &s, const DiffractionGeometry &geom, + const std::optional &axis, int64_t image_number) { + std::optional back_rot; + if (axis) { + const float angle_deg = axis->GetAngle_deg(static_cast(image_number)) + + axis->GetWedge_deg() / 2.0f; + back_rot = axis->GetTransformationAngle(angle_deg); + } + + CurrentSpot spot; + spot.recip_lab = s.ReciprocalCoord(geom); + spot.recip_crystal = back_rot ? (*back_rot * spot.recip_lab) : spot.recip_lab; + spot.image_x = s.x; + spot.image_y = s.y; + spot.image_number = image_number; + spot.h = static_cast(s.h); + spot.k = static_cast(s.k); + spot.l = static_cast(s.l); + spot.indexed = s.indexed; + spot.ice_ring = s.ice_ring; + + spots_.emplace_back(spot); +} + +void JFJochViewerReciprocalSpaceWindow::spotsLoaded(std::shared_ptr reader_spots) { + if (!reader_spots || !current_dataset_) + return; + + full_dataset_mode_ = true; + + spots_.clear(); + reflections_.clear(); + current_back_rot_.reset(); + + const auto geom = current_dataset_->experiment.GetDiffractionGeometry(); + const auto axis = current_dataset_->experiment.GetGoniometer(); + + size_t total_spots = 0; + for (const auto &image_spots : reader_spots->spots) + total_spots += image_spots.size(); + + spots_.reserve(total_spots); + + for (size_t image_index = 0; image_index < reader_spots->spots.size(); ++image_index) { + const int64_t image_number = reader_spots->start_image + image_index * reader_spots->stride; + + for (const auto &s : reader_spots->spots[image_index]) + addSpot(s, geom, axis, image_number); + } + + // Keep the cell vectors from the currently visible image if available. + // Later we can improve this by reading/choosing a representative lattice for the range. + if (current_image_ && current_image_->ImageData().indexing_lattice) + indexed_lattice_ = current_image_->ImageData().indexing_lattice; rebuildGL(); } @@ -546,10 +651,6 @@ void JFJochViewerReciprocalSpaceWindow::rebuildGL() { toF(ice_ring_color, xr, xg, xb); toF(prediction_color, pr, pg, pb); - int hMax = 0; - int kMax = 0; - int lMax = 0; - for (const auto &spot : spots_) { const Coord &c = crystal_frame ? spot.recip_crystal : spot.recip_lab; @@ -575,86 +676,57 @@ void JFJochViewerReciprocalSpaceWindow::rebuildGL() { r, g, b, 1.0f, spot.image_x, spot.image_y, + static_cast(spot.image_number), 1.0f }); - - if (spot.indexed) { - hMax = std::max(hMax, std::abs(spot.h)); - kMax = std::max(kMax, std::abs(spot.k)); - lMax = std::max(lMax, std::abs(spot.l)); - } } - /* - // Also include predicted-reflection HKLs in the plotting range. - for (const auto &r : reflections_) { - hMax = std::max(hMax, std::abs(r.h)); - kMax = std::max(kMax, std::abs(r.k)); - lMax = std::max(lMax, std::abs(r.l)); - } */ - // Explicit 000 reflection marker. spotVerts.push_back({ 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, + -1.0f, 0.0f }); - // Predicted reciprocal-lattice nodes: - // q = h*Astar + k*Bstar + l*Cstar, in the currently plotted frame. - if (showPredictedCheck->isChecked() && plot_lattice && hMax > 0 && kMax > 0 && lMax > 0) { + if (showPredictedCheck->isChecked() && plot_lattice) { const Coord a = plot_lattice->Astar(); const Coord b = plot_lattice->Bstar(); const Coord c = plot_lattice->Cstar(); - for (int h = -hMax; h <= hMax; ++h) { - for (int k = -kMax; k <= kMax; ++k) { - for (int l = -lMax; l <= lMax; ++l) { - if (h == 0 && k == 0 && l == 0) - continue; - - bool observedIndexed = false; - for (const auto &spot : spots_) { - if (spot.indexed && spot.h == h && spot.k == k && spot.l == l) { - observedIndexed = true; - break; - } - } - - if (observedIndexed) - continue; - - bool predictedForImage = false; - for (const auto &r : reflections_) { - if (r.h == h && r.k == k && r.l == l) { - predictedForImage = true; - break; - } - } - - const Coord node{ - h * a.x + k * b.x + l * c.x, - h * a.y + k * b.y + l * c.y, - h * a.z + k * b.z + l * c.z - }; - - if (predictedForImage) { - // Highlight nodes that are actual predictions for this image. - spotVerts.push_back({ - node.x * scene_scale_, - node.y * scene_scale_, - node.z * scene_scale_, - pr, pg, pb, 0.85f, - 0.0f, 0.0f, - 0.0f - }); - } + for (const auto &r : reflections_) { + bool observedIndexed = false; + for (const auto &spot : spots_) { + if (spot.indexed && spot.h == r.h && spot.k == r.k && spot.l == r.l) { + observedIndexed = true; + break; } } + + if (observedIndexed) + continue; + + const Coord node{ + r.h * a.x + r.k * b.x + r.l * c.x, + r.h * a.y + r.k * b.y + r.l * c.y, + r.h * a.z + r.k * b.z + r.l * c.z + }; + + // Highlight nodes that are actual predictions for this image. + spotVerts.push_back({ + node.x * scene_scale_, + node.y * scene_scale_, + node.z * scene_scale_, + pr, pg, pb, 0.80f, + r.image_x, r.image_y, + -1.0f, + 1.0f + }); } } + // --- Lines: axes + optional cell vectors --------------------------------- std::vector lineVerts; @@ -667,14 +739,14 @@ void JFJochViewerReciprocalSpaceWindow::rebuildGL() { a.x(), a.y(), a.z(), r, g, bv, alpha, 0.0f, 0.0f, - 0.0f + -1.0f, 0.0f, }); lineVerts.push_back({ b.x(), b.y(), b.z(), r, g, bv, alpha, 0.0f, 0.0f, - 0.0f + -1.0f, 0.0f }); }; diff --git a/viewer/windows/JFJochViewerReciprocalSpaceWindow.h b/viewer/windows/JFJochViewerReciprocalSpaceWindow.h index 9923715b..d4008969 100644 --- a/viewer/windows/JFJochViewerReciprocalSpaceWindow.h +++ b/viewer/windows/JFJochViewerReciprocalSpaceWindow.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -19,10 +20,14 @@ #include "JFJochHelperWindow.h" // your existing base class #include "../../common/CrystalLattice.h" // Coord, RotMatrix, etc. +#include "../../common/SpotToSave.h" +#include "../../common/DiffractionGeometry.h" +#include "../../common/GoniometerAxis.h" // Forward declarations from your codebase -class JFJochReaderDataset; +struct JFJochReaderDataset; class JFJochReaderImage; +struct JFJochReaderSpots; // --------------------------------------------------------------------------- // ReciprocalSpaceGLView – the actual OpenGL viewport @@ -39,6 +44,7 @@ public: float r, g, b, a; float image_x = 0.0f; float image_y = 0.0f; + float image_number = -1.0f; float pickable = 0.0f; }; @@ -95,14 +101,19 @@ private: // --------------------------------------------------------------------------- // JFJochViewerReciprocalSpaceWindow – the outer QMainWindow // --------------------------------------------------------------------------- + class JFJochViewerReciprocalSpaceWindow : public JFJochHelperWindow { Q_OBJECT public: explicit JFJochViewerReciprocalSpaceWindow(QWidget *parent = nullptr); +signals: + void loadSpotsRequest(int64_t start_image, int64_t end_image, int64_t stride); + public slots: void datasetLoaded(std::shared_ptr dataset); void imageLoaded(std::shared_ptr image); + void spotsLoaded(std::shared_ptr spots); void setSpotColor(QColor color); void setFeatureColor(QColor color); void setPredictionColor(QColor color); @@ -113,6 +124,7 @@ private: Coord recip_crystal; float image_x = 0.0f; float image_y = 0.0f; + int64_t image_number = -1; int32_t h = 0; int32_t k = 0; int32_t l = 0; @@ -124,23 +136,36 @@ private: int32_t h = 0; int32_t k = 0; int32_t l = 0; + float image_x = 0.0f; + float image_y = 0.0f; + int64_t image_number = -1; }; QColor spotColorFor(bool indexed, bool ice_ring) const; void rebuildGL(); // rebuilds both spot and line vertex data + void loadCurrentImageSpots(std::shared_ptr image); + void addSpot(const SpotToSave &s, + const DiffractionGeometry &geom, + const std::optional &axis, + int64_t image_number); // UI ReciprocalSpaceGLView *glView_ = nullptr; QCheckBox *crystalFrameCheck = nullptr; QCheckBox *showCellCheck = nullptr; QCheckBox *showPredictedCheck = nullptr; + QComboBox *strideCombo = nullptr; // Data + std::shared_ptr current_dataset_; + std::shared_ptr current_image_; + std::vector spots_; std::vector reflections_; std::optional indexed_lattice_; std::optional current_back_rot_; bool has_rotation_ = false; + bool full_dataset_mode_ = false; float scene_scale_ = 100.0f; // Colors -- 2.52.0 From 06a3b57700d16441f7080b5b303e2781c51d1e51 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Tue, 2 Jun 2026 10:15:08 +0200 Subject: [PATCH 26/27] VERSION: 1.0.0-rc.147 --- VERSION | 2 +- 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 +- .../model/Calibration_statistics_inner.cpp | 2 +- .../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 +- ...et_settings_xray_fluorescence_spectrum.cpp | 2 +- ...aset_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 +- .../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 +- .../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_status.cpp | 2 +- broker/gen/model/Image_pusher_status.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_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 +- .../gen/model/Standard_detector_geometry.cpp | 2 +- broker/gen/model/Standard_detector_geometry.h | 2 +- broker/gen/model/Tcp_settings.cpp | 2 +- broker/gen/model/Tcp_settings.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 | 4 +- docs/CHANGELOG.md | 6 + docs/conf.py | 2 +- docs/python_client/README.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-lock.json | 144 +++++++++++------- frontend/package.json | 2 +- frontend/src/openapi/core/OpenAPI.ts | 2 +- frontend/src/version.ts | 2 +- 130 files changed, 223 insertions(+), 187 deletions(-) diff --git a/VERSION b/VERSION index 53b90da1..52fce327 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.0-rc.146 +1.0.0-rc.147 diff --git a/broker/gen/model/Azim_int_settings.cpp b/broker/gen/model/Azim_int_settings.cpp index 916ae6a0..4f1418c6 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 919966c5..59ca3f74 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 500f1b25..079ef60c 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 c1144ef4..676ae6e9 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 02728631..505ed9ad 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 13a682ab..f7c980d7 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 240163be..68e30d67 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 5164aa3f..f1e0a446 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 a8c532a3..bb3ae59c 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 ae6a179d..e3c68252 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 f5d192da..3039284e 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 c6144fc9..f1dd6854 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 1ee2e4f0..7bfd2715 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 6e1b393a..11c8d637 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 056ea1a3..0bddd3b6 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 db254370..abf37779 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 b28c71ab..3f692cf2 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 87297114..31c00b1b 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 3aef0e6d..01ce8e49 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 0d75e149..adf4befe 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 318954df..7e741399 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 766af013..e3baf78f 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 ebe54543..4a40e0a5 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 2de4f892..c2d41a28 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 04ec9293..50720cc9 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 df133bb2..a989e1d7 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 5ac769ee..65a2f50e 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 88e2a989..9feeb53f 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 c181444b..782b4d37 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 95a290d2..3a0fee59 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 239c2a98..71afd850 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 5a803338..6b299ece 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 65d47a97..aa429a5f 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 c3ed0e6e..a9dac232 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 09219586..fcd3b699 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 4b6301da..88af7002 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 5a28f9d1..6781be92 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 3b842bab..692ccbf4 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 82ce5e36..5ba59185 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 05ad9534..88d32bb7 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 a2c34259..c4d0adf0 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 e094ca33..b17ffc19 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 848c6ad9..ec1575b1 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 8b973b03..26e04be6 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 d142be56..3f2ea484 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 e7ff00e8..65a5dd1c 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 251e0be3..0d596dee 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 9fcad3fe..58ece0e1 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 3bee8b95..32a753f1 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 4728a9f1..7bbd0424 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 c59a04bc..e823ccdc 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 ca90f6f3..3ed1aca0 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 d5559f95..2af077df 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 6861ace4..293a463b 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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_status.cpp b/broker/gen/model/Image_pusher_status.cpp index a2e744fd..1dcc32de 100644 --- a/broker/gen/model/Image_pusher_status.cpp +++ b/broker/gen/model/Image_pusher_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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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_status.h b/broker/gen/model/Image_pusher_status.h index 208d82a7..fa83e947 100644 --- a/broker/gen/model/Image_pusher_status.h +++ b/broker/gen/model/Image_pusher_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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 b0227733..cc758507 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 868db48e..6fc054e6 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 46a83876..ee7cbbe8 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 57de746f..07c3bdb8 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 2f0d50a2..e9f38675 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 d1a9def9..4f19e8f5 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 6e06dd03..535b0151 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 b1642aab..2f58c1df 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 84707a82..4602d939 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 d8aad51a..2380d36d 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 e0abc281..54bbbd5c 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 b752653b..e0deb5b0 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 f19da8b3..cb560518 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 69c5ab26..76fac830 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 1c12ec96..809e86bd 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 d603a12f..3b8c8f51 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 b13a848e..81380576 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 7a03965b..01d54f8a 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 4455d5f9..df98313f 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 14d803b2..17c3ef40 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 c080b201..ba7eb86b 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 c15ee0aa..46e0eb07 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 faf9f72d..00329d07 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 f32f2d31..84daae86 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 7afe427c..426765a5 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 55818081..35daf81e 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 85279990..a2b572bf 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 63ef9f88..57c44b7f 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 43cbaa04..80d05f46 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 52fc4a11..2edca114 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 09221426..20b90218 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 ff941871..d55bf885 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 6922ac2d..6ba8c4bd 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 a9e3ea45..ae6affc0 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 fcf3643f..41722cd4 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 ce2f9223..92277278 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 bb191347..dccd95a0 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 04c99925..345ec04d 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 a6e751f7..1ad0e10f 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 c7a12c36..5223e732 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 29a3e49b..e594f2f8 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 c99ce1d2..0ef93dcd 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 ca731edd..f414eac0 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 67fbf861..93da2f57 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 38d4f14b..a1b09f86 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 ea398faf..b996d931 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 44cb25df..f65dc9b4 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 b0dc4259..ce1b497d 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Tcp_settings.cpp b/broker/gen/model/Tcp_settings.cpp index 0d6c55a6..fea40813 100644 --- a/broker/gen/model/Tcp_settings.cpp +++ b/broker/gen/model/Tcp_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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * Contact: filip.leonarski@psi.ch * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/broker/gen/model/Tcp_settings.h b/broker/gen/model/Tcp_settings.h index 41a0f06b..2b125fd6 100644 --- a/broker/gen/model/Tcp_settings.h +++ b/broker/gen/model/Tcp_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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 705770a2..0bba9eb9 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 fada4fe4..9485dae4 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 04c898c4..6cf3db7b 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 62ab4fe0..4c6e6c4c 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 ad7c6b85..5e60a91c 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 df4562f3..4f70198b 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 21ee0060..4675c302 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 1960addc..c80b23b5 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.146 +* The version of the OpenAPI document: 1.0.0-rc.147 * 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 4631a42c..cac02daf 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.146 + version: 1.0.0-rc.147 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 6df2bf02..8a904e81 100644 --- a/broker/redoc-static.html +++ b/broker/redoc-static.html @@ -399,7 +399,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.146)

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). + " fill="currentColor">

Jungfraujoch (1.0.0-rc.147)

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). 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 @@ -933,7 +933,7 @@ then image might be replaced in the buffer between calling /images and /image.cb