From 982383980f0eb505bd079117855be207672e8230 Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Tue, 17 Jun 2025 17:15:12 +0200 Subject: [PATCH] wip --- slsDetectorSoftware/src/DetectorImpl.cpp | 171 ++++++++++++++---- slsDetectorSoftware/src/DetectorImpl.h | 13 +- .../tests/Caller/test-Caller-rx.cpp | 119 ++++++------ slsSupportLib/include/sls/sls_detector_defs.h | 3 +- 4 files changed, 210 insertions(+), 96 deletions(-) diff --git a/slsDetectorSoftware/src/DetectorImpl.cpp b/slsDetectorSoftware/src/DetectorImpl.cpp index 34e58dc5f..7e405d7a8 100644 --- a/slsDetectorSoftware/src/DetectorImpl.cpp +++ b/slsDetectorSoftware/src/DetectorImpl.cpp @@ -1544,31 +1544,6 @@ void DetectorImpl::setDefaultDac(defs::dacIndex index, int defaultValue, Parallel(&Module::setDefaultDac, pos, index, defaultValue, sett); } -defs::xy DetectorImpl::getPortGeometry() const { - defs::xy portGeometry(1, 1); - switch (shm()->detType) { - case EIGER: - portGeometry.x = modules[0]->getNumberofUDPInterfacesFromShm(); - break; - case JUNGFRAU: - case MOENCH: - portGeometry.y = modules[0]->getNumberofUDPInterfacesFromShm(); - break; - default: - break; - } - return portGeometry; -} - -defs::xy DetectorImpl::calculatePosition(int moduleIndex, - defs::xy geometry) const { - defs::xy pos{}; - int maxYMods = shm()->numberOfModules.y; - pos.y = (moduleIndex % maxYMods) * geometry.y; - pos.x = (moduleIndex / maxYMods) * geometry.x; - return pos; -} - void DetectorImpl::verifyUniqueDetHost(const uint16_t port, std::vector positions) const { // port for given positions @@ -1707,9 +1682,10 @@ std::vector DetectorImpl::getRxROI() const { // TODO } -bool DetectorImpl::roisOverlap(const defs::ROI &a, const defs::ROI &b) { - return !(a.xmax < b.xmin || a.xmin > b.xmax || a.ymax < b.ymin || - a.ymin > b.ymax); +bool DetectorImpl::roisOverlap(const defs::ROI &a, const defs::ROI &b) const { + bool xOverlap = !(a.xmax < b.xmin || a.xmin > b.xmax); + bool yOverlap = !(a.ymax < b.ymin || a.ymin > b.ymax); + return xOverlap && yOverlap; } void DetectorImpl::validateROIs(const std::vector &rois) { @@ -1719,10 +1695,13 @@ void DetectorImpl::validateROIs(const std::vector &rois) { if (roi.noRoi()) { throw RuntimeError("Invalid Roi of size 0. Roi: " + ToString(roi)); } + bool is2D = (modules[0]->getNumberOfChannels().y > 1 ? true : false); if (roi.completeRoi()) { - throw RuntimeError("Did you mean the clear roi command (API: " - "clearRxROI, cmd: rx_clearroi) Roi: " + - ToString(roi) + "?"); + std::ostringstream oss; + oss << "Did you mean the clear roi command (API: clearRxROI, cmd: " + "rx_clearroi) Roi: [ -1, -1 "; + oss << (is2D ? ", -1, -1 ]?" : "]?"); + throw RuntimeError(oss.str()); } if (roi.xmin > roi.xmax || roi.ymin > roi.ymax) { throw RuntimeError( @@ -1736,7 +1715,6 @@ void DetectorImpl::validateROIs(const std::vector &rois) { ToString(roi)); } - bool is2D = (modules[0]->getNumberOfChannels().y > 1 ? true : false); if (is2D) { if (roi.ymin < 0 || roi.ymax >= shm()->numberOfChannels.y) { throw RuntimeError( @@ -1754,13 +1732,115 @@ void DetectorImpl::validateROIs(const std::vector &rois) { for (size_t j = i + 1; j < rois.size(); ++j) { if (roisOverlap(rois[i], rois[j])) { - clearRxROI(); - throw RuntimeError("Overlapping ROIs detected — all cleared."); + throw RuntimeError("Invalid Overlapping Rois."); } } } } +defs::xy DetectorImpl::calculatePosition(size_t moduleIndex, + const defs::xy &geometry) const { + if ((geometry.x != 0 && geometry.x != 1) || + (geometry.y != 0 && geometry.y != 1)) { + throw RuntimeError("Invalid geometry configuration. Geometry: " + + ToString(geometry)); + } + + if (moduleIndex >= static_cast(geometry.x * geometry.y)) { + throw RuntimeError("Module index " + std::to_string(moduleIndex) + + " out of bounds."); + } + + int x = moduleIndex % geometry.x; + int y = moduleIndex / geometry.x; + return defs::xy{x, y}; +} + +defs::xy DetectorImpl::getPortGeometry() const { + defs::xy portGeometry(1, 1); + switch (shm()->detType) { + case EIGER: + portGeometry.x = modules[0]->getNumberofUDPInterfacesFromShm(); + break; + case JUNGFRAU: + case MOENCH: + portGeometry.y = modules[0]->getNumberofUDPInterfacesFromShm(); + break; + default: + break; + } + return portGeometry; +} + +defs::xy DetectorImpl::calculatePosition(int moduleIndex, + defs::xy geometry) const { + int maxYMods = shm()->numberOfModules.y; + int y = (moduleIndex % maxYMods) * geometry.y; + int x = (moduleIndex / maxYMods) * geometry.x; + return defs::xy{x, y}; +} + +defs::ROI DetectorImpl::getModuleROI(int moduleIndex) const { + const defs::xy modSize = modules[0]->getNumberOfChannels(); + // calculate module position (not taking into account port geometry) + const defs::xy modPos = calculatePosition(moduleIndex, defs::xy{1, 1}); + return defs::ROI{modSize.x * modPos.x, modSize.x * (modPos.x + 1) - 1, + modSize.y * modPos.y, + modSize.y * (modPos.y + 1) - 1}; // convert y for 1d? +} + +void DetectorImpl::convertGlobalRoiToPortLevel( + const defs::ROI &userRoi, const defs::ROI &moduleRoi, + std::vector> &portRois) const { + const defs::xy modSize = modules[0]->getNumberOfChannels(); + const defs::xy geometry = getPortGeometry(); + const int numPorts = geometry.x * geometry.y; + if (numPorts > 2) { + throw RuntimeError("Only up to 2 ports per module supported."); + } + + for (int port = 0; port < numPorts; ++port) { + defs::ROI portRoi = moduleRoi; + // Calculate port ROI boundaries (split vertically or horizontally) + if (geometry.x == 2) { + int midX = (moduleRoi.xmin + moduleRoi.xmax) / 2; + if (port == 0) + portRoi.xmax = midX; + else + portRoi.xmin = midX + 1; + } else if (geometry.y == 2) { + int midY = (moduleRoi.ymin + moduleRoi.ymax) / 2; + if (port == 0) + portRoi.ymax = midY; + else + portRoi.ymin = midY + 1; + } + + // Check if user ROI overlaps with this port ROI + if (roisOverlap(userRoi, portRoi)) { + defs::ROI clipped{}; + clipped.xmin = std::max(userRoi.xmin, portRoi.xmin); + clipped.xmax = std::min(userRoi.xmax, portRoi.xmax); + if (modSize.y > 1) { + clipped.ymin = std::max(userRoi.ymin, portRoi.ymin); + clipped.ymax = std::min(userRoi.ymax, portRoi.ymax); + } + + // Check if port ROI already exists for this port + for (const auto &m : portRois) { + if (m.find(port) != m.end()) { + throw RuntimeError( + "Multiple ROIs specified for the same port " + + std::to_string(port) + + " with ROI: " + ToString(userRoi)); + } + } + + portRois.push_back({{port, clipped}}); + } + } +} + void DetectorImpl::setRxROI(const std::vector &args) { if (shm()->detType == CHIPTESTBOARD || shm()->detType == defs::XILINX_CHIPTESTBOARD) { @@ -1772,9 +1852,28 @@ void DetectorImpl::setRxROI(const std::vector &args) { validateROIs(args); - rxRoiTemp = args; + for (size_t iModule = 0; iModule < modules.size(); ++iModule) { + auto moduleGlobalRoi = getModuleROI(iModule); - // TODO + // at most 2 rois per module (for each port) + std::vector> portRois; + + for (const auto &arg : args) { + if (roisOverlap(arg, moduleGlobalRoi)) { + convertGlobalRoiToPortLevel(arg, moduleGlobalRoi, portRois); + } + } + // print the rois for debugging + LOG(logINFOBLUE) << "Module " << iModule << " RxROIs:"; + for (const auto &portRoi : portRois) { + for (const auto &roi : portRoi) { + LOG(logINFOBLUE) + << " Port " << roi.first << ": " << ToString(roi.second); + } + } + // modules[iModule]->setRxROIs(portRois); TODO + } + rxRoiTemp = args; } void DetectorImpl::clearRxROI() { rxRoiTemp.clear(); } diff --git a/slsDetectorSoftware/src/DetectorImpl.h b/slsDetectorSoftware/src/DetectorImpl.h index b6a6af905..b4329de49 100644 --- a/slsDetectorSoftware/src/DetectorImpl.h +++ b/slsDetectorSoftware/src/DetectorImpl.h @@ -421,14 +421,19 @@ class DetectorImpl : public virtual slsDetectorDefs { */ int kbhit(); - defs::xy getPortGeometry() const; - defs::xy calculatePosition(int moduleIndex, defs::xy geometry) const; - void verifyUniqueHost( bool isDet, std::vector> &hosts) const; - bool roisOverlap(const defs::ROI &a, const defs::ROI &b); + bool roisOverlap(const defs::ROI &a, const defs::ROI &b) const; void validateROIs(const std::vector &rois); + defs::xy calculatePosition(size_t moduleIndex, + const defs::xy &geometry) const; + defs::xy getPortGeometry() const; + defs::xy calculatePosition(int moduleIndex, defs::xy geometry) const; + defs::ROI getModuleROI(int moduleIndex) const; + void convertGlobalRoiToPortLevel( + const defs::ROI &userRoi, const defs::ROI &moduleRoi, + std::vector> &portRois) const; const int detectorIndex{0}; SharedMemory shm{0, -1}; diff --git a/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp b/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp index 82bc1e2af..45e2b8cc8 100644 --- a/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp +++ b/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp @@ -491,45 +491,42 @@ TEST_CASE("rx_roi", "[.cmdcall]") { caller.call("rx_roi", {"10", "15"}, -1, PUT, oss); REQUIRE(oss.str() == "rx_roi [10, 15]\n"); } - REQUIRE_THROWS(caller.call("rx_roi", {"-1", "-1"}, -1, PUT)); - REQUIRE_THROWS( - caller.call("rx_roi", {"10", "15", "25", "30"}, -1, PUT)); // vector of rois - { - std::ostringstream oss; - caller.call("rx_roi", {"[5, 10, -1, -1]; [25, 20, -1, -1]"}, -1, - PUT, oss); - REQUIRE(oss.str() == - "rx_roi [5, 10, -1, -1]; [25, 20, -1, -1]\n"); - } - REQUIRE_THROWS(caller.call( - "rx_roi", {"[5, 20, -1, -1; 25, 30 -1, -1]"}, -1, PUT)); - REQUIRE_THROWS(caller.call( - "rx_roi", {"[5, 20, -1]; [25, 30 -1, -1]"}, -1, PUT)); // separated by space is allowed REQUIRE_NOTHROW(caller.call( "rx_roi", {"[5, 10, -1, -1]", "[25, 28, -1, -1]"}, -1, PUT)); - REQUIRE_NOTHROW(caller.call("rx_roi", - {"[0, 10, -1, -1];[20, 30, -1, -1];[9, " - "10, -1, -1];[40, 50, -1, -1]"}, - -1, PUT)); - // overlapping rois - REQUIRE_THROWS(caller.call( - "rx_roi", {"[0, 10,-1, -1];[5, 15, -1, -1]"}, 0, PUT)); - // xmin > xmax - REQUIRE_THROWS(caller.call("rx_roi", {"[12, 8, -1, -1]"}, 0, PUT)); - // outside detector bounds - REQUIRE_THROWS( - caller.call("rx_roi", {"[95, 105, -1, -1]"}, 0, PUT)); - // module level not allowed - REQUIRE_THROWS(caller.call( - "rx_roi", {"[5, 10, -1, -1]; [25, 28, -1, -1]"}, 0, PUT)); + // separated by semicolon is allowed + REQUIRE_NOTHROW(caller.call( + "rx_roi", {"[0, 10, -1, -1];[20, 30, -1, -1];[40, 50, -1, -1]"}, + -1, PUT)); // square brackets missing REQUIRE_THROWS(caller.call( "rx_roi", {"[5, 20, -1, -1; 25, 30, -1, -1]"}, -1, PUT)); // invalid roi, 4 parts expected REQUIRE_THROWS(caller.call( "rx_roi", {"[5, 20, -1]; [25, 30, -1, -1]"}, -1, PUT)); + REQUIRE_THROWS(caller.call("rx_roi", {"0", "0"}, -1, PUT)); + REQUIRE_THROWS(caller.call("rx_roi", {"-1", "-1"}, -1, PUT)); + // xmin > xmax + REQUIRE_THROWS(caller.call("rx_roi", {"[12, 8, -1, -1]"}, -1, PUT)); + // outside detector bounds + REQUIRE_THROWS(caller.call( + "rx_roi", + {"[95," + std::to_string(detsize.x + 5) + ", -1, -1]"}, -1, + PUT)); + // module level not allowed + REQUIRE_THROWS(caller.call( + "rx_roi", {"[5, 10, -1, -1]; [25, 28, -1, -1]"}, 0, PUT)); + // overlapping rois + REQUIRE_THROWS(caller.call( + "rx_roi", {"[0, 10,-1, -1];[5, 15, -1, -1]"}, -1, PUT)); + // valid + { + std::ostringstream oss; + caller.call("rx_roi", {"[5, 10, -1, -1]; [15, 20, -1, -1]"}, -1, + PUT, oss); + REQUIRE(oss.str() == "rx_roi [5, 10];[15, 20]\n"); + } } // 2d else { @@ -555,9 +552,46 @@ TEST_CASE("rx_roi", "[.cmdcall]") { std::to_string(detsize.y - 5) + std::string("]\n")); } + // vector of rois + // separated by space is allowed + REQUIRE_NOTHROW(caller.call( + "rx_roi", {"[5, 10, 20, 30]", "[25, 28, 14, 15]"}, -1, PUT)); + // separated by semicolon is allowed + REQUIRE_NOTHROW(caller.call("rx_roi", + {"[0, 10, 0, 10];[20, 30, 0, 10];[0, " + "10, 20, 30];[40, 50, 0, 10]"}, + -1, PUT)); + // square brackets missing + REQUIRE_THROWS(caller.call( + "rx_roi", {"[5, 20, 20, 30; 25, 30, 14, 15]"}, -1, PUT)); + // invalid roi, 4 parts expected + REQUIRE_THROWS(caller.call( + "rx_roi", {"[5, 20, 20]; [25, 30, 14, 15]"}, -1, PUT)); + REQUIRE_THROWS( + caller.call("rx_roi", {"0", "0", "0", "0"}, -1, PUT)); REQUIRE_THROWS( caller.call("rx_roi", {"-1", "-1", "-1", "-1"}, -1, PUT)); - // vector of rois + // xmin > xmax + REQUIRE_THROWS(caller.call("rx_roi", {"[12, 8, 0, 10]"}, -1, PUT)); + // ymin > ymax + REQUIRE_THROWS(caller.call("rx_roi", {"[0, 10, 20, 5]"}, -1, PUT)); + // outside detector bounds + REQUIRE_THROWS(caller.call( + "rx_roi", {"[95," + std::to_string(detsize.x + 5) + ", 0, 10]"}, + -1, PUT)); + REQUIRE_THROWS(caller.call( + "rx_roi", + {"[95, 100, 0, " + std::to_string(detsize.y + 5) + "]"}, -1, + PUT)); + // module level not allowed + REQUIRE_THROWS(caller.call( + "rx_roi", {"[5, 10, 20, 30]; [25, 28, 14, 15]"}, 0, PUT)); + // overlapping rois + REQUIRE_THROWS(caller.call( + "rx_roi", {"[0, 10, 0, 10];[5, 15, 0, 10]"}, -1, PUT)); + REQUIRE_THROWS(caller.call( + "rx_roi", {"[0, 10, 0, 10];[0, 10, 9, 11]"}, -1, PUT)); + // valid { std::ostringstream oss; caller.call("rx_roi", {"[5, 10, 20, 30]; [25, 28, 14, 15]"}, -1, @@ -565,31 +599,6 @@ TEST_CASE("rx_roi", "[.cmdcall]") { REQUIRE(oss.str() == "rx_roi [5, 10, 20, 30];[25, 28, 14, 15]\n"); } - // separated by space is allowed - REQUIRE_NOTHROW(caller.call( - "rx_roi", {"[5, 10, 20, 30]", "[25, 28, 14, 15]"}, -1, PUT)); - REQUIRE_NOTHROW(caller.call("rx_roi", - {"[0, 10, 0, 10];[20, 30, 0, 10];[0, " - "10, 20, 30];[40, 50, 0, 10]"}, - -1, PUT)); - // overlapping rois - REQUIRE_THROWS(caller.call( - "rx_roi", {"[0, 10, 0, 10];[5, 15, 0, 10]"}, 0, PUT)); - // xmin > xmax - REQUIRE_THROWS(caller.call("rx_roi", {"[12, 8, 0, 10]"}, 0, PUT)); - // ymin > ymax - REQUIRE_THROWS(caller.call("rx_roi", {"[0, 10, 20, 5]"}, 0, PUT)); - // outside detector bounds - REQUIRE_THROWS(caller.call("rx_roi", {"[95, 105, 0, 10]"}, 0, PUT)); - // module level not allowed - REQUIRE_THROWS(caller.call( - "rx_roi", {"[5, 10, 20, 30]; [25, 28, 14, 15]"}, 0, PUT)); - // square brackets missing - REQUIRE_THROWS(caller.call( - "rx_roi", {"[5, 20, 20, 30; 25, 30, 14, 15]"}, -1, PUT)); - // invalid roi, 4 parts expected - REQUIRE_THROWS(caller.call( - "rx_roi", {"[5, 20, 20]; [25, 30, 14, 15]"}, -1, PUT)); } for (int i = 0; i != det.size(); ++i) { diff --git a/slsSupportLib/include/sls/sls_detector_defs.h b/slsSupportLib/include/sls/sls_detector_defs.h index 9a010ba4c..34f24d75d 100644 --- a/slsSupportLib/include/sls/sls_detector_defs.h +++ b/slsSupportLib/include/sls/sls_detector_defs.h @@ -237,7 +237,8 @@ class slsDetectorDefs { return (xmin == -1 && xmax == -1 && ymin == -1 && ymax == -1); } constexpr bool noRoi() const { - return (xmin == 0 && xmax == 0 && ymin == 0 && ymax == 0); + return ((xmin == 0 && xmax == 0) && + ((ymin == 0 && ymax == 0) || (ymin == -1 && ymax == -1))); } void setNoRoi() { xmin = 0;