diff --git a/include/aare/RawMasterFile.hpp b/include/aare/RawMasterFile.hpp index d7b13a4..7b8283b 100644 --- a/include/aare/RawMasterFile.hpp +++ b/include/aare/RawMasterFile.hpp @@ -109,6 +109,13 @@ class RawMasterFile { std::optional m_number_of_rows; std::optional m_counter_mask; + /// @brief index of disabled UDP ports - index relative to UDP_port_types + std::optional> m_disabled_udp_ports{}; + + /// @brief udp port types + std::optional> + m_udp_port_types{}; // TODO: UDPPortType? - string_to conversion? + std::optional> m_rois; public: @@ -143,6 +150,16 @@ class RawMasterFile { std::optional number_of_rows() const; std::optional counter_mask() const; + /// @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; + + /// @brief Get the indices of disabled UDP ports + /// @return Optional vector of indices of disabled UDP ports (only present + /// for masterfile version >= 8.1) + std::optional> disabled_udp_ports() const; + std::optional> rois() const; std::optional roi() const; diff --git a/python/src/raw_master_file.hpp b/python/src/raw_master_file.hpp index b67720b..a76bee4 100644 --- a/python/src/raw_master_file.hpp +++ b/python/src/raw_master_file.hpp @@ -108,6 +108,34 @@ 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 + ---------- + Optional[List[ROI]] + Optional vector of ROIs (only present for masterfile version >= 8.1) + )") + .def_property_readonly("udp_port_types", &RawMasterFile::udp_port_types, + R"( + Get the types of UDP ports + + Returns + ---------- + Optional[List[str]] + 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 + ---------- + Optional[List[int]] + Optional vector of disabled UDP port indices relative to UDP port types (only present for + masterfile version >= 8.1) + )") .def_property_readonly("period", [](RawMasterFile &self) { double seconds = std::chrono::duration(self.period()).count(); diff --git a/src/RawFile.cpp b/src/RawFile.cpp index cecf3e8..67c3d1d 100644 --- a/src/RawFile.cpp +++ b/src/RawFile.cpp @@ -25,7 +25,52 @@ RawFile::RawFile(const std::filesystem::path &fname, const std::string &mode) : 1); if (mode == "r") { - if (m_master.rois().has_value()) { + // TODO: should we support both ROI and disabled udp port - which one + // should have precedence? + if (m_master.disabled_udp_ports().has_value() && + m_master.disabled_udp_ports().value().size() > 0) { + + // no ROI use full detector + m_ROI_geometries.reserve(1); + ROI roi{}; + + auto disabled_ports = m_master.disabled_udp_ports().value(); + + for (auto disabled_port : disabled_ports) { + std::string disabled_port_type = + m_master.udp_port_types() + .value()[disabled_port]; // TODO: string_to? - anyway + // defined in slsDetectorDefs + if (disabled_port_type == "bottom") { + roi = ROI{0, static_cast(m_master.pixels_x()), + static_cast(m_master.pixels_y()), + 2 * static_cast(m_master.pixels_y())}; + } else if (disabled_port_type == "top") { + roi = ROI{0, static_cast(m_master.pixels_x()), 0, + static_cast(m_master.pixels_y())}; + } else if (disabled_port_type == "left") { + roi = ROI{0, static_cast(m_master.pixels_x()), 0, + static_cast( + m_master.pixels_y())}; // TODO: need to check + // eiger data !!!! + } else if (disabled_port_type == "right") { + roi = ROI{ + static_cast(m_master.pixels_x()), + 2 * static_cast(m_master.pixels_x()), 0, + static_cast( + m_master.pixels_y())}; // TODO: need to check eiger + // data, bottom port flipped? + } else { + throw std::runtime_error( + LOCATION + + "Unknown UDP port type: " + disabled_port_type); + } + } + + m_ROI_geometries.push_back(ROIGeometry(roi, m_geometry)); // roi, + + open_subfiles(0); + } else if (m_master.rois().has_value()) { m_ROI_geometries.reserve(m_master.rois()->size()); // iterate over all ROIS @@ -37,7 +82,6 @@ RawFile::RawFile(const std::filesystem::path &fname, const std::string &mode) open_subfiles(roi_index); ++roi_index; } - } else { // no ROI use full detector m_ROI_geometries.reserve(1); diff --git a/src/RawFile.test.cpp b/src/RawFile.test.cpp index 88efc02..29acc10 100644 --- a/src/RawFile.test.cpp +++ b/src/RawFile.test.cpp @@ -404,4 +404,69 @@ TEST_CASE("Read Mythenframe", "[.with-data][RawFile]") { REQUIRE(f.master().roi().value().height() == 1); auto frame = f.read_frame(); REQUIRE(frame.cols() == 2560); +} + +TEST_CASE("Read Jungfrau frame with disabled UDP ports", + "[.with-data][RawFile]") { + // auto fpath = test_data_path() / "raw/jungfrau" / + //"2_interfaces_top_disabled_master_6.json"; + + SECTION("disabled top port") { + auto fpath = test_data_path() / "raw/jungfrau" / + "2_interfaces_top_disabled_master_6.json"; + REQUIRE(std::filesystem::exists(fpath)); + RawFile f(fpath); + REQUIRE(f.master().disabled_udp_ports().value() == + std::vector{1}); + REQUIRE(f.master().udp_port_types().value() == + std::vector{"bottom", "top"}); + auto frame = f.read_frame(); + REQUIRE(frame.cols() == 1024); + REQUIRE(frame.rows() == 256); + } + + SECTION("disabled bottom port") { + auto fpath = test_data_path() / "raw/jungfrau" / + "2_interfaces_bottom_port_disabled_master_0.json"; + REQUIRE(std::filesystem::exists(fpath)); + RawFile f(fpath); + REQUIRE(f.master().disabled_udp_ports().value() == + std::vector{0}); + REQUIRE(f.master().udp_port_types().value() == + std::vector{"bottom", "top"}); + auto frame = f.read_frame(); + REQUIRE(frame.cols() == 1024); + REQUIRE(frame.rows() == 256); + } +} + +TEST_CASE("Read Moench frame with disabled UDP ports", + "[.with-data][RawFile]") { + SECTION("disabled top port") { + auto fpath = test_data_path() / "raw/moench" / + "2_interfaces_top_port_disabled_master_0.json"; + REQUIRE(std::filesystem::exists(fpath)); + RawFile f(fpath); + REQUIRE(f.master().disabled_udp_ports().value() == + std::vector{1}); + REQUIRE(f.master().udp_port_types().value() == + std::vector{"bottom", "top"}); + auto frame = f.read_frame(); + REQUIRE(frame.cols() == 400); + REQUIRE(frame.rows() == 200); + } + + SECTION("disabled bottom port") { + auto fpath = test_data_path() / "raw/moench" / + "2_interfaces_bottom_port_disabled_master_6.json"; + REQUIRE(std::filesystem::exists(fpath)); + RawFile f(fpath); + REQUIRE(f.master().disabled_udp_ports().value() == + std::vector{0}); + REQUIRE(f.master().udp_port_types().value() == + std::vector{"bottom", "top"}); + auto frame = f.read_frame(); + REQUIRE(frame.cols() == 400); + REQUIRE(frame.rows() == 200); + } } \ No newline at end of file diff --git a/src/RawMasterFile.cpp b/src/RawMasterFile.cpp index d399c25..0407411 100644 --- a/src/RawMasterFile.cpp +++ b/src/RawMasterFile.cpp @@ -193,6 +193,14 @@ ScanParameters RawMasterFile::scan_parameters() const { return m_scan_parameters; } +std::optional> RawMasterFile::udp_port_types() const { + return m_udp_port_types; +} + +std::optional> RawMasterFile::disabled_udp_ports() const { + return m_disabled_udp_ports; +} + std::optional RawMasterFile::roi() const { if (!m_rois) { return std::nullopt; @@ -364,7 +372,24 @@ void RawMasterFile::parse_json(std::istream &is) { } catch (const json::out_of_range &e) { // not a scan } - + try { + 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); + } + } catch (const json::out_of_range &e) { + // leave the optional empty + } + try { + auto json_list_obj = j.at("UDP Ports Disabled"); + m_disabled_udp_ports.emplace(); + for (auto &elem : json_list_obj) { + m_disabled_udp_ports.value().push_back(static_cast(elem)); + } + } catch (const json::out_of_range &e) { + // leave the optional empty + } try { m_udp_interfaces_per_module = {j.at("Number of UDP Interfaces"), 1}; } catch (const json::out_of_range &e) {