diff --git a/CMakeLists.txt b/CMakeLists.txt index b8cc777..165c435 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -289,6 +289,7 @@ set(PUBLICHEADERS include/aare/File.hpp include/aare/FileInterface.hpp include/aare/Frame.hpp + include/aare/geo_helpers.hpp include/aare/NDArray.hpp include/aare/NDView.hpp include/aare/NumpyFile.hpp @@ -311,6 +312,7 @@ set(SourceFiles ${CMAKE_CURRENT_SOURCE_DIR}/src/decode.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Frame.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/File.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/geo_helpers.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/NumpyFile.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/NumpyHelpers.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/PixelMap.cpp @@ -352,6 +354,7 @@ if(AARE_TESTS) ${CMAKE_CURRENT_SOURCE_DIR}/src/defs.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/RawMasterFile.test.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/NDArray.test.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/NDView.test.cpp diff --git a/include/aare/RawFile.hpp b/include/aare/RawFile.hpp index eb044e3..f744ac2 100644 --- a/include/aare/RawFile.hpp +++ b/include/aare/RawFile.hpp @@ -34,15 +34,19 @@ class RawFile : public FileInterface { size_t n_subfile_parts{}; // d0,d1...dn //TODO! move to vector of SubFile instead of pointers std::vector> subfiles; //subfiles[f0,f1...fn][d0,d1...dn] - std::vector positions; - std::vector m_module_pixel_0; + // std::vector positions; + ModuleConfig cfg{0, 0}; RawMasterFile m_master; size_t m_current_frame{}; - size_t m_rows{}; - size_t m_cols{}; + + // std::vector m_module_pixel_0; + // size_t m_rows{}; + // size_t m_cols{}; + + DetectorGeometry m_geometry; public: /** @@ -111,11 +115,12 @@ class RawFile : public FileInterface { */ static DetectorHeader read_header(const std::filesystem::path &fname); - void update_geometry_with_roi(); + // void update_geometry_with_roi(); int find_number_of_subfiles(); void open_subfiles(); void find_geometry(); }; + } // namespace aare \ No newline at end of file diff --git a/include/aare/RawMasterFile.hpp b/include/aare/RawMasterFile.hpp index 42c324e..beaeb29 100644 --- a/include/aare/RawMasterFile.hpp +++ b/include/aare/RawMasterFile.hpp @@ -62,17 +62,6 @@ class ScanParameters { }; -struct ROI{ - int64_t xmin{}; - int64_t xmax{}; - int64_t ymin{}; - int64_t ymax{}; - - int64_t height() const { return ymax - ymin; } - int64_t width() const { return xmax - xmin; } -}; - - /** * @brief Class for parsing a master file either in our .json format or the old * .raw format diff --git a/include/aare/defs.hpp b/include/aare/defs.hpp index 7466410..db1a47b 100644 --- a/include/aare/defs.hpp +++ b/include/aare/defs.hpp @@ -179,13 +179,42 @@ 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 x{}; - int y{}; + 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; +}; + +struct ROI{ + int64_t xmin{}; + int64_t xmax{}; + int64_t ymin{}; + int64_t ymax{}; + + int64_t height() const { return ymax - ymin; } + int64_t width() const { return xmax - xmin; } + }; + using dynamic_shape = std::vector; diff --git a/include/aare/geo_helpers.hpp b/include/aare/geo_helpers.hpp new file mode 100644 index 0000000..d0d5d1a --- /dev/null +++ b/include/aare/geo_helpers.hpp @@ -0,0 +1,16 @@ +#pragma once +#include "aare/defs.hpp" +#include "aare/RawMasterFile.hpp" //ROI refactor away +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/python/examples/play.py b/python/examples/play.py index 25bbe12..316c196 100644 --- a/python/examples/play.py +++ b/python/examples/play.py @@ -8,13 +8,15 @@ import numpy as np import boost_histogram as bh import time -from aare import File, ClusterFinder, VarClusterFinder, ClusterFile +from aare import RawFile -base = Path('/mnt/sls_det_storage/matterhorn_data/aare_test_data/ci/aare_test_data/clusters/') +f = RawFile('/mnt/sls_det_storage/jungfrau_data1/vadym_tests/jf12_M431/laser_scan/laserScan_pedestal_G0_master_0.json') -f = ClusterFile(base/'beam_En700eV_-40deg_300V_10us_d0_f0_100.clust') +print(f'{f.frame_number(1)}') -c = f.read_clusters(100) +for i in range(10): + header, img = f.read_frame() + print(header['frameNumber'], img.shape) # for i, frame in enumerate(f): # print(f'{i}', end='\r') diff --git a/src/RawFile.cpp b/src/RawFile.cpp index b8c49cf..ef622ee 100644 --- a/src/RawFile.cpp +++ b/src/RawFile.cpp @@ -1,6 +1,7 @@ #include "aare/RawFile.hpp" #include "aare/PixelMap.hpp" #include "aare/defs.hpp" +#include "aare/geo_helpers.hpp" #include #include @@ -21,8 +22,11 @@ RawFile::RawFile(const std::filesystem::path &fname, const std::string &mode) find_geometry(); - update_geometry_with_roi(); + if (m_master.roi()){ + m_geometry = update_geometry_with_roi(m_geometry, m_master.roi().value()); + } + open_subfiles(); } else { throw std::runtime_error(LOCATION + @@ -72,9 +76,13 @@ size_t RawFile::n_mod() const { return n_subfile_parts; } size_t RawFile::bytes_per_frame() { - return m_rows * m_cols * m_master.bitdepth() / 8; + // return m_rows * m_cols * m_master.bitdepth() / 8; + return m_geometry.pixels_x * m_geometry.pixels_y * m_master.bitdepth() / 8; +} +size_t RawFile::pixels_per_frame() { + // return m_rows * m_cols; + return m_geometry.pixels_x * m_geometry.pixels_y; } -size_t RawFile::pixels_per_frame() { return m_rows * m_cols; } DetectorType RawFile::detector_type() const { return m_master.detector_type(); } @@ -92,8 +100,8 @@ 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_rows; } -size_t RawFile::cols() const { return m_cols; } +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(); } @@ -102,11 +110,12 @@ void RawFile::open_subfiles() { for (size_t i = 0; i != n_subfiles; ++i) { auto v = std::vector(n_subfile_parts); for (size_t j = 0; j != n_subfile_parts; ++j) { - auto pos = m_module_pixel_0[j]; + auto pos = m_geometry.module_pixel_0[j]; + fmt::println("POS: {} {} {} {}", pos.origin_x, pos.origin_y, pos.width, pos.height); v[j] = new RawSubFile(m_master.data_fname(j, i), m_master.detector_type(), pos.height, pos.width, m_master.bitdepth(), - positions[j].row, positions[j].col); + pos.row_index, pos.col_index); } subfiles.push_back(v); @@ -149,112 +158,49 @@ int RawFile::find_number_of_subfiles() { RawMasterFile RawFile::master() const { return m_master; } +/** + * @brief Find the geometry of the detector by opening all the subfiles and + * reading the headers. + */ void RawFile::find_geometry() { + + //Hold the maximal row and column number found + //Later used for calculating the total number of rows and columns uint16_t r{}; uint16_t c{}; for (size_t i = 0; i < n_subfile_parts; i++) { - auto h = this->read_header(m_master.data_fname(i, 0)); + auto h = read_header(m_master.data_fname(i, 0)); r = std::max(r, h.row); c = std::max(c, h.column); - positions.push_back({h.row, h.column}); + // positions.push_back({h.row, h.column}); + ModuleGeometry g; - g.x = h.column * m_master.pixels_x(); - g.y = h.row * m_master.pixels_y(); + g.origin_x = h.column * m_master.pixels_x(); + g.origin_y = h.row * m_master.pixels_y(); + g.row_index = h.row; + g.col_index = h.column; g.width = m_master.pixels_x(); g.height = m_master.pixels_y(); - m_module_pixel_0.push_back(g); + m_geometry.module_pixel_0.push_back(g); } r++; c++; - m_rows = (r * m_master.pixels_y()); - m_cols = (c * m_master.pixels_x()); - - m_rows += static_cast((r - 1) * cfg.module_gap_row); - -#ifdef AARE_VERBOSE - fmt::print("\nRawFile::find_geometry()\n"); - for (size_t i = 0; i < m_module_pixel_0.size(); i++) { - fmt::print("Module {} at position: (r:{},c:{})\n", i, - m_module_pixel_0[i].y, m_module_pixel_0[i].x); - } - fmt::print("Image size: {}x{}\n\n", m_rows, m_cols); -#endif -} - -void RawFile::update_geometry_with_roi() { - // TODO! implement this - if (m_master.roi()) { - auto roi = m_master.roi().value(); - - // TODO! can we do this cleaner? - int pos_y = 0; - int pos_y_increment = 0; - for (size_t row = 0; row < m_master.geometry().row; row++) { - int pos_x = 0; - for (size_t col = 0; col < m_master.geometry().col; col++) { - auto &m = m_module_pixel_0[row * m_master.geometry().col + col]; - auto original_height = m.height; - auto original_width = m.width; - - // module is to the left of the roi - if (m.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.x) { - m.width -= roi.xmin - m.x; - } - if (roi.xmax < m.x + m.width) { - m.width -= m.x + original_width - roi.xmax; - } - m.x = pos_x; - pos_x += m.width; - } - - if (m.y + m.height < roi.ymin) { - m.height = 0; - } else { - if ((roi.ymin > m.y) && (roi.ymin < m.y + m.height)) { - m.height -= roi.ymin - m.y; - - } - if (roi.ymax < m.y + m.height) { - m.height -= m.y + original_height - roi.ymax; - } - m.y = pos_y; - pos_y_increment = m.height; - } - } - // increment pos_y - pos_y += pos_y_increment; - } - - m_rows = roi.height(); - m_cols = roi.width(); - } - -#ifdef AARE_VERBOSE - fmt::print("RawFile::update_geometry_with_roi()\n"); - for (const auto &m : m_module_pixel_0) { - fmt::print("Module at position: (r:{}, c:{}, h:{}, w:{})\n", m.y, m.x, - m.height, m.width); - } - fmt::print("Updated image size: {}x{}\n\n", m_rows, m_cols); - fmt::print("\n"); -#endif + m_geometry.pixels_y = (r * m_master.pixels_y()); + m_geometry.pixels_x = (c * m_master.pixels_x()); + m_geometry.modules_x = c; + m_geometry.modules_y = r; + m_geometry.pixels_y += static_cast((r - 1) * cfg.module_gap_row); } + Frame RawFile::get_frame(size_t frame_index) { - auto f = Frame(m_rows, m_cols, Dtype::from_bitdepth(m_master.bitdepth())); + 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); return f; @@ -321,10 +267,10 @@ void RawFile::get_frame_into(size_t frame_index, std::byte *frame_buffer, Detect } // This is where we start writing - auto offset = (m_module_pixel_0[part_idx].y * m_cols + - m_module_pixel_0[part_idx].x)*m_master.bitdepth()/8; + auto offset = (m_geometry.module_pixel_0[part_idx].origin_y * m_geometry.pixels_x + + m_geometry.module_pixel_0[part_idx].origin_x)*m_master.bitdepth()/8; - if (m_module_pixel_0[part_idx].x!=0) + if (m_geometry.module_pixel_0[part_idx].origin_x!=0) throw std::runtime_error(LOCATION + "Implementation error. x pos not 0."); //TODO! Risk for out of range access @@ -348,7 +294,7 @@ void RawFile::get_frame_into(size_t frame_index, std::byte *frame_buffer, Detect // level for (size_t part_idx = 0; part_idx != n_subfile_parts; ++part_idx) { - auto pos = m_module_pixel_0[part_idx]; + auto pos = m_geometry.module_pixel_0[part_idx]; auto corrected_idx = frame_indices[part_idx]; auto subfile_id = corrected_idx / m_master.max_frames_per_file(); if (subfile_id >= subfiles.size()) { @@ -364,9 +310,9 @@ void RawFile::get_frame_into(size_t frame_index, std::byte *frame_buffer, Detect for (size_t cur_row = 0; cur_row < static_cast(pos.height); cur_row++) { - auto irow = (pos.y + cur_row); - auto icol = pos.x; - auto dest = (irow * this->m_cols + icol); + auto irow = (pos.origin_y + cur_row); + auto icol = pos.origin_x; + auto dest = (irow * this->m_geometry.pixels_x + icol); dest = dest * m_master.bitdepth() / 8; memcpy(frame_buffer + dest, part_buffer + cur_row * pos.width * @@ -412,4 +358,8 @@ RawFile::~RawFile() { } } + + + + } // namespace aare \ No newline at end of file diff --git a/src/RawFile.test.cpp b/src/RawFile.test.cpp index faefd28..5f9b2e1 100644 --- a/src/RawFile.test.cpp +++ b/src/RawFile.test.cpp @@ -1,10 +1,13 @@ #include "aare/File.hpp" +#include "aare/RawMasterFile.hpp" //needed for ROI +#include "aare/RawFile.hpp" #include #include #include "test_config.hpp" + using aare::File; TEST_CASE("Read number of frames from a jungfrau raw file", "[.integration]") { @@ -148,3 +151,5 @@ TEST_CASE("Read file with unordered frames", "[.integration]") { File f(fpath); REQUIRE_THROWS((f.read_frame())); } + + diff --git a/src/RawSubFile.cpp b/src/RawSubFile.cpp index 4612747..a3bb79c 100644 --- a/src/RawSubFile.cpp +++ b/src/RawSubFile.cpp @@ -44,7 +44,7 @@ RawSubFile::RawSubFile(const std::filesystem::path &fname, void RawSubFile::seek(size_t frame_index) { if (frame_index >= n_frames) { - throw std::runtime_error("Frame number out of range"); + throw std::runtime_error(LOCATION + fmt::format("Frame index {} out of range in a file with {} frames", frame_index, n_frames)); } m_file.seekg((sizeof(DetectorHeader) + bytes_per_frame()) * frame_index); } diff --git a/src/geo_helpers.cpp b/src/geo_helpers.cpp new file mode 100644 index 0000000..e823f22 --- /dev/null +++ b/src/geo_helpers.cpp @@ -0,0 +1,71 @@ + +#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 (size_t row = 0; row < geo.modules_y; row++) { + int pos_x = 0; + for (size_t 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 new file mode 100644 index 0000000..08ee96c --- /dev/null +++ b/src/geo_helpers.test.cpp @@ -0,0 +1,230 @@ +#include "aare/File.hpp" +#include "aare/RawMasterFile.hpp" //needed for ROI +#include "aare/RawFile.hpp" + +#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