From c488c0063d1d9dfa055b757bdaeb3536af2ff60d Mon Sep 17 00:00:00 2001 From: Alice Date: Tue, 1 Sep 2026 17:08:00 +0200 Subject: [PATCH] use enum for udpporttype --- include/aare/RawMasterFile.hpp | 5 ++-- include/aare/defs.hpp | 7 ++++++ python/aare/__init__.py | 2 ++ python/src/bind_Defs.hpp | 45 ++++++++++++++++++++++++++++++++++ python/src/file.hpp | 39 ----------------------------- python/src/raw_master_file.hpp | 2 +- python/tests/test_RawFile.py | 6 +++-- src/RawFile.test.cpp | 36 ++++++++++++++++++--------- src/RawMasterFile.cpp | 39 ++++++++++++++++++----------- src/to_string.cpp | 13 ++++++++++ src/to_string.hpp | 8 ++++++ 11 files changed, 131 insertions(+), 71 deletions(-) diff --git a/include/aare/RawMasterFile.hpp b/include/aare/RawMasterFile.hpp index 79f6a425..6159991f 100644 --- a/include/aare/RawMasterFile.hpp +++ b/include/aare/RawMasterFile.hpp @@ -115,8 +115,7 @@ class RawMasterFile { std::optional> m_disabled_udp_ports{}; /// @brief udp port types - std::optional> - m_udp_port_types{}; // TODO: UDPPortType? - string_to conversion? + std::optional> m_udp_port_types{}; /// @brief ROIs defined in master file or derived from disabled UDP ports std::vector m_rois; @@ -166,7 +165,7 @@ class RawMasterFile { /// @brief Get the types of UDP ports /// @return Optional vector of UDP port types as strings (only present for /// masterfile version >= 8.1) - std::optional> udp_port_types() const; + std::optional> udp_port_types() const; /// @brief Get the indices of disabled UDP ports /// @return Optional vector of indices of disabled UDP ports (only present diff --git a/include/aare/defs.hpp b/include/aare/defs.hpp index 058399dd..19abb032 100644 --- a/include/aare/defs.hpp +++ b/include/aare/defs.hpp @@ -302,6 +302,13 @@ enum class corner : int { cBottomRight = 3 }; +enum class UDPPortPosition : uint8_t { + LEFT = 0, + RIGHT = 1, + TOP = 2, + BOTTOM = 3 +}; + enum class TimingMode { Auto, Trigger }; enum class FrameDiscardPolicy { NoDiscard, Discard, DiscardPartial }; diff --git a/python/aare/__init__.py b/python/aare/__init__.py index 84224613..8267d706 100644 --- a/python/aare/__init__.py +++ b/python/aare/__init__.py @@ -17,6 +17,8 @@ from ._aare import hitmap from ._aare import ROI from ._aare import corner +from ._aare import UDPPortPosition + # from ._aare import ClusterFinderMT, ClusterCollector, ClusterFileSink, ClusterVector_i from ._version import __version__ diff --git a/python/src/bind_Defs.hpp b/python/src/bind_Defs.hpp index f0917884..1165e5b3 100644 --- a/python/src/bind_Defs.hpp +++ b/python/src/bind_Defs.hpp @@ -27,4 +27,49 @@ void define_defs_bindings(py::module &m) { moench05.attr("nRows") = Moench05::nRows; moench05.attr("nCols") = Moench05::nCols; moench05.attr("adcNumbers") = Moench05::adcNumbers; + + py::class_(m, "ROI") + .def(py::init<>()) + .def(py::init(), py::arg("xmin"), + py::arg("xmax"), py::arg("ymin"), py::arg("ymax")) + .def_readwrite("xmin", &ROI::xmin) + .def_readwrite("xmax", &ROI::xmax) + .def_readwrite("ymin", &ROI::ymin) + .def_readwrite("ymax", &ROI::ymax) + .def("__str__", + [](const ROI &self) { + return fmt::format("ROI: xmin: {} xmax: {} ymin: {} ymax: {}", + self.xmin, self.xmax, self.ymin, self.ymax); + }) + .def("__repr__", + [](const ROI &self) { + return fmt::format( + "", self.xmin, + self.xmax, self.ymin, self.ymax); + }) + .def("__iter__", + [](const ROI &self) { + return py::make_iterator(&self.xmin, &self.ymax + 1); // NOLINT + }) + + .def("__eq__", [](const ROI &self, const ROI &other) { + return self.xmin == other.xmin && self.xmax == other.xmax && + self.ymin == other.ymin && self.ymax == other.ymax; + }); + + py::enum_(m, "DetectorType") + .value("Jungfrau", DetectorType::Jungfrau) + .value("Eiger", DetectorType::Eiger) + .value("Mythen3", DetectorType::Mythen3) + .value("Moench", DetectorType::Moench) + .value("Moench03", DetectorType::Moench03) + .value("Moench03_old", DetectorType::Moench03_old) + .value("ChipTestBoard", DetectorType::ChipTestBoard) + .value("Unknown", DetectorType::Unknown); + + py::enum_(m, "UDPPortPosition") + .value("LEFT", UDPPortPosition::LEFT) + .value("RIGHT", UDPPortPosition::RIGHT) + .value("TOP", UDPPortPosition::TOP) + .value("BOTTOM", UDPPortPosition::BOTTOM); } diff --git a/python/src/file.hpp b/python/src/file.hpp index 9c365b13..a493c910 100644 --- a/python/src/file.hpp +++ b/python/src/file.hpp @@ -28,16 +28,6 @@ using namespace ::aare; void define_file_io_bindings(py::module &m) { - py::enum_(m, "DetectorType") - .value("Jungfrau", DetectorType::Jungfrau) - .value("Eiger", DetectorType::Eiger) - .value("Mythen3", DetectorType::Mythen3) - .value("Moench", DetectorType::Moench) - .value("Moench03", DetectorType::Moench03) - .value("Moench03_old", DetectorType::Moench03_old) - .value("ChipTestBoard", DetectorType::ChipTestBoard) - .value("Unknown", DetectorType::Unknown); - PYBIND11_NUMPY_DTYPE(DetectorHeader, frameNumber, expLength, packetNumber, bunchId, timestamp, modId, row, column, reserved, debug, roundRNumber, detType, version, packetMask); @@ -171,34 +161,5 @@ void define_file_io_bindings(py::module &m) { .def_property_readonly("stop", &ScanParameters::stop) .def_property_readonly("step", &ScanParameters::step); - py::class_(m, "ROI") - .def(py::init<>()) - .def(py::init(), py::arg("xmin"), - py::arg("xmax"), py::arg("ymin"), py::arg("ymax")) - .def_readwrite("xmin", &ROI::xmin) - .def_readwrite("xmax", &ROI::xmax) - .def_readwrite("ymin", &ROI::ymin) - .def_readwrite("ymax", &ROI::ymax) - .def("__str__", - [](const ROI &self) { - return fmt::format("ROI: xmin: {} xmax: {} ymin: {} ymax: {}", - self.xmin, self.xmax, self.ymin, self.ymax); - }) - .def("__repr__", - [](const ROI &self) { - return fmt::format( - "", self.xmin, - self.xmax, self.ymin, self.ymax); - }) - .def("__iter__", - [](const ROI &self) { - return py::make_iterator(&self.xmin, &self.ymax + 1); // NOLINT - }) - - .def("__eq__", [](const ROI &self, const ROI &other) { - return self.xmin == other.xmin && self.xmax == other.xmax && - self.ymin == other.ymin && self.ymax == other.ymax; - }); - #pragma GCC diagnostic pop } \ No newline at end of file diff --git a/python/src/raw_master_file.hpp b/python/src/raw_master_file.hpp index 0feb857f..ec762335 100644 --- a/python/src/raw_master_file.hpp +++ b/python/src/raw_master_file.hpp @@ -122,7 +122,7 @@ void define_raw_master_file_bindings(py::module &m) { Returns ---------- - Optional[List[str]] + Optional[List[UDPPortPosition]] Optional vector of UDP port types as strings (only present for masterfile version >= 8.1) )") diff --git a/python/tests/test_RawFile.py b/python/tests/test_RawFile.py index fac13225..5909c04c 100644 --- a/python/tests/test_RawFile.py +++ b/python/tests/test_RawFile.py @@ -1,6 +1,6 @@ # SPDX-License-Identifier: MPL-2.0 import pytest -from aare import RawFile, ROI +from aare import RawFile, ROI, UDPPortPosition import numpy as np @pytest.mark.withdata @@ -120,6 +120,7 @@ def test_read_eiger_udp_port_disabled(test_data_path): assert(len(frame) == 2) assert frame[0].shape == (256, 512) assert frame[1].shape == (256, 1024) + assert f.master.udp_port_types == [UDPPortPosition.LEFT, UDPPortPosition.RIGHT] rois = f.master.rois assert len(rois) == 2 assert rois[0] == ROI(512, 1024, 0, 256) @@ -130,6 +131,7 @@ def test_read_eiger_udp_port_disabled(test_data_path): assert frame.shape == (256, 512) assert(f.master.disabled_udp_ports == [1]) + assert f.master.udp_port_types == [UDPPortPosition.TOP, UDPPortPosition.BOTTOM] rois = f.master.rois assert len(rois) == 1 assert rois[0] == ROI(0, 512, 256, 512) @@ -141,7 +143,7 @@ def test_read_eiger_udp_port_disabled(test_data_path): assert frame[0].shape == (512, 512) assert frame[1].shape == (512, 512) assert (f.master.disabled_udp_ports == [1, 3, 5, 7]) - + assert f.master.udp_port_types == [UDPPortPosition.LEFT, UDPPortPosition.RIGHT] rois = f.master.rois assert len(rois) == 2 assert rois[0] == ROI(0, 512, 0, 512) diff --git a/src/RawFile.test.cpp b/src/RawFile.test.cpp index 6974272a..5ad0a564 100644 --- a/src/RawFile.test.cpp +++ b/src/RawFile.test.cpp @@ -418,7 +418,8 @@ TEST_CASE("Read Jungfrau frame with disabled UDP ports", REQUIRE(f.master().disabled_udp_ports().value() == std::vector{1}); REQUIRE(f.master().udp_port_types().value() == - std::vector{"bottom", "top"}); + std::vector{UDPPortPosition::BOTTOM, + UDPPortPosition::TOP}); auto frame = f.read_frame(); REQUIRE(frame.cols() == 1024); REQUIRE(frame.rows() == 256); @@ -437,7 +438,8 @@ TEST_CASE("Read Jungfrau frame with disabled UDP ports", REQUIRE(f.master().disabled_udp_ports().value() == std::vector{0}); REQUIRE(f.master().udp_port_types().value() == - std::vector{"bottom", "top"}); + std::vector{UDPPortPosition::BOTTOM, + UDPPortPosition::TOP}); auto frame = f.read_frame(); REQUIRE(frame.cols() == 1024); REQUIRE(frame.rows() == 256); @@ -453,7 +455,8 @@ TEST_CASE("Read Jungfrau frame with disabled UDP ports", REQUIRE(f.master().disabled_udp_ports().value() == std::vector{1, 3}); REQUIRE(f.master().udp_port_types().value() == - std::vector{"bottom", "top"}); + std::vector{UDPPortPosition::BOTTOM, + UDPPortPosition::TOP}); REQUIRE_THROWS_WITH( f.read_frame(), Catch::Matchers::ContainsSubstring( @@ -481,7 +484,8 @@ TEST_CASE("Read Jungfrau frame with disabled UDP ports", REQUIRE(f.master().disabled_udp_ports().value() == std::vector{0, 3}); REQUIRE(f.master().udp_port_types().value() == - std::vector{"bottom", "top"}); + std::vector{UDPPortPosition::BOTTOM, + UDPPortPosition::TOP}); auto frame = f.read_frame(); REQUIRE(frame.cols() == 1024); REQUIRE(frame.rows() == 512); @@ -497,7 +501,8 @@ TEST_CASE("Read Jungfrau frame with disabled UDP ports", REQUIRE(f.master().disabled_udp_ports().value() == std::vector{1, 3, 4, 6}); REQUIRE(f.master().udp_port_types().value() == - std::vector{"bottom", "top"}); + std::vector{UDPPortPosition::BOTTOM, + UDPPortPosition::TOP}); REQUIRE_THROWS_WITH( f.read_frame(), Catch::Matchers::ContainsSubstring( @@ -532,7 +537,8 @@ TEST_CASE("Read Moench frame with disabled UDP ports", REQUIRE(f.master().disabled_udp_ports().value() == std::vector{1}); REQUIRE(f.master().udp_port_types().value() == - std::vector{"bottom", "top"}); + std::vector{UDPPortPosition::BOTTOM, + UDPPortPosition::TOP}); auto frame = f.read_frame(); REQUIRE(frame.cols() == 400); REQUIRE(frame.rows() == 200); @@ -550,7 +556,8 @@ TEST_CASE("Read Moench frame with disabled UDP ports", REQUIRE(f.master().disabled_udp_ports().value() == std::vector{0}); REQUIRE(f.master().udp_port_types().value() == - std::vector{"bottom", "top"}); + std::vector{UDPPortPosition::BOTTOM, + UDPPortPosition::TOP}); auto frame = f.read_frame(); REQUIRE(frame.cols() == 400); REQUIRE(frame.rows() == 200); @@ -571,7 +578,8 @@ TEST_CASE("Read Eiger frame with disabled UDP ports", REQUIRE(f.master().disabled_udp_ports().value() == std::vector{0, 2}); REQUIRE(f.master().udp_port_types().value() == - std::vector{"left", "right"}); + std::vector{UDPPortPosition::LEFT, + UDPPortPosition::RIGHT}); auto frame = f.read_frame(); REQUIRE(frame.cols() == 512); @@ -589,7 +597,8 @@ TEST_CASE("Read Eiger frame with disabled UDP ports", REQUIRE(f.master().disabled_udp_ports().value() == std::vector{1, 3}); REQUIRE(f.master().udp_port_types().value() == - std::vector{"left", "right"}); + std::vector{UDPPortPosition::LEFT, + UDPPortPosition::RIGHT}); auto frame = f.read_frame(); REQUIRE(frame.cols() == 512); REQUIRE(frame.rows() == 512); @@ -606,7 +615,8 @@ TEST_CASE("Read Eiger frame with disabled UDP ports", REQUIRE(f.master().disabled_udp_ports().value() == std::vector{1, 3, 5, 7}); REQUIRE(f.master().udp_port_types().value() == - std::vector{"left", "right"}); + std::vector{UDPPortPosition::LEFT, + UDPPortPosition::RIGHT}); REQUIRE_THROWS_WITH( f.read_frame(), Catch::Matchers::ContainsSubstring( @@ -632,7 +642,8 @@ TEST_CASE("Read Eiger frame with disabled UDP ports", REQUIRE(f.master().disabled_udp_ports().value() == std::vector{1}); REQUIRE(f.master().udp_port_types().value() == - std::vector{"top", "bottom"}); + std::vector{UDPPortPosition::TOP, + UDPPortPosition::BOTTOM}); auto frame = f.read_frame(); REQUIRE(frame.cols() == 512); REQUIRE(frame.rows() == 256); @@ -649,7 +660,8 @@ TEST_CASE("Read Eiger frame with disabled UDP ports", REQUIRE(f.master().disabled_udp_ports().value() == std::vector{0}); REQUIRE(f.master().udp_port_types().value() == - std::vector{"left", "right"}); + std::vector{UDPPortPosition::LEFT, + UDPPortPosition::RIGHT}); auto frame = f.read_rois(); REQUIRE(frame.size() == 2); REQUIRE(frame[0].cols() == 512); diff --git a/src/RawMasterFile.cpp b/src/RawMasterFile.cpp index f2abd419..12dd103c 100644 --- a/src/RawMasterFile.cpp +++ b/src/RawMasterFile.cpp @@ -120,7 +120,8 @@ RawMasterFile::RawMasterFile(const std::filesystem::path &fpath) m_udp_interfaces_per_module, m_quad); if (m_quad == 1 && m_udp_port_types.has_value()) { - m_udp_port_types.value() = {"top", "bottom"}; + m_udp_port_types.value() = {UDPPortPosition::TOP, + UDPPortPosition::BOTTOM}; } if (m_disabled_udp_ports.has_value()) { @@ -224,7 +225,8 @@ ScanParameters RawMasterFile::scan_parameters() const { return m_scan_parameters; } -std::optional> RawMasterFile::udp_port_types() const { +std::optional> +RawMasterFile::udp_port_types() const { return m_udp_port_types; } @@ -416,7 +418,8 @@ void RawMasterFile::parse_json(std::istream &is) { auto json_list_obj = j.at("UDP Ports Type"); m_udp_port_types.emplace(); for (auto &elem : json_list_obj) { - m_udp_port_types.value().push_back(elem); + m_udp_port_types.value().push_back( + string_to(elem)); } } catch (const json::out_of_range &e) { // leave the optional empty @@ -456,8 +459,11 @@ void RawMasterFile::parse_json(std::istream &is) { } else { // fill ROI with full detector size if not present in master // file - m_rois.push_back({0, static_cast(m_pixels_x), 0, - static_cast(m_pixels_y)}); + m_rois.push_back( + {0, + m_detector_layout.col * static_cast(m_pixels_x), + 0, + m_detector_layout.row * static_cast(m_pixels_y)}); } } else { auto obj = j.at("Receiver Rois"); @@ -477,8 +483,9 @@ void RawMasterFile::parse_json(std::istream &is) { } catch (const json::out_of_range &e) { // fill ROI with full detector size if not present in master file - m_rois.push_back({0, static_cast(m_pixels_x), 0, - static_cast(m_pixels_y)}); + m_rois.push_back( + {0, m_detector_layout.col * static_cast(m_pixels_x), 0, + m_detector_layout.row * static_cast(m_pixels_y)}); } if (j.contains("Counter Mask")) { @@ -668,7 +675,7 @@ void RawMasterFile::update_rois_from_disabled_udp_ports() { if (all_ports_equal && port_disabled_for_all_modules) { - if (m_udp_port_types.value()[first_port] == "left") { + if (m_udp_port_types.value()[first_port] == UDPPortPosition::LEFT) { const size_t num_rois = m_geometry.modules_x() / udp_ports_per_module; m_rois.resize(num_rois); @@ -688,7 +695,7 @@ void RawMasterFile::update_rois_from_disabled_udp_ports() { 0, static_cast(m_geometry.pixels_y())}; }); } - if (m_udp_port_types.value()[first_port] == "right") { + if (m_udp_port_types.value()[first_port] == UDPPortPosition::RIGHT) { const size_t num_rois = m_geometry.modules_x() / udp_ports_per_module; m_rois.resize(num_rois); @@ -707,7 +714,7 @@ void RawMasterFile::update_rois_from_disabled_udp_ports() { 0, static_cast(m_geometry.pixels_y())}; }); } - if (m_udp_port_types.value()[first_port] == "top") { + if (m_udp_port_types.value()[first_port] == UDPPortPosition::TOP) { size_t num_rois = m_geometry.modules_y() / udp_ports_per_module; m_rois.resize(num_rois); // assumes euclidean coordinate system with origin at bottom @@ -726,7 +733,7 @@ void RawMasterFile::update_rois_from_disabled_udp_ports() { pixels_per_module_y}; }); } - if (m_udp_port_types.value()[first_port] == "bottom") { + if (m_udp_port_types.value()[first_port] == UDPPortPosition::BOTTOM) { size_t num_rois = m_geometry.modules_y() / udp_ports_per_module; m_rois.resize(num_rois); const ssize_t pixels_per_module_y = @@ -770,12 +777,16 @@ void RawMasterFile::update_rois_from_disabled_udp_ports() { module_geometry.origin_y + module_geometry.height}); } - if (m_udp_port_types == std::vector{"left", "right"}) { + if (m_udp_port_types == + std::vector{UDPPortPosition::LEFT, + UDPPortPosition::RIGHT}) { m_rois = merge_consecutive_rois(m_rois); } else if (m_udp_port_types == - std::vector{"bottom", "top"} || + std::vector{UDPPortPosition::BOTTOM, + UDPPortPosition::TOP} || m_udp_port_types == - std::vector{"top", "bottom"}) { + std::vector{UDPPortPosition::TOP, + UDPPortPosition::BOTTOM}) { m_rois = merge_consecutive_rois(m_rois); } else { throw std::runtime_error(LOCATION + "Unsupported UDP port types"); diff --git a/src/to_string.cpp b/src/to_string.cpp index d950b13c..bac7873b 100644 --- a/src/to_string.cpp +++ b/src/to_string.cpp @@ -235,6 +235,19 @@ template <> DACIndex string_to(const std::string &arg) { "\""); } +template <> UDPPortPosition string_to(const std::string &arg) { + if (arg == "left") + return UDPPortPosition::LEFT; + if (arg == "right") + return UDPPortPosition::RIGHT; + if (arg == "top") + return UDPPortPosition::TOP; + if (arg == "bottom") + return UDPPortPosition::BOTTOM; + throw std::runtime_error("Could not decode UDPPortPosition from: \"" + arg + + "\""); +} + std::string remove_unit(std::string &str) { auto it = str.begin(); while (it != str.end()) { diff --git a/src/to_string.hpp b/src/to_string.hpp index 0bb10ada..690d82fa 100644 --- a/src/to_string.hpp +++ b/src/to_string.hpp @@ -55,6 +55,14 @@ template T string_to(const std::string &arg) { */ template <> DetectorType string_to(const std::string &arg); +/** + * @brief Convert a string to UDPPortPosition + * @param name string representation of the UDPPortPosition + * @return UDPPortPosition + * @throw runtime_error if the string does not match any UDPPortPosition + */ +template <> UDPPortPosition string_to(const std::string &arg); + /** * @brief Convert a string to TimingMode * @param mode string representation of the TimingMode