use enum for udpporttype
Build on RHEL9 / build (push) Successful in 2m31s
Build on RHEL8 / build (push) Successful in 3m16s
Run tests using data on local RHEL8 / build (push) Successful in 3m58s

This commit is contained in:
2026-09-01 17:11:02 +02:00
parent 33ee8f9143
commit c488c0063d
11 changed files with 131 additions and 71 deletions
+2 -3
View File
@@ -115,8 +115,7 @@ class RawMasterFile {
std::optional<std::vector<size_t>> m_disabled_udp_ports{};
/// @brief udp port types
std::optional<std::vector<std::string>>
m_udp_port_types{}; // TODO: UDPPortType? - string_to conversion?
std::optional<std::vector<UDPPortPosition>> m_udp_port_types{};
/// @brief ROIs defined in master file or derived from disabled UDP ports
std::vector<ROI> 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<std::vector<std::string>> udp_port_types() const;
std::optional<std::vector<UDPPortPosition>> udp_port_types() const;
/// @brief Get the indices of disabled UDP ports
/// @return Optional vector of indices of disabled UDP ports (only present
+7
View File
@@ -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 };
+2
View File
@@ -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__
+45
View File
@@ -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_<ROI>(m, "ROI")
.def(py::init<>())
.def(py::init<ssize_t, ssize_t, ssize_t, ssize_t>(), 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(
"<ROI: xmin: {} xmax: {} ymin: {} ymax: {}>", 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_<DetectorType>(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_<UDPPortPosition>(m, "UDPPortPosition")
.value("LEFT", UDPPortPosition::LEFT)
.value("RIGHT", UDPPortPosition::RIGHT)
.value("TOP", UDPPortPosition::TOP)
.value("BOTTOM", UDPPortPosition::BOTTOM);
}
-39
View File
@@ -28,16 +28,6 @@ using namespace ::aare;
void define_file_io_bindings(py::module &m) {
py::enum_<DetectorType>(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_<ROI>(m, "ROI")
.def(py::init<>())
.def(py::init<ssize_t, ssize_t, ssize_t, ssize_t>(), 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(
"<ROI: xmin: {} xmax: {} ymin: {} ymax: {}>", 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
}
+1 -1
View File
@@ -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)
)")
+4 -2
View File
@@ -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)
+24 -12
View File
@@ -418,7 +418,8 @@ TEST_CASE("Read Jungfrau frame with disabled UDP ports",
REQUIRE(f.master().disabled_udp_ports().value() ==
std::vector<size_t>{1});
REQUIRE(f.master().udp_port_types().value() ==
std::vector<std::string>{"bottom", "top"});
std::vector<UDPPortPosition>{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<size_t>{0});
REQUIRE(f.master().udp_port_types().value() ==
std::vector<std::string>{"bottom", "top"});
std::vector<UDPPortPosition>{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<size_t>{1, 3});
REQUIRE(f.master().udp_port_types().value() ==
std::vector<std::string>{"bottom", "top"});
std::vector<UDPPortPosition>{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<size_t>{0, 3});
REQUIRE(f.master().udp_port_types().value() ==
std::vector<std::string>{"bottom", "top"});
std::vector<UDPPortPosition>{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<size_t>{1, 3, 4, 6});
REQUIRE(f.master().udp_port_types().value() ==
std::vector<std::string>{"bottom", "top"});
std::vector<UDPPortPosition>{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<size_t>{1});
REQUIRE(f.master().udp_port_types().value() ==
std::vector<std::string>{"bottom", "top"});
std::vector<UDPPortPosition>{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<size_t>{0});
REQUIRE(f.master().udp_port_types().value() ==
std::vector<std::string>{"bottom", "top"});
std::vector<UDPPortPosition>{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<size_t>{0, 2});
REQUIRE(f.master().udp_port_types().value() ==
std::vector<std::string>{"left", "right"});
std::vector<UDPPortPosition>{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<size_t>{1, 3});
REQUIRE(f.master().udp_port_types().value() ==
std::vector<std::string>{"left", "right"});
std::vector<UDPPortPosition>{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<size_t>{1, 3, 5, 7});
REQUIRE(f.master().udp_port_types().value() ==
std::vector<std::string>{"left", "right"});
std::vector<UDPPortPosition>{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<size_t>{1});
REQUIRE(f.master().udp_port_types().value() ==
std::vector<std::string>{"top", "bottom"});
std::vector<UDPPortPosition>{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<size_t>{0});
REQUIRE(f.master().udp_port_types().value() ==
std::vector<std::string>{"left", "right"});
std::vector<UDPPortPosition>{UDPPortPosition::LEFT,
UDPPortPosition::RIGHT});
auto frame = f.read_rois();
REQUIRE(frame.size() == 2);
REQUIRE(frame[0].cols() == 512);
+25 -14
View File
@@ -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<std::vector<std::string>> RawMasterFile::udp_port_types() const {
std::optional<std::vector<UDPPortPosition>>
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<UDPPortPosition>(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<ssize_t>(m_pixels_x), 0,
static_cast<ssize_t>(m_pixels_y)});
m_rois.push_back(
{0,
m_detector_layout.col * static_cast<ssize_t>(m_pixels_x),
0,
m_detector_layout.row * static_cast<ssize_t>(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<ssize_t>(m_pixels_x), 0,
static_cast<ssize_t>(m_pixels_y)});
m_rois.push_back(
{0, m_detector_layout.col * static_cast<ssize_t>(m_pixels_x), 0,
m_detector_layout.row * static_cast<ssize_t>(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<ssize_t>(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<ssize_t>(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<std::string>{"left", "right"}) {
if (m_udp_port_types ==
std::vector<UDPPortPosition>{UDPPortPosition::LEFT,
UDPPortPosition::RIGHT}) {
m_rois = merge_consecutive_rois<false, true>(m_rois);
} else if (m_udp_port_types ==
std::vector<std::string>{"bottom", "top"} ||
std::vector<UDPPortPosition>{UDPPortPosition::BOTTOM,
UDPPortPosition::TOP} ||
m_udp_port_types ==
std::vector<std::string>{"top", "bottom"}) {
std::vector<UDPPortPosition>{UDPPortPosition::TOP,
UDPPortPosition::BOTTOM}) {
m_rois = merge_consecutive_rois<true, false>(m_rois);
} else {
throw std::runtime_error(LOCATION + "Unsupported UDP port types");
+13
View File
@@ -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()) {
+8
View File
@@ -55,6 +55,14 @@ template <typename T> 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