From be67bbab6baab2bd48d447acd81aaf9126909164 Mon Sep 17 00:00:00 2001 From: Alice Date: Fri, 13 Jun 2025 16:16:23 +0200 Subject: [PATCH] extended DetectorGeometry class with find_geometry, update_geometry (refactoring) --- CMakeLists.txt | 6 +- include/aare/DetectorGeometry.hpp | 81 +++++++++++ include/aare/RawFile.hpp | 22 +-- include/aare/defs.hpp | 29 ---- include/aare/geo_helpers.hpp | 15 -- src/DetectorGeometry.cpp | 152 ++++++++++++++++++++ src/DetectorGeometry.test.cpp | 194 +++++++++++++++++++++++++ src/RawFile.cpp | 130 +++++++---------- src/RawFile.test.cpp | 93 ++++++------ src/geo_helpers.cpp | 72 ---------- src/geo_helpers.test.cpp | 228 ------------------------------ 11 files changed, 526 insertions(+), 496 deletions(-) create mode 100644 include/aare/DetectorGeometry.hpp delete mode 100644 include/aare/geo_helpers.hpp create mode 100644 src/DetectorGeometry.cpp create mode 100644 src/DetectorGeometry.test.cpp delete mode 100644 src/geo_helpers.cpp delete mode 100644 src/geo_helpers.test.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index f0bd5d7..e08768b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -361,7 +361,7 @@ set(PUBLICHEADERS include/aare/FilePtr.hpp include/aare/Frame.hpp include/aare/GainMap.hpp - include/aare/geo_helpers.hpp + include/aare/DetectorGeometry.hpp include/aare/JungfrauDataFile.hpp include/aare/NDArray.hpp include/aare/NDView.hpp @@ -386,7 +386,7 @@ set(SourceFiles ${CMAKE_CURRENT_SOURCE_DIR}/src/File.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/FilePtr.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Fit.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/geo_helpers.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/DetectorGeometry.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/JungfrauDataFile.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/NumpyFile.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/NumpyHelpers.cpp @@ -441,7 +441,7 @@ if(AARE_TESTS) ${CMAKE_CURRENT_SOURCE_DIR}/src/decode.test.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Dtype.test.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Frame.test.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/geo_helpers.test.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/DetectorGeometry.test.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/RawMasterFile.test.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/NDArray.test.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/NDView.test.cpp diff --git a/include/aare/DetectorGeometry.hpp b/include/aare/DetectorGeometry.hpp new file mode 100644 index 0000000..0511319 --- /dev/null +++ b/include/aare/DetectorGeometry.hpp @@ -0,0 +1,81 @@ +#pragma once +#include "aare/RawMasterFile.hpp" //ROI refactor away +#include "aare/defs.hpp" +namespace aare { + +struct ModuleConfig { + int module_gap_row{}; + int module_gap_col{}; + + bool operator==(const ModuleConfig &other) const { + if (module_gap_col != other.module_gap_col) + return false; + if (module_gap_row != other.module_gap_row) + return false; + return true; + } +}; + +/** + * @brief Class to hold the geometry of a module. Where pixel 0 is located and + * the size of the module + */ +struct ModuleGeometry { + int origin_x{}; + int origin_y{}; + int height{}; + int width{}; + int row_index{}; + int col_index{}; +}; + +/** + * @brief Class to hold the geometry of a detector. Number of modules, their + * size and where pixel 0 for each module is located + */ +class DetectorGeometry { + public: + DetectorGeometry(const xy &geometry, const ssize_t module_pixels_x, + const ssize_t module_pixels_y, + const xy udp_interfaces_per_module = xy{1, 1}, + const bool quad = false); + + ~DetectorGeometry() = default; + + /** + * @brief Update the detector geometry given a region of interest + * + * @param roi + * @return DetectorGeometry + */ + void update_geometry_with_roi(ROI roi); + + size_t n_modules() const; + + size_t n_modules_in_roi() const; + + size_t pixels_x() const; + size_t pixels_y() const; + + size_t modules_x() const; + size_t modules_y() const; + + const std::vector &get_modules_in_roi() const; + + ssize_t get_modules_in_roi(const size_t index) const; + + const std::vector &get_module_geometries() const; + + const ModuleGeometry &get_module_geometries(const size_t index) const; + + private: + size_t m_modules_x{}; + size_t m_modules_y{}; + size_t m_pixels_x{}; + size_t m_pixels_y{}; + static constexpr ModuleConfig cfg{0, 0}; + std::vector module_geometries{}; + std::vector modules_in_roi{}; +}; + +} // namespace aare \ No newline at end of file diff --git a/include/aare/RawFile.hpp b/include/aare/RawFile.hpp index d48dc9b..67390fa 100644 --- a/include/aare/RawFile.hpp +++ b/include/aare/RawFile.hpp @@ -1,4 +1,5 @@ #pragma once +#include "aare/DetectorGeometry.hpp" #include "aare/FileInterface.hpp" #include "aare/Frame.hpp" #include "aare/NDArray.hpp" //for pixel map @@ -13,18 +14,6 @@ namespace aare { -struct ModuleConfig { - int module_gap_row{}; - int module_gap_col{}; - - bool operator==(const ModuleConfig &other) const { - if (module_gap_col != other.module_gap_col) - return false; - if (module_gap_row != other.module_gap_row) - return false; - return true; - } -}; #ifdef AARE_TESTS TEST_CASE_PRIVATE_FWD(check_find_geometry) // forward declaration TEST_CASE_PRIVATE_FWD(open_multi_module_file_with_roi) @@ -43,13 +32,11 @@ class RawFile : public FileInterface { FRIEND_TEST(open_multi_module_file_with_roi) #endif std::vector> m_subfiles; - ModuleConfig cfg{0, 0}; + RawMasterFile m_master; size_t m_current_frame{}; size_t m_current_subfile{}; - std::vector m_modules_in_roi{}; - DetectorGeometry m_geometry; public: @@ -84,7 +71,6 @@ class RawFile : public FileInterface { size_t cols() const override; size_t bitdepth() const override; xy geometry(); - size_t n_modules() const; RawMasterFile master() const; @@ -115,10 +101,6 @@ class RawFile : public FileInterface { Frame get_frame(size_t frame_index); void open_subfiles(); - - size_t n_modules_in_roi() const; - - void find_geometry(); }; } // namespace aare \ No newline at end of file diff --git a/include/aare/defs.hpp b/include/aare/defs.hpp index 71d8c49..9bb8cfa 100644 --- a/include/aare/defs.hpp +++ b/include/aare/defs.hpp @@ -174,35 +174,6 @@ template struct t_xy { }; using xy = t_xy; -/** - * @brief Class to hold the geometry of a module. Where pixel 0 is located and - * the size of the module - */ -struct ModuleGeometry { - int origin_x{}; - int origin_y{}; - int height{}; - int width{}; - int row_index{}; - int col_index{}; -}; - -/** - * @brief Class to hold the geometry of a detector. Number of modules, their - * size and where pixel 0 for each module is located - */ -struct DetectorGeometry { - int modules_x{}; - int modules_y{}; - int pixels_x{}; - int pixels_y{}; - int module_gap_row{}; - int module_gap_col{}; - std::vector module_pixel_0; - - auto size() const { return module_pixel_0.size(); } -}; - struct ROI { ssize_t xmin{}; ssize_t xmax{}; diff --git a/include/aare/geo_helpers.hpp b/include/aare/geo_helpers.hpp deleted file mode 100644 index c6454a5..0000000 --- a/include/aare/geo_helpers.hpp +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once -#include "aare/RawMasterFile.hpp" //ROI refactor away -#include "aare/defs.hpp" -namespace aare { - -/** - * @brief Update the detector geometry given a region of interest - * - * @param geo - * @param roi - * @return DetectorGeometry - */ -DetectorGeometry update_geometry_with_roi(DetectorGeometry geo, ROI roi); - -} // namespace aare \ No newline at end of file diff --git a/src/DetectorGeometry.cpp b/src/DetectorGeometry.cpp new file mode 100644 index 0000000..c7f0125 --- /dev/null +++ b/src/DetectorGeometry.cpp @@ -0,0 +1,152 @@ + +#include "aare/DetectorGeometry.hpp" +#include "fmt/core.h" +#include +#include + +namespace aare { + +DetectorGeometry::DetectorGeometry(const xy &geometry, + const ssize_t module_pixels_x, + const ssize_t module_pixels_y, + const xy udp_interfaces_per_module, + const bool quad) { + + size_t num_modules = geometry.col * geometry.row; + module_geometries.reserve(num_modules); + for (size_t col = 0; col < geometry.col; + col += udp_interfaces_per_module.col) + for (size_t row = 0; row < geometry.row; + row += udp_interfaces_per_module.row) { + for (size_t port_row = 0; port_row < udp_interfaces_per_module.row; + ++port_row) + for (size_t port_col = 0; + port_col < udp_interfaces_per_module.col; ++port_col) { + ModuleGeometry g; + g.origin_x = (col + port_col) * module_pixels_x; + g.origin_y = (row + port_row) * + module_pixels_y; // TODO: quad doesnt seem + // to have an effect + g.row_index = + quad ? (row + port_row + 1) % 2 : (row + port_row); + g.col_index = col + port_col; + g.width = module_pixels_x; + g.height = module_pixels_y; + module_geometries.push_back(g); + } + } + + m_pixels_y = (geometry.row * module_pixels_y); + m_pixels_x = (geometry.col * module_pixels_x); + m_modules_x = geometry.col; + m_modules_y = geometry.row; + m_pixels_y += static_cast((geometry.row - 1) * cfg.module_gap_row); + + modules_in_roi.resize(num_modules); + std::iota(modules_in_roi.begin(), modules_in_roi.end(), 0); +} + +size_t DetectorGeometry::n_modules() const { return m_modules_x * m_modules_y; } + +size_t DetectorGeometry::n_modules_in_roi() const { + return modules_in_roi.size(); +}; + +size_t DetectorGeometry::pixels_x() const { return m_pixels_x; } +size_t DetectorGeometry::pixels_y() const { return m_pixels_y; } + +size_t DetectorGeometry::modules_x() const { return m_modules_x; }; +size_t DetectorGeometry::modules_y() const { return m_modules_y; }; + +const std::vector &DetectorGeometry::get_modules_in_roi() const { + return modules_in_roi; +} + +ssize_t DetectorGeometry::get_modules_in_roi(const size_t index) const { + return modules_in_roi[index]; +} + +const std::vector & +DetectorGeometry::get_module_geometries() const { + return module_geometries; +} + +const ModuleGeometry & +DetectorGeometry::get_module_geometries(const size_t index) const { + return module_geometries[index]; +} + +void DetectorGeometry::update_geometry_with_roi(ROI roi) { +#ifdef AARE_VERBOSE + fmt::println("update_geometry_with_roi() called with ROI: {} {} {} {}", + roi.xmin, roi.xmax, roi.ymin, roi.ymax); + fmt::println("Geometry: {} {} {} {} {} {}", m_modules_x, m_modules_y, + m_pixels_x, m_pixels_y, cfg.module_gap_row, + cfg.module_gap_col); + +#endif + + modules_in_roi.clear(); + modules_in_roi.reserve(m_modules_x * m_modules_y); + int pos_y = 0; + int pos_y_increment = 0; + for (size_t row = 0; row < m_modules_y; row++) { + int pos_x = 0; + for (size_t col = 0; col < m_modules_x; col++) { + auto &m = module_geometries[row * m_modules_x + col]; + + auto original_height = m.height; + auto original_width = m.width; + + // module is to the left of the roi + if (m.origin_x + m.width < roi.xmin) { + m.width = 0; + + // roi is in module + } else { + // here we only arrive when the roi is in or to the left of + // the module + if (roi.xmin > m.origin_x) { + m.width -= roi.xmin - m.origin_x; + } + if (roi.xmax < m.origin_x + original_width) { + m.width -= m.origin_x + original_width - roi.xmax; + } + m.origin_x = pos_x; + pos_x += m.width; + } + + if (m.origin_y + m.height < roi.ymin) { + m.height = 0; + } else { + if ((roi.ymin > m.origin_y) && + (roi.ymin < m.origin_y + m.height)) { + m.height -= roi.ymin - m.origin_y; + } + if (roi.ymax < m.origin_y + original_height) { + m.height -= m.origin_y + original_height - roi.ymax; + } + m.origin_y = pos_y; + pos_y_increment = m.height; + } + + if (m.height != 0 && m.width != 0) { + modules_in_roi.push_back(row * m_modules_x + col); + } + +#ifdef AARE_VERBOSE + fmt::println("Module {} {} {} {}", m.origin_x, m.origin_y, m.width, + m.height); +#endif + } + // increment pos_y + pos_y += pos_y_increment; + } + + // m_rows = roi.height(); + // m_cols = roi.width(); + m_pixels_x = roi.width(); + m_pixels_y = roi.height(); +} + +} // namespace aare \ No newline at end of file diff --git a/src/DetectorGeometry.test.cpp b/src/DetectorGeometry.test.cpp new file mode 100644 index 0000000..1424f0a --- /dev/null +++ b/src/DetectorGeometry.test.cpp @@ -0,0 +1,194 @@ +#include "aare/File.hpp" +#include "aare/RawFile.hpp" +#include "aare/RawMasterFile.hpp" //needed for ROI + +#include +#include + +#include "aare/DetectorGeometry.hpp" +#include "test_config.hpp" + +TEST_CASE("Simple ROIs on one module") { + // DetectorGeometry update_geometry_with_roi(DetectorGeometry geo, aare::ROI + // roi) + aare::DetectorGeometry geo(aare::xy{1, 1}, 1024, 512); + + REQUIRE(geo.get_module_geometries(0).origin_x == 0); + REQUIRE(geo.get_module_geometries(0).origin_y == 0); + REQUIRE(geo.get_module_geometries(0).width == 1024); + REQUIRE(geo.get_module_geometries(0).height == 512); + + SECTION("ROI is the whole module") { + aare::ROI roi; + roi.xmin = 0; + roi.xmax = 1024; + roi.ymin = 0; + roi.ymax = 512; + geo.update_geometry_with_roi(roi); + + REQUIRE(geo.pixels_x() == 1024); + REQUIRE(geo.pixels_y() == 512); + REQUIRE(geo.modules_x() == 1); + REQUIRE(geo.modules_y() == 1); + REQUIRE(geo.get_module_geometries(0).height == 512); + REQUIRE(geo.get_module_geometries(0).width == 1024); + } + SECTION("ROI is the top left corner of the module") { + aare::ROI roi; + roi.xmin = 100; + roi.xmax = 200; + roi.ymin = 150; + roi.ymax = 200; + geo.update_geometry_with_roi(roi); + + REQUIRE(geo.pixels_x() == 100); + REQUIRE(geo.pixels_y() == 50); + REQUIRE(geo.modules_x() == 1); + REQUIRE(geo.modules_y() == 1); + REQUIRE(geo.get_module_geometries(0).height == 50); + REQUIRE(geo.get_module_geometries(0).width == 100); + } + + SECTION("ROI is a small square") { + aare::ROI roi; + roi.xmin = 1000; + roi.xmax = 1010; + roi.ymin = 500; + roi.ymax = 510; + geo.update_geometry_with_roi(roi); + + REQUIRE(geo.pixels_x() == 10); + REQUIRE(geo.pixels_y() == 10); + REQUIRE(geo.modules_x() == 1); + REQUIRE(geo.modules_y() == 1); + REQUIRE(geo.get_module_geometries(0).height == 10); + REQUIRE(geo.get_module_geometries(0).width == 10); + } + SECTION("ROI is a few columns") { + aare::ROI roi; + roi.xmin = 750; + roi.xmax = 800; + roi.ymin = 0; + roi.ymax = 512; + geo.update_geometry_with_roi(roi); + + REQUIRE(geo.pixels_x() == 50); + REQUIRE(geo.pixels_y() == 512); + REQUIRE(geo.modules_x() == 1); + REQUIRE(geo.modules_y() == 1); + REQUIRE(geo.get_module_geometries(0).height == 512); + REQUIRE(geo.get_module_geometries(0).width == 50); + } +} + +TEST_CASE("Two modules side by side") { + // DetectorGeometry update_geometry_with_roi(DetectorGeometry geo, aare::ROI + // roi) + aare::DetectorGeometry geo(aare::xy{1, 2}, 1024, 512); + + REQUIRE(geo.get_module_geometries(0).origin_x == 0); + REQUIRE(geo.get_module_geometries(0).origin_y == 0); + REQUIRE(geo.get_module_geometries(0).width == 1024); + REQUIRE(geo.get_module_geometries(0).height == 512); + REQUIRE(geo.get_module_geometries(1).origin_x == 1024); + REQUIRE(geo.get_module_geometries(1).origin_y == 0); + + SECTION("ROI is the whole image") { + aare::ROI roi; + roi.xmin = 0; + roi.xmax = 2048; + roi.ymin = 0; + roi.ymax = 512; + geo.update_geometry_with_roi(roi); + + REQUIRE(geo.pixels_x() == 2048); + REQUIRE(geo.pixels_y() == 512); + REQUIRE(geo.modules_x() == 2); + REQUIRE(geo.modules_y() == 1); + } + SECTION("rectangle on both modules") { + aare::ROI roi; + roi.xmin = 800; + roi.xmax = 1300; + roi.ymin = 200; + roi.ymax = 499; + geo.update_geometry_with_roi(roi); + + REQUIRE(geo.pixels_x() == 500); + REQUIRE(geo.pixels_y() == 299); + REQUIRE(geo.modules_x() == 2); + REQUIRE(geo.modules_y() == 1); + REQUIRE(geo.get_module_geometries(0).height == 299); + REQUIRE(geo.get_module_geometries(0).width == 224); + REQUIRE(geo.get_module_geometries(1).height == 299); + REQUIRE(geo.get_module_geometries(1).width == 276); + } +} + +TEST_CASE("Three modules side by side") { + // DetectorGeometry update_geometry_with_roi(DetectorGeometry geo, aare::ROI + // roi) + aare::DetectorGeometry geo(aare::xy{1, 3}, 1024, 512); + aare::ROI roi; + roi.xmin = 700; + roi.xmax = 2500; + roi.ymin = 0; + roi.ymax = 123; + + REQUIRE(geo.get_module_geometries(0).origin_x == 0); + REQUIRE(geo.get_module_geometries(0).origin_y == 0); + REQUIRE(geo.get_module_geometries(0).width == 1024); + REQUIRE(geo.get_module_geometries(0).height == 512); + REQUIRE(geo.get_module_geometries(1).origin_x == 1024); + REQUIRE(geo.get_module_geometries(2).origin_x == 2048); + + geo.update_geometry_with_roi(roi); + + REQUIRE(geo.pixels_x() == 1800); + REQUIRE(geo.pixels_y() == 123); + REQUIRE(geo.modules_x() == 3); + REQUIRE(geo.modules_y() == 1); + REQUIRE(geo.get_module_geometries(0).height == 123); + REQUIRE(geo.get_module_geometries(0).width == 324); + REQUIRE(geo.get_module_geometries(1).height == 123); + REQUIRE(geo.get_module_geometries(1).width == 1024); + REQUIRE(geo.get_module_geometries(2).height == 123); + REQUIRE(geo.get_module_geometries(2).width == 452); +} + +TEST_CASE("Four modules as a square") { + // DetectorGeometry update_geometry_with_roi(DetectorGeometry geo, aare::ROI + // roi) + aare::DetectorGeometry geo(aare::xy{2, 2}, 1024, 512, aare::xy{1, 2}); + aare::ROI roi; + roi.xmin = 500; + roi.xmax = 2000; + roi.ymin = 500; + roi.ymax = 600; + + REQUIRE(geo.get_module_geometries(0).origin_x == 0); + REQUIRE(geo.get_module_geometries(0).origin_y == 0); + REQUIRE(geo.get_module_geometries(0).width == 1024); + REQUIRE(geo.get_module_geometries(0).height == 512); + REQUIRE(geo.get_module_geometries(1).origin_x == 1024); + REQUIRE(geo.get_module_geometries(1).origin_y == 0); + REQUIRE(geo.get_module_geometries(2).origin_x == 0); + REQUIRE(geo.get_module_geometries(2).origin_y == 512); + REQUIRE(geo.get_module_geometries(3).origin_x == 1024); + REQUIRE(geo.get_module_geometries(3).origin_y == 512); + + geo.update_geometry_with_roi(roi); + + REQUIRE(geo.pixels_x() == 1500); + REQUIRE(geo.pixels_y() == 100); + REQUIRE(geo.modules_x() == 2); + REQUIRE(geo.modules_y() == 2); + REQUIRE(geo.get_module_geometries(0).height == 12); + REQUIRE(geo.get_module_geometries(0).width == 524); + REQUIRE(geo.get_module_geometries(1).height == 12); + REQUIRE(geo.get_module_geometries(1).width == 976); + REQUIRE(geo.get_module_geometries(2).height == 88); + REQUIRE(geo.get_module_geometries(2).width == 524); + REQUIRE(geo.get_module_geometries(3).height == 88); + REQUIRE(geo.get_module_geometries(3).width == 976); +} \ No newline at end of file diff --git a/src/RawFile.cpp b/src/RawFile.cpp index 23d653b..2c46a90 100644 --- a/src/RawFile.cpp +++ b/src/RawFile.cpp @@ -1,8 +1,8 @@ #include "aare/RawFile.hpp" +#include "aare/DetectorGeometry.hpp" #include "aare/PixelMap.hpp" #include "aare/algorithm.hpp" #include "aare/defs.hpp" -#include "aare/geo_helpers.hpp" #include "aare/logger.hpp" #include @@ -13,26 +13,16 @@ using json = nlohmann::json; namespace aare { RawFile::RawFile(const std::filesystem::path &fname, const std::string &mode) - : m_master(fname) { + : m_master(fname), + m_geometry(m_master.geometry(), m_master.pixels_x(), m_master.pixels_y(), + m_master.udp_interfaces_per_module(), m_master.quad()) { m_mode = mode; if (mode == "r") { - find_geometry(); if (m_master.roi()) { - m_geometry = - update_geometry_with_roi(m_geometry, m_master.roi().value()); - m_modules_in_roi.reserve(n_modules()); - for (size_t module_index = 0; module_index < n_modules(); - ++module_index) { - if (m_geometry.module_pixel_0[module_index].width != 0 && - m_geometry.module_pixel_0[module_index].height != 0) - m_modules_in_roi.push_back(module_index); - } - } else { - m_modules_in_roi.resize(n_modules()); - std::iota(m_modules_in_roi.begin(), m_modules_in_roi.end(), 0); + m_geometry.update_geometry_with_roi(m_master.roi().value()); + open_subfiles(); } - open_subfiles(); } else { throw std::runtime_error(LOCATION + " Unsupported mode. Can only read RawFiles."); @@ -72,28 +62,30 @@ void RawFile::read_into(std::byte *image_buf, size_t n_frames, this->get_frame_into(m_current_frame++, image_buf, header); image_buf += bytes_per_frame(); if (header) - header += n_modules(); + header += m_geometry.n_modules(); } } -size_t RawFile::n_modules() const { return m_master.n_modules(); } +// size_t RawFile::n_modules() const { return m_master.n_modules(); } -size_t RawFile::n_modules_in_roi() const { return m_modules_in_roi.size(); } +// size_t RawFile::n_modules_in_roi() const { return +// m_modules_in_roi.size(); } size_t RawFile::bytes_per_frame() { - return m_geometry.pixels_x * m_geometry.pixels_y * m_master.bitdepth() / + return m_geometry.pixels_x() * m_geometry.pixels_y() * m_master.bitdepth() / bits_per_byte; } size_t RawFile::pixels_per_frame() { // return m_rows * m_cols; - return m_geometry.pixels_x * m_geometry.pixels_y; + return m_geometry.pixels_x() * m_geometry.pixels_y(); } DetectorType RawFile::detector_type() const { return m_master.detector_type(); } void RawFile::seek(size_t frame_index) { // check if the frame number is greater than the total frames - // if frame_number == total_frames, then the next read will throw an error + // if frame_number == total_frames, then the next read will throw an + // error if (frame_index > total_frames()) { throw std::runtime_error( fmt::format("frame number {} is greater than total frames {}", @@ -105,15 +97,15 @@ void RawFile::seek(size_t frame_index) { size_t RawFile::tell() { return m_current_frame; } size_t RawFile::total_frames() const { return m_master.frames_in_file(); } -size_t RawFile::rows() const { return m_geometry.pixels_y; } -size_t RawFile::cols() const { return m_geometry.pixels_x; } +size_t RawFile::rows() const { return m_geometry.pixels_y(); } +size_t RawFile::cols() const { return m_geometry.pixels_x(); } size_t RawFile::bitdepth() const { return m_master.bitdepth(); } xy RawFile::geometry() { return m_master.geometry(); } void RawFile::open_subfiles() { if (m_mode == "r") - for (size_t i : m_modules_in_roi) { - auto pos = m_geometry.module_pixel_0[i]; + for (size_t i : m_geometry.get_modules_in_roi()) { + auto pos = m_geometry.get_module_geometries(i); m_subfiles.emplace_back(std::make_unique( m_master.data_fname(i, 0), m_master.detector_type(), pos.height, pos.width, m_master.bitdepth(), pos.row_index, pos.col_index)); @@ -143,46 +135,8 @@ DetectorHeader RawFile::read_header(const std::filesystem::path &fname) { RawMasterFile RawFile::master() const { return m_master; } -/** - * @brief Find the geometry of the detector - */ -void RawFile::find_geometry() { - - m_geometry.module_pixel_0.reserve(n_modules()); - for (size_t col = 0; col < m_master.geometry().col; - col += m_master.udp_interfaces_per_module().col) - for (size_t row = 0; row < m_master.geometry().row; - row += m_master.udp_interfaces_per_module().row) { - for (size_t port_row = 0; - port_row < m_master.udp_interfaces_per_module().row; - ++port_row) - for (size_t port_col = 0; - port_col < m_master.udp_interfaces_per_module().col; - ++port_col) { - ModuleGeometry g; - g.origin_x = (col + port_col) * m_master.pixels_x(); - g.origin_y = (row + port_row) * - m_master.pixels_y(); // TODO: quad doesnt seem - // to have an effect - g.row_index = m_master.quad() ? (row + port_row + 1) % 2 - : (row + port_row); - g.col_index = col + port_col; - g.width = m_master.pixels_x(); - g.height = m_master.pixels_y(); - m_geometry.module_pixel_0.push_back(g); - } - } - - m_geometry.pixels_y = (m_master.geometry().row * m_master.pixels_y()); - m_geometry.pixels_x = (m_master.geometry().col * m_master.pixels_x()); - m_geometry.modules_x = m_master.geometry().col; - m_geometry.modules_y = m_master.geometry().row; - m_geometry.pixels_y += - static_cast((m_master.geometry().row - 1) * cfg.module_gap_row); -} - Frame RawFile::get_frame(size_t frame_index) { - auto f = Frame(m_geometry.pixels_y, m_geometry.pixels_x, + auto f = Frame(m_geometry.pixels_y(), m_geometry.pixels_x(), Dtype::from_bitdepth(m_master.bitdepth())); std::byte *frame_buffer = f.data(); get_frame_into(frame_index, frame_buffer); @@ -197,13 +151,15 @@ void RawFile::get_frame_into(size_t frame_index, std::byte *frame_buffer, if (frame_index >= total_frames()) { throw std::runtime_error(LOCATION + "Frame number out of range"); } - std::vector frame_numbers(n_modules_in_roi()); - std::vector frame_indices(n_modules_in_roi(), frame_index); + std::vector frame_numbers(m_geometry.n_modules_in_roi()); + std::vector frame_indices(m_geometry.n_modules_in_roi(), + frame_index); // sync the frame numbers - if (n_modules() != 1) { // if we have more than one module - for (size_t part_idx = 0; part_idx != n_modules_in_roi(); ++part_idx) { + if (m_geometry.n_modules() != 1) { // if we have more than one module + for (size_t part_idx = 0; part_idx != m_geometry.n_modules_in_roi(); + ++part_idx) { frame_numbers[part_idx] = m_subfiles[part_idx]->frame_number(frame_index); } @@ -233,24 +189,32 @@ void RawFile::get_frame_into(size_t frame_index, std::byte *frame_buffer, if (m_master.geometry().col == 1) { // get the part from each subfile and copy it to the frame - for (size_t part_idx = 0; part_idx != n_modules_in_roi(); ++part_idx) { + for (size_t part_idx = 0; part_idx != m_geometry.n_modules_in_roi(); + ++part_idx) { auto corrected_idx = frame_indices[part_idx]; // This is where we start writing - auto offset = (m_geometry.module_pixel_0[m_modules_in_roi[part_idx]] + auto offset = (m_geometry + .get_module_geometries( + m_geometry.get_modules_in_roi(part_idx)) .origin_y * - m_geometry.pixels_x + - m_geometry.module_pixel_0[m_modules_in_roi[part_idx]] + m_geometry.pixels_x() + + m_geometry + .get_module_geometries( + m_geometry.get_modules_in_roi(part_idx)) .origin_x) * m_master.bitdepth() / 8; - if (m_geometry.module_pixel_0[m_modules_in_roi[part_idx]] + if (m_geometry + .get_module_geometries( + m_geometry.get_modules_in_roi(part_idx)) .origin_x != 0) throw std::runtime_error( LOCATION + - " Implementation error. x pos not 0."); // TODO: origin can - // still change if - // roi changes + " Implementation error. x pos not 0."); // TODO: origin + // can still + // change if roi + // changes // TODO! What if the files don't match? m_subfiles[part_idx]->seek(corrected_idx); m_subfiles[part_idx]->read_into(frame_buffer + offset, header); @@ -268,11 +232,13 @@ void RawFile::get_frame_into(size_t frame_index, std::byte *frame_buffer, auto *part_buffer = new std::byte[bytes_per_part]; - // TODO! if we have many submodules we should reorder them on the module - // level + // TODO! if we have many submodules we should reorder them on the + // module level - for (size_t part_idx = 0; part_idx != n_modules_in_roi(); ++part_idx) { - auto pos = m_geometry.module_pixel_0[m_modules_in_roi[part_idx]]; + for (size_t part_idx = 0; part_idx != m_geometry.n_modules_in_roi(); + ++part_idx) { + auto pos = m_geometry.get_module_geometries( + m_geometry.get_modules_in_roi(part_idx)); auto corrected_idx = frame_indices[part_idx]; m_subfiles[part_idx]->seek(corrected_idx); @@ -285,7 +251,7 @@ void RawFile::get_frame_into(size_t frame_index, std::byte *frame_buffer, auto irow = (pos.origin_y + cur_row); auto icol = pos.origin_x; - auto dest = (irow * this->m_geometry.pixels_x + icol); + auto dest = (irow * this->m_geometry.pixels_x() + icol); dest = dest * m_master.bitdepth() / 8; memcpy(frame_buffer + dest, part_buffer + diff --git a/src/RawFile.test.cpp b/src/RawFile.test.cpp index b0409de..978d011 100644 --- a/src/RawFile.test.cpp +++ b/src/RawFile.test.cpp @@ -167,44 +167,45 @@ TEST_CASE("Read multipart files", "[.integration]") { struct TestParameters { const std::string master_filename{}; const uint8_t num_ports{}; - const DetectorGeometry geometry{}; + const size_t modules_x{}; + const size_t modules_y{}; + const size_t pixels_x{}; + const size_t pixels_y{}; + std::vector module_geometries{}; }; TEST_CASE_PRIVATE(aare, check_find_geometry, "check find_geometry", "[.integration][.files][.rawfile]") { auto test_parameters = GENERATE( + TestParameters{"raw/jungfrau_2modules_version6.1.2/run_master_0.raw", 2, + 1, 2, 1024, 1024, + std::vector{ + ModuleGeometry{0, 0, 512, 1024, 0, 0}, + ModuleGeometry{0, 512, 512, 1024, 0, 1}}}, TestParameters{ - "raw/jungfrau_2modules_version6.1.2/run_master_0.raw", 2, - DetectorGeometry{1, 2, 1024, 1024, 0, 0, - std::vector{ - ModuleGeometry{0, 0, 512, 1024, 0, 0}, - ModuleGeometry{0, 512, 512, 1024, 0, 1}}}}, - TestParameters{ - "raw/eiger_1_module_version7.0.0/eiger_1mod_master_7.json", 4, - DetectorGeometry{2, 2, 1024, 512, 0, 0, - std::vector{ - ModuleGeometry{0, 0, 256, 512, 0, 0}, - ModuleGeometry{512, 0, 256, 512, 0, 1}, - ModuleGeometry{0, 256, 256, 512, 1, 0}, - ModuleGeometry{512, 256, 256, 512, 1, 1}}}}, + "raw/eiger_1_module_version7.0.0/eiger_1mod_master_7.json", 4, 2, 2, + 1024, 512, + std::vector{ + ModuleGeometry{0, 0, 256, 512, 0, 0}, + ModuleGeometry{512, 0, 256, 512, 0, 1}, + ModuleGeometry{0, 256, 256, 512, 1, 0}, + ModuleGeometry{512, 256, 256, 512, 1, 1}}}, - TestParameters{ - "raw/jungfrau_2modules_2interfaces/run_master_0.json", 4, - DetectorGeometry{1, 4, 1024, 1024, 0, 0, - std::vector{ - ModuleGeometry{0, 0, 256, 1024, 0, 0}, - ModuleGeometry{0, 256, 256, 1024, 1, 0}, - ModuleGeometry{0, 512, 256, 1024, 2, 0}, - ModuleGeometry{0, 768, 256, 1024, 3, 0}}}}, + TestParameters{"raw/jungfrau_2modules_2interfaces/run_master_0.json", 4, + 1, 4, 1024, 1024, + std::vector{ + ModuleGeometry{0, 0, 256, 1024, 0, 0}, + ModuleGeometry{0, 256, 256, 1024, 1, 0}, + ModuleGeometry{0, 512, 256, 1024, 2, 0}, + ModuleGeometry{0, 768, 256, 1024, 3, 0}}}, TestParameters{ "raw/eiger_quad_data/" "W13_vthreshscan_m21C_300V_800eV_vrpre3400_master_0.json", - 2, - DetectorGeometry{1, 2, 512, 512, 0, 0, - std::vector{ - ModuleGeometry{0, 0, 256, 512, 0, 0}, - ModuleGeometry{0, 256, 256, 512, 1, 0}}}}); + 2, 1, 2, 512, 512, + std::vector{ + ModuleGeometry{0, 0, 256, 512, 0, 0}, + ModuleGeometry{0, 256, 256, 512, 1, 0}}}); auto fpath = test_data_path() / test_parameters.master_filename; @@ -212,17 +213,15 @@ TEST_CASE_PRIVATE(aare, check_find_geometry, "check find_geometry", RawFile f(fpath, "r"); - f.m_geometry.module_pixel_0.clear(); - f.find_geometry(); - auto geometry = f.m_geometry; - CHECK(geometry.modules_x == test_parameters.geometry.modules_x); - CHECK(geometry.modules_y == test_parameters.geometry.modules_y); - CHECK(geometry.pixels_x == test_parameters.geometry.pixels_x); - CHECK(geometry.pixels_y == test_parameters.geometry.pixels_y); + CHECK(geometry.modules_x() == test_parameters.modules_x); + CHECK(geometry.modules_y() == test_parameters.modules_y); + CHECK(geometry.pixels_x() == test_parameters.pixels_x); + CHECK(geometry.pixels_y() == test_parameters.pixels_y); - REQUIRE(geometry.module_pixel_0.size() == test_parameters.num_ports); + REQUIRE(geometry.get_module_geometries().size() == + test_parameters.num_ports); // compare to data stored in header for (size_t i = 0; i < test_parameters.num_ports; ++i) { @@ -232,18 +231,18 @@ TEST_CASE_PRIVATE(aare, check_find_geometry, "check find_geometry", auto header = RawFile::read_header(subfile1_path); - CHECK(header.column == geometry.module_pixel_0[i].col_index); - CHECK(header.row == geometry.module_pixel_0[i].row_index); + CHECK(header.column == geometry.get_module_geometries(i).col_index); + CHECK(header.row == geometry.get_module_geometries(i).row_index); - CHECK(geometry.module_pixel_0[i].height == - test_parameters.geometry.module_pixel_0[i].height); - CHECK(geometry.module_pixel_0[i].width == - test_parameters.geometry.module_pixel_0[i].width); + CHECK(geometry.get_module_geometries(i).height == + test_parameters.module_geometries[i].height); + CHECK(geometry.get_module_geometries(i).width == + test_parameters.module_geometries[i].width); - CHECK(geometry.module_pixel_0[i].origin_x == - test_parameters.geometry.module_pixel_0[i].origin_x); - CHECK(geometry.module_pixel_0[i].origin_y == - test_parameters.geometry.module_pixel_0[i].origin_y); + CHECK(geometry.get_module_geometries(i).origin_x == + test_parameters.module_geometries[i].origin_x); + CHECK(geometry.get_module_geometries(i).origin_y == + test_parameters.module_geometries[i].origin_y); } } @@ -261,9 +260,9 @@ TEST_CASE_PRIVATE(aare, open_multi_module_file_with_roi, REQUIRE(f.master().roi().value().width() == 256); REQUIRE(f.master().roi().value().height() == 256); - CHECK(f.n_modules() == 2); + CHECK(f.m_geometry.n_modules() == 2); - CHECK(f.n_modules_in_roi() == 1); + CHECK(f.m_geometry.n_modules_in_roi() == 1); } } // close namespace aare diff --git a/src/geo_helpers.cpp b/src/geo_helpers.cpp deleted file mode 100644 index 96a9056..0000000 --- a/src/geo_helpers.cpp +++ /dev/null @@ -1,72 +0,0 @@ - -#include "aare/geo_helpers.hpp" -#include "fmt/core.h" - -namespace aare { - -DetectorGeometry update_geometry_with_roi(DetectorGeometry geo, aare::ROI roi) { -#ifdef AARE_VERBOSE - fmt::println("update_geometry_with_roi() called with ROI: {} {} {} {}", - roi.xmin, roi.xmax, roi.ymin, roi.ymax); - fmt::println("Geometry: {} {} {} {} {} {}", geo.modules_x, geo.modules_y, - geo.pixels_x, geo.pixels_y, geo.module_gap_row, - geo.module_gap_col); -#endif - int pos_y = 0; - int pos_y_increment = 0; - for (int row = 0; row < geo.modules_y; row++) { - int pos_x = 0; - for (int col = 0; col < geo.modules_x; col++) { - auto &m = geo.module_pixel_0[row * geo.modules_x + col]; - auto original_height = m.height; - auto original_width = m.width; - - // module is to the left of the roi - if (m.origin_x + m.width < roi.xmin) { - m.width = 0; - - // roi is in module - } else { - // here we only arrive when the roi is in or to the left of - // the module - if (roi.xmin > m.origin_x) { - m.width -= roi.xmin - m.origin_x; - } - if (roi.xmax < m.origin_x + original_width) { - m.width -= m.origin_x + original_width - roi.xmax; - } - m.origin_x = pos_x; - pos_x += m.width; - } - - if (m.origin_y + m.height < roi.ymin) { - m.height = 0; - } else { - if ((roi.ymin > m.origin_y) && - (roi.ymin < m.origin_y + m.height)) { - m.height -= roi.ymin - m.origin_y; - } - if (roi.ymax < m.origin_y + original_height) { - m.height -= m.origin_y + original_height - roi.ymax; - } - m.origin_y = pos_y; - pos_y_increment = m.height; - } -#ifdef AARE_VERBOSE - fmt::println("Module {} {} {} {}", m.origin_x, m.origin_y, m.width, - m.height); -#endif - } - // increment pos_y - pos_y += pos_y_increment; - } - - // m_rows = roi.height(); - // m_cols = roi.width(); - geo.pixels_x = roi.width(); - geo.pixels_y = roi.height(); - - return geo; -} - -} // namespace aare \ No newline at end of file diff --git a/src/geo_helpers.test.cpp b/src/geo_helpers.test.cpp deleted file mode 100644 index 48ae9cf..0000000 --- a/src/geo_helpers.test.cpp +++ /dev/null @@ -1,228 +0,0 @@ -#include "aare/File.hpp" -#include "aare/RawFile.hpp" -#include "aare/RawMasterFile.hpp" //needed for ROI - -#include -#include - -#include "aare/geo_helpers.hpp" -#include "test_config.hpp" - -TEST_CASE("Simple ROIs on one module") { - // DetectorGeometry update_geometry_with_roi(DetectorGeometry geo, aare::ROI - // roi) - aare::DetectorGeometry geo; - - aare::ModuleGeometry mod; - mod.origin_x = 0; - mod.origin_y = 0; - mod.width = 1024; - mod.height = 512; - - geo.pixels_x = 1024; - geo.pixels_y = 512; - geo.modules_x = 1; - geo.modules_y = 1; - geo.module_pixel_0.push_back(mod); - - SECTION("ROI is the whole module") { - aare::ROI roi; - roi.xmin = 0; - roi.xmax = 1024; - roi.ymin = 0; - roi.ymax = 512; - auto updated_geo = aare::update_geometry_with_roi(geo, roi); - - REQUIRE(updated_geo.pixels_x == 1024); - REQUIRE(updated_geo.pixels_y == 512); - REQUIRE(updated_geo.modules_x == 1); - REQUIRE(updated_geo.modules_y == 1); - REQUIRE(updated_geo.module_pixel_0[0].height == 512); - REQUIRE(updated_geo.module_pixel_0[0].width == 1024); - } - SECTION("ROI is the top left corner of the module") { - aare::ROI roi; - roi.xmin = 100; - roi.xmax = 200; - roi.ymin = 150; - roi.ymax = 200; - auto updated_geo = aare::update_geometry_with_roi(geo, roi); - - REQUIRE(updated_geo.pixels_x == 100); - REQUIRE(updated_geo.pixels_y == 50); - REQUIRE(updated_geo.modules_x == 1); - REQUIRE(updated_geo.modules_y == 1); - REQUIRE(updated_geo.module_pixel_0[0].height == 50); - REQUIRE(updated_geo.module_pixel_0[0].width == 100); - } - - SECTION("ROI is a small square") { - aare::ROI roi; - roi.xmin = 1000; - roi.xmax = 1010; - roi.ymin = 500; - roi.ymax = 510; - auto updated_geo = aare::update_geometry_with_roi(geo, roi); - - REQUIRE(updated_geo.pixels_x == 10); - REQUIRE(updated_geo.pixels_y == 10); - REQUIRE(updated_geo.modules_x == 1); - REQUIRE(updated_geo.modules_y == 1); - REQUIRE(updated_geo.module_pixel_0[0].height == 10); - REQUIRE(updated_geo.module_pixel_0[0].width == 10); - } - SECTION("ROI is a few columns") { - aare::ROI roi; - roi.xmin = 750; - roi.xmax = 800; - roi.ymin = 0; - roi.ymax = 512; - auto updated_geo = aare::update_geometry_with_roi(geo, roi); - - REQUIRE(updated_geo.pixels_x == 50); - REQUIRE(updated_geo.pixels_y == 512); - REQUIRE(updated_geo.modules_x == 1); - REQUIRE(updated_geo.modules_y == 1); - REQUIRE(updated_geo.module_pixel_0[0].height == 512); - REQUIRE(updated_geo.module_pixel_0[0].width == 50); - } -} - -TEST_CASE("Two modules side by side") { - // DetectorGeometry update_geometry_with_roi(DetectorGeometry geo, aare::ROI - // roi) - aare::DetectorGeometry geo; - - aare::ModuleGeometry mod; - mod.origin_x = 0; - mod.origin_y = 0; - mod.width = 1024; - mod.height = 512; - - geo.pixels_x = 2048; - geo.pixels_y = 512; - geo.modules_x = 2; - geo.modules_y = 1; - - geo.module_pixel_0.push_back(mod); - mod.origin_x = 1024; - geo.module_pixel_0.push_back(mod); - - SECTION("ROI is the whole image") { - aare::ROI roi; - roi.xmin = 0; - roi.xmax = 2048; - roi.ymin = 0; - roi.ymax = 512; - auto updated_geo = aare::update_geometry_with_roi(geo, roi); - - REQUIRE(updated_geo.pixels_x == 2048); - REQUIRE(updated_geo.pixels_y == 512); - REQUIRE(updated_geo.modules_x == 2); - REQUIRE(updated_geo.modules_y == 1); - } - SECTION("rectangle on both modules") { - aare::ROI roi; - roi.xmin = 800; - roi.xmax = 1300; - roi.ymin = 200; - roi.ymax = 499; - auto updated_geo = aare::update_geometry_with_roi(geo, roi); - - REQUIRE(updated_geo.pixels_x == 500); - REQUIRE(updated_geo.pixels_y == 299); - REQUIRE(updated_geo.modules_x == 2); - REQUIRE(updated_geo.modules_y == 1); - REQUIRE(updated_geo.module_pixel_0[0].height == 299); - REQUIRE(updated_geo.module_pixel_0[0].width == 224); - REQUIRE(updated_geo.module_pixel_0[1].height == 299); - REQUIRE(updated_geo.module_pixel_0[1].width == 276); - } -} - -TEST_CASE("Three modules side by side") { - // DetectorGeometry update_geometry_with_roi(DetectorGeometry geo, aare::ROI - // roi) - aare::DetectorGeometry geo; - aare::ROI roi; - roi.xmin = 700; - roi.xmax = 2500; - roi.ymin = 0; - roi.ymax = 123; - - aare::ModuleGeometry mod; - mod.origin_x = 0; - mod.origin_y = 0; - mod.width = 1024; - mod.height = 512; - - geo.pixels_x = 3072; - geo.pixels_y = 512; - geo.modules_x = 3; - geo.modules_y = 1; - - geo.module_pixel_0.push_back(mod); - mod.origin_x = 1024; - geo.module_pixel_0.push_back(mod); - mod.origin_x = 2048; - geo.module_pixel_0.push_back(mod); - - auto updated_geo = aare::update_geometry_with_roi(geo, roi); - - REQUIRE(updated_geo.pixels_x == 1800); - REQUIRE(updated_geo.pixels_y == 123); - REQUIRE(updated_geo.modules_x == 3); - REQUIRE(updated_geo.modules_y == 1); - REQUIRE(updated_geo.module_pixel_0[0].height == 123); - REQUIRE(updated_geo.module_pixel_0[0].width == 324); - REQUIRE(updated_geo.module_pixel_0[1].height == 123); - REQUIRE(updated_geo.module_pixel_0[1].width == 1024); - REQUIRE(updated_geo.module_pixel_0[2].height == 123); - REQUIRE(updated_geo.module_pixel_0[2].width == 452); -} - -TEST_CASE("Four modules as a square") { - // DetectorGeometry update_geometry_with_roi(DetectorGeometry geo, aare::ROI - // roi) - aare::DetectorGeometry geo; - aare::ROI roi; - roi.xmin = 500; - roi.xmax = 2000; - roi.ymin = 500; - roi.ymax = 600; - - aare::ModuleGeometry mod; - mod.origin_x = 0; - mod.origin_y = 0; - mod.width = 1024; - mod.height = 512; - - geo.pixels_x = 2048; - geo.pixels_y = 1024; - geo.modules_x = 2; - geo.modules_y = 2; - - geo.module_pixel_0.push_back(mod); - mod.origin_x = 1024; - geo.module_pixel_0.push_back(mod); - mod.origin_x = 0; - mod.origin_y = 512; - geo.module_pixel_0.push_back(mod); - mod.origin_x = 1024; - geo.module_pixel_0.push_back(mod); - - auto updated_geo = aare::update_geometry_with_roi(geo, roi); - - REQUIRE(updated_geo.pixels_x == 1500); - REQUIRE(updated_geo.pixels_y == 100); - REQUIRE(updated_geo.modules_x == 2); - REQUIRE(updated_geo.modules_y == 2); - REQUIRE(updated_geo.module_pixel_0[0].height == 12); - REQUIRE(updated_geo.module_pixel_0[0].width == 524); - REQUIRE(updated_geo.module_pixel_0[1].height == 12); - REQUIRE(updated_geo.module_pixel_0[1].width == 976); - REQUIRE(updated_geo.module_pixel_0[2].height == 88); - REQUIRE(updated_geo.module_pixel_0[2].width == 524); - REQUIRE(updated_geo.module_pixel_0[3].height == 88); - REQUIRE(updated_geo.module_pixel_0[3].width == 976); -} \ No newline at end of file