From 93b733d5723a857519b97701b9f36fd8cc8c7c04 Mon Sep 17 00:00:00 2001 From: James Beilsten-Edmands <30625594+jbeilstenedmands@users.noreply.github.com> Date: Fri, 26 Sep 2025 15:15:39 +0100 Subject: [PATCH 1/4] Define an ImageSequence, allow updating of models. --- dx2/detector.cxx | 6 ++++++ include/dx2/detector.hpp | 1 + include/dx2/experiment.hpp | 30 ++++++++++++++++++++++++++++ include/dx2/imageset.hpp | 41 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 78 insertions(+) create mode 100644 include/dx2/imageset.hpp diff --git a/dx2/detector.cxx b/dx2/detector.cxx index 732b77c..f120582 100644 --- a/dx2/detector.cxx +++ b/dx2/detector.cxx @@ -236,6 +236,12 @@ Detector::Detector(json detector_data) { } } +Detector::Detector(std::vector panels) { + for (auto it = panels.begin(); it != panels.end(); ++it) { + _panels.push_back(*it); + } +} + json Detector::to_json() const { json detector_data; std::vector panels_array; diff --git a/include/dx2/detector.hpp b/include/dx2/detector.hpp index 5875d07..1b1af14 100644 --- a/include/dx2/detector.hpp +++ b/include/dx2/detector.hpp @@ -99,6 +99,7 @@ class Detector { public: Detector() = default; Detector(json detector_data); + Detector(std::vector panels); json to_json() const; std::vector panels() const; std::optional>> diff --git a/include/dx2/experiment.hpp b/include/dx2/experiment.hpp index d19cc70..1ca00cd 100644 --- a/include/dx2/experiment.hpp +++ b/include/dx2/experiment.hpp @@ -22,6 +22,11 @@ template class Experiment { Detector &detector(); const Crystal &crystal() const; void set_crystal(Crystal crystal); + void set_beam(BeamType beam); + void set_scan(Scan scan); + void set_detector(Detector detector); + void set_goniometer(Goniometer goniometer); + void set_imageset_json(json imageset_json); void set_identifier(std::string identifier); protected: @@ -115,10 +120,35 @@ void Experiment::set_crystal(Crystal crystal) { _crystal = crystal; } +template +void Experiment::set_beam(BeamType beam) { + _beam = beam; +} + template BeamType &Experiment::beam() { return _beam; } +template +void Experiment::set_scan(Scan scan) { + _scan = scan; +} + +template +void Experiment::set_detector(Detector detector) { + _detector = detector; +} + +template +void Experiment::set_goniometer(Goniometer goniometer) { + _goniometer = goniometer; +} + +template +void Experiment::set_imageset_json(json imageset_json) { + _imageset_json = imageset_json; +} + template const std::string &Experiment::identifier() const { return _identifier; diff --git a/include/dx2/imageset.hpp b/include/dx2/imageset.hpp new file mode 100644 index 0000000..00cbe1e --- /dev/null +++ b/include/dx2/imageset.hpp @@ -0,0 +1,41 @@ +#pragma once +#include + +using Eigen::Vector3d; +using json = nlohmann::json; + +class ImageSequence { +public: + ImageSequence() = default; + ImageSequence(std::string filename, int n_images); + json to_json() const; +protected: + int n_images_ {}; + std::string filename_ {}; + std::vector single_file_indices_{}; +}; + +ImageSequence::ImageSequence(std::string filename, int n_images) : filename_(filename), n_images_(n_images) { + single_file_indices_.reserve(n_images_); + for (std::size_t i=0;i Date: Mon, 17 Nov 2025 13:44:37 +0000 Subject: [PATCH 2/4] Update name, use proper class rather than json. --- dx2/CMakeLists.txt | 1 + dx2/imagesequence.cxx | 56 +++++++++++++++++++++++++++++++++++ include/dx2/experiment.hpp | 17 ++++++----- include/dx2/imagesequence.hpp | 17 +++++++++++ include/dx2/imageset.hpp | 41 ------------------------- 5 files changed, 83 insertions(+), 49 deletions(-) create mode 100644 dx2/imagesequence.cxx create mode 100644 include/dx2/imagesequence.hpp delete mode 100644 include/dx2/imageset.hpp diff --git a/dx2/CMakeLists.txt b/dx2/CMakeLists.txt index ca7b921..877c607 100644 --- a/dx2/CMakeLists.txt +++ b/dx2/CMakeLists.txt @@ -9,6 +9,7 @@ add_library( goniometer.cxx scan.cxx detector_attenuations.cxx + imagesequence.cxx ) target_link_libraries( dx2 diff --git a/dx2/imagesequence.cxx b/dx2/imagesequence.cxx new file mode 100644 index 0000000..e15c7e4 --- /dev/null +++ b/dx2/imagesequence.cxx @@ -0,0 +1,56 @@ +#include "dx2/imagesequence.hpp" + +using json = nlohmann::json; + +ImageSequence::ImageSequence(std::string filename, int n_images) : filename_(filename), n_images_(n_images) { + single_file_indices_.reserve(n_images_); + for (std::size_t i=0;i required_keys = {"template", "single_file_indices", "__id__"}; + for (const auto &key : required_keys) { + if (imagesequence_data.find(key) == imagesequence_data.end()) { + throw std::invalid_argument("Key " + key + + " is missing from the input imageset JSON"); + } + } + if (imagesequence_data["__id__"] != std::string("ImageSequence")){ + throw std::runtime_error("Only ImageSequences are supported"); + } + filename_ = imagesequence_data["template"]; + json indices = imagesequence_data["single_file_indices"]; + single_file_indices_ = {}; + if (*(indices.begin()) < 0){ + throw std::runtime_error("Starting file index <0"); + } + for (json::iterator it = indices.begin(); it != indices.end(); + ++it) { + single_file_indices_.push_back(*it); + } + n_images_ = single_file_indices_.size(); + imagesequence_data_ = imagesequence_data; // To propagate during serialization/deserialization. +} + +json ImageSequence::to_json() const { + json imageset_data = imagesequence_data_; + imageset_data["__id__"] = "ImageSequence"; + imageset_data["template"] = filename_; + imageset_data["single_file_indices"] = single_file_indices_; + // Set defaults and null for now. + std::vector optional_keys = {"mask", "gain", "pedestal", "dx", "dy"}; + for (const auto &key : optional_keys) { + if (imagesequence_data_.find(key) == imagesequence_data_.end()) { + imageset_data[key] = nullptr; + } + } + if (imagesequence_data_.find("params") == imagesequence_data_.end()) { + json params; + params["dynamic_shadowing"] = "Auto"; + params["multi_panel"] = false; + imageset_data["params"] = params; + } + return imageset_data; +} \ No newline at end of file diff --git a/include/dx2/experiment.hpp b/include/dx2/experiment.hpp index 1ca00cd..a4e2345 100644 --- a/include/dx2/experiment.hpp +++ b/include/dx2/experiment.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include using Eigen::Vector3d; @@ -26,7 +27,7 @@ template class Experiment { void set_scan(Scan scan); void set_detector(Detector detector); void set_goniometer(Goniometer goniometer); - void set_imageset_json(json imageset_json); + void set_imagesequence(ImageSequence imagesequence); void set_identifier(std::string identifier); protected: @@ -35,7 +36,7 @@ template class Experiment { Goniometer _goniometer{}; Detector _detector{}; Crystal _crystal{}; - json _imageset_json{}; + ImageSequence _imagesequence{}; std::string _identifier{}; }; @@ -56,8 +57,9 @@ Experiment::Experiment(json experiment_data) { this->_goniometer = gonio; this->_detector = detector; // Save the imageset json to propagate when saving to file. - json imageset_data = experiment_data["imageset"][0]; - this->_imageset_json = imageset_data; + json imagesequence_data = experiment_data["imageset"][0]; + ImageSequence imagesequence(imagesequence_data); + this->_imagesequence = imagesequence; try { // We don't always have a crystal model e.g. before indexing. json crystal_data = experiment_data["crystal"][0]; Crystal crystal(crystal_data); @@ -72,7 +74,6 @@ template json Experiment::to_json() const { json elist_out; // a list of potentially multiple experiments elist_out["__id__"] = "ExperimentList"; json expt_out; // our single experiment - // no imageset (for now?). expt_out["__id__"] = "Experiment"; expt_out["identifier"] = _identifier; expt_out["beam"] = @@ -87,7 +88,7 @@ template json Experiment::to_json() const { elist_out["goniometer"] = std::array{_goniometer.to_json()}; elist_out["beam"] = std::array{_beam.to_json()}; elist_out["detector"] = std::array{_detector.to_json()}; - elist_out["imageset"] = std::array{_imageset_json}; + elist_out["imageset"] = std::array{_imagesequence.to_json()}; if (_crystal.get_U_matrix().determinant()) { expt_out["crystal"] = 0; @@ -145,8 +146,8 @@ void Experiment::set_goniometer(Goniometer goniometer) { } template -void Experiment::set_imageset_json(json imageset_json) { - _imageset_json = imageset_json; +void Experiment::set_imagesequence(ImageSequence imagesequence) { + _imagesequence = imagesequence; } template diff --git a/include/dx2/imagesequence.hpp b/include/dx2/imagesequence.hpp new file mode 100644 index 0000000..b3935df --- /dev/null +++ b/include/dx2/imagesequence.hpp @@ -0,0 +1,17 @@ +#pragma once +#include + +using json = nlohmann::json; + +class ImageSequence { +public: + ImageSequence() = default; + ImageSequence(std::string filename, int n_images); + ImageSequence(json imagesequence_data); + json to_json() const; +protected: + int n_images_ {}; + std::string filename_ {}; + std::vector single_file_indices_{}; + json imagesequence_data_ {}; // For propagating additional metadata during serialization/deserialization. +}; \ No newline at end of file diff --git a/include/dx2/imageset.hpp b/include/dx2/imageset.hpp deleted file mode 100644 index 00cbe1e..0000000 --- a/include/dx2/imageset.hpp +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once -#include - -using Eigen::Vector3d; -using json = nlohmann::json; - -class ImageSequence { -public: - ImageSequence() = default; - ImageSequence(std::string filename, int n_images); - json to_json() const; -protected: - int n_images_ {}; - std::string filename_ {}; - std::vector single_file_indices_{}; -}; - -ImageSequence::ImageSequence(std::string filename, int n_images) : filename_(filename), n_images_(n_images) { - single_file_indices_.reserve(n_images_); - for (std::size_t i=0;i Date: Mon, 17 Nov 2025 14:32:35 +0000 Subject: [PATCH 3/4] Move ersatz_uuid function into utils, split into header and implementation. --- dx2/CMakeLists.txt | 1 + dx2/imagesequence.cxx | 31 ++++++++++------ dx2/reflection.cxx | 27 +------------- dx2/utils.cxx | 68 +++++++++++++++++++++++++++++++++++ include/dx2/experiment.hpp | 7 ++++ include/dx2/imagesequence.hpp | 3 +- include/dx2/reflection.hpp | 21 ----------- include/dx2/utils.hpp | 18 ++-------- 8 files changed, 102 insertions(+), 74 deletions(-) create mode 100644 dx2/utils.cxx diff --git a/dx2/CMakeLists.txt b/dx2/CMakeLists.txt index 877c607..bf28b2e 100644 --- a/dx2/CMakeLists.txt +++ b/dx2/CMakeLists.txt @@ -1,5 +1,6 @@ add_library( dx2 + utils.cxx reflection.cxx h5/h5read_processed.cxx h5/h5write.cxx diff --git a/dx2/imagesequence.cxx b/dx2/imagesequence.cxx index e15c7e4..33455ca 100644 --- a/dx2/imagesequence.cxx +++ b/dx2/imagesequence.cxx @@ -2,6 +2,7 @@ using json = nlohmann::json; +// Constructor for MultiImage formats e.g. h5. ImageSequence::ImageSequence(std::string filename, int n_images) : filename_(filename), n_images_(n_images) { single_file_indices_.reserve(n_images_); for (std::size_t i=0;i required_keys = {"template", "single_file_indices", "__id__"}; + std::vector required_keys = {"template", "__id__"}; for (const auto &key : required_keys) { if (imagesequence_data.find(key) == imagesequence_data.end()) { throw std::invalid_argument("Key " + key + @@ -21,16 +25,19 @@ ImageSequence::ImageSequence(json imagesequence_data) { throw std::runtime_error("Only ImageSequences are supported"); } filename_ = imagesequence_data["template"]; - json indices = imagesequence_data["single_file_indices"]; - single_file_indices_ = {}; - if (*(indices.begin()) < 0){ - throw std::runtime_error("Starting file index <0"); - } - for (json::iterator it = indices.begin(); it != indices.end(); - ++it) { - single_file_indices_.push_back(*it); + if (imagesequence_data.find("single_file_indices") != imagesequence_data.end()) { + // for non-multimage formats (e.g. non-h5), allow parsing. + json indices = imagesequence_data["single_file_indices"]; + single_file_indices_ = {}; + if (*(indices.begin()) < 0){ + throw std::runtime_error("Starting file index <0"); + } + for (json::iterator it = indices.begin(); it != indices.end(); + ++it) { + single_file_indices_.push_back(*it); + } + n_images_ = single_file_indices_.size(); } - n_images_ = single_file_indices_.size(); imagesequence_data_ = imagesequence_data; // To propagate during serialization/deserialization. } @@ -38,7 +45,9 @@ json ImageSequence::to_json() const { json imageset_data = imagesequence_data_; imageset_data["__id__"] = "ImageSequence"; imageset_data["template"] = filename_; - imageset_data["single_file_indices"] = single_file_indices_; + if (single_file_indices_.size() > 0){ // i.e. MultiImage formats (h5). + imageset_data["single_file_indices"] = single_file_indices_; + } // Set defaults and null for now. std::vector optional_keys = {"mask", "gain", "pedestal", "dx", "dy"}; for (const auto &key : optional_keys) { diff --git a/dx2/reflection.cxx b/dx2/reflection.cxx index df0cc01..369efcc 100644 --- a/dx2/reflection.cxx +++ b/dx2/reflection.cxx @@ -4,6 +4,7 @@ */ #include "dx2/reflection.hpp" +#include "dx2/utils.hpp" #include #include #include @@ -142,32 +143,6 @@ void ReflectionTable::merge_into_set(std::unordered_set &set, const std::vector &rows) const { set.insert(rows.begin(), rows.end()); } - -std::string ReflectionTable::ersatz_uuid4() const { - // Generate 16 random bytes - std::array bytes; - std::random_device rd; - std::uniform_int_distribution dist(0, 255); - for (auto &b : bytes) { - b = static_cast(dist(rd)); - } - - // Convert bytes to a single 128-bit hex string (little endian) - std::ostringstream oss; - for (auto it = bytes.rbegin(); it != bytes.rend(); ++it) { - oss << std::hex << std::setw(2) << std::setfill('0') - << static_cast(*it); - } - std::string hex = oss.str(); - - // Format as UUID: 8-4-4-4-12 - std::ostringstream uuid; - uuid << hex.substr(0, 8) << "-" << hex.substr(8, 4) << "-" - << hex.substr(12, 4) << "-" << hex.substr(16, 4) << "-" - << hex.substr(20, 12); - - return uuid.str(); -} #pragma endregion #pragma region Selection Methods diff --git a/dx2/utils.cxx b/dx2/utils.cxx new file mode 100644 index 0000000..37adb67 --- /dev/null +++ b/dx2/utils.cxx @@ -0,0 +1,68 @@ +#include "dx2/utils.hpp" +#include +#include +#include +#include +#include + +using Eigen::Vector3d; + +double angle_between_vectors_degrees(Vector3d v1, Vector3d v2) { + double l1 = v1.norm(); + double l2 = v2.norm(); + double dot = v1.dot(v2); + double normdot = dot / (l1 * l2); + if (std::abs(normdot - 1.0) < 1E-6) { + return 0.0; + } + if (std::abs(normdot + 1.0) < 1E-6) { + return 180.0; + } + double angle = std::acos(normdot) * 180.0 / M_PI; + return angle; +} + +/** + * @brief Generate a pseudo-random UUID-like identifier. + * + * This function replicates the behaviour of the Python function + * `ersatz_uuid4` from the dxtbx library. It generates a 128-bit + * random value and formats it as a UUID-style string using + * little-endian byte order, without enforcing RFC 4122 compliance. + * + * The output is a 36-character string in the format: + * `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`, where each `x` is a + * hexadecimal digit. + * + * @return A string representing the generated UUID-like identifier. + * + * @note This function does not set the version or variant bits as + * specified in RFC 4122. It is intended for internal use where + * uniqueness is sufficient, and compliance with UUID standards + * is unnecessary. + */ +std::string ersatz_uuid4() { + // Generate 16 random bytes + std::array bytes; + std::random_device rd; + std::uniform_int_distribution dist(0, 255); + for (auto &b : bytes) { + b = static_cast(dist(rd)); + } + + // Convert bytes to a single 128-bit hex string (little endian) + std::ostringstream oss; + for (auto it = bytes.rbegin(); it != bytes.rend(); ++it) { + oss << std::hex << std::setw(2) << std::setfill('0') + << static_cast(*it); + } + std::string hex = oss.str(); + + // Format as UUID: 8-4-4-4-12 + std::ostringstream uuid; + uuid << hex.substr(0, 8) << "-" << hex.substr(8, 4) << "-" + << hex.substr(12, 4) << "-" << hex.substr(16, 4) << "-" + << hex.substr(20, 12); + + return uuid.str(); +} \ No newline at end of file diff --git a/include/dx2/experiment.hpp b/include/dx2/experiment.hpp index a4e2345..70fc361 100644 --- a/include/dx2/experiment.hpp +++ b/include/dx2/experiment.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -29,6 +30,7 @@ template class Experiment { void set_goniometer(Goniometer goniometer); void set_imagesequence(ImageSequence imagesequence); void set_identifier(std::string identifier); + void generate_identifier(); protected: BeamType _beam{}; @@ -157,4 +159,9 @@ const std::string &Experiment::identifier() const { template void Experiment::set_identifier(std::string identifier) { _identifier = identifier; +} + +template +void Experiment::generate_identifier() { + _identifier = ersatz_uuid4(); } \ No newline at end of file diff --git a/include/dx2/imagesequence.hpp b/include/dx2/imagesequence.hpp index b3935df..6eea2fa 100644 --- a/include/dx2/imagesequence.hpp +++ b/include/dx2/imagesequence.hpp @@ -6,7 +6,8 @@ using json = nlohmann::json; class ImageSequence { public: ImageSequence() = default; - ImageSequence(std::string filename, int n_images); + ImageSequence(std::string filename, int n_images); // Constructor for MultiImage formats e.g. h5. + ImageSequence(std::string filename); // Constructor for non-MultiImage formats e.g. cbf. ImageSequence(json imagesequence_data); json to_json() const; protected: diff --git a/include/dx2/reflection.hpp b/include/dx2/reflection.hpp index 5563f76..4a9c468 100644 --- a/include/dx2/reflection.hpp +++ b/include/dx2/reflection.hpp @@ -316,27 +316,6 @@ class ReflectionTable { template struct is_column_predicate> : std::true_type {}; - /** - * @brief Generate a pseudo-random UUID-like identifier. - * - * This function replicates the behaviour of the Python function - * `ersatz_uuid4` from the dxtbx library. It generates a 128-bit - * random value and formats it as a UUID-style string using - * little-endian byte order, without enforcing RFC 4122 compliance. - * - * The output is a 36-character string in the format: - * `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`, where each `x` is a - * hexadecimal digit. - * - * @return A string representing the generated UUID-like identifier. - * - * @note This function does not set the version or variant bits as - * specified in RFC 4122. It is intended for internal use where - * uniqueness is sufficient, and compliance with UUID standards - * is unnecessary. - */ - std::string ersatz_uuid4() const; - public: #pragma region Constructors /// Re-exported type aliase for convenience diff --git a/include/dx2/utils.hpp b/include/dx2/utils.hpp index 65079b4..a0ea002 100644 --- a/include/dx2/utils.hpp +++ b/include/dx2/utils.hpp @@ -1,20 +1,8 @@ #pragma once #include -#include using Eigen::Vector3d; -double angle_between_vectors_degrees(Vector3d v1, Vector3d v2) { - double l1 = v1.norm(); - double l2 = v2.norm(); - double dot = v1.dot(v2); - double normdot = dot / (l1 * l2); - if (std::abs(normdot - 1.0) < 1E-6) { - return 0.0; - } - if (std::abs(normdot + 1.0) < 1E-6) { - return 180.0; - } - double angle = std::acos(normdot) * 180.0 / M_PI; - return angle; -} +double angle_between_vectors_degrees(Vector3d v1, Vector3d v2); + +std::string ersatz_uuid4(); \ No newline at end of file From 076d42565f7833ba3f34275d655bf5ec0a4a0638 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 18 Nov 2025 09:31:18 +0000 Subject: [PATCH 4/4] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- dx2/imagesequence.cxx | 95 ++++++++++++++++++----------------- dx2/utils.cxx | 38 +++++++------- include/dx2/experiment.hpp | 11 ++-- include/dx2/imagesequence.hpp | 22 ++++---- 4 files changed, 85 insertions(+), 81 deletions(-) diff --git a/dx2/imagesequence.cxx b/dx2/imagesequence.cxx index 33455ca..3205a56 100644 --- a/dx2/imagesequence.cxx +++ b/dx2/imagesequence.cxx @@ -3,63 +3,66 @@ using json = nlohmann::json; // Constructor for MultiImage formats e.g. h5. -ImageSequence::ImageSequence(std::string filename, int n_images) : filename_(filename), n_images_(n_images) { - single_file_indices_.reserve(n_images_); - for (std::size_t i=0;i required_keys = {"template", "__id__"}; - for (const auto &key : required_keys) { - if (imagesequence_data.find(key) == imagesequence_data.end()) { - throw std::invalid_argument("Key " + key + - " is missing from the input imageset JSON"); - } + std::vector required_keys = {"template", "__id__"}; + for (const auto &key : required_keys) { + if (imagesequence_data.find(key) == imagesequence_data.end()) { + throw std::invalid_argument("Key " + key + + " is missing from the input imageset JSON"); } - if (imagesequence_data["__id__"] != std::string("ImageSequence")){ - throw std::runtime_error("Only ImageSequences are supported"); + } + if (imagesequence_data["__id__"] != std::string("ImageSequence")) { + throw std::runtime_error("Only ImageSequences are supported"); + } + filename_ = imagesequence_data["template"]; + if (imagesequence_data.find("single_file_indices") != + imagesequence_data.end()) { + // for non-multimage formats (e.g. non-h5), allow parsing. + json indices = imagesequence_data["single_file_indices"]; + single_file_indices_ = {}; + if (*(indices.begin()) < 0) { + throw std::runtime_error("Starting file index <0"); } - filename_ = imagesequence_data["template"]; - if (imagesequence_data.find("single_file_indices") != imagesequence_data.end()) { - // for non-multimage formats (e.g. non-h5), allow parsing. - json indices = imagesequence_data["single_file_indices"]; - single_file_indices_ = {}; - if (*(indices.begin()) < 0){ - throw std::runtime_error("Starting file index <0"); - } - for (json::iterator it = indices.begin(); it != indices.end(); - ++it) { - single_file_indices_.push_back(*it); - } - n_images_ = single_file_indices_.size(); + for (json::iterator it = indices.begin(); it != indices.end(); ++it) { + single_file_indices_.push_back(*it); } - imagesequence_data_ = imagesequence_data; // To propagate during serialization/deserialization. + n_images_ = single_file_indices_.size(); + } + imagesequence_data_ = + imagesequence_data; // To propagate during serialization/deserialization. } json ImageSequence::to_json() const { - json imageset_data = imagesequence_data_; - imageset_data["__id__"] = "ImageSequence"; - imageset_data["template"] = filename_; - if (single_file_indices_.size() > 0){ // i.e. MultiImage formats (h5). - imageset_data["single_file_indices"] = single_file_indices_; - } - // Set defaults and null for now. - std::vector optional_keys = {"mask", "gain", "pedestal", "dx", "dy"}; - for (const auto &key : optional_keys) { - if (imagesequence_data_.find(key) == imagesequence_data_.end()) { - imageset_data[key] = nullptr; - } - } - if (imagesequence_data_.find("params") == imagesequence_data_.end()) { - json params; - params["dynamic_shadowing"] = "Auto"; - params["multi_panel"] = false; - imageset_data["params"] = params; + json imageset_data = imagesequence_data_; + imageset_data["__id__"] = "ImageSequence"; + imageset_data["template"] = filename_; + if (single_file_indices_.size() > 0) { // i.e. MultiImage formats (h5). + imageset_data["single_file_indices"] = single_file_indices_; + } + // Set defaults and null for now. + std::vector optional_keys = {"mask", "gain", "pedestal", "dx", + "dy"}; + for (const auto &key : optional_keys) { + if (imagesequence_data_.find(key) == imagesequence_data_.end()) { + imageset_data[key] = nullptr; } - return imageset_data; + } + if (imagesequence_data_.find("params") == imagesequence_data_.end()) { + json params; + params["dynamic_shadowing"] = "Auto"; + params["multi_panel"] = false; + imageset_data["params"] = params; + } + return imageset_data; } \ No newline at end of file diff --git a/dx2/utils.cxx b/dx2/utils.cxx index 37adb67..48c12f0 100644 --- a/dx2/utils.cxx +++ b/dx2/utils.cxx @@ -1,9 +1,9 @@ #include "dx2/utils.hpp" #include +#include #include #include #include -#include using Eigen::Vector3d; @@ -23,24 +23,24 @@ double angle_between_vectors_degrees(Vector3d v1, Vector3d v2) { } /** - * @brief Generate a pseudo-random UUID-like identifier. - * - * This function replicates the behaviour of the Python function - * `ersatz_uuid4` from the dxtbx library. It generates a 128-bit - * random value and formats it as a UUID-style string using - * little-endian byte order, without enforcing RFC 4122 compliance. - * - * The output is a 36-character string in the format: - * `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`, where each `x` is a - * hexadecimal digit. - * - * @return A string representing the generated UUID-like identifier. - * - * @note This function does not set the version or variant bits as - * specified in RFC 4122. It is intended for internal use where - * uniqueness is sufficient, and compliance with UUID standards - * is unnecessary. - */ + * @brief Generate a pseudo-random UUID-like identifier. + * + * This function replicates the behaviour of the Python function + * `ersatz_uuid4` from the dxtbx library. It generates a 128-bit + * random value and formats it as a UUID-style string using + * little-endian byte order, without enforcing RFC 4122 compliance. + * + * The output is a 36-character string in the format: + * `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`, where each `x` is a + * hexadecimal digit. + * + * @return A string representing the generated UUID-like identifier. + * + * @note This function does not set the version or variant bits as + * specified in RFC 4122. It is intended for internal use where + * uniqueness is sufficient, and compliance with UUID standards + * is unnecessary. + */ std::string ersatz_uuid4() { // Generate 16 random bytes std::array bytes; diff --git a/include/dx2/experiment.hpp b/include/dx2/experiment.hpp index 70fc361..8d9bd91 100644 --- a/include/dx2/experiment.hpp +++ b/include/dx2/experiment.hpp @@ -4,9 +4,9 @@ #include #include #include +#include #include #include -#include #include using Eigen::Vector3d; @@ -123,8 +123,7 @@ void Experiment::set_crystal(Crystal crystal) { _crystal = crystal; } -template -void Experiment::set_beam(BeamType beam) { +template void Experiment::set_beam(BeamType beam) { _beam = beam; } @@ -132,8 +131,7 @@ template BeamType &Experiment::beam() { return _beam; } -template -void Experiment::set_scan(Scan scan) { +template void Experiment::set_scan(Scan scan) { _scan = scan; } @@ -161,7 +159,6 @@ void Experiment::set_identifier(std::string identifier) { _identifier = identifier; } -template -void Experiment::generate_identifier() { +template void Experiment::generate_identifier() { _identifier = ersatz_uuid4(); } \ No newline at end of file diff --git a/include/dx2/imagesequence.hpp b/include/dx2/imagesequence.hpp index 6eea2fa..a386472 100644 --- a/include/dx2/imagesequence.hpp +++ b/include/dx2/imagesequence.hpp @@ -5,14 +5,18 @@ using json = nlohmann::json; class ImageSequence { public: - ImageSequence() = default; - ImageSequence(std::string filename, int n_images); // Constructor for MultiImage formats e.g. h5. - ImageSequence(std::string filename); // Constructor for non-MultiImage formats e.g. cbf. - ImageSequence(json imagesequence_data); - json to_json() const; + ImageSequence() = default; + ImageSequence(std::string filename, + int n_images); // Constructor for MultiImage formats e.g. h5. + ImageSequence( + std::string filename); // Constructor for non-MultiImage formats e.g. cbf. + ImageSequence(json imagesequence_data); + json to_json() const; + protected: - int n_images_ {}; - std::string filename_ {}; - std::vector single_file_indices_{}; - json imagesequence_data_ {}; // For propagating additional metadata during serialization/deserialization. + int n_images_{}; + std::string filename_{}; + std::vector single_file_indices_{}; + json imagesequence_data_{}; // For propagating additional metadata during + // serialization/deserialization. }; \ No newline at end of file