Dev/filereading for disabled udp (#342)
Build on RHEL9 / build (push) Successful in 2m41s
Build on RHEL8 / build (push) Successful in 3m15s
Run tests using data on local RHEL8 / build (push) Failing after 4m13s
Build on local RHEL8 / build (push) Successful in 2m53s

- handles file reading of disabled udp ports 
- adds members disabled_udp_ports in master file as an optional 
- adds member diasbled_udp_port_types in master file as an optional
- Treats enabled udp ports as ROIs 
- merges/combines consecutive ROis into one 

### To discuss: 

- right now can only handle either ROI or disabled udp ports (disabled
udp ports has higher precedence)
- Should Frames in File be removed from Master File as value is nonsense
for disabled udp ports

---------

Co-authored-by: Erik Fröjdh <erik.frojdh@psi.ch>
This commit is contained in:
2026-09-03 14:14:57 +02:00
committed by GitHub
co-authored by Erik Fröjdh
parent eddb919328
commit 641ef047b5
25 changed files with 1252 additions and 267 deletions
+2
View File
@@ -27,6 +27,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);
}
+1 -33
View File
@@ -2,6 +2,7 @@
#include "aare/CtbRawFile.hpp"
#include "aare/File.hpp"
#include "aare/Frame.hpp"
#include "aare/ROI.hpp"
#include "aare/RawFile.hpp"
#include "aare/RawMasterFile.hpp"
#include "aare/RawSubFile.hpp"
@@ -27,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);
@@ -170,28 +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
});
#pragma GCC diagnostic pop
}
+29 -1
View File
@@ -66,7 +66,8 @@ void define_raw_master_file_bindings(py::module &m) {
.def_property_readonly("total_frames_expected",
&RawMasterFile::total_frames_expected)
.def_property_readonly("geometry", &RawMasterFile::geometry)
.def_property_readonly("detector_layout",
&RawMasterFile::detector_layout)
.def_property_readonly("udp_interfaces_per_module",
&RawMasterFile::udp_interfaces_per_module)
.def_property_readonly("analog_samples", &RawMasterFile::analog_samples,
@@ -107,6 +108,33 @@ void define_raw_master_file_bindings(py::module &m) {
return std::nullopt;
}
})
.def_property_readonly("rois", &RawMasterFile::rois, R"(
Get the ROIs defined in the master file
Returns
----------
List[ROI]
List of ROIs (default complete ROI)
)")
.def_property_readonly("udp_port_types", &RawMasterFile::udp_port_types,
R"(
Get the types of UDP ports
Returns
----------
Optional[List[UDPPortPosition]]
Optional vector of UDP port types as strings (only present for
masterfile version >= 8.1)
)")
.def_property_readonly("disabled_udp_ports",
&RawMasterFile::disabled_udp_ports, R"(
Get the indices of disabled UDP ports
Returns
----------
List[int]
Vector of disabled UDP port indices relative to UDP port types (empty if none are disabled)
)")
.def_property_readonly("period", [](RawMasterFile &self) {
double seconds =
std::chrono::duration<double>(self.period()).count();
+39 -1
View File
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: MPL-2.0
import pytest
from aare import RawFile
from aare import RawFile, ROI, UDPPortPosition
import numpy as np
@pytest.mark.withdata
@@ -110,3 +110,41 @@ def test_read_rawfile_eiger_and_compare_to_numpy(test_data_path):
header, image1 = f.read_frame()
assert (image == image1).all()
@pytest.mark.withdata
def test_read_eiger_udp_port_disabled(test_data_path):
with RawFile(test_data_path / "raw/eiger/one_udp_port_disabled_master_0.json") as f:
_, frame = f.read_rois()
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)
assert rois[1] == ROI(0, 1024, 256, 512)
with RawFile(test_data_path / "raw/eiger/quad_eiger_disabled_bottom_port_master_0.json") as f:
_, frame = f.read_frame()
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)
with RawFile(test_data_path / "raw/eiger/2_modules_eiger_disabled_udp_port_master_0.json") as f:
_, frame = f.read_rois()
assert(len(frame) == 2)
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)
assert rois[1] == ROI(1024, 1536, 0, 512)