From e4f329466c5682d941092cee10e38778a7f02a5f Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Mon, 16 Jun 2025 17:25:21 +0200 Subject: [PATCH 01/49] wip --- python/src/detector.cpp | 11 --- slsDetectorSoftware/generator/commands.yaml | 36 ++++---- slsDetectorSoftware/include/sls/Detector.h | 10 +-- slsDetectorSoftware/src/Caller.cpp | 4 +- slsDetectorSoftware/src/Caller.h | 8 +- slsDetectorSoftware/src/CallerSpecial.cpp | 3 +- slsDetectorSoftware/src/Detector.cpp | 16 ++-- slsDetectorSoftware/src/DetectorImpl.cpp | 97 ++++++++++++++------- slsDetectorSoftware/src/DetectorImpl.h | 12 +-- slsDetectorSoftware/src/Module.cpp | 4 +- slsDetectorSoftware/src/Module.h | 6 +- slsDetectorSoftware/tests/CMakeLists.txt | 1 + slsDetectorSoftware/tests/test-Roi.cpp | 84 ++++++++++++++++++ 13 files changed, 204 insertions(+), 88 deletions(-) create mode 100644 slsDetectorSoftware/tests/test-Roi.cpp diff --git a/python/src/detector.cpp b/python/src/detector.cpp index 5393cbf6e..4a5ffc02c 100644 --- a/python/src/detector.cpp +++ b/python/src/detector.cpp @@ -924,17 +924,6 @@ void init_det(py::module &m) { (void (Detector::*)(bool, sls::Positions)) & Detector::setRxArping, py::arg(), py::arg() = Positions{}); - CppDetectorApi.def("getIndividualRxROIs", - (Result(Detector::*)(sls::Positions) const) & - Detector::getIndividualRxROIs, - py::arg()); - CppDetectorApi.def("getRxROI", - (defs::ROI(Detector::*)() const) & Detector::getRxROI); - CppDetectorApi.def( - "setRxROI", (void (Detector::*)(const defs::ROI)) & Detector::setRxROI, - py::arg()); - CppDetectorApi.def("clearRxROI", - (void (Detector::*)()) & Detector::clearRxROI); CppDetectorApi.def( "getFileFormat", (Result(Detector::*)(sls::Positions) const) & diff --git a/slsDetectorSoftware/generator/commands.yaml b/slsDetectorSoftware/generator/commands.yaml index f33cf7be2..3b96e48f5 100644 --- a/slsDetectorSoftware/generator/commands.yaml +++ b/slsDetectorSoftware/generator/commands.yaml @@ -1739,12 +1739,13 @@ readout: PUT: function: startDetectorReadout -rx_clearroi: - inherit_actions: EXECUTE_SET_COMMAND_NOID - help: "\n\tResets Region of interest in receiver. Default is all channels/pixels enabled." - actions: - PUT: - function: clearRxROI +# TODO +#rx_clearroi: +# inherit_actions: EXECUTE_SET_COMMAND_NOID +# help: "\n\tResets Region of interest in receiver. Default is all channels/pixels enabled." +# actions: +# PUT: +# function: clearRxROI ################# EXECUTE_SET_COMMAND ######################## start: @@ -2592,17 +2593,18 @@ rx_zmqip: PUT: argc: -1 -rx_roi: - is_description: true - actions: - GET: - argc: 0 - PUT: - args: - - argc: 2 - arg_types: [ int, int ] - - argc: 4 - arg_types: [ int, int, int, int ] +#TODO +#rx_roi: +# is_description: true +# actions: +# GET: +# argc: 0 +# PUT: +# args: +# - argc: 2 +# arg_types: [ int, int ] +# - argc: 4 +# arg_types: [ int, int, int, int ] ratecorr: is_description: true diff --git a/slsDetectorSoftware/include/sls/Detector.h b/slsDetectorSoftware/include/sls/Detector.h index eb679a578..fd85e427a 100644 --- a/slsDetectorSoftware/include/sls/Detector.h +++ b/slsDetectorSoftware/include/sls/Detector.h @@ -985,16 +985,16 @@ class Detector { * every minute. Useful in 10G mode. */ void setRxArping(bool value, Positions pos = {}); - /** at module level */ - Result getIndividualRxROIs(Positions pos) const; - - defs::ROI getRxROI() const; + std::vector getRxROI() const; /** only at multi module level without gap pixels */ - void setRxROI(const defs::ROI value); + void setRxROI(const std::vector& args); void clearRxROI(); + int getNumberOfUdpPortsInRxROI() const; + + ///@} /** @name File */ diff --git a/slsDetectorSoftware/src/Caller.cpp b/slsDetectorSoftware/src/Caller.cpp index 78a6f79d7..9fb08ff69 100644 --- a/slsDetectorSoftware/src/Caller.cpp +++ b/slsDetectorSoftware/src/Caller.cpp @@ -10594,7 +10594,7 @@ std::string Caller::rx_arping(int action) { return os.str(); } - +/* std::string Caller::rx_clearroi(int action) { std::ostringstream os; @@ -10637,7 +10637,7 @@ std::string Caller::rx_clearroi(int action) { return os.str(); } - +*/ std::string Caller::rx_dbitoffset(int action) { std::ostringstream os; diff --git a/slsDetectorSoftware/src/Caller.h b/slsDetectorSoftware/src/Caller.h index 3e1be13ac..d1df0c0f2 100644 --- a/slsDetectorSoftware/src/Caller.h +++ b/slsDetectorSoftware/src/Caller.h @@ -233,7 +233,7 @@ class Caller { std::string runclk(int action); std::string runtime(int action); std::string rx_arping(int action); - std::string rx_clearroi(int action); + //std::string rx_clearroi(int action); std::string rx_dbitlist(int action); std::string rx_dbitoffset(int action); std::string rx_dbitreorder(int action); @@ -251,7 +251,7 @@ class Caller { std::string rx_padding(int action); std::string rx_printconfig(int action); std::string rx_realudpsocksize(int action); - std::string rx_roi(int action); + //std::string rx_roi(int action); std::string rx_silent(int action); std::string rx_start(int action); std::string rx_status(int action); @@ -580,7 +580,7 @@ class Caller { {"runclk", &Caller::runclk}, {"runtime", &Caller::runtime}, {"rx_arping", &Caller::rx_arping}, - {"rx_clearroi", &Caller::rx_clearroi}, + //{"rx_clearroi", &Caller::rx_clearroi}, {"rx_dbitlist", &Caller::rx_dbitlist}, {"rx_dbitoffset", &Caller::rx_dbitoffset}, {"rx_dbitreorder", &Caller::rx_dbitreorder}, @@ -598,7 +598,7 @@ class Caller { {"rx_padding", &Caller::rx_padding}, {"rx_printconfig", &Caller::rx_printconfig}, {"rx_realudpsocksize", &Caller::rx_realudpsocksize}, - {"rx_roi", &Caller::rx_roi}, + //{"rx_roi", &Caller::rx_roi}, {"rx_silent", &Caller::rx_silent}, {"rx_start", &Caller::rx_start}, {"rx_status", &Caller::rx_status}, diff --git a/slsDetectorSoftware/src/CallerSpecial.cpp b/slsDetectorSoftware/src/CallerSpecial.cpp index bdea93207..394a9d5e7 100644 --- a/slsDetectorSoftware/src/CallerSpecial.cpp +++ b/slsDetectorSoftware/src/CallerSpecial.cpp @@ -719,6 +719,7 @@ std::string Caller::rx_zmqip(int action) { } return os.str(); } +/* TODO std::string Caller::rx_roi(int action) { std::ostringstream os; if (action == defs::HELP_ACTION) { @@ -761,7 +762,7 @@ std::string Caller::rx_roi(int action) { throw RuntimeError("Unknown action"); } return os.str(); -} +}*/ std::string Caller::ratecorr(int action) { std::ostringstream os; if (action == defs::HELP_ACTION) { diff --git a/slsDetectorSoftware/src/Detector.cpp b/slsDetectorSoftware/src/Detector.cpp index f84e5fbb3..375faaeaa 100644 --- a/slsDetectorSoftware/src/Detector.cpp +++ b/slsDetectorSoftware/src/Detector.cpp @@ -1367,16 +1367,22 @@ void Detector::setRxArping(bool value, Positions pos) { pimpl->Parallel(&Module::setRxArping, pos, value); } -Result Detector::getIndividualRxROIs(Positions pos) const { - return pimpl->Parallel(&Module::getRxROI, pos); +std::vector Detector::getRxROI() const { + return pimpl->getRxROI(); } -defs::ROI Detector::getRxROI() const { return pimpl->getRxROI(); } - -void Detector::setRxROI(const defs::ROI value) { pimpl->setRxROI(value); } +// RxROIs can be set for all types except CTB. At multi level without gap pixels +void Detector::setRxROI(const std::vector& args) { + pimpl->setRxROI(args); +} void Detector::clearRxROI() { pimpl->clearRxROI(); } +int Detector::getNumberOfUdpPortsInRxROI() const { + return pimpl->getNumberOfUdpPortsInRxROI(); + +} + // File Result Detector::getFileFormat(Positions pos) const { diff --git a/slsDetectorSoftware/src/DetectorImpl.cpp b/slsDetectorSoftware/src/DetectorImpl.cpp index 3e3efb8b5..07117715a 100644 --- a/slsDetectorSoftware/src/DetectorImpl.cpp +++ b/slsDetectorSoftware/src/DetectorImpl.cpp @@ -31,6 +31,7 @@ namespace sls { + DetectorImpl::DetectorImpl(int detector_index, bool verify, bool update) : detectorIndex(detector_index), shm(detector_index, -1), ctb_shm(detector_index, -1, CtbConfig::shm_tag()) { @@ -130,10 +131,6 @@ void DetectorImpl::initializeDetectorStructure() { shm()->gapPixels = false; // zmqlib default shm()->zmqHwm = -1; - shm()->rx_roi.xmin = -1; - shm()->rx_roi.xmax = -1; - shm()->rx_roi.ymin = -1; - shm()->rx_roi.ymax = -1; } void DetectorImpl::initializeMembers(bool verify) { @@ -539,7 +536,7 @@ void DetectorImpl::readFrameFromReceiver() { bool quadEnable = false; // to flip image bool eiger = false; - std::array rxRoi = shm()->rx_roi.getIntArray(); + std::array rxRoi {};//TODO: get roi from json header std::vector runningList(zmqSocket.size()); std::vector connectList(zmqSocket.size()); @@ -1696,7 +1693,8 @@ void DetectorImpl::verifyUniqueHost( } } -defs::ROI DetectorImpl::getRxROI() const { +std::vector DetectorImpl::getRxROI() const { + if (shm()->detType == CHIPTESTBOARD || shm()->detType == defs::XILINX_CHIPTESTBOARD) { throw RuntimeError("RxRoi not implemented for this Detector"); @@ -1704,6 +1702,9 @@ defs::ROI DetectorImpl::getRxROI() const { if (modules.size() == 0) { throw RuntimeError("No Modules added"); } + + return std::vector{}; + /* // complete detector in roi auto t = Parallel(&Module::getRxROI, {}); if (t.equal() && t.front().completeRoi()) { @@ -1770,9 +1771,56 @@ defs::ROI DetectorImpl::getRxROI() const { retval.ymax = 0; } return retval; + */ } -void DetectorImpl::setRxROI(const defs::ROI arg) { +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); + +} + +void DetectorImpl::validateROIs(const std::vector& rois) { + for (size_t i = 0; i < rois.size(); ++i) { + const auto& roi = rois[i]; + + if (roi.noRoi()) { + throw RuntimeError("Invalid Roi of size 0. Roi: " + ToString(roi)); + } + if (roi.completeRoi()) { + throw RuntimeError("Did you mean the clear roi command (API: " + "clearRxROI, cmd: rx_clearroi) Roi: " + ToString(roi) + "?"); + } + if (roi.xmin > roi.xmax || roi.ymin > roi.ymax) { + throw RuntimeError( + "Invalid Roi. xmin/ymin exceeds xmax/ymax. Roi: " + ToString(roi)); + } + + if (roi.xmin < 0 || roi.xmax >= shm()->numberOfChannels.x) { + throw RuntimeError("ROI x-dimension outside detector bounds. Roi: " + ToString(roi)); + } + + bool is2D = (modules[0]->getNumberOfChannels().y > 1 ? true : false); + if (is2D) { + if (roi.ymin < 0 || roi.ymax >= shm()->numberOfChannels.y) { + throw RuntimeError("ROI y-dimension outside detector bounds. Roi: " + ToString(roi)); + } + } else { + if ((roi.ymin != -1 && roi.ymin != 0) || (roi.ymax != -1 && roi.ymax != 0)) { + throw RuntimeError("Invalid Y range for 1D detector: should be -1. Roi: " + ToString(roi)); + } + } + + for (size_t j = i + 1; j < rois.size(); ++j) { + if (roisOverlap(rois[i], rois[j])) { + clearRxROI(); + throw RuntimeError("Overlapping ROIs detected — all cleared."); + } + } + } +} + +void DetectorImpl::setRxROI(const std::vector& args) { if (shm()->detType == CHIPTESTBOARD || shm()->detType == defs::XILINX_CHIPTESTBOARD) { throw RuntimeError("RxRoi not implemented for this Detector"); @@ -1780,32 +1828,14 @@ void DetectorImpl::setRxROI(const defs::ROI arg) { if (modules.size() == 0) { throw RuntimeError("No Modules added"); } - if (arg.noRoi()) { - throw RuntimeError("Invalid Roi of size 0."); - } - if (arg.completeRoi()) { - throw RuntimeError("Did you mean the clear roi command (API: " - "clearRxROI, cmd: rx_clearroi)?"); - } - if (arg.xmin > arg.xmax || arg.ymin > arg.ymax) { - throw RuntimeError( - "Invalid Receiver Roi. xmin/ymin exceeds xmax/ymax."); - } + + validateROIs(args); +/* defs::xy numChansPerMod = modules[0]->getNumberOfChannels(); bool is2D = (numChansPerMod.y > 1 ? true : false); defs::xy geometry = getPortGeometry(); - if (!is2D && ((arg.ymin != -1 && arg.ymin != 0) || - (arg.ymax != -1 && arg.ymax != 0))) { - throw RuntimeError( - "Invalid Receiver roi. Cannot set 2d roi for a 1d detector."); - } - - if (arg.xmin < 0 || arg.xmax >= shm()->numberOfChannels.x || - (is2D && (arg.ymin < 0 || arg.ymax >= shm()->numberOfChannels.y))) { - throw RuntimeError("Invalid Receiver Roi. Outside detector range."); - } for (size_t iModule = 0; iModule != modules.size(); ++iModule) { // default init = complete roi @@ -1884,14 +1914,15 @@ void DetectorImpl::setRxROI(const defs::ROI arg) { } else { modules[0]->setRxROIMetadata(arg); } + */ } void DetectorImpl::clearRxROI() { - Parallel(&Module::setRxROI, {}, defs::ROI{}); - shm()->rx_roi.xmin = -1; - shm()->rx_roi.ymin = -1; - shm()->rx_roi.xmax = -1; - shm()->rx_roi.ymax = -1; + ;//Parallel(&Module::setRxROI, {}, defs::ROI{}); TODO: clear roi +} + +int DetectorImpl::getNumberOfUdpPortsInRxROI() const { + return 0;// TODO } void DetectorImpl::getBadChannels(const std::string &fname, diff --git a/slsDetectorSoftware/src/DetectorImpl.h b/slsDetectorSoftware/src/DetectorImpl.h index da56e5a22..c899566f2 100644 --- a/slsDetectorSoftware/src/DetectorImpl.h +++ b/slsDetectorSoftware/src/DetectorImpl.h @@ -24,7 +24,7 @@ class detectorData; class Module; #define DETECTOR_SHMAPIVERSION 0x190809 -#define DETECTOR_SHMVERSION 0x220505 +#define DETECTOR_SHMVERSION 0x250616 #define SHORT_STRING_LENGTH 50 /** @@ -65,8 +65,6 @@ struct sharedDetector { bool gapPixels; /** high water mark of listening tcp port (only data) */ int zmqHwm; - /** in shm for gui purposes */ - defs::ROI rx_roi{}; }; class DetectorImpl : public virtual slsDetectorDefs { @@ -303,9 +301,10 @@ class DetectorImpl : public virtual slsDetectorDefs { std::vector> verifyUniqueRxHost(const std::vector &names) const; - defs::ROI getRxROI() const; - void setRxROI(const defs::ROI arg); + std::vector getRxROI() const; + void setRxROI(const std::vector& args); void clearRxROI(); + int getNumberOfUdpPortsInRxROI() const; void getBadChannels(const std::string &fname, Positions pos) const; void setBadChannels(const std::string &fname, Positions pos); @@ -428,6 +427,9 @@ class DetectorImpl : public virtual slsDetectorDefs { void verifyUniqueHost( bool isDet, std::vector> &hosts) const; + bool roisOverlap(const defs::ROI& a, const defs::ROI& b); + void validateROIs(const std::vector& rois); + const int detectorIndex{0}; SharedMemory shm{0, -1}; SharedMemory ctb_shm{0, -1, CtbConfig::shm_tag()}; diff --git a/slsDetectorSoftware/src/Module.cpp b/slsDetectorSoftware/src/Module.cpp index d1356c30f..47f4ffe79 100644 --- a/slsDetectorSoftware/src/Module.cpp +++ b/slsDetectorSoftware/src/Module.cpp @@ -1520,7 +1520,7 @@ bool Module::getRxArping() const { void Module::setRxArping(bool enable) { sendToReceiver(F_SET_RECEIVER_ARPING, static_cast(enable), nullptr); } - +/* defs::ROI Module::getRxROI() const { return sendToReceiver(F_RECEIVER_GET_RECEIVER_ROI); } @@ -1533,7 +1533,7 @@ void Module::setRxROI(const slsDetectorDefs::ROI arg) { void Module::setRxROIMetadata(const slsDetectorDefs::ROI arg) { sendToReceiver(F_RECEIVER_SET_RECEIVER_ROI_METADATA, arg, nullptr); } - +*/ // File slsDetectorDefs::fileFormat Module::getFileFormat() const { return sendToReceiver(F_GET_RECEIVER_FILE_FORMAT); diff --git a/slsDetectorSoftware/src/Module.h b/slsDetectorSoftware/src/Module.h index 86c9e3d5f..a687be6c3 100644 --- a/slsDetectorSoftware/src/Module.h +++ b/slsDetectorSoftware/src/Module.h @@ -301,9 +301,9 @@ class Module : public virtual slsDetectorDefs { std::array getReceiverThreadIds() const; bool getRxArping() const; void setRxArping(bool enable); - defs::ROI getRxROI() const; - void setRxROI(const slsDetectorDefs::ROI arg); - void setRxROIMetadata(const slsDetectorDefs::ROI arg); + //defs::ROI getRxROI() const; + //void setRxROI(const slsDetectorDefs::ROI arg); + //void setRxROIMetadata(const slsDetectorDefs::ROI arg); /************************************************** * * diff --git a/slsDetectorSoftware/tests/CMakeLists.txt b/slsDetectorSoftware/tests/CMakeLists.txt index d87f17ed0..f70e393f2 100755 --- a/slsDetectorSoftware/tests/CMakeLists.txt +++ b/slsDetectorSoftware/tests/CMakeLists.txt @@ -5,6 +5,7 @@ target_sources(tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/test-SharedMemory.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test-slsDetector.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/test-Roi.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Caller/test-Caller.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Caller/test-Caller-rx.cpp diff --git a/slsDetectorSoftware/tests/test-Roi.cpp b/slsDetectorSoftware/tests/test-Roi.cpp new file mode 100644 index 000000000..9ce6c3b30 --- /dev/null +++ b/slsDetectorSoftware/tests/test-Roi.cpp @@ -0,0 +1,84 @@ +#include "catch.hpp" +#include + +#include + +#include "DetectorImpl.h" +#include "sls/Detector.h" +#include "Module.h" + +#include + +namespace sls { + +TEST_CASE("ROI validation") { + DetectorImpl det(0, false, false); + det.addTestModule(slsDetectorDefs::JUNGFRAU); + std::cout << "size:"<< det.size() << std::endl; + DetectorImpl detector(0, false, false); + + SECTION("Valid non-overlapping ROIs") { + std::vector rois = { + {0, 10, 0, 10}, + {20, 30, 0, 10}, + {0, 10, 20, 30}, + {40, 50, 0, 10} + }; + REQUIRE_NOTHROW(DetectorImplTestHelper::testValidateRois(detector, rois)); + } + + SECTION("Overlapping ROIs should throw") { + std::vector rois = { + {0, 10, 0, 10}, + {5, 15, 0, 10} + }; + REQUIRE_THROWS_AS(DetectorImplTestHelper::testValidateRois(detector, rois), + sls::RuntimeError); + } + + SECTION("Invalid ROI (xmin > xmax)") { + std::vector rois = { + {12, 8, 0, 10} + }; + REQUIRE_THROWS_AS(DetectorImplTestHelper::testValidateRois(detector, rois), + sls::RuntimeError); + } + + SECTION("Invalid ROI (ymin > ymax)") { + std::vector rois = { + {0, 10, 20, 5} + }; + REQUIRE_THROWS_AS(DetectorImplTestHelper::testValidateRois(detector, rois), + sls::RuntimeError); + } + + SECTION("Invalid ROI (outside detector bounds)") { + // Assuming detector has 100x100 dimensions + detector.setNumberOfChannels({100, 100}); + std::vector rois = { + {95, 105, 0, 10} // xmax out of bounds + }; + REQUIRE_THROWS_AS(DetectorImplTestHelper::testValidateRois(detector, rois), + sls::RuntimeError); + } + + SECTION("Valid ROI for 1D detector") { + detector.setNumberOfChannels({100, 1}); + std::vector rois = { + {10, 20, -1, -1} + }; + REQUIRE_NOTHROW(DetectorImplTestHelper::testValidateRois(detector, rois)); + } + + SECTION("Invalid Y for 1D detector") { + detector.setNumberOfChannels({100, 1}); + std::vector rois = { + {10, 20, 0, 10} // Y should be -1 for 1D + }; + REQUIRE_THROWS_AS(DetectorImplTestHelper::testValidateRois(detector, rois), + sls::RuntimeError); + } +} + + +} // namespace sls From 06f06cfbf44ae5806bae402009f5423cb70fb064 Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Mon, 16 Jun 2025 22:13:35 +0200 Subject: [PATCH 02/49] wip --- slsDetectorSoftware/src/DetectorImpl.cpp | 156 +---------------------- 1 file changed, 3 insertions(+), 153 deletions(-) diff --git a/slsDetectorSoftware/src/DetectorImpl.cpp b/slsDetectorSoftware/src/DetectorImpl.cpp index 07117715a..6bd1ae8cc 100644 --- a/slsDetectorSoftware/src/DetectorImpl.cpp +++ b/slsDetectorSoftware/src/DetectorImpl.cpp @@ -1704,74 +1704,7 @@ std::vector DetectorImpl::getRxROI() const { } return std::vector{}; - /* - // complete detector in roi - auto t = Parallel(&Module::getRxROI, {}); - if (t.equal() && t.front().completeRoi()) { - LOG(logDEBUG) << "no roi"; - return defs::ROI(0, shm()->numberOfChannels.x - 1, 0, - shm()->numberOfChannels.y - 1); - } - - defs::xy numChansPerMod = modules[0]->getNumberOfChannels(); - bool is2D = (numChansPerMod.y > 1 ? true : false); - defs::xy geometry = getPortGeometry(); - - defs::ROI retval{}; - for (size_t iModule = 0; iModule != modules.size(); ++iModule) { - - defs::ROI moduleRoi = modules[iModule]->getRxROI(); - if (moduleRoi.noRoi()) { - LOG(logDEBUG) << iModule << ": no roi"; - } else { - // expand complete roi - if (moduleRoi.completeRoi()) { - moduleRoi.xmin = 0; - moduleRoi.xmax = numChansPerMod.x; - if (is2D) { - moduleRoi.ymin = 0; - moduleRoi.ymax = numChansPerMod.y; - } - } - LOG(logDEBUG) << iModule << ": " << moduleRoi; - - // get roi at detector level - defs::xy pos = calculatePosition(iModule, geometry); - defs::ROI moduleFullRoi{}; - moduleFullRoi.xmin = numChansPerMod.x * pos.x + moduleRoi.xmin; - moduleFullRoi.xmax = numChansPerMod.x * pos.x + moduleRoi.xmax; - if (is2D) { - moduleFullRoi.ymin = numChansPerMod.y * pos.y + moduleRoi.ymin; - moduleFullRoi.ymax = numChansPerMod.y * pos.y + moduleRoi.ymax; - } - LOG(logDEBUG) << iModule << ": (full roi)" << moduleFullRoi; - - // get min and max - if (retval.xmin == -1 || moduleFullRoi.xmin < retval.xmin) { - LOG(logDEBUG) << iModule << ": xmin updated"; - retval.xmin = moduleFullRoi.xmin; - } - if (retval.xmax == -1 || moduleFullRoi.xmax > retval.xmax) { - LOG(logDEBUG) << iModule << ": xmax updated"; - retval.xmax = moduleFullRoi.xmax; - } - if (retval.ymin == -1 || moduleFullRoi.ymin < retval.ymin) { - LOG(logDEBUG) << iModule << ": ymin updated"; - retval.ymin = moduleFullRoi.ymin; - } - if (retval.ymax == -1 || moduleFullRoi.ymax > retval.ymax) { - LOG(logDEBUG) << iModule << ": ymax updated"; - retval.ymax = moduleFullRoi.ymax; - } - } - LOG(logDEBUG) << iModule << ": (retval): " << retval; - } - if (retval.ymin == -1) { - retval.ymin = 0; - retval.ymax = 0; - } - return retval; - */ +//TODO } bool DetectorImpl::roisOverlap(const defs::ROI& a, const defs::ROI& b) { @@ -1831,94 +1764,11 @@ void DetectorImpl::setRxROI(const std::vector& args) { validateROIs(args); -/* - defs::xy numChansPerMod = modules[0]->getNumberOfChannels(); - bool is2D = (numChansPerMod.y > 1 ? true : false); - defs::xy geometry = getPortGeometry(); - - - for (size_t iModule = 0; iModule != modules.size(); ++iModule) { - // default init = complete roi - defs::ROI moduleRoi{}; - - // incomplete roi - if (!arg.completeRoi()) { - // multi module Gotthard2 - if (shm()->detType == GOTTHARD2 && size() > 1) { - moduleRoi.xmin = arg.xmin / 2; - moduleRoi.xmax = arg.xmax / 2; - if (iModule == 0) { - // all should be even - if (arg.xmin % 2 != 0) { - ++moduleRoi.xmin; - } - } else if (iModule == 1) { - // all should be odd - if (arg.xmax % 2 == 0) { - --moduleRoi.xmax; - } - } else { - throw RuntimeError("Cannot have more than 2 modules for a " - "Gotthard2 detector"); - } - } else { - // get module limits - defs::xy pos = calculatePosition(iModule, geometry); - defs::ROI moduleFullRoi{}; - moduleFullRoi.xmin = numChansPerMod.x * pos.x; - moduleFullRoi.xmax = numChansPerMod.x * (pos.x + 1) - 1; - if (is2D) { - moduleFullRoi.ymin = numChansPerMod.y * pos.y; - moduleFullRoi.ymax = numChansPerMod.y * (pos.y + 1) - 1; - } - - // no roi - if (arg.xmin > moduleFullRoi.xmax || - arg.xmax < moduleFullRoi.xmin || - (is2D && (arg.ymin > moduleFullRoi.ymax || - arg.ymax < moduleFullRoi.ymin))) { - moduleRoi.setNoRoi(); - } - // incomplete module roi - else if (arg.xmin > moduleFullRoi.xmin || - arg.xmax < moduleFullRoi.xmax || - (is2D && (arg.ymin > moduleFullRoi.ymin || - arg.ymax < moduleFullRoi.ymax))) { - moduleRoi.xmin = (arg.xmin <= moduleFullRoi.xmin) - ? 0 - : (arg.xmin % numChansPerMod.x); - moduleRoi.xmax = (arg.xmax >= moduleFullRoi.xmax) - ? numChansPerMod.x - 1 - : (arg.xmax % numChansPerMod.x); - if (is2D) { - moduleRoi.ymin = (arg.ymin <= moduleFullRoi.ymin) - ? 0 - : (arg.ymin % numChansPerMod.y); - moduleRoi.ymax = (arg.ymax >= moduleFullRoi.ymax) - ? numChansPerMod.y - 1 - : (arg.ymax % numChansPerMod.y); - } - } - } - } - modules[iModule]->setRxROI(moduleRoi); - } - // updating shm rx_roi for gui purposes - shm()->rx_roi = arg; - - // metadata - if (arg.completeRoi()) { - modules[0]->setRxROIMetadata(defs::ROI(0, shm()->numberOfChannels.x - 1, - 0, - shm()->numberOfChannels.y - 1)); - } else { - modules[0]->setRxROIMetadata(arg); - } - */ +//TODO } void DetectorImpl::clearRxROI() { - ;//Parallel(&Module::setRxROI, {}, defs::ROI{}); TODO: clear roi + ;// TODO: clear roi } int DetectorImpl::getNumberOfUdpPortsInRxROI() const { From 56aa96e9b589a0b2551f8bb4fca74742f1e6f5fd Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Tue, 17 Jun 2025 00:00:50 +0200 Subject: [PATCH 03/49] wip to parse vector of rois at command line --- slsDetectorSoftware/generator/Caller.in.h | 1 + slsDetectorSoftware/generator/commands.yaml | 32 ++--- slsDetectorSoftware/include/sls/Detector.h | 3 +- slsDetectorSoftware/src/Caller.cpp | 4 +- slsDetectorSoftware/src/Caller.h | 9 +- slsDetectorSoftware/src/CallerSpecial.cpp | 114 +++++++++++++++--- slsDetectorSoftware/src/Detector.cpp | 7 +- slsDetectorSoftware/src/DetectorImpl.cpp | 54 +++++---- slsDetectorSoftware/src/DetectorImpl.h | 8 +- slsDetectorSoftware/src/Module.h | 6 +- slsDetectorSoftware/tests/CMakeLists.txt | 1 - .../tests/Caller/test-Caller-rx.cpp | 69 +++++++++++ slsDetectorSoftware/tests/test-Roi.cpp | 84 ------------- slsSupportLib/include/sls/ToString.h | 18 +++ 14 files changed, 244 insertions(+), 166 deletions(-) delete mode 100644 slsDetectorSoftware/tests/test-Roi.cpp diff --git a/slsDetectorSoftware/generator/Caller.in.h b/slsDetectorSoftware/generator/Caller.in.h index f1a3a2821..de91b2abc 100644 --- a/slsDetectorSoftware/generator/Caller.in.h +++ b/slsDetectorSoftware/generator/Caller.in.h @@ -21,6 +21,7 @@ class Caller { UdpDestination getUdpEntry(); int GetLevelAndInsertIntoArgs(std::string levelSeparatedCommand); void WrongNumberOfParameters(size_t expected); + std::vector parseRoiVector(const std::string &input); template std::string OutStringHex(const V &value) { if (value.equal()) diff --git a/slsDetectorSoftware/generator/commands.yaml b/slsDetectorSoftware/generator/commands.yaml index 3b96e48f5..1ae493055 100644 --- a/slsDetectorSoftware/generator/commands.yaml +++ b/slsDetectorSoftware/generator/commands.yaml @@ -1739,13 +1739,12 @@ readout: PUT: function: startDetectorReadout -# TODO -#rx_clearroi: -# inherit_actions: EXECUTE_SET_COMMAND_NOID -# help: "\n\tResets Region of interest in receiver. Default is all channels/pixels enabled." -# actions: -# PUT: -# function: clearRxROI +rx_clearroi: + inherit_actions: EXECUTE_SET_COMMAND_NOID + help: "\n\tResets Region of interest in receiver. Default is all channels/pixels enabled." + actions: + PUT: + function: clearRxROI ################# EXECUTE_SET_COMMAND ######################## start: @@ -2593,18 +2592,13 @@ rx_zmqip: PUT: argc: -1 -#TODO -#rx_roi: -# is_description: true -# actions: -# GET: -# argc: 0 -# PUT: -# args: -# - argc: 2 -# arg_types: [ int, int ] -# - argc: 4 -# arg_types: [ int, int, int, int ] +rx_roi: + is_description: true + actions: + GET: + argc: 0 + PUT: + argc: -1 ratecorr: is_description: true diff --git a/slsDetectorSoftware/include/sls/Detector.h b/slsDetectorSoftware/include/sls/Detector.h index fd85e427a..ae407f22b 100644 --- a/slsDetectorSoftware/include/sls/Detector.h +++ b/slsDetectorSoftware/include/sls/Detector.h @@ -988,13 +988,12 @@ class Detector { std::vector getRxROI() const; /** only at multi module level without gap pixels */ - void setRxROI(const std::vector& args); + void setRxROI(const std::vector &args); void clearRxROI(); int getNumberOfUdpPortsInRxROI() const; - ///@} /** @name File */ diff --git a/slsDetectorSoftware/src/Caller.cpp b/slsDetectorSoftware/src/Caller.cpp index 9fb08ff69..78a6f79d7 100644 --- a/slsDetectorSoftware/src/Caller.cpp +++ b/slsDetectorSoftware/src/Caller.cpp @@ -10594,7 +10594,7 @@ std::string Caller::rx_arping(int action) { return os.str(); } -/* + std::string Caller::rx_clearroi(int action) { std::ostringstream os; @@ -10637,7 +10637,7 @@ std::string Caller::rx_clearroi(int action) { return os.str(); } -*/ + std::string Caller::rx_dbitoffset(int action) { std::ostringstream os; diff --git a/slsDetectorSoftware/src/Caller.h b/slsDetectorSoftware/src/Caller.h index d1df0c0f2..5a667938f 100644 --- a/slsDetectorSoftware/src/Caller.h +++ b/slsDetectorSoftware/src/Caller.h @@ -21,6 +21,7 @@ class Caller { UdpDestination getUdpEntry(); int GetLevelAndInsertIntoArgs(std::string levelSeparatedCommand); void WrongNumberOfParameters(size_t expected); + std::vector parseRoiVector(const std::string &input); template std::string OutStringHex(const V &value) { if (value.equal()) @@ -233,7 +234,7 @@ class Caller { std::string runclk(int action); std::string runtime(int action); std::string rx_arping(int action); - //std::string rx_clearroi(int action); + std::string rx_clearroi(int action); std::string rx_dbitlist(int action); std::string rx_dbitoffset(int action); std::string rx_dbitreorder(int action); @@ -251,7 +252,7 @@ class Caller { std::string rx_padding(int action); std::string rx_printconfig(int action); std::string rx_realudpsocksize(int action); - //std::string rx_roi(int action); + std::string rx_roi(int action); std::string rx_silent(int action); std::string rx_start(int action); std::string rx_status(int action); @@ -580,7 +581,7 @@ class Caller { {"runclk", &Caller::runclk}, {"runtime", &Caller::runtime}, {"rx_arping", &Caller::rx_arping}, - //{"rx_clearroi", &Caller::rx_clearroi}, + {"rx_clearroi", &Caller::rx_clearroi}, {"rx_dbitlist", &Caller::rx_dbitlist}, {"rx_dbitoffset", &Caller::rx_dbitoffset}, {"rx_dbitreorder", &Caller::rx_dbitreorder}, @@ -598,7 +599,7 @@ class Caller { {"rx_padding", &Caller::rx_padding}, {"rx_printconfig", &Caller::rx_printconfig}, {"rx_realudpsocksize", &Caller::rx_realudpsocksize}, - //{"rx_roi", &Caller::rx_roi}, + {"rx_roi", &Caller::rx_roi}, {"rx_silent", &Caller::rx_silent}, {"rx_start", &Caller::rx_start}, {"rx_status", &Caller::rx_status}, diff --git a/slsDetectorSoftware/src/CallerSpecial.cpp b/slsDetectorSoftware/src/CallerSpecial.cpp index 394a9d5e7..033224ad8 100644 --- a/slsDetectorSoftware/src/CallerSpecial.cpp +++ b/slsDetectorSoftware/src/CallerSpecial.cpp @@ -719,50 +719,124 @@ std::string Caller::rx_zmqip(int action) { } return os.str(); } -/* TODO + std::string Caller::rx_roi(int action) { std::ostringstream os; if (action == defs::HELP_ACTION) { os << "[xmin] [xmax] [ymin] [ymax]\n\tRegion of interest in " - "receiver.\n\tOnly allowed at multi module level and without gap " + "receiver.\n\t" + << "For a list of rois, use '[' and '];' to distinguish between " + "rois and use comma inside the square brackets.\n\t" + << "For example: [0, 100, 0, 100];[200, 300, 0, 100] will set two " + "rois.\n\t" + << "Only allowed at multi module level and without gap " "pixels." << '\n'; } else if (action == defs::GET_ACTION) { if (!args.empty()) { WrongNumberOfParameters(0); } - if (det_id == -1) { - auto t = det->getRxROI(); - os << t << '\n'; + if (det_id != -1) { + throw RuntimeError("Cannot execute receiver ROI at module level"); } else { - auto t = det->getIndividualRxROIs(std::vector{det_id}); - os << t << '\n'; + auto t = det->getRxROI(); + // os << ToString(t) << '\n'; + for (const auto &r : t) { + os << r << ';'; + } + if (!t.empty()) { + os.seekp(-1, std::ios_base::end); // remove trailing ; + } + os << '\n'; } } else if (action == defs::PUT_ACTION) { - defs::ROI t; - // 2 or 4 arguments - if (args.size() != 2 && args.size() != 4) { - WrongNumberOfParameters(2); - } - if (args.size() == 2 || args.size() == 4) { + std::vector rois; + + // Support multiple args with bracketed ROIs, or single arg with + // semicolon-separated vector + bool isVectorInput = + std::all_of(args.begin(), args.end(), [](const std::string &a) { + return a.find('[') != std::string::npos && + a.find(']') != std::string::npos; + }); + + // previous format: 2 or 4 separate args + if ((args.size() == 2 || args.size() == 4) && !isVectorInput) { + defs::ROI t; t.xmin = StringTo(args[0]); t.xmax = StringTo(args[1]); + if (args.size() == 4) { + t.ymin = StringTo(args[2]); + t.ymax = StringTo(args[3]); + } + rois.emplace_back(t); + } else { + if (!isVectorInput) + WrongNumberOfParameters(2); + else { + for (const auto &arg : args) { + auto subRois = parseRoiVector(arg); + rois.insert(rois.end(), subRois.begin(), subRois.end()); + } + } } - if (args.size() == 4) { - t.ymin = StringTo(args[2]); - t.ymax = StringTo(args[3]); - } + // only multi level if (det_id != -1) { throw RuntimeError("Cannot execute receiver ROI at module level"); } - det->setRxROI(t); - os << t << '\n'; + + det->setRxROI(rois); + // os << ToString(rois) << '\n'; + for (const auto &r : rois) { + os << r << ';'; + } + if (!rois.empty()) { + os.seekp(-1, std::ios_base::end); // remove trailing ; + } + os << '\n'; } else { throw RuntimeError("Unknown action"); } return os.str(); -}*/ +} + +std::vector Caller::parseRoiVector(const std::string &input) { + std::vector rois; + std::stringstream ss(input); + std::string token; + + while (std::getline(ss, token, ';')) { + token.erase(std::remove_if(token.begin(), token.end(), ::isspace), + token.end()); + if (token.empty()) + continue; + if (token.front() != '[' || token.back() != ']') { + throw RuntimeError("Each ROI must be enclosed in square brackets: " + "[xmin,xmax,ymin,ymax]"); + } + token = token.substr(1, token.size() - 2); // remove brackets + std::vector parts; + std::stringstream inner(token); + std::string num; + while (std::getline(inner, num, ',')) { + parts.push_back(num); + } + + if (parts.size() != 4) { + throw RuntimeError("ROI must have 4 comma-separated integers"); + } + + defs::ROI roi; + roi.xmin = StringTo(parts[0]); + roi.xmax = StringTo(parts[1]); + roi.ymin = StringTo(parts[2]); + roi.ymax = StringTo(parts[3]); + rois.emplace_back(roi); + } + return rois; +} + std::string Caller::ratecorr(int action) { std::ostringstream os; if (action == defs::HELP_ACTION) { diff --git a/slsDetectorSoftware/src/Detector.cpp b/slsDetectorSoftware/src/Detector.cpp index 375faaeaa..785868e2d 100644 --- a/slsDetectorSoftware/src/Detector.cpp +++ b/slsDetectorSoftware/src/Detector.cpp @@ -1367,12 +1367,10 @@ void Detector::setRxArping(bool value, Positions pos) { pimpl->Parallel(&Module::setRxArping, pos, value); } -std::vector Detector::getRxROI() const { - return pimpl->getRxROI(); -} +std::vector Detector::getRxROI() const { return pimpl->getRxROI(); } // RxROIs can be set for all types except CTB. At multi level without gap pixels -void Detector::setRxROI(const std::vector& args) { +void Detector::setRxROI(const std::vector &args) { pimpl->setRxROI(args); } @@ -1380,7 +1378,6 @@ void Detector::clearRxROI() { pimpl->clearRxROI(); } int Detector::getNumberOfUdpPortsInRxROI() const { return pimpl->getNumberOfUdpPortsInRxROI(); - } // File diff --git a/slsDetectorSoftware/src/DetectorImpl.cpp b/slsDetectorSoftware/src/DetectorImpl.cpp index 6bd1ae8cc..34e58dc5f 100644 --- a/slsDetectorSoftware/src/DetectorImpl.cpp +++ b/slsDetectorSoftware/src/DetectorImpl.cpp @@ -31,7 +31,6 @@ namespace sls { - DetectorImpl::DetectorImpl(int detector_index, bool verify, bool update) : detectorIndex(detector_index), shm(detector_index, -1), ctb_shm(detector_index, -1, CtbConfig::shm_tag()) { @@ -536,7 +535,7 @@ void DetectorImpl::readFrameFromReceiver() { bool quadEnable = false; // to flip image bool eiger = false; - std::array rxRoi {};//TODO: get roi from json header + std::array rxRoi{}; // TODO: get roi from json header std::vector runningList(zmqSocket.size()); std::vector connectList(zmqSocket.size()); @@ -1703,44 +1702,53 @@ std::vector DetectorImpl::getRxROI() const { throw RuntimeError("No Modules added"); } - return std::vector{}; -//TODO + // return std::vector{}; + return rxRoiTemp; + // 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) { + return !(a.xmax < b.xmin || a.xmin > b.xmax || a.ymax < b.ymin || + a.ymin > b.ymax); } -void DetectorImpl::validateROIs(const std::vector& rois) { +void DetectorImpl::validateROIs(const std::vector &rois) { for (size_t i = 0; i < rois.size(); ++i) { - const auto& roi = rois[i]; + const auto &roi = rois[i]; if (roi.noRoi()) { throw RuntimeError("Invalid Roi of size 0. Roi: " + ToString(roi)); } if (roi.completeRoi()) { throw RuntimeError("Did you mean the clear roi command (API: " - "clearRxROI, cmd: rx_clearroi) Roi: " + ToString(roi) + "?"); + "clearRxROI, cmd: rx_clearroi) Roi: " + + ToString(roi) + "?"); } if (roi.xmin > roi.xmax || roi.ymin > roi.ymax) { throw RuntimeError( - "Invalid Roi. xmin/ymin exceeds xmax/ymax. Roi: " + ToString(roi)); + "Invalid Roi. xmin/ymin exceeds xmax/ymax. Roi: " + + ToString(roi)); } if (roi.xmin < 0 || roi.xmax >= shm()->numberOfChannels.x) { - throw RuntimeError("ROI x-dimension outside detector bounds. Roi: " + ToString(roi)); + throw RuntimeError( + "ROI x-dimension outside detector bounds. Roi: " + + ToString(roi)); } bool is2D = (modules[0]->getNumberOfChannels().y > 1 ? true : false); if (is2D) { if (roi.ymin < 0 || roi.ymax >= shm()->numberOfChannels.y) { - throw RuntimeError("ROI y-dimension outside detector bounds. Roi: " + ToString(roi)); + throw RuntimeError( + "ROI y-dimension outside detector bounds. Roi: " + + ToString(roi)); } } else { - if ((roi.ymin != -1 && roi.ymin != 0) || (roi.ymax != -1 && roi.ymax != 0)) { - throw RuntimeError("Invalid Y range for 1D detector: should be -1. Roi: " + ToString(roi)); + if ((roi.ymin != -1 && roi.ymin != 0) || + (roi.ymax != -1 && roi.ymax != 0)) { + throw RuntimeError( + "Invalid Y range for 1D detector: should be -1. Roi: " + + ToString(roi)); } } @@ -1753,7 +1761,7 @@ void DetectorImpl::validateROIs(const std::vector& rois) { } } -void DetectorImpl::setRxROI(const std::vector& args) { +void DetectorImpl::setRxROI(const std::vector &args) { if (shm()->detType == CHIPTESTBOARD || shm()->detType == defs::XILINX_CHIPTESTBOARD) { throw RuntimeError("RxRoi not implemented for this Detector"); @@ -1761,18 +1769,18 @@ void DetectorImpl::setRxROI(const std::vector& args) { if (modules.size() == 0) { throw RuntimeError("No Modules added"); } - + validateROIs(args); -//TODO + rxRoiTemp = args; + + // TODO } -void DetectorImpl::clearRxROI() { - ;// TODO: clear roi -} +void DetectorImpl::clearRxROI() { rxRoiTemp.clear(); } int DetectorImpl::getNumberOfUdpPortsInRxROI() const { - return 0;// TODO + return 0; // TODO } void DetectorImpl::getBadChannels(const std::string &fname, diff --git a/slsDetectorSoftware/src/DetectorImpl.h b/slsDetectorSoftware/src/DetectorImpl.h index c899566f2..b6a6af905 100644 --- a/slsDetectorSoftware/src/DetectorImpl.h +++ b/slsDetectorSoftware/src/DetectorImpl.h @@ -302,7 +302,7 @@ class DetectorImpl : public virtual slsDetectorDefs { verifyUniqueRxHost(const std::vector &names) const; std::vector getRxROI() const; - void setRxROI(const std::vector& args); + void setRxROI(const std::vector &args); void clearRxROI(); int getNumberOfUdpPortsInRxROI() const; @@ -427,8 +427,8 @@ class DetectorImpl : public virtual slsDetectorDefs { void verifyUniqueHost( bool isDet, std::vector> &hosts) const; - bool roisOverlap(const defs::ROI& a, const defs::ROI& b); - void validateROIs(const std::vector& rois); + bool roisOverlap(const defs::ROI &a, const defs::ROI &b); + void validateROIs(const std::vector &rois); const int detectorIndex{0}; SharedMemory shm{0, -1}; @@ -457,6 +457,8 @@ class DetectorImpl : public virtual slsDetectorDefs { void (*dataReady)(detectorData *, uint64_t, uint32_t, void *){nullptr}; void *pCallbackArg{nullptr}; + + std::vector rxRoiTemp; }; } // namespace sls \ No newline at end of file diff --git a/slsDetectorSoftware/src/Module.h b/slsDetectorSoftware/src/Module.h index a687be6c3..c84fa378b 100644 --- a/slsDetectorSoftware/src/Module.h +++ b/slsDetectorSoftware/src/Module.h @@ -301,9 +301,9 @@ class Module : public virtual slsDetectorDefs { std::array getReceiverThreadIds() const; bool getRxArping() const; void setRxArping(bool enable); - //defs::ROI getRxROI() const; - //void setRxROI(const slsDetectorDefs::ROI arg); - //void setRxROIMetadata(const slsDetectorDefs::ROI arg); + // defs::ROI getRxROI() const; + // void setRxROI(const slsDetectorDefs::ROI arg); + // void setRxROIMetadata(const slsDetectorDefs::ROI arg); /************************************************** * * diff --git a/slsDetectorSoftware/tests/CMakeLists.txt b/slsDetectorSoftware/tests/CMakeLists.txt index f70e393f2..d87f17ed0 100755 --- a/slsDetectorSoftware/tests/CMakeLists.txt +++ b/slsDetectorSoftware/tests/CMakeLists.txt @@ -5,7 +5,6 @@ target_sources(tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/test-SharedMemory.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test-slsDetector.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/test-Roi.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Caller/test-Caller.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Caller/test-Caller-rx.cpp diff --git a/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp b/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp index fcf0de97d..82bc1e2af 100644 --- a/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp +++ b/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp @@ -494,6 +494,42 @@ TEST_CASE("rx_roi", "[.cmdcall]") { 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)); + // 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)); } // 2d else { @@ -521,6 +557,39 @@ TEST_CASE("rx_roi", "[.cmdcall]") { } REQUIRE_THROWS( caller.call("rx_roi", {"-1", "-1", "-1", "-1"}, -1, PUT)); + // vector of rois + { + std::ostringstream oss; + caller.call("rx_roi", {"[5, 10, 20, 30]; [25, 28, 14, 15]"}, -1, + PUT, oss); + 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/slsDetectorSoftware/tests/test-Roi.cpp b/slsDetectorSoftware/tests/test-Roi.cpp deleted file mode 100644 index 9ce6c3b30..000000000 --- a/slsDetectorSoftware/tests/test-Roi.cpp +++ /dev/null @@ -1,84 +0,0 @@ -#include "catch.hpp" -#include - -#include - -#include "DetectorImpl.h" -#include "sls/Detector.h" -#include "Module.h" - -#include - -namespace sls { - -TEST_CASE("ROI validation") { - DetectorImpl det(0, false, false); - det.addTestModule(slsDetectorDefs::JUNGFRAU); - std::cout << "size:"<< det.size() << std::endl; - DetectorImpl detector(0, false, false); - - SECTION("Valid non-overlapping ROIs") { - std::vector rois = { - {0, 10, 0, 10}, - {20, 30, 0, 10}, - {0, 10, 20, 30}, - {40, 50, 0, 10} - }; - REQUIRE_NOTHROW(DetectorImplTestHelper::testValidateRois(detector, rois)); - } - - SECTION("Overlapping ROIs should throw") { - std::vector rois = { - {0, 10, 0, 10}, - {5, 15, 0, 10} - }; - REQUIRE_THROWS_AS(DetectorImplTestHelper::testValidateRois(detector, rois), - sls::RuntimeError); - } - - SECTION("Invalid ROI (xmin > xmax)") { - std::vector rois = { - {12, 8, 0, 10} - }; - REQUIRE_THROWS_AS(DetectorImplTestHelper::testValidateRois(detector, rois), - sls::RuntimeError); - } - - SECTION("Invalid ROI (ymin > ymax)") { - std::vector rois = { - {0, 10, 20, 5} - }; - REQUIRE_THROWS_AS(DetectorImplTestHelper::testValidateRois(detector, rois), - sls::RuntimeError); - } - - SECTION("Invalid ROI (outside detector bounds)") { - // Assuming detector has 100x100 dimensions - detector.setNumberOfChannels({100, 100}); - std::vector rois = { - {95, 105, 0, 10} // xmax out of bounds - }; - REQUIRE_THROWS_AS(DetectorImplTestHelper::testValidateRois(detector, rois), - sls::RuntimeError); - } - - SECTION("Valid ROI for 1D detector") { - detector.setNumberOfChannels({100, 1}); - std::vector rois = { - {10, 20, -1, -1} - }; - REQUIRE_NOTHROW(DetectorImplTestHelper::testValidateRois(detector, rois)); - } - - SECTION("Invalid Y for 1D detector") { - detector.setNumberOfChannels({100, 1}); - std::vector rois = { - {10, 20, 0, 10} // Y should be -1 for 1D - }; - REQUIRE_THROWS_AS(DetectorImplTestHelper::testValidateRois(detector, rois), - sls::RuntimeError); - } -} - - -} // namespace sls diff --git a/slsSupportLib/include/sls/ToString.h b/slsSupportLib/include/sls/ToString.h index ea97a8436..55d6b628b 100644 --- a/slsSupportLib/include/sls/ToString.h +++ b/slsSupportLib/include/sls/ToString.h @@ -348,5 +348,23 @@ std::vector StringTo(const std::vector &strings) { result.push_back(StringTo(s)); return result; } +/* +template +std::string ToString(const std::vector &vec) { + std::ostringstream oss; + oss << "["; + for (size_t i = 0; i < vec.size(); ++i) { + oss << vec[i]; + if (i != vec.size() - 1) + oss << ", "; + } + oss << "]"; + return oss.str(); +}*/ + +/*template +std::ostream &operator<<(std::ostream &os, const std::vector &v) { + return os << ToString(v); +}*/ } // namespace sls From 982383980f0eb505bd079117855be207672e8230 Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Tue, 17 Jun 2025 17:15:12 +0200 Subject: [PATCH 04/49] 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; From 8dd91650782dbfe8c669cce235731ef26a5fc21d Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Wed, 18 Jun 2025 13:56:14 +0200 Subject: [PATCH 05/49] first level test --- slsDetectorSoftware/include/sls/Detector.h | 4 + slsDetectorSoftware/src/CallerSpecial.cpp | 62 +++++----- slsDetectorSoftware/src/Detector.cpp | 16 +++ slsDetectorSoftware/src/DetectorImpl.h | 2 +- .../tests/Caller/test-Caller-rx.cpp | 117 +++++++++++------- 5 files changed, 125 insertions(+), 76 deletions(-) diff --git a/slsDetectorSoftware/include/sls/Detector.h b/slsDetectorSoftware/include/sls/Detector.h index ae407f22b..aaca367ec 100644 --- a/slsDetectorSoftware/include/sls/Detector.h +++ b/slsDetectorSoftware/include/sls/Detector.h @@ -119,6 +119,10 @@ class Detector { Result getModuleSize(Positions pos = {}) const; + defs::xy getPortPerModuleGeometry() const; + + Result getPortSize(Positions pos = {}) const; + /** Gets the actual full detector size. It is the same even if ROI changes */ defs::xy getDetectorSize() const; diff --git a/slsDetectorSoftware/src/CallerSpecial.cpp b/slsDetectorSoftware/src/CallerSpecial.cpp index 033224ad8..bb0cfdf2f 100644 --- a/slsDetectorSoftware/src/CallerSpecial.cpp +++ b/slsDetectorSoftware/src/CallerSpecial.cpp @@ -722,16 +722,15 @@ std::string Caller::rx_zmqip(int action) { std::string Caller::rx_roi(int action) { std::ostringstream os; + std::string helpMessage = std::string("[xmin] [xmax] [ymin] [ymax]\n\tRegion of interest in receiver.\n\t") + + "For a list of rois, use '[' and ']; ' to distinguish between " + "rois and use comma inside the square brackets.\n\t If one fails to use space after semicolon, please use quotes" + + "For example: [0,100,0,100]; [200,300,0,100] will set two " + "rois.or '[0,100,0,100];[200,300,0,100]' when the vector is a single string\n\t" + + "Only allowed at multi module level and without gap " + "pixels.\n"; if (action == defs::HELP_ACTION) { - os << "[xmin] [xmax] [ymin] [ymax]\n\tRegion of interest in " - "receiver.\n\t" - << "For a list of rois, use '[' and '];' to distinguish between " - "rois and use comma inside the square brackets.\n\t" - << "For example: [0, 100, 0, 100];[200, 300, 0, 100] will set two " - "rois.\n\t" - << "Only allowed at multi module level and without gap " - "pixels." - << '\n'; + os << helpMessage; } else if (action == defs::GET_ACTION) { if (!args.empty()) { WrongNumberOfParameters(0); @@ -759,26 +758,29 @@ std::string Caller::rx_roi(int action) { return a.find('[') != std::string::npos && a.find(']') != std::string::npos; }); - - // previous format: 2 or 4 separate args - if ((args.size() == 2 || args.size() == 4) && !isVectorInput) { - defs::ROI t; - t.xmin = StringTo(args[0]); - t.xmax = StringTo(args[1]); - if (args.size() == 4) { - t.ymin = StringTo(args[2]); - t.ymax = StringTo(args[3]); - } - rois.emplace_back(t); - } else { - if (!isVectorInput) - WrongNumberOfParameters(2); - else { - for (const auto &arg : args) { - auto subRois = parseRoiVector(arg); - rois.insert(rois.end(), subRois.begin(), subRois.end()); + try { + // previous format: 2 or 4 separate args + if ((args.size() == 2 || args.size() == 4) && !isVectorInput) { + defs::ROI t; + t.xmin = StringTo(args[0]); + t.xmax = StringTo(args[1]); + if (args.size() == 4) { + t.ymin = StringTo(args[2]); + t.ymax = StringTo(args[3]); + } + rois.emplace_back(t); + } else { + if (!isVectorInput) + WrongNumberOfParameters(2); + else { + for (const auto &arg : args) { + auto subRois = parseRoiVector(arg); + rois.insert(rois.end(), subRois.begin(), subRois.end()); + } } } + } catch (const std::exception &e) { + throw RuntimeError("Could not parse ROI: " + helpMessage); } // only multi level @@ -791,9 +793,9 @@ std::string Caller::rx_roi(int action) { for (const auto &r : rois) { os << r << ';'; } - if (!rois.empty()) { - os.seekp(-1, std::ios_base::end); // remove trailing ; - } + //if (!rois.empty()) { + // os.seekp(-1, std::ios_base::end); // remove trailing ; + //} os << '\n'; } else { throw RuntimeError("Unknown action"); diff --git a/slsDetectorSoftware/src/Detector.cpp b/slsDetectorSoftware/src/Detector.cpp index 785868e2d..960b84654 100644 --- a/slsDetectorSoftware/src/Detector.cpp +++ b/slsDetectorSoftware/src/Detector.cpp @@ -201,6 +201,22 @@ Result Detector::getModuleSize(Positions pos) const { return pimpl->Parallel(&Module::getNumberOfChannels, pos); } +defs::xy Detector::getPortPerModuleGeometry() const { + return pimpl->getPortGeometry(); +} + +Result Detector::getPortSize(Positions pos) const { + Result res = pimpl->Parallel(&Module::getNumberOfChannels, pos); + defs::xy portGeometry = getPortPerModuleGeometry(); + for (auto &it : res) { + if (portGeometry.x == 2) + it.x /= 2; + if (portGeometry.y == 2) + it.y /= 2; + } + return res; +} + defs::xy Detector::getDetectorSize() const { return pimpl->getNumberOfChannels(); } diff --git a/slsDetectorSoftware/src/DetectorImpl.h b/slsDetectorSoftware/src/DetectorImpl.h index b4329de49..4d82088b7 100644 --- a/slsDetectorSoftware/src/DetectorImpl.h +++ b/slsDetectorSoftware/src/DetectorImpl.h @@ -301,6 +301,7 @@ class DetectorImpl : public virtual slsDetectorDefs { std::vector> verifyUniqueRxHost(const std::vector &names) const; + defs::xy getPortGeometry() const; std::vector getRxROI() const; void setRxROI(const std::vector &args); void clearRxROI(); @@ -428,7 +429,6 @@ class DetectorImpl : public virtual slsDetectorDefs { 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( diff --git a/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp b/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp index 45e2b8cc8..aff9ef607 100644 --- a/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp +++ b/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp @@ -466,7 +466,6 @@ TEST_CASE("rx_arping", "[.cmdcall][.rx]") { } } } - TEST_CASE("rx_roi", "[.cmdcall]") { Detector det; Caller caller(&det); @@ -479,8 +478,7 @@ TEST_CASE("rx_roi", "[.cmdcall]") { defs::xy detsize = det.getDetectorSize(); // 1d - if (det_type == defs::GOTTHARD || det_type == defs::GOTTHARD2 || - det_type == defs::MYTHEN3) { + if (det_type == defs::GOTTHARD2 || det_type == defs::MYTHEN3) { { std::ostringstream oss; caller.call("rx_roi", {"5", "10"}, -1, PUT, oss); @@ -491,20 +489,6 @@ TEST_CASE("rx_roi", "[.cmdcall]") { caller.call("rx_roi", {"10", "15"}, -1, PUT, oss); REQUIRE(oss.str() == "rx_roi [10, 15]\n"); } - // vector of rois - // separated by space is allowed - REQUIRE_NOTHROW(caller.call( - "rx_roi", {"[5, 10, -1, -1]", "[25, 28, -1, -1]"}, -1, 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 @@ -516,19 +500,37 @@ TEST_CASE("rx_roi", "[.cmdcall]") { PUT)); // module level not allowed REQUIRE_THROWS(caller.call( - "rx_roi", {"[5, 10, -1, -1]; [25, 28, -1, -1]"}, 0, PUT)); + "rx_roi", {"[5, 10, -1, -1]"}, 0, PUT)); + + // vector of rois + // 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)); // overlapping rois REQUIRE_THROWS(caller.call( "rx_roi", {"[0, 10,-1, -1];[5, 15, -1, -1]"}, -1, PUT)); - // valid - { + + if (det.size() == 2) { + auto moduleSize = det.getModuleSize()[0]; + std::string stringMin = std::to_string(moduleSize.x); + std::string stringMax = std::to_string(moduleSize.x + 1); + + // separated by space is allowed + REQUIRE_NOTHROW(caller.call( + "rx_roi", {"[5, 10, -1, -1]", "[" + stringMin + ", " + stringMax + ", -1, -1]"}, -1, PUT)); 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"); + // separated by semicolon is allowed + REQUIRE_NOTHROW(caller.call( + "rx_roi", {"[5, 10, -1, -1];[" + stringMin + ", " + stringMax + ", -1, -1]"}, -1, PUT, oss)); + REQUIRE(oss.str() == + "rx_roi [5, 10];[" + stringMin + ", " + stringMax + "]\n"); + } } - // 2d + // 2d eiger, jungfrau, moench else { { std::ostringstream oss; @@ -552,21 +554,6 @@ 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( @@ -585,19 +572,58 @@ TEST_CASE("rx_roi", "[.cmdcall]") { PUT)); // module level not allowed REQUIRE_THROWS(caller.call( - "rx_roi", {"[5, 10, 20, 30]; [25, 28, 14, 15]"}, 0, PUT)); + "rx_roi", {"[5, 10, 20, 30]"}, 0, PUT)); + + // vector of rois + // 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)); // 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 - { + + auto portSize = det.getPortSize()[0]; + if (det_type == defs::EIGER) { + std::string stringMin = std::to_string(portSize.x); + std::string stringMax = std::to_string(portSize.x + 1); + + // separated by space is allowed + REQUIRE_NOTHROW(caller.call( + "rx_roi", {"[5, 10, 20, 30]", "[" + stringMin + ", " + stringMax + ", 20, 30]"}, -1, PUT)); std::ostringstream oss; - caller.call("rx_roi", {"[5, 10, 20, 30]; [25, 28, 14, 15]"}, -1, - PUT, oss); + // separated by semicolon is allowed + REQUIRE_NOTHROW(caller.call( + "rx_roi", {"[5, 10, 20, 30];[" + stringMin + ", " + stringMax + ", 20, 30]"}, -1, PUT, oss)); REQUIRE(oss.str() == - "rx_roi [5, 10, 20, 30];[25, 28, 14, 15]\n"); + "rx_roi [5, 10, 20, 30];[" + stringMin + ", " + stringMax + ", 20, 30]\n"); + } + if (det_type == defs::JUNGFRAU || det_type == defs::MOENCH) { + // 2 interfaces or 2 modules + if ((det.getNumberofUDPInterfaces().tsquash( + "inconsistent number of interfaces") == 2) || (det.size() == 2)) { + std::string stringMin = std::to_string(portSize.y); + std::string stringMax = std::to_string(portSize.y + 1); + if (det.size() == 2) { + auto moduleSize = det.getModuleSize()[0]; + stringMin = std::to_string(moduleSize.y); + stringMax = std::to_string(moduleSize.y + 1); + } + + // separated by space is allowed + REQUIRE_NOTHROW(caller.call( + "rx_roi", {"[5, 10, 20, 30]", "[25, 28, " + stringMin + ", " + stringMax + "]"}, -1, PUT)); + std::ostringstream oss; + // separated by semicolon is allowed + REQUIRE_NOTHROW(caller.call( + "rx_roi", {"[5, 10, 20, 30];[25, 28, " + stringMin + ", " + stringMax + "]"}, -1, PUT, oss)); + REQUIRE(oss.str() == + "rx_roi [5, 10, 20, 30];[25, 28, " + stringMin + ", " + stringMax + "]\n"); + } } } @@ -607,6 +633,7 @@ TEST_CASE("rx_roi", "[.cmdcall]") { } } + TEST_CASE("rx_clearroi", "[.cmdcall]") { Detector det; Caller caller(&det); From aac3f8904b30d088b8271efd508c4d0034b3dcfb Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Wed, 18 Jun 2025 17:55:20 +0200 Subject: [PATCH 06/49] can get individual rois, but not connected to command yet --- slsDetectorSoftware/include/sls/Detector.h | 8 ++-- slsDetectorSoftware/src/CallerSpecial.cpp | 18 +-------- slsDetectorSoftware/src/Detector.cpp | 11 ++++-- slsDetectorSoftware/src/DetectorImpl.cpp | 38 ++++++++++--------- slsDetectorSoftware/src/DetectorImpl.h | 2 +- slsDetectorSoftware/src/Module.cpp | 25 ++++++++---- slsDetectorSoftware/src/Module.h | 6 +-- .../tests/Caller/test-Caller-rx.cpp | 18 ++++----- slsSupportLib/include/sls/ToString.h | 17 --------- 9 files changed, 64 insertions(+), 79 deletions(-) diff --git a/slsDetectorSoftware/include/sls/Detector.h b/slsDetectorSoftware/include/sls/Detector.h index aaca367ec..b0a261e94 100644 --- a/slsDetectorSoftware/include/sls/Detector.h +++ b/slsDetectorSoftware/include/sls/Detector.h @@ -989,15 +989,17 @@ class Detector { * every minute. Useful in 10G mode. */ void setRxArping(bool value, Positions pos = {}); + /** Returns multi level ROIs */ std::vector getRxROI() const; - /** only at multi module level without gap pixels */ + /** Returns port level ROIs. Max 2 ports and hence max 2 elements per readout */ + Result> getRxROI(int module_id) const; + + /** only at multi module level without gap pixels. At most, 1 ROI per UDP port */ void setRxROI(const std::vector &args); void clearRxROI(); - int getNumberOfUdpPortsInRxROI() const; - ///@} /** @name File */ diff --git a/slsDetectorSoftware/src/CallerSpecial.cpp b/slsDetectorSoftware/src/CallerSpecial.cpp index bb0cfdf2f..9ceb3803a 100644 --- a/slsDetectorSoftware/src/CallerSpecial.cpp +++ b/slsDetectorSoftware/src/CallerSpecial.cpp @@ -739,14 +739,7 @@ std::string Caller::rx_roi(int action) { throw RuntimeError("Cannot execute receiver ROI at module level"); } else { auto t = det->getRxROI(); - // os << ToString(t) << '\n'; - for (const auto &r : t) { - os << r << ';'; - } - if (!t.empty()) { - os.seekp(-1, std::ios_base::end); // remove trailing ; - } - os << '\n'; + os << ToString(t) << '\n'; } } else if (action == defs::PUT_ACTION) { std::vector rois; @@ -789,14 +782,7 @@ std::string Caller::rx_roi(int action) { } det->setRxROI(rois); - // os << ToString(rois) << '\n'; - for (const auto &r : rois) { - os << r << ';'; - } - //if (!rois.empty()) { - // os.seekp(-1, std::ios_base::end); // remove trailing ; - //} - os << '\n'; + os << ToString(rois) << '\n'; } else { throw RuntimeError("Unknown action"); } diff --git a/slsDetectorSoftware/src/Detector.cpp b/slsDetectorSoftware/src/Detector.cpp index 960b84654..a274f06f7 100644 --- a/slsDetectorSoftware/src/Detector.cpp +++ b/slsDetectorSoftware/src/Detector.cpp @@ -1383,7 +1383,13 @@ void Detector::setRxArping(bool value, Positions pos) { pimpl->Parallel(&Module::setRxArping, pos, value); } -std::vector Detector::getRxROI() const { return pimpl->getRxROI(); } +std::vector Detector::getRxROI() const { + return pimpl->getRxROI(); +} + +Result> Detector::getRxROI(int module_id) const { + return pimpl->Parallel(&Module::getRxROI, {module_id}); +} // RxROIs can be set for all types except CTB. At multi level without gap pixels void Detector::setRxROI(const std::vector &args) { @@ -1392,9 +1398,6 @@ void Detector::setRxROI(const std::vector &args) { void Detector::clearRxROI() { pimpl->clearRxROI(); } -int Detector::getNumberOfUdpPortsInRxROI() const { - return pimpl->getNumberOfUdpPortsInRxROI(); -} // File diff --git a/slsDetectorSoftware/src/DetectorImpl.cpp b/slsDetectorSoftware/src/DetectorImpl.cpp index 7e405d7a8..1fa906dc3 100644 --- a/slsDetectorSoftware/src/DetectorImpl.cpp +++ b/slsDetectorSoftware/src/DetectorImpl.cpp @@ -1791,7 +1791,7 @@ defs::ROI DetectorImpl::getModuleROI(int moduleIndex) const { void DetectorImpl::convertGlobalRoiToPortLevel( const defs::ROI &userRoi, const defs::ROI &moduleRoi, - std::vector> &portRois) const { + std::array &portRois) const { const defs::xy modSize = modules[0]->getNumberOfChannels(); const defs::xy geometry = getPortGeometry(); const int numPorts = geometry.x * geometry.y; @@ -1827,16 +1827,13 @@ void DetectorImpl::convertGlobalRoiToPortLevel( } // 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)); - } + if (!portRois[port].completeRoi()) { + throw RuntimeError( + "Multiple ROIs specified for the same port " + + std::to_string(port) + + " with ROI: " + ToString(userRoi)); } - - portRois.push_back({{port, clipped}}); + portRois[port] = clipped; } } } @@ -1856,7 +1853,7 @@ void DetectorImpl::setRxROI(const std::vector &args) { auto moduleGlobalRoi = getModuleROI(iModule); // at most 2 rois per module (for each port) - std::vector> portRois; + std::array portRois{}; for (const auto &arg : args) { if (roisOverlap(arg, moduleGlobalRoi)) { @@ -1865,18 +1862,23 @@ void DetectorImpl::setRxROI(const std::vector &args) { } // 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); - } + for (size_t iPort = 0; iPort != 2; iPort++) { + LOG(logINFOBLUE) + << " Port " << iPort << ": " << ToString(portRois[iPort]); } - // modules[iModule]->setRxROIs(portRois); TODO + modules[iModule]->setRxROI(portRois); } rxRoiTemp = args; + // metadata + modules[0]->setRxROIMetadata(args); } -void DetectorImpl::clearRxROI() { rxRoiTemp.clear(); } +void DetectorImpl::clearRxROI() { + rxRoiTemp.clear(); + for (size_t iModule = 0; iModule < modules.size(); ++iModule) { + modules[iModule]->setRxROI(std::array{}); + } +} int DetectorImpl::getNumberOfUdpPortsInRxROI() const { return 0; // TODO diff --git a/slsDetectorSoftware/src/DetectorImpl.h b/slsDetectorSoftware/src/DetectorImpl.h index 4d82088b7..a43707c0c 100644 --- a/slsDetectorSoftware/src/DetectorImpl.h +++ b/slsDetectorSoftware/src/DetectorImpl.h @@ -433,7 +433,7 @@ class DetectorImpl : public virtual slsDetectorDefs { defs::ROI getModuleROI(int moduleIndex) const; void convertGlobalRoiToPortLevel( const defs::ROI &userRoi, const defs::ROI &moduleRoi, - std::vector> &portRois) const; + std::array &portRois) const; const int detectorIndex{0}; SharedMemory shm{0, -1}; diff --git a/slsDetectorSoftware/src/Module.cpp b/slsDetectorSoftware/src/Module.cpp index 47f4ffe79..25af1c403 100644 --- a/slsDetectorSoftware/src/Module.cpp +++ b/slsDetectorSoftware/src/Module.cpp @@ -1520,20 +1520,29 @@ bool Module::getRxArping() const { void Module::setRxArping(bool enable) { sendToReceiver(F_SET_RECEIVER_ARPING, static_cast(enable), nullptr); } -/* -defs::ROI Module::getRxROI() const { - return sendToReceiver(F_RECEIVER_GET_RECEIVER_ROI); + +std::array Module::getRxROI() const { + return sendToReceiver>(F_RECEIVER_GET_RECEIVER_ROI); } -void Module::setRxROI(const slsDetectorDefs::ROI arg) { - LOG(logDEBUG) << moduleIndex << ": " << arg; - sendToReceiver(F_RECEIVER_SET_RECEIVER_ROI, arg, nullptr); +void Module::setRxROI(std::array portRois) { + /*LOG(logDEBUG) << "Sending to receiver " << moduleIndex << " [rx roi: " << ToString(portRois) + << ']'; + auto receiver = ReceiverSocket(shm()->rxHostname, shm()->rxTCPPort); + receiver.Send(F_RECEIVER_SET_RECEIVER_ROI); + receiver.setFnum(F_RECEIVER_SET_RECEIVER_ROI); + receiver.Send(portRois); + if (receiver.Receive() == FAIL) { + throw ReceiverError("Receiver " + std::to_string(moduleIndex) + + " returned error: " + receiver.readErrorMessage()); + }*/ + sendToReceiver(F_RECEIVER_SET_RECEIVER_ROI, portRois, nullptr); } -void Module::setRxROIMetadata(const slsDetectorDefs::ROI arg) { +void Module::setRxROIMetadata(const std::vector &arg) { sendToReceiver(F_RECEIVER_SET_RECEIVER_ROI_METADATA, arg, nullptr); } -*/ + // File slsDetectorDefs::fileFormat Module::getFileFormat() const { return sendToReceiver(F_GET_RECEIVER_FILE_FORMAT); diff --git a/slsDetectorSoftware/src/Module.h b/slsDetectorSoftware/src/Module.h index c84fa378b..ca79f44d7 100644 --- a/slsDetectorSoftware/src/Module.h +++ b/slsDetectorSoftware/src/Module.h @@ -301,9 +301,9 @@ class Module : public virtual slsDetectorDefs { std::array getReceiverThreadIds() const; bool getRxArping() const; void setRxArping(bool enable); - // defs::ROI getRxROI() const; - // void setRxROI(const slsDetectorDefs::ROI arg); - // void setRxROIMetadata(const slsDetectorDefs::ROI arg); + std::array getRxROI() const; + void setRxROI(const std::array portRois); + void setRxROIMetadata(const std::vector &args); /************************************************** * * diff --git a/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp b/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp index aff9ef607..72d4c23a0 100644 --- a/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp +++ b/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp @@ -482,12 +482,12 @@ TEST_CASE("rx_roi", "[.cmdcall]") { { std::ostringstream oss; caller.call("rx_roi", {"5", "10"}, -1, PUT, oss); - REQUIRE(oss.str() == "rx_roi [5, 10]\n"); + REQUIRE(oss.str() == "rx_roi [[5, 10]]\n"); } { std::ostringstream oss; caller.call("rx_roi", {"10", "15"}, -1, PUT, oss); - REQUIRE(oss.str() == "rx_roi [10, 15]\n"); + REQUIRE(oss.str() == "rx_roi [[10, 15]]\n"); } REQUIRE_THROWS(caller.call("rx_roi", {"0", "0"}, -1, PUT)); REQUIRE_THROWS(caller.call("rx_roi", {"-1", "-1"}, -1, PUT)); @@ -526,7 +526,7 @@ TEST_CASE("rx_roi", "[.cmdcall]") { REQUIRE_NOTHROW(caller.call( "rx_roi", {"[5, 10, -1, -1];[" + stringMin + ", " + stringMax + ", -1, -1]"}, -1, PUT, oss)); REQUIRE(oss.str() == - "rx_roi [5, 10];[" + stringMin + ", " + stringMax + "]\n"); + "rx_roi [[5, 10], [" + stringMin + ", " + stringMax + "]]\n"); } } @@ -535,12 +535,12 @@ TEST_CASE("rx_roi", "[.cmdcall]") { { std::ostringstream oss; caller.call("rx_roi", {"10", "15", "1", "5"}, -1, PUT, oss); - REQUIRE(oss.str() == "rx_roi [10, 15, 1, 5]\n"); + REQUIRE(oss.str() == "rx_roi [[10, 15, 1, 5]]\n"); } { std::ostringstream oss; caller.call("rx_roi", {"10", "22", "18", "19"}, -1, PUT, oss); - REQUIRE(oss.str() == "rx_roi [10, 22, 18, 19]\n"); + REQUIRE(oss.str() == "rx_roi [[10, 22, 18, 19]]\n"); } { std::ostringstream oss; @@ -548,11 +548,11 @@ TEST_CASE("rx_roi", "[.cmdcall]") { {"1", std::to_string(detsize.x - 5), "1", std::to_string(detsize.y - 5)}, -1, PUT, oss); - REQUIRE(oss.str() == std::string("rx_roi [1, ") + + REQUIRE(oss.str() == std::string("rx_roi [[1, ") + std::to_string(detsize.x - 5) + std::string(", 1, ") + std::to_string(detsize.y - 5) + - std::string("]\n")); + std::string("]]\n")); } REQUIRE_THROWS( caller.call("rx_roi", {"0", "0", "0", "0"}, -1, PUT)); @@ -600,7 +600,7 @@ TEST_CASE("rx_roi", "[.cmdcall]") { REQUIRE_NOTHROW(caller.call( "rx_roi", {"[5, 10, 20, 30];[" + stringMin + ", " + stringMax + ", 20, 30]"}, -1, PUT, oss)); REQUIRE(oss.str() == - "rx_roi [5, 10, 20, 30];[" + stringMin + ", " + stringMax + ", 20, 30]\n"); + "rx_roi [[5, 10, 20, 30], [" + stringMin + ", " + stringMax + ", 20, 30]]\n"); } if (det_type == defs::JUNGFRAU || det_type == defs::MOENCH) { // 2 interfaces or 2 modules @@ -622,7 +622,7 @@ TEST_CASE("rx_roi", "[.cmdcall]") { REQUIRE_NOTHROW(caller.call( "rx_roi", {"[5, 10, 20, 30];[25, 28, " + stringMin + ", " + stringMax + "]"}, -1, PUT, oss)); REQUIRE(oss.str() == - "rx_roi [5, 10, 20, 30];[25, 28, " + stringMin + ", " + stringMax + "]\n"); + "rx_roi [[5, 10, 20, 30], [25, 28, " + stringMin + ", " + stringMax + "]]\n"); } } } diff --git a/slsSupportLib/include/sls/ToString.h b/slsSupportLib/include/sls/ToString.h index 55d6b628b..71d9a1190 100644 --- a/slsSupportLib/include/sls/ToString.h +++ b/slsSupportLib/include/sls/ToString.h @@ -348,23 +348,6 @@ std::vector StringTo(const std::vector &strings) { result.push_back(StringTo(s)); return result; } -/* -template -std::string ToString(const std::vector &vec) { - std::ostringstream oss; - oss << "["; - for (size_t i = 0; i < vec.size(); ++i) { - oss << vec[i]; - if (i != vec.size() - 1) - oss << ", "; - } - oss << "]"; - return oss.str(); -}*/ -/*template -std::ostream &operator<<(std::ostream &os, const std::vector &v) { - return os << ToString(v); -}*/ } // namespace sls From 24f878a17b403a1358c0d610de5a392323707e24 Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Fri, 20 Jun 2025 17:20:19 +0200 Subject: [PATCH 07/49] rois shoudl work. left to implement tests for individual rois, create multiple datasets (1 for each roi) in the virutal data file. currently virutal dataset with roi is not implemented and a warning is given instead. wonder why since the inviduviaual roi files are clipped --- slsDetectorSoftware/src/CallerSpecial.cpp | 23 +- slsDetectorSoftware/src/DetectorImpl.cpp | 1 + slsDetectorSoftware/src/Module.cpp | 26 +- slsDetectorSoftware/src/Module.h | 2 +- slsReceiverSoftware/src/ClientInterface.cpp | 26 +- slsReceiverSoftware/src/DataProcessor.cpp | 36 +-- slsReceiverSoftware/src/DataProcessor.h | 8 +- slsReceiverSoftware/src/DataStreamer.cpp | 11 +- slsReceiverSoftware/src/DataStreamer.h | 4 +- slsReceiverSoftware/src/Implementation.cpp | 131 ++------ slsReceiverSoftware/src/Implementation.h | 11 +- slsReceiverSoftware/src/Listener.cpp | 10 +- slsReceiverSoftware/src/Listener.h | 4 +- slsReceiverSoftware/src/MasterAttributes.cpp | 310 +++++++++---------- slsReceiverSoftware/src/MasterAttributes.h | 75 ++--- 15 files changed, 314 insertions(+), 364 deletions(-) diff --git a/slsDetectorSoftware/src/CallerSpecial.cpp b/slsDetectorSoftware/src/CallerSpecial.cpp index 9ceb3803a..946f92570 100644 --- a/slsDetectorSoftware/src/CallerSpecial.cpp +++ b/slsDetectorSoftware/src/CallerSpecial.cpp @@ -722,13 +722,19 @@ std::string Caller::rx_zmqip(int action) { std::string Caller::rx_roi(int action) { std::ostringstream os; - std::string helpMessage = std::string("[xmin] [xmax] [ymin] [ymax]\n\tRegion of interest in receiver.\n\t") - + "For a list of rois, use '[' and ']; ' to distinguish between " - "rois and use comma inside the square brackets.\n\t If one fails to use space after semicolon, please use quotes" - + "For example: [0,100,0,100]; [200,300,0,100] will set two " - "rois.or '[0,100,0,100];[200,300,0,100]' when the vector is a single string\n\t" - + "Only allowed at multi module level and without gap " - "pixels.\n"; + std::string helpMessage = + std::string("[xmin] [xmax] [ymin] [ymax]\n\tRegion of interest in " + "receiver.\n\t") + + "For a list of rois, use '[' and ']; ' to distinguish between " + "rois and use comma inside the square brackets.\n\t If one fails to " + "use space after semicolon, please use quotes" + + "For example: [0,100,0,100]; [200,300,0,100] will set two " + "rois.or '[0,100,0,100];[200,300,0,100]' when the vector is a single " + "string\n\n\t" + + "Only allowed to set at multi module level and without gap " + "ixels.\n\n\t" + + "One can get rx_roi also at port level, by specifying the module id " + "and it will return the roi for each port.\n"; if (action == defs::HELP_ACTION) { os << helpMessage; } else if (action == defs::GET_ACTION) { @@ -736,7 +742,8 @@ std::string Caller::rx_roi(int action) { WrongNumberOfParameters(0); } if (det_id != -1) { - throw RuntimeError("Cannot execute receiver ROI at module level"); + auto t = det->getRxROI(det_id); + os << ToString(t) << '\n'; } else { auto t = det->getRxROI(); os << ToString(t) << '\n'; diff --git a/slsDetectorSoftware/src/DetectorImpl.cpp b/slsDetectorSoftware/src/DetectorImpl.cpp index 1fa906dc3..66d4b7a73 100644 --- a/slsDetectorSoftware/src/DetectorImpl.cpp +++ b/slsDetectorSoftware/src/DetectorImpl.cpp @@ -1766,6 +1766,7 @@ defs::xy DetectorImpl::getPortGeometry() const { case MOENCH: portGeometry.y = modules[0]->getNumberofUDPInterfacesFromShm(); break; + case GOTTHARD2: // 2nd port if used is for veto, not data default: break; } diff --git a/slsDetectorSoftware/src/Module.cpp b/slsDetectorSoftware/src/Module.cpp index 25af1c403..12b8be264 100644 --- a/slsDetectorSoftware/src/Module.cpp +++ b/slsDetectorSoftware/src/Module.cpp @@ -1525,22 +1525,22 @@ std::array Module::getRxROI() const { return sendToReceiver>(F_RECEIVER_GET_RECEIVER_ROI); } -void Module::setRxROI(std::array portRois) { - /*LOG(logDEBUG) << "Sending to receiver " << moduleIndex << " [rx roi: " << ToString(portRois) - << ']'; - auto receiver = ReceiverSocket(shm()->rxHostname, shm()->rxTCPPort); - receiver.Send(F_RECEIVER_SET_RECEIVER_ROI); - receiver.setFnum(F_RECEIVER_SET_RECEIVER_ROI); - receiver.Send(portRois); - if (receiver.Receive() == FAIL) { - throw ReceiverError("Receiver " + std::to_string(moduleIndex) + - " returned error: " + receiver.readErrorMessage()); - }*/ +void Module::setRxROI(const std::array &portRois) { sendToReceiver(F_RECEIVER_SET_RECEIVER_ROI, portRois, nullptr); } -void Module::setRxROIMetadata(const std::vector &arg) { - sendToReceiver(F_RECEIVER_SET_RECEIVER_ROI_METADATA, arg, nullptr); +void Module::setRxROIMetadata(const std::vector &args) { + LOG(logDEBUG) << "Sending to receiver " << moduleIndex + << " [roi metadata: " << ToString(args) << ']'; + auto receiver = ReceiverSocket(shm()->rxHostname, shm()->rxTCPPort); + receiver.Send(F_RECEIVER_SET_RECEIVER_ROI_METADATA); + receiver.setFnum(F_RECEIVER_SET_RECEIVER_ROI_METADATA); + receiver.Send(static_cast(args.size())); + receiver.Send(args); + if (receiver.Receive() == FAIL) { + throw ReceiverError("Receiver " + std::to_string(moduleIndex) + + " returned error: " + receiver.readErrorMessage()); + } } // File diff --git a/slsDetectorSoftware/src/Module.h b/slsDetectorSoftware/src/Module.h index ca79f44d7..47284fec0 100644 --- a/slsDetectorSoftware/src/Module.h +++ b/slsDetectorSoftware/src/Module.h @@ -302,7 +302,7 @@ class Module : public virtual slsDetectorDefs { bool getRxArping() const; void setRxArping(bool enable); std::array getRxROI() const; - void setRxROI(const std::array portRois); + void setRxROI(const std::array &portRois); void setRxROIMetadata(const std::vector &args); /************************************************** diff --git a/slsReceiverSoftware/src/ClientInterface.cpp b/slsReceiverSoftware/src/ClientInterface.cpp index f3de129b5..4a58619ab 100644 --- a/slsReceiverSoftware/src/ClientInterface.cpp +++ b/slsReceiverSoftware/src/ClientInterface.cpp @@ -1693,19 +1693,19 @@ int ClientInterface::set_arping(Interface &socket) { } int ClientInterface::get_receiver_roi(Interface &socket) { - auto retval = impl()->getReceiverROI(); - LOG(logDEBUG1) << "Receiver roi retval:" << ToString(retval); - return socket.sendResult(retval); + auto retvals = impl()->getPortROIs(); + LOG(logDEBUG1) << "Receiver roi retval:" << ToString(retvals); + return socket.sendResult(retvals); } int ClientInterface::set_receiver_roi(Interface &socket) { - auto arg = socket.Receive(); + auto args = socket.Receive>(); if (detType == CHIPTESTBOARD || detType == XILINX_CHIPTESTBOARD) functionNotImplemented(); - LOG(logDEBUG1) << "Set Receiver ROI: " << ToString(arg); + LOG(logDEBUG1) << "Set Receiver ROI: " << ToString(args); verifyIdle(socket); try { - impl()->setReceiverROI(arg); + impl()->setPortROIs(args); } catch (const std::exception &e) { throw RuntimeError("Could not set Receiver ROI [" + std::string(e.what()) + ']'); @@ -1715,18 +1715,24 @@ int ClientInterface::set_receiver_roi(Interface &socket) { } int ClientInterface::set_receiver_roi_metadata(Interface &socket) { - auto arg = socket.Receive(); + auto roiSize = socket.Receive(); + if (roiSize <= 0) { + throw RuntimeError("Invalid number of ReceiverROI metadata: " + + std::to_string(roiSize)); + } + LOG(logDEBUG) << "Number of ReceiverROI metadata: " << roiSize; + std::vector rois(roiSize); + socket.Receive(rois); if (detType == CHIPTESTBOARD || detType == XILINX_CHIPTESTBOARD) functionNotImplemented(); - LOG(logDEBUG1) << "Set Receiver ROI Metadata: " << ToString(arg); verifyIdle(socket); + LOG(logINFO) << "Setting ReceiverROI metadata[" << roiSize << ']'; try { - impl()->setReceiverROIMetadata(arg); + impl()->setMultiROIMetadata(rois); } catch (const std::exception &e) { throw RuntimeError("Could not set ReceiverROI metadata [" + std::string(e.what()) + ']'); } - return socket.Send(OK); } diff --git a/slsReceiverSoftware/src/DataProcessor.cpp b/slsReceiverSoftware/src/DataProcessor.cpp index 9cedcd522..7a02d2f62 100644 --- a/slsReceiverSoftware/src/DataProcessor.cpp +++ b/slsReceiverSoftware/src/DataProcessor.cpp @@ -48,10 +48,10 @@ void DataProcessor::SetUdpPortNumber(const uint16_t portNumber) { void DataProcessor::SetActivate(bool enable) { activated = enable; } -void DataProcessor::SetReceiverROI(ROI roi) { - receiverRoi = roi; - receiverRoiEnabled = receiverRoi.completeRoi() ? false : true; - receiverNoRoi = receiverRoi.noRoi(); +void DataProcessor::SetPortROI(ROI roi) { + portRoi = roi; + isPartiallyInRoi = portRoi.completeRoi() ? false : true; + isOutsideRoi = portRoi.noRoi(); } void DataProcessor::SetDataStreamEnable(bool enable) { @@ -154,17 +154,17 @@ void DataProcessor::CreateFirstFiles(const std::string &fileNamePrefix, CloseFiles(); // deactivated (half module/ single port or no roi), dont write file - if (!activated || !detectorDataStream || receiverNoRoi) { + if (!activated || !detectorDataStream || isOutsideRoi) { return; } #ifdef HDF5C int nx = generalData->nPixelsX; int ny = generalData->nPixelsY; - if (receiverRoiEnabled) { - nx = receiverRoi.xmax - receiverRoi.xmin + 1; - ny = receiverRoi.ymax - receiverRoi.ymin + 1; - if (receiverRoi.ymax == -1 || receiverRoi.ymin == -1) { + if (isPartiallyInRoi) { + nx = portRoi.xmax - portRoi.xmin + 1; + ny = portRoi.ymax - portRoi.ymin + 1; + if (portRoi.ymax == -1 || portRoi.ymin == -1) { ny = 1; } } @@ -203,7 +203,7 @@ std::string DataProcessor::CreateVirtualFile( const int modulePos, const int numModX, const int numModY, std::mutex *hdf5LibMutex) { - if (receiverRoiEnabled) { + if (isPartiallyInRoi) { throw std::runtime_error( "Skipping virtual hdf5 file since rx_roi is enabled."); } @@ -235,7 +235,7 @@ void DataProcessor::LinkFileInMaster(const std::string &masterFileName, const bool silentMode, std::mutex *hdf5LibMutex) { - if (receiverRoiEnabled) { + if (isPartiallyInRoi) { throw std::runtime_error( "Should not be here, roi with hdf5 virtual should throw."); } @@ -301,7 +301,7 @@ void DataProcessor::ThreadExecution() { // stream (if time/freq to stream) or free if (streamCurrentFrame) { // copy the complete image back if roi enabled - if (receiverRoiEnabled) { + if (isPartiallyInRoi) { memImage->size = generalData->imageSize; memcpy(memImage->data, &completeImageToStreamBeforeCropping[0], generalData->imageSize); @@ -381,7 +381,7 @@ void DataProcessor::ProcessAnImage(sls_receiver_header &header, size_t &size, streamCurrentFrame = false; } - if (receiverRoiEnabled) { + if (isPartiallyInRoi) { // copy the complete image to stream before cropping if (streamCurrentFrame) { memcpy(&completeImageToStreamBeforeCropping[0], data, @@ -687,12 +687,12 @@ void DataProcessor::ArrangeDbitData(size_t &size, char *data) { } void DataProcessor::CropImage(size_t &size, char *data) { - LOG(logDEBUG) << "Cropping Image to ROI " << ToString(receiverRoi); + LOG(logDEBUG) << "Cropping Image to ROI " << ToString(portRoi); int nPixelsX = generalData->nPixelsX; - int xmin = receiverRoi.xmin; - int xmax = receiverRoi.xmax; - int ymin = receiverRoi.ymin; - int ymax = receiverRoi.ymax; + int xmin = portRoi.xmin; + int xmax = portRoi.xmax; + int ymin = portRoi.ymin; + int ymax = portRoi.ymax; int xwidth = xmax - xmin + 1; int ywidth = ymax - ymin + 1; if (ymin == -1 || ymax == -1) { diff --git a/slsReceiverSoftware/src/DataProcessor.h b/slsReceiverSoftware/src/DataProcessor.h index 2f1c8f4ba..a53e38de4 100644 --- a/slsReceiverSoftware/src/DataProcessor.h +++ b/slsReceiverSoftware/src/DataProcessor.h @@ -39,7 +39,7 @@ class DataProcessor : private virtual slsDetectorDefs, public ThreadObject { void SetUdpPortNumber(const uint16_t portNumber); void SetActivate(bool enable); - void SetReceiverROI(ROI roi); + void SetPortROI(const ROI arg); void SetDataStreamEnable(bool enable); void SetStreamingFrequency(uint32_t value); void SetStreamingTimerInMs(uint32_t value); @@ -159,9 +159,9 @@ class DataProcessor : private virtual slsDetectorDefs, public ThreadObject { uint16_t udpPortNumber{0}; bool dataStreamEnable; bool activated{false}; - ROI receiverRoi{}; - bool receiverRoiEnabled{false}; - bool receiverNoRoi{false}; + ROI portRoi{}; + bool isPartiallyInRoi{false}; + bool isOutsideRoi{false}; std::unique_ptr completeImageToStreamBeforeCropping; /** if 0, sending random images with a timer */ uint32_t streamingFrequency; diff --git a/slsReceiverSoftware/src/DataStreamer.cpp b/slsReceiverSoftware/src/DataStreamer.cpp index c1b31b75b..f2f6a4b9e 100644 --- a/slsReceiverSoftware/src/DataStreamer.cpp +++ b/slsReceiverSoftware/src/DataStreamer.cpp @@ -53,7 +53,14 @@ void DataStreamer::SetAdditionalJsonHeader( isAdditionalJsonUpdated = true; } -void DataStreamer::SetReceiverROI(ROI roi) { receiverRoi = roi; } +void DataStreamer::SetPortROI(ROI roi) { + if (roi.completeRoi()) { + portRoi = + ROI(0, generalData->nPixelsX - 1, 0, generalData->nPixelsY - 1); + } else { + portRoi = roi; + } +} void DataStreamer::ResetParametersforNewAcquisition(const std::string &fname) { StopRunning(); @@ -210,7 +217,7 @@ int DataStreamer::SendDataHeader(sls_detector_header header, uint32_t size, isAdditionalJsonUpdated = false; } zHeader.addJsonHeader = localAdditionalJsonHeader; - zHeader.rx_roi = receiverRoi.getIntArray(); + zHeader.rx_roi = portRoi.getIntArray(); return zmqSocket->SendHeader(index, zHeader); } diff --git a/slsReceiverSoftware/src/DataStreamer.h b/slsReceiverSoftware/src/DataStreamer.h index dc28e35ac..d8eaaabcf 100644 --- a/slsReceiverSoftware/src/DataStreamer.h +++ b/slsReceiverSoftware/src/DataStreamer.h @@ -38,7 +38,7 @@ class DataStreamer : private virtual slsDetectorDefs, public ThreadObject { void SetNumberofTotalFrames(uint64_t value); void SetAdditionalJsonHeader(const std::map &json); - void SetReceiverROI(ROI roi); + void SetPortROI(ROI roi); void ResetParametersforNewAcquisition(const std::string &fname); /** @@ -91,7 +91,7 @@ class DataStreamer : private virtual slsDetectorDefs, public ThreadObject { uint64_t fileIndex{0}; bool flipRows{false}; std::map additionalJsonHeader; - ROI receiverRoi{}; + ROI portRoi{}; /** Used by streamer thread to update local copy (reduce number of locks * during streaming) */ diff --git a/slsReceiverSoftware/src/Implementation.cpp b/slsReceiverSoftware/src/Implementation.cpp index f9480c5d4..adc16a894 100644 --- a/slsReceiverSoftware/src/Implementation.cpp +++ b/slsReceiverSoftware/src/Implementation.cpp @@ -184,7 +184,7 @@ void Implementation::SetupListener(int i) { listener[i]->SetUdpPortNumber(udpPortNum[i]); listener[i]->SetEthernetInterface(eth[i]); listener[i]->SetActivate(activated); - listener[i]->SetNoRoi(portRois[i].noRoi()); + listener[i]->SetIsOutsideRoi(portRois[i].noRoi()); listener[i]->SetDetectorDatastream(detectorDataStream[i]); listener[i]->SetSilentMode(silentMode); } @@ -194,7 +194,7 @@ void Implementation::SetupDataProcessor(int i) { dataProcessor[i]->SetGeneralData(generalData); dataProcessor[i]->SetUdpPortNumber(udpPortNum[i]); dataProcessor[i]->SetActivate(activated); - dataProcessor[i]->SetReceiverROI(portRois[i]); + dataProcessor[i]->SetPortROI(portRois[i]); dataProcessor[i]->SetDataStreamEnable(dataStreamEnable); dataProcessor[i]->SetStreamingFrequency(streamingFrequency); dataProcessor[i]->SetStreamingTimerInMs(streamingTimerInMs); @@ -216,8 +216,7 @@ void Implementation::SetupDataStreamer(int i) { dataStreamer[i]->SetFlipRows(flipRows); dataStreamer[i]->SetNumberofPorts(numPorts); dataStreamer[i]->SetNumberofTotalFrames(numberOfTotalFrames); - dataStreamer[i]->SetReceiverROI( - portRois[i].completeRoi() ? GetMaxROIPerPort() : portRois[i]); + dataStreamer[i]->SetPortROI(portRois[i]); } slsDetectorDefs::xy Implementation::getDetectorSize() const { @@ -233,18 +232,13 @@ const slsDetectorDefs::xy Implementation::GetPortGeometry() const { return portGeometry; } -const slsDetectorDefs::ROI Implementation::GetMaxROIPerPort() const { - return slsDetectorDefs::ROI{0, (int)generalData->nPixelsX - 1, 0, - (int)generalData->nPixelsY - 1}; -} - void Implementation::setDetectorSize(const slsDetectorDefs::xy size) { xy portGeometry = GetPortGeometry(); std::string log_message = "Detector Size (ports): ("; numModules = size; - numPorts.x = portGeometry.x * size.x; - numPorts.y = portGeometry.y * size.y; + numPorts.x = portGeometry.x * numModules.x; + numPorts.y = portGeometry.y * numModules.y; if (quadEnable) { numPorts.x = 1; numPorts.y = 2; @@ -401,97 +395,27 @@ void Implementation::setArping(const bool i, } } -slsDetectorDefs::ROI Implementation::getReceiverROI() const { - return receiverRoi; +std::array Implementation::getPortROIs() const { + return portRois; } -void Implementation::setReceiverROI(const slsDetectorDefs::ROI arg) { - receiverRoi = arg; +void Implementation::setPortROIs(const std::array &args) { + portRois = args; - if (generalData->numUDPInterfaces == 1 || - generalData->detType == slsDetectorDefs::GOTTHARD2) { - portRois[0] = arg; - } else { - slsDetectorDefs::xy nPortDim(generalData->nPixelsX, - generalData->nPixelsY); - - for (int iPort = 0; iPort != generalData->numUDPInterfaces; ++iPort) { - // default init = complete roi - slsDetectorDefs::ROI portRoi{}; - - // no roi - if (arg.noRoi()) { - portRoi.setNoRoi(); - } - - // incomplete roi - else if (!arg.completeRoi()) { - // get port limits - slsDetectorDefs::ROI portFullRoi{0, nPortDim.x - 1, 0, - nPortDim.y - 1}; - if (iPort == 1) { - // left right (eiger) - if (GetPortGeometry().x == 2) { - portFullRoi.xmin += nPortDim.x; - portFullRoi.xmax += nPortDim.x; - } - // top bottom (jungfrau or moench) - else { - portFullRoi.ymin += nPortDim.y; - portFullRoi.ymax += nPortDim.y; - } - } - LOG(logDEBUG) - << iPort << ": portfullroi:" << ToString(portFullRoi); - - // no roi - if (arg.xmin > portFullRoi.xmax || - arg.xmax < portFullRoi.xmin || - arg.ymin > portFullRoi.ymax || - arg.ymax < portFullRoi.ymin) { - portRoi.setNoRoi(); - } - - // incomplete module roi - else if (arg.xmin > portFullRoi.xmin || - arg.xmax < portFullRoi.xmax || - arg.ymin > portFullRoi.ymin || - arg.ymax < portFullRoi.ymax) { - portRoi.xmin = (arg.xmin <= portFullRoi.xmin) - ? 0 - : (arg.xmin % nPortDim.x); - portRoi.xmax = (arg.xmax >= portFullRoi.xmax) - ? nPortDim.x - 1 - : (arg.xmax % nPortDim.x); - portRoi.ymin = (arg.ymin <= portFullRoi.ymin) - ? 0 - : (arg.ymin % nPortDim.y); - portRoi.ymax = (arg.ymax >= portFullRoi.ymax) - ? nPortDim.y - 1 - : (arg.ymax % nPortDim.y); - } - } - portRois[iPort] = portRoi; - } - } for (size_t i = 0; i != listener.size(); ++i) - listener[i]->SetNoRoi(portRois[i].noRoi()); + listener[i]->SetIsOutsideRoi(portRois[i].noRoi()); for (size_t i = 0; i != dataProcessor.size(); ++i) - dataProcessor[i]->SetReceiverROI(portRois[i]); + dataProcessor[i]->SetPortROI(portRois[i]); for (size_t i = 0; i != dataStreamer.size(); ++i) { - dataStreamer[i]->SetReceiverROI( - portRois[i].completeRoi() ? GetMaxROIPerPort() : portRois[i]); - } - LOG(logINFO) << "receiver roi: " << ToString(receiverRoi); - if (generalData->numUDPInterfaces == 2 && - generalData->detType != slsDetectorDefs::GOTTHARD2) { - LOG(logINFO) << "port rois: " << ToString(portRois); + dataStreamer[i]->SetPortROI(portRois[i]); } + LOG(logINFOBLUE) << "Rois (per port): " << ToString(portRois); } -void Implementation::setReceiverROIMetadata(const ROI arg) { - receiverRoiMetadata = arg; - LOG(logINFO) << "receiver roi Metadata: " << ToString(receiverRoiMetadata); +void Implementation::setMultiROIMetadata( + const std::vector &args) { + multiRoiMetadata = args; + LOG(logINFOBLUE) << "Multi ROI Metadata: " << ToString(multiRoiMetadata); } /************************************************** @@ -787,8 +711,7 @@ void Implementation::stopReceiver() { summary = (i == 0 ? "\n\tDeactivated Left Port" : "\n\tDeactivated Right Port"); } else if (portRois[i].noRoi()) { - summary = (i == 0 ? "\n\tNo Roi on Left Port" - : "\n\tNo Roi on Right Port"); + summary = "\n\tNo Roi on Port[" + std::to_string(i) + ']'; } else { std::ostringstream os; os << "\n\tMissing Packets\t\t: " << mpMessage @@ -958,7 +881,19 @@ void Implementation::StartMasterWriter() { masterAttributes.framePadding = framePadding; masterAttributes.scanParams = scanParams; masterAttributes.totalFrames = numberOfTotalFrames; - masterAttributes.receiverRoi = receiverRoiMetadata; + // complete ROI + if (multiRoiMetadata.empty()) { + int nTotalPixelsX = (generalData->nPixelsX * numPorts.x); + int nTotalPixelsY = (generalData->nPixelsY * numPorts.y); + if (nTotalPixelsY == 1) { + masterAttributes.rois.push_back(ROI{0, nTotalPixelsX - 1}); + } else { + masterAttributes.rois.push_back( + ROI{0, nTotalPixelsX - 1, 0, nTotalPixelsY - 1}); + } + } else { + masterAttributes.rois = multiRoiMetadata; + } masterAttributes.exptime = acquisitionTime; masterAttributes.period = acquisitionPeriod; masterAttributes.burstMode = burstMode; @@ -1087,8 +1022,8 @@ void Implementation::setNumberofUDPInterfaces(const int n) { // fifo SetupFifoStructure(); - // recalculate port rois - setReceiverROI(receiverRoi); + // recalculate port rois booleans for listener, processor and streamer + setPortROIs(portRois); // create threads for (int i = 0; i < generalData->numUDPInterfaces; ++i) { diff --git a/slsReceiverSoftware/src/Implementation.h b/slsReceiverSoftware/src/Implementation.h index 9fbf1fd28..2d663b85b 100644 --- a/slsReceiverSoftware/src/Implementation.h +++ b/slsReceiverSoftware/src/Implementation.h @@ -58,9 +58,9 @@ class Implementation : private virtual slsDetectorDefs { bool getArping() const; pid_t getArpingProcessId() const; void setArping(const bool i, const std::vector ips); - ROI getReceiverROI() const; - void setReceiverROI(const ROI arg); - void setReceiverROIMetadata(const ROI arg); + std::array getPortROIs() const; + void setPortROIs(const std::array &args); + void setMultiROIMetadata(const std::vector &args); /************************************************** * * @@ -283,7 +283,6 @@ class Implementation : private virtual slsDetectorDefs { void SetupFifoStructure(); const xy GetPortGeometry() const; - const ROI GetMaxROIPerPort() const; void ResetParametersforNewAcquisition(); void CreateUDPSockets(); void SetupWriter(); @@ -308,10 +307,8 @@ class Implementation : private virtual slsDetectorDefs { bool framePadding{true}; pid_t parentThreadId; pid_t tcpThreadId; - ROI receiverRoi{}; std::array portRois{}; - // receiver roi for complete detector for metadata - ROI receiverRoiMetadata{}; + std::vector multiRoiMetadata{}; // file parameters fileFormat fileFormatType{BINARY}; diff --git a/slsReceiverSoftware/src/Listener.cpp b/slsReceiverSoftware/src/Listener.cpp index 9c465883b..f1450e847 100644 --- a/slsReceiverSoftware/src/Listener.cpp +++ b/slsReceiverSoftware/src/Listener.cpp @@ -85,17 +85,17 @@ void Listener::SetEthernetInterface(const std::string e) { void Listener::SetActivate(bool enable) { activated = enable; - disabledPort = (!activated || !detectorDataStream || noRoi); + disabledPort = (!activated || !detectorDataStream || isOutsideRoi); } void Listener::SetDetectorDatastream(bool enable) { detectorDataStream = enable; - disabledPort = (!activated || !detectorDataStream || noRoi); + disabledPort = (!activated || !detectorDataStream || isOutsideRoi); } -void Listener::SetNoRoi(bool enable) { - noRoi = enable; - disabledPort = (!activated || !detectorDataStream || noRoi); +void Listener::SetIsOutsideRoi(bool enable) { + isOutsideRoi = enable; + disabledPort = (!activated || !detectorDataStream || isOutsideRoi); } void Listener::SetSilentMode(bool enable) { silentMode = enable; } diff --git a/slsReceiverSoftware/src/Listener.h b/slsReceiverSoftware/src/Listener.h index b5d437e64..628c8e349 100644 --- a/slsReceiverSoftware/src/Listener.h +++ b/slsReceiverSoftware/src/Listener.h @@ -43,7 +43,7 @@ class Listener : private virtual slsDetectorDefs, public ThreadObject { void SetEthernetInterface(const std::string e); void SetActivate(bool enable); void SetDetectorDatastream(bool enable); - void SetNoRoi(bool enable); + void SetIsOutsideRoi(bool enable); void SetSilentMode(bool enable); void ResetParametersforNewAcquisition(); @@ -116,7 +116,7 @@ class Listener : private virtual slsDetectorDefs, public ThreadObject { std::string eth; bool activated{false}; bool detectorDataStream{true}; - bool noRoi{false}; + bool isOutsideRoi{false}; bool silentMode; bool disabledPort{false}; diff --git a/slsReceiverSoftware/src/MasterAttributes.cpp b/slsReceiverSoftware/src/MasterAttributes.cpp index 8420e31ad..9eb2bd3a7 100644 --- a/slsReceiverSoftware/src/MasterAttributes.cpp +++ b/slsReceiverSoftware/src/MasterAttributes.cpp @@ -43,30 +43,30 @@ void MasterAttributes::WriteHDF5Attributes(H5::H5File *fd, H5::Group *group) { WriteCommonHDF5Attributes(fd, group); switch (detType) { case slsDetectorDefs::JUNGFRAU: - WriteJungfrauHDF5Attributes(fd, group); + WriteJungfrauHDF5Attributes(group); break; case slsDetectorDefs::MOENCH: - WriteMoenchHDF5Attributes(fd, group); + WriteMoenchHDF5Attributes(group); break; case slsDetectorDefs::EIGER: - WriteEigerHDF5Attributes(fd, group); + WriteEigerHDF5Attributes(group); break; case slsDetectorDefs::MYTHEN3: - WriteMythen3HDF5Attributes(fd, group); + WriteMythen3HDF5Attributes(group); break; case slsDetectorDefs::GOTTHARD2: - WriteGotthard2HDF5Attributes(fd, group); + WriteGotthard2HDF5Attributes(group); break; case slsDetectorDefs::CHIPTESTBOARD: - WriteCtbHDF5Attributes(fd, group); + WriteCtbHDF5Attributes(group); break; case slsDetectorDefs::XILINX_CHIPTESTBOARD: - WriteXilinxCtbHDF5Attributes(fd, group); + WriteXilinxCtbHDF5Attributes(group); break; default: throw RuntimeError("Unknown Detector type to get master attributes"); } - WriteFinalHDF5Attributes(fd, group); + WriteFinalHDF5Attributes(group); } #endif @@ -110,17 +110,6 @@ void MasterAttributes::GetCommonBinaryAttributes( w->String(ToString(scanParams).c_str()); w->Key("Total Frames"); w->Uint64(totalFrames); - w->Key("Receiver Roi"); - w->StartObject(); - w->Key("xmin"); - w->Uint(receiverRoi.xmin); - w->Key("xmax"); - w->Uint(receiverRoi.xmax); - w->Key("ymin"); - w->Uint(receiverRoi.ymin); - w->Key("ymax"); - w->Uint(receiverRoi.ymax); - w->EndObject(); } void MasterAttributes::GetFinalBinaryAttributes( @@ -287,38 +276,9 @@ void MasterAttributes::WriteCommonHDF5Attributes(H5::H5File *fd, "Total Frames", H5::PredType::STD_U64LE, dataspace); dataset.write(&totalFrames, H5::PredType::STD_U64LE); } - // Receiver Roi xmin - { - H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR); - H5::DataSet dataset = group->createDataSet( - "receiver roi xmin", H5::PredType::NATIVE_INT, dataspace); - dataset.write(&receiverRoi.xmin, H5::PredType::NATIVE_INT); - } - // Receiver Roi xmax - { - H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR); - H5::DataSet dataset = group->createDataSet( - "receiver roi xmax", H5::PredType::NATIVE_INT, dataspace); - dataset.write(&receiverRoi.xmax, H5::PredType::NATIVE_INT); - } - // Receiver Roi ymin - { - H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR); - H5::DataSet dataset = group->createDataSet( - "receiver roi ymin", H5::PredType::NATIVE_INT, dataspace); - dataset.write(&receiverRoi.ymin, H5::PredType::NATIVE_INT); - } - // Receiver Roi ymax - { - H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR); - H5::DataSet dataset = group->createDataSet( - "receiver roi ymax", H5::PredType::NATIVE_INT, dataspace); - dataset.write(&receiverRoi.ymax, H5::PredType::NATIVE_INT); - } } -void MasterAttributes::WriteFinalHDF5Attributes(H5::H5File *fd, - H5::Group *group) { +void MasterAttributes::WriteFinalHDF5Attributes(H5::Group *group) { char c[1024]{}; // Total Frames in file { @@ -339,7 +299,20 @@ void MasterAttributes::WriteFinalHDF5Attributes(H5::H5File *fd, } } -void MasterAttributes::WriteHDF5Exptime(H5::H5File *fd, H5::Group *group) { +void MasterAttributes::WriteHDF5ROIs(H5::Group *group) { + hsize_t dims[1] = {rois.size()}; + H5::DataSpace dataspace(1, dims); + H5::StrType strdatatype(H5::PredType::C_S1, 1024); + H5::DataSet dataset = + group->createDataSet("Receiver Rois", strdatatype, dataspace); + std::vector cRois(rois.size()); + for (size_t i = 0; i < rois.size(); ++i) { + strcpy_safe(cRois[i], ToString(rois[i])); + } + dataset.write(cRois.data(), strdatatype); +} + +void MasterAttributes::WriteHDF5Exptime(H5::Group *group) { H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR); H5::StrType strdatatype(H5::PredType::C_S1, 256); H5::DataSet dataset = @@ -349,7 +322,7 @@ void MasterAttributes::WriteHDF5Exptime(H5::H5File *fd, H5::Group *group) { dataset.write(c, strdatatype); } -void MasterAttributes::WriteHDF5Period(H5::H5File *fd, H5::Group *group) { +void MasterAttributes::WriteHDF5Period(H5::Group *group) { H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR); H5::StrType strdatatype(H5::PredType::C_S1, 256); H5::DataSet dataset = @@ -359,7 +332,7 @@ void MasterAttributes::WriteHDF5Period(H5::H5File *fd, H5::Group *group) { dataset.write(c, strdatatype); } -void MasterAttributes::WriteHDF5DynamicRange(H5::H5File *fd, H5::Group *group) { +void MasterAttributes::WriteHDF5DynamicRange(H5::Group *group) { H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR); H5::DataSet dataset = group->createDataSet( "Dynamic Range", H5::PredType::NATIVE_INT, dataspace); @@ -372,30 +345,28 @@ void MasterAttributes::WriteHDF5DynamicRange(H5::H5File *fd, H5::Group *group) { attribute.write(strdatatype, c); } -void MasterAttributes::WriteHDF5TenGiga(H5::H5File *fd, H5::Group *group) { +void MasterAttributes::WriteHDF5TenGiga(H5::Group *group) { H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR); H5::DataSet dataset = group->createDataSet( "Ten Giga Enable", H5::PredType::NATIVE_INT, dataspace); dataset.write(&tenGiga, H5::PredType::NATIVE_INT); } -void MasterAttributes::WriteHDF5NumUDPInterfaces(H5::H5File *fd, - H5::Group *group) { +void MasterAttributes::WriteHDF5NumUDPInterfaces(H5::Group *group) { H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR); H5::DataSet dataset = group->createDataSet( "Number of UDP Interfaces", H5::PredType::NATIVE_INT, dataspace); dataset.write(&numUDPInterfaces, H5::PredType::NATIVE_INT); } -void MasterAttributes::WriteHDF5ReadNRows(H5::H5File *fd, H5::Group *group) { +void MasterAttributes::WriteHDF5ReadNRows(H5::Group *group) { H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR); H5::DataSet dataset = group->createDataSet( "Number of rows", H5::PredType::NATIVE_INT, dataspace); dataset.write(&readNRows, H5::PredType::NATIVE_INT); } -void MasterAttributes::WriteHDF5ThresholdEnergy(H5::H5File *fd, - H5::Group *group) { +void MasterAttributes::WriteHDF5ThresholdEnergy(H5::Group *group) { char c[1024]{}; H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR); H5::DataSet dataset = group->createDataSet( @@ -409,8 +380,7 @@ void MasterAttributes::WriteHDF5ThresholdEnergy(H5::H5File *fd, attribute.write(strdatatype, c); } -void MasterAttributes::WriteHDF5ThresholdEnergies(H5::H5File *fd, - H5::Group *group) { +void MasterAttributes::WriteHDF5ThresholdEnergies(H5::Group *group) { char c[1024]{}; H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR); H5::StrType strdatatype(H5::PredType::C_S1, 1024); @@ -420,7 +390,7 @@ void MasterAttributes::WriteHDF5ThresholdEnergies(H5::H5File *fd, dataset.write(c, strdatatype); } -void MasterAttributes::WriteHDF5SubExpTime(H5::H5File *fd, H5::Group *group) { +void MasterAttributes::WriteHDF5SubExpTime(H5::Group *group) { char c[1024]{}; H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR); H5::StrType strdatatype(H5::PredType::C_S1, 256); @@ -430,7 +400,7 @@ void MasterAttributes::WriteHDF5SubExpTime(H5::H5File *fd, H5::Group *group) { dataset.write(c, strdatatype); } -void MasterAttributes::WriteHDF5SubPeriod(H5::H5File *fd, H5::Group *group) { +void MasterAttributes::WriteHDF5SubPeriod(H5::Group *group) { char c[1024]{}; H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR); H5::StrType strdatatype(H5::PredType::C_S1, 256); @@ -440,15 +410,14 @@ void MasterAttributes::WriteHDF5SubPeriod(H5::H5File *fd, H5::Group *group) { dataset.write(c, strdatatype); } -void MasterAttributes::WriteHDF5SubQuad(H5::H5File *fd, H5::Group *group) { +void MasterAttributes::WriteHDF5SubQuad(H5::Group *group) { H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR); H5::DataSet dataset = group->createDataSet("Quad", H5::PredType::NATIVE_INT, dataspace); dataset.write(&quad, H5::PredType::NATIVE_INT); } -void MasterAttributes::WriteHDF5RateCorrections(H5::H5File *fd, - H5::Group *group) { +void MasterAttributes::WriteHDF5RateCorrections(H5::Group *group) { char c[1024]{}; H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR); H5::StrType strdatatype(H5::PredType::C_S1, 1024); @@ -458,14 +427,14 @@ void MasterAttributes::WriteHDF5RateCorrections(H5::H5File *fd, dataset.write(c, strdatatype); } -void MasterAttributes::WriteHDF5CounterMask(H5::H5File *fd, H5::Group *group) { +void MasterAttributes::WriteHDF5CounterMask(H5::Group *group) { H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR); H5::DataSet dataset = group->createDataSet( "Counter Mask", H5::PredType::STD_U32LE, dataspace); dataset.write(&counterMask, H5::PredType::STD_U32LE); } -void MasterAttributes::WriteHDF5ExptimeArray(H5::H5File *fd, H5::Group *group) { +void MasterAttributes::WriteHDF5ExptimeArray(H5::Group *group) { for (int i = 0; i != 3; ++i) { char c[1024]{}; H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR); @@ -477,8 +446,7 @@ void MasterAttributes::WriteHDF5ExptimeArray(H5::H5File *fd, H5::Group *group) { } } -void MasterAttributes::WriteHDF5GateDelayArray(H5::H5File *fd, - H5::Group *group) { +void MasterAttributes::WriteHDF5GateDelayArray(H5::Group *group) { for (int i = 0; i != 3; ++i) { char c[1024]{}; H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR); @@ -490,14 +458,14 @@ void MasterAttributes::WriteHDF5GateDelayArray(H5::H5File *fd, } } -void MasterAttributes::WriteHDF5Gates(H5::H5File *fd, H5::Group *group) { +void MasterAttributes::WriteHDF5Gates(H5::Group *group) { H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR); H5::DataSet dataset = group->createDataSet("Gates", H5::PredType::STD_U32LE, dataspace); dataset.write(&gates, H5::PredType::STD_U32LE); } -void MasterAttributes::WriteHDF5BurstMode(H5::H5File *fd, H5::Group *group) { +void MasterAttributes::WriteHDF5BurstMode(H5::Group *group) { H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR); H5::StrType strdatatype(H5::PredType::C_S1, 256); H5::DataSet dataset = @@ -507,82 +475,77 @@ void MasterAttributes::WriteHDF5BurstMode(H5::H5File *fd, H5::Group *group) { dataset.write(c, strdatatype); } -void MasterAttributes::WriteHDF5AdcMask(H5::H5File *fd, H5::Group *group) { +void MasterAttributes::WriteHDF5AdcMask(H5::Group *group) { H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR); H5::DataSet dataset = group->createDataSet("ADC Mask", H5::PredType::NATIVE_INT, dataspace); dataset.write(&adcmask, H5::PredType::NATIVE_INT); } -void MasterAttributes::WriteHDF5AnalogFlag(H5::H5File *fd, H5::Group *group) { +void MasterAttributes::WriteHDF5AnalogFlag(H5::Group *group) { H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR); H5::DataSet dataset = group->createDataSet( "Analog Flag", H5::PredType::NATIVE_INT, dataspace); dataset.write(&analog, H5::PredType::NATIVE_INT); } -void MasterAttributes::WriteHDF5AnalogSamples(H5::H5File *fd, - H5::Group *group) { +void MasterAttributes::WriteHDF5AnalogSamples(H5::Group *group) { H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR); H5::DataSet dataset = group->createDataSet( "Analog Samples", H5::PredType::NATIVE_INT, dataspace); dataset.write(&analogSamples, H5::PredType::NATIVE_INT); } -void MasterAttributes::WriteHDF5DigitalFlag(H5::H5File *fd, H5::Group *group) { +void MasterAttributes::WriteHDF5DigitalFlag(H5::Group *group) { H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR); H5::DataSet dataset = group->createDataSet( "Digital Flag", H5::PredType::NATIVE_INT, dataspace); dataset.write(&digital, H5::PredType::NATIVE_INT); } -void MasterAttributes::WriteHDF5DigitalSamples(H5::H5File *fd, - H5::Group *group) { +void MasterAttributes::WriteHDF5DigitalSamples(H5::Group *group) { H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR); H5::DataSet dataset = group->createDataSet( "Digital Samples", H5::PredType::NATIVE_INT, dataspace); dataset.write(&digitalSamples, H5::PredType::NATIVE_INT); } -void MasterAttributes::WriteHDF5DbitOffset(H5::H5File *fd, H5::Group *group) { +void MasterAttributes::WriteHDF5DbitOffset(H5::Group *group) { H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR); H5::DataSet dataset = group->createDataSet( "Dbit Offset", H5::PredType::NATIVE_INT, dataspace); dataset.write(&dbitoffset, H5::PredType::NATIVE_INT); } -void MasterAttributes::WriteHDF5DbitReorder(H5::H5File *fd, H5::Group *group) { +void MasterAttributes::WriteHDF5DbitReorder(H5::Group *group) { H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR); H5::DataSet dataset = group->createDataSet( "Dbit Reorder", H5::PredType::NATIVE_INT, dataspace); dataset.write(&dbitreorder, H5::PredType::NATIVE_INT); } -void MasterAttributes::WriteHDF5DbitList(H5::H5File *fd, H5::Group *group) { +void MasterAttributes::WriteHDF5DbitList(H5::Group *group) { H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR); H5::DataSet dataset = group->createDataSet( "Dbit Bitset List", H5::PredType::STD_U64LE, dataspace); dataset.write(&dbitlist, H5::PredType::STD_U64LE); } -void MasterAttributes::WriteHDF5TransceiverMask(H5::H5File *fd, - H5::Group *group) { +void MasterAttributes::WriteHDF5TransceiverMask(H5::Group *group) { H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR); H5::DataSet dataset = group->createDataSet( "Transceiver Mask", H5::PredType::NATIVE_INT, dataspace); dataset.write(&transceiverMask, H5::PredType::NATIVE_INT); } -void MasterAttributes::WriteHDF5TransceiverFlag(H5::H5File *fd, - H5::Group *group) { +void MasterAttributes::WriteHDF5TransceiverFlag(H5::Group *group) { H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR); H5::DataSet dataset = group->createDataSet( "Transceiver Flag", H5::PredType::NATIVE_INT, dataspace); dataset.write(&transceiver, H5::PredType::NATIVE_INT); } -void MasterAttributes::WriteHDF5TransceiverSamples(H5::H5File *fd, - H5::Group *group) { +void MasterAttributes::WriteHDF5TransceiverSamples(H5::Group *group) { H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR); H5::DataSet dataset = group->createDataSet( "Transceiver Samples", H5::PredType::NATIVE_INT, dataspace); @@ -592,6 +555,13 @@ void MasterAttributes::WriteHDF5TransceiverSamples(H5::H5File *fd, void MasterAttributes::GetJungfrauBinaryAttributes( rapidjson::PrettyWriter *w) { + w->Key("Receiver Rois"); + w->StartArray(); + for (const slsDetectorDefs::ROI &roi : rois) { + std::string roi_str = ToString(roi); + w->String(roi_str.c_str()); + } + w->EndArray(); w->Key("Exptime"); w->String(ToString(exptime).c_str()); w->Key("Period"); @@ -603,17 +573,24 @@ void MasterAttributes::GetJungfrauBinaryAttributes( } #ifdef HDF5C -void MasterAttributes::WriteJungfrauHDF5Attributes(H5::H5File *fd, - H5::Group *group) { - MasterAttributes::WriteHDF5Exptime(fd, group); - MasterAttributes::WriteHDF5Period(fd, group); - MasterAttributes::WriteHDF5NumUDPInterfaces(fd, group); - MasterAttributes::WriteHDF5ReadNRows(fd, group); +void MasterAttributes::WriteJungfrauHDF5Attributes(H5::Group *group) { + MasterAttributes::WriteHDF5ROIs(group); + MasterAttributes::WriteHDF5Exptime(group); + MasterAttributes::WriteHDF5Period(group); + MasterAttributes::WriteHDF5NumUDPInterfaces(group); + MasterAttributes::WriteHDF5ReadNRows(group); } #endif void MasterAttributes::GetMoenchBinaryAttributes( rapidjson::PrettyWriter *w) { + w->Key("Receiver Rois"); + w->StartArray(); + for (const slsDetectorDefs::ROI &roi : rois) { + std::string roi_str = ToString(roi); + w->String(roi_str.c_str()); + } + w->EndArray(); w->Key("Exptime"); w->String(ToString(exptime).c_str()); w->Key("Period"); @@ -625,17 +602,24 @@ void MasterAttributes::GetMoenchBinaryAttributes( } #ifdef HDF5C -void MasterAttributes::WriteMoenchHDF5Attributes(H5::H5File *fd, - H5::Group *group) { - MasterAttributes::WriteHDF5Exptime(fd, group); - MasterAttributes::WriteHDF5Period(fd, group); - MasterAttributes::WriteHDF5NumUDPInterfaces(fd, group); - MasterAttributes::WriteHDF5ReadNRows(fd, group); +void MasterAttributes::WriteMoenchHDF5Attributes(H5::Group *group) { + MasterAttributes::WriteHDF5ROIs(group); + MasterAttributes::WriteHDF5Exptime(group); + MasterAttributes::WriteHDF5Period(group); + MasterAttributes::WriteHDF5NumUDPInterfaces(group); + MasterAttributes::WriteHDF5ReadNRows(group); } #endif void MasterAttributes::GetEigerBinaryAttributes( rapidjson::PrettyWriter *w) { + w->Key("Receiver Rois"); + w->StartArray(); + for (const slsDetectorDefs::ROI &roi : rois) { + std::string roi_str = ToString(roi); + w->String(roi_str.c_str()); + } + w->EndArray(); w->Key("Dynamic Range"); w->Uint(dynamicRange); w->Key("Ten Giga"); @@ -659,23 +643,30 @@ void MasterAttributes::GetEigerBinaryAttributes( } #ifdef HDF5C -void MasterAttributes::WriteEigerHDF5Attributes(H5::H5File *fd, - H5::Group *group) { - MasterAttributes::WriteHDF5DynamicRange(fd, group); - MasterAttributes::WriteHDF5TenGiga(fd, group); - MasterAttributes::WriteHDF5Exptime(fd, group); - MasterAttributes::WriteHDF5Period(fd, group); - MasterAttributes::WriteHDF5ThresholdEnergy(fd, group); - MasterAttributes::WriteHDF5SubExpTime(fd, group); - MasterAttributes::WriteHDF5SubPeriod(fd, group); - MasterAttributes::WriteHDF5SubQuad(fd, group); - MasterAttributes::WriteHDF5ReadNRows(fd, group); - MasterAttributes::WriteHDF5RateCorrections(fd, group); +void MasterAttributes::WriteEigerHDF5Attributes(H5::Group *group) { + MasterAttributes::WriteHDF5ROIs(group); + MasterAttributes::WriteHDF5DynamicRange(group); + MasterAttributes::WriteHDF5TenGiga(group); + MasterAttributes::WriteHDF5Exptime(group); + MasterAttributes::WriteHDF5Period(group); + MasterAttributes::WriteHDF5ThresholdEnergy(group); + MasterAttributes::WriteHDF5SubExpTime(group); + MasterAttributes::WriteHDF5SubPeriod(group); + MasterAttributes::WriteHDF5SubQuad(group); + MasterAttributes::WriteHDF5ReadNRows(group); + MasterAttributes::WriteHDF5RateCorrections(group); } #endif void MasterAttributes::GetMythen3BinaryAttributes( rapidjson::PrettyWriter *w) { + w->Key("Receiver Rois"); + w->StartArray(); + for (const slsDetectorDefs::ROI &roi : rois) { + std::string roi_str = ToString(roi); + w->String(roi_str.c_str()); + } + w->EndArray(); w->Key("Dynamic Range"); w->Uint(dynamicRange); w->Key("Ten Giga"); @@ -699,21 +690,28 @@ void MasterAttributes::GetMythen3BinaryAttributes( } #ifdef HDF5C -void MasterAttributes::WriteMythen3HDF5Attributes(H5::H5File *fd, - H5::Group *group) { - MasterAttributes::WriteHDF5DynamicRange(fd, group); - MasterAttributes::WriteHDF5TenGiga(fd, group); - MasterAttributes::WriteHDF5Period(fd, group); - MasterAttributes::WriteHDF5CounterMask(fd, group); - MasterAttributes::WriteHDF5ExptimeArray(fd, group); - MasterAttributes::WriteHDF5GateDelayArray(fd, group); - MasterAttributes::WriteHDF5Gates(fd, group); - MasterAttributes::WriteHDF5ThresholdEnergies(fd, group); +void MasterAttributes::WriteMythen3HDF5Attributes(H5::Group *group) { + MasterAttributes::WriteHDF5ROIs(group); + MasterAttributes::WriteHDF5DynamicRange(group); + MasterAttributes::WriteHDF5TenGiga(group); + MasterAttributes::WriteHDF5Period(group); + MasterAttributes::WriteHDF5CounterMask(group); + MasterAttributes::WriteHDF5ExptimeArray(group); + MasterAttributes::WriteHDF5GateDelayArray(group); + MasterAttributes::WriteHDF5Gates(group); + MasterAttributes::WriteHDF5ThresholdEnergies(group); } #endif void MasterAttributes::GetGotthard2BinaryAttributes( rapidjson::PrettyWriter *w) { + w->Key("Receiver Rois"); + w->StartArray(); + for (const slsDetectorDefs::ROI &roi : rois) { + std::string roi_str = ToString(roi); + w->String(roi_str.c_str()); + } + w->EndArray(); w->Key("Exptime"); w->String(ToString(exptime).c_str()); w->Key("Period"); @@ -723,11 +721,11 @@ void MasterAttributes::GetGotthard2BinaryAttributes( } #ifdef HDF5C -void MasterAttributes::WriteGotthard2HDF5Attributes(H5::H5File *fd, - H5::Group *group) { - MasterAttributes::WriteHDF5Exptime(fd, group); - MasterAttributes::WriteHDF5Period(fd, group); - MasterAttributes::WriteHDF5BurstMode(fd, group); +void MasterAttributes::WriteGotthard2HDF5Attributes(H5::Group *group) { + MasterAttributes::WriteHDF5ROIs(group); + MasterAttributes::WriteHDF5Exptime(group); + MasterAttributes::WriteHDF5Period(group); + MasterAttributes::WriteHDF5BurstMode(group); } #endif @@ -764,22 +762,21 @@ void MasterAttributes::GetCtbBinaryAttributes( } #ifdef HDF5C -void MasterAttributes::WriteCtbHDF5Attributes(H5::H5File *fd, - H5::Group *group) { - MasterAttributes::WriteHDF5Exptime(fd, group); - MasterAttributes::WriteHDF5Period(fd, group); - MasterAttributes::WriteHDF5TenGiga(fd, group); - MasterAttributes::WriteHDF5AdcMask(fd, group); - MasterAttributes::WriteHDF5AnalogFlag(fd, group); - MasterAttributes::WriteHDF5AnalogSamples(fd, group); - MasterAttributes::WriteHDF5DigitalFlag(fd, group); - MasterAttributes::WriteHDF5DigitalSamples(fd, group); - MasterAttributes::WriteHDF5DbitOffset(fd, group); - MasterAttributes::WriteHDF5DbitReorder(fd, group); - MasterAttributes::WriteHDF5DbitList(fd, group); - MasterAttributes::WriteHDF5TransceiverMask(fd, group); - MasterAttributes::WriteHDF5TransceiverFlag(fd, group); - MasterAttributes::WriteHDF5TransceiverSamples(fd, group); +void MasterAttributes::WriteCtbHDF5Attributes(H5::Group *group) { + MasterAttributes::WriteHDF5Exptime(group); + MasterAttributes::WriteHDF5Period(group); + MasterAttributes::WriteHDF5TenGiga(group); + MasterAttributes::WriteHDF5AdcMask(group); + MasterAttributes::WriteHDF5AnalogFlag(group); + MasterAttributes::WriteHDF5AnalogSamples(group); + MasterAttributes::WriteHDF5DigitalFlag(group); + MasterAttributes::WriteHDF5DigitalSamples(group); + MasterAttributes::WriteHDF5DbitOffset(group); + MasterAttributes::WriteHDF5DbitReorder(group); + MasterAttributes::WriteHDF5DbitList(group); + MasterAttributes::WriteHDF5TransceiverMask(group); + MasterAttributes::WriteHDF5TransceiverFlag(group); + MasterAttributes::WriteHDF5TransceiverSamples(group); } #endif @@ -814,21 +811,20 @@ void MasterAttributes::GetXilinxCtbBinaryAttributes( } #ifdef HDF5C -void MasterAttributes::WriteXilinxCtbHDF5Attributes(H5::H5File *fd, - H5::Group *group) { - MasterAttributes::WriteHDF5Exptime(fd, group); - MasterAttributes::WriteHDF5Period(fd, group); - MasterAttributes::WriteHDF5AdcMask(fd, group); - MasterAttributes::WriteHDF5AnalogFlag(fd, group); - MasterAttributes::WriteHDF5AnalogSamples(fd, group); - MasterAttributes::WriteHDF5DigitalFlag(fd, group); - MasterAttributes::WriteHDF5DigitalSamples(fd, group); - MasterAttributes::WriteHDF5DbitOffset(fd, group); - MasterAttributes::WriteHDF5DbitReorder(fd, group); - MasterAttributes::WriteHDF5DbitList(fd, group); - MasterAttributes::WriteHDF5TransceiverMask(fd, group); - MasterAttributes::WriteHDF5TransceiverFlag(fd, group); - MasterAttributes::WriteHDF5TransceiverSamples(fd, group); +void MasterAttributes::WriteXilinxCtbHDF5Attributes(H5::Group *group) { + MasterAttributes::WriteHDF5Exptime(group); + MasterAttributes::WriteHDF5Period(group); + MasterAttributes::WriteHDF5AdcMask(group); + MasterAttributes::WriteHDF5AnalogFlag(group); + MasterAttributes::WriteHDF5AnalogSamples(group); + MasterAttributes::WriteHDF5DigitalFlag(group); + MasterAttributes::WriteHDF5DigitalSamples(group); + MasterAttributes::WriteHDF5DbitOffset(group); + MasterAttributes::WriteHDF5DbitReorder(group); + MasterAttributes::WriteHDF5DbitList(group); + MasterAttributes::WriteHDF5TransceiverMask(group); + MasterAttributes::WriteHDF5TransceiverFlag(group); + MasterAttributes::WriteHDF5TransceiverSamples(group); } #endif } // namespace sls diff --git a/slsReceiverSoftware/src/MasterAttributes.h b/slsReceiverSoftware/src/MasterAttributes.h index 0e3c168ae..81442fad0 100644 --- a/slsReceiverSoftware/src/MasterAttributes.h +++ b/slsReceiverSoftware/src/MasterAttributes.h @@ -57,7 +57,7 @@ class MasterAttributes { uint32_t transceiverMask{0}; uint32_t transceiver{0}; uint32_t transceiverSamples{0}; - slsDetectorDefs::ROI receiverRoi{}; + std::vector rois{}; uint32_t counterMask{0}; std::array exptimeArray{}; std::array gateDelayArray{}; @@ -80,77 +80,78 @@ class MasterAttributes { rapidjson::PrettyWriter *w); #ifdef HDF5C void WriteCommonHDF5Attributes(H5::H5File *fd, H5::Group *group); - void WriteFinalHDF5Attributes(H5::H5File *fd, H5::Group *group); - void WriteHDF5Exptime(H5::H5File *fd, H5::Group *group); - void WriteHDF5Period(H5::H5File *fd, H5::Group *group); - void WriteHDF5DynamicRange(H5::H5File *fd, H5::Group *group); - void WriteHDF5TenGiga(H5::H5File *fd, H5::Group *group); - void WriteHDF5NumUDPInterfaces(H5::H5File *fd, H5::Group *group); - void WriteHDF5ReadNRows(H5::H5File *fd, H5::Group *group); - void WriteHDF5ThresholdEnergy(H5::H5File *fd, H5::Group *group); - void WriteHDF5ThresholdEnergies(H5::H5File *fd, H5::Group *group); - void WriteHDF5SubExpTime(H5::H5File *fd, H5::Group *group); - void WriteHDF5SubPeriod(H5::H5File *fd, H5::Group *group); - void WriteHDF5SubQuad(H5::H5File *fd, H5::Group *group); - void WriteHDF5RateCorrections(H5::H5File *fd, H5::Group *group); - void WriteHDF5CounterMask(H5::H5File *fd, H5::Group *group); - void WriteHDF5ExptimeArray(H5::H5File *fd, H5::Group *group); - void WriteHDF5GateDelayArray(H5::H5File *fd, H5::Group *group); - void WriteHDF5Gates(H5::H5File *fd, H5::Group *group); - void WriteHDF5BurstMode(H5::H5File *fd, H5::Group *group); - void WriteHDF5AdcMask(H5::H5File *fd, H5::Group *group); - void WriteHDF5AnalogFlag(H5::H5File *fd, H5::Group *group); - void WriteHDF5AnalogSamples(H5::H5File *fd, H5::Group *group); - void WriteHDF5DigitalFlag(H5::H5File *fd, H5::Group *group); - void WriteHDF5DigitalSamples(H5::H5File *fd, H5::Group *group); - void WriteHDF5DbitOffset(H5::H5File *fd, H5::Group *group); - void WriteHDF5DbitList(H5::H5File *fd, H5::Group *group); - void WriteHDF5DbitReorder(H5::H5File *fd, H5::Group *group); - void WriteHDF5TransceiverMask(H5::H5File *fd, H5::Group *group); - void WriteHDF5TransceiverFlag(H5::H5File *fd, H5::Group *group); - void WriteHDF5TransceiverSamples(H5::H5File *fd, H5::Group *group); + void WriteFinalHDF5Attributes(H5::Group *group); + void WriteHDF5ROIs(H5::Group *group); + void WriteHDF5Exptime(H5::Group *group); + void WriteHDF5Period(H5::Group *group); + void WriteHDF5DynamicRange(H5::Group *group); + void WriteHDF5TenGiga(H5::Group *group); + void WriteHDF5NumUDPInterfaces(H5::Group *group); + void WriteHDF5ReadNRows(H5::Group *group); + void WriteHDF5ThresholdEnergy(H5::Group *group); + void WriteHDF5ThresholdEnergies(H5::Group *group); + void WriteHDF5SubExpTime(H5::Group *group); + void WriteHDF5SubPeriod(H5::Group *group); + void WriteHDF5SubQuad(H5::Group *group); + void WriteHDF5RateCorrections(H5::Group *group); + void WriteHDF5CounterMask(H5::Group *group); + void WriteHDF5ExptimeArray(H5::Group *group); + void WriteHDF5GateDelayArray(H5::Group *group); + void WriteHDF5Gates(H5::Group *group); + void WriteHDF5BurstMode(H5::Group *group); + void WriteHDF5AdcMask(H5::Group *group); + void WriteHDF5AnalogFlag(H5::Group *group); + void WriteHDF5AnalogSamples(H5::Group *group); + void WriteHDF5DigitalFlag(H5::Group *group); + void WriteHDF5DigitalSamples(H5::Group *group); + void WriteHDF5DbitOffset(H5::Group *group); + void WriteHDF5DbitList(H5::Group *group); + void WriteHDF5DbitReorder(H5::Group *group); + void WriteHDF5TransceiverMask(H5::Group *group); + void WriteHDF5TransceiverFlag(H5::Group *group); + void WriteHDF5TransceiverSamples(H5::Group *group); #endif void GetJungfrauBinaryAttributes( rapidjson::PrettyWriter *w); #ifdef HDF5C - void WriteJungfrauHDF5Attributes(H5::H5File *fd, H5::Group *group); + void WriteJungfrauHDF5Attributes(H5::Group *group); #endif void GetEigerBinaryAttributes( rapidjson::PrettyWriter *w); #ifdef HDF5C - void WriteEigerHDF5Attributes(H5::H5File *fd, H5::Group *group); + void WriteEigerHDF5Attributes(H5::Group *group); #endif void GetMythen3BinaryAttributes( rapidjson::PrettyWriter *w); #ifdef HDF5C - void WriteMythen3HDF5Attributes(H5::H5File *fd, H5::Group *group); + void WriteMythen3HDF5Attributes(H5::Group *group); #endif void GetGotthard2BinaryAttributes( rapidjson::PrettyWriter *w); #ifdef HDF5C - void WriteGotthard2HDF5Attributes(H5::H5File *fd, H5::Group *group); + void WriteGotthard2HDF5Attributes(H5::Group *group); #endif void GetMoenchBinaryAttributes( rapidjson::PrettyWriter *w); #ifdef HDF5C - void WriteMoenchHDF5Attributes(H5::H5File *fd, H5::Group *group); + void WriteMoenchHDF5Attributes(H5::Group *group); #endif void GetCtbBinaryAttributes(rapidjson::PrettyWriter *w); #ifdef HDF5C - void WriteCtbHDF5Attributes(H5::H5File *fd, H5::Group *group); + void WriteCtbHDF5Attributes(H5::Group *group); #endif void GetXilinxCtbBinaryAttributes( rapidjson::PrettyWriter *w); #ifdef HDF5C - void WriteXilinxCtbHDF5Attributes(H5::H5File *fd, H5::Group *group); + void WriteXilinxCtbHDF5Attributes(H5::Group *group); #endif }; From 230d43d1fec7f92cbbbbaf55a6199b69545806b1 Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Fri, 20 Jun 2025 17:34:26 +0200 Subject: [PATCH 08/49] all tests pased --- .../tests/Caller/test-Caller-rx.cpp | 21 +++++++++++++++++++ slsReceiverSoftware/src/ClientInterface.cpp | 8 +++---- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp b/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp index 72d4c23a0..6e02d7f99 100644 --- a/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp +++ b/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp @@ -623,6 +623,27 @@ TEST_CASE("rx_roi", "[.cmdcall]") { "rx_roi", {"[5, 10, 20, 30];[25, 28, " + stringMin + ", " + stringMax + "]"}, -1, PUT, oss)); REQUIRE(oss.str() == "rx_roi [[5, 10, 20, 30], [25, 28, " + stringMin + ", " + stringMax + "]]\n"); + + // verify individual roi + if (det_type == defs::JUNGFRAU) { + std::ostringstream oss, oss1; + REQUIRE_NOTHROW(caller.call( + "rx_roi", {"[100,500,100,400]"}, -1, PUT, oss)); + REQUIRE(oss.str() == "rx_roi [[100, 500, 100, 400]]\n"); + REQUIRE_NOTHROW( + caller.call("rx_roi", {}, 0, GET, oss1)); + REQUIRE(oss1.str() == "rx_roi [[[100, 500, 100, 255], " + "[100, 500, 256, 400]]]\n"); + } else { + std::ostringstream oss, oss1; + REQUIRE_NOTHROW(caller.call( + "rx_roi", {"[100,200,100,300]"}, -1, PUT, oss)); + REQUIRE(oss.str() == "rx_roi [[100, 200, 100, 300]]\n"); + REQUIRE_NOTHROW( + caller.call("rx_roi", {}, 0, GET, oss1)); + REQUIRE(oss1.str() == "rx_roi [[[100, 200, 100, 199], " + "[100, 200, 200, 300]]]\n"); + } } } } diff --git a/slsReceiverSoftware/src/ClientInterface.cpp b/slsReceiverSoftware/src/ClientInterface.cpp index 4a58619ab..cee0b7f87 100644 --- a/slsReceiverSoftware/src/ClientInterface.cpp +++ b/slsReceiverSoftware/src/ClientInterface.cpp @@ -1716,13 +1716,11 @@ int ClientInterface::set_receiver_roi(Interface &socket) { int ClientInterface::set_receiver_roi_metadata(Interface &socket) { auto roiSize = socket.Receive(); - if (roiSize <= 0) { - throw RuntimeError("Invalid number of ReceiverROI metadata: " + - std::to_string(roiSize)); - } LOG(logDEBUG) << "Number of ReceiverROI metadata: " << roiSize; std::vector rois(roiSize); - socket.Receive(rois); + if (roiSize > 0) { + socket.Receive(rois); + } if (detType == CHIPTESTBOARD || detType == XILINX_CHIPTESTBOARD) functionNotImplemented(); verifyIdle(socket); From 953c3f15879ecb2dc12e628ab6173b30763cd005 Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Fri, 20 Jun 2025 17:35:04 +0200 Subject: [PATCH 09/49] minor --- slsReceiverSoftware/src/Implementation.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/slsReceiverSoftware/src/Implementation.cpp b/slsReceiverSoftware/src/Implementation.cpp index adc16a894..bb3372443 100644 --- a/slsReceiverSoftware/src/Implementation.cpp +++ b/slsReceiverSoftware/src/Implementation.cpp @@ -409,13 +409,13 @@ void Implementation::setPortROIs(const std::array &args) { for (size_t i = 0; i != dataStreamer.size(); ++i) { dataStreamer[i]->SetPortROI(portRois[i]); } - LOG(logINFOBLUE) << "Rois (per port): " << ToString(portRois); + LOG(logINFO) << "Rois (per port): " << ToString(portRois); } void Implementation::setMultiROIMetadata( const std::vector &args) { multiRoiMetadata = args; - LOG(logINFOBLUE) << "Multi ROI Metadata: " << ToString(multiRoiMetadata); + LOG(logINFO) << "Multi ROI Metadata: " << ToString(multiRoiMetadata); } /************************************************** From 83482c82850367a5bb5a72adbf6515b6f2126c97 Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Mon, 23 Jun 2025 20:01:32 +0200 Subject: [PATCH 10/49] fixed rx_roi for multi modules jungfrau , tests for eiger, multi modules jungfrau in x and 2 interfaces --- .../tests/Caller/test-Caller-rx.cpp | 97 +++++++++++-------- 1 file changed, 57 insertions(+), 40 deletions(-) diff --git a/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp b/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp index 6e02d7f99..a57d15086 100644 --- a/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp +++ b/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp @@ -587,8 +587,13 @@ TEST_CASE("rx_roi", "[.cmdcall]") { REQUIRE_THROWS(caller.call( "rx_roi", {"[0, 10, 0, 10];[0, 10, 9, 11]"}, -1, PUT)); + + int numinterfaces = det.getNumberofUDPInterfaces().tsquash( + "inconsistent number of interfaces"); auto portSize = det.getPortSize()[0]; - if (det_type == defs::EIGER) { + int delta = 50; + // multiple ports horizontally + if (det_type == defs::EIGER || (det.size() == 2 && det.getModuleGeometry().x > 1)) { std::string stringMin = std::to_string(portSize.x); std::string stringMax = std::to_string(portSize.x + 1); @@ -601,48 +606,60 @@ TEST_CASE("rx_roi", "[.cmdcall]") { "rx_roi", {"[5, 10, 20, 30];[" + stringMin + ", " + stringMax + ", 20, 30]"}, -1, PUT, oss)); REQUIRE(oss.str() == "rx_roi [[5, 10, 20, 30], [" + stringMin + ", " + stringMax + ", 20, 30]]\n"); - } - if (det_type == defs::JUNGFRAU || det_type == defs::MOENCH) { - // 2 interfaces or 2 modules - if ((det.getNumberofUDPInterfaces().tsquash( - "inconsistent number of interfaces") == 2) || (det.size() == 2)) { - std::string stringMin = std::to_string(portSize.y); - std::string stringMax = std::to_string(portSize.y + 1); - if (det.size() == 2) { - auto moduleSize = det.getModuleSize()[0]; - stringMin = std::to_string(moduleSize.y); - stringMax = std::to_string(moduleSize.y + 1); + + // verify individual roi + { + stringMin = std::to_string(portSize.x - delta); + stringMax = std::to_string(portSize.x + delta); + std::ostringstream oss, oss1; + REQUIRE_NOTHROW(caller.call( + "rx_roi", {"[" + stringMin + ", " + stringMax + ", 20, 30]"}, -1, PUT, oss)); + REQUIRE(oss.str() == "rx_roi [[" + stringMin + ", " + stringMax + ", 20, 30]]\n"); + REQUIRE_NOTHROW( + caller.call("rx_roi", {}, 0, GET, oss1)); + // eiger returns 2 values for 2 ports per module + if (det_type == defs::EIGER) { + REQUIRE(oss1.str() == "rx_roi [[[" + stringMin + ", " + std::to_string(portSize.x - 1) + "20, 30], [" + std::to_string(portSize.x + 1) + ", " + stringMax + ", 20, 30]]]\n"); } + // others return only 1 roi per module (1 port per module) + else { + REQUIRE(oss1.str() == "rx_roi [[[" + stringMin + ", " + std::to_string(portSize.x - 1) + "20, 30]]]\n"); + } + } + } - // separated by space is allowed - REQUIRE_NOTHROW(caller.call( - "rx_roi", {"[5, 10, 20, 30]", "[25, 28, " + stringMin + ", " + stringMax + "]"}, -1, PUT)); - std::ostringstream oss; - // separated by semicolon is allowed - REQUIRE_NOTHROW(caller.call( - "rx_roi", {"[5, 10, 20, 30];[25, 28, " + stringMin + ", " + stringMax + "]"}, -1, PUT, oss)); - REQUIRE(oss.str() == - "rx_roi [[5, 10, 20, 30], [25, 28, " + stringMin + ", " + stringMax + "]]\n"); + // multiple ports vertically + else if (numinterfaces == 2 || (det.size() == 2 && det.getModuleGeometry().y > 1)) { + std::string stringMin = std::to_string(portSize.y); + std::string stringMax = std::to_string(portSize.y + 1); - // verify individual roi - if (det_type == defs::JUNGFRAU) { - std::ostringstream oss, oss1; - REQUIRE_NOTHROW(caller.call( - "rx_roi", {"[100,500,100,400]"}, -1, PUT, oss)); - REQUIRE(oss.str() == "rx_roi [[100, 500, 100, 400]]\n"); - REQUIRE_NOTHROW( - caller.call("rx_roi", {}, 0, GET, oss1)); - REQUIRE(oss1.str() == "rx_roi [[[100, 500, 100, 255], " - "[100, 500, 256, 400]]]\n"); - } else { - std::ostringstream oss, oss1; - REQUIRE_NOTHROW(caller.call( - "rx_roi", {"[100,200,100,300]"}, -1, PUT, oss)); - REQUIRE(oss.str() == "rx_roi [[100, 200, 100, 300]]\n"); - REQUIRE_NOTHROW( - caller.call("rx_roi", {}, 0, GET, oss1)); - REQUIRE(oss1.str() == "rx_roi [[[100, 200, 100, 199], " - "[100, 200, 200, 300]]]\n"); + // separated by space is allowed + REQUIRE_NOTHROW(caller.call( + "rx_roi", {"[5, 10, 20, 30]", "[25, 28, " + stringMin + ", " + stringMax + "]"}, -1, PUT)); + std::ostringstream oss; + // separated by semicolon is allowed + REQUIRE_NOTHROW(caller.call( + "rx_roi", {"[5, 10, 20, 30];[25, 28, " + stringMin + ", " + stringMax + "]"}, -1, PUT, oss)); + REQUIRE(oss.str() == + "rx_roi [[5, 10, 20, 30], [25, 28, " + stringMin + ", " + stringMax + "]]\n"); + + // verify individual roi + { + stringMin = std::to_string(portSize.y - delta); + stringMax = std::to_string(portSize.y + delta); + std::ostringstream oss, oss1; + REQUIRE_NOTHROW(caller.call( + "rx_roi", {"[ 20, 30, " + stringMin + ", " + stringMax + "]"}, -1, PUT, oss)); + REQUIRE(oss.str() == "rx_roi [[20, 30, " + stringMin + ", " + stringMax + "]]\n"); + REQUIRE_NOTHROW( + caller.call("rx_roi", {}, 0, GET, oss1)); + // non-eiger with 2 interfaces returns 2 values for 2 ports per module + if (numinterfaces == 2) { + REQUIRE(oss1.str() == "rx_roi [[[20, 30, " + stringMin + ", " + std::to_string(portSize.y - 1) + "], [20, 30, " + std::to_string(portSize.y + 1) + ", " + stringMax + "]]]\n"); + } + // others return only 1 roi per module (1 port per module) + else { + REQUIRE(oss1.str() == "rx_roi [[[20, 30, " + stringMin + ", " + std::to_string(portSize.y - 1) + "], [-1, -1]]]\n"); } } } From 686eebd69b8a8b71872d2c59f99bf0567feef67a Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Mon, 23 Jun 2025 21:31:52 +0200 Subject: [PATCH 11/49] works for eiger as well --- slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp b/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp index a57d15086..3576b4d40 100644 --- a/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp +++ b/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp @@ -619,7 +619,7 @@ TEST_CASE("rx_roi", "[.cmdcall]") { caller.call("rx_roi", {}, 0, GET, oss1)); // eiger returns 2 values for 2 ports per module if (det_type == defs::EIGER) { - REQUIRE(oss1.str() == "rx_roi [[[" + stringMin + ", " + std::to_string(portSize.x - 1) + "20, 30], [" + std::to_string(portSize.x + 1) + ", " + stringMax + ", 20, 30]]]\n"); + REQUIRE(oss1.str() == "rx_roi [[[" + stringMin + ", " + std::to_string(portSize.x - 1) + ", 20, 30], [" + std::to_string(portSize.x) + ", " + stringMax + ", 20, 30]]]\n"); } // others return only 1 roi per module (1 port per module) else { @@ -655,7 +655,7 @@ TEST_CASE("rx_roi", "[.cmdcall]") { caller.call("rx_roi", {}, 0, GET, oss1)); // non-eiger with 2 interfaces returns 2 values for 2 ports per module if (numinterfaces == 2) { - REQUIRE(oss1.str() == "rx_roi [[[20, 30, " + stringMin + ", " + std::to_string(portSize.y - 1) + "], [20, 30, " + std::to_string(portSize.y + 1) + ", " + stringMax + "]]]\n"); + REQUIRE(oss1.str() == "rx_roi [[[20, 30, " + stringMin + ", " + std::to_string(portSize.y - 1) + "], [20, 30, " + std::to_string(portSize.y) + ", " + stringMax + "]]]\n"); } // others return only 1 roi per module (1 port per module) else { From 28792ea7e7aea8d993a9170015e7adc8d24e20ea Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Tue, 24 Jun 2025 09:39:28 +0200 Subject: [PATCH 12/49] switched to vector instead of std::array>, which prints extra [-1, -1] when theres only 1 udp interface --- slsDetectorSoftware/include/sls/Detector.h | 2 +- slsDetectorSoftware/src/Detector.cpp | 4 +- slsDetectorSoftware/src/DetectorImpl.cpp | 30 +++++++---- slsDetectorSoftware/src/DetectorImpl.h | 5 +- slsDetectorSoftware/src/Module.cpp | 52 ++++++++++++++++--- slsDetectorSoftware/src/Module.h | 4 +- .../tests/Caller/test-Caller-rx.cpp | 8 +-- slsReceiverSoftware/src/ClientInterface.cpp | 19 +++++-- slsReceiverSoftware/src/DataStreamer.cpp | 2 +- slsReceiverSoftware/src/Implementation.cpp | 40 ++++++++++---- slsReceiverSoftware/src/Implementation.h | 6 +-- 11 files changed, 127 insertions(+), 45 deletions(-) diff --git a/slsDetectorSoftware/include/sls/Detector.h b/slsDetectorSoftware/include/sls/Detector.h index b0a261e94..10a3acba6 100644 --- a/slsDetectorSoftware/include/sls/Detector.h +++ b/slsDetectorSoftware/include/sls/Detector.h @@ -993,7 +993,7 @@ class Detector { std::vector getRxROI() const; /** Returns port level ROIs. Max 2 ports and hence max 2 elements per readout */ - Result> getRxROI(int module_id) const; + std::vector getRxROI(int module_id) const; /** only at multi module level without gap pixels. At most, 1 ROI per UDP port */ void setRxROI(const std::vector &args); diff --git a/slsDetectorSoftware/src/Detector.cpp b/slsDetectorSoftware/src/Detector.cpp index a274f06f7..b2d70937c 100644 --- a/slsDetectorSoftware/src/Detector.cpp +++ b/slsDetectorSoftware/src/Detector.cpp @@ -1387,8 +1387,8 @@ std::vector Detector::getRxROI() const { return pimpl->getRxROI(); } -Result> Detector::getRxROI(int module_id) const { - return pimpl->Parallel(&Module::getRxROI, {module_id}); +std::vector Detector::getRxROI(int module_id) const { + return pimpl->getRxROI(module_id); } // RxROIs can be set for all types except CTB. At multi level without gap pixels diff --git a/slsDetectorSoftware/src/DetectorImpl.cpp b/slsDetectorSoftware/src/DetectorImpl.cpp index 66d4b7a73..5cb2744b5 100644 --- a/slsDetectorSoftware/src/DetectorImpl.cpp +++ b/slsDetectorSoftware/src/DetectorImpl.cpp @@ -1667,8 +1667,7 @@ void DetectorImpl::verifyUniqueHost( } } -std::vector DetectorImpl::getRxROI() const { - +std::vector DetectorImpl::getRxROI(int module_id) const { if (shm()->detType == CHIPTESTBOARD || shm()->detType == defs::XILINX_CHIPTESTBOARD) { throw RuntimeError("RxRoi not implemented for this Detector"); @@ -1677,6 +1676,14 @@ std::vector DetectorImpl::getRxROI() const { throw RuntimeError("No Modules added"); } + // individual module rois + if (module_id >= 0) { + if (module_id >= (int)modules.size()) + throw RuntimeError("Invalid module index " + std::to_string(module_id) + ". Out of bounds."); + return modules[module_id]->getRxROI(); + } + + // multi roi // return std::vector{}; return rxRoiTemp; // TODO @@ -1792,13 +1799,18 @@ defs::ROI DetectorImpl::getModuleROI(int moduleIndex) const { void DetectorImpl::convertGlobalRoiToPortLevel( const defs::ROI &userRoi, const defs::ROI &moduleRoi, - std::array &portRois) const { + 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."); } + if (numPorts != (int)portRois.size()) { + throw RuntimeError("Number of port ROIs does not match number of ports in module. Expected: " + + std::to_string(numPorts) + ", got: " + + std::to_string(portRois.size())); + } for (int port = 0; port < numPorts; ++port) { defs::ROI portRoi = moduleRoi; @@ -1849,12 +1861,13 @@ void DetectorImpl::setRxROI(const std::vector &args) { } validateROIs(args); + int nPortsPerModule = Parallel(&Module::getNumberofUDPInterfacesFromShm, {}).tsquash("Inconsistent number of udp ports set up per module"); for (size_t iModule = 0; iModule < modules.size(); ++iModule) { auto moduleGlobalRoi = getModuleROI(iModule); // at most 2 rois per module (for each port) - std::array portRois{}; + std::vector portRois(nPortsPerModule); for (const auto &arg : args) { if (roisOverlap(arg, moduleGlobalRoi)) { @@ -1863,7 +1876,7 @@ void DetectorImpl::setRxROI(const std::vector &args) { } // print the rois for debugging LOG(logINFOBLUE) << "Module " << iModule << " RxROIs:"; - for (size_t iPort = 0; iPort != 2; iPort++) { + for (size_t iPort = 0; iPort != portRois.size(); iPort++) { LOG(logINFOBLUE) << " Port " << iPort << ": " << ToString(portRois[iPort]); } @@ -1876,15 +1889,12 @@ void DetectorImpl::setRxROI(const std::vector &args) { void DetectorImpl::clearRxROI() { rxRoiTemp.clear(); + int nPortsPerModule = Parallel(&Module::getNumberofUDPInterfacesFromShm, {}).tsquash("Inconsistent number of udp ports set up per module"); for (size_t iModule = 0; iModule < modules.size(); ++iModule) { - modules[iModule]->setRxROI(std::array{}); + modules[iModule]->setRxROI(std::vector(nPortsPerModule)); } } -int DetectorImpl::getNumberOfUdpPortsInRxROI() const { - return 0; // TODO -} - void DetectorImpl::getBadChannels(const std::string &fname, Positions pos) const { auto res = Parallel(&Module::getBadChannels, pos); diff --git a/slsDetectorSoftware/src/DetectorImpl.h b/slsDetectorSoftware/src/DetectorImpl.h index a43707c0c..45d95e4cf 100644 --- a/slsDetectorSoftware/src/DetectorImpl.h +++ b/slsDetectorSoftware/src/DetectorImpl.h @@ -302,10 +302,9 @@ class DetectorImpl : public virtual slsDetectorDefs { verifyUniqueRxHost(const std::vector &names) const; defs::xy getPortGeometry() const; - std::vector getRxROI() const; + std::vector getRxROI(int module_id = -1) const; void setRxROI(const std::vector &args); void clearRxROI(); - int getNumberOfUdpPortsInRxROI() const; void getBadChannels(const std::string &fname, Positions pos) const; void setBadChannels(const std::string &fname, Positions pos); @@ -433,7 +432,7 @@ class DetectorImpl : public virtual slsDetectorDefs { defs::ROI getModuleROI(int moduleIndex) const; void convertGlobalRoiToPortLevel( const defs::ROI &userRoi, const defs::ROI &moduleRoi, - std::array &portRois) const; + std::vector &portRois) const; const int detectorIndex{0}; SharedMemory shm{0, -1}; diff --git a/slsDetectorSoftware/src/Module.cpp b/slsDetectorSoftware/src/Module.cpp index 12b8be264..6ee96af9e 100644 --- a/slsDetectorSoftware/src/Module.cpp +++ b/slsDetectorSoftware/src/Module.cpp @@ -1521,12 +1521,50 @@ void Module::setRxArping(bool enable) { sendToReceiver(F_SET_RECEIVER_ARPING, static_cast(enable), nullptr); } -std::array Module::getRxROI() const { - return sendToReceiver>(F_RECEIVER_GET_RECEIVER_ROI); +std::vector Module::getRxROI() const { + LOG(logDEBUG1) << "Getting receiver ROI for Module " << moduleIndex; + // check number of ports + if (!shm()->useReceiverFlag) { + throw RuntimeError("No receiver to get ROI."); + } + auto client = ReceiverSocket(shm()->rxHostname, shm()->rxTCPPort); + client.Send(F_RECEIVER_GET_RECEIVER_ROI); + client.setFnum(F_RECEIVER_GET_RECEIVER_ROI); + auto nPorts = client.Receive(); + std::vector retval(nPorts); + if (nPorts > 0) + client.Receive(retval); + if (nPorts > shm()->numUDPInterfaces) { + throw RuntimeError("Invalid number of rois: " + std::to_string(nPorts) + ". Max: " + std::to_string(shm()->numUDPInterfaces)); + } + LOG(logDEBUG1) << "ROI of Receiver" << moduleIndex << ": " + << ToString(retval); + return retval; } -void Module::setRxROI(const std::array &portRois) { - sendToReceiver(F_RECEIVER_SET_RECEIVER_ROI, portRois, nullptr); +void Module::setRxROI(const std::vector &portRois) { + LOG(logDEBUG) << "Sending to receiver " << moduleIndex + << " [roi: " << ToString(portRois) << ']'; + if (!shm()->useReceiverFlag) { + throw RuntimeError("No receiver to set ROI."); + } + if ((int)portRois.size() > shm()->numUDPInterfaces) { + throw RuntimeError("Invalid number of ROIs: " + + std::to_string(portRois.size()) + + ". Max: " + std::to_string(shm()->numUDPInterfaces)); + } + // check number of ports + auto client = ReceiverSocket(shm()->rxHostname, shm()->rxTCPPort); + client.Send(F_RECEIVER_SET_RECEIVER_ROI); + client.setFnum(F_RECEIVER_SET_RECEIVER_ROI); + int size = static_cast(portRois.size()); + client.Send(size); + if (size > 0) + client.Send(portRois); + if (client.Receive() == FAIL) { + throw ReceiverError("Receiver " + std::to_string(moduleIndex) + + " returned error: " + client.readErrorMessage()); + } } void Module::setRxROIMetadata(const std::vector &args) { @@ -1535,8 +1573,10 @@ void Module::setRxROIMetadata(const std::vector &args) { auto receiver = ReceiverSocket(shm()->rxHostname, shm()->rxTCPPort); receiver.Send(F_RECEIVER_SET_RECEIVER_ROI_METADATA); receiver.setFnum(F_RECEIVER_SET_RECEIVER_ROI_METADATA); - receiver.Send(static_cast(args.size())); - receiver.Send(args); + int size = static_cast(args.size()); + receiver.Send(size); + if (size > 0) + receiver.Send(args); if (receiver.Receive() == FAIL) { throw ReceiverError("Receiver " + std::to_string(moduleIndex) + " returned error: " + receiver.readErrorMessage()); diff --git a/slsDetectorSoftware/src/Module.h b/slsDetectorSoftware/src/Module.h index 47284fec0..86516cbb5 100644 --- a/slsDetectorSoftware/src/Module.h +++ b/slsDetectorSoftware/src/Module.h @@ -301,8 +301,8 @@ class Module : public virtual slsDetectorDefs { std::array getReceiverThreadIds() const; bool getRxArping() const; void setRxArping(bool enable); - std::array getRxROI() const; - void setRxROI(const std::array &portRois); + std::vector getRxROI() const; + void setRxROI(const std::vector &portRois); void setRxROIMetadata(const std::vector &args); /************************************************** diff --git a/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp b/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp index 3576b4d40..9b0a42997 100644 --- a/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp +++ b/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp @@ -619,11 +619,11 @@ TEST_CASE("rx_roi", "[.cmdcall]") { caller.call("rx_roi", {}, 0, GET, oss1)); // eiger returns 2 values for 2 ports per module if (det_type == defs::EIGER) { - REQUIRE(oss1.str() == "rx_roi [[[" + stringMin + ", " + std::to_string(portSize.x - 1) + ", 20, 30], [" + std::to_string(portSize.x) + ", " + stringMax + ", 20, 30]]]\n"); + REQUIRE(oss1.str() == "rx_roi [[" + stringMin + ", " + std::to_string(portSize.x - 1) + ", 20, 30], [" + std::to_string(portSize.x) + ", " + stringMax + ", 20, 30]]\n"); } // others return only 1 roi per module (1 port per module) else { - REQUIRE(oss1.str() == "rx_roi [[[" + stringMin + ", " + std::to_string(portSize.x - 1) + "20, 30]]]\n"); + REQUIRE(oss1.str() == "rx_roi [[" + stringMin + ", " + std::to_string(portSize.x - 1) + "20, 30]]\n"); } } } @@ -655,11 +655,11 @@ TEST_CASE("rx_roi", "[.cmdcall]") { caller.call("rx_roi", {}, 0, GET, oss1)); // non-eiger with 2 interfaces returns 2 values for 2 ports per module if (numinterfaces == 2) { - REQUIRE(oss1.str() == "rx_roi [[[20, 30, " + stringMin + ", " + std::to_string(portSize.y - 1) + "], [20, 30, " + std::to_string(portSize.y) + ", " + stringMax + "]]]\n"); + REQUIRE(oss1.str() == "rx_roi [[20, 30, " + stringMin + ", " + std::to_string(portSize.y - 1) + "], [20, 30, " + std::to_string(portSize.y) + ", " + stringMax + "]]\n"); } // others return only 1 roi per module (1 port per module) else { - REQUIRE(oss1.str() == "rx_roi [[[20, 30, " + stringMin + ", " + std::to_string(portSize.y - 1) + "], [-1, -1]]]\n"); + REQUIRE(oss1.str() == "rx_roi [[20, 30, " + stringMin + ", " + std::to_string(portSize.y - 1) + "]]\n"); } } } diff --git a/slsReceiverSoftware/src/ClientInterface.cpp b/slsReceiverSoftware/src/ClientInterface.cpp index cee0b7f87..37611ad5d 100644 --- a/slsReceiverSoftware/src/ClientInterface.cpp +++ b/slsReceiverSoftware/src/ClientInterface.cpp @@ -1695,11 +1695,24 @@ int ClientInterface::set_arping(Interface &socket) { int ClientInterface::get_receiver_roi(Interface &socket) { auto retvals = impl()->getPortROIs(); LOG(logDEBUG1) << "Receiver roi retval:" << ToString(retvals); - return socket.sendResult(retvals); + auto size = static_cast(retvals.size()); + socket.Send(size); + if (size > 0) + socket.Send(retvals); + return OK; } int ClientInterface::set_receiver_roi(Interface &socket) { - auto args = socket.Receive>(); + auto roiSize = socket.Receive(); + std::vector args(roiSize); + if (roiSize > 0) { + socket.Receive(args); + } + if (roiSize > impl()->getNumberofUDPInterfaces()) { + throw RuntimeError("Invalid number of ROIs received: " + + std::to_string(roiSize) + ". Max: " + + std::to_string(impl()->getNumberofUDPInterfaces())); + } if (detType == CHIPTESTBOARD || detType == XILINX_CHIPTESTBOARD) functionNotImplemented(); LOG(logDEBUG1) << "Set Receiver ROI: " << ToString(args); @@ -1716,7 +1729,7 @@ int ClientInterface::set_receiver_roi(Interface &socket) { int ClientInterface::set_receiver_roi_metadata(Interface &socket) { auto roiSize = socket.Receive(); - LOG(logDEBUG) << "Number of ReceiverROI metadata: " << roiSize; + LOG(logDEBUG1) << "Number of ReceiverROI metadata: " << roiSize; std::vector rois(roiSize); if (roiSize > 0) { socket.Receive(rois); diff --git a/slsReceiverSoftware/src/DataStreamer.cpp b/slsReceiverSoftware/src/DataStreamer.cpp index f2f6a4b9e..e971dae30 100644 --- a/slsReceiverSoftware/src/DataStreamer.cpp +++ b/slsReceiverSoftware/src/DataStreamer.cpp @@ -54,7 +54,7 @@ void DataStreamer::SetAdditionalJsonHeader( } void DataStreamer::SetPortROI(ROI roi) { - if (roi.completeRoi()) { + if (roi.completeRoi()) {//TODO: just not send zmq if not in roi? portRoi = ROI(0, generalData->nPixelsX - 1, 0, generalData->nPixelsY - 1); } else { diff --git a/slsReceiverSoftware/src/Implementation.cpp b/slsReceiverSoftware/src/Implementation.cpp index bb3372443..ffffb7d05 100644 --- a/slsReceiverSoftware/src/Implementation.cpp +++ b/slsReceiverSoftware/src/Implementation.cpp @@ -184,7 +184,7 @@ void Implementation::SetupListener(int i) { listener[i]->SetUdpPortNumber(udpPortNum[i]); listener[i]->SetEthernetInterface(eth[i]); listener[i]->SetActivate(activated); - listener[i]->SetIsOutsideRoi(portRois[i].noRoi()); + listener[i]->SetIsOutsideRoi(i >= (int)portRois.size()); listener[i]->SetDetectorDatastream(detectorDataStream[i]); listener[i]->SetSilentMode(silentMode); } @@ -194,7 +194,12 @@ void Implementation::SetupDataProcessor(int i) { dataProcessor[i]->SetGeneralData(generalData); dataProcessor[i]->SetUdpPortNumber(udpPortNum[i]); dataProcessor[i]->SetActivate(activated); - dataProcessor[i]->SetPortROI(portRois[i]); + if (i >= (int)portRois.size()) { + ROI roi{0, 0, 0, 0}; + dataProcessor[i]->SetPortROI(roi); + } else { + dataProcessor[i]->SetPortROI(portRois[i]); + } dataProcessor[i]->SetDataStreamEnable(dataStreamEnable); dataProcessor[i]->SetStreamingFrequency(streamingFrequency); dataProcessor[i]->SetStreamingTimerInMs(streamingTimerInMs); @@ -216,7 +221,12 @@ void Implementation::SetupDataStreamer(int i) { dataStreamer[i]->SetFlipRows(flipRows); dataStreamer[i]->SetNumberofPorts(numPorts); dataStreamer[i]->SetNumberofTotalFrames(numberOfTotalFrames); - dataStreamer[i]->SetPortROI(portRois[i]); + if (i >= (int)portRois.size()) { + ROI roi{0, 0, 0, 0}; + dataStreamer[i]->SetPortROI(roi); + } else { + dataStreamer[i]->SetPortROI(portRois[i]); + } } slsDetectorDefs::xy Implementation::getDetectorSize() const { @@ -395,19 +405,29 @@ void Implementation::setArping(const bool i, } } -std::array Implementation::getPortROIs() const { +std::vector Implementation::getPortROIs() const { return portRois; } -void Implementation::setPortROIs(const std::array &args) { +void Implementation::setPortROIs(const std::vector &args) { portRois = args; for (size_t i = 0; i != listener.size(); ++i) - listener[i]->SetIsOutsideRoi(portRois[i].noRoi()); + listener[i]->SetIsOutsideRoi(i >= portRois.size()); for (size_t i = 0; i != dataProcessor.size(); ++i) - dataProcessor[i]->SetPortROI(portRois[i]); + if (i >= portRois.size()) { + ROI roi{0, 0, 0, 0}; + dataProcessor[i]->SetPortROI(roi); + } else { + dataProcessor[i]->SetPortROI(portRois[i]); + } for (size_t i = 0; i != dataStreamer.size(); ++i) { - dataStreamer[i]->SetPortROI(portRois[i]); + if (i >= portRois.size()) { + ROI roi{0, 0, 0, 0}; + dataStreamer[i]->SetPortROI(roi); + } else { + dataStreamer[i]->SetPortROI(portRois[i]); + } } LOG(logINFO) << "Rois (per port): " << ToString(portRois); } @@ -710,7 +730,7 @@ void Implementation::stopReceiver() { } else if (!detectorDataStream[i]) { summary = (i == 0 ? "\n\tDeactivated Left Port" : "\n\tDeactivated Right Port"); - } else if (portRois[i].noRoi()) { + } else if (i >= (int)portRois.size()) { summary = "\n\tNo Roi on Port[" + std::to_string(i) + ']'; } else { std::ostringstream os; @@ -881,7 +901,7 @@ void Implementation::StartMasterWriter() { masterAttributes.framePadding = framePadding; masterAttributes.scanParams = scanParams; masterAttributes.totalFrames = numberOfTotalFrames; - // complete ROI + // complete ROI (for each port TODO?) if (multiRoiMetadata.empty()) { int nTotalPixelsX = (generalData->nPixelsX * numPorts.x); int nTotalPixelsY = (generalData->nPixelsY * numPorts.y); diff --git a/slsReceiverSoftware/src/Implementation.h b/slsReceiverSoftware/src/Implementation.h index 2d663b85b..6f25287fd 100644 --- a/slsReceiverSoftware/src/Implementation.h +++ b/slsReceiverSoftware/src/Implementation.h @@ -58,8 +58,8 @@ class Implementation : private virtual slsDetectorDefs { bool getArping() const; pid_t getArpingProcessId() const; void setArping(const bool i, const std::vector ips); - std::array getPortROIs() const; - void setPortROIs(const std::array &args); + std::vector getPortROIs() const; + void setPortROIs(const std::vector &args); void setMultiROIMetadata(const std::vector &args); /************************************************** @@ -307,7 +307,7 @@ class Implementation : private virtual slsDetectorDefs { bool framePadding{true}; pid_t parentThreadId; pid_t tcpThreadId; - std::array portRois{}; + std::vector portRois{}; std::vector multiRoiMetadata{}; // file parameters From 7258adfe158342f47aa8591a0b5163aaba9d9461 Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Tue, 24 Jun 2025 14:29:19 +0200 Subject: [PATCH 13/49] wip --- slsReceiverSoftware/src/DataProcessor.cpp | 15 +- slsReceiverSoftware/src/DataProcessor.h | 3 + slsReceiverSoftware/src/Implementation.cpp | 9 +- slsReceiverSoftware/src/MasterFileUtility.cpp | 250 ++++++++++-------- slsReceiverSoftware/src/MasterFileUtility.h | 3 +- 5 files changed, 157 insertions(+), 123 deletions(-) diff --git a/slsReceiverSoftware/src/DataProcessor.cpp b/slsReceiverSoftware/src/DataProcessor.cpp index 7a02d2f62..64ae23547 100644 --- a/slsReceiverSoftware/src/DataProcessor.cpp +++ b/slsReceiverSoftware/src/DataProcessor.cpp @@ -54,6 +54,11 @@ void DataProcessor::SetPortROI(ROI roi) { isOutsideRoi = portRoi.noRoi(); } +void DataProcessor::setMultiROIMetadata( + const std::vector &args) { + multiRoiMetadata = args; +} + void DataProcessor::SetDataStreamEnable(bool enable) { dataStreamEnable = enable; } @@ -203,9 +208,9 @@ std::string DataProcessor::CreateVirtualFile( const int modulePos, const int numModX, const int numModY, std::mutex *hdf5LibMutex) { - if (isPartiallyInRoi) { - throw std::runtime_error( - "Skipping virtual hdf5 file since rx_roi is enabled."); + if (!multiRoiMetadata.empty() && generalData->dynamicRange == 4) { + throw std::runtime_error("Skipping virtual hdf5 file since rx_roi is " + "enabled in 4 bit mode."); } bool gotthard25um = ((generalData->detType == GOTTHARD || @@ -227,7 +232,7 @@ std::string DataProcessor::CreateVirtualFile( generalData->nPixelsX, generalData->nPixelsY, generalData->dynamicRange, numFramesCaught, numModX, numModY, dataFile->GetPDataType(), dataFile->GetParameterNames(), dataFile->GetParameterDataTypes(), - hdf5LibMutex, gotthard25um); + hdf5LibMutex, gotthard25um, multiRoiMetadata); } void DataProcessor::LinkFileInMaster(const std::string &masterFileName, @@ -235,7 +240,7 @@ void DataProcessor::LinkFileInMaster(const std::string &masterFileName, const bool silentMode, std::mutex *hdf5LibMutex) { - if (isPartiallyInRoi) { + if (!multiRoiMetadata.empty()) { throw std::runtime_error( "Should not be here, roi with hdf5 virtual should throw."); } diff --git a/slsReceiverSoftware/src/DataProcessor.h b/slsReceiverSoftware/src/DataProcessor.h index a53e38de4..ecfdacc7e 100644 --- a/slsReceiverSoftware/src/DataProcessor.h +++ b/slsReceiverSoftware/src/DataProcessor.h @@ -40,6 +40,7 @@ class DataProcessor : private virtual slsDetectorDefs, public ThreadObject { void SetUdpPortNumber(const uint16_t portNumber); void SetActivate(bool enable); void SetPortROI(const ROI arg); + void setMultiROIMetadata(const std::vector &args); void SetDataStreamEnable(bool enable); void SetStreamingFrequency(uint32_t value); void SetStreamingTimerInMs(uint32_t value); @@ -162,6 +163,8 @@ class DataProcessor : private virtual slsDetectorDefs, public ThreadObject { ROI portRoi{}; bool isPartiallyInRoi{false}; bool isOutsideRoi{false}; + std::vector multiRoiMetadata{}; + std::unique_ptr completeImageToStreamBeforeCropping; /** if 0, sending random images with a timer */ uint32_t streamingFrequency; diff --git a/slsReceiverSoftware/src/Implementation.cpp b/slsReceiverSoftware/src/Implementation.cpp index ffffb7d05..10f5aead7 100644 --- a/slsReceiverSoftware/src/Implementation.cpp +++ b/slsReceiverSoftware/src/Implementation.cpp @@ -200,6 +200,8 @@ void Implementation::SetupDataProcessor(int i) { } else { dataProcessor[i]->SetPortROI(portRois[i]); } + if (i == 0) + dataProcessor[0]->setMultiROIMetadata(multiRoiMetadata); dataProcessor[i]->SetDataStreamEnable(dataStreamEnable); dataProcessor[i]->SetStreamingFrequency(streamingFrequency); dataProcessor[i]->SetStreamingTimerInMs(streamingTimerInMs); @@ -414,13 +416,16 @@ void Implementation::setPortROIs(const std::vector &args) { for (size_t i = 0; i != listener.size(); ++i) listener[i]->SetIsOutsideRoi(i >= portRois.size()); - for (size_t i = 0; i != dataProcessor.size(); ++i) + for (size_t i = 0; i != dataProcessor.size(); ++i) { if (i >= portRois.size()) { ROI roi{0, 0, 0, 0}; dataProcessor[i]->SetPortROI(roi); } else { dataProcessor[i]->SetPortROI(portRois[i]); } + } + if (dataProcessor.size() > 0) + dataProcessor[0]->setMultiROIMetadata(multiRoiMetadata); for (size_t i = 0; i != dataStreamer.size(); ++i) { if (i >= portRois.size()) { ROI roi{0, 0, 0, 0}; @@ -435,6 +440,8 @@ void Implementation::setPortROIs(const std::vector &args) { void Implementation::setMultiROIMetadata( const std::vector &args) { multiRoiMetadata = args; + if (dataProcessor.size() > 0) + dataProcessor[0]->setMultiROIMetadata(multiRoiMetadata); LOG(logINFO) << "Multi ROI Metadata: " << ToString(multiRoiMetadata); } diff --git a/slsReceiverSoftware/src/MasterFileUtility.cpp b/slsReceiverSoftware/src/MasterFileUtility.cpp index 793dc777e..6e0c7903b 100644 --- a/slsReceiverSoftware/src/MasterFileUtility.cpp +++ b/slsReceiverSoftware/src/MasterFileUtility.cpp @@ -160,6 +160,7 @@ std::string CreateMasterHDF5File(const std::string &filePath, return fileName; } +/** Will not be called if dynamic range is 4 and roi enabled */ std::string CreateVirtualHDF5File( const std::string &filePath, const std::string &fileNamePrefix, const uint64_t fileIndex, const bool overWriteEnable, const bool silentMode, @@ -169,7 +170,8 @@ std::string CreateVirtualHDF5File( const uint64_t numImagesCaught, const int numModX, const int numModY, const H5::DataType dataType, const std::vector parameterNames, const std::vector parameterDataTypes, - std::mutex *hdf5LibMutex, bool gotthard25um) { + std::mutex *hdf5LibMutex, bool gotthard25um, + std::vector &multiRoi) { // virtual file name std::ostringstream osfn; @@ -205,134 +207,150 @@ std::string CreateVirtualHDF5File( "version", H5::PredType::NATIVE_DOUBLE, dataspace_attr); attribute.write(H5::PredType::NATIVE_DOUBLE, &dValue); - // dataspace - hsize_t vdsDims[DATA_RANK] = {numImagesCaught, numModY * nDimy, - numModZ * nDimz}; - hsize_t vdsDimsPara[VDS_PARA_RANK] = {numImagesCaught, - numModY * numModZ}; - H5::DataSpace vdsDataSpace(DATA_RANK, vdsDims, nullptr); - H5::DataSpace vdsDataSpacePara(VDS_PARA_RANK, vdsDimsPara, nullptr); - - // property list - H5::DSetCreatPropList plist; - uint64_t fill_value = -1; - plist.setFillValue(dataType, &fill_value); - std::vector plistPara(paraSize); - // ignoring last fill (string) - for (unsigned int i = 0; i != plistPara.size() - 1; ++i) { - plistPara[i].setFillValue(parameterDataTypes[i], &fill_value); + // complete detector in roi + if (multiRoi.empty()) { + int ny = nPixelsY * numModY; + int nx = nPixelsX * numModX; + if (nPixelsY == 1) { + multiRoi.push_back(defs::ROI{0, nx - 1}); + } else { + multiRoi.push_back(defs::ROI{0, nx - 1, 0, ny - 1}); + } } - // hyperslab (files) - int numFiles = numImagesCaught / maxFramesPerFile; - if (numImagesCaught % maxFramesPerFile) - ++numFiles; - uint64_t framesSaved = 0; - for (int iFile = 0; iFile < numFiles; ++iFile) { + for (size_t iRoi = 0; iRoi != multiRoi.size(); ++iRoi) { - uint64_t nDimx = - ((numImagesCaught - framesSaved) > maxFramesPerFile) - ? maxFramesPerFile - : (numImagesCaught - framesSaved); + // dataspace + hsize_t vdsDims[DATA_RANK] = {numImagesCaught, numModY * nDimy, + numModZ * nDimz}; + hsize_t vdsDimsPara[VDS_PARA_RANK] = {numImagesCaught, + numModY * numModZ}; + H5::DataSpace vdsDataSpace(DATA_RANK, vdsDims, nullptr); + H5::DataSpace vdsDataSpacePara(VDS_PARA_RANK, vdsDimsPara, nullptr); - hsize_t startLocation[DATA_RANK] = {framesSaved, 0, 0}; - hsize_t strideBetweenBlocks[DATA_RANK] = {1, 1, 1}; - hsize_t numBlocks[DATA_RANK] = {nDimx, nDimy, nDimz}; - hsize_t blockSize[DATA_RANK] = {1, 1, 1}; - - hsize_t startLocationPara[VDS_PARA_RANK] = {framesSaved, 0}; - hsize_t strideBetweenBlocksPara[VDS_PARA_RANK] = {1, 1}; - hsize_t numBlocksPara[VDS_PARA_RANK] = {nDimx, 1}; - hsize_t blockSizePara[VDS_PARA_RANK] = {1, 1}; - - // interleaving for g2 - if (gotthard25um) { - strideBetweenBlocks[2] = 2; + // property list + H5::DSetCreatPropList plist; + uint64_t fill_value = -1; + plist.setFillValue(dataType, &fill_value); + std::vector plistPara(paraSize); + // ignoring last fill (string) + for (unsigned int i = 0; i != plistPara.size() - 1; ++i) { + plistPara[i].setFillValue(parameterDataTypes[i], &fill_value); } - for (unsigned int iReadout = 0; iReadout < numModY * numModZ; - ++iReadout) { + // hyperslab (files) + int numFiles = numImagesCaught / maxFramesPerFile; + if (numImagesCaught % maxFramesPerFile) + ++numFiles; + uint64_t framesSaved = 0; + for (int iFile = 0; iFile < numFiles; ++iFile) { - // interleaving for g2 (startLocation is 0 and 1) + uint64_t nDimx = + ((numImagesCaught - framesSaved) > maxFramesPerFile) + ? maxFramesPerFile + : (numImagesCaught - framesSaved); + + hsize_t startLocation[DATA_RANK] = {framesSaved, 0, 0}; + hsize_t strideBetweenBlocks[DATA_RANK] = {1, 1, 1}; + hsize_t numBlocks[DATA_RANK] = {nDimx, nDimy, nDimz}; + hsize_t blockSize[DATA_RANK] = {1, 1, 1}; + + hsize_t startLocationPara[VDS_PARA_RANK] = {framesSaved, 0}; + hsize_t strideBetweenBlocksPara[VDS_PARA_RANK] = {1, 1}; + hsize_t numBlocksPara[VDS_PARA_RANK] = {nDimx, 1}; + hsize_t blockSizePara[VDS_PARA_RANK] = {1, 1}; + + // interleaving for g2 if (gotthard25um) { - startLocation[2] = iReadout; + strideBetweenBlocks[2] = 2; } - vdsDataSpace.selectHyperslab(H5S_SELECT_SET, numBlocks, - startLocation, strideBetweenBlocks, - blockSize); + for (unsigned int iReadout = 0; iReadout < numModY * numModZ; + ++iReadout) { - vdsDataSpacePara.selectHyperslab( - H5S_SELECT_SET, numBlocksPara, startLocationPara, - strideBetweenBlocksPara, blockSizePara); - - // source file name - std::ostringstream os; - os << filePath << "/" << fileNamePrefix << "_d" - << (modulePos * numUnitsPerReadout + iReadout) << "_f" - << iFile << '_' << fileIndex << ".h5"; - std::string srcFileName = os.str(); - LOG(logDEBUG1) << srcFileName; - - // find relative path - std::string relative_srcFileName = srcFileName; - { - size_t p = srcFileName.rfind('/', srcFileName.length()); - if (p != std::string::npos) - relative_srcFileName = (srcFileName.substr( - p + 1, srcFileName.length() - p)); - } - - // source dataspace - hsize_t srcDims[DATA_RANK] = {nDimx, nDimy, nDimz}; - hsize_t srcDimsMax[DATA_RANK] = {H5S_UNLIMITED, nDimy, nDimz}; - H5::DataSpace srcDataSpace(DATA_RANK, srcDims, srcDimsMax); - hsize_t srcDimsPara[PARA_RANK] = {nDimx}; - hsize_t srcDimsMaxPara[PARA_RANK] = {H5S_UNLIMITED}; - H5::DataSpace srcDataSpacePara(PARA_RANK, srcDimsPara, - srcDimsMaxPara); - // temporary fixfor corner case bug: - // (framescaught not multiple of framesperfile, - // virtual parameter datasets error loading (bad scalar value)) - if (nDimx != maxFramesPerFile) { - hsize_t count[1] = {nDimx}; - hsize_t start[1] = {0}; - srcDataSpacePara.selectHyperslab( - H5S_SELECT_SET, count, start, strideBetweenBlocksPara, - blockSizePara); - } - - // mapping of property list - plist.setVirtual(vdsDataSpace, relative_srcFileName.c_str(), - DATASET_NAME, srcDataSpace); - for (unsigned int p = 0; p < paraSize; ++p) { - plistPara[p].setVirtual( - vdsDataSpacePara, relative_srcFileName.c_str(), - parameterNames[p].c_str(), srcDataSpacePara); - } - - // H5Sclose(srcDataspace); - // H5Sclose(srcDataspace_para); - - if (!gotthard25um) { - startLocation[2] += nDimz; - if (startLocation[2] >= (numModZ * nDimz)) { - startLocation[2] = 0; - startLocation[1] += nDimy; + // interleaving for g2 (startLocation is 0 and 1) + if (gotthard25um) { + startLocation[2] = iReadout; } - } - ++startLocationPara[1]; - } - framesSaved += nDimx; - } - // datasets - H5::DataSet vdsDataSet( - fd->createDataSet(DATASET_NAME, dataType, vdsDataSpace, plist)); - for (unsigned int p = 0; p < paraSize; ++p) { - H5::DataSet vdsDataSetPara(fd->createDataSet( - parameterNames[p].c_str(), parameterDataTypes[p], - vdsDataSpacePara, plistPara[p])); + vdsDataSpace.selectHyperslab( + H5S_SELECT_SET, numBlocks, startLocation, + strideBetweenBlocks, blockSize); + + vdsDataSpacePara.selectHyperslab( + H5S_SELECT_SET, numBlocksPara, startLocationPara, + strideBetweenBlocksPara, blockSizePara); + + // source file name + std::ostringstream os; + os << filePath << "/" << fileNamePrefix << "_d" + << (modulePos * numUnitsPerReadout + iReadout) << "_f" + << iFile << '_' << fileIndex << ".h5"; + std::string srcFileName = os.str(); + LOG(logDEBUG1) << srcFileName; + + // find relative path + std::string relative_srcFileName = srcFileName; + { + size_t p = srcFileName.rfind('/', srcFileName.length()); + if (p != std::string::npos) + relative_srcFileName = (srcFileName.substr( + p + 1, srcFileName.length() - p)); + } + + // source dataspace + hsize_t srcDims[DATA_RANK] = {nDimx, nDimy, nDimz}; + hsize_t srcDimsMax[DATA_RANK] = {H5S_UNLIMITED, nDimy, + nDimz}; + H5::DataSpace srcDataSpace(DATA_RANK, srcDims, srcDimsMax); + hsize_t srcDimsPara[PARA_RANK] = {nDimx}; + hsize_t srcDimsMaxPara[PARA_RANK] = {H5S_UNLIMITED}; + H5::DataSpace srcDataSpacePara(PARA_RANK, srcDimsPara, + srcDimsMaxPara); + // temporary fixfor corner case bug: + // (framescaught not multiple of framesperfile, + // virtual parameter datasets error loading (bad scalar + // value)) + if (nDimx != maxFramesPerFile) { + hsize_t count[1] = {nDimx}; + hsize_t start[1] = {0}; + srcDataSpacePara.selectHyperslab( + H5S_SELECT_SET, count, start, + strideBetweenBlocksPara, blockSizePara); + } + + // mapping of property list + plist.setVirtual(vdsDataSpace, relative_srcFileName.c_str(), + DATASET_NAME, srcDataSpace); + for (unsigned int p = 0; p < paraSize; ++p) { + plistPara[p].setVirtual( + vdsDataSpacePara, relative_srcFileName.c_str(), + parameterNames[p].c_str(), srcDataSpacePara); + } + + // H5Sclose(srcDataspace); + // H5Sclose(srcDataspace_para); + + if (!gotthard25um) { + startLocation[2] += nDimz; + if (startLocation[2] >= (numModZ * nDimz)) { + startLocation[2] = 0; + startLocation[1] += nDimy; + } + } + ++startLocationPara[1]; + } + framesSaved += nDimx; + } + // datasets + H5::DataSet vdsDataSet( + fd->createDataSet(DATASET_NAME, dataType, vdsDataSpace, plist)); + + for (unsigned int p = 0; p < paraSize; ++p) { + H5::DataSet vdsDataSetPara(fd->createDataSet( + parameterNames[p].c_str(), parameterDataTypes[p], + vdsDataSpacePara, plistPara[p])); + } } fd->close(); diff --git a/slsReceiverSoftware/src/MasterFileUtility.h b/slsReceiverSoftware/src/MasterFileUtility.h index ec7494c1d..0cdcb93d3 100644 --- a/slsReceiverSoftware/src/MasterFileUtility.h +++ b/slsReceiverSoftware/src/MasterFileUtility.h @@ -39,7 +39,8 @@ std::string CreateVirtualHDF5File( const uint64_t numImagesCaught, const int numModX, const int numModY, const H5::DataType dataType, const std::vector parameterNames, const std::vector parameterDataTypes, - std::mutex *hdf5LibMutex, bool gotthard25um); + std::mutex *hdf5LibMutex, bool gotthard25um, + std::vector &multiRoi); #endif } // namespace masterFileUtility From 24fcfb3f9d4d51eab347e7d3cbf83ab47463612e Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Tue, 24 Jun 2025 17:05:40 +0200 Subject: [PATCH 14/49] fix for empty roi vectors (which shouldnt be) as you cant know if its all or not in roi --- slsDetectorSoftware/include/sls/Detector.h | 5 +- slsDetectorSoftware/src/CallerSpecial.cpp | 3 +- slsDetectorSoftware/src/Module.cpp | 20 +- slsReceiverSoftware/src/ClientInterface.cpp | 13 +- slsReceiverSoftware/src/DataProcessor.cpp | 8 +- slsReceiverSoftware/src/Implementation.cpp | 44 ++- slsReceiverSoftware/src/Implementation.h | 4 +- slsReceiverSoftware/src/MasterFileUtility.cpp | 253 +++++++++--------- 8 files changed, 176 insertions(+), 174 deletions(-) diff --git a/slsDetectorSoftware/include/sls/Detector.h b/slsDetectorSoftware/include/sls/Detector.h index 10a3acba6..86e8d2372 100644 --- a/slsDetectorSoftware/include/sls/Detector.h +++ b/slsDetectorSoftware/include/sls/Detector.h @@ -714,7 +714,7 @@ class Detector { * restarts client and receiver zmq sockets if zmq streaming enabled. \n * [Gotthard2] second interface enabled to send veto information via 10Gbps * for debugging. By default, if veto enabled, it is sent via 2.5 gbps - * interface. */ + * interface. \nSetting this resets the receiver roi */ void setNumberofUDPInterfaces(int n, Positions pos = {}); /** [Jungfrau][Moench] */ @@ -995,7 +995,8 @@ class Detector { /** Returns port level ROIs. Max 2 ports and hence max 2 elements per readout */ std::vector getRxROI(int module_id) const; - /** only at multi module level without gap pixels. At most, 1 ROI per UDP port */ + /** only at multi module level without gap pixels. At most, 1 ROI per UDP + * port. Setting number of udp interfaces will clear the roi */ void setRxROI(const std::vector &args); void clearRxROI(); diff --git a/slsDetectorSoftware/src/CallerSpecial.cpp b/slsDetectorSoftware/src/CallerSpecial.cpp index 946f92570..4d921ef3a 100644 --- a/slsDetectorSoftware/src/CallerSpecial.cpp +++ b/slsDetectorSoftware/src/CallerSpecial.cpp @@ -734,7 +734,8 @@ std::string Caller::rx_roi(int action) { "Only allowed to set at multi module level and without gap " "ixels.\n\n\t" + "One can get rx_roi also at port level, by specifying the module id " - "and it will return the roi for each port.\n"; + "and it will return the roi for each port.\n" + "Setting number of udp interfaces will clear the rx_roi\n"; if (action == defs::HELP_ACTION) { os << helpMessage; } else if (action == defs::GET_ACTION) { diff --git a/slsDetectorSoftware/src/Module.cpp b/slsDetectorSoftware/src/Module.cpp index 6ee96af9e..c1c65add3 100644 --- a/slsDetectorSoftware/src/Module.cpp +++ b/slsDetectorSoftware/src/Module.cpp @@ -1534,8 +1534,10 @@ std::vector Module::getRxROI() const { std::vector retval(nPorts); if (nPorts > 0) client.Receive(retval); - if (nPorts > shm()->numUDPInterfaces) { - throw RuntimeError("Invalid number of rois: " + std::to_string(nPorts) + ". Max: " + std::to_string(shm()->numUDPInterfaces)); + if (nPorts != shm()->numUDPInterfaces) { + throw RuntimeError( + "Invalid number of rois: " + std::to_string(nPorts) + + ". Expected: " + std::to_string(shm()->numUDPInterfaces)); } LOG(logDEBUG1) << "ROI of Receiver" << moduleIndex << ": " << ToString(retval); @@ -1548,11 +1550,11 @@ void Module::setRxROI(const std::vector &portRois) { if (!shm()->useReceiverFlag) { throw RuntimeError("No receiver to set ROI."); } - if ((int)portRois.size() > shm()->numUDPInterfaces) { - throw RuntimeError("Invalid number of ROIs: " + - std::to_string(portRois.size()) + - ". Max: " + std::to_string(shm()->numUDPInterfaces)); - } + if ((int)portRois.size() != shm()->numUDPInterfaces) { + throw RuntimeError( + "Invalid number of ROIs: " + std::to_string(portRois.size()) + + ". Expected: " + std::to_string(shm()->numUDPInterfaces)); + } // check number of ports auto client = ReceiverSocket(shm()->rxHostname, shm()->rxTCPPort); client.Send(F_RECEIVER_SET_RECEIVER_ROI); @@ -1577,6 +1579,10 @@ void Module::setRxROIMetadata(const std::vector &args) { receiver.Send(size); if (size > 0) receiver.Send(args); + if (size < 1) { + throw RuntimeError("Invalid number of ROI metadata: " + + std::to_string(size) + ". Min: 1."); + } if (receiver.Receive() == FAIL) { throw ReceiverError("Receiver " + std::to_string(moduleIndex) + " returned error: " + receiver.readErrorMessage()); diff --git a/slsReceiverSoftware/src/ClientInterface.cpp b/slsReceiverSoftware/src/ClientInterface.cpp index 37611ad5d..d0336ba49 100644 --- a/slsReceiverSoftware/src/ClientInterface.cpp +++ b/slsReceiverSoftware/src/ClientInterface.cpp @@ -1696,6 +1696,11 @@ int ClientInterface::get_receiver_roi(Interface &socket) { auto retvals = impl()->getPortROIs(); LOG(logDEBUG1) << "Receiver roi retval:" << ToString(retvals); auto size = static_cast(retvals.size()); + if (size != impl()->getNumberofUDPInterfaces()) { + throw RuntimeError("Invalid number of ROIs received: " + + std::to_string(size) + ". Expected: " + + std::to_string(impl()->getNumberofUDPInterfaces())); + } socket.Send(size); if (size > 0) socket.Send(retvals); @@ -1708,9 +1713,9 @@ int ClientInterface::set_receiver_roi(Interface &socket) { if (roiSize > 0) { socket.Receive(args); } - if (roiSize > impl()->getNumberofUDPInterfaces()) { + if (roiSize != impl()->getNumberofUDPInterfaces()) { throw RuntimeError("Invalid number of ROIs received: " + - std::to_string(roiSize) + ". Max: " + + std::to_string(roiSize) + ". Expected: " + std::to_string(impl()->getNumberofUDPInterfaces())); } if (detType == CHIPTESTBOARD || detType == XILINX_CHIPTESTBOARD) @@ -1730,6 +1735,10 @@ int ClientInterface::set_receiver_roi(Interface &socket) { int ClientInterface::set_receiver_roi_metadata(Interface &socket) { auto roiSize = socket.Receive(); LOG(logDEBUG1) << "Number of ReceiverROI metadata: " << roiSize; + if (roiSize < 1) { + throw RuntimeError("Invalid number of ROIs received: " + + std::to_string(roiSize) + ". Min: 1."); + } std::vector rois(roiSize); if (roiSize > 0) { socket.Receive(rois); diff --git a/slsReceiverSoftware/src/DataProcessor.cpp b/slsReceiverSoftware/src/DataProcessor.cpp index 64ae23547..1beac1bcc 100644 --- a/slsReceiverSoftware/src/DataProcessor.cpp +++ b/slsReceiverSoftware/src/DataProcessor.cpp @@ -208,10 +208,10 @@ std::string DataProcessor::CreateVirtualFile( const int modulePos, const int numModX, const int numModY, std::mutex *hdf5LibMutex) { - if (!multiRoiMetadata.empty() && generalData->dynamicRange == 4) { + /*if (!multiRoiMetadata.empty() && generalData->dynamicRange == 4) { throw std::runtime_error("Skipping virtual hdf5 file since rx_roi is " "enabled in 4 bit mode."); - } + }*/ bool gotthard25um = ((generalData->detType == GOTTHARD || generalData->detType == GOTTHARD2) && @@ -240,10 +240,10 @@ void DataProcessor::LinkFileInMaster(const std::string &masterFileName, const bool silentMode, std::mutex *hdf5LibMutex) { - if (!multiRoiMetadata.empty()) { + /*if (!multiRoiMetadata.empty()) { throw std::runtime_error( "Should not be here, roi with hdf5 virtual should throw."); - } + }*/ std::string fname{virtualFileName}, masterfname{masterFileName}; // if no virtual file, link data file if (virtualFileName.empty()) { diff --git a/slsReceiverSoftware/src/Implementation.cpp b/slsReceiverSoftware/src/Implementation.cpp index 10f5aead7..8a9dcdd4b 100644 --- a/slsReceiverSoftware/src/Implementation.cpp +++ b/slsReceiverSoftware/src/Implementation.cpp @@ -184,7 +184,7 @@ void Implementation::SetupListener(int i) { listener[i]->SetUdpPortNumber(udpPortNum[i]); listener[i]->SetEthernetInterface(eth[i]); listener[i]->SetActivate(activated); - listener[i]->SetIsOutsideRoi(i >= (int)portRois.size()); + listener[i]->SetIsOutsideRoi(portRois[i].noRoi()); listener[i]->SetDetectorDatastream(detectorDataStream[i]); listener[i]->SetSilentMode(silentMode); } @@ -194,12 +194,7 @@ void Implementation::SetupDataProcessor(int i) { dataProcessor[i]->SetGeneralData(generalData); dataProcessor[i]->SetUdpPortNumber(udpPortNum[i]); dataProcessor[i]->SetActivate(activated); - if (i >= (int)portRois.size()) { - ROI roi{0, 0, 0, 0}; - dataProcessor[i]->SetPortROI(roi); - } else { - dataProcessor[i]->SetPortROI(portRois[i]); - } + dataProcessor[i]->SetPortROI(portRois[i]); if (i == 0) dataProcessor[0]->setMultiROIMetadata(multiRoiMetadata); dataProcessor[i]->SetDataStreamEnable(dataStreamEnable); @@ -223,12 +218,7 @@ void Implementation::SetupDataStreamer(int i) { dataStreamer[i]->SetFlipRows(flipRows); dataStreamer[i]->SetNumberofPorts(numPorts); dataStreamer[i]->SetNumberofTotalFrames(numberOfTotalFrames); - if (i >= (int)portRois.size()) { - ROI roi{0, 0, 0, 0}; - dataStreamer[i]->SetPortROI(roi); - } else { - dataStreamer[i]->SetPortROI(portRois[i]); - } + dataStreamer[i]->SetPortROI(portRois[i]); } slsDetectorDefs::xy Implementation::getDetectorSize() const { @@ -415,24 +405,14 @@ void Implementation::setPortROIs(const std::vector &args) { portRois = args; for (size_t i = 0; i != listener.size(); ++i) - listener[i]->SetIsOutsideRoi(i >= portRois.size()); + listener[i]->SetIsOutsideRoi(portRois[i].noRoi()); for (size_t i = 0; i != dataProcessor.size(); ++i) { - if (i >= portRois.size()) { - ROI roi{0, 0, 0, 0}; - dataProcessor[i]->SetPortROI(roi); - } else { - dataProcessor[i]->SetPortROI(portRois[i]); - } + dataProcessor[i]->SetPortROI(portRois[i]); } if (dataProcessor.size() > 0) dataProcessor[0]->setMultiROIMetadata(multiRoiMetadata); for (size_t i = 0; i != dataStreamer.size(); ++i) { - if (i >= portRois.size()) { - ROI roi{0, 0, 0, 0}; - dataStreamer[i]->SetPortROI(roi); - } else { - dataStreamer[i]->SetPortROI(portRois[i]); - } + dataStreamer[i]->SetPortROI(portRois[i]); } LOG(logINFO) << "Rois (per port): " << ToString(portRois); } @@ -737,7 +717,7 @@ void Implementation::stopReceiver() { } else if (!detectorDataStream[i]) { summary = (i == 0 ? "\n\tDeactivated Left Port" : "\n\tDeactivated Right Port"); - } else if (i >= (int)portRois.size()) { + } else if (portRois[i].noRoi()) { summary = "\n\tNo Roi on Port[" + std::to_string(i) + ']'; } else { std::ostringstream os; @@ -909,7 +889,8 @@ void Implementation::StartMasterWriter() { masterAttributes.scanParams = scanParams; masterAttributes.totalFrames = numberOfTotalFrames; // complete ROI (for each port TODO?) - if (multiRoiMetadata.empty()) { + if (multiRoiMetadata.size() == 1 && + multiRoiMetadata[0].completeRoi()) { int nTotalPixelsX = (generalData->nPixelsX * numPorts.x); int nTotalPixelsY = (generalData->nPixelsY * numPorts.y); if (nTotalPixelsY == 1) { @@ -1049,8 +1030,13 @@ void Implementation::setNumberofUDPInterfaces(const int n) { // fifo SetupFifoStructure(); + + // roi cleared - complete detector + std::vector rois(n); + std::vector multiRoi(1); // recalculate port rois booleans for listener, processor and streamer - setPortROIs(portRois); + setPortROIs(rois); + setMultiROIMetadata(multiRoi); // create threads for (int i = 0; i < generalData->numUDPInterfaces; ++i) { diff --git a/slsReceiverSoftware/src/Implementation.h b/slsReceiverSoftware/src/Implementation.h index 6f25287fd..099454441 100644 --- a/slsReceiverSoftware/src/Implementation.h +++ b/slsReceiverSoftware/src/Implementation.h @@ -307,8 +307,8 @@ class Implementation : private virtual slsDetectorDefs { bool framePadding{true}; pid_t parentThreadId; pid_t tcpThreadId; - std::vector portRois{}; - std::vector multiRoiMetadata{}; + std::vector portRois{1}; + std::vector multiRoiMetadata{1}; // file parameters fileFormat fileFormatType{BINARY}; diff --git a/slsReceiverSoftware/src/MasterFileUtility.cpp b/slsReceiverSoftware/src/MasterFileUtility.cpp index 6e0c7903b..529dbde33 100644 --- a/slsReceiverSoftware/src/MasterFileUtility.cpp +++ b/slsReceiverSoftware/src/MasterFileUtility.cpp @@ -208,150 +208,149 @@ std::string CreateVirtualHDF5File( attribute.write(H5::PredType::NATIVE_DOUBLE, &dValue); // complete detector in roi - if (multiRoi.empty()) { - int ny = nPixelsY * numModY; - int nx = nPixelsX * numModX; - if (nPixelsY == 1) { - multiRoi.push_back(defs::ROI{0, nx - 1}); - } else { - multiRoi.push_back(defs::ROI{0, nx - 1, 0, ny - 1}); - } + /*if (multiRoi.empty()) { + int ny = nPixelsY * numModY; + int nx = nPixelsX * numModX; + if (nPixelsY == 1) { + multiRoi.push_back(defs::ROI{0, nx - 1}); + } else { + multiRoi.push_back(defs::ROI{0, nx - 1, 0, ny - 1}); + } + }*/ + + // for (size_t iRoi = 0; iRoi != multiRoi.size(); ++iRoi) { + + // dataspace + hsize_t vdsDims[DATA_RANK] = {numImagesCaught, numModY * nDimy, + numModZ * nDimz}; + hsize_t vdsDimsPara[VDS_PARA_RANK] = {numImagesCaught, + numModY * numModZ}; + H5::DataSpace vdsDataSpace(DATA_RANK, vdsDims, nullptr); + H5::DataSpace vdsDataSpacePara(VDS_PARA_RANK, vdsDimsPara, nullptr); + + // property list + H5::DSetCreatPropList plist; + uint64_t fill_value = -1; + plist.setFillValue(dataType, &fill_value); + std::vector plistPara(paraSize); + // ignoring last fill (string) + for (unsigned int i = 0; i != plistPara.size() - 1; ++i) { + plistPara[i].setFillValue(parameterDataTypes[i], &fill_value); } - for (size_t iRoi = 0; iRoi != multiRoi.size(); ++iRoi) { + // hyperslab (files) + int numFiles = numImagesCaught / maxFramesPerFile; + if (numImagesCaught % maxFramesPerFile) + ++numFiles; + uint64_t framesSaved = 0; + for (int iFile = 0; iFile < numFiles; ++iFile) { - // dataspace - hsize_t vdsDims[DATA_RANK] = {numImagesCaught, numModY * nDimy, - numModZ * nDimz}; - hsize_t vdsDimsPara[VDS_PARA_RANK] = {numImagesCaught, - numModY * numModZ}; - H5::DataSpace vdsDataSpace(DATA_RANK, vdsDims, nullptr); - H5::DataSpace vdsDataSpacePara(VDS_PARA_RANK, vdsDimsPara, nullptr); + uint64_t nDimx = + ((numImagesCaught - framesSaved) > maxFramesPerFile) + ? maxFramesPerFile + : (numImagesCaught - framesSaved); - // property list - H5::DSetCreatPropList plist; - uint64_t fill_value = -1; - plist.setFillValue(dataType, &fill_value); - std::vector plistPara(paraSize); - // ignoring last fill (string) - for (unsigned int i = 0; i != plistPara.size() - 1; ++i) { - plistPara[i].setFillValue(parameterDataTypes[i], &fill_value); + hsize_t startLocation[DATA_RANK] = {framesSaved, 0, 0}; + hsize_t strideBetweenBlocks[DATA_RANK] = {1, 1, 1}; + hsize_t numBlocks[DATA_RANK] = {nDimx, nDimy, nDimz}; + hsize_t blockSize[DATA_RANK] = {1, 1, 1}; + + hsize_t startLocationPara[VDS_PARA_RANK] = {framesSaved, 0}; + hsize_t strideBetweenBlocksPara[VDS_PARA_RANK] = {1, 1}; + hsize_t numBlocksPara[VDS_PARA_RANK] = {nDimx, 1}; + hsize_t blockSizePara[VDS_PARA_RANK] = {1, 1}; + + // interleaving for g2 + if (gotthard25um) { + strideBetweenBlocks[2] = 2; } - // hyperslab (files) - int numFiles = numImagesCaught / maxFramesPerFile; - if (numImagesCaught % maxFramesPerFile) - ++numFiles; - uint64_t framesSaved = 0; - for (int iFile = 0; iFile < numFiles; ++iFile) { + for (unsigned int iReadout = 0; iReadout < numModY * numModZ; + ++iReadout) { - uint64_t nDimx = - ((numImagesCaught - framesSaved) > maxFramesPerFile) - ? maxFramesPerFile - : (numImagesCaught - framesSaved); - - hsize_t startLocation[DATA_RANK] = {framesSaved, 0, 0}; - hsize_t strideBetweenBlocks[DATA_RANK] = {1, 1, 1}; - hsize_t numBlocks[DATA_RANK] = {nDimx, nDimy, nDimz}; - hsize_t blockSize[DATA_RANK] = {1, 1, 1}; - - hsize_t startLocationPara[VDS_PARA_RANK] = {framesSaved, 0}; - hsize_t strideBetweenBlocksPara[VDS_PARA_RANK] = {1, 1}; - hsize_t numBlocksPara[VDS_PARA_RANK] = {nDimx, 1}; - hsize_t blockSizePara[VDS_PARA_RANK] = {1, 1}; - - // interleaving for g2 + // interleaving for g2 (startLocation is 0 and 1) if (gotthard25um) { - strideBetweenBlocks[2] = 2; + startLocation[2] = iReadout; } - for (unsigned int iReadout = 0; iReadout < numModY * numModZ; - ++iReadout) { + vdsDataSpace.selectHyperslab(H5S_SELECT_SET, numBlocks, + startLocation, strideBetweenBlocks, + blockSize); - // interleaving for g2 (startLocation is 0 and 1) - if (gotthard25um) { - startLocation[2] = iReadout; - } + vdsDataSpacePara.selectHyperslab( + H5S_SELECT_SET, numBlocksPara, startLocationPara, + strideBetweenBlocksPara, blockSizePara); - vdsDataSpace.selectHyperslab( - H5S_SELECT_SET, numBlocks, startLocation, - strideBetweenBlocks, blockSize); + // source file name + std::ostringstream os; + os << filePath << "/" << fileNamePrefix << "_d" + << (modulePos * numUnitsPerReadout + iReadout) << "_f" + << iFile << '_' << fileIndex << ".h5"; + std::string srcFileName = os.str(); + LOG(logDEBUG1) << srcFileName; - vdsDataSpacePara.selectHyperslab( - H5S_SELECT_SET, numBlocksPara, startLocationPara, - strideBetweenBlocksPara, blockSizePara); - - // source file name - std::ostringstream os; - os << filePath << "/" << fileNamePrefix << "_d" - << (modulePos * numUnitsPerReadout + iReadout) << "_f" - << iFile << '_' << fileIndex << ".h5"; - std::string srcFileName = os.str(); - LOG(logDEBUG1) << srcFileName; - - // find relative path - std::string relative_srcFileName = srcFileName; - { - size_t p = srcFileName.rfind('/', srcFileName.length()); - if (p != std::string::npos) - relative_srcFileName = (srcFileName.substr( - p + 1, srcFileName.length() - p)); - } - - // source dataspace - hsize_t srcDims[DATA_RANK] = {nDimx, nDimy, nDimz}; - hsize_t srcDimsMax[DATA_RANK] = {H5S_UNLIMITED, nDimy, - nDimz}; - H5::DataSpace srcDataSpace(DATA_RANK, srcDims, srcDimsMax); - hsize_t srcDimsPara[PARA_RANK] = {nDimx}; - hsize_t srcDimsMaxPara[PARA_RANK] = {H5S_UNLIMITED}; - H5::DataSpace srcDataSpacePara(PARA_RANK, srcDimsPara, - srcDimsMaxPara); - // temporary fixfor corner case bug: - // (framescaught not multiple of framesperfile, - // virtual parameter datasets error loading (bad scalar - // value)) - if (nDimx != maxFramesPerFile) { - hsize_t count[1] = {nDimx}; - hsize_t start[1] = {0}; - srcDataSpacePara.selectHyperslab( - H5S_SELECT_SET, count, start, - strideBetweenBlocksPara, blockSizePara); - } - - // mapping of property list - plist.setVirtual(vdsDataSpace, relative_srcFileName.c_str(), - DATASET_NAME, srcDataSpace); - for (unsigned int p = 0; p < paraSize; ++p) { - plistPara[p].setVirtual( - vdsDataSpacePara, relative_srcFileName.c_str(), - parameterNames[p].c_str(), srcDataSpacePara); - } - - // H5Sclose(srcDataspace); - // H5Sclose(srcDataspace_para); - - if (!gotthard25um) { - startLocation[2] += nDimz; - if (startLocation[2] >= (numModZ * nDimz)) { - startLocation[2] = 0; - startLocation[1] += nDimy; - } - } - ++startLocationPara[1]; + // find relative path + std::string relative_srcFileName = srcFileName; + { + size_t p = srcFileName.rfind('/', srcFileName.length()); + if (p != std::string::npos) + relative_srcFileName = (srcFileName.substr( + p + 1, srcFileName.length() - p)); } - framesSaved += nDimx; - } - // datasets - H5::DataSet vdsDataSet( - fd->createDataSet(DATASET_NAME, dataType, vdsDataSpace, plist)); - for (unsigned int p = 0; p < paraSize; ++p) { - H5::DataSet vdsDataSetPara(fd->createDataSet( - parameterNames[p].c_str(), parameterDataTypes[p], - vdsDataSpacePara, plistPara[p])); + // source dataspace + hsize_t srcDims[DATA_RANK] = {nDimx, nDimy, nDimz}; + hsize_t srcDimsMax[DATA_RANK] = {H5S_UNLIMITED, nDimy, nDimz}; + H5::DataSpace srcDataSpace(DATA_RANK, srcDims, srcDimsMax); + hsize_t srcDimsPara[PARA_RANK] = {nDimx}; + hsize_t srcDimsMaxPara[PARA_RANK] = {H5S_UNLIMITED}; + H5::DataSpace srcDataSpacePara(PARA_RANK, srcDimsPara, + srcDimsMaxPara); + // temporary fixfor corner case bug: + // (framescaught not multiple of framesperfile, + // virtual parameter datasets error loading (bad scalar + // value)) + if (nDimx != maxFramesPerFile) { + hsize_t count[1] = {nDimx}; + hsize_t start[1] = {0}; + srcDataSpacePara.selectHyperslab( + H5S_SELECT_SET, count, start, strideBetweenBlocksPara, + blockSizePara); + } + + // mapping of property list + plist.setVirtual(vdsDataSpace, relative_srcFileName.c_str(), + DATASET_NAME, srcDataSpace); + for (unsigned int p = 0; p < paraSize; ++p) { + plistPara[p].setVirtual( + vdsDataSpacePara, relative_srcFileName.c_str(), + parameterNames[p].c_str(), srcDataSpacePara); + } + + // H5Sclose(srcDataspace); + // H5Sclose(srcDataspace_para); + + if (!gotthard25um) { + startLocation[2] += nDimz; + if (startLocation[2] >= (numModZ * nDimz)) { + startLocation[2] = 0; + startLocation[1] += nDimy; + } + } + ++startLocationPara[1]; } + framesSaved += nDimx; } + // datasets + H5::DataSet vdsDataSet( + fd->createDataSet(DATASET_NAME, dataType, vdsDataSpace, plist)); + + for (unsigned int p = 0; p < paraSize; ++p) { + H5::DataSet vdsDataSetPara(fd->createDataSet( + parameterNames[p].c_str(), parameterDataTypes[p], + vdsDataSpacePara, plistPara[p])); + } + //} fd->close(); } catch (const H5::Exception &error) { From 8f0c9463932d957db81079b46b6dea42b45aa3ce Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Tue, 24 Jun 2025 17:30:59 +0200 Subject: [PATCH 15/49] wip: to map roi to virutal --- slsReceiverSoftware/src/MasterFileUtility.cpp | 260 +++++++++--------- 1 file changed, 131 insertions(+), 129 deletions(-) diff --git a/slsReceiverSoftware/src/MasterFileUtility.cpp b/slsReceiverSoftware/src/MasterFileUtility.cpp index 529dbde33..bc9d06586 100644 --- a/slsReceiverSoftware/src/MasterFileUtility.cpp +++ b/slsReceiverSoftware/src/MasterFileUtility.cpp @@ -208,149 +208,151 @@ std::string CreateVirtualHDF5File( attribute.write(H5::PredType::NATIVE_DOUBLE, &dValue); // complete detector in roi - /*if (multiRoi.empty()) { - int ny = nPixelsY * numModY; - int nx = nPixelsX * numModX; - if (nPixelsY == 1) { - multiRoi.push_back(defs::ROI{0, nx - 1}); - } else { - multiRoi.push_back(defs::ROI{0, nx - 1, 0, ny - 1}); - } - }*/ - - // for (size_t iRoi = 0; iRoi != multiRoi.size(); ++iRoi) { - - // dataspace - hsize_t vdsDims[DATA_RANK] = {numImagesCaught, numModY * nDimy, - numModZ * nDimz}; - hsize_t vdsDimsPara[VDS_PARA_RANK] = {numImagesCaught, - numModY * numModZ}; - H5::DataSpace vdsDataSpace(DATA_RANK, vdsDims, nullptr); - H5::DataSpace vdsDataSpacePara(VDS_PARA_RANK, vdsDimsPara, nullptr); - - // property list - H5::DSetCreatPropList plist; - uint64_t fill_value = -1; - plist.setFillValue(dataType, &fill_value); - std::vector plistPara(paraSize); - // ignoring last fill (string) - for (unsigned int i = 0; i != plistPara.size() - 1; ++i) { - plistPara[i].setFillValue(parameterDataTypes[i], &fill_value); + if (multiRoi.size() == 1 && multiRoi[0].isComplete()) { + int ny = nPixelsY * numModY; + int nx = nPixelsX * numModX; + if (nPixelsY == 1) { + multiRoi.push_back(defs::ROI{0, nx - 1}); + } else { + multiRoi.push_back(defs::ROI{0, nx - 1, 0, ny - 1}); + } } - // hyperslab (files) - int numFiles = numImagesCaught / maxFramesPerFile; - if (numImagesCaught % maxFramesPerFile) - ++numFiles; - uint64_t framesSaved = 0; - for (int iFile = 0; iFile < numFiles; ++iFile) { + for (size_t iRoi = 0; iRoi != multiRoi.size(); ++iRoi) { - uint64_t nDimx = - ((numImagesCaught - framesSaved) > maxFramesPerFile) - ? maxFramesPerFile - : (numImagesCaught - framesSaved); + // dataspace + hsize_t vdsDims[DATA_RANK] = {numImagesCaught, numModY * nDimy, + numModZ * nDimz}; + hsize_t vdsDimsPara[VDS_PARA_RANK] = {numImagesCaught, + numModY * numModZ}; + H5::DataSpace vdsDataSpace(DATA_RANK, vdsDims, nullptr); + H5::DataSpace vdsDataSpacePara(VDS_PARA_RANK, vdsDimsPara, nullptr); - hsize_t startLocation[DATA_RANK] = {framesSaved, 0, 0}; - hsize_t strideBetweenBlocks[DATA_RANK] = {1, 1, 1}; - hsize_t numBlocks[DATA_RANK] = {nDimx, nDimy, nDimz}; - hsize_t blockSize[DATA_RANK] = {1, 1, 1}; - - hsize_t startLocationPara[VDS_PARA_RANK] = {framesSaved, 0}; - hsize_t strideBetweenBlocksPara[VDS_PARA_RANK] = {1, 1}; - hsize_t numBlocksPara[VDS_PARA_RANK] = {nDimx, 1}; - hsize_t blockSizePara[VDS_PARA_RANK] = {1, 1}; - - // interleaving for g2 - if (gotthard25um) { - strideBetweenBlocks[2] = 2; + // property list + H5::DSetCreatPropList plist; + uint64_t fill_value = -1; + plist.setFillValue(dataType, &fill_value); + std::vector plistPara(paraSize); + // ignoring last fill (string) + for (unsigned int i = 0; i != plistPara.size() - 1; ++i) { + plistPara[i].setFillValue(parameterDataTypes[i], &fill_value); } - for (unsigned int iReadout = 0; iReadout < numModY * numModZ; - ++iReadout) { + // hyperslab (files) + int numFiles = numImagesCaught / maxFramesPerFile; + if (numImagesCaught % maxFramesPerFile) + ++numFiles; + uint64_t framesSaved = 0; + for (int iFile = 0; iFile < numFiles; ++iFile) { - // interleaving for g2 (startLocation is 0 and 1) + uint64_t nDimx = + ((numImagesCaught - framesSaved) > maxFramesPerFile) + ? maxFramesPerFile + : (numImagesCaught - framesSaved); + + hsize_t startLocation[DATA_RANK] = {framesSaved, 0, 0}; + hsize_t strideBetweenBlocks[DATA_RANK] = {1, 1, 1}; + hsize_t numBlocks[DATA_RANK] = {nDimx, nDimy, nDimz}; + hsize_t blockSize[DATA_RANK] = {1, 1, 1}; + + hsize_t startLocationPara[VDS_PARA_RANK] = {framesSaved, 0}; + hsize_t strideBetweenBlocksPara[VDS_PARA_RANK] = {1, 1}; + hsize_t numBlocksPara[VDS_PARA_RANK] = {nDimx, 1}; + hsize_t blockSizePara[VDS_PARA_RANK] = {1, 1}; + + // interleaving for g2 if (gotthard25um) { - startLocation[2] = iReadout; + strideBetweenBlocks[2] = 2; } - vdsDataSpace.selectHyperslab(H5S_SELECT_SET, numBlocks, - startLocation, strideBetweenBlocks, - blockSize); + for (unsigned int iReadout = 0; iReadout < numModY * numModZ; + ++iReadout) { - vdsDataSpacePara.selectHyperslab( - H5S_SELECT_SET, numBlocksPara, startLocationPara, - strideBetweenBlocksPara, blockSizePara); - - // source file name - std::ostringstream os; - os << filePath << "/" << fileNamePrefix << "_d" - << (modulePos * numUnitsPerReadout + iReadout) << "_f" - << iFile << '_' << fileIndex << ".h5"; - std::string srcFileName = os.str(); - LOG(logDEBUG1) << srcFileName; - - // find relative path - std::string relative_srcFileName = srcFileName; - { - size_t p = srcFileName.rfind('/', srcFileName.length()); - if (p != std::string::npos) - relative_srcFileName = (srcFileName.substr( - p + 1, srcFileName.length() - p)); - } - - // source dataspace - hsize_t srcDims[DATA_RANK] = {nDimx, nDimy, nDimz}; - hsize_t srcDimsMax[DATA_RANK] = {H5S_UNLIMITED, nDimy, nDimz}; - H5::DataSpace srcDataSpace(DATA_RANK, srcDims, srcDimsMax); - hsize_t srcDimsPara[PARA_RANK] = {nDimx}; - hsize_t srcDimsMaxPara[PARA_RANK] = {H5S_UNLIMITED}; - H5::DataSpace srcDataSpacePara(PARA_RANK, srcDimsPara, - srcDimsMaxPara); - // temporary fixfor corner case bug: - // (framescaught not multiple of framesperfile, - // virtual parameter datasets error loading (bad scalar - // value)) - if (nDimx != maxFramesPerFile) { - hsize_t count[1] = {nDimx}; - hsize_t start[1] = {0}; - srcDataSpacePara.selectHyperslab( - H5S_SELECT_SET, count, start, strideBetweenBlocksPara, - blockSizePara); - } - - // mapping of property list - plist.setVirtual(vdsDataSpace, relative_srcFileName.c_str(), - DATASET_NAME, srcDataSpace); - for (unsigned int p = 0; p < paraSize; ++p) { - plistPara[p].setVirtual( - vdsDataSpacePara, relative_srcFileName.c_str(), - parameterNames[p].c_str(), srcDataSpacePara); - } - - // H5Sclose(srcDataspace); - // H5Sclose(srcDataspace_para); - - if (!gotthard25um) { - startLocation[2] += nDimz; - if (startLocation[2] >= (numModZ * nDimz)) { - startLocation[2] = 0; - startLocation[1] += nDimy; + // interleaving for g2 (startLocation is 0 and 1) + if (gotthard25um) { + startLocation[2] = iReadout; } - } - ++startLocationPara[1]; - } - framesSaved += nDimx; - } - // datasets - H5::DataSet vdsDataSet( - fd->createDataSet(DATASET_NAME, dataType, vdsDataSpace, plist)); - for (unsigned int p = 0; p < paraSize; ++p) { - H5::DataSet vdsDataSetPara(fd->createDataSet( - parameterNames[p].c_str(), parameterDataTypes[p], - vdsDataSpacePara, plistPara[p])); + vdsDataSpace.selectHyperslab( + H5S_SELECT_SET, numBlocks, startLocation, + strideBetweenBlocks, blockSize); + + vdsDataSpacePara.selectHyperslab( + H5S_SELECT_SET, numBlocksPara, startLocationPara, + strideBetweenBlocksPara, blockSizePara); + + // source file name + std::ostringstream os; + os << filePath << "/" << fileNamePrefix << "_d" + << (modulePos * numUnitsPerReadout + iReadout) << "_f" + << iFile << '_' << fileIndex << ".h5"; + std::string srcFileName = os.str(); + LOG(logDEBUG1) << srcFileName; + + // find relative path + std::string relative_srcFileName = srcFileName; + { + size_t p = srcFileName.rfind('/', srcFileName.length()); + if (p != std::string::npos) + relative_srcFileName = (srcFileName.substr( + p + 1, srcFileName.length() - p)); + } + + // source dataspace + hsize_t srcDims[DATA_RANK] = {nDimx, nDimy, nDimz}; + hsize_t srcDimsMax[DATA_RANK] = {H5S_UNLIMITED, nDimy, + nDimz}; + H5::DataSpace srcDataSpace(DATA_RANK, srcDims, srcDimsMax); + hsize_t srcDimsPara[PARA_RANK] = {nDimx}; + hsize_t srcDimsMaxPara[PARA_RANK] = {H5S_UNLIMITED}; + H5::DataSpace srcDataSpacePara(PARA_RANK, srcDimsPara, + srcDimsMaxPara); + // temporary fixfor corner case bug: + // (framescaught not multiple of framesperfile, + // virtual parameter datasets error loading (bad scalar + // value)) + // TODO WHY???? + /*if (nDimx != maxFramesPerFile) { + hsize_t count[1] = {nDimx}; + hsize_t start[1] = {0}; + srcDataSpacePara.selectHyperslab( + H5S_SELECT_SET, count, start, + strideBetweenBlocksPara, blockSizePara); + }*/ + + // mapping of property list + plist.setVirtual(vdsDataSpace, relative_srcFileName.c_str(), + DATASET_NAME, srcDataSpace); + for (unsigned int p = 0; p < paraSize; ++p) { + plistPara[p].setVirtual( + vdsDataSpacePara, relative_srcFileName.c_str(), + parameterNames[p].c_str(), srcDataSpacePara); + } + + // H5Sclose(srcDataspace); + // H5Sclose(srcDataspace_para); + + if (!gotthard25um) { + startLocation[2] += nDimz; + if (startLocation[2] >= (numModZ * nDimz)) { + startLocation[2] = 0; + startLocation[1] += nDimy; + } + } + ++startLocationPara[1]; + } + framesSaved += nDimx; + } + // datasets + H5::DataSet vdsDataSet( + fd->createDataSet(DATASET_NAME, dataType, vdsDataSpace, plist)); + + for (unsigned int p = 0; p < paraSize; ++p) { + H5::DataSet vdsDataSetPara(fd->createDataSet( + parameterNames[p].c_str(), parameterDataTypes[p], + vdsDataSpacePara, plistPara[p])); + } } - //} fd->close(); } catch (const H5::Exception &error) { From 23f898134610bad10ad2f94be42c46cec6ff8b56 Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Wed, 25 Jun 2025 13:41:47 +0200 Subject: [PATCH 16/49] fix for eiger, added python test for testig roi in different module and detector type configurations --- slsDetectorSoftware/src/DetectorImpl.cpp | 4 + .../tests/Caller/test-Caller-rx.cpp | 17 ++- slsReceiverSoftware/src/Implementation.cpp | 14 ++- slsReceiverSoftware/src/MasterFileUtility.cpp | 4 +- tests/CMakeLists.txt | 1 + tests/scripts/test_roi.py | 114 ++++++++++++++++++ 6 files changed, 146 insertions(+), 8 deletions(-) create mode 100644 tests/scripts/test_roi.py diff --git a/slsDetectorSoftware/src/DetectorImpl.cpp b/slsDetectorSoftware/src/DetectorImpl.cpp index 5cb2744b5..236447a9a 100644 --- a/slsDetectorSoftware/src/DetectorImpl.cpp +++ b/slsDetectorSoftware/src/DetectorImpl.cpp @@ -1860,6 +1860,10 @@ void DetectorImpl::setRxROI(const std::vector &args) { throw RuntimeError("No Modules added"); } + if (args.empty()) { + return clearRxROI(); + } + validateROIs(args); int nPortsPerModule = Parallel(&Module::getNumberofUDPInterfacesFromShm, {}).tsquash("Inconsistent number of udp ports set up per module"); diff --git a/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp b/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp index 9b0a42997..24f815cc7 100644 --- a/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp +++ b/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp @@ -626,10 +626,13 @@ TEST_CASE("rx_roi", "[.cmdcall]") { REQUIRE(oss1.str() == "rx_roi [[" + stringMin + ", " + std::to_string(portSize.x - 1) + "20, 30]]\n"); } } + std::cout << "done with eiger roi tests" << std::endl; } // multiple ports vertically - else if (numinterfaces == 2 || (det.size() == 2 && det.getModuleGeometry().y > 1)) { + if (((det_type == defs::JUNGFRAU || det_type == defs::MOENCH) && (numinterfaces == 2)) || + (det.size() == 2 && det.getModuleGeometry().y > 1)) { + std::cout << "starting with jungfrau or other tests" << std::endl; std::string stringMin = std::to_string(portSize.y); std::string stringMax = std::to_string(portSize.y + 1); @@ -653,13 +656,19 @@ TEST_CASE("rx_roi", "[.cmdcall]") { REQUIRE(oss.str() == "rx_roi [[20, 30, " + stringMin + ", " + stringMax + "]]\n"); REQUIRE_NOTHROW( caller.call("rx_roi", {}, 0, GET, oss1)); - // non-eiger with 2 interfaces returns 2 values for 2 ports per module - if (numinterfaces == 2) { + + // non-eiger with 2 interfaces returns 2 values for 2 ports per module + if ((det_type == defs::JUNGFRAU || det_type == defs::MOENCH) && (numinterfaces == 2)) { REQUIRE(oss1.str() == "rx_roi [[20, 30, " + stringMin + ", " + std::to_string(portSize.y - 1) + "], [20, 30, " + std::to_string(portSize.y) + ", " + stringMax + "]]\n"); } // others return only 1 roi per module (1 port per module) else { - REQUIRE(oss1.str() == "rx_roi [[20, 30, " + stringMin + ", " + std::to_string(portSize.y - 1) + "]]\n"); + // (eiger 2 ports) + if (det_type == defs::EIGER) { + REQUIRE(oss1.str() == "rx_roi [[20, 30, " + stringMin + ", " + std::to_string(portSize.y - 1) + "], [-1, -1]]\n"); + } else { + REQUIRE(oss1.str() == "rx_roi [[20, 30, " + stringMin + ", " + std::to_string(portSize.y - 1) + "]]\n"); + } } } } diff --git a/slsReceiverSoftware/src/Implementation.cpp b/slsReceiverSoftware/src/Implementation.cpp index 8a9dcdd4b..9a50d3dcb 100644 --- a/slsReceiverSoftware/src/Implementation.cpp +++ b/slsReceiverSoftware/src/Implementation.cpp @@ -155,9 +155,18 @@ void Implementation::setDetectorType(const detectorType d) { break; } + if (d == EIGER) { + // resets ROIs and sets size to 2 + std::vector rois(2); + std::vector multiRoi(1); + setPortROIs(rois); + setMultiROIMetadata(multiRoi); + } + SetLocalNetworkParameters(); SetupFifoStructure(); + // create threads for (int i = 0; i < generalData->numUDPInterfaces; ++i) { @@ -1013,6 +1022,8 @@ int Implementation::getNumberofUDPInterfaces() const { // not Eiger void Implementation::setNumberofUDPInterfaces(const int n) { + LOG(logDEBUG) << "Setting Number of UDP Interfaces: " << n; + if (generalData->detType == EIGER) { throw RuntimeError("Cannot set number of UDP interfaces for Eiger"); } @@ -1031,10 +1042,9 @@ void Implementation::setNumberofUDPInterfaces(const int n) { // fifo SetupFifoStructure(); - // roi cleared - complete detector + // roi cleared - complete detector and sets roi vector size std::vector rois(n); std::vector multiRoi(1); - // recalculate port rois booleans for listener, processor and streamer setPortROIs(rois); setMultiROIMetadata(multiRoi); diff --git a/slsReceiverSoftware/src/MasterFileUtility.cpp b/slsReceiverSoftware/src/MasterFileUtility.cpp index bc9d06586..172f529d0 100644 --- a/slsReceiverSoftware/src/MasterFileUtility.cpp +++ b/slsReceiverSoftware/src/MasterFileUtility.cpp @@ -208,7 +208,7 @@ std::string CreateVirtualHDF5File( attribute.write(H5::PredType::NATIVE_DOUBLE, &dValue); // complete detector in roi - if (multiRoi.size() == 1 && multiRoi[0].isComplete()) { + /*if (multiRoi.size() == 1 && multiRoi[0].completeRoi()) { int ny = nPixelsY * numModY; int nx = nPixelsX * numModX; if (nPixelsY == 1) { @@ -216,7 +216,7 @@ std::string CreateVirtualHDF5File( } else { multiRoi.push_back(defs::ROI{0, nx - 1, 0, ny - 1}); } - } + }*/ for (size_t iRoi = 0; iRoi != multiRoi.size(); ++iRoi) { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 4811f1798..e585c90ab 100755 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -62,3 +62,4 @@ catch_discover_tests(tests) configure_file(scripts/test_simulators.py ${CMAKE_BINARY_DIR}/bin/test_simulators.py COPYONLY) configure_file(scripts/test_frame_synchronizer.py ${CMAKE_BINARY_DIR}/bin/test_frame_synchronizer.py COPYONLY) configure_file(scripts/utils_for_test.py ${CMAKE_BINARY_DIR}/bin/utils_for_test.py COPYONLY) +configure_file(scripts/test_roi.py ${CMAKE_BINARY_DIR}/bin/test_roi.py COPYONLY) diff --git a/tests/scripts/test_roi.py b/tests/scripts/test_roi.py new file mode 100644 index 000000000..07565b591 --- /dev/null +++ b/tests/scripts/test_roi.py @@ -0,0 +1,114 @@ +# SPDX-License-Identifier: LGPL-3.0-or-other +# Copyright (C) 2021 Contributors to the SLS Detector Package +''' +This file is used to start up simulators, receivers and test roi for every detector in many configurations. +''' + +import sys, time +import traceback + +from slsdet import Detector +from slsdet.defines import DEFAULT_TCP_RX_PORTNO, DEFAULT_UDP_DST_PORTNO + + +from utils_for_test import ( + Log, + LogLevel, + RuntimeException, + cleanup, + startProcessInBackground, + startDetectorVirtualServer, + connectToVirtualServers, + runProcessWithLogFile +) + +LOG_PREFIX_FNAME = '/tmp/slsDetectorPackage_virtual_roi_test' +MAIN_LOG_FNAME = LOG_PREFIX_FNAME + '_log.txt' +ROI_TEST_FNAME = LOG_PREFIX_FNAME + '_results_' + +def startReceiver(num_mods, fp): + if num_mods == 1: + cmd = ['slsReceiver'] + else: + cmd = ['slsMultiReceiver', str(DEFAULT_TCP_RX_PORTNO), str(num_mods)] + # in 10.0.0 + #cmd = ['slsMultiReceiver', '-p', str(DEFAULT_TCP_RX_PORTNO), '-n', str(num_mods)] + startProcessInBackground(cmd, fp) + time.sleep(1) + + +def loadConfigForRoi(name, fp, num_mods = 1, num_interfaces = 1): + Log(LogLevel.INFO, 'Loading config') + Log(LogLevel.INFO, 'Loading config', fp) + try: + d = connectToVirtualServers(name, num_mods) + + if name == 'jungfrau' or name == 'moench': + d.numinterfaces = num_interfaces + + d.udp_dstport = DEFAULT_UDP_DST_PORTNO + if name == 'eiger' or name == 'jungfrau' or name == 'moench': + d.udp_dstport2 = DEFAULT_UDP_DST_PORTNO + 1 + + d.rx_hostname = 'localhost' + d.udp_dstip = 'auto' + if name != "eiger": + d.udp_srcip = 'auto' + if name == 'jungfrau' or name == 'moench': + d.udp_dstip2 = 'auto' + + except Exception as e: + raise RuntimeException(f'Could not load config for {name}. Error: {str(e)}') from e + + + + +def startTestsForAll(fp): + servers = [ + 'eiger', + 'jungfrau', + 'mythen3', + 'gotthard2', + 'moench', + ] + nmods = 2 + for server in servers: + for ninterfaces in range(1, 2): + if ninterfaces == 2 and server != 'jungfrau' and server != 'moench': + continue + try: + msg = f'Starting Roi Tests for {server}' + if server == 'jungfrau' or server == 'moench': + msg += f' with {ninterfaces} interfaces' + Log(LogLevel.INFOBLUE, msg) + Log(LogLevel.INFOBLUE, msg, fp) + cleanup(fp) + startDetectorVirtualServer(server, nmods, fp) + startReceiver(nmods, fp) + loadConfigForRoi(name=server, fp=fp, num_mods=nmods, num_interfaces=ninterfaces) + + fname = ROI_TEST_FNAME + server + '.txt' + cmd = ['tests', 'rx_roi', '--abort', '-s'] + runProcessWithLogFile('Roi Tests for ' + server, cmd, fp, fname) + Log(LogLevel.INFO, '\n') + except Exception as e: + raise RuntimeException(f'Roi Tests failed') from e + + Log(LogLevel.INFOGREEN, 'Passed all Roi tests for all detectors \n' + str(servers)) + + +if __name__ == '__main__': + Log(LogLevel.INFOBLUE, '\nLog File: ' + MAIN_LOG_FNAME + '\n') + + with open(MAIN_LOG_FNAME, 'w') as fp: + try: + startTestsForAll(fp) + #TODO: check master file as well for both json and hdf5 as well + cleanup(fp) + except Exception as e: + with open(MAIN_LOG_FNAME, 'a') as fp_error: + traceback.print_exc(file=fp_error) + cleanup(fp) + Log(LogLevel.ERROR, f'Tests Failed.') + + From 707bf023c655ad4028ade24108f9ff1d651fdc57 Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Wed, 25 Jun 2025 16:42:33 +0200 Subject: [PATCH 17/49] wip, fails with master and virtual --- slsDetectorSoftware/src/DetectorImpl.cpp | 47 ++--- slsDetectorSoftware/src/DetectorImpl.h | 4 +- slsReceiverSoftware/src/DataProcessor.cpp | 12 +- slsReceiverSoftware/src/MasterFileUtility.cpp | 189 ++++++++++++------ slsReceiverSoftware/src/MasterFileUtility.h | 10 +- slsSupportLib/include/sls/sls_detector_defs.h | 10 + 6 files changed, 158 insertions(+), 114 deletions(-) diff --git a/slsDetectorSoftware/src/DetectorImpl.cpp b/slsDetectorSoftware/src/DetectorImpl.cpp index 236447a9a..55ae9db33 100644 --- a/slsDetectorSoftware/src/DetectorImpl.cpp +++ b/slsDetectorSoftware/src/DetectorImpl.cpp @@ -1689,12 +1689,6 @@ std::vector DetectorImpl::getRxROI(int module_id) const { // TODO } -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) { for (size_t i = 0; i < rois.size(); ++i) { const auto &roi = rois[i]; @@ -1738,31 +1732,13 @@ void DetectorImpl::validateROIs(const std::vector &rois) { } for (size_t j = i + 1; j < rois.size(); ++j) { - if (roisOverlap(rois[i], rois[j])) { + if (rois[i].overlap(rois[j])) { 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) { @@ -1780,21 +1756,22 @@ defs::xy DetectorImpl::getPortGeometry() const { return portGeometry; } -defs::xy DetectorImpl::calculatePosition(int moduleIndex, - defs::xy geometry) const { +defs::xy DetectorImpl::calculatePosition(int moduleIndex) const { int maxYMods = shm()->numberOfModules.y; - int y = (moduleIndex % maxYMods) * geometry.y; - int x = (moduleIndex / maxYMods) * geometry.x; + int y = (moduleIndex % maxYMods); + int x = (moduleIndex / maxYMods); 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? + const defs::xy modPos = calculatePosition(moduleIndex); + const int xmin = modSize.x * modPos.x; + const int xmax = xmin + modSize.x - 1; + const int ymin = modSize.y * modPos.y; + const int ymax = ymin + modSize.y - 1; + return defs::ROI{xmin, xmax, ymin, ymax}; } void DetectorImpl::convertGlobalRoiToPortLevel( @@ -1830,7 +1807,7 @@ void DetectorImpl::convertGlobalRoiToPortLevel( } // Check if user ROI overlaps with this port ROI - if (roisOverlap(userRoi, portRoi)) { + if (userRoi.overlap(portRoi)) { defs::ROI clipped{}; clipped.xmin = std::max(userRoi.xmin, portRoi.xmin); clipped.xmax = std::min(userRoi.xmax, portRoi.xmax); @@ -1874,7 +1851,7 @@ void DetectorImpl::setRxROI(const std::vector &args) { std::vector portRois(nPortsPerModule); for (const auto &arg : args) { - if (roisOverlap(arg, moduleGlobalRoi)) { + if (arg.overlap(moduleGlobalRoi)) { convertGlobalRoiToPortLevel(arg, moduleGlobalRoi, portRois); } } diff --git a/slsDetectorSoftware/src/DetectorImpl.h b/slsDetectorSoftware/src/DetectorImpl.h index 45d95e4cf..d90c4c303 100644 --- a/slsDetectorSoftware/src/DetectorImpl.h +++ b/slsDetectorSoftware/src/DetectorImpl.h @@ -426,9 +426,7 @@ class DetectorImpl : public virtual slsDetectorDefs { 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 calculatePosition(int moduleIndex, defs::xy geometry) const; + defs::xy calculatePosition(int moduleIndex) const; defs::ROI getModuleROI(int moduleIndex) const; void convertGlobalRoiToPortLevel( const defs::ROI &userRoi, const defs::ROI &moduleRoi, diff --git a/slsReceiverSoftware/src/DataProcessor.cpp b/slsReceiverSoftware/src/DataProcessor.cpp index 1beac1bcc..f93c7d923 100644 --- a/slsReceiverSoftware/src/DataProcessor.cpp +++ b/slsReceiverSoftware/src/DataProcessor.cpp @@ -208,11 +208,9 @@ std::string DataProcessor::CreateVirtualFile( const int modulePos, const int numModX, const int numModY, std::mutex *hdf5LibMutex) { - /*if (!multiRoiMetadata.empty() && generalData->dynamicRange == 4) { - throw std::runtime_error("Skipping virtual hdf5 file since rx_roi is " - "enabled in 4 bit mode."); - }*/ - + int ny = generalData->nPixelsY; + if (generalData->dynamicRange == 4) + ny = generalData->nPixelsY / 2; bool gotthard25um = ((generalData->detType == GOTTHARD || generalData->detType == GOTTHARD2) && (numModX * numModY) == 2); @@ -229,7 +227,7 @@ std::string DataProcessor::CreateVirtualFile( return masterFileUtility::CreateVirtualHDF5File( filePath, fileNamePrefix, fileIndex, overWriteEnable, silentMode, modulePos, generalData->numUDPInterfaces, framesPerFile, - generalData->nPixelsX, generalData->nPixelsY, generalData->dynamicRange, + generalData->nPixelsX, ny, generalData->dynamicRange, numFramesCaught, numModX, numModY, dataFile->GetPDataType(), dataFile->GetParameterNames(), dataFile->GetParameterDataTypes(), hdf5LibMutex, gotthard25um, multiRoiMetadata); @@ -251,7 +249,7 @@ void DataProcessor::LinkFileInMaster(const std::string &masterFileName, } masterFileUtility::LinkHDF5FileInMaster(masterfname, fname, dataFile->GetParameterNames(), - silentMode, hdf5LibMutex); + silentMode, hdf5LibMutex, multiRoiMetadata.size()); } #endif diff --git a/slsReceiverSoftware/src/MasterFileUtility.cpp b/slsReceiverSoftware/src/MasterFileUtility.cpp index 172f529d0..8200bca08 100644 --- a/slsReceiverSoftware/src/MasterFileUtility.cpp +++ b/slsReceiverSoftware/src/MasterFileUtility.cpp @@ -49,7 +49,7 @@ std::string CreateMasterBinaryFile(const std::string &filePath, void LinkHDF5FileInMaster(std::string &masterFileName, std::string &dataFilename, std::vector parameterNames, - const bool silentMode, std::mutex *hdf5LibMutex) { + const bool silentMode, std::mutex *hdf5LibMutex, size_t multiRoiSize) { std::lock_guard lock(*hdf5LibMutex); std::unique_ptr fd{nullptr}; @@ -67,27 +67,32 @@ void LinkHDF5FileInMaster(std::string &masterFileName, fd = make_unique(dataFilename.c_str(), H5F_ACC_RDONLY, H5::FileCreatPropList::DEFAULT, flist); - // create link for data dataset - H5::DataSet dset = fd->openDataSet(DATASET_NAME); - std::string linkname = - std::string("/entry/data/") + std::string(DATASET_NAME); - if (H5Lcreate_external(dataFilename.c_str(), DATASET_NAME, - masterfd.getLocId(), linkname.c_str(), - H5P_DEFAULT, H5P_DEFAULT) < 0) { - throw RuntimeError( - "Could not create link to data dataset in master"); - } + for (size_t iRoi = 0; iRoi != multiRoiSize; ++iRoi) { - // create link for parameter datasets - for (unsigned int i = 0; i < parameterNames.size(); ++i) { - H5::DataSet pDset = fd->openDataSet(parameterNames[i].c_str()); - linkname = std::string("/entry/data/") + parameterNames[i]; - if (H5Lcreate_external(dataFilename.c_str(), - parameterNames[i].c_str(), - masterfd.getLocId(), linkname.c_str(), - H5P_DEFAULT, H5P_DEFAULT) < 0) { + // create link for data dataset + std::string datasetname = DATASET_NAME + '_' + std::to_string(iRoi); + H5::DataSet dset = fd->openDataSet(datasetname); + std::string linkname = + std::string("/entry/data/") + datasetname; + if (H5Lcreate_external(dataFilename.c_str(), datasetname.c_str(), + masterfd.getLocId(), linkname.c_str(), + H5P_DEFAULT, H5P_DEFAULT) < 0) { throw RuntimeError( - "Could not create link to parameter dataset in master"); + "Could not create link to data dataset in master"); + } + + // create link for parameter datasets + for (unsigned int i = 0; i < parameterNames.size(); ++i) { + std::string parameterDsetName = parameterNames[i] + '_' + std::to_string(iRoi); + H5::DataSet pDset = fd->openDataSet(parameterDsetName.c_str()); + linkname = std::string("/entry/data/") + parameterDsetName; + if (H5Lcreate_external(dataFilename.c_str(), + parameterDsetName.c_str(), + masterfd.getLocId(), linkname.c_str(), + H5P_DEFAULT, H5P_DEFAULT) < 0) { + throw RuntimeError( + "Could not create link to parameter dataset in master"); + } } } fd->close(); @@ -160,18 +165,51 @@ std::string CreateMasterHDF5File(const std::string &filePath, return fileName; } +defs::ROI GetGlobalPortRoi(const int iPort, const defs::xy portSize, const int numPortsY) { + defs::xy portPos = {(iPort / numPortsY), (iPort % numPortsY)}; + const int xmin = portSize.x * portPos.x; + const int xmax = xmin + portSize.x - 1; + const int ymin = portSize.y * portPos.y; + const int ymax = ymin + portSize.y - 1; + return defs::ROI{xmin, xmax, ymin, ymax}; +} + +int GetNumPortsInRoi(const defs::ROI roi, const defs::xy portSize) { + if (portSize.x == 0 || portSize.y == 0) { + throw RuntimeError("Port width or height cannot be zero"); + } + int iPortXMin = roi.xmin / portSize.x; + int iPortXMax = roi.xmax / portSize.x; + int iPortYMin = roi.ymin / portSize.y; + int iPortYMax = roi.ymax / portSize.y; + return ((iPortXMax - iPortXMin + 1) * (iPortYMax - iPortYMin + 1)); +} + /** Will not be called if dynamic range is 4 and roi enabled */ std::string CreateVirtualHDF5File( const std::string &filePath, const std::string &fileNamePrefix, const uint64_t fileIndex, const bool overWriteEnable, const bool silentMode, const int modulePos, const int numUnitsPerReadout, - const uint32_t maxFramesPerFile, const uint32_t nPixelsX, - const uint32_t nPixelsY, const uint32_t dynamicRange, + const uint32_t maxFramesPerFile, const int nPixelsX, + const int nPixelsY, const uint32_t dynamicRange, const uint64_t numImagesCaught, const int numModX, const int numModY, const H5::DataType dataType, const std::vector parameterNames, const std::vector parameterDataTypes, std::mutex *hdf5LibMutex, bool gotthard25um, - std::vector &multiRoi) { + std::vector multiRoi) { + + // cannot create + if (!multiRoi.empty()) { + if (dynamicRange == 4) { + throw std::runtime_error("Skipping virtual hdf5 file since rx_roi is " + "enabled and it is in 4 bit mode."); + } + if (gotthard25um && (numModX * numModY) == 2) { + throw std::runtime_error("Skipping virtual hdf5 file since rx_roi is " + "enabled and there are 2 Gotthard 25um modules."); + } + } + // virtual file name std::ostringstream osfn; @@ -180,9 +218,6 @@ std::string CreateVirtualHDF5File( std::string fileName = osfn.str(); unsigned int paraSize = parameterNames.size(); - uint64_t numModZ = numModX; - uint32_t nDimy = nPixelsY; - uint32_t nDimz = ((dynamicRange == 4) ? (nPixelsX / 2) : nPixelsX); std::lock_guard lock(*hdf5LibMutex); @@ -208,7 +243,7 @@ std::string CreateVirtualHDF5File( attribute.write(H5::PredType::NATIVE_DOUBLE, &dValue); // complete detector in roi - /*if (multiRoi.size() == 1 && multiRoi[0].completeRoi()) { + if (multiRoi.size() == 1 && multiRoi[0].completeRoi()) { int ny = nPixelsY * numModY; int nx = nPixelsX * numModX; if (nPixelsY == 1) { @@ -216,15 +251,23 @@ std::string CreateVirtualHDF5File( } else { multiRoi.push_back(defs::ROI{0, nx - 1, 0, ny - 1}); } - }*/ + } + + uint64_t depth = numImagesCaught; + uint64_t nports = numModX * numModY; + int numFiles = numImagesCaught / maxFramesPerFile; + if (numImagesCaught % maxFramesPerFile) + ++numFiles; + defs::xy portSize{nPixelsX, nPixelsY}; for (size_t iRoi = 0; iRoi != multiRoi.size(); ++iRoi) { + uint64_t width = multiRoi[iRoi].width(); + uint64_t height = multiRoi[iRoi].height(); + uint64_t nportsInRoi = GetNumPortsInRoi(multiRoi[iRoi], portSize); // dataspace - hsize_t vdsDims[DATA_RANK] = {numImagesCaught, numModY * nDimy, - numModZ * nDimz}; - hsize_t vdsDimsPara[VDS_PARA_RANK] = {numImagesCaught, - numModY * numModZ}; + hsize_t vdsDims[DATA_RANK] = {depth, height, width}; + hsize_t vdsDimsPara[VDS_PARA_RANK] = {depth, nportsInRoi}; H5::DataSpace vdsDataSpace(DATA_RANK, vdsDims, nullptr); H5::DataSpace vdsDataSpacePara(VDS_PARA_RANK, vdsDimsPara, nullptr); @@ -239,38 +282,59 @@ std::string CreateVirtualHDF5File( } // hyperslab (files) - int numFiles = numImagesCaught / maxFramesPerFile; - if (numImagesCaught % maxFramesPerFile) - ++numFiles; uint64_t framesSaved = 0; - for (int iFile = 0; iFile < numFiles; ++iFile) { - - uint64_t nDimx = - ((numImagesCaught - framesSaved) > maxFramesPerFile) - ? maxFramesPerFile - : (numImagesCaught - framesSaved); + for (int iFile = 0; iFile != numFiles; ++iFile) { + + uint64_t nImagesInFile = numImagesCaught - framesSaved; + if ((numImagesCaught - framesSaved) > maxFramesPerFile) + nImagesInFile = maxFramesPerFile; + // start location and blocksize recalculated later for each readout (because of irregular roi) hsize_t startLocation[DATA_RANK] = {framesSaved, 0, 0}; + hsize_t nx = static_cast(nPixelsX); + hsize_t ny = static_cast(nPixelsY); + hsize_t blockSize[DATA_RANK] = {nImagesInFile, nx, ny}; hsize_t strideBetweenBlocks[DATA_RANK] = {1, 1, 1}; - hsize_t numBlocks[DATA_RANK] = {nDimx, nDimy, nDimz}; - hsize_t blockSize[DATA_RANK] = {1, 1, 1}; + hsize_t numBlocks[DATA_RANK] = {1, 1, 1}; + + // start location of parameter datasets is recalcualted later hsize_t startLocationPara[VDS_PARA_RANK] = {framesSaved, 0}; hsize_t strideBetweenBlocksPara[VDS_PARA_RANK] = {1, 1}; - hsize_t numBlocksPara[VDS_PARA_RANK] = {nDimx, 1}; - hsize_t blockSizePara[VDS_PARA_RANK] = {1, 1}; + hsize_t numBlocksPara[VDS_PARA_RANK] = {1, 1}; + hsize_t blockSizePara[VDS_PARA_RANK] = {nImagesInFile, 1}; // interleaving for g2 if (gotthard25um) { strideBetweenBlocks[2] = 2; } - for (unsigned int iReadout = 0; iReadout < numModY * numModZ; - ++iReadout) { + for (unsigned int iReadout = 0; iReadout < nports; ++iReadout) { + // skip if roi does not overlap + auto globalPortRoi = GetGlobalPortRoi(iReadout, portSize, numModY); + if (!globalPortRoi.overlap(multiRoi[iRoi])) + continue; + + // calculate start location (with roi) + int xmin = std::max(multiRoi[iRoi].xmin, globalPortRoi.xmin); + int xmax = std::min(multiRoi[iRoi].xmax, globalPortRoi.xmax); + int ymin = std::max(multiRoi[iRoi].ymin, globalPortRoi.ymin); + int ymax = std::min(multiRoi[iRoi].ymax, globalPortRoi.ymax); + uint32_t portRoiHeight = ymax - ymin + 1; + uint32_t portRoiWidth = xmax - xmin + 1; + + // recalculating start location and block size + ++startLocationPara[1]; + if (!gotthard25um) { + startLocation[1] = ymin; + startLocation[2] = xmin; + blockSize[1] = portRoiHeight; + blockSize[2] = portRoiWidth; + } // interleaving for g2 (startLocation is 0 and 1) - if (gotthard25um) { - startLocation[2] = iReadout; + else { + ++startLocation[2]; } vdsDataSpace.selectHyperslab( @@ -299,11 +363,11 @@ std::string CreateVirtualHDF5File( } // source dataspace - hsize_t srcDims[DATA_RANK] = {nDimx, nDimy, nDimz}; - hsize_t srcDimsMax[DATA_RANK] = {H5S_UNLIMITED, nDimy, - nDimz}; + hsize_t srcDims[DATA_RANK] = {nImagesInFile, portRoiHeight, portRoiWidth}; + hsize_t srcDimsMax[DATA_RANK] = {H5S_UNLIMITED, portRoiHeight, + portRoiWidth}; H5::DataSpace srcDataSpace(DATA_RANK, srcDims, srcDimsMax); - hsize_t srcDimsPara[PARA_RANK] = {nDimx}; + hsize_t srcDimsPara[PARA_RANK] = {nImagesInFile}; hsize_t srcDimsMaxPara[PARA_RANK] = {H5S_UNLIMITED}; H5::DataSpace srcDataSpacePara(PARA_RANK, srcDimsPara, srcDimsMaxPara); @@ -312,8 +376,8 @@ std::string CreateVirtualHDF5File( // virtual parameter datasets error loading (bad scalar // value)) // TODO WHY???? - /*if (nDimx != maxFramesPerFile) { - hsize_t count[1] = {nDimx}; + /*if (nDimz != maxFramesPerFile) { + hsize_t count[1] = {nDimz}; hsize_t start[1] = {0}; srcDataSpacePara.selectHyperslab( H5S_SELECT_SET, count, start, @@ -321,27 +385,22 @@ std::string CreateVirtualHDF5File( }*/ // mapping of property list + std::string datasetname = DATASET_NAME + '_' + std::to_string(iRoi); plist.setVirtual(vdsDataSpace, relative_srcFileName.c_str(), - DATASET_NAME, srcDataSpace); + datasetname.c_str(), srcDataSpace); for (unsigned int p = 0; p < paraSize; ++p) { + std::string parameterDsetName = parameterNames[p] + '_' + std::to_string(iRoi); plistPara[p].setVirtual( vdsDataSpacePara, relative_srcFileName.c_str(), - parameterNames[p].c_str(), srcDataSpacePara); + parameterDsetName.c_str(), srcDataSpacePara); } // H5Sclose(srcDataspace); // H5Sclose(srcDataspace_para); - if (!gotthard25um) { - startLocation[2] += nDimz; - if (startLocation[2] >= (numModZ * nDimz)) { - startLocation[2] = 0; - startLocation[1] += nDimy; - } - } ++startLocationPara[1]; } - framesSaved += nDimx; + framesSaved += nImagesInFile; } // datasets H5::DataSet vdsDataSet( diff --git a/slsReceiverSoftware/src/MasterFileUtility.h b/slsReceiverSoftware/src/MasterFileUtility.h index 0cdcb93d3..51360da74 100644 --- a/slsReceiverSoftware/src/MasterFileUtility.h +++ b/slsReceiverSoftware/src/MasterFileUtility.h @@ -21,7 +21,7 @@ std::string CreateMasterBinaryFile(const std::string &filePath, void LinkHDF5FileInMaster(std::string &masterFileName, std::string &dataFilename, std::vector parameterNames, - const bool silentMode, std::mutex *hdf5LibMutex); + const bool silentMode, std::mutex *hdf5LibMutex, size_t multiRoiSize); std::string CreateMasterHDF5File(const std::string &filePath, const std::string &fileNamePrefix, @@ -29,18 +29,20 @@ std::string CreateMasterHDF5File(const std::string &filePath, const bool overWriteEnable, const bool silentMode, MasterAttributes *attr, std::mutex *hdf5LibMutex); +defs::ROI GetGlobalPortRoi(const int iPort, const defs::xy portSize, const int numPortsY); +int GetNumPortsInRoi(const defs::ROI roi, const defs::xy portSize); std::string CreateVirtualHDF5File( const std::string &filePath, const std::string &fileNamePrefix, const uint64_t fileIndex, const bool overWriteEnable, const bool silentMode, const int modulePos, const int numUnitsPerReadout, - const uint32_t maxFramesPerFile, const uint32_t nPixelsX, - const uint32_t nPixelsY, const uint32_t dynamicRange, + const uint32_t maxFramesPerFile, const int nPixelsX, + const int nPixelsY, const uint32_t dynamicRange, const uint64_t numImagesCaught, const int numModX, const int numModY, const H5::DataType dataType, const std::vector parameterNames, const std::vector parameterDataTypes, std::mutex *hdf5LibMutex, bool gotthard25um, - std::vector &multiRoi); + std::vector multiRoi); #endif } // namespace masterFileUtility diff --git a/slsSupportLib/include/sls/sls_detector_defs.h b/slsSupportLib/include/sls/sls_detector_defs.h index 34f24d75d..0f0a5dc0f 100644 --- a/slsSupportLib/include/sls/sls_detector_defs.h +++ b/slsSupportLib/include/sls/sls_detector_defs.h @@ -230,6 +230,12 @@ class slsDetectorDefs { ROI(int xmin, int xmax) : xmin(xmin), xmax(xmax){}; ROI(int xmin, int xmax, int ymin, int ymax) : xmin(xmin), xmax(xmax), ymin(ymin), ymax(ymax){}; + constexpr int width() const { + return (xmax - xmin + 1); + } + constexpr int height() const { + return (ymax - ymin + 1); + } constexpr std::array getIntArray() const { return std::array({xmin, xmax, ymin, ymax}); } @@ -246,6 +252,10 @@ class slsDetectorDefs { ymin = 0; ymax = 0; } + constexpr bool overlap(const ROI & other) const { + return ((xmin <= other.xmax && xmax >= other.xmin) && + (ymin <= other.ymax && ymax >= other.ymin)); + } constexpr bool operator==(const ROI &other) const { return ((xmin == other.xmin) && (xmax == other.xmax) && (ymin == other.ymin) && (ymax == other.ymax)); From 91f33edcf8d4c6b23692a96b3d04610de5c28b2b Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Fri, 27 Jun 2025 15:18:05 +0200 Subject: [PATCH 18/49] works for complete roi --- slsReceiverSoftware/src/MasterFileUtility.cpp | 147 +++++++++--------- 1 file changed, 77 insertions(+), 70 deletions(-) diff --git a/slsReceiverSoftware/src/MasterFileUtility.cpp b/slsReceiverSoftware/src/MasterFileUtility.cpp index 8200bca08..1f25a342e 100644 --- a/slsReceiverSoftware/src/MasterFileUtility.cpp +++ b/slsReceiverSoftware/src/MasterFileUtility.cpp @@ -70,7 +70,9 @@ void LinkHDF5FileInMaster(std::string &masterFileName, for (size_t iRoi = 0; iRoi != multiRoiSize; ++iRoi) { // create link for data dataset - std::string datasetname = DATASET_NAME + '_' + std::to_string(iRoi); + std::string datasetname = std::string(DATASET_NAME); + if (multiRoiSize > 1) + datasetname += ('_' + std::to_string(iRoi)); H5::DataSet dset = fd->openDataSet(datasetname); std::string linkname = std::string("/entry/data/") + datasetname; @@ -83,7 +85,9 @@ void LinkHDF5FileInMaster(std::string &masterFileName, // create link for parameter datasets for (unsigned int i = 0; i < parameterNames.size(); ++i) { - std::string parameterDsetName = parameterNames[i] + '_' + std::to_string(iRoi); + std::string parameterDsetName = parameterNames[i]; + if (multiRoiSize > 1) + parameterDsetName += ('_' + std::to_string(iRoi)); H5::DataSet pDset = fd->openDataSet(parameterDsetName.c_str()); linkname = std::string("/entry/data/") + parameterDsetName; if (H5Lcreate_external(dataFilename.c_str(), @@ -198,8 +202,13 @@ std::string CreateVirtualHDF5File( std::mutex *hdf5LibMutex, bool gotthard25um, std::vector multiRoi) { - // cannot create - if (!multiRoi.empty()) { + bool completeRoi = false; + if (multiRoi.size() == 1 && multiRoi[0].completeRoi()) { + completeRoi = true; + } + + // roi not allowed in 4 bit mode and with gotthard 2 mods + if (!completeRoi) { if (dynamicRange == 4) { throw std::runtime_error("Skipping virtual hdf5 file since rx_roi is " "enabled and it is in 4 bit mode."); @@ -216,11 +225,8 @@ std::string CreateVirtualHDF5File( osfn << filePath << "/" << fileNamePrefix << "_virtual" << "_" << fileIndex << ".h5"; std::string fileName = osfn.str(); - unsigned int paraSize = parameterNames.size(); - std::lock_guard lock(*hdf5LibMutex); - std::unique_ptr fd{nullptr}; try { H5::Exception::dontPrint(); // to handle errors @@ -242,32 +248,37 @@ std::string CreateVirtualHDF5File( "version", H5::PredType::NATIVE_DOUBLE, dataspace_attr); attribute.write(H5::PredType::NATIVE_DOUBLE, &dValue); - // complete detector in roi - if (multiRoi.size() == 1 && multiRoi[0].completeRoi()) { - int ny = nPixelsY * numModY; - int nx = nPixelsX * numModX; - if (nPixelsY == 1) { - multiRoi.push_back(defs::ROI{0, nx - 1}); - } else { - multiRoi.push_back(defs::ROI{0, nx - 1, 0, ny - 1}); - } - } - - uint64_t depth = numImagesCaught; - uint64_t nports = numModX * numModY; - int numFiles = numImagesCaught / maxFramesPerFile; - if (numImagesCaught % maxFramesPerFile) - ++numFiles; - defs::xy portSize{nPixelsX, nPixelsY}; for (size_t iRoi = 0; iRoi != multiRoi.size(); ++iRoi) { - uint64_t width = multiRoi[iRoi].width(); - uint64_t height = multiRoi[iRoi].height(); - uint64_t nportsInRoi = GetNumPortsInRoi(multiRoi[iRoi], portSize); + + auto currentRoi = multiRoi[iRoi]; + defs::xy detectorSize = {nPixelsX * numModX, nPixelsY * numModY}; + if (completeRoi) { + currentRoi = defs::ROI{0, detectorSize.x - 1, + 0, detectorSize.y - 1}; + } + if (multiRoi[iRoi].completeRoi()&& iRoi != 0) + throw RuntimeError("Cannot have complete roi and multiple rois"); + + // get detector shape and number of ports in roi + defs::xy portSize{nPixelsX, nPixelsY}; + uint32_t nTotalPorts = numModX * numModY; + hsize_t roiWidth = detectorSize.x; + hsize_t roiHeight = detectorSize.y; + hsize_t nPortsInRoi = nTotalPorts; + if (!completeRoi) { + roiWidth = multiRoi[iRoi].width(); + roiHeight = multiRoi[iRoi].height(); + nPortsInRoi = GetNumPortsInRoi(multiRoi[iRoi], portSize); + } // dataspace - hsize_t vdsDims[DATA_RANK] = {depth, height, width}; - hsize_t vdsDimsPara[VDS_PARA_RANK] = {depth, nportsInRoi}; + uint64_t nImages = numImagesCaught; + int numFiles = numImagesCaught / maxFramesPerFile; + if (numImagesCaught % maxFramesPerFile) + ++numFiles; + hsize_t vdsDims[DATA_RANK] = {nImages, roiHeight, roiWidth}; + hsize_t vdsDimsPara[VDS_PARA_RANK] = {nImages, nPortsInRoi}; H5::DataSpace vdsDataSpace(DATA_RANK, vdsDims, nullptr); H5::DataSpace vdsDataSpacePara(VDS_PARA_RANK, vdsDimsPara, nullptr); @@ -285,58 +296,52 @@ std::string CreateVirtualHDF5File( uint64_t framesSaved = 0; for (int iFile = 0; iFile != numFiles; ++iFile) { - uint64_t nImagesInFile = numImagesCaught - framesSaved; + // images in src file + uint64_t nSrcFileImages = numImagesCaught - framesSaved; if ((numImagesCaught - framesSaved) > maxFramesPerFile) - nImagesInFile = maxFramesPerFile; + nSrcFileImages = maxFramesPerFile; - // start location and blocksize recalculated later for each readout (because of irregular roi) - hsize_t startLocation[DATA_RANK] = {framesSaved, 0, 0}; - hsize_t nx = static_cast(nPixelsX); - hsize_t ny = static_cast(nPixelsY); - hsize_t blockSize[DATA_RANK] = {nImagesInFile, nx, ny}; hsize_t strideBetweenBlocks[DATA_RANK] = {1, 1, 1}; hsize_t numBlocks[DATA_RANK] = {1, 1, 1}; - - - // start location of parameter datasets is recalcualted later - hsize_t startLocationPara[VDS_PARA_RANK] = {framesSaved, 0}; hsize_t strideBetweenBlocksPara[VDS_PARA_RANK] = {1, 1}; hsize_t numBlocksPara[VDS_PARA_RANK] = {1, 1}; - hsize_t blockSizePara[VDS_PARA_RANK] = {nImagesInFile, 1}; + hsize_t blockSizePara[VDS_PARA_RANK] = {nSrcFileImages, 1}; + + // following recalculated for every readout + hsize_t blockSize[DATA_RANK] = {nSrcFileImages, static_cast(nPixelsY), static_cast(nPixelsX)}; + hsize_t startLocation[DATA_RANK] = {framesSaved, 0, 0}; + hsize_t startLocationPara[VDS_PARA_RANK] = {framesSaved, 0}; // interleaving for g2 if (gotthard25um) { strideBetweenBlocks[2] = 2; } - for (unsigned int iReadout = 0; iReadout < nports; ++iReadout) { - - // skip if roi does not overlap + for (unsigned int iReadout = 0; iReadout < nTotalPorts; ++iReadout) { auto globalPortRoi = GetGlobalPortRoi(iReadout, portSize, numModY); - if (!globalPortRoi.overlap(multiRoi[iRoi])) + if (!globalPortRoi.overlap(currentRoi)) continue; - // calculate start location (with roi) - int xmin = std::max(multiRoi[iRoi].xmin, globalPortRoi.xmin); - int xmax = std::min(multiRoi[iRoi].xmax, globalPortRoi.xmax); - int ymin = std::max(multiRoi[iRoi].ymin, globalPortRoi.ymin); - int ymax = std::min(multiRoi[iRoi].ymax, globalPortRoi.ymax); - uint32_t portRoiHeight = ymax - ymin + 1; - uint32_t portRoiWidth = xmax - xmin + 1; + // calculate start location (special for roi) + int xmin = std::max(currentRoi.xmin, globalPortRoi.xmin); + int xmax = std::min(currentRoi.xmax, globalPortRoi.xmax); + int ymin = std::max(currentRoi.ymin, globalPortRoi.ymin); + int ymax = std::min(currentRoi.ymax, globalPortRoi.ymax); + hsize_t portRoiHeight = ymax - ymin + 1; + hsize_t portRoiWidth = xmax - xmin + 1; // recalculating start location and block size - ++startLocationPara[1]; if (!gotthard25um) { startLocation[1] = ymin; startLocation[2] = xmin; blockSize[1] = portRoiHeight; blockSize[2] = portRoiWidth; } - // interleaving for g2 (startLocation is 0 and 1) + // interleaving for g2 (startLocation is 0 and 1) (g2 had no roi) else { ++startLocation[2]; } - + vdsDataSpace.selectHyperslab( H5S_SELECT_SET, numBlocks, startLocation, strideBetweenBlocks, blockSize); @@ -363,14 +368,13 @@ std::string CreateVirtualHDF5File( } // source dataspace - hsize_t srcDims[DATA_RANK] = {nImagesInFile, portRoiHeight, portRoiWidth}; + hsize_t srcDims[DATA_RANK] = {nSrcFileImages, portRoiHeight, portRoiWidth}; hsize_t srcDimsMax[DATA_RANK] = {H5S_UNLIMITED, portRoiHeight, portRoiWidth}; H5::DataSpace srcDataSpace(DATA_RANK, srcDims, srcDimsMax); - hsize_t srcDimsPara[PARA_RANK] = {nImagesInFile}; + hsize_t srcDimsPara[PARA_RANK] = {nSrcFileImages}; hsize_t srcDimsMaxPara[PARA_RANK] = {H5S_UNLIMITED}; - H5::DataSpace srcDataSpacePara(PARA_RANK, srcDimsPara, - srcDimsMaxPara); + H5::DataSpace srcDataSpacePara(PARA_RANK, srcDimsPara, srcDimsMaxPara); // temporary fixfor corner case bug: // (framescaught not multiple of framesperfile, // virtual parameter datasets error loading (bad scalar @@ -385,30 +389,33 @@ std::string CreateVirtualHDF5File( }*/ // mapping of property list - std::string datasetname = DATASET_NAME + '_' + std::to_string(iRoi); plist.setVirtual(vdsDataSpace, relative_srcFileName.c_str(), - datasetname.c_str(), srcDataSpace); + DATASET_NAME, srcDataSpace); for (unsigned int p = 0; p < paraSize; ++p) { - std::string parameterDsetName = parameterNames[p] + '_' + std::to_string(iRoi); plistPara[p].setVirtual( vdsDataSpacePara, relative_srcFileName.c_str(), - parameterDsetName.c_str(), srcDataSpacePara); + parameterNames[p].c_str(), srcDataSpacePara); } - // H5Sclose(srcDataspace); - // H5Sclose(srcDataspace_para); - + // map next readout ++startLocationPara[1]; } - framesSaved += nImagesInFile; + framesSaved += nSrcFileImages; } // datasets + std::string datasetname = std::string(DATASET_NAME); + // suffix '_[iRoi]' for multiple rois + if (multiRoi.size() > 1) + datasetname += ('_' + std::to_string(iRoi)); H5::DataSet vdsDataSet( - fd->createDataSet(DATASET_NAME, dataType, vdsDataSpace, plist)); - + fd->createDataSet(datasetname, dataType, vdsDataSpace, plist)); for (unsigned int p = 0; p < paraSize; ++p) { + std::string parameterDsetName = parameterNames[p]; + // suffix '_[iRoi]' for multiple rois + if (multiRoi.size() > 1) + parameterDsetName += ('_' + std::to_string(iRoi)); H5::DataSet vdsDataSetPara(fd->createDataSet( - parameterNames[p].c_str(), parameterDataTypes[p], + parameterDsetName.c_str(), parameterDataTypes[p], vdsDataSpacePara, plistPara[p])); } } From 3d4eaec178abdb2039337e3d6aed3e1dce122241 Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Fri, 27 Jun 2025 16:04:30 +0200 Subject: [PATCH 19/49] wip, works for a single roi --- slsReceiverSoftware/src/MasterFileUtility.cpp | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/slsReceiverSoftware/src/MasterFileUtility.cpp b/slsReceiverSoftware/src/MasterFileUtility.cpp index 1f25a342e..775e33325 100644 --- a/slsReceiverSoftware/src/MasterFileUtility.cpp +++ b/slsReceiverSoftware/src/MasterFileUtility.cpp @@ -230,6 +230,7 @@ std::string CreateVirtualHDF5File( std::unique_ptr fd{nullptr}; try { H5::Exception::dontPrint(); // to handle errors + H5Eset_auto(H5E_DEFAULT, (H5E_auto2_t)H5Eprint, stderr); // file H5::FileAccPropList fapl; @@ -248,6 +249,7 @@ std::string CreateVirtualHDF5File( "version", H5::PredType::NATIVE_DOUBLE, dataspace_attr); attribute.write(H5::PredType::NATIVE_DOUBLE, &dValue); + LOG(logINFORED) << "Rois:" << ToString(multiRoi); for (size_t iRoi = 0; iRoi != multiRoi.size(); ++iRoi) { @@ -277,6 +279,17 @@ std::string CreateVirtualHDF5File( int numFiles = numImagesCaught / maxFramesPerFile; if (numImagesCaught % maxFramesPerFile) ++numFiles; + LOG(logINFORED) << "Current Roi: " << currentRoi + << " detectorSize: " << ToString(detectorSize) + << " portSize: " << ToString(portSize) + << " nTotalPorts: " << nTotalPorts + << " roiWidth: " << roiWidth + << " roiHeight: " << roiHeight + << " nPortsInRoi: " << nPortsInRoi + << " nImages: " << nImages + << " numFiles: " << numFiles + << " maxFramesPerFile: " << maxFramesPerFile; + hsize_t vdsDims[DATA_RANK] = {nImages, roiHeight, roiWidth}; hsize_t vdsDimsPara[VDS_PARA_RANK] = {nImages, nPortsInRoi}; H5::DataSpace vdsDataSpace(DATA_RANK, vdsDims, nullptr); @@ -332,8 +345,8 @@ std::string CreateVirtualHDF5File( // recalculating start location and block size if (!gotthard25um) { - startLocation[1] = ymin; - startLocation[2] = xmin; + startLocation[1] = ymin - currentRoi.ymin; + startLocation[2] = xmin - currentRoi.xmin; blockSize[1] = portRoiHeight; blockSize[2] = portRoiWidth; } @@ -341,6 +354,12 @@ std::string CreateVirtualHDF5File( else { ++startLocation[2]; } + LOG(logINFORED) << "iReadout: " << iReadout + << " globalPortRoi: " << globalPortRoi + << " startLocation: " << ToString(startLocation) + << " blockSize: " << ToString(blockSize) + << " portRoiHeight: " << portRoiHeight + << " portRoiWidth: " << portRoiWidth; vdsDataSpace.selectHyperslab( H5S_SELECT_SET, numBlocks, startLocation, From ca3311da4c3955bc46c95a0e6853f8ce4ac1e966 Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Fri, 27 Jun 2025 17:17:19 +0200 Subject: [PATCH 20/49] works for all rois --- slsDetectorSoftware/src/DetectorImpl.cpp | 11 ++++++----- slsReceiverSoftware/src/DataProcessor.cpp | 4 ++-- slsReceiverSoftware/src/Implementation.cpp | 13 +++++++++++++ slsReceiverSoftware/src/MasterFileUtility.cpp | 18 ------------------ 4 files changed, 21 insertions(+), 25 deletions(-) diff --git a/slsDetectorSoftware/src/DetectorImpl.cpp b/slsDetectorSoftware/src/DetectorImpl.cpp index 55ae9db33..642c3ca1f 100644 --- a/slsDetectorSoftware/src/DetectorImpl.cpp +++ b/slsDetectorSoftware/src/DetectorImpl.cpp @@ -1809,15 +1809,16 @@ void DetectorImpl::convertGlobalRoiToPortLevel( // Check if user ROI overlaps with this port ROI if (userRoi.overlap(portRoi)) { defs::ROI clipped{}; - clipped.xmin = std::max(userRoi.xmin, portRoi.xmin); - clipped.xmax = std::min(userRoi.xmax, portRoi.xmax); + // Clip user ROI to port ROI + clipped.xmin = std::max(userRoi.xmin, portRoi.xmin) - portRoi.xmin; + clipped.xmax = std::min(userRoi.xmax, portRoi.xmax) - portRoi.xmin; if (modSize.y > 1) { - clipped.ymin = std::max(userRoi.ymin, portRoi.ymin); - clipped.ymax = std::min(userRoi.ymax, portRoi.ymax); + clipped.ymin = std::max(userRoi.ymin, portRoi.ymin) - portRoi.ymin; + clipped.ymax = std::min(userRoi.ymax, portRoi.ymax) - portRoi.ymin; } // Check if port ROI already exists for this port - if (!portRois[port].completeRoi()) { + if (!portRois[port].completeRoi() && !portRois[port].noRoi()) { throw RuntimeError( "Multiple ROIs specified for the same port " + std::to_string(port) + diff --git a/slsReceiverSoftware/src/DataProcessor.cpp b/slsReceiverSoftware/src/DataProcessor.cpp index f93c7d923..73959a6cf 100644 --- a/slsReceiverSoftware/src/DataProcessor.cpp +++ b/slsReceiverSoftware/src/DataProcessor.cpp @@ -690,7 +690,7 @@ void DataProcessor::ArrangeDbitData(size_t &size, char *data) { } void DataProcessor::CropImage(size_t &size, char *data) { - LOG(logDEBUG) << "Cropping Image to ROI " << ToString(portRoi); + LOG(logDEBUG1) << "Cropping Image to ROI " << ToString(portRoi); int nPixelsX = generalData->nPixelsX; int xmin = portRoi.xmin; int xmax = portRoi.xmax; @@ -702,7 +702,7 @@ void DataProcessor::CropImage(size_t &size, char *data) { ywidth = 1; ymin = 0; } - + // calculate total roi size double bytesPerPixel = generalData->dynamicRange / 8.00; int startOffset = (int)((nPixelsX * ymin + xmin) * bytesPerPixel); diff --git a/slsReceiverSoftware/src/Implementation.cpp b/slsReceiverSoftware/src/Implementation.cpp index 9a50d3dcb..9ac27668c 100644 --- a/slsReceiverSoftware/src/Implementation.cpp +++ b/slsReceiverSoftware/src/Implementation.cpp @@ -411,6 +411,19 @@ std::vector Implementation::getPortROIs() const { } void Implementation::setPortROIs(const std::vector &args) { + int nx = static_cast(generalData->nPixelsX); + int ny = static_cast(generalData->nPixelsY); + // validate rois + for (auto &it : args) { + if (it.completeRoi() || it.noRoi()) { + continue; // valid + } + if (it.xmin < 0 || it.ymin < 0 || it.xmax < 0 || it.ymax < 0 || + it.xmin >= nx || it.xmax >= nx || + it.ymin >= ny || it.ymax >= ny) { + throw RuntimeError("Invalid ROI coordinates: " + ToString(it)); + } + } portRois = args; for (size_t i = 0; i != listener.size(); ++i) diff --git a/slsReceiverSoftware/src/MasterFileUtility.cpp b/slsReceiverSoftware/src/MasterFileUtility.cpp index 775e33325..c9f0c1ee1 100644 --- a/slsReceiverSoftware/src/MasterFileUtility.cpp +++ b/slsReceiverSoftware/src/MasterFileUtility.cpp @@ -249,8 +249,6 @@ std::string CreateVirtualHDF5File( "version", H5::PredType::NATIVE_DOUBLE, dataspace_attr); attribute.write(H5::PredType::NATIVE_DOUBLE, &dValue); - LOG(logINFORED) << "Rois:" << ToString(multiRoi); - for (size_t iRoi = 0; iRoi != multiRoi.size(); ++iRoi) { auto currentRoi = multiRoi[iRoi]; @@ -279,16 +277,6 @@ std::string CreateVirtualHDF5File( int numFiles = numImagesCaught / maxFramesPerFile; if (numImagesCaught % maxFramesPerFile) ++numFiles; - LOG(logINFORED) << "Current Roi: " << currentRoi - << " detectorSize: " << ToString(detectorSize) - << " portSize: " << ToString(portSize) - << " nTotalPorts: " << nTotalPorts - << " roiWidth: " << roiWidth - << " roiHeight: " << roiHeight - << " nPortsInRoi: " << nPortsInRoi - << " nImages: " << nImages - << " numFiles: " << numFiles - << " maxFramesPerFile: " << maxFramesPerFile; hsize_t vdsDims[DATA_RANK] = {nImages, roiHeight, roiWidth}; hsize_t vdsDimsPara[VDS_PARA_RANK] = {nImages, nPortsInRoi}; @@ -354,12 +342,6 @@ std::string CreateVirtualHDF5File( else { ++startLocation[2]; } - LOG(logINFORED) << "iReadout: " << iReadout - << " globalPortRoi: " << globalPortRoi - << " startLocation: " << ToString(startLocation) - << " blockSize: " << ToString(blockSize) - << " portRoiHeight: " << portRoiHeight - << " portRoiWidth: " << portRoiWidth; vdsDataSpace.selectHyperslab( H5S_SELECT_SET, numBlocks, startLocation, From 25e4070168d1fc67bd3e9e164fc6e1d24ac61f89 Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Fri, 27 Jun 2025 17:37:15 +0200 Subject: [PATCH 21/49] wip to fix tests --- slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp b/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp index 24f815cc7..ba429a82a 100644 --- a/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp +++ b/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp @@ -626,13 +626,11 @@ TEST_CASE("rx_roi", "[.cmdcall]") { REQUIRE(oss1.str() == "rx_roi [[" + stringMin + ", " + std::to_string(portSize.x - 1) + "20, 30]]\n"); } } - std::cout << "done with eiger roi tests" << std::endl; } // multiple ports vertically if (((det_type == defs::JUNGFRAU || det_type == defs::MOENCH) && (numinterfaces == 2)) || (det.size() == 2 && det.getModuleGeometry().y > 1)) { - std::cout << "starting with jungfrau or other tests" << std::endl; std::string stringMin = std::to_string(portSize.y); std::string stringMax = std::to_string(portSize.y + 1); From 856ca1e5581287fafeb053552592092e2e706b10 Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Sun, 29 Jun 2025 01:06:34 +0200 Subject: [PATCH 22/49] 1d fixes --- slsDetectorSoftware/src/CallerSpecial.cpp | 10 ++++---- .../tests/Caller/test-Caller-rx.cpp | 24 +++++++++++++++---- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/slsDetectorSoftware/src/CallerSpecial.cpp b/slsDetectorSoftware/src/CallerSpecial.cpp index 4d921ef3a..7362af87d 100644 --- a/slsDetectorSoftware/src/CallerSpecial.cpp +++ b/slsDetectorSoftware/src/CallerSpecial.cpp @@ -819,15 +819,17 @@ std::vector Caller::parseRoiVector(const std::string &input) { parts.push_back(num); } - if (parts.size() != 4) { - throw RuntimeError("ROI must have 4 comma-separated integers"); + if (parts.size() != 2 && parts.size() != 4) { + throw RuntimeError("ROI must have 2 or 4 comma-separated integers"); } defs::ROI roi; roi.xmin = StringTo(parts[0]); roi.xmax = StringTo(parts[1]); - roi.ymin = StringTo(parts[2]); - roi.ymax = StringTo(parts[3]); + if (parts.size() == 4) { + roi.ymin = StringTo(parts[2]); + roi.ymax = StringTo(parts[3]); + } rois.emplace_back(roi); } return rois; diff --git a/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp b/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp index ba429a82a..2b7fbec98 100644 --- a/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp +++ b/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp @@ -476,6 +476,8 @@ TEST_CASE("rx_roi", "[.cmdcall]") { } else { auto prev_val = det.getRxROI(); defs::xy detsize = det.getDetectorSize(); + auto portSize = det.getPortSize()[0]; + int delta = 50; // 1d if (det_type == defs::GOTTHARD2 || det_type == defs::MYTHEN3) { @@ -528,6 +530,19 @@ TEST_CASE("rx_roi", "[.cmdcall]") { REQUIRE(oss.str() == "rx_roi [[5, 10], [" + stringMin + ", " + stringMax + "]]\n"); + // verify individual roi + { + stringMin = std::to_string(moduleSize.x - 50); + stringMax = std::to_string(moduleSize.x + 50); + std::ostringstream oss, oss1; + REQUIRE_NOTHROW(caller.call( + "rx_roi", {"[" + stringMin + ", " + stringMax + "]"}, -1, PUT, oss)); + REQUIRE(oss.str() == + "rx_roi [[" + stringMin + ", " + stringMax + "]]\n"); + REQUIRE_NOTHROW( + caller.call("rx_roi", {}, 0, GET, oss1)); + REQUIRE(oss1.str() == "rx_roi [[" + stringMin + ", " + std::to_string(moduleSize.x - 1) + "]]\n"); + } } } // 2d eiger, jungfrau, moench @@ -590,8 +605,7 @@ TEST_CASE("rx_roi", "[.cmdcall]") { int numinterfaces = det.getNumberofUDPInterfaces().tsquash( "inconsistent number of interfaces"); - auto portSize = det.getPortSize()[0]; - int delta = 50; + // multiple ports horizontally if (det_type == defs::EIGER || (det.size() == 2 && det.getModuleGeometry().x > 1)) { std::string stringMin = std::to_string(portSize.x); @@ -619,11 +633,11 @@ TEST_CASE("rx_roi", "[.cmdcall]") { caller.call("rx_roi", {}, 0, GET, oss1)); // eiger returns 2 values for 2 ports per module if (det_type == defs::EIGER) { - REQUIRE(oss1.str() == "rx_roi [[" + stringMin + ", " + std::to_string(portSize.x - 1) + ", 20, 30], [" + std::to_string(portSize.x) + ", " + stringMax + ", 20, 30]]\n"); + REQUIRE(oss1.str() == "rx_roi [[" + stringMin + ", " + std::to_string(portSize.x - 1) + ", 20, 30], [0, " + std::to_string(delta) + ", 20, 30]]\n"); } // others return only 1 roi per module (1 port per module) else { - REQUIRE(oss1.str() == "rx_roi [[" + stringMin + ", " + std::to_string(portSize.x - 1) + "20, 30]]\n"); + REQUIRE(oss1.str() == "rx_roi [[" + stringMin + ", " + std::to_string(portSize.x - 1) + ", 20, 30]]\n"); } } } @@ -657,7 +671,7 @@ TEST_CASE("rx_roi", "[.cmdcall]") { // non-eiger with 2 interfaces returns 2 values for 2 ports per module if ((det_type == defs::JUNGFRAU || det_type == defs::MOENCH) && (numinterfaces == 2)) { - REQUIRE(oss1.str() == "rx_roi [[20, 30, " + stringMin + ", " + std::to_string(portSize.y - 1) + "], [20, 30, " + std::to_string(portSize.y) + ", " + stringMax + "]]\n"); + REQUIRE(oss1.str() == "rx_roi [[20, 30, " + stringMin + ", " + std::to_string(portSize.y - 1) + "], [20, 30, 0, " + std::to_string(delta) + "]]\n"); } // others return only 1 roi per module (1 port per module) else { From 8e20d08af26662e26b3add05d6ca1ab5b98a11f7 Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Sun, 29 Jun 2025 15:13:51 +0200 Subject: [PATCH 23/49] rois test work on 1d as well --- slsDetectorSoftware/src/DetectorImpl.cpp | 21 ++++++++++++++++----- slsReceiverSoftware/src/Implementation.cpp | 11 +++++++---- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/slsDetectorSoftware/src/DetectorImpl.cpp b/slsDetectorSoftware/src/DetectorImpl.cpp index 642c3ca1f..06b37640a 100644 --- a/slsDetectorSoftware/src/DetectorImpl.cpp +++ b/slsDetectorSoftware/src/DetectorImpl.cpp @@ -1769,8 +1769,11 @@ defs::ROI DetectorImpl::getModuleROI(int moduleIndex) const { const defs::xy modPos = calculatePosition(moduleIndex); const int xmin = modSize.x * modPos.x; const int xmax = xmin + modSize.x - 1; - const int ymin = modSize.y * modPos.y; - const int ymax = ymin + modSize.y - 1; + int ymin = -1, ymax = -1; + if (modSize.y > 1) { + ymin = modSize.y * modPos.y; + ymax = ymin + modSize.y - 1; + } return defs::ROI{xmin, xmax, ymin, ymax}; } @@ -1780,6 +1783,7 @@ void DetectorImpl::convertGlobalRoiToPortLevel( 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."); } @@ -1806,16 +1810,20 @@ void DetectorImpl::convertGlobalRoiToPortLevel( portRoi.ymin = midY + 1; } - // Check if user ROI overlaps with this port ROI + // Check if user ROI overlaps with port if (userRoi.overlap(portRoi)) { defs::ROI clipped{}; // Clip user ROI to port ROI clipped.xmin = std::max(userRoi.xmin, portRoi.xmin) - portRoi.xmin; clipped.xmax = std::min(userRoi.xmax, portRoi.xmax) - portRoi.xmin; + LOG(logDEBUG1) << "User ROI: " << ToString(userRoi) + << ", Port ROI: " << ToString(portRoi) << " clipped roi:"<< ToString(clipped); if (modSize.y > 1) { clipped.ymin = std::max(userRoi.ymin, portRoi.ymin) - portRoi.ymin; clipped.ymax = std::min(userRoi.ymax, portRoi.ymax) - portRoi.ymin; } + LOG(logDEBUG1) << "Clipped ROI for port " << port + << ": " << ToString(clipped); // Check if port ROI already exists for this port if (!portRois[port].completeRoi() && !portRois[port].noRoi()) { @@ -1847,19 +1855,22 @@ void DetectorImpl::setRxROI(const std::vector &args) { for (size_t iModule = 0; iModule < modules.size(); ++iModule) { auto moduleGlobalRoi = getModuleROI(iModule); + LOG(logDEBUG1) << "Module " << iModule + << " Global ROI: " << ToString(moduleGlobalRoi); // at most 2 rois per module (for each port) std::vector portRois(nPortsPerModule); + // check overlap with module for (const auto &arg : args) { if (arg.overlap(moduleGlobalRoi)) { convertGlobalRoiToPortLevel(arg, moduleGlobalRoi, portRois); } } // print the rois for debugging - LOG(logINFOBLUE) << "Module " << iModule << " RxROIs:"; + LOG(logDEBUG1) << "Module " << iModule << " RxROIs:"; for (size_t iPort = 0; iPort != portRois.size(); iPort++) { - LOG(logINFOBLUE) + LOG(logDEBUG1) << " Port " << iPort << ": " << ToString(portRois[iPort]); } modules[iModule]->setRxROI(portRois); diff --git a/slsReceiverSoftware/src/Implementation.cpp b/slsReceiverSoftware/src/Implementation.cpp index 9ac27668c..cf895c617 100644 --- a/slsReceiverSoftware/src/Implementation.cpp +++ b/slsReceiverSoftware/src/Implementation.cpp @@ -418,10 +418,13 @@ void Implementation::setPortROIs(const std::vector &args) { if (it.completeRoi() || it.noRoi()) { continue; // valid } - if (it.xmin < 0 || it.ymin < 0 || it.xmax < 0 || it.ymax < 0 || - it.xmin >= nx || it.xmax >= nx || - it.ymin >= ny || it.ymax >= ny) { - throw RuntimeError("Invalid ROI coordinates: " + ToString(it)); + if (it.xmin < 0 || it.xmax < 0 || + it.xmin >= nx || it.xmax >= nx) { + throw RuntimeError("Invalid ROIvx coordinates: " + ToString(it)); + } + if (ny > 1 && (it.ymin < 0 || it.ymax < 0 || + it.ymin >= ny || it.ymax >= ny)) { + throw RuntimeError("Invalid ROI y coordinates: " + ToString(it)); } } portRois = args; From 72bf1fa2571d451748c953dea02b5a88d346d5aa Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Sun, 29 Jun 2025 17:09:30 +0200 Subject: [PATCH 24/49] check master file creation as well in rx_roi tests --- .../tests/Caller/test-Caller-rx.cpp | 41 +++++++++++++++++++ tests/scripts/test_roi.py | 10 +++-- 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp b/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp index 2b7fbec98..f89428553 100644 --- a/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp +++ b/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp @@ -8,6 +8,7 @@ #include "test-Caller-global.h" #include +#include #include "sls/versionAPI.h" #include "tests/globals.h" @@ -686,6 +687,46 @@ TEST_CASE("rx_roi", "[.cmdcall]") { } } + // check master file creation + // TODO: check roi in master file + { + auto prev_write = det.getFileWrite().tsquash( + "inconsistent file write values in test"); + auto prev_path = det.getFilePath().tsquash( + "inconsistent file path values in test"); + auto prev_format = det.getFileFormat().tsquash( + "inconsistent file format values in test"); + auto prev_index = det.getAcquisitionIndex().tsquash( + "inconsistent file index values in test"); + auto prev_fname = det.getFileNamePrefix().tsquash( + "inconsistent file name prefix values in test"); + + det.setFileWrite(true); + det.setFilePath("/tmp"); + det.setFileNamePrefix("test"); + + det.setAcquisitionIndex(0); + det.setFileFormat(defs::BINARY); + REQUIRE_NOTHROW(caller.call("acquire", {}, -1, PUT)); + std::string file_path = "/tmp/test_master_0.json"; + REQUIRE(std::filesystem::exists(file_path) == true); + + det.setAcquisitionIndex(0); + det.setFileFormat(defs::HDF5); + REQUIRE_NOTHROW(caller.call("acquire", {}, -1, PUT)); + file_path = "/tmp/test_master_0.h5"; + REQUIRE(std::filesystem::exists(file_path) == true); + file_path = "/tmp/test_virtual_0.h5"; + REQUIRE(std::filesystem::exists(file_path) == true); + + det.setFileWrite(prev_write); + if (!prev_path.empty()) + det.setFilePath(prev_path); + det.setFileFormat(prev_format); + det.setAcquisitionIndex(prev_index); + det.setFileNamePrefix(prev_fname); + } + for (int i = 0; i != det.size(); ++i) { det.setRxROI(prev_val); } diff --git a/tests/scripts/test_roi.py b/tests/scripts/test_roi.py index 07565b591..2f56f31b1 100644 --- a/tests/scripts/test_roi.py +++ b/tests/scripts/test_roi.py @@ -56,12 +56,14 @@ def loadConfigForRoi(name, fp, num_mods = 1, num_interfaces = 1): d.udp_srcip = 'auto' if name == 'jungfrau' or name == 'moench': d.udp_dstip2 = 'auto' + d.powerchip = 1 + + d.frames = 5 except Exception as e: raise RuntimeException(f'Could not load config for {name}. Error: {str(e)}') from e - - - + + return d def startTestsForAll(fp): servers = [ @@ -85,7 +87,7 @@ def startTestsForAll(fp): cleanup(fp) startDetectorVirtualServer(server, nmods, fp) startReceiver(nmods, fp) - loadConfigForRoi(name=server, fp=fp, num_mods=nmods, num_interfaces=ninterfaces) + d = loadConfigForRoi(name=server, fp=fp, num_mods=nmods, num_interfaces=ninterfaces) fname = ROI_TEST_FNAME + server + '.txt' cmd = ['tests', 'rx_roi', '--abort', '-s'] From b775dd0efa70e5b600831210f06496cdd05c41cc Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Sun, 29 Jun 2025 18:56:07 +0200 Subject: [PATCH 25/49] get rx_roi from metadata from rxr, cant reconstruct. fixed clear roi should give 1 roi min --- slsDetectorSoftware/src/DetectorImpl.cpp | 15 ++++-------- slsDetectorSoftware/src/DetectorImpl.h | 2 -- slsDetectorSoftware/src/Module.cpp | 23 +++++++++++++++++++ slsDetectorSoftware/src/Module.h | 1 + .../tests/Caller/test-Caller-rx.cpp | 5 +++- slsReceiverSoftware/src/ClientInterface.cpp | 13 +++++++++++ slsReceiverSoftware/src/ClientInterface.h | 1 + slsReceiverSoftware/src/Implementation.cpp | 4 ++++ slsReceiverSoftware/src/Implementation.h | 1 + .../include/sls/sls_detector_funcs.h | 2 ++ 10 files changed, 54 insertions(+), 13 deletions(-) diff --git a/slsDetectorSoftware/src/DetectorImpl.cpp b/slsDetectorSoftware/src/DetectorImpl.cpp index 06b37640a..35e0b4dd8 100644 --- a/slsDetectorSoftware/src/DetectorImpl.cpp +++ b/slsDetectorSoftware/src/DetectorImpl.cpp @@ -1675,18 +1675,14 @@ std::vector DetectorImpl::getRxROI(int module_id) const { if (modules.size() == 0) { throw RuntimeError("No Modules added"); } - - // individual module rois + if (module_id >= (int)modules.size()) { + throw RuntimeError("Invalid module id: " + std::to_string(module_id)); + } if (module_id >= 0) { - if (module_id >= (int)modules.size()) - throw RuntimeError("Invalid module index " + std::to_string(module_id) + ". Out of bounds."); return modules[module_id]->getRxROI(); } - // multi roi - // return std::vector{}; - return rxRoiTemp; - // TODO + return modules[0]->getRxROIMetadata(); } void DetectorImpl::validateROIs(const std::vector &rois) { @@ -1875,17 +1871,16 @@ void DetectorImpl::setRxROI(const std::vector &args) { } modules[iModule]->setRxROI(portRois); } - rxRoiTemp = args; // metadata modules[0]->setRxROIMetadata(args); } void DetectorImpl::clearRxROI() { - rxRoiTemp.clear(); int nPortsPerModule = Parallel(&Module::getNumberofUDPInterfacesFromShm, {}).tsquash("Inconsistent number of udp ports set up per module"); for (size_t iModule = 0; iModule < modules.size(); ++iModule) { modules[iModule]->setRxROI(std::vector(nPortsPerModule)); } + modules[0]->setRxROIMetadata(std::vector(1)); } void DetectorImpl::getBadChannels(const std::string &fname, diff --git a/slsDetectorSoftware/src/DetectorImpl.h b/slsDetectorSoftware/src/DetectorImpl.h index d90c4c303..34f53e28a 100644 --- a/slsDetectorSoftware/src/DetectorImpl.h +++ b/slsDetectorSoftware/src/DetectorImpl.h @@ -459,8 +459,6 @@ class DetectorImpl : public virtual slsDetectorDefs { void (*dataReady)(detectorData *, uint64_t, uint32_t, void *){nullptr}; void *pCallbackArg{nullptr}; - - std::vector rxRoiTemp; }; } // namespace sls \ No newline at end of file diff --git a/slsDetectorSoftware/src/Module.cpp b/slsDetectorSoftware/src/Module.cpp index c1c65add3..6a3161928 100644 --- a/slsDetectorSoftware/src/Module.cpp +++ b/slsDetectorSoftware/src/Module.cpp @@ -1569,6 +1569,29 @@ void Module::setRxROI(const std::vector &portRois) { } } +std::vector Module::getRxROIMetadata() const { + LOG(logDEBUG1) << "Getting receiver ROI metadata for Module " + << moduleIndex; + // check number of ports + if (!shm()->useReceiverFlag) { + throw RuntimeError("No receiver to get ROI metadata."); + } + auto client = ReceiverSocket(shm()->rxHostname, shm()->rxTCPPort); + client.Send(F_RECEIVER_GET_ROI_METADATA); + client.setFnum(F_RECEIVER_GET_ROI_METADATA); + auto size = client.Receive(); + std::vector retval(size); + if (size > 0) + client.Receive(retval); + if (size == 0) { + throw RuntimeError("Invalid number of ROI metadata: " + + std::to_string(size) + ". Min: 1."); + } + LOG(logDEBUG1) << "ROI metadata of Receiver: " + << ToString(retval); + return retval; +} + void Module::setRxROIMetadata(const std::vector &args) { LOG(logDEBUG) << "Sending to receiver " << moduleIndex << " [roi metadata: " << ToString(args) << ']'; diff --git a/slsDetectorSoftware/src/Module.h b/slsDetectorSoftware/src/Module.h index 86516cbb5..4494383b0 100644 --- a/slsDetectorSoftware/src/Module.h +++ b/slsDetectorSoftware/src/Module.h @@ -304,6 +304,7 @@ class Module : public virtual slsDetectorDefs { std::vector getRxROI() const; void setRxROI(const std::vector &portRois); void setRxROIMetadata(const std::vector &args); + std::vector getRxROIMetadata() const; /************************************************** * * diff --git a/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp b/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp index f89428553..4172f4559 100644 --- a/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp +++ b/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp @@ -728,7 +728,10 @@ TEST_CASE("rx_roi", "[.cmdcall]") { } for (int i = 0; i != det.size(); ++i) { - det.setRxROI(prev_val); + if (prev_val.size() == 1 && prev_val[0].completeRoi()) { + det.clearRxROI(); + } else + det.setRxROI(prev_val); } } } diff --git a/slsReceiverSoftware/src/ClientInterface.cpp b/slsReceiverSoftware/src/ClientInterface.cpp index d0336ba49..c05ee6245 100644 --- a/slsReceiverSoftware/src/ClientInterface.cpp +++ b/slsReceiverSoftware/src/ClientInterface.cpp @@ -220,6 +220,7 @@ int ClientInterface::functionTable(){ flist[F_RECEIVER_SET_COLUMN] = &ClientInterface::set_column; flist[F_GET_RECEIVER_DBIT_REORDER] = &ClientInterface::get_dbit_reorder; flist[F_SET_RECEIVER_DBIT_REORDER] = &ClientInterface::set_dbit_reorder; + flist[F_RECEIVER_GET_ROI_METADATA] = &ClientInterface::get_roi_metadata; for (int i = NUM_DET_FUNCTIONS + 1; i < NUM_REC_FUNCTIONS ; i++) { @@ -1838,4 +1839,16 @@ int ClientInterface::set_dbit_reorder(Interface &socket) { return socket.Send(OK); } +int ClientInterface::get_roi_metadata(Interface &socket) { + if (detType == CHIPTESTBOARD || detType == XILINX_CHIPTESTBOARD) + functionNotImplemented(); + auto retvals = impl()->getMultiROIMetadata(); + LOG(logINFORED) << "Receiver ROI metadata retval:" << ToString(retvals); + auto size = static_cast(retvals.size()); + socket.Send(size); + if (size > 0) + socket.Send(retvals); + return OK; +} + } // namespace sls diff --git a/slsReceiverSoftware/src/ClientInterface.h b/slsReceiverSoftware/src/ClientInterface.h index 665e0f396..e17a3ab85 100644 --- a/slsReceiverSoftware/src/ClientInterface.h +++ b/slsReceiverSoftware/src/ClientInterface.h @@ -166,6 +166,7 @@ class ClientInterface : private virtual slsDetectorDefs { int set_column(ServerInterface &socket); int get_dbit_reorder(ServerInterface &socket); int set_dbit_reorder(ServerInterface &socket); + int get_roi_metadata(ServerInterface &socket); Implementation *impl() { if (receiver != nullptr) { diff --git a/slsReceiverSoftware/src/Implementation.cpp b/slsReceiverSoftware/src/Implementation.cpp index cf895c617..5e0940f4b 100644 --- a/slsReceiverSoftware/src/Implementation.cpp +++ b/slsReceiverSoftware/src/Implementation.cpp @@ -450,6 +450,10 @@ void Implementation::setMultiROIMetadata( LOG(logINFO) << "Multi ROI Metadata: " << ToString(multiRoiMetadata); } +std::vector Implementation::getMultiROIMetadata() const { + return multiRoiMetadata; +} + /************************************************** * * * File Parameters * diff --git a/slsReceiverSoftware/src/Implementation.h b/slsReceiverSoftware/src/Implementation.h index 099454441..e83539304 100644 --- a/slsReceiverSoftware/src/Implementation.h +++ b/slsReceiverSoftware/src/Implementation.h @@ -61,6 +61,7 @@ class Implementation : private virtual slsDetectorDefs { std::vector getPortROIs() const; void setPortROIs(const std::vector &args); void setMultiROIMetadata(const std::vector &args); + std::vector getMultiROIMetadata() const; /************************************************** * * diff --git a/slsSupportLib/include/sls/sls_detector_funcs.h b/slsSupportLib/include/sls/sls_detector_funcs.h index ec1c6d2f1..20688941c 100755 --- a/slsSupportLib/include/sls/sls_detector_funcs.h +++ b/slsSupportLib/include/sls/sls_detector_funcs.h @@ -412,6 +412,7 @@ enum detFuncs { F_RECEIVER_SET_COLUMN, F_GET_RECEIVER_DBIT_REORDER, F_SET_RECEIVER_DBIT_REORDER, + F_RECEIVER_GET_ROI_METADATA, NUM_REC_FUNCTIONS }; @@ -820,6 +821,7 @@ const char* getFunctionNameFromEnum(enum detFuncs func) { case F_RECEIVER_SET_COLUMN: return "F_RECEIVER_SET_COLUMN"; case F_GET_RECEIVER_DBIT_REORDER: return "F_GET_RECEIVER_DBIT_REORDER"; case F_SET_RECEIVER_DBIT_REORDER: return "F_SET_RECEIVER_DBIT_REORDER"; + case F_RECEIVER_GET_ROI_METADATA: return "F_RECEIVER_GET_ROI_METADATA"; case NUM_REC_FUNCTIONS: return "NUM_REC_FUNCTIONS"; default: return "Unknown Function"; From cbd0aed8e53e2c6ec3d4d5f9cf3d3cad1cbe9398 Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Mon, 30 Jun 2025 12:03:39 +0200 Subject: [PATCH 26/49] gui shows roi now --- slsDetectorGui/include/qDrawPlot.h | 6 +- .../slsDetectorPlotting/include/SlsQt1DPlot.h | 8 +- .../slsDetectorPlotting/include/SlsQt2DPlot.h | 8 +- .../slsDetectorPlotting/src/SlsQt1DPlot.cpp | 28 ++++--- .../slsDetectorPlotting/src/SlsQt2DPlot.cpp | 28 +++---- slsDetectorGui/src/qDetectorMain.cpp | 1 + slsDetectorGui/src/qDrawPlot.cpp | 84 ++++++++++--------- .../include/sls/detectorData.h | 9 -- slsDetectorSoftware/src/DetectorImpl.cpp | 3 +- slsReceiverSoftware/src/ClientInterface.cpp | 2 +- 10 files changed, 92 insertions(+), 85 deletions(-) diff --git a/slsDetectorGui/include/qDrawPlot.h b/slsDetectorGui/include/qDrawPlot.h index 92f660b50..c4b3b2a9d 100644 --- a/slsDetectorGui/include/qDrawPlot.h +++ b/slsDetectorGui/include/qDrawPlot.h @@ -40,6 +40,7 @@ class qDrawPlot : public QWidget, private Ui::PlotObject { void SetDataCallBack(bool enable); void SetBinary(bool enable, int from = 0, int to = 0); void StartAcquisition(); + void UpdateROI(); public slots: void SetPersistency(int val); @@ -166,8 +167,8 @@ class qDrawPlot : public QWidget, private Ui::PlotObject { int64_t currentFrame{0}; mutable std::mutex mPlots; int64_t currentAcqIndex{0}; - slsDetectorDefs::ROI rxRoi{}; - bool isRxRoiDisplayed{false}; + bool hasRoi{false}; + bool roiDisplayInitialized{false}; bool isGapPixels{false}; unsigned int nPixelsX{0}; @@ -176,6 +177,7 @@ class qDrawPlot : public QWidget, private Ui::PlotObject { uint32_t gainMask{0}; int gainOffset{0}; bool gotthard25; + std::vector roi{1}; }; } // namespace sls diff --git a/slsDetectorGui/slsDetectorPlotting/include/SlsQt1DPlot.h b/slsDetectorGui/slsDetectorPlotting/include/SlsQt1DPlot.h index 9dfdee151..878a43b81 100644 --- a/slsDetectorGui/slsDetectorPlotting/include/SlsQt1DPlot.h +++ b/slsDetectorGui/slsDetectorPlotting/include/SlsQt1DPlot.h @@ -5,6 +5,8 @@ #include "SlsQt1DZoomer.h" #include "sls/ansi.h" +#include "sls/sls_detector_defs.h" + #include #include #include @@ -141,8 +143,9 @@ class SlsQt1DPlot : public QwtPlot { void SetLogX(bool yes = 1); void SetLogY(bool yes = 1); - void EnableRoiBox(std::array roi); - void DisableRoiBox(); + void EnableRoiBoxes(std::vector roi, int ymin, + int ymax); + void DisableRoiBoxes(); private: bool gainPlot{false}; @@ -169,6 +172,7 @@ class SlsQt1DPlot : public QwtPlot { friend void SlsQtH1D::Attach(SlsQt1DPlot *p); friend void SlsQtH1D::Detach(SlsQt1DPlot *p); + std::vector> roiBoxes{}; QwtPlotShapeItem *roiBox{nullptr}; signals: diff --git a/slsDetectorGui/slsDetectorPlotting/include/SlsQt2DPlot.h b/slsDetectorGui/slsDetectorPlotting/include/SlsQt2DPlot.h index 4c55db6af..f7142b6eb 100644 --- a/slsDetectorGui/slsDetectorPlotting/include/SlsQt2DPlot.h +++ b/slsDetectorGui/slsDetectorPlotting/include/SlsQt2DPlot.h @@ -3,6 +3,8 @@ #pragma once #include "SlsQt2DHist.h" #include "SlsQt2DZoomer.h" +#include "sls/sls_detector_defs.h" + #include #include #include @@ -71,8 +73,8 @@ class SlsQt2DPlot : public QwtPlot { void SetLogz(bool enable, bool isMin, bool isMax, double min, double max); void SetZRange(bool isMin, bool isMax, double min, double max); void LogZ(bool on = 1); - void EnableRoiBox(std::array roi); - void DisableRoiBox(); + void EnableRoiBoxes(std::vector roi); + void DisableRoiBoxes(); public slots: void showSpectrogram(bool on); @@ -101,7 +103,7 @@ class SlsQt2DPlot : public QwtPlot { QList contourLevelsLog; bool disableZoom{false}; int isLog; - QwtPlotShapeItem *roiBox{nullptr}; + std::vector> roiBoxes{}; }; } // namespace sls diff --git a/slsDetectorGui/slsDetectorPlotting/src/SlsQt1DPlot.cpp b/slsDetectorGui/slsDetectorPlotting/src/SlsQt1DPlot.cpp index 55716cc33..8ae58d4b2 100644 --- a/slsDetectorGui/slsDetectorPlotting/src/SlsQt1DPlot.cpp +++ b/slsDetectorGui/slsDetectorPlotting/src/SlsQt1DPlot.cpp @@ -462,24 +462,26 @@ void SlsQt1DPlot::SetLog(int axisId, bool yes) { Update(); } -void SlsQt1DPlot::EnableRoiBox(std::array roi) { - if (roiBox == nullptr) { - roiBox = new QwtPlotShapeItem(); - roiBox->attach(this); - roiBox->setPen(QColor(Qt::yellow), 2.0, Qt::SolidLine); +void SlsQt1DPlot::EnableRoiBoxes(std::vector roi, + int ymin, int ymax) { + roiBoxes.clear(); + for (auto &r : roi) { + auto box = std::make_unique(); + box->setPen(QColor(Qt::yellow), 2.0, Qt::SolidLine); + // TopLeft - BottomRight (max points are +1 on graph) + QRectF myRect(QPointF(r.xmin, ymin), QPointF(r.xmax - 1, ymax - 1)); + box->setRect(myRect); + box->attach(this); + roiBoxes.push_back(std::move(box)); } - - // TopLeft - BottomRight (max points are +1 on graph) - QRect myRect(QPoint(roi[0], roi[2]), QPoint(roi[1] - 1, roi[3] - 1)); - roiBox->setRect(QRectF(myRect)); replot(); } -void SlsQt1DPlot::DisableRoiBox() { - if (roiBox != nullptr) { - roiBox->detach(); - replot(); +void SlsQt1DPlot::DisableRoiBoxes() { + for (auto &r : roiBoxes) { + r->detach(); } + replot(); } void SlsQt1DPlot::SetZoomX(const QRectF &rect) { diff --git a/slsDetectorGui/slsDetectorPlotting/src/SlsQt2DPlot.cpp b/slsDetectorGui/slsDetectorPlotting/src/SlsQt2DPlot.cpp index 3418abf08..ecd7b6eb3 100644 --- a/slsDetectorGui/slsDetectorPlotting/src/SlsQt2DPlot.cpp +++ b/slsDetectorGui/slsDetectorPlotting/src/SlsQt2DPlot.cpp @@ -350,25 +350,25 @@ void SlsQt2DPlot::showSpectrogram(bool on) { Update(); } -void SlsQt2DPlot::EnableRoiBox(std::array roi) { - if (roiBox == nullptr) { - roiBox = new QwtPlotShapeItem(); +void SlsQt2DPlot::EnableRoiBoxes(std::vector roi) { + roiBoxes.clear(); + for (auto &r : roi) { + auto box = std::make_unique(); + box->setPen(QColor(Qt::yellow), 2.0, Qt::SolidLine); + // TopLeft - BottomRight (max points are +1 on graph) + QRectF myRect(QPointF(r.xmin, r.ymin), QPointF(r.xmax - 1, r.ymax - 1)); + box->setRect(myRect); + box->attach(this); + roiBoxes.push_back(std::move(box)); } - roiBox->setPen(QColor(Qt::yellow), 2.0, Qt::SolidLine); - - // TopLeft - BottomRight (max points are +1 on graph) - QRect myRect(QPoint(roi[0], roi[2]), QPoint(roi[1] - 1, roi[3] - 1)); - roiBox->setRect(QRectF(myRect)); - - roiBox->attach(this); replot(); } -void SlsQt2DPlot::DisableRoiBox() { - if (roiBox != nullptr) { - roiBox->detach(); - replot(); +void SlsQt2DPlot::DisableRoiBoxes() { + for (auto &r : roiBoxes) { + r->detach(); } + replot(); } } // namespace sls diff --git a/slsDetectorGui/src/qDetectorMain.cpp b/slsDetectorGui/src/qDetectorMain.cpp index c5ddc8618..438707c36 100644 --- a/slsDetectorGui/src/qDetectorMain.cpp +++ b/slsDetectorGui/src/qDetectorMain.cpp @@ -539,6 +539,7 @@ void qDetectorMain::EnableTabs(bool enable) { tabDeveloper->Refresh(); tabPlot->Refresh(); + plot->UpdateROI(); plot->StartAcquisition(); } else { // to enable scan box tabPlot->Refresh(); diff --git a/slsDetectorGui/src/qDrawPlot.cpp b/slsDetectorGui/src/qDrawPlot.cpp index 829a3c81a..0eb8e2e11 100644 --- a/slsDetectorGui/src/qDrawPlot.cpp +++ b/slsDetectorGui/src/qDrawPlot.cpp @@ -608,7 +608,6 @@ void qDrawPlot::StartAcquisition() { currentFrame = 0; boxPlot->setTitle("Old Plot"); det->clearAcquiringFlag(); // (from previous exit) or if running - isRxRoiDisplayed = false; // ensure data streaming in receiver (if plot enabled) if (isPlot) { @@ -632,6 +631,33 @@ void qDrawPlot::StartAcquisition() { LOG(logDEBUG) << "End of Starting Acquisition in qDrawPlot"; } +void qDrawPlot::UpdateROI() { + try { + std::lock_guard lock(mPlots); + roi = det->getRxROI(); + roiDisplayInitialized = false; + // roi enabled + if (roi.size() > 1 || !roi[0].completeRoi()) { + hasRoi = true; + // update gap pixels (gap pixels only for 2d) + if (isGapPixels) { + for (auto &r : roi) { + r.xmin += ((r.xmin / 1024) * 6 + (r.xmin / 256) * 2); + r.xmax += ((r.xmax / 1024) * 6 + (r.xmax / 256) * 2); + r.ymin += ((r.ymin / 512) * 34 + (r.ymin / 256) * 2); + r.ymax += ((r.ymax / 512) * 34 + (r.ymax / 256) * 2); + } + LOG(logINFO) + << "Roi recalculated with gap pixels: " << ToString(roi); + } + } else { + hasRoi = false; + } + LOG(logDEBUG) << "Roi: " << ToString(roi); + } + CATCH_DISPLAY("Could not get reciver ROI.", "qDrawPlot::UpdateRoi") +} + void qDrawPlot::AcquireThread() { LOG(logDEBUG) << "Acquire Thread"; std::string mess; @@ -709,7 +735,6 @@ void qDrawPlot::GetData(detectorData *data, uint64_t frameIndex, << " \t dynamic range: " << data->dynamicRange << std::endl << " \t file index: " << data->fileIndex << std::endl << " \t complete image: " << data->completeImage << std::endl - << " \t rx Roi: " << ToString(data->rxRoi) << std::endl << " ]"; progress = data->progressIndex; @@ -717,22 +742,6 @@ void qDrawPlot::GetData(detectorData *data, uint64_t frameIndex, currentFrame = frameIndex; LOG(logDEBUG) << "[ Progress:" << progress << "%, Frame:" << currentFrame << " ]"; - if (!isRxRoiDisplayed) { - rxRoi.xmin = data->rxRoi[0]; - rxRoi.xmax = data->rxRoi[1]; - rxRoi.ymin = data->rxRoi[2]; - rxRoi.ymax = data->rxRoi[3]; - // only for 2d anyway - if (isGapPixels) { - rxRoi.xmin += ((rxRoi.xmin / 1024) * 6 + (rxRoi.xmin / 256) * 2); - rxRoi.xmax += ((rxRoi.xmax / 1024) * 6 + (rxRoi.xmax / 256) * 2); - rxRoi.ymin += ((rxRoi.ymin / 512) * 34 + (rxRoi.ymin / 256) * 2); - rxRoi.ymax += ((rxRoi.ymax / 512) * 34 + (rxRoi.ymax / 256) * 2); - LOG(logINFO) << "Rx_roi recalculated with gap pixels: " - << ToString(rxRoi); - } - LOG(logDEBUG) << "Rx_roi: " << ToString(rxRoi); - } // 1d check if npixelX has changed (m3 for different counters enabled) if (is1d && static_cast(nPixelsX) != data->nx) { @@ -971,30 +980,27 @@ void qDrawPlot::Update1dPlot() { xyRangeChanged = false; } plot1d->DisableZoom(disableZoom); - if (!isRxRoiDisplayed) { - isRxRoiDisplayed = true; - if (rxRoi.completeRoi()) { - plot1d->DisableRoiBox(); + if (!roiDisplayInitialized) { + roiDisplayInitialized = true; + if (!hasRoi) { + plot1d->DisableRoiBoxes(); if (isGainDataExtracted) { - gainplot1d->DisableRoiBox(); + gainplot1d->DisableRoiBoxes(); } lblRxRoiEnabled->hide(); } else { - plot1d->EnableRoiBox(std::array{ - rxRoi.xmin, rxRoi.xmax, (int)plot1d->GetYMinimum(), - (int)plot1d->GetYMaximum()}); + plot1d->EnableRoiBoxes(roi, (int)plot1d->GetYMinimum(), + (int)plot1d->GetYMaximum()); if (isGainDataExtracted) { - gainplot1d->EnableRoiBox( - std::array{rxRoi.xmin, rxRoi.xmax, 0, 3}); + gainplot1d->EnableRoiBoxes(roi, 0, 3); } lblRxRoiEnabled->show(); } } // ymin and ymax could change (so replot roi every time) - if (!rxRoi.completeRoi()) { - plot1d->EnableRoiBox(std::array{rxRoi.xmin, rxRoi.xmax, - (int)plot1d->GetYMinimum(), - (int)plot1d->GetYMaximum()}); + if (hasRoi) { + plot1d->EnableRoiBoxes(roi, (int)plot1d->GetYMinimum(), + (int)plot1d->GetYMaximum()); } } @@ -1025,18 +1031,18 @@ void qDrawPlot::Update2dPlot() { } plot2d->DisableZoom(disableZoom); plot2d->SetZRange(isZRange[0], isZRange[1], zRange[0], zRange[1]); - if (!isRxRoiDisplayed) { - isRxRoiDisplayed = true; - if (rxRoi.completeRoi()) { - plot2d->DisableRoiBox(); + if (!roiDisplayInitialized) { + roiDisplayInitialized = true; + if (!hasRoi) { + plot2d->DisableRoiBoxes(); if (isGainDataExtracted) { - gainplot2d->DisableRoiBox(); + gainplot2d->DisableRoiBoxes(); } lblRxRoiEnabled->hide(); } else { - plot2d->EnableRoiBox(rxRoi.getIntArray()); + plot2d->EnableRoiBoxes(roi); if (isGainDataExtracted) { - gainplot2d->EnableRoiBox(rxRoi.getIntArray()); + gainplot2d->EnableRoiBoxes(roi); } lblRxRoiEnabled->show(); } diff --git a/slsDetectorSoftware/include/sls/detectorData.h b/slsDetectorSoftware/include/sls/detectorData.h index 33f983a66..c55906482 100644 --- a/slsDetectorSoftware/include/sls/detectorData.h +++ b/slsDetectorSoftware/include/sls/detectorData.h @@ -19,14 +19,6 @@ class detectorData { databytes(databytes), dynamicRange(dynamicRange), completeImage(completeImage){}; - detectorData(double progressIndex, std::string fileName, int nx, int ny, - char *data, int databytes, int dynamicRange, - uint64_t fileIndex, bool completeImage, - std::array rxRoi) - : progressIndex(progressIndex), fileName(fileName), - fileIndex(fileIndex), nx(nx), ny(ny), data(data), - databytes(databytes), dynamicRange(dynamicRange), - completeImage(completeImage), rxRoi(rxRoi){}; /** * data has to be deleted by caller */ @@ -62,7 +54,6 @@ class detectorData { int databytes; int dynamicRange; bool completeImage; - std::array rxRoi{{-1, -1, -1, -1}}; }; } // namespace sls diff --git a/slsDetectorSoftware/src/DetectorImpl.cpp b/slsDetectorSoftware/src/DetectorImpl.cpp index 35e0b4dd8..5727edb78 100644 --- a/slsDetectorSoftware/src/DetectorImpl.cpp +++ b/slsDetectorSoftware/src/DetectorImpl.cpp @@ -535,7 +535,6 @@ void DetectorImpl::readFrameFromReceiver() { bool quadEnable = false; // to flip image bool eiger = false; - std::array rxRoi{}; // TODO: get roi from json header std::vector runningList(zmqSocket.size()); std::vector connectList(zmqSocket.size()); @@ -732,7 +731,7 @@ void DetectorImpl::readFrameFromReceiver() { thisData = new detectorData(currentProgress, currentFileName, nDetActualPixelsX, nDetActualPixelsY, callbackImage, imagesize, dynamicRange, - currentFileIndex, completeImage, rxRoi); + currentFileIndex, completeImage); try { dataReady( thisData, currentFrameIndex, diff --git a/slsReceiverSoftware/src/ClientInterface.cpp b/slsReceiverSoftware/src/ClientInterface.cpp index c05ee6245..902870a8f 100644 --- a/slsReceiverSoftware/src/ClientInterface.cpp +++ b/slsReceiverSoftware/src/ClientInterface.cpp @@ -1843,7 +1843,7 @@ int ClientInterface::get_roi_metadata(Interface &socket) { if (detType == CHIPTESTBOARD || detType == XILINX_CHIPTESTBOARD) functionNotImplemented(); auto retvals = impl()->getMultiROIMetadata(); - LOG(logINFORED) << "Receiver ROI metadata retval:" << ToString(retvals); + LOG(logDEBUG1) << "Receiver ROI metadata retval:" << ToString(retvals); auto size = static_cast(retvals.size()); socket.Send(size); if (size > 0) From 5d31d86b8342d42ac2ce172b026ac4e4b98153f4 Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Mon, 30 Jun 2025 12:32:05 +0200 Subject: [PATCH 27/49] format --- slsDetectorSoftware/include/sls/Detector.h | 3 +- slsDetectorSoftware/src/Detector.cpp | 5 +- slsDetectorSoftware/src/DetectorImpl.cpp | 43 +++-- slsDetectorSoftware/src/DetectorImpl.h | 6 +- slsDetectorSoftware/src/Module.cpp | 9 +- .../tests/Caller/test-Caller-rx.cpp | 156 +++++++++++------- slsReceiverSoftware/src/DataProcessor.cpp | 12 +- slsReceiverSoftware/src/DataStreamer.cpp | 2 +- slsReceiverSoftware/src/Implementation.cpp | 10 +- slsReceiverSoftware/src/MasterFileUtility.cpp | 90 +++++----- slsReceiverSoftware/src/MasterFileUtility.h | 14 +- slsSupportLib/include/sls/ToString.h | 1 - slsSupportLib/include/sls/sls_detector_defs.h | 10 +- 13 files changed, 205 insertions(+), 156 deletions(-) diff --git a/slsDetectorSoftware/include/sls/Detector.h b/slsDetectorSoftware/include/sls/Detector.h index 86e8d2372..90f2cd6ac 100644 --- a/slsDetectorSoftware/include/sls/Detector.h +++ b/slsDetectorSoftware/include/sls/Detector.h @@ -992,7 +992,8 @@ class Detector { /** Returns multi level ROIs */ std::vector getRxROI() const; - /** Returns port level ROIs. Max 2 ports and hence max 2 elements per readout */ + /** Returns port level ROIs. Max 2 ports and hence max 2 elements per + * readout */ std::vector getRxROI(int module_id) const; /** only at multi module level without gap pixels. At most, 1 ROI per UDP diff --git a/slsDetectorSoftware/src/Detector.cpp b/slsDetectorSoftware/src/Detector.cpp index b2d70937c..06e44a308 100644 --- a/slsDetectorSoftware/src/Detector.cpp +++ b/slsDetectorSoftware/src/Detector.cpp @@ -1383,9 +1383,7 @@ void Detector::setRxArping(bool value, Positions pos) { pimpl->Parallel(&Module::setRxArping, pos, value); } -std::vector Detector::getRxROI() const { - return pimpl->getRxROI(); -} +std::vector Detector::getRxROI() const { return pimpl->getRxROI(); } std::vector Detector::getRxROI(int module_id) const { return pimpl->getRxROI(module_id); @@ -1398,7 +1396,6 @@ void Detector::setRxROI(const std::vector &args) { void Detector::clearRxROI() { pimpl->clearRxROI(); } - // File Result Detector::getFileFormat(Positions pos) const { diff --git a/slsDetectorSoftware/src/DetectorImpl.cpp b/slsDetectorSoftware/src/DetectorImpl.cpp index 5727edb78..497791140 100644 --- a/slsDetectorSoftware/src/DetectorImpl.cpp +++ b/slsDetectorSoftware/src/DetectorImpl.cpp @@ -1676,7 +1676,7 @@ std::vector DetectorImpl::getRxROI(int module_id) const { } if (module_id >= (int)modules.size()) { throw RuntimeError("Invalid module id: " + std::to_string(module_id)); - } + } if (module_id >= 0) { return modules[module_id]->getRxROI(); } @@ -1783,9 +1783,10 @@ void DetectorImpl::convertGlobalRoiToPortLevel( throw RuntimeError("Only up to 2 ports per module supported."); } if (numPorts != (int)portRois.size()) { - throw RuntimeError("Number of port ROIs does not match number of ports in module. Expected: " + - std::to_string(numPorts) + ", got: " + - std::to_string(portRois.size())); + throw RuntimeError("Number of port ROIs does not match number of ports " + "in module. Expected: " + + std::to_string(numPorts) + + ", got: " + std::to_string(portRois.size())); } for (int port = 0; port < numPorts; ++port) { @@ -1812,20 +1813,22 @@ void DetectorImpl::convertGlobalRoiToPortLevel( clipped.xmin = std::max(userRoi.xmin, portRoi.xmin) - portRoi.xmin; clipped.xmax = std::min(userRoi.xmax, portRoi.xmax) - portRoi.xmin; LOG(logDEBUG1) << "User ROI: " << ToString(userRoi) - << ", Port ROI: " << ToString(portRoi) << " clipped roi:"<< ToString(clipped); + << ", Port ROI: " << ToString(portRoi) + << " clipped roi:" << ToString(clipped); if (modSize.y > 1) { - clipped.ymin = std::max(userRoi.ymin, portRoi.ymin) - portRoi.ymin; - clipped.ymax = std::min(userRoi.ymax, portRoi.ymax) - portRoi.ymin; + clipped.ymin = + std::max(userRoi.ymin, portRoi.ymin) - portRoi.ymin; + clipped.ymax = + std::min(userRoi.ymax, portRoi.ymax) - portRoi.ymin; } - LOG(logDEBUG1) << "Clipped ROI for port " << port - << ": " << ToString(clipped); + LOG(logDEBUG1) << "Clipped ROI for port " << port << ": " + << ToString(clipped); // Check if port ROI already exists for this port if (!portRois[port].completeRoi() && !portRois[port].noRoi()) { throw RuntimeError( "Multiple ROIs specified for the same port " + - std::to_string(port) + - " with ROI: " + ToString(userRoi)); + std::to_string(port) + " with ROI: " + ToString(userRoi)); } portRois[port] = clipped; } @@ -1846,12 +1849,14 @@ void DetectorImpl::setRxROI(const std::vector &args) { } validateROIs(args); - int nPortsPerModule = Parallel(&Module::getNumberofUDPInterfacesFromShm, {}).tsquash("Inconsistent number of udp ports set up per module"); + int nPortsPerModule = + Parallel(&Module::getNumberofUDPInterfacesFromShm, {}) + .tsquash("Inconsistent number of udp ports set up per module"); for (size_t iModule = 0; iModule < modules.size(); ++iModule) { auto moduleGlobalRoi = getModuleROI(iModule); LOG(logDEBUG1) << "Module " << iModule - << " Global ROI: " << ToString(moduleGlobalRoi); + << " Global ROI: " << ToString(moduleGlobalRoi); // at most 2 rois per module (for each port) std::vector portRois(nPortsPerModule); @@ -1865,8 +1870,8 @@ void DetectorImpl::setRxROI(const std::vector &args) { // print the rois for debugging LOG(logDEBUG1) << "Module " << iModule << " RxROIs:"; for (size_t iPort = 0; iPort != portRois.size(); iPort++) { - LOG(logDEBUG1) - << " Port " << iPort << ": " << ToString(portRois[iPort]); + LOG(logDEBUG1) << " Port " << iPort << ": " + << ToString(portRois[iPort]); } modules[iModule]->setRxROI(portRois); } @@ -1874,10 +1879,12 @@ void DetectorImpl::setRxROI(const std::vector &args) { modules[0]->setRxROIMetadata(args); } -void DetectorImpl::clearRxROI() { - int nPortsPerModule = Parallel(&Module::getNumberofUDPInterfacesFromShm, {}).tsquash("Inconsistent number of udp ports set up per module"); +void DetectorImpl::clearRxROI() { + int nPortsPerModule = + Parallel(&Module::getNumberofUDPInterfacesFromShm, {}) + .tsquash("Inconsistent number of udp ports set up per module"); for (size_t iModule = 0; iModule < modules.size(); ++iModule) { - modules[iModule]->setRxROI(std::vector(nPortsPerModule)); + modules[iModule]->setRxROI(std::vector(nPortsPerModule)); } modules[0]->setRxROIMetadata(std::vector(1)); } diff --git a/slsDetectorSoftware/src/DetectorImpl.h b/slsDetectorSoftware/src/DetectorImpl.h index 34f53e28a..5b2789e0b 100644 --- a/slsDetectorSoftware/src/DetectorImpl.h +++ b/slsDetectorSoftware/src/DetectorImpl.h @@ -428,9 +428,9 @@ class DetectorImpl : public virtual slsDetectorDefs { void validateROIs(const std::vector &rois); defs::xy calculatePosition(int moduleIndex) const; defs::ROI getModuleROI(int moduleIndex) const; - void convertGlobalRoiToPortLevel( - const defs::ROI &userRoi, const defs::ROI &moduleRoi, - std::vector &portRois) 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/src/Module.cpp b/slsDetectorSoftware/src/Module.cpp index 6a3161928..440386080 100644 --- a/slsDetectorSoftware/src/Module.cpp +++ b/slsDetectorSoftware/src/Module.cpp @@ -1526,7 +1526,7 @@ std::vector Module::getRxROI() const { // check number of ports if (!shm()->useReceiverFlag) { throw RuntimeError("No receiver to get ROI."); - } + } auto client = ReceiverSocket(shm()->rxHostname, shm()->rxTCPPort); client.Send(F_RECEIVER_GET_RECEIVER_ROI); client.setFnum(F_RECEIVER_GET_RECEIVER_ROI); @@ -1561,12 +1561,12 @@ void Module::setRxROI(const std::vector &portRois) { client.setFnum(F_RECEIVER_SET_RECEIVER_ROI); int size = static_cast(portRois.size()); client.Send(size); - if (size > 0) + if (size > 0) client.Send(portRois); if (client.Receive() == FAIL) { throw ReceiverError("Receiver " + std::to_string(moduleIndex) + " returned error: " + client.readErrorMessage()); - } + } } std::vector Module::getRxROIMetadata() const { @@ -1587,8 +1587,7 @@ std::vector Module::getRxROIMetadata() const { throw RuntimeError("Invalid number of ROI metadata: " + std::to_string(size) + ". Min: 1."); } - LOG(logDEBUG1) << "ROI metadata of Receiver: " - << ToString(retval); + LOG(logDEBUG1) << "ROI metadata of Receiver: " << ToString(retval); return retval; } diff --git a/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp b/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp index 4172f4559..df9edbacd 100644 --- a/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp +++ b/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp @@ -7,8 +7,8 @@ #include "sls/sls_detector_defs.h" #include "test-Caller-global.h" -#include #include +#include #include "sls/versionAPI.h" #include "tests/globals.h" @@ -502,8 +502,7 @@ TEST_CASE("rx_roi", "[.cmdcall]") { {"[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]"}, 0, PUT)); + REQUIRE_THROWS(caller.call("rx_roi", {"[5, 10, -1, -1]"}, 0, PUT)); // vector of rois // square brackets missing @@ -518,18 +517,23 @@ TEST_CASE("rx_roi", "[.cmdcall]") { if (det.size() == 2) { auto moduleSize = det.getModuleSize()[0]; - std::string stringMin = std::to_string(moduleSize.x); - std::string stringMax = std::to_string(moduleSize.x + 1); + std::string stringMin = std::to_string(moduleSize.x); + std::string stringMax = std::to_string(moduleSize.x + 1); // separated by space is allowed REQUIRE_NOTHROW(caller.call( - "rx_roi", {"[5, 10, -1, -1]", "[" + stringMin + ", " + stringMax + ", -1, -1]"}, -1, PUT)); + "rx_roi", + {"[5, 10, -1, -1]", + "[" + stringMin + ", " + stringMax + ", -1, -1]"}, + -1, PUT)); std::ostringstream oss; // separated by semicolon is allowed - REQUIRE_NOTHROW(caller.call( - "rx_roi", {"[5, 10, -1, -1];[" + stringMin + ", " + stringMax + ", -1, -1]"}, -1, PUT, oss)); - REQUIRE(oss.str() == - "rx_roi [[5, 10], [" + stringMin + ", " + stringMax + "]]\n"); + REQUIRE_NOTHROW(caller.call("rx_roi", + {"[5, 10, -1, -1];[" + stringMin + + ", " + stringMax + ", -1, -1]"}, + -1, PUT, oss)); + REQUIRE(oss.str() == "rx_roi [[5, 10], [" + stringMin + ", " + + stringMax + "]]\n"); // verify individual roi { @@ -537,12 +541,14 @@ TEST_CASE("rx_roi", "[.cmdcall]") { stringMax = std::to_string(moduleSize.x + 50); std::ostringstream oss, oss1; REQUIRE_NOTHROW(caller.call( - "rx_roi", {"[" + stringMin + ", " + stringMax + "]"}, -1, PUT, oss)); - REQUIRE(oss.str() == - "rx_roi [[" + stringMin + ", " + stringMax + "]]\n"); - REQUIRE_NOTHROW( - caller.call("rx_roi", {}, 0, GET, oss1)); - REQUIRE(oss1.str() == "rx_roi [[" + stringMin + ", " + std::to_string(moduleSize.x - 1) + "]]\n"); + "rx_roi", {"[" + stringMin + ", " + stringMax + "]"}, + -1, PUT, oss)); + REQUIRE(oss.str() == "rx_roi [[" + stringMin + ", " + + stringMax + "]]\n"); + REQUIRE_NOTHROW(caller.call("rx_roi", {}, 0, GET, oss1)); + REQUIRE(oss1.str() == "rx_roi [[" + stringMin + ", " + + std::to_string(moduleSize.x - 1) + + "]]\n"); } } } @@ -587,8 +593,7 @@ TEST_CASE("rx_roi", "[.cmdcall]") { {"[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]"}, 0, PUT)); + REQUIRE_THROWS(caller.call("rx_roi", {"[5, 10, 20, 30]"}, 0, PUT)); // vector of rois // square brackets missing @@ -603,24 +608,29 @@ TEST_CASE("rx_roi", "[.cmdcall]") { REQUIRE_THROWS(caller.call( "rx_roi", {"[0, 10, 0, 10];[0, 10, 9, 11]"}, -1, PUT)); - int numinterfaces = det.getNumberofUDPInterfaces().tsquash( - "inconsistent number of interfaces"); + "inconsistent number of interfaces"); // multiple ports horizontally - if (det_type == defs::EIGER || (det.size() == 2 && det.getModuleGeometry().x > 1)) { - std::string stringMin = std::to_string(portSize.x); - std::string stringMax = std::to_string(portSize.x + 1); + if (det_type == defs::EIGER || + (det.size() == 2 && det.getModuleGeometry().x > 1)) { + std::string stringMin = std::to_string(portSize.x); + std::string stringMax = std::to_string(portSize.x + 1); // separated by space is allowed REQUIRE_NOTHROW(caller.call( - "rx_roi", {"[5, 10, 20, 30]", "[" + stringMin + ", " + stringMax + ", 20, 30]"}, -1, PUT)); + "rx_roi", + {"[5, 10, 20, 30]", + "[" + stringMin + ", " + stringMax + ", 20, 30]"}, + -1, PUT)); std::ostringstream oss; // separated by semicolon is allowed - REQUIRE_NOTHROW(caller.call( - "rx_roi", {"[5, 10, 20, 30];[" + stringMin + ", " + stringMax + ", 20, 30]"}, -1, PUT, oss)); - REQUIRE(oss.str() == - "rx_roi [[5, 10, 20, 30], [" + stringMin + ", " + stringMax + ", 20, 30]]\n"); + REQUIRE_NOTHROW(caller.call("rx_roi", + {"[5, 10, 20, 30];[" + stringMin + + ", " + stringMax + ", 20, 30]"}, + -1, PUT, oss)); + REQUIRE(oss.str() == "rx_roi [[5, 10, 20, 30], [" + stringMin + + ", " + stringMax + ", 20, 30]]\n"); // verify individual roi { @@ -628,36 +638,52 @@ TEST_CASE("rx_roi", "[.cmdcall]") { stringMax = std::to_string(portSize.x + delta); std::ostringstream oss, oss1; REQUIRE_NOTHROW(caller.call( - "rx_roi", {"[" + stringMin + ", " + stringMax + ", 20, 30]"}, -1, PUT, oss)); - REQUIRE(oss.str() == "rx_roi [[" + stringMin + ", " + stringMax + ", 20, 30]]\n"); - REQUIRE_NOTHROW( - caller.call("rx_roi", {}, 0, GET, oss1)); + "rx_roi", + {"[" + stringMin + ", " + stringMax + ", 20, 30]"}, -1, + PUT, oss)); + REQUIRE(oss.str() == "rx_roi [[" + stringMin + ", " + + stringMax + ", 20, 30]]\n"); + REQUIRE_NOTHROW(caller.call("rx_roi", {}, 0, GET, oss1)); // eiger returns 2 values for 2 ports per module if (det_type == defs::EIGER) { - REQUIRE(oss1.str() == "rx_roi [[" + stringMin + ", " + std::to_string(portSize.x - 1) + ", 20, 30], [0, " + std::to_string(delta) + ", 20, 30]]\n"); + REQUIRE(oss1.str() == + "rx_roi [[" + stringMin + ", " + + std::to_string(portSize.x - 1) + + ", 20, 30], [0, " + std::to_string(delta) + + ", 20, 30]]\n"); } - // others return only 1 roi per module (1 port per module) + // others return only 1 roi per module (1 port per module) else { - REQUIRE(oss1.str() == "rx_roi [[" + stringMin + ", " + std::to_string(portSize.x - 1) + ", 20, 30]]\n"); + REQUIRE(oss1.str() == + "rx_roi [[" + stringMin + ", " + + std::to_string(portSize.x - 1) + + ", 20, 30]]\n"); } } } // multiple ports vertically - if (((det_type == defs::JUNGFRAU || det_type == defs::MOENCH) && (numinterfaces == 2)) || - (det.size() == 2 && det.getModuleGeometry().y > 1)) { - std::string stringMin = std::to_string(portSize.y); - std::string stringMax = std::to_string(portSize.y + 1); + if (((det_type == defs::JUNGFRAU || det_type == defs::MOENCH) && + (numinterfaces == 2)) || + (det.size() == 2 && det.getModuleGeometry().y > 1)) { + std::string stringMin = std::to_string(portSize.y); + std::string stringMax = std::to_string(portSize.y + 1); // separated by space is allowed - REQUIRE_NOTHROW(caller.call( - "rx_roi", {"[5, 10, 20, 30]", "[25, 28, " + stringMin + ", " + stringMax + "]"}, -1, PUT)); + REQUIRE_NOTHROW( + caller.call("rx_roi", + {"[5, 10, 20, 30]", "[25, 28, " + stringMin + + ", " + stringMax + "]"}, + -1, PUT)); std::ostringstream oss; // separated by semicolon is allowed - REQUIRE_NOTHROW(caller.call( - "rx_roi", {"[5, 10, 20, 30];[25, 28, " + stringMin + ", " + stringMax + "]"}, -1, PUT, oss)); - REQUIRE(oss.str() == - "rx_roi [[5, 10, 20, 30], [25, 28, " + stringMin + ", " + stringMax + "]]\n"); + REQUIRE_NOTHROW( + caller.call("rx_roi", + {"[5, 10, 20, 30];[25, 28, " + stringMin + + ", " + stringMax + "]"}, + -1, PUT, oss)); + REQUIRE(oss.str() == "rx_roi [[5, 10, 20, 30], [25, 28, " + + stringMin + ", " + stringMax + "]]\n"); // verify individual roi { @@ -665,22 +691,37 @@ TEST_CASE("rx_roi", "[.cmdcall]") { stringMax = std::to_string(portSize.y + delta); std::ostringstream oss, oss1; REQUIRE_NOTHROW(caller.call( - "rx_roi", {"[ 20, 30, " + stringMin + ", " + stringMax + "]"}, -1, PUT, oss)); - REQUIRE(oss.str() == "rx_roi [[20, 30, " + stringMin + ", " + stringMax + "]]\n"); - REQUIRE_NOTHROW( - caller.call("rx_roi", {}, 0, GET, oss1)); - - // non-eiger with 2 interfaces returns 2 values for 2 ports per module - if ((det_type == defs::JUNGFRAU || det_type == defs::MOENCH) && (numinterfaces == 2)) { - REQUIRE(oss1.str() == "rx_roi [[20, 30, " + stringMin + ", " + std::to_string(portSize.y - 1) + "], [20, 30, 0, " + std::to_string(delta) + "]]\n"); + "rx_roi", + {"[ 20, 30, " + stringMin + ", " + stringMax + "]"}, -1, + PUT, oss)); + REQUIRE(oss.str() == "rx_roi [[20, 30, " + stringMin + + ", " + stringMax + "]]\n"); + REQUIRE_NOTHROW(caller.call("rx_roi", {}, 0, GET, oss1)); + + // non-eiger with 2 interfaces returns 2 values for 2 ports + // per module + if ((det_type == defs::JUNGFRAU || + det_type == defs::MOENCH) && + (numinterfaces == 2)) { + REQUIRE(oss1.str() == + "rx_roi [[20, 30, " + stringMin + ", " + + std::to_string(portSize.y - 1) + + "], [20, 30, 0, " + std::to_string(delta) + + "]]\n"); } - // others return only 1 roi per module (1 port per module) + // others return only 1 roi per module (1 port per module) else { // (eiger 2 ports) if (det_type == defs::EIGER) { - REQUIRE(oss1.str() == "rx_roi [[20, 30, " + stringMin + ", " + std::to_string(portSize.y - 1) + "], [-1, -1]]\n"); + REQUIRE(oss1.str() == + "rx_roi [[20, 30, " + stringMin + ", " + + std::to_string(portSize.y - 1) + + "], [-1, -1]]\n"); } else { - REQUIRE(oss1.str() == "rx_roi [[20, 30, " + stringMin + ", " + std::to_string(portSize.y - 1) + "]]\n"); + REQUIRE(oss1.str() == + "rx_roi [[20, 30, " + stringMin + ", " + + std::to_string(portSize.y - 1) + + "]]\n"); } } } @@ -700,7 +741,7 @@ TEST_CASE("rx_roi", "[.cmdcall]") { "inconsistent file index values in test"); auto prev_fname = det.getFileNamePrefix().tsquash( "inconsistent file name prefix values in test"); - + det.setFileWrite(true); det.setFilePath("/tmp"); det.setFileNamePrefix("test"); @@ -736,7 +777,6 @@ TEST_CASE("rx_roi", "[.cmdcall]") { } } - TEST_CASE("rx_clearroi", "[.cmdcall]") { Detector det; Caller caller(&det); diff --git a/slsReceiverSoftware/src/DataProcessor.cpp b/slsReceiverSoftware/src/DataProcessor.cpp index 73959a6cf..a863e39d5 100644 --- a/slsReceiverSoftware/src/DataProcessor.cpp +++ b/slsReceiverSoftware/src/DataProcessor.cpp @@ -227,8 +227,8 @@ std::string DataProcessor::CreateVirtualFile( return masterFileUtility::CreateVirtualHDF5File( filePath, fileNamePrefix, fileIndex, overWriteEnable, silentMode, modulePos, generalData->numUDPInterfaces, framesPerFile, - generalData->nPixelsX, ny, generalData->dynamicRange, - numFramesCaught, numModX, numModY, dataFile->GetPDataType(), + generalData->nPixelsX, ny, generalData->dynamicRange, numFramesCaught, + numModX, numModY, dataFile->GetPDataType(), dataFile->GetParameterNames(), dataFile->GetParameterDataTypes(), hdf5LibMutex, gotthard25um, multiRoiMetadata); } @@ -247,9 +247,9 @@ void DataProcessor::LinkFileInMaster(const std::string &masterFileName, if (virtualFileName.empty()) { fname = dataFile->GetFileName(); } - masterFileUtility::LinkHDF5FileInMaster(masterfname, fname, - dataFile->GetParameterNames(), - silentMode, hdf5LibMutex, multiRoiMetadata.size()); + masterFileUtility::LinkHDF5FileInMaster( + masterfname, fname, dataFile->GetParameterNames(), silentMode, + hdf5LibMutex, multiRoiMetadata.size()); } #endif @@ -702,7 +702,7 @@ void DataProcessor::CropImage(size_t &size, char *data) { ywidth = 1; ymin = 0; } - + // calculate total roi size double bytesPerPixel = generalData->dynamicRange / 8.00; int startOffset = (int)((nPixelsX * ymin + xmin) * bytesPerPixel); diff --git a/slsReceiverSoftware/src/DataStreamer.cpp b/slsReceiverSoftware/src/DataStreamer.cpp index e971dae30..8a8e83833 100644 --- a/slsReceiverSoftware/src/DataStreamer.cpp +++ b/slsReceiverSoftware/src/DataStreamer.cpp @@ -54,7 +54,7 @@ void DataStreamer::SetAdditionalJsonHeader( } void DataStreamer::SetPortROI(ROI roi) { - if (roi.completeRoi()) {//TODO: just not send zmq if not in roi? + if (roi.completeRoi()) { // TODO: just not send zmq if not in roi? portRoi = ROI(0, generalData->nPixelsX - 1, 0, generalData->nPixelsY - 1); } else { diff --git a/slsReceiverSoftware/src/Implementation.cpp b/slsReceiverSoftware/src/Implementation.cpp index 5e0940f4b..1c974063d 100644 --- a/slsReceiverSoftware/src/Implementation.cpp +++ b/slsReceiverSoftware/src/Implementation.cpp @@ -166,7 +166,6 @@ void Implementation::setDetectorType(const detectorType d) { SetLocalNetworkParameters(); SetupFifoStructure(); - // create threads for (int i = 0; i < generalData->numUDPInterfaces; ++i) { @@ -418,12 +417,11 @@ void Implementation::setPortROIs(const std::vector &args) { if (it.completeRoi() || it.noRoi()) { continue; // valid } - if (it.xmin < 0 || it.xmax < 0 || - it.xmin >= nx || it.xmax >= nx) { + if (it.xmin < 0 || it.xmax < 0 || it.xmin >= nx || it.xmax >= nx) { throw RuntimeError("Invalid ROIvx coordinates: " + ToString(it)); - } - if (ny > 1 && (it.ymin < 0 || it.ymax < 0 || - it.ymin >= ny || it.ymax >= ny)) { + } + if (ny > 1 && + (it.ymin < 0 || it.ymax < 0 || it.ymin >= ny || it.ymax >= ny)) { throw RuntimeError("Invalid ROI y coordinates: " + ToString(it)); } } diff --git a/slsReceiverSoftware/src/MasterFileUtility.cpp b/slsReceiverSoftware/src/MasterFileUtility.cpp index c9f0c1ee1..b05ec579f 100644 --- a/slsReceiverSoftware/src/MasterFileUtility.cpp +++ b/slsReceiverSoftware/src/MasterFileUtility.cpp @@ -49,7 +49,8 @@ std::string CreateMasterBinaryFile(const std::string &filePath, void LinkHDF5FileInMaster(std::string &masterFileName, std::string &dataFilename, std::vector parameterNames, - const bool silentMode, std::mutex *hdf5LibMutex, size_t multiRoiSize) { + const bool silentMode, std::mutex *hdf5LibMutex, + size_t multiRoiSize) { std::lock_guard lock(*hdf5LibMutex); std::unique_ptr fd{nullptr}; @@ -74,11 +75,10 @@ void LinkHDF5FileInMaster(std::string &masterFileName, if (multiRoiSize > 1) datasetname += ('_' + std::to_string(iRoi)); H5::DataSet dset = fd->openDataSet(datasetname); - std::string linkname = - std::string("/entry/data/") + datasetname; + std::string linkname = std::string("/entry/data/") + datasetname; if (H5Lcreate_external(dataFilename.c_str(), datasetname.c_str(), - masterfd.getLocId(), linkname.c_str(), - H5P_DEFAULT, H5P_DEFAULT) < 0) { + masterfd.getLocId(), linkname.c_str(), + H5P_DEFAULT, H5P_DEFAULT) < 0) { throw RuntimeError( "Could not create link to data dataset in master"); } @@ -91,9 +91,9 @@ void LinkHDF5FileInMaster(std::string &masterFileName, H5::DataSet pDset = fd->openDataSet(parameterDsetName.c_str()); linkname = std::string("/entry/data/") + parameterDsetName; if (H5Lcreate_external(dataFilename.c_str(), - parameterDsetName.c_str(), - masterfd.getLocId(), linkname.c_str(), - H5P_DEFAULT, H5P_DEFAULT) < 0) { + parameterDsetName.c_str(), + masterfd.getLocId(), linkname.c_str(), + H5P_DEFAULT, H5P_DEFAULT) < 0) { throw RuntimeError( "Could not create link to parameter dataset in master"); } @@ -169,13 +169,14 @@ std::string CreateMasterHDF5File(const std::string &filePath, return fileName; } -defs::ROI GetGlobalPortRoi(const int iPort, const defs::xy portSize, const int numPortsY) { +defs::ROI GetGlobalPortRoi(const int iPort, const defs::xy portSize, + const int numPortsY) { defs::xy portPos = {(iPort / numPortsY), (iPort % numPortsY)}; const int xmin = portSize.x * portPos.x; const int xmax = xmin + portSize.x - 1; const int ymin = portSize.y * portPos.y; const int ymax = ymin + portSize.y - 1; - return defs::ROI{xmin, xmax, ymin, ymax}; + return defs::ROI{xmin, xmax, ymin, ymax}; } int GetNumPortsInRoi(const defs::ROI roi, const defs::xy portSize) { @@ -194,32 +195,33 @@ std::string CreateVirtualHDF5File( const std::string &filePath, const std::string &fileNamePrefix, const uint64_t fileIndex, const bool overWriteEnable, const bool silentMode, const int modulePos, const int numUnitsPerReadout, - const uint32_t maxFramesPerFile, const int nPixelsX, - const int nPixelsY, const uint32_t dynamicRange, - const uint64_t numImagesCaught, const int numModX, const int numModY, - const H5::DataType dataType, const std::vector parameterNames, + const uint32_t maxFramesPerFile, const int nPixelsX, const int nPixelsY, + const uint32_t dynamicRange, const uint64_t numImagesCaught, + const int numModX, const int numModY, const H5::DataType dataType, + const std::vector parameterNames, const std::vector parameterDataTypes, std::mutex *hdf5LibMutex, bool gotthard25um, std::vector multiRoi) { bool completeRoi = false; if (multiRoi.size() == 1 && multiRoi[0].completeRoi()) { - completeRoi = true; + completeRoi = true; } // roi not allowed in 4 bit mode and with gotthard 2 mods if (!completeRoi) { if (dynamicRange == 4) { - throw std::runtime_error("Skipping virtual hdf5 file since rx_roi is " - "enabled and it is in 4 bit mode."); + throw std::runtime_error( + "Skipping virtual hdf5 file since rx_roi is " + "enabled and it is in 4 bit mode."); } if (gotthard25um && (numModX * numModY) == 2) { - throw std::runtime_error("Skipping virtual hdf5 file since rx_roi is " - "enabled and there are 2 Gotthard 25um modules."); + throw std::runtime_error( + "Skipping virtual hdf5 file since rx_roi is " + "enabled and there are 2 Gotthard 25um modules."); } } - // virtual file name std::ostringstream osfn; osfn << filePath << "/" << fileNamePrefix << "_virtual" @@ -250,15 +252,16 @@ std::string CreateVirtualHDF5File( attribute.write(H5::PredType::NATIVE_DOUBLE, &dValue); for (size_t iRoi = 0; iRoi != multiRoi.size(); ++iRoi) { - + auto currentRoi = multiRoi[iRoi]; defs::xy detectorSize = {nPixelsX * numModX, nPixelsY * numModY}; if (completeRoi) { - currentRoi = defs::ROI{0, detectorSize.x - 1, - 0, detectorSize.y - 1}; + currentRoi = + defs::ROI{0, detectorSize.x - 1, 0, detectorSize.y - 1}; } - if (multiRoi[iRoi].completeRoi()&& iRoi != 0) - throw RuntimeError("Cannot have complete roi and multiple rois"); + if (multiRoi[iRoi].completeRoi() && iRoi != 0) + throw RuntimeError( + "Cannot have complete roi and multiple rois"); // get detector shape and number of ports in roi defs::xy portSize{nPixelsX, nPixelsY}; @@ -276,8 +279,8 @@ std::string CreateVirtualHDF5File( uint64_t nImages = numImagesCaught; int numFiles = numImagesCaught / maxFramesPerFile; if (numImagesCaught % maxFramesPerFile) - ++numFiles; - + ++numFiles; + hsize_t vdsDims[DATA_RANK] = {nImages, roiHeight, roiWidth}; hsize_t vdsDimsPara[VDS_PARA_RANK] = {nImages, nPortsInRoi}; H5::DataSpace vdsDataSpace(DATA_RANK, vdsDims, nullptr); @@ -296,7 +299,7 @@ std::string CreateVirtualHDF5File( // hyperslab (files) uint64_t framesSaved = 0; for (int iFile = 0; iFile != numFiles; ++iFile) { - + // images in src file uint64_t nSrcFileImages = numImagesCaught - framesSaved; if ((numImagesCaught - framesSaved) > maxFramesPerFile) @@ -309,7 +312,9 @@ std::string CreateVirtualHDF5File( hsize_t blockSizePara[VDS_PARA_RANK] = {nSrcFileImages, 1}; // following recalculated for every readout - hsize_t blockSize[DATA_RANK] = {nSrcFileImages, static_cast(nPixelsY), static_cast(nPixelsX)}; + hsize_t blockSize[DATA_RANK] = {nSrcFileImages, + static_cast(nPixelsY), + static_cast(nPixelsX)}; hsize_t startLocation[DATA_RANK] = {framesSaved, 0, 0}; hsize_t startLocationPara[VDS_PARA_RANK] = {framesSaved, 0}; @@ -318,18 +323,20 @@ std::string CreateVirtualHDF5File( strideBetweenBlocks[2] = 2; } - for (unsigned int iReadout = 0; iReadout < nTotalPorts; ++iReadout) { - auto globalPortRoi = GetGlobalPortRoi(iReadout, portSize, numModY); + for (unsigned int iReadout = 0; iReadout < nTotalPorts; + ++iReadout) { + auto globalPortRoi = + GetGlobalPortRoi(iReadout, portSize, numModY); if (!globalPortRoi.overlap(currentRoi)) - continue; + continue; // calculate start location (special for roi) int xmin = std::max(currentRoi.xmin, globalPortRoi.xmin); int xmax = std::min(currentRoi.xmax, globalPortRoi.xmax); int ymin = std::max(currentRoi.ymin, globalPortRoi.ymin); int ymax = std::min(currentRoi.ymax, globalPortRoi.ymax); - hsize_t portRoiHeight = ymax - ymin + 1; - hsize_t portRoiWidth = xmax - xmin + 1; + hsize_t portRoiHeight = ymax - ymin + 1; + hsize_t portRoiWidth = xmax - xmin + 1; // recalculating start location and block size if (!gotthard25um) { @@ -338,11 +345,12 @@ std::string CreateVirtualHDF5File( blockSize[1] = portRoiHeight; blockSize[2] = portRoiWidth; } - // interleaving for g2 (startLocation is 0 and 1) (g2 had no roi) + // interleaving for g2 (startLocation is 0 and 1) (g2 had no + // roi) else { ++startLocation[2]; } - + vdsDataSpace.selectHyperslab( H5S_SELECT_SET, numBlocks, startLocation, strideBetweenBlocks, blockSize); @@ -369,13 +377,15 @@ std::string CreateVirtualHDF5File( } // source dataspace - hsize_t srcDims[DATA_RANK] = {nSrcFileImages, portRoiHeight, portRoiWidth}; - hsize_t srcDimsMax[DATA_RANK] = {H5S_UNLIMITED, portRoiHeight, - portRoiWidth}; + hsize_t srcDims[DATA_RANK] = {nSrcFileImages, portRoiHeight, + portRoiWidth}; + hsize_t srcDimsMax[DATA_RANK] = { + H5S_UNLIMITED, portRoiHeight, portRoiWidth}; H5::DataSpace srcDataSpace(DATA_RANK, srcDims, srcDimsMax); hsize_t srcDimsPara[PARA_RANK] = {nSrcFileImages}; hsize_t srcDimsMaxPara[PARA_RANK] = {H5S_UNLIMITED}; - H5::DataSpace srcDataSpacePara(PARA_RANK, srcDimsPara, srcDimsMaxPara); + H5::DataSpace srcDataSpacePara(PARA_RANK, srcDimsPara, + srcDimsMaxPara); // temporary fixfor corner case bug: // (framescaught not multiple of framesperfile, // virtual parameter datasets error loading (bad scalar diff --git a/slsReceiverSoftware/src/MasterFileUtility.h b/slsReceiverSoftware/src/MasterFileUtility.h index 51360da74..cbf68be39 100644 --- a/slsReceiverSoftware/src/MasterFileUtility.h +++ b/slsReceiverSoftware/src/MasterFileUtility.h @@ -21,7 +21,8 @@ std::string CreateMasterBinaryFile(const std::string &filePath, void LinkHDF5FileInMaster(std::string &masterFileName, std::string &dataFilename, std::vector parameterNames, - const bool silentMode, std::mutex *hdf5LibMutex, size_t multiRoiSize); + const bool silentMode, std::mutex *hdf5LibMutex, + size_t multiRoiSize); std::string CreateMasterHDF5File(const std::string &filePath, const std::string &fileNamePrefix, @@ -29,17 +30,18 @@ std::string CreateMasterHDF5File(const std::string &filePath, const bool overWriteEnable, const bool silentMode, MasterAttributes *attr, std::mutex *hdf5LibMutex); -defs::ROI GetGlobalPortRoi(const int iPort, const defs::xy portSize, const int numPortsY); +defs::ROI GetGlobalPortRoi(const int iPort, const defs::xy portSize, + const int numPortsY); int GetNumPortsInRoi(const defs::ROI roi, const defs::xy portSize); std::string CreateVirtualHDF5File( const std::string &filePath, const std::string &fileNamePrefix, const uint64_t fileIndex, const bool overWriteEnable, const bool silentMode, const int modulePos, const int numUnitsPerReadout, - const uint32_t maxFramesPerFile, const int nPixelsX, - const int nPixelsY, const uint32_t dynamicRange, - const uint64_t numImagesCaught, const int numModX, const int numModY, - const H5::DataType dataType, const std::vector parameterNames, + const uint32_t maxFramesPerFile, const int nPixelsX, const int nPixelsY, + const uint32_t dynamicRange, const uint64_t numImagesCaught, + const int numModX, const int numModY, const H5::DataType dataType, + const std::vector parameterNames, const std::vector parameterDataTypes, std::mutex *hdf5LibMutex, bool gotthard25um, std::vector multiRoi); diff --git a/slsSupportLib/include/sls/ToString.h b/slsSupportLib/include/sls/ToString.h index 71d9a1190..ea97a8436 100644 --- a/slsSupportLib/include/sls/ToString.h +++ b/slsSupportLib/include/sls/ToString.h @@ -349,5 +349,4 @@ std::vector StringTo(const std::vector &strings) { return result; } - } // namespace sls diff --git a/slsSupportLib/include/sls/sls_detector_defs.h b/slsSupportLib/include/sls/sls_detector_defs.h index 0f0a5dc0f..942774bbf 100644 --- a/slsSupportLib/include/sls/sls_detector_defs.h +++ b/slsSupportLib/include/sls/sls_detector_defs.h @@ -230,12 +230,8 @@ class slsDetectorDefs { ROI(int xmin, int xmax) : xmin(xmin), xmax(xmax){}; ROI(int xmin, int xmax, int ymin, int ymax) : xmin(xmin), xmax(xmax), ymin(ymin), ymax(ymax){}; - constexpr int width() const { - return (xmax - xmin + 1); - } - constexpr int height() const { - return (ymax - ymin + 1); - } + constexpr int width() const { return (xmax - xmin + 1); } + constexpr int height() const { return (ymax - ymin + 1); } constexpr std::array getIntArray() const { return std::array({xmin, xmax, ymin, ymax}); } @@ -252,7 +248,7 @@ class slsDetectorDefs { ymin = 0; ymax = 0; } - constexpr bool overlap(const ROI & other) const { + constexpr bool overlap(const ROI &other) const { return ((xmin <= other.xmax && xmax >= other.xmin) && (ymin <= other.ymax && ymax >= other.ymin)); } From ba02094c4efe2a9bd47fc86c8b58b169b14a222c Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Mon, 30 Jun 2025 14:43:17 +0200 Subject: [PATCH 28/49] updated python bindings --- python/src/detector.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/python/src/detector.cpp b/python/src/detector.cpp index 4a5ffc02c..c11e61167 100644 --- a/python/src/detector.cpp +++ b/python/src/detector.cpp @@ -109,6 +109,13 @@ void init_det(py::module &m) { (Result(Detector::*)(sls::Positions) const) & Detector::getModuleSize, py::arg() = Positions{}); + CppDetectorApi.def("getPortPerModuleGeometry", + (defs::xy(Detector::*)() const) & + Detector::getPortPerModuleGeometry); + CppDetectorApi.def("getPortSize", + (Result(Detector::*)(sls::Positions) const) & + Detector::getPortSize, + py::arg() = Positions{}); CppDetectorApi.def("getDetectorSize", (defs::xy(Detector::*)() const) & Detector::getDetectorSize); CppDetectorApi.def("setDetectorSize", @@ -924,6 +931,19 @@ void init_det(py::module &m) { (void (Detector::*)(bool, sls::Positions)) & Detector::setRxArping, py::arg(), py::arg() = Positions{}); + CppDetectorApi.def("getRxROI", + (std::vector(Detector::*)() const) & + Detector::getRxROI); + CppDetectorApi.def("getRxROI", + (std::vector(Detector::*)(int) const) & + Detector::getRxROI, + py::arg()); + CppDetectorApi.def("setRxROI", + (void (Detector::*)(const std::vector &)) & + Detector::setRxROI, + py::arg()); + CppDetectorApi.def("clearRxROI", + (void (Detector::*)()) & Detector::clearRxROI); CppDetectorApi.def( "getFileFormat", (Result(Detector::*)(sls::Positions) const) & From da3037a8ead508e51b384294bf3f016dc50966c9 Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Mon, 30 Jun 2025 16:38:54 +0200 Subject: [PATCH 29/49] updated master file versions --- slsReceiverSoftware/src/receiver_defs.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/slsReceiverSoftware/src/receiver_defs.h b/slsReceiverSoftware/src/receiver_defs.h index ade363e79..0d38ba749 100644 --- a/slsReceiverSoftware/src/receiver_defs.h +++ b/slsReceiverSoftware/src/receiver_defs.h @@ -19,8 +19,8 @@ namespace sls { // files // versions -#define HDF5_WRITER_VERSION (6.7) // 1 decimal places -#define BINARY_WRITER_VERSION (7.3) // 1 decimal places +#define HDF5_WRITER_VERSION (7.0) // 1 decimal places +#define BINARY_WRITER_VERSION (8.0) // 1 decimal places #define MAX_FRAMES_PER_FILE 20000 #define SHORT_MAX_FRAMES_PER_FILE 100000 From 5def4bdfc490087c6460f6ad506ef81e1abef4cb Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Mon, 30 Jun 2025 17:31:22 +0200 Subject: [PATCH 30/49] cmd generation and formatting --- .../autocomplete/bash_autocomplete.sh | 14 ------------- .../autocomplete/zsh_autocomplete.sh | 14 ------------- .../generator/extended_commands.yaml | 21 ++----------------- slsDetectorSoftware/src/inferAction.cpp | 18 ++-------------- 4 files changed, 4 insertions(+), 63 deletions(-) diff --git a/slsDetectorSoftware/generator/autocomplete/bash_autocomplete.sh b/slsDetectorSoftware/generator/autocomplete/bash_autocomplete.sh index 3ce858ee8..5fe099a7d 100644 --- a/slsDetectorSoftware/generator/autocomplete/bash_autocomplete.sh +++ b/slsDetectorSoftware/generator/autocomplete/bash_autocomplete.sh @@ -2193,20 +2193,6 @@ return 0 } __rx_roi() { FCN_RETURN="" -if [[ ${IS_GET} -eq 0 ]]; then -if [[ "${cword}" == "2" ]]; then -FCN_RETURN="" -fi -if [[ "${cword}" == "3" ]]; then -FCN_RETURN="" -fi -if [[ "${cword}" == "4" ]]; then -FCN_RETURN="" -fi -if [[ "${cword}" == "5" ]]; then -FCN_RETURN="" -fi -fi return 0 } __rx_silent() { diff --git a/slsDetectorSoftware/generator/autocomplete/zsh_autocomplete.sh b/slsDetectorSoftware/generator/autocomplete/zsh_autocomplete.sh index c59c1e4a3..64598dd2b 100644 --- a/slsDetectorSoftware/generator/autocomplete/zsh_autocomplete.sh +++ b/slsDetectorSoftware/generator/autocomplete/zsh_autocomplete.sh @@ -2117,20 +2117,6 @@ return 0 } __rx_roi() { FCN_RETURN="" -if [[ ${IS_GET} -eq 0 ]]; then -if [[ "${cword}" == "2" ]]; then -FCN_RETURN="" -fi -if [[ "${cword}" == "3" ]]; then -FCN_RETURN="" -fi -if [[ "${cword}" == "4" ]]; then -FCN_RETURN="" -fi -if [[ "${cword}" == "5" ]]; then -FCN_RETURN="" -fi -fi return 0 } __rx_silent() { diff --git a/slsDetectorSoftware/generator/extended_commands.yaml b/slsDetectorSoftware/generator/extended_commands.yaml index 6b9f72577..3a698f537 100644 --- a/slsDetectorSoftware/generator/extended_commands.yaml +++ b/slsDetectorSoftware/generator/extended_commands.yaml @@ -8831,25 +8831,8 @@ rx_roi: store_result_in_t: true PUT: args: - - arg_types: - - int - - int - argc: 2 - cast_input: [] - check_det_id: false - convert_det_id: true - function: '' - input: [] - input_types: [] - output: [] - require_det_id: false - store_result_in_t: false - - arg_types: - - int - - int - - int - - int - argc: 4 + - arg_types: [] + argc: -1 cast_input: [] check_det_id: false convert_det_id: true diff --git a/slsDetectorSoftware/src/inferAction.cpp b/slsDetectorSoftware/src/inferAction.cpp index 68c8638f1..7865cd692 100644 --- a/slsDetectorSoftware/src/inferAction.cpp +++ b/slsDetectorSoftware/src/inferAction.cpp @@ -2769,22 +2769,8 @@ int InferAction::rx_realudpsocksize() { int InferAction::rx_roi() { - if (args.size() == 0) { - return slsDetectorDefs::GET_ACTION; - } - - if (args.size() == 2) { - return slsDetectorDefs::PUT_ACTION; - } - - if (args.size() == 4) { - return slsDetectorDefs::PUT_ACTION; - } - - else { - - throw RuntimeError("Could not infer action: Wrong number of arguments"); - } + throw RuntimeError("sls_detector is disabled for command: rx_roi. Use " + "sls_detector_get or sls_detector_put"); } int InferAction::rx_silent() { From f42609b66f5d7d970528e8b423fabcabcc93b0ae Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Tue, 1 Jul 2025 12:30:41 +0200 Subject: [PATCH 31/49] minor fixes in command line and help --- slsDetectorSoftware/src/CallerSpecial.cpp | 57 ++++++++++++------- .../tests/Caller/test-Caller-rx.cpp | 23 ++++---- 2 files changed, 49 insertions(+), 31 deletions(-) diff --git a/slsDetectorSoftware/src/CallerSpecial.cpp b/slsDetectorSoftware/src/CallerSpecial.cpp index 7362af87d..174c51276 100644 --- a/slsDetectorSoftware/src/CallerSpecial.cpp +++ b/slsDetectorSoftware/src/CallerSpecial.cpp @@ -723,19 +723,30 @@ std::string Caller::rx_zmqip(int action) { std::string Caller::rx_roi(int action) { std::ostringstream os; std::string helpMessage = - std::string("[xmin] [xmax] [ymin] [ymax]\n\tRegion of interest in " - "receiver.\n\t") + - "For a list of rois, use '[' and ']; ' to distinguish between " - "rois and use comma inside the square brackets.\n\t If one fails to " - "use space after semicolon, please use quotes" + - "For example: [0,100,0,100]; [200,300,0,100] will set two " - "rois.or '[0,100,0,100];[200,300,0,100]' when the vector is a single " - "string\n\n\t" + - "Only allowed to set at multi module level and without gap " - "ixels.\n\n\t" + - "One can get rx_roi also at port level, by specifying the module id " - "and it will return the roi for each port.\n" - "Setting number of udp interfaces will clear the rx_roi\n"; + std::string("[xmin] [xmax] [ymin] [ymax]\n") + + "\tDefines a single region of interest (ROI) in the receiver.\n" + "\tFor example, to set a single ROI: 0 100 20 30\n\n" + + "\tTo specify multiple ROIs, use square brackets between ROIs and " + "commas inside for each ROI. \n" + "\tInside each bracket, no spaces allowed.\n\n" + + "\tIf you use semicolon (along with '['and ']' to separate rois), \n" + "\tenclose the entire list in quotes.\n" + "\tExamples:\n" + "\t [0,100,0,100] [200,300,0,100]\n" + "\t \"[0,100,0,100];[200,300,0,100]\"\n\n" + + "\tNotes:\n" + "\t- ROIs can only be set at the multi-module level.\n" + "\t- ROIs coordinates assume no gap pixels, even if they are enabled " + "in gui.\n" + "\t- To retrieve ROIs per port, specify the module ID when using the " + "get command.\n" + "\t- Use the command 'rx_clearroi' to clear all ROIs.\n" + "\t- Changing the number of UDP interfaces will automatically clear " + "the current ROIs.\n"; + if (action == defs::HELP_ACTION) { os << helpMessage; } else if (action == defs::GET_ACTION) { @@ -751,9 +762,8 @@ std::string Caller::rx_roi(int action) { } } else if (action == defs::PUT_ACTION) { std::vector rois; - // Support multiple args with bracketed ROIs, or single arg with - // semicolon-separated vector + // semicolon-separated vector in quotes bool isVectorInput = std::all_of(args.begin(), args.end(), [](const std::string &a) { return a.find('[') != std::string::npos && @@ -781,7 +791,9 @@ std::string Caller::rx_roi(int action) { } } } catch (const std::exception &e) { - throw RuntimeError("Could not parse ROI: " + helpMessage); + throw RuntimeError("Could not parse ROI: Did you use spaces inside " + "the brackets? Use sls_detector_help " + + cmd + " to get the right syntax expected."); } // only multi level @@ -802,16 +814,19 @@ std::vector Caller::parseRoiVector(const std::string &input) { std::stringstream ss(input); std::string token; - while (std::getline(ss, token, ';')) { - token.erase(std::remove_if(token.begin(), token.end(), ::isspace), - token.end()); + while (std::getline(ss, token, ']')) { + // remove spaces and semicolons + token.erase( + std::remove_if(token.begin(), token.end(), + [](char c) { return std::isspace(c) || c == ';'; }), + token.end()); if (token.empty()) continue; - if (token.front() != '[' || token.back() != ']') { + if (token.front() != '[') { throw RuntimeError("Each ROI must be enclosed in square brackets: " "[xmin,xmax,ymin,ymax]"); } - token = token.substr(1, token.size() - 2); // remove brackets + token = token.substr(1, token.size() - 1); // remove brackets std::vector parts; std::stringstream inner(token); std::string num; diff --git a/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp b/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp index df9edbacd..387f72b56 100644 --- a/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp +++ b/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp @@ -507,13 +507,13 @@ TEST_CASE("rx_roi", "[.cmdcall]") { // vector of rois // square brackets missing REQUIRE_THROWS(caller.call( - "rx_roi", {"[5, 20, -1, -1; 25, 30, -1, -1]"}, -1, PUT)); + "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)); + "rx_roi", {"[5, 20, -1] [25, 30, -1, -1]"}, -1, PUT)); // overlapping rois REQUIRE_THROWS(caller.call( - "rx_roi", {"[0, 10,-1, -1];[5, 15, -1, -1]"}, -1, PUT)); + "rx_roi", {"[0, 10,-1, -1] [5, 15, -1, -1]"}, -1, PUT)); if (det.size() == 2) { auto moduleSize = det.getModuleSize()[0]; @@ -527,7 +527,8 @@ TEST_CASE("rx_roi", "[.cmdcall]") { "[" + stringMin + ", " + stringMax + ", -1, -1]"}, -1, PUT)); std::ostringstream oss; - // separated by semicolon is allowed + // separated by semicolon with quotes is allowed (skips + // cmdParser) REQUIRE_NOTHROW(caller.call("rx_roi", {"[5, 10, -1, -1];[" + stringMin + ", " + stringMax + ", -1, -1]"}, @@ -598,15 +599,15 @@ TEST_CASE("rx_roi", "[.cmdcall]") { // vector of rois // square brackets missing REQUIRE_THROWS(caller.call( - "rx_roi", {"[5, 20, 20, 30; 25, 30, 14, 15]"}, -1, PUT)); + "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)); + "rx_roi", {"[5, 20, 20] [25, 30, 14, 15]"}, -1, PUT)); // overlapping rois REQUIRE_THROWS(caller.call( - "rx_roi", {"[0, 10, 0, 10];[5, 15, 0, 10]"}, -1, PUT)); + "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)); + "rx_roi", {"[0, 10, 0, 10] [0, 10, 9, 11]"}, -1, PUT)); int numinterfaces = det.getNumberofUDPInterfaces().tsquash( "inconsistent number of interfaces"); @@ -624,7 +625,8 @@ TEST_CASE("rx_roi", "[.cmdcall]") { "[" + stringMin + ", " + stringMax + ", 20, 30]"}, -1, PUT)); std::ostringstream oss; - // separated by semicolon is allowed + // separated by semicolon with quotes is allowed (skips + // cmdParser) REQUIRE_NOTHROW(caller.call("rx_roi", {"[5, 10, 20, 30];[" + stringMin + ", " + stringMax + ", 20, 30]"}, @@ -676,7 +678,8 @@ TEST_CASE("rx_roi", "[.cmdcall]") { ", " + stringMax + "]"}, -1, PUT)); std::ostringstream oss; - // separated by semicolon is allowed + // separated by semicolon is allowed with quotes (skips + // cmdParser) REQUIRE_NOTHROW( caller.call("rx_roi", {"[5, 10, 20, 30];[25, 28, " + stringMin + From e274524c5548fd678fa28957e14a1cfde534764c Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Tue, 1 Jul 2025 14:55:40 +0200 Subject: [PATCH 32/49] minor --- slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp | 8 ++++++-- slsReceiverSoftware/src/DataProcessor.cpp | 4 ---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp b/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp index 387f72b56..76462e3c4 100644 --- a/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp +++ b/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp @@ -507,7 +507,9 @@ TEST_CASE("rx_roi", "[.cmdcall]") { // vector of rois // square brackets missing REQUIRE_THROWS(caller.call( - "rx_roi", {"[5, 20, -1, -1] 25, 30, -1, -1]"}, -1, PUT)); + "rx_roi", {"[5, 20, -1, -1]; 25, 30, -1, -1]"}, -1, PUT)); + 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)); @@ -599,7 +601,9 @@ TEST_CASE("rx_roi", "[.cmdcall]") { // vector of rois // square brackets missing REQUIRE_THROWS(caller.call( - "rx_roi", {"[5, 20, 20, 30] 25, 30, 14, 15]"}, -1, PUT)); + "rx_roi", {"[5, 20, 20, 30]; 25, 30, 14, 15]"}, -1, PUT)); + 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)); diff --git a/slsReceiverSoftware/src/DataProcessor.cpp b/slsReceiverSoftware/src/DataProcessor.cpp index a863e39d5..47e2b3d17 100644 --- a/slsReceiverSoftware/src/DataProcessor.cpp +++ b/slsReceiverSoftware/src/DataProcessor.cpp @@ -238,10 +238,6 @@ void DataProcessor::LinkFileInMaster(const std::string &masterFileName, const bool silentMode, std::mutex *hdf5LibMutex) { - /*if (!multiRoiMetadata.empty()) { - throw std::runtime_error( - "Should not be here, roi with hdf5 virtual should throw."); - }*/ std::string fname{virtualFileName}, masterfname{masterFileName}; // if no virtual file, link data file if (virtualFileName.empty()) { From 98d0612314c7c2e0e1284e110816d0a06ec089df Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Tue, 1 Jul 2025 15:03:33 +0200 Subject: [PATCH 33/49] doesnt happen anymore --- slsReceiverSoftware/src/MasterFileUtility.cpp | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/slsReceiverSoftware/src/MasterFileUtility.cpp b/slsReceiverSoftware/src/MasterFileUtility.cpp index b05ec579f..1477b91fd 100644 --- a/slsReceiverSoftware/src/MasterFileUtility.cpp +++ b/slsReceiverSoftware/src/MasterFileUtility.cpp @@ -386,18 +386,6 @@ std::string CreateVirtualHDF5File( hsize_t srcDimsMaxPara[PARA_RANK] = {H5S_UNLIMITED}; H5::DataSpace srcDataSpacePara(PARA_RANK, srcDimsPara, srcDimsMaxPara); - // temporary fixfor corner case bug: - // (framescaught not multiple of framesperfile, - // virtual parameter datasets error loading (bad scalar - // value)) - // TODO WHY???? - /*if (nDimz != maxFramesPerFile) { - hsize_t count[1] = {nDimz}; - hsize_t start[1] = {0}; - srcDataSpacePara.selectHyperslab( - H5S_SELECT_SET, count, start, - strideBetweenBlocksPara, blockSizePara); - }*/ // mapping of property list plist.setVirtual(vdsDataSpace, relative_srcFileName.c_str(), From cd06ea1e31b1e9d59bbba5a34f75e145a06812a8 Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Tue, 1 Jul 2025 15:07:52 +0200 Subject: [PATCH 34/49] comment --- slsDetectorGui/src/qDrawPlot.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/slsDetectorGui/src/qDrawPlot.cpp b/slsDetectorGui/src/qDrawPlot.cpp index 0eb8e2e11..e967862a3 100644 --- a/slsDetectorGui/src/qDrawPlot.cpp +++ b/slsDetectorGui/src/qDrawPlot.cpp @@ -639,7 +639,8 @@ void qDrawPlot::UpdateROI() { // roi enabled if (roi.size() > 1 || !roi[0].completeRoi()) { hasRoi = true; - // update gap pixels (gap pixels only for 2d) + // update gap pixels + // hardcoded gap pixels because only for eiger and jungfrau if (isGapPixels) { for (auto &r : roi) { r.xmin += ((r.xmin / 1024) * 6 + (r.xmin / 256) * 2); From 36ed20117d22e0fc9c8d0c50d66999c0f0bb1acf Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Tue, 1 Jul 2025 15:33:30 +0200 Subject: [PATCH 35/49] minor --- slsDetectorSoftware/include/sls/Detector.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/slsDetectorSoftware/include/sls/Detector.h b/slsDetectorSoftware/include/sls/Detector.h index 90f2cd6ac..5acd767c8 100644 --- a/slsDetectorSoftware/include/sls/Detector.h +++ b/slsDetectorSoftware/include/sls/Detector.h @@ -996,8 +996,9 @@ class Detector { * readout */ std::vector getRxROI(int module_id) const; - /** only at multi module level without gap pixels. At most, 1 ROI per UDP - * port. Setting number of udp interfaces will clear the roi */ + /** only at multi module level without gap pixels. If more than 1 ROI per + * UDP port, it will throw. Setting number of udp interfaces will clear the + * roi */ void setRxROI(const std::vector &args); void clearRxROI(); From 274a338520e4b195be8c07d2e104c7e24491e767 Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Tue, 1 Jul 2025 16:58:27 +0200 Subject: [PATCH 36/49] redundant getRxROI in Detector class for multi level and module level --- slsDetectorSoftware/include/sls/Detector.h | 9 +++------ slsDetectorSoftware/src/Detector.cpp | 2 -- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/slsDetectorSoftware/include/sls/Detector.h b/slsDetectorSoftware/include/sls/Detector.h index 5acd767c8..ef4b9c251 100644 --- a/slsDetectorSoftware/include/sls/Detector.h +++ b/slsDetectorSoftware/include/sls/Detector.h @@ -989,12 +989,9 @@ class Detector { * every minute. Useful in 10G mode. */ void setRxArping(bool value, Positions pos = {}); - /** Returns multi level ROIs */ - std::vector getRxROI() const; - - /** Returns port level ROIs. Max 2 ports and hence max 2 elements per - * readout */ - std::vector getRxROI(int module_id) const; + /** If module_id is -1, returns multi level ROIs. Else it returns port + * level ROIs. Max 2 ports and hence max 2 elements per readout */ + std::vector getRxROI(int module_id = -1) const; /** only at multi module level without gap pixels. If more than 1 ROI per * UDP port, it will throw. Setting number of udp interfaces will clear the diff --git a/slsDetectorSoftware/src/Detector.cpp b/slsDetectorSoftware/src/Detector.cpp index 06e44a308..cb7e33018 100644 --- a/slsDetectorSoftware/src/Detector.cpp +++ b/slsDetectorSoftware/src/Detector.cpp @@ -1383,8 +1383,6 @@ void Detector::setRxArping(bool value, Positions pos) { pimpl->Parallel(&Module::setRxArping, pos, value); } -std::vector Detector::getRxROI() const { return pimpl->getRxROI(); } - std::vector Detector::getRxROI(int module_id) const { return pimpl->getRxROI(module_id); } From f8a06d78f31837f316b117461b675400b530b90c Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Tue, 1 Jul 2025 17:00:59 +0200 Subject: [PATCH 37/49] refactor cmd parsing (detid can be parsed directly) --- slsDetectorSoftware/src/CallerSpecial.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/slsDetectorSoftware/src/CallerSpecial.cpp b/slsDetectorSoftware/src/CallerSpecial.cpp index 174c51276..10330f1b6 100644 --- a/slsDetectorSoftware/src/CallerSpecial.cpp +++ b/slsDetectorSoftware/src/CallerSpecial.cpp @@ -753,13 +753,8 @@ std::string Caller::rx_roi(int action) { if (!args.empty()) { WrongNumberOfParameters(0); } - if (det_id != -1) { - auto t = det->getRxROI(det_id); - os << ToString(t) << '\n'; - } else { - auto t = det->getRxROI(); - os << ToString(t) << '\n'; - } + auto t = det->getRxROI(det_id); + os << ToString(t) << '\n'; } else if (action == defs::PUT_ACTION) { std::vector rois; // Support multiple args with bracketed ROIs, or single arg with From a28c78c47ffde2787d2f180c8e9a8b0de74f8bae Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Tue, 1 Jul 2025 17:13:59 +0200 Subject: [PATCH 38/49] refactor cmd line --- slsDetectorSoftware/src/CallerSpecial.cpp | 48 ++++++++++++----------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/slsDetectorSoftware/src/CallerSpecial.cpp b/slsDetectorSoftware/src/CallerSpecial.cpp index 10330f1b6..5b9426ceb 100644 --- a/slsDetectorSoftware/src/CallerSpecial.cpp +++ b/slsDetectorSoftware/src/CallerSpecial.cpp @@ -756,7 +756,9 @@ std::string Caller::rx_roi(int action) { auto t = det->getRxROI(det_id); os << ToString(t) << '\n'; } else if (action == defs::PUT_ACTION) { - std::vector rois; + if (det_id != -1) { + throw RuntimeError("Cannot set receiver ROI at module level"); + } // Support multiple args with bracketed ROIs, or single arg with // semicolon-separated vector in quotes bool isVectorInput = @@ -764,25 +766,30 @@ std::string Caller::rx_roi(int action) { return a.find('[') != std::string::npos && a.find(']') != std::string::npos; }); + std::vector rois; try { - // previous format: 2 or 4 separate args - if ((args.size() == 2 || args.size() == 4) && !isVectorInput) { - defs::ROI t; - t.xmin = StringTo(args[0]); - t.xmax = StringTo(args[1]); - if (args.size() == 4) { - t.ymin = StringTo(args[2]); - t.ymax = StringTo(args[3]); - } - rois.emplace_back(t); - } else { - if (!isVectorInput) - WrongNumberOfParameters(2); - else { - for (const auto &arg : args) { - auto subRois = parseRoiVector(arg); - rois.insert(rois.end(), subRois.begin(), subRois.end()); + // single roi in previous format: [xmin,xmax,ymin,ymax] + if (!isVectorInput) { + if (args.size() == 2 || args.size() == 4) { + defs::ROI t; + t.xmin = StringTo(args[0]); + t.xmax = StringTo(args[1]); + if (args.size() == 4) { + t.ymin = StringTo(args[2]); + t.ymax = StringTo(args[3]); } + rois.emplace_back(t); + } else { + WrongNumberOfParameters(2); + } + } + // multiple roi or single roi with brackets + // multiple roi: multiple args with bracketed ROIs, or single arg + // with semicolon-bracketed Rois in quotes + else { + for (const auto &arg : args) { + auto subRois = parseRoiVector(arg); + rois.insert(rois.end(), subRois.begin(), subRois.end()); } } } catch (const std::exception &e) { @@ -791,11 +798,6 @@ std::string Caller::rx_roi(int action) { cmd + " to get the right syntax expected."); } - // only multi level - if (det_id != -1) { - throw RuntimeError("Cannot execute receiver ROI at module level"); - } - det->setRxROI(rois); os << ToString(rois) << '\n'; } else { From 929e441dc60abf2971bac4a6b4a0da2f5223d0a7 Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Tue, 1 Jul 2025 17:31:49 +0200 Subject: [PATCH 39/49] refactor command line parsing of roi --- slsDetectorSoftware/generator/Caller.in.h | 1 + slsDetectorSoftware/src/Caller.h | 1 + slsDetectorSoftware/src/CallerSpecial.cpp | 42 ++++++++++------------- 3 files changed, 21 insertions(+), 23 deletions(-) diff --git a/slsDetectorSoftware/generator/Caller.in.h b/slsDetectorSoftware/generator/Caller.in.h index de91b2abc..715922dfb 100644 --- a/slsDetectorSoftware/generator/Caller.in.h +++ b/slsDetectorSoftware/generator/Caller.in.h @@ -22,6 +22,7 @@ class Caller { int GetLevelAndInsertIntoArgs(std::string levelSeparatedCommand); void WrongNumberOfParameters(size_t expected); std::vector parseRoiVector(const std::string &input); + defs::ROI parseRoi(const std::vector &args); template std::string OutStringHex(const V &value) { if (value.equal()) diff --git a/slsDetectorSoftware/src/Caller.h b/slsDetectorSoftware/src/Caller.h index 5a667938f..068aca94c 100644 --- a/slsDetectorSoftware/src/Caller.h +++ b/slsDetectorSoftware/src/Caller.h @@ -22,6 +22,7 @@ class Caller { int GetLevelAndInsertIntoArgs(std::string levelSeparatedCommand); void WrongNumberOfParameters(size_t expected); std::vector parseRoiVector(const std::string &input); + defs::ROI parseRoi(const std::vector &args); template std::string OutStringHex(const V &value) { if (value.equal()) diff --git a/slsDetectorSoftware/src/CallerSpecial.cpp b/slsDetectorSoftware/src/CallerSpecial.cpp index 5b9426ceb..f7c08a5bd 100644 --- a/slsDetectorSoftware/src/CallerSpecial.cpp +++ b/slsDetectorSoftware/src/CallerSpecial.cpp @@ -770,18 +770,8 @@ std::string Caller::rx_roi(int action) { try { // single roi in previous format: [xmin,xmax,ymin,ymax] if (!isVectorInput) { - if (args.size() == 2 || args.size() == 4) { - defs::ROI t; - t.xmin = StringTo(args[0]); - t.xmax = StringTo(args[1]); - if (args.size() == 4) { - t.ymin = StringTo(args[2]); - t.ymax = StringTo(args[3]); - } - rois.emplace_back(t); - } else { - WrongNumberOfParameters(2); - } + auto t = parseRoi(args); + rois.emplace_back(t); } // multiple roi or single roi with brackets // multiple roi: multiple args with bracketed ROIs, or single arg @@ -831,22 +821,28 @@ std::vector Caller::parseRoiVector(const std::string &input) { parts.push_back(num); } - if (parts.size() != 2 && parts.size() != 4) { - throw RuntimeError("ROI must have 2 or 4 comma-separated integers"); - } - - defs::ROI roi; - roi.xmin = StringTo(parts[0]); - roi.xmax = StringTo(parts[1]); - if (parts.size() == 4) { - roi.ymin = StringTo(parts[2]); - roi.ymax = StringTo(parts[3]); - } + auto roi = parseRoi(parts); rois.emplace_back(roi); } return rois; } +defs::ROI Caller::parseRoi(const std::vector &parts) { + if (parts.size() != 2 && parts.size() != 4) { + throw RuntimeError( + "Could not parse ROI. A ROI must have 2 or 4 integers"); + } + + defs::ROI roi; + roi.xmin = StringTo(parts[0]); + roi.xmax = StringTo(parts[1]); + if (parts.size() == 4) { + roi.ymin = StringTo(parts[2]); + roi.ymax = StringTo(parts[3]); + } + return roi; +} + std::string Caller::ratecorr(int action) { std::ostringstream os; if (action == defs::HELP_ACTION) { From 92fd3f060902b4eb16483ccee712e68afd35a181 Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Tue, 1 Jul 2025 17:34:40 +0200 Subject: [PATCH 40/49] modified comments about ctb and xilinx not using roi --- slsDetectorSoftware/include/sls/Detector.h | 2 +- slsDetectorSoftware/src/CallerSpecial.cpp | 3 ++- slsDetectorSoftware/src/Detector.cpp | 1 - 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/slsDetectorSoftware/include/sls/Detector.h b/slsDetectorSoftware/include/sls/Detector.h index ef4b9c251..743c80b77 100644 --- a/slsDetectorSoftware/include/sls/Detector.h +++ b/slsDetectorSoftware/include/sls/Detector.h @@ -995,7 +995,7 @@ class Detector { /** only at multi module level without gap pixels. If more than 1 ROI per * UDP port, it will throw. Setting number of udp interfaces will clear the - * roi */ + * roi. Cannot be set for CTB or Xilinx CTB */ void setRxROI(const std::vector &args); void clearRxROI(); diff --git a/slsDetectorSoftware/src/CallerSpecial.cpp b/slsDetectorSoftware/src/CallerSpecial.cpp index f7c08a5bd..7ff78d8ef 100644 --- a/slsDetectorSoftware/src/CallerSpecial.cpp +++ b/slsDetectorSoftware/src/CallerSpecial.cpp @@ -745,7 +745,8 @@ std::string Caller::rx_roi(int action) { "get command.\n" "\t- Use the command 'rx_clearroi' to clear all ROIs.\n" "\t- Changing the number of UDP interfaces will automatically clear " - "the current ROIs.\n"; + "the current ROIs.\n\n" + "\t- Cannot be set for CTB or Xilinx CTB.\n"; if (action == defs::HELP_ACTION) { os << helpMessage; diff --git a/slsDetectorSoftware/src/Detector.cpp b/slsDetectorSoftware/src/Detector.cpp index cb7e33018..14a6d7cc0 100644 --- a/slsDetectorSoftware/src/Detector.cpp +++ b/slsDetectorSoftware/src/Detector.cpp @@ -1387,7 +1387,6 @@ std::vector Detector::getRxROI(int module_id) const { return pimpl->getRxROI(module_id); } -// RxROIs can be set for all types except CTB. At multi level without gap pixels void Detector::setRxROI(const std::vector &args) { pimpl->setRxROI(args); } From 6c4c60ca712323cc27c0c8c390251e85fe456824 Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Wed, 2 Jul 2025 14:08:00 +0200 Subject: [PATCH 41/49] refactoring --- slsDetectorSoftware/src/Detector.cpp | 9 +++--- slsDetectorSoftware/src/DetectorImpl.cpp | 36 ++++++++---------------- 2 files changed, 17 insertions(+), 28 deletions(-) diff --git a/slsDetectorSoftware/src/Detector.cpp b/slsDetectorSoftware/src/Detector.cpp index b2d70937c..c8b3b1026 100644 --- a/slsDetectorSoftware/src/Detector.cpp +++ b/slsDetectorSoftware/src/Detector.cpp @@ -208,11 +208,12 @@ defs::xy Detector::getPortPerModuleGeometry() const { Result Detector::getPortSize(Positions pos) const { Result res = pimpl->Parallel(&Module::getNumberOfChannels, pos); defs::xy portGeometry = getPortPerModuleGeometry(); + if ((portGeometry.x != 1 && portGeometry.x != 2) || (portGeometry.y != 1 && portGeometry.y != 2)) { + throw RuntimeError("Port size is not 1 or 2 in either dimension. Port geometry:" + ToString(portGeometry)); + } for (auto &it : res) { - if (portGeometry.x == 2) - it.x /= 2; - if (portGeometry.y == 2) - it.y /= 2; + it.x /= portGeometry.x; + it.y /= portGeometry.y; } return res; } diff --git a/slsDetectorSoftware/src/DetectorImpl.cpp b/slsDetectorSoftware/src/DetectorImpl.cpp index 35e0b4dd8..1abaab8c2 100644 --- a/slsDetectorSoftware/src/DetectorImpl.cpp +++ b/slsDetectorSoftware/src/DetectorImpl.cpp @@ -1777,28 +1777,28 @@ 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; + const defs::xy portGeometry = getPortGeometry(); + const int numPortsPerModule = portGeometry.x * portGeometry.y; - if (numPorts > 2) { + if (numPortsPerModule > 2) { throw RuntimeError("Only up to 2 ports per module supported."); } - if (numPorts != (int)portRois.size()) { + if (numPortsPerModule != (int)portRois.size()) { throw RuntimeError("Number of port ROIs does not match number of ports in module. Expected: " + - std::to_string(numPorts) + ", got: " + + std::to_string(numPortsPerModule) + ", got: " + std::to_string(portRois.size())); } - for (int port = 0; port < numPorts; ++port) { + for (int port = 0; port != numPortsPerModule; ++port) { defs::ROI portRoi = moduleRoi; - // Calculate port ROI boundaries (split vertically or horizontally) - if (geometry.x == 2) { + // Recalculate port ROI boundaries (split vertically or horizontally) + if (portGeometry.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) { + } else if (portGeometry.y == 2) { int midY = (moduleRoi.ymin + moduleRoi.ymax) / 2; if (port == 0) portRoi.ymax = midY; @@ -1806,22 +1806,18 @@ void DetectorImpl::convertGlobalRoiToPortLevel( portRoi.ymin = midY + 1; } - // Check if user ROI overlaps with port + // find overlapped roi (port vs user roi) if (userRoi.overlap(portRoi)) { defs::ROI clipped{}; // Clip user ROI to port ROI clipped.xmin = std::max(userRoi.xmin, portRoi.xmin) - portRoi.xmin; clipped.xmax = std::min(userRoi.xmax, portRoi.xmax) - portRoi.xmin; - LOG(logDEBUG1) << "User ROI: " << ToString(userRoi) - << ", Port ROI: " << ToString(portRoi) << " clipped roi:"<< ToString(clipped); if (modSize.y > 1) { clipped.ymin = std::max(userRoi.ymin, portRoi.ymin) - portRoi.ymin; clipped.ymax = std::min(userRoi.ymax, portRoi.ymax) - portRoi.ymin; } - LOG(logDEBUG1) << "Clipped ROI for port " << port - << ": " << ToString(clipped); - // Check if port ROI already exists for this port + // Check if port ROI already exists for this port (from another user roi) if (!portRois[port].completeRoi() && !portRois[port].noRoi()) { throw RuntimeError( "Multiple ROIs specified for the same port " + @@ -1851,9 +1847,6 @@ void DetectorImpl::setRxROI(const std::vector &args) { for (size_t iModule = 0; iModule < modules.size(); ++iModule) { auto moduleGlobalRoi = getModuleROI(iModule); - LOG(logDEBUG1) << "Module " << iModule - << " Global ROI: " << ToString(moduleGlobalRoi); - // at most 2 rois per module (for each port) std::vector portRois(nPortsPerModule); @@ -1863,12 +1856,7 @@ void DetectorImpl::setRxROI(const std::vector &args) { convertGlobalRoiToPortLevel(arg, moduleGlobalRoi, portRois); } } - // print the rois for debugging - LOG(logDEBUG1) << "Module " << iModule << " RxROIs:"; - for (size_t iPort = 0; iPort != portRois.size(); iPort++) { - LOG(logDEBUG1) - << " Port " << iPort << ": " << ToString(portRois[iPort]); - } + modules[iModule]->setRxROI(portRois); } // metadata From 67042e831505d3c5a0bcf004b7c103bc25fcd63c Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Wed, 2 Jul 2025 18:11:19 +0200 Subject: [PATCH 42/49] refactorign --- slsReceiverSoftware/src/DataProcessor.cpp | 2 +- slsReceiverSoftware/src/Implementation.cpp | 25 +++++----- slsReceiverSoftware/src/Implementation.h | 1 + slsReceiverSoftware/src/MasterAttributes.cpp | 51 ++++++-------------- slsReceiverSoftware/src/MasterAttributes.h | 2 + 5 files changed, 31 insertions(+), 50 deletions(-) diff --git a/slsReceiverSoftware/src/DataProcessor.cpp b/slsReceiverSoftware/src/DataProcessor.cpp index 47e2b3d17..f7e4afb43 100644 --- a/slsReceiverSoftware/src/DataProcessor.cpp +++ b/slsReceiverSoftware/src/DataProcessor.cpp @@ -210,7 +210,7 @@ std::string DataProcessor::CreateVirtualFile( int ny = generalData->nPixelsY; if (generalData->dynamicRange == 4) - ny = generalData->nPixelsY / 2; + ny /= 2; bool gotthard25um = ((generalData->detType == GOTTHARD || generalData->detType == GOTTHARD2) && (numModX * numModY) == 2); diff --git a/slsReceiverSoftware/src/Implementation.cpp b/slsReceiverSoftware/src/Implementation.cpp index 1c974063d..c6943886e 100644 --- a/slsReceiverSoftware/src/Implementation.cpp +++ b/slsReceiverSoftware/src/Implementation.cpp @@ -156,11 +156,7 @@ void Implementation::setDetectorType(const detectorType d) { } if (d == EIGER) { - // resets ROIs and sets size to 2 - std::vector rois(2); - std::vector multiRoi(1); - setPortROIs(rois); - setMultiROIMetadata(multiRoi); + ResetRois(); } SetLocalNetworkParameters(); @@ -409,6 +405,15 @@ std::vector Implementation::getPortROIs() const { return portRois; } +void Implementation::ResetRois() { + int numports = generalData->numUDPInterfaces; + std::vector rois(numports); + std::vector multiRoi(1); + setPortROIs(rois); + setMultiROIMetadata(multiRoi); +} + + void Implementation::setPortROIs(const std::vector &args) { int nx = static_cast(generalData->nPixelsX); int ny = static_cast(generalData->nPixelsY); @@ -432,8 +437,6 @@ void Implementation::setPortROIs(const std::vector &args) { for (size_t i = 0; i != dataProcessor.size(); ++i) { dataProcessor[i]->SetPortROI(portRois[i]); } - if (dataProcessor.size() > 0) - dataProcessor[0]->setMultiROIMetadata(multiRoiMetadata); for (size_t i = 0; i != dataStreamer.size(); ++i) { dataStreamer[i]->SetPortROI(portRois[i]); } @@ -1040,8 +1043,6 @@ int Implementation::getNumberofUDPInterfaces() const { // not Eiger void Implementation::setNumberofUDPInterfaces(const int n) { - LOG(logDEBUG) << "Setting Number of UDP Interfaces: " << n; - if (generalData->detType == EIGER) { throw RuntimeError("Cannot set number of UDP interfaces for Eiger"); } @@ -1060,11 +1061,7 @@ void Implementation::setNumberofUDPInterfaces(const int n) { // fifo SetupFifoStructure(); - // roi cleared - complete detector and sets roi vector size - std::vector rois(n); - std::vector multiRoi(1); - setPortROIs(rois); - setMultiROIMetadata(multiRoi); + ResetRois(); // create threads for (int i = 0; i < generalData->numUDPInterfaces; ++i) { diff --git a/slsReceiverSoftware/src/Implementation.h b/slsReceiverSoftware/src/Implementation.h index e83539304..5764a8d09 100644 --- a/slsReceiverSoftware/src/Implementation.h +++ b/slsReceiverSoftware/src/Implementation.h @@ -284,6 +284,7 @@ class Implementation : private virtual slsDetectorDefs { void SetupFifoStructure(); const xy GetPortGeometry() const; + void ResetRois(); void ResetParametersforNewAcquisition(); void CreateUDPSockets(); void SetupWriter(); diff --git a/slsReceiverSoftware/src/MasterAttributes.cpp b/slsReceiverSoftware/src/MasterAttributes.cpp index 9eb2bd3a7..e6ecd12e4 100644 --- a/slsReceiverSoftware/src/MasterAttributes.cpp +++ b/slsReceiverSoftware/src/MasterAttributes.cpp @@ -154,6 +154,17 @@ void MasterAttributes::GetFinalBinaryAttributes( w->EndObject(); } +void MasterAttributes::GetBinaryRois( + rapidjson::PrettyWriter *w) { + w->Key("Receiver Rois"); + w->StartArray(); + for (const slsDetectorDefs::ROI &roi : rois) { + std::string roi_str = ToString(roi); + w->String(roi_str.c_str()); + } + w->EndArray(); +} + #ifdef HDF5C void MasterAttributes::WriteCommonHDF5Attributes(H5::H5File *fd, H5::Group *group) { @@ -555,13 +566,7 @@ void MasterAttributes::WriteHDF5TransceiverSamples(H5::Group *group) { void MasterAttributes::GetJungfrauBinaryAttributes( rapidjson::PrettyWriter *w) { - w->Key("Receiver Rois"); - w->StartArray(); - for (const slsDetectorDefs::ROI &roi : rois) { - std::string roi_str = ToString(roi); - w->String(roi_str.c_str()); - } - w->EndArray(); + GetBinaryRois(w); w->Key("Exptime"); w->String(ToString(exptime).c_str()); w->Key("Period"); @@ -584,13 +589,7 @@ void MasterAttributes::WriteJungfrauHDF5Attributes(H5::Group *group) { void MasterAttributes::GetMoenchBinaryAttributes( rapidjson::PrettyWriter *w) { - w->Key("Receiver Rois"); - w->StartArray(); - for (const slsDetectorDefs::ROI &roi : rois) { - std::string roi_str = ToString(roi); - w->String(roi_str.c_str()); - } - w->EndArray(); + GetBinaryRois(w); w->Key("Exptime"); w->String(ToString(exptime).c_str()); w->Key("Period"); @@ -613,13 +612,7 @@ void MasterAttributes::WriteMoenchHDF5Attributes(H5::Group *group) { void MasterAttributes::GetEigerBinaryAttributes( rapidjson::PrettyWriter *w) { - w->Key("Receiver Rois"); - w->StartArray(); - for (const slsDetectorDefs::ROI &roi : rois) { - std::string roi_str = ToString(roi); - w->String(roi_str.c_str()); - } - w->EndArray(); + GetBinaryRois(w); w->Key("Dynamic Range"); w->Uint(dynamicRange); w->Key("Ten Giga"); @@ -660,13 +653,7 @@ void MasterAttributes::WriteEigerHDF5Attributes(H5::Group *group) { void MasterAttributes::GetMythen3BinaryAttributes( rapidjson::PrettyWriter *w) { - w->Key("Receiver Rois"); - w->StartArray(); - for (const slsDetectorDefs::ROI &roi : rois) { - std::string roi_str = ToString(roi); - w->String(roi_str.c_str()); - } - w->EndArray(); + GetBinaryRois(w); w->Key("Dynamic Range"); w->Uint(dynamicRange); w->Key("Ten Giga"); @@ -705,13 +692,7 @@ void MasterAttributes::WriteMythen3HDF5Attributes(H5::Group *group) { void MasterAttributes::GetGotthard2BinaryAttributes( rapidjson::PrettyWriter *w) { - w->Key("Receiver Rois"); - w->StartArray(); - for (const slsDetectorDefs::ROI &roi : rois) { - std::string roi_str = ToString(roi); - w->String(roi_str.c_str()); - } - w->EndArray(); + GetBinaryRois(w); w->Key("Exptime"); w->String(ToString(exptime).c_str()); w->Key("Period"); diff --git a/slsReceiverSoftware/src/MasterAttributes.h b/slsReceiverSoftware/src/MasterAttributes.h index 81442fad0..3d07b45a2 100644 --- a/slsReceiverSoftware/src/MasterAttributes.h +++ b/slsReceiverSoftware/src/MasterAttributes.h @@ -78,6 +78,8 @@ class MasterAttributes { rapidjson::PrettyWriter *w); void GetFinalBinaryAttributes( rapidjson::PrettyWriter *w); + void GetBinaryRois( + rapidjson::PrettyWriter *w); #ifdef HDF5C void WriteCommonHDF5Attributes(H5::H5File *fd, H5::Group *group); void WriteFinalHDF5Attributes(H5::Group *group); From 66ee7954db148d5032d1fe6ad6c58533fd6e2fba Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Wed, 2 Jul 2025 19:38:42 +0200 Subject: [PATCH 43/49] refactoring wip --- slsReceiverSoftware/src/DataProcessor.cpp | 5 +---- slsReceiverSoftware/src/DataProcessor.h | 2 +- slsReceiverSoftware/src/Implementation.cpp | 18 +++++++++++++++++- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/slsReceiverSoftware/src/DataProcessor.cpp b/slsReceiverSoftware/src/DataProcessor.cpp index f7e4afb43..8631af36c 100644 --- a/slsReceiverSoftware/src/DataProcessor.cpp +++ b/slsReceiverSoftware/src/DataProcessor.cpp @@ -206,14 +206,11 @@ std::string DataProcessor::CreateVirtualFile( const std::string &filePath, const std::string &fileNamePrefix, const uint64_t fileIndex, const bool overWriteEnable, const bool silentMode, const int modulePos, const int numModX, const int numModY, - std::mutex *hdf5LibMutex) { + std::mutex *hdf5LibMutex, bool gotthard25um) { int ny = generalData->nPixelsY; if (generalData->dynamicRange == 4) ny /= 2; - bool gotthard25um = ((generalData->detType == GOTTHARD || - generalData->detType == GOTTHARD2) && - (numModX * numModY) == 2); // 0 for infinite files uint32_t framesPerFile = diff --git a/slsReceiverSoftware/src/DataProcessor.h b/slsReceiverSoftware/src/DataProcessor.h index ecfdacc7e..dfed87819 100644 --- a/slsReceiverSoftware/src/DataProcessor.h +++ b/slsReceiverSoftware/src/DataProcessor.h @@ -70,7 +70,7 @@ class DataProcessor : private virtual slsDetectorDefs, public ThreadObject { const bool overWriteEnable, const bool silentMode, const int modulePos, const int numModX, const int numModY, - std::mutex *hdf5LibMutex); + std::mutex *hdf5LibMutex, bool gotthard25um); void LinkFileInMaster(const std::string &masterFileName, const std::string &virtualFileName, const bool silentMode, std::mutex *hdf5LibMutex); diff --git a/slsReceiverSoftware/src/Implementation.cpp b/slsReceiverSoftware/src/Implementation.cpp index c6943886e..03114244b 100644 --- a/slsReceiverSoftware/src/Implementation.cpp +++ b/slsReceiverSoftware/src/Implementation.cpp @@ -992,14 +992,30 @@ void Implementation::StartMasterWriter() { fileFormatType, &masterAttributes, &hdf5LibMutex); } #ifdef HDF5C + // create virtual and master file if (fileFormatType == HDF5) { + + bool gotthard25um = ((generalData->detType == GOTTHARD || generalData->detType == GOTTHARD2) && (numPorts.x * numPorts.y) == 2); + + // virtual hdf5 not allowed with roi for the following cases in hdf5 + if (multiRoiMetadata.size() > 1 || (!multiRoiMetadata[0].completeRoi())) { + if (generalData->dynamicRange == 4) { + throw std::runtime_error("Skipping virtual hdf5 file since rx_roi is enabled and it is in 4 bit mode."); + } + if (gotthard25um && (numPorts.x * numPorts.y) == 2) { + throw std::runtime_error( + "Skipping virtual hdf5 file since rx_roi is " + "enabled and there are 2 Gotthard 25um modules."); + } + } + std::string virtualFileName; // create virtual hdf5 file (if multiple files) if (dataProcessor[0]->GetFilesInAcquisition() > 1 || (numPorts.x * numPorts.y) > 1) { virtualFileName = dataProcessor[0]->CreateVirtualFile( filePath, fileName, fileIndex, overwriteEnable, silentMode, - modulePos, numPorts.x, numPorts.y, &hdf5LibMutex); + modulePos, numPorts.x, numPorts.y, &hdf5LibMutex, gotthard25um); } // link file in master if (masterFileWriteEnable) { From 313fc75950edf468d716fb1baec980aa64269172 Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Wed, 2 Jul 2025 19:44:30 +0200 Subject: [PATCH 44/49] wip refactoring --- slsReceiverSoftware/src/Implementation.cpp | 2 ++ slsReceiverSoftware/src/MasterFileUtility.cpp | 14 -------------- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/slsReceiverSoftware/src/Implementation.cpp b/slsReceiverSoftware/src/Implementation.cpp index 03114244b..7947e509e 100644 --- a/slsReceiverSoftware/src/Implementation.cpp +++ b/slsReceiverSoftware/src/Implementation.cpp @@ -155,6 +155,7 @@ void Implementation::setDetectorType(const detectorType d) { break; } + // number of portrois should be equal to number of interfaces if (d == EIGER) { ResetRois(); } @@ -1077,6 +1078,7 @@ void Implementation::setNumberofUDPInterfaces(const int n) { // fifo SetupFifoStructure(); + // number of portrois should be equal to number of interfaces ResetRois(); // create threads diff --git a/slsReceiverSoftware/src/MasterFileUtility.cpp b/slsReceiverSoftware/src/MasterFileUtility.cpp index 1477b91fd..08412ace9 100644 --- a/slsReceiverSoftware/src/MasterFileUtility.cpp +++ b/slsReceiverSoftware/src/MasterFileUtility.cpp @@ -208,20 +208,6 @@ std::string CreateVirtualHDF5File( completeRoi = true; } - // roi not allowed in 4 bit mode and with gotthard 2 mods - if (!completeRoi) { - if (dynamicRange == 4) { - throw std::runtime_error( - "Skipping virtual hdf5 file since rx_roi is " - "enabled and it is in 4 bit mode."); - } - if (gotthard25um && (numModX * numModY) == 2) { - throw std::runtime_error( - "Skipping virtual hdf5 file since rx_roi is " - "enabled and there are 2 Gotthard 25um modules."); - } - } - // virtual file name std::ostringstream osfn; osfn << filePath << "/" << fileNamePrefix << "_virtual" From 94a94765509706c29d95f691718b2ac33453b819 Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Wed, 2 Jul 2025 19:44:44 +0200 Subject: [PATCH 45/49] formattin --- slsDetectorSoftware/src/Detector.cpp | 7 +++++-- slsDetectorSoftware/src/DetectorImpl.cpp | 10 ++++++---- slsReceiverSoftware/src/Implementation.cpp | 17 +++++++++++------ slsReceiverSoftware/src/MasterAttributes.cpp | 2 +- slsReceiverSoftware/src/MasterAttributes.h | 3 +-- 5 files changed, 24 insertions(+), 15 deletions(-) diff --git a/slsDetectorSoftware/src/Detector.cpp b/slsDetectorSoftware/src/Detector.cpp index 9d5a5f0a0..8c95fbf63 100644 --- a/slsDetectorSoftware/src/Detector.cpp +++ b/slsDetectorSoftware/src/Detector.cpp @@ -208,8 +208,11 @@ defs::xy Detector::getPortPerModuleGeometry() const { Result Detector::getPortSize(Positions pos) const { Result res = pimpl->Parallel(&Module::getNumberOfChannels, pos); defs::xy portGeometry = getPortPerModuleGeometry(); - if ((portGeometry.x != 1 && portGeometry.x != 2) || (portGeometry.y != 1 && portGeometry.y != 2)) { - throw RuntimeError("Port size is not 1 or 2 in either dimension. Port geometry:" + ToString(portGeometry)); + if ((portGeometry.x != 1 && portGeometry.x != 2) || + (portGeometry.y != 1 && portGeometry.y != 2)) { + throw RuntimeError( + "Port size is not 1 or 2 in either dimension. Port geometry:" + + ToString(portGeometry)); } for (auto &it : res) { it.x /= portGeometry.x; diff --git a/slsDetectorSoftware/src/DetectorImpl.cpp b/slsDetectorSoftware/src/DetectorImpl.cpp index 99dd3e5ce..d51c3d802 100644 --- a/slsDetectorSoftware/src/DetectorImpl.cpp +++ b/slsDetectorSoftware/src/DetectorImpl.cpp @@ -1783,9 +1783,10 @@ void DetectorImpl::convertGlobalRoiToPortLevel( throw RuntimeError("Only up to 2 ports per module supported."); } if (numPortsPerModule != (int)portRois.size()) { - throw RuntimeError("Number of port ROIs does not match number of ports in module. Expected: " + - std::to_string(numPortsPerModule) + ", got: " + - std::to_string(portRois.size())); + throw RuntimeError("Number of port ROIs does not match number of ports " + "in module. Expected: " + + std::to_string(numPortsPerModule) + + ", got: " + std::to_string(portRois.size())); } for (int port = 0; port != numPortsPerModule; ++port) { @@ -1818,7 +1819,8 @@ void DetectorImpl::convertGlobalRoiToPortLevel( std::min(userRoi.ymax, portRoi.ymax) - portRoi.ymin; } - // Check if port ROI already exists for this port (from another user roi) + // Check if port ROI already exists for this port (from another user + // roi) if (!portRois[port].completeRoi() && !portRois[port].noRoi()) { throw RuntimeError( "Multiple ROIs specified for the same port " + diff --git a/slsReceiverSoftware/src/Implementation.cpp b/slsReceiverSoftware/src/Implementation.cpp index 7947e509e..7c033f498 100644 --- a/slsReceiverSoftware/src/Implementation.cpp +++ b/slsReceiverSoftware/src/Implementation.cpp @@ -414,7 +414,6 @@ void Implementation::ResetRois() { setMultiROIMetadata(multiRoi); } - void Implementation::setPortROIs(const std::vector &args) { int nx = static_cast(generalData->nPixelsX); int ny = static_cast(generalData->nPixelsY); @@ -996,12 +995,17 @@ void Implementation::StartMasterWriter() { // create virtual and master file if (fileFormatType == HDF5) { - bool gotthard25um = ((generalData->detType == GOTTHARD || generalData->detType == GOTTHARD2) && (numPorts.x * numPorts.y) == 2); + bool gotthard25um = ((generalData->detType == GOTTHARD || + generalData->detType == GOTTHARD2) && + (numPorts.x * numPorts.y) == 2); // virtual hdf5 not allowed with roi for the following cases in hdf5 - if (multiRoiMetadata.size() > 1 || (!multiRoiMetadata[0].completeRoi())) { + if (multiRoiMetadata.size() > 1 || + (!multiRoiMetadata[0].completeRoi())) { if (generalData->dynamicRange == 4) { - throw std::runtime_error("Skipping virtual hdf5 file since rx_roi is enabled and it is in 4 bit mode."); + throw std::runtime_error( + "Skipping virtual hdf5 file since rx_roi is enabled " + "and it is in 4 bit mode."); } if (gotthard25um && (numPorts.x * numPorts.y) == 2) { throw std::runtime_error( @@ -1009,14 +1013,15 @@ void Implementation::StartMasterWriter() { "enabled and there are 2 Gotthard 25um modules."); } } - + std::string virtualFileName; // create virtual hdf5 file (if multiple files) if (dataProcessor[0]->GetFilesInAcquisition() > 1 || (numPorts.x * numPorts.y) > 1) { virtualFileName = dataProcessor[0]->CreateVirtualFile( filePath, fileName, fileIndex, overwriteEnable, silentMode, - modulePos, numPorts.x, numPorts.y, &hdf5LibMutex, gotthard25um); + modulePos, numPorts.x, numPorts.y, &hdf5LibMutex, + gotthard25um); } // link file in master if (masterFileWriteEnable) { diff --git a/slsReceiverSoftware/src/MasterAttributes.cpp b/slsReceiverSoftware/src/MasterAttributes.cpp index e6ecd12e4..211b6f439 100644 --- a/slsReceiverSoftware/src/MasterAttributes.cpp +++ b/slsReceiverSoftware/src/MasterAttributes.cpp @@ -155,7 +155,7 @@ void MasterAttributes::GetFinalBinaryAttributes( } void MasterAttributes::GetBinaryRois( - rapidjson::PrettyWriter *w) { + rapidjson::PrettyWriter *w) { w->Key("Receiver Rois"); w->StartArray(); for (const slsDetectorDefs::ROI &roi : rois) { diff --git a/slsReceiverSoftware/src/MasterAttributes.h b/slsReceiverSoftware/src/MasterAttributes.h index 3d07b45a2..f195ee70a 100644 --- a/slsReceiverSoftware/src/MasterAttributes.h +++ b/slsReceiverSoftware/src/MasterAttributes.h @@ -78,8 +78,7 @@ class MasterAttributes { rapidjson::PrettyWriter *w); void GetFinalBinaryAttributes( rapidjson::PrettyWriter *w); - void GetBinaryRois( - rapidjson::PrettyWriter *w); + void GetBinaryRois(rapidjson::PrettyWriter *w); #ifdef HDF5C void WriteCommonHDF5Attributes(H5::H5File *fd, H5::Group *group); void WriteFinalHDF5Attributes(H5::Group *group); From f9d41f1d66f05e95a6ab356c7b7fe23d5ff26afb Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Thu, 3 Jul 2025 10:58:44 +0200 Subject: [PATCH 46/49] to avoid confusion, moved default initialized, single sized declared vector of roi to be created at setDetectorType --- slsReceiverSoftware/src/Implementation.cpp | 4 +--- slsReceiverSoftware/src/Implementation.h | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/slsReceiverSoftware/src/Implementation.cpp b/slsReceiverSoftware/src/Implementation.cpp index 7c033f498..faf3bf031 100644 --- a/slsReceiverSoftware/src/Implementation.cpp +++ b/slsReceiverSoftware/src/Implementation.cpp @@ -156,9 +156,7 @@ void Implementation::setDetectorType(const detectorType d) { } // number of portrois should be equal to number of interfaces - if (d == EIGER) { - ResetRois(); - } + ResetRois(); SetLocalNetworkParameters(); SetupFifoStructure(); diff --git a/slsReceiverSoftware/src/Implementation.h b/slsReceiverSoftware/src/Implementation.h index 5764a8d09..31359930f 100644 --- a/slsReceiverSoftware/src/Implementation.h +++ b/slsReceiverSoftware/src/Implementation.h @@ -309,8 +309,8 @@ class Implementation : private virtual slsDetectorDefs { bool framePadding{true}; pid_t parentThreadId; pid_t tcpThreadId; - std::vector portRois{1}; - std::vector multiRoiMetadata{1}; + std::vector portRois; + std::vector multiRoiMetadata; // file parameters fileFormat fileFormatType{BINARY}; From b1c6b4b078bc0c91c13fb5ebcd32d2f8de5df803 Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Thu, 3 Jul 2025 11:42:24 +0200 Subject: [PATCH 47/49] pybind only 1 function for getRxROI --- python/src/detector.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/python/src/detector.cpp b/python/src/detector.cpp index c11e61167..f9e3821d7 100644 --- a/python/src/detector.cpp +++ b/python/src/detector.cpp @@ -932,10 +932,7 @@ void init_det(py::module &m) { Detector::setRxArping, py::arg(), py::arg() = Positions{}); CppDetectorApi.def("getRxROI", - (std::vector(Detector::*)() const) & - Detector::getRxROI); - CppDetectorApi.def("getRxROI", - (std::vector(Detector::*)(int) const) & + (std::vector (Detector::*)(int) const) & Detector::getRxROI, py::arg()); CppDetectorApi.def("setRxROI", From 34002f5be09eefb55b72cc10de389040a4b424d8 Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Thu, 3 Jul 2025 11:51:01 +0200 Subject: [PATCH 48/49] command line help --- slsDetectorSoftware/src/CallerSpecial.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/slsDetectorSoftware/src/CallerSpecial.cpp b/slsDetectorSoftware/src/CallerSpecial.cpp index 7ff78d8ef..a4ddf69ae 100644 --- a/slsDetectorSoftware/src/CallerSpecial.cpp +++ b/slsDetectorSoftware/src/CallerSpecial.cpp @@ -739,6 +739,8 @@ std::string Caller::rx_roi(int action) { "\tNotes:\n" "\t- ROIs can only be set at the multi-module level.\n" + "\t- If multi module ROIs ends up with more then 1 ROI per UDP " + "port or if they overlap each other, it will throw an error.\n" "\t- ROIs coordinates assume no gap pixels, even if they are enabled " "in gui.\n" "\t- To retrieve ROIs per port, specify the module ID when using the " From d210b0956ecd6486a7bb2c03bf6e46c5cd68d637 Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Wed, 9 Jul 2025 11:18:13 +0200 Subject: [PATCH 49/49] hdf5 definitions in test when not compiled with hdf5 --- slsDetectorSoftware/tests/CMakeLists.txt | 11 ++++++++--- slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp | 2 ++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/slsDetectorSoftware/tests/CMakeLists.txt b/slsDetectorSoftware/tests/CMakeLists.txt index d87f17ed0..6a4c03855 100755 --- a/slsDetectorSoftware/tests/CMakeLists.txt +++ b/slsDetectorSoftware/tests/CMakeLists.txt @@ -24,11 +24,16 @@ target_sources(tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/test-Module.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test-Pattern.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test-CtbConfig.cpp - - - ) +# HDF5 file +if (SLS_USE_HDF5) + target_compile_definitions(tests + PUBLIC + -DHDF5C ${HDF5_DEFINITIONS} + ) +endif (SLS_USE_HDF5) + target_include_directories(tests PUBLIC "$" diff --git a/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp b/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp index 76462e3c4..51fe04899 100644 --- a/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp +++ b/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp @@ -759,6 +759,7 @@ TEST_CASE("rx_roi", "[.cmdcall]") { std::string file_path = "/tmp/test_master_0.json"; REQUIRE(std::filesystem::exists(file_path) == true); +#ifdef HDF5C det.setAcquisitionIndex(0); det.setFileFormat(defs::HDF5); REQUIRE_NOTHROW(caller.call("acquire", {}, -1, PUT)); @@ -766,6 +767,7 @@ TEST_CASE("rx_roi", "[.cmdcall]") { REQUIRE(std::filesystem::exists(file_path) == true); file_path = "/tmp/test_virtual_0.h5"; REQUIRE(std::filesystem::exists(file_path) == true); +#endif det.setFileWrite(prev_write); if (!prev_path.empty())