Merge pull request #1242 from slsdetectorgroup/dev/roi_per_port
All checks were successful
Build on RHEL9 / build (push) Successful in 3m27s
Build on RHEL8 / build (push) Successful in 5m1s

Roi per port
This commit is contained in:
2025-07-10 11:29:01 +02:00
committed by GitHub
44 changed files with 1555 additions and 945 deletions

View File

@ -109,6 +109,13 @@ void init_det(py::module &m) {
(Result<defs::xy>(Detector::*)(sls::Positions) const) & (Result<defs::xy>(Detector::*)(sls::Positions) const) &
Detector::getModuleSize, Detector::getModuleSize,
py::arg() = Positions{}); py::arg() = Positions{});
CppDetectorApi.def("getPortPerModuleGeometry",
(defs::xy(Detector::*)() const) &
Detector::getPortPerModuleGeometry);
CppDetectorApi.def("getPortSize",
(Result<defs::xy>(Detector::*)(sls::Positions) const) &
Detector::getPortSize,
py::arg() = Positions{});
CppDetectorApi.def("getDetectorSize", (defs::xy(Detector::*)() const) & CppDetectorApi.def("getDetectorSize", (defs::xy(Detector::*)() const) &
Detector::getDetectorSize); Detector::getDetectorSize);
CppDetectorApi.def("setDetectorSize", CppDetectorApi.def("setDetectorSize",
@ -924,15 +931,14 @@ void init_det(py::module &m) {
(void (Detector::*)(bool, sls::Positions)) & (void (Detector::*)(bool, sls::Positions)) &
Detector::setRxArping, Detector::setRxArping,
py::arg(), py::arg() = Positions{}); py::arg(), py::arg() = Positions{});
CppDetectorApi.def("getIndividualRxROIs",
(Result<defs::ROI>(Detector::*)(sls::Positions) const) &
Detector::getIndividualRxROIs,
py::arg());
CppDetectorApi.def("getRxROI", CppDetectorApi.def("getRxROI",
(defs::ROI(Detector::*)() const) & Detector::getRxROI); (std::vector<defs::ROI> (Detector::*)(int) const) &
CppDetectorApi.def( Detector::getRxROI,
"setRxROI", (void (Detector::*)(const defs::ROI)) & Detector::setRxROI, py::arg());
py::arg()); CppDetectorApi.def("setRxROI",
(void (Detector::*)(const std::vector<defs::ROI> &)) &
Detector::setRxROI,
py::arg());
CppDetectorApi.def("clearRxROI", CppDetectorApi.def("clearRxROI",
(void (Detector::*)()) & Detector::clearRxROI); (void (Detector::*)()) & Detector::clearRxROI);
CppDetectorApi.def( CppDetectorApi.def(

View File

@ -40,6 +40,7 @@ class qDrawPlot : public QWidget, private Ui::PlotObject {
void SetDataCallBack(bool enable); void SetDataCallBack(bool enable);
void SetBinary(bool enable, int from = 0, int to = 0); void SetBinary(bool enable, int from = 0, int to = 0);
void StartAcquisition(); void StartAcquisition();
void UpdateROI();
public slots: public slots:
void SetPersistency(int val); void SetPersistency(int val);
@ -166,8 +167,8 @@ class qDrawPlot : public QWidget, private Ui::PlotObject {
int64_t currentFrame{0}; int64_t currentFrame{0};
mutable std::mutex mPlots; mutable std::mutex mPlots;
int64_t currentAcqIndex{0}; int64_t currentAcqIndex{0};
slsDetectorDefs::ROI rxRoi{}; bool hasRoi{false};
bool isRxRoiDisplayed{false}; bool roiDisplayInitialized{false};
bool isGapPixels{false}; bool isGapPixels{false};
unsigned int nPixelsX{0}; unsigned int nPixelsX{0};
@ -176,6 +177,7 @@ class qDrawPlot : public QWidget, private Ui::PlotObject {
uint32_t gainMask{0}; uint32_t gainMask{0};
int gainOffset{0}; int gainOffset{0};
bool gotthard25; bool gotthard25;
std::vector<slsDetectorDefs::ROI> roi{1};
}; };
} // namespace sls } // namespace sls

View File

@ -5,6 +5,8 @@
#include "SlsQt1DZoomer.h" #include "SlsQt1DZoomer.h"
#include "sls/ansi.h" #include "sls/ansi.h"
#include "sls/sls_detector_defs.h"
#include <array> #include <array>
#include <qwt_plot.h> #include <qwt_plot.h>
#include <qwt_plot_curve.h> #include <qwt_plot_curve.h>
@ -141,8 +143,9 @@ class SlsQt1DPlot : public QwtPlot {
void SetLogX(bool yes = 1); void SetLogX(bool yes = 1);
void SetLogY(bool yes = 1); void SetLogY(bool yes = 1);
void EnableRoiBox(std::array<int, 4> roi); void EnableRoiBoxes(std::vector<slsDetectorDefs::ROI> roi, int ymin,
void DisableRoiBox(); int ymax);
void DisableRoiBoxes();
private: private:
bool gainPlot{false}; bool gainPlot{false};
@ -169,6 +172,7 @@ class SlsQt1DPlot : public QwtPlot {
friend void SlsQtH1D::Attach(SlsQt1DPlot *p); friend void SlsQtH1D::Attach(SlsQt1DPlot *p);
friend void SlsQtH1D::Detach(SlsQt1DPlot *p); friend void SlsQtH1D::Detach(SlsQt1DPlot *p);
std::vector<std::unique_ptr<QwtPlotShapeItem>> roiBoxes{};
QwtPlotShapeItem *roiBox{nullptr}; QwtPlotShapeItem *roiBox{nullptr};
signals: signals:

View File

@ -3,6 +3,8 @@
#pragma once #pragma once
#include "SlsQt2DHist.h" #include "SlsQt2DHist.h"
#include "SlsQt2DZoomer.h" #include "SlsQt2DZoomer.h"
#include "sls/sls_detector_defs.h"
#include <array> #include <array>
#include <qlist.h> #include <qlist.h>
#include <qwt_plot.h> #include <qwt_plot.h>
@ -71,8 +73,8 @@ class SlsQt2DPlot : public QwtPlot {
void SetLogz(bool enable, bool isMin, bool isMax, double min, double max); void SetLogz(bool enable, bool isMin, bool isMax, double min, double max);
void SetZRange(bool isMin, bool isMax, double min, double max); void SetZRange(bool isMin, bool isMax, double min, double max);
void LogZ(bool on = 1); void LogZ(bool on = 1);
void EnableRoiBox(std::array<int, 4> roi); void EnableRoiBoxes(std::vector<slsDetectorDefs::ROI> roi);
void DisableRoiBox(); void DisableRoiBoxes();
public slots: public slots:
void showSpectrogram(bool on); void showSpectrogram(bool on);
@ -101,7 +103,7 @@ class SlsQt2DPlot : public QwtPlot {
QList<double> contourLevelsLog; QList<double> contourLevelsLog;
bool disableZoom{false}; bool disableZoom{false};
int isLog; int isLog;
QwtPlotShapeItem *roiBox{nullptr}; std::vector<std::unique_ptr<QwtPlotShapeItem>> roiBoxes{};
}; };
} // namespace sls } // namespace sls

View File

@ -462,24 +462,26 @@ void SlsQt1DPlot::SetLog(int axisId, bool yes) {
Update(); Update();
} }
void SlsQt1DPlot::EnableRoiBox(std::array<int, 4> roi) { void SlsQt1DPlot::EnableRoiBoxes(std::vector<slsDetectorDefs::ROI> roi,
if (roiBox == nullptr) { int ymin, int ymax) {
roiBox = new QwtPlotShapeItem(); roiBoxes.clear();
roiBox->attach(this); for (auto &r : roi) {
roiBox->setPen(QColor(Qt::yellow), 2.0, Qt::SolidLine); auto box = std::make_unique<QwtPlotShapeItem>();
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(); replot();
} }
void SlsQt1DPlot::DisableRoiBox() { void SlsQt1DPlot::DisableRoiBoxes() {
if (roiBox != nullptr) { for (auto &r : roiBoxes) {
roiBox->detach(); r->detach();
replot();
} }
replot();
} }
void SlsQt1DPlot::SetZoomX(const QRectF &rect) { void SlsQt1DPlot::SetZoomX(const QRectF &rect) {

View File

@ -350,25 +350,25 @@ void SlsQt2DPlot::showSpectrogram(bool on) {
Update(); Update();
} }
void SlsQt2DPlot::EnableRoiBox(std::array<int, 4> roi) { void SlsQt2DPlot::EnableRoiBoxes(std::vector<slsDetectorDefs::ROI> roi) {
if (roiBox == nullptr) { roiBoxes.clear();
roiBox = new QwtPlotShapeItem(); for (auto &r : roi) {
auto box = std::make_unique<QwtPlotShapeItem>();
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(); replot();
} }
void SlsQt2DPlot::DisableRoiBox() { void SlsQt2DPlot::DisableRoiBoxes() {
if (roiBox != nullptr) { for (auto &r : roiBoxes) {
roiBox->detach(); r->detach();
replot();
} }
replot();
} }
} // namespace sls } // namespace sls

View File

@ -539,6 +539,7 @@ void qDetectorMain::EnableTabs(bool enable) {
tabDeveloper->Refresh(); tabDeveloper->Refresh();
tabPlot->Refresh(); tabPlot->Refresh();
plot->UpdateROI();
plot->StartAcquisition(); plot->StartAcquisition();
} else { // to enable scan box } else { // to enable scan box
tabPlot->Refresh(); tabPlot->Refresh();

View File

@ -608,7 +608,6 @@ void qDrawPlot::StartAcquisition() {
currentFrame = 0; currentFrame = 0;
boxPlot->setTitle("Old Plot"); boxPlot->setTitle("Old Plot");
det->clearAcquiringFlag(); // (from previous exit) or if running det->clearAcquiringFlag(); // (from previous exit) or if running
isRxRoiDisplayed = false;
// ensure data streaming in receiver (if plot enabled) // ensure data streaming in receiver (if plot enabled)
if (isPlot) { if (isPlot) {
@ -632,6 +631,34 @@ void qDrawPlot::StartAcquisition() {
LOG(logDEBUG) << "End of Starting Acquisition in qDrawPlot"; LOG(logDEBUG) << "End of Starting Acquisition in qDrawPlot";
} }
void qDrawPlot::UpdateROI() {
try {
std::lock_guard<std::mutex> lock(mPlots);
roi = det->getRxROI();
roiDisplayInitialized = false;
// roi enabled
if (roi.size() > 1 || !roi[0].completeRoi()) {
hasRoi = true;
// 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);
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() { void qDrawPlot::AcquireThread() {
LOG(logDEBUG) << "Acquire Thread"; LOG(logDEBUG) << "Acquire Thread";
std::string mess; std::string mess;
@ -709,7 +736,6 @@ void qDrawPlot::GetData(detectorData *data, uint64_t frameIndex,
<< " \t dynamic range: " << data->dynamicRange << std::endl << " \t dynamic range: " << data->dynamicRange << std::endl
<< " \t file index: " << data->fileIndex << std::endl << " \t file index: " << data->fileIndex << std::endl
<< " \t complete image: " << data->completeImage << std::endl << " \t complete image: " << data->completeImage << std::endl
<< " \t rx Roi: " << ToString(data->rxRoi) << std::endl
<< " ]"; << " ]";
progress = data->progressIndex; progress = data->progressIndex;
@ -717,22 +743,6 @@ void qDrawPlot::GetData(detectorData *data, uint64_t frameIndex,
currentFrame = frameIndex; currentFrame = frameIndex;
LOG(logDEBUG) << "[ Progress:" << progress << "%, Frame:" << currentFrame 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) // 1d check if npixelX has changed (m3 for different counters enabled)
if (is1d && static_cast<int>(nPixelsX) != data->nx) { if (is1d && static_cast<int>(nPixelsX) != data->nx) {
@ -971,30 +981,27 @@ void qDrawPlot::Update1dPlot() {
xyRangeChanged = false; xyRangeChanged = false;
} }
plot1d->DisableZoom(disableZoom); plot1d->DisableZoom(disableZoom);
if (!isRxRoiDisplayed) { if (!roiDisplayInitialized) {
isRxRoiDisplayed = true; roiDisplayInitialized = true;
if (rxRoi.completeRoi()) { if (!hasRoi) {
plot1d->DisableRoiBox(); plot1d->DisableRoiBoxes();
if (isGainDataExtracted) { if (isGainDataExtracted) {
gainplot1d->DisableRoiBox(); gainplot1d->DisableRoiBoxes();
} }
lblRxRoiEnabled->hide(); lblRxRoiEnabled->hide();
} else { } else {
plot1d->EnableRoiBox(std::array<int, 4>{ plot1d->EnableRoiBoxes(roi, (int)plot1d->GetYMinimum(),
rxRoi.xmin, rxRoi.xmax, (int)plot1d->GetYMinimum(), (int)plot1d->GetYMaximum());
(int)plot1d->GetYMaximum()});
if (isGainDataExtracted) { if (isGainDataExtracted) {
gainplot1d->EnableRoiBox( gainplot1d->EnableRoiBoxes(roi, 0, 3);
std::array<int, 4>{rxRoi.xmin, rxRoi.xmax, 0, 3});
} }
lblRxRoiEnabled->show(); lblRxRoiEnabled->show();
} }
} }
// ymin and ymax could change (so replot roi every time) // ymin and ymax could change (so replot roi every time)
if (!rxRoi.completeRoi()) { if (hasRoi) {
plot1d->EnableRoiBox(std::array<int, 4>{rxRoi.xmin, rxRoi.xmax, plot1d->EnableRoiBoxes(roi, (int)plot1d->GetYMinimum(),
(int)plot1d->GetYMinimum(), (int)plot1d->GetYMaximum());
(int)plot1d->GetYMaximum()});
} }
} }
@ -1025,18 +1032,18 @@ void qDrawPlot::Update2dPlot() {
} }
plot2d->DisableZoom(disableZoom); plot2d->DisableZoom(disableZoom);
plot2d->SetZRange(isZRange[0], isZRange[1], zRange[0], zRange[1]); plot2d->SetZRange(isZRange[0], isZRange[1], zRange[0], zRange[1]);
if (!isRxRoiDisplayed) { if (!roiDisplayInitialized) {
isRxRoiDisplayed = true; roiDisplayInitialized = true;
if (rxRoi.completeRoi()) { if (!hasRoi) {
plot2d->DisableRoiBox(); plot2d->DisableRoiBoxes();
if (isGainDataExtracted) { if (isGainDataExtracted) {
gainplot2d->DisableRoiBox(); gainplot2d->DisableRoiBoxes();
} }
lblRxRoiEnabled->hide(); lblRxRoiEnabled->hide();
} else { } else {
plot2d->EnableRoiBox(rxRoi.getIntArray()); plot2d->EnableRoiBoxes(roi);
if (isGainDataExtracted) { if (isGainDataExtracted) {
gainplot2d->EnableRoiBox(rxRoi.getIntArray()); gainplot2d->EnableRoiBoxes(roi);
} }
lblRxRoiEnabled->show(); lblRxRoiEnabled->show();
} }

View File

@ -21,6 +21,8 @@ class Caller {
UdpDestination getUdpEntry(); UdpDestination getUdpEntry();
int GetLevelAndInsertIntoArgs(std::string levelSeparatedCommand); int GetLevelAndInsertIntoArgs(std::string levelSeparatedCommand);
void WrongNumberOfParameters(size_t expected); void WrongNumberOfParameters(size_t expected);
std::vector<defs::ROI> parseRoiVector(const std::string &input);
defs::ROI parseRoi(const std::vector<std::string> &args);
template <typename V> std::string OutStringHex(const V &value) { template <typename V> std::string OutStringHex(const V &value) {
if (value.equal()) if (value.equal())

View File

@ -2193,20 +2193,6 @@ return 0
} }
__rx_roi() { __rx_roi() {
FCN_RETURN="" 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 return 0
} }
__rx_silent() { __rx_silent() {

View File

@ -2117,20 +2117,6 @@ return 0
} }
__rx_roi() { __rx_roi() {
FCN_RETURN="" 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 return 0
} }
__rx_silent() { __rx_silent() {

View File

@ -2598,11 +2598,7 @@ rx_roi:
GET: GET:
argc: 0 argc: 0
PUT: PUT:
args: argc: -1
- argc: 2
arg_types: [ int, int ]
- argc: 4
arg_types: [ int, int, int, int ]
ratecorr: ratecorr:
is_description: true is_description: true

View File

@ -8831,25 +8831,8 @@ rx_roi:
store_result_in_t: true store_result_in_t: true
PUT: PUT:
args: args:
- arg_types: - arg_types: []
- int argc: -1
- 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
cast_input: [] cast_input: []
check_det_id: false check_det_id: false
convert_det_id: true convert_det_id: true

View File

@ -119,6 +119,10 @@ class Detector {
Result<defs::xy> getModuleSize(Positions pos = {}) const; Result<defs::xy> getModuleSize(Positions pos = {}) const;
defs::xy getPortPerModuleGeometry() const;
Result<defs::xy> getPortSize(Positions pos = {}) const;
/** Gets the actual full detector size. It is the same even if ROI changes /** Gets the actual full detector size. It is the same even if ROI changes
*/ */
defs::xy getDetectorSize() const; defs::xy getDetectorSize() const;
@ -710,7 +714,7 @@ class Detector {
* restarts client and receiver zmq sockets if zmq streaming enabled. \n * restarts client and receiver zmq sockets if zmq streaming enabled. \n
* [Gotthard2] second interface enabled to send veto information via 10Gbps * [Gotthard2] second interface enabled to send veto information via 10Gbps
* for debugging. By default, if veto enabled, it is sent via 2.5 gbps * 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 = {}); void setNumberofUDPInterfaces(int n, Positions pos = {});
/** [Jungfrau][Moench] */ /** [Jungfrau][Moench] */
@ -985,13 +989,14 @@ class Detector {
* every minute. Useful in 10G mode. */ * every minute. Useful in 10G mode. */
void setRxArping(bool value, Positions pos = {}); void setRxArping(bool value, Positions pos = {});
/** at module level */ /** If module_id is -1, returns multi level ROIs. Else it returns port
Result<defs::ROI> getIndividualRxROIs(Positions pos) const; * level ROIs. Max 2 ports and hence max 2 elements per readout */
std::vector<defs::ROI> getRxROI(int module_id = -1) const;
defs::ROI getRxROI() 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
/** only at multi module level without gap pixels */ * roi. Cannot be set for CTB or Xilinx CTB */
void setRxROI(const defs::ROI value); void setRxROI(const std::vector<defs::ROI> &args);
void clearRxROI(); void clearRxROI();

View File

@ -19,14 +19,6 @@ class detectorData {
databytes(databytes), dynamicRange(dynamicRange), databytes(databytes), dynamicRange(dynamicRange),
completeImage(completeImage){}; 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<int, 4> 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 * data has to be deleted by caller
*/ */
@ -62,7 +54,6 @@ class detectorData {
int databytes; int databytes;
int dynamicRange; int dynamicRange;
bool completeImage; bool completeImage;
std::array<int, 4> rxRoi{{-1, -1, -1, -1}};
}; };
} // namespace sls } // namespace sls

View File

@ -21,6 +21,8 @@ class Caller {
UdpDestination getUdpEntry(); UdpDestination getUdpEntry();
int GetLevelAndInsertIntoArgs(std::string levelSeparatedCommand); int GetLevelAndInsertIntoArgs(std::string levelSeparatedCommand);
void WrongNumberOfParameters(size_t expected); void WrongNumberOfParameters(size_t expected);
std::vector<defs::ROI> parseRoiVector(const std::string &input);
defs::ROI parseRoi(const std::vector<std::string> &args);
template <typename V> std::string OutStringHex(const V &value) { template <typename V> std::string OutStringHex(const V &value) {
if (value.equal()) if (value.equal())

View File

@ -719,49 +719,133 @@ std::string Caller::rx_zmqip(int action) {
} }
return os.str(); return os.str();
} }
std::string Caller::rx_roi(int action) { std::string Caller::rx_roi(int action) {
std::ostringstream os; std::ostringstream os;
std::string helpMessage =
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- 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 "
"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\n"
"\t- Cannot be set for CTB or Xilinx CTB.\n";
if (action == defs::HELP_ACTION) { if (action == defs::HELP_ACTION) {
os << "[xmin] [xmax] [ymin] [ymax]\n\tRegion of interest in " os << helpMessage;
"receiver.\n\tOnly allowed at multi module level and without gap "
"pixels."
<< '\n';
} else if (action == defs::GET_ACTION) { } else if (action == defs::GET_ACTION) {
if (!args.empty()) { if (!args.empty()) {
WrongNumberOfParameters(0); WrongNumberOfParameters(0);
} }
if (det_id == -1) { auto t = det->getRxROI(det_id);
auto t = det->getRxROI(); os << ToString(t) << '\n';
os << t << '\n';
} else {
auto t = det->getIndividualRxROIs(std::vector<int>{det_id});
os << t << '\n';
}
} else if (action == defs::PUT_ACTION) { } 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) {
t.xmin = StringTo<int>(args[0]);
t.xmax = StringTo<int>(args[1]);
}
if (args.size() == 4) {
t.ymin = StringTo<int>(args[2]);
t.ymax = StringTo<int>(args[3]);
}
// only multi level
if (det_id != -1) { if (det_id != -1) {
throw RuntimeError("Cannot execute receiver ROI at module level"); throw RuntimeError("Cannot set receiver ROI at module level");
} }
det->setRxROI(t); // Support multiple args with bracketed ROIs, or single arg with
os << t << '\n'; // semicolon-separated vector in quotes
bool isVectorInput =
std::all_of(args.begin(), args.end(), [](const std::string &a) {
return a.find('[') != std::string::npos &&
a.find(']') != std::string::npos;
});
std::vector<defs::ROI> rois;
try {
// single roi in previous format: [xmin,xmax,ymin,ymax]
if (!isVectorInput) {
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
// 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) {
throw RuntimeError("Could not parse ROI: Did you use spaces inside "
"the brackets? Use sls_detector_help " +
cmd + " to get the right syntax expected.");
}
det->setRxROI(rois);
os << ToString(rois) << '\n';
} else { } else {
throw RuntimeError("Unknown action"); throw RuntimeError("Unknown action");
} }
return os.str(); return os.str();
} }
std::vector<defs::ROI> Caller::parseRoiVector(const std::string &input) {
std::vector<defs::ROI> rois;
std::stringstream ss(input);
std::string token;
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() != '[') {
throw RuntimeError("Each ROI must be enclosed in square brackets: "
"[xmin,xmax,ymin,ymax]");
}
token = token.substr(1, token.size() - 1); // remove brackets
std::vector<std::string> parts;
std::stringstream inner(token);
std::string num;
while (std::getline(inner, num, ',')) {
parts.push_back(num);
}
auto roi = parseRoi(parts);
rois.emplace_back(roi);
}
return rois;
}
defs::ROI Caller::parseRoi(const std::vector<std::string> &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<int>(parts[0]);
roi.xmax = StringTo<int>(parts[1]);
if (parts.size() == 4) {
roi.ymin = StringTo<int>(parts[2]);
roi.ymax = StringTo<int>(parts[3]);
}
return roi;
}
std::string Caller::ratecorr(int action) { std::string Caller::ratecorr(int action) {
std::ostringstream os; std::ostringstream os;
if (action == defs::HELP_ACTION) { if (action == defs::HELP_ACTION) {

View File

@ -201,6 +201,26 @@ Result<defs::xy> Detector::getModuleSize(Positions pos) const {
return pimpl->Parallel(&Module::getNumberOfChannels, pos); return pimpl->Parallel(&Module::getNumberOfChannels, pos);
} }
defs::xy Detector::getPortPerModuleGeometry() const {
return pimpl->getPortGeometry();
}
Result<defs::xy> Detector::getPortSize(Positions pos) const {
Result<defs::xy> 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) {
it.x /= portGeometry.x;
it.y /= portGeometry.y;
}
return res;
}
defs::xy Detector::getDetectorSize() const { defs::xy Detector::getDetectorSize() const {
return pimpl->getNumberOfChannels(); return pimpl->getNumberOfChannels();
} }
@ -1367,13 +1387,13 @@ void Detector::setRxArping(bool value, Positions pos) {
pimpl->Parallel(&Module::setRxArping, pos, value); pimpl->Parallel(&Module::setRxArping, pos, value);
} }
Result<defs::ROI> Detector::getIndividualRxROIs(Positions pos) const { std::vector<defs::ROI> Detector::getRxROI(int module_id) const {
return pimpl->Parallel(&Module::getRxROI, pos); return pimpl->getRxROI(module_id);
} }
defs::ROI Detector::getRxROI() const { return pimpl->getRxROI(); } void Detector::setRxROI(const std::vector<defs::ROI> &args) {
pimpl->setRxROI(args);
void Detector::setRxROI(const defs::ROI value) { pimpl->setRxROI(value); } }
void Detector::clearRxROI() { pimpl->clearRxROI(); } void Detector::clearRxROI() { pimpl->clearRxROI(); }

View File

@ -130,10 +130,6 @@ void DetectorImpl::initializeDetectorStructure() {
shm()->gapPixels = false; shm()->gapPixels = false;
// zmqlib default // zmqlib default
shm()->zmqHwm = -1; 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) { void DetectorImpl::initializeMembers(bool verify) {
@ -539,7 +535,6 @@ void DetectorImpl::readFrameFromReceiver() {
bool quadEnable = false; bool quadEnable = false;
// to flip image // to flip image
bool eiger = false; bool eiger = false;
std::array<int, 4> rxRoi = shm()->rx_roi.getIntArray();
std::vector<bool> runningList(zmqSocket.size()); std::vector<bool> runningList(zmqSocket.size());
std::vector<bool> connectList(zmqSocket.size()); std::vector<bool> connectList(zmqSocket.size());
@ -736,7 +731,7 @@ void DetectorImpl::readFrameFromReceiver() {
thisData = new detectorData(currentProgress, currentFileName, thisData = new detectorData(currentProgress, currentFileName,
nDetActualPixelsX, nDetActualPixelsY, nDetActualPixelsX, nDetActualPixelsY,
callbackImage, imagesize, dynamicRange, callbackImage, imagesize, dynamicRange,
currentFileIndex, completeImage, rxRoi); currentFileIndex, completeImage);
try { try {
dataReady( dataReady(
thisData, currentFrameIndex, thisData, currentFrameIndex,
@ -1548,31 +1543,6 @@ void DetectorImpl::setDefaultDac(defs::dacIndex index, int defaultValue,
Parallel(&Module::setDefaultDac, pos, index, defaultValue, sett); 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, void DetectorImpl::verifyUniqueDetHost(const uint16_t port,
std::vector<int> positions) const { std::vector<int> positions) const {
// port for given positions // port for given positions
@ -1696,7 +1666,7 @@ void DetectorImpl::verifyUniqueHost(
} }
} }
defs::ROI DetectorImpl::getRxROI() const { std::vector<defs::ROI> DetectorImpl::getRxROI(int module_id) const {
if (shm()->detType == CHIPTESTBOARD || if (shm()->detType == CHIPTESTBOARD ||
shm()->detType == defs::XILINX_CHIPTESTBOARD) { shm()->detType == defs::XILINX_CHIPTESTBOARD) {
throw RuntimeError("RxRoi not implemented for this Detector"); throw RuntimeError("RxRoi not implemented for this Detector");
@ -1704,75 +1674,164 @@ defs::ROI DetectorImpl::getRxROI() const {
if (modules.size() == 0) { if (modules.size() == 0) {
throw RuntimeError("No Modules added"); throw RuntimeError("No Modules added");
} }
// complete detector in roi if (module_id >= (int)modules.size()) {
auto t = Parallel(&Module::getRxROI, {}); throw RuntimeError("Invalid module id: " + std::to_string(module_id));
if (t.equal() && t.front().completeRoi()) { }
LOG(logDEBUG) << "no roi"; if (module_id >= 0) {
return defs::ROI(0, shm()->numberOfChannels.x - 1, 0, return modules[module_id]->getRxROI();
shm()->numberOfChannels.y - 1);
} }
defs::xy numChansPerMod = modules[0]->getNumberOfChannels(); return modules[0]->getRxROIMetadata();
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;
} }
void DetectorImpl::setRxROI(const defs::ROI arg) { void DetectorImpl::validateROIs(const std::vector<defs::ROI> &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));
}
bool is2D = (modules[0]->getNumberOfChannels().y > 1 ? true : false);
if (roi.completeRoi()) {
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(
"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));
}
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 (rois[i].overlap(rois[j])) {
throw RuntimeError("Invalid Overlapping Rois.");
}
}
}
}
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;
case GOTTHARD2: // 2nd port if used is for veto, not data
default:
break;
}
return portGeometry;
}
defs::xy DetectorImpl::calculatePosition(int moduleIndex) const {
int maxYMods = shm()->numberOfModules.y;
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);
const int xmin = modSize.x * modPos.x;
const int xmax = xmin + modSize.x - 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};
}
void DetectorImpl::convertGlobalRoiToPortLevel(
const defs::ROI &userRoi, const defs::ROI &moduleRoi,
std::vector<defs::ROI> &portRois) const {
const defs::xy modSize = modules[0]->getNumberOfChannels();
const defs::xy portGeometry = getPortGeometry();
const int numPortsPerModule = portGeometry.x * portGeometry.y;
if (numPortsPerModule > 2) {
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()));
}
for (int port = 0; port != numPortsPerModule; ++port) {
defs::ROI portRoi = moduleRoi;
// 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 (portGeometry.y == 2) {
int midY = (moduleRoi.ymin + moduleRoi.ymax) / 2;
if (port == 0)
portRoi.ymax = midY;
else
portRoi.ymin = midY + 1;
}
// 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;
if (modSize.y > 1) {
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 (from another user
// roi)
if (!portRois[port].completeRoi() && !portRois[port].noRoi()) {
throw RuntimeError(
"Multiple ROIs specified for the same port " +
std::to_string(port) + " with ROI: " + ToString(userRoi));
}
portRois[port] = clipped;
}
}
}
void DetectorImpl::setRxROI(const std::vector<defs::ROI> &args) {
if (shm()->detType == CHIPTESTBOARD || if (shm()->detType == CHIPTESTBOARD ||
shm()->detType == defs::XILINX_CHIPTESTBOARD) { shm()->detType == defs::XILINX_CHIPTESTBOARD) {
throw RuntimeError("RxRoi not implemented for this Detector"); throw RuntimeError("RxRoi not implemented for this Detector");
@ -1780,118 +1839,41 @@ void DetectorImpl::setRxROI(const defs::ROI arg) {
if (modules.size() == 0) { if (modules.size() == 0) {
throw RuntimeError("No Modules added"); throw RuntimeError("No Modules added");
} }
if (arg.noRoi()) {
throw RuntimeError("Invalid Roi of size 0."); if (args.empty()) {
} return clearRxROI();
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.");
} }
defs::xy numChansPerMod = modules[0]->getNumberOfChannels(); validateROIs(args);
bool is2D = (numChansPerMod.y > 1 ? true : false); int nPortsPerModule =
defs::xy geometry = getPortGeometry(); Parallel(&Module::getNumberofUDPInterfacesFromShm, {})
.tsquash("Inconsistent number of udp ports set up per module");
if (!is2D && ((arg.ymin != -1 && arg.ymin != 0) || for (size_t iModule = 0; iModule < modules.size(); ++iModule) {
(arg.ymax != -1 && arg.ymax != 0))) { auto moduleGlobalRoi = getModuleROI(iModule);
throw RuntimeError( // at most 2 rois per module (for each port)
"Invalid Receiver roi. Cannot set 2d roi for a 1d detector."); std::vector<defs::ROI> portRois(nPortsPerModule);
}
if (arg.xmin < 0 || arg.xmax >= shm()->numberOfChannels.x || // check overlap with module
(is2D && (arg.ymin < 0 || arg.ymax >= shm()->numberOfChannels.y))) { for (const auto &arg : args) {
throw RuntimeError("Invalid Receiver Roi. Outside detector range."); if (arg.overlap(moduleGlobalRoi)) {
} convertGlobalRoiToPortLevel(arg, moduleGlobalRoi, portRois);
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); modules[iModule]->setRxROI(portRois);
} }
// updating shm rx_roi for gui purposes
shm()->rx_roi = arg;
// metadata // metadata
if (arg.completeRoi()) { modules[0]->setRxROIMetadata(args);
modules[0]->setRxROIMetadata(defs::ROI(0, shm()->numberOfChannels.x - 1,
0,
shm()->numberOfChannels.y - 1));
} else {
modules[0]->setRxROIMetadata(arg);
}
} }
void DetectorImpl::clearRxROI() { void DetectorImpl::clearRxROI() {
Parallel(&Module::setRxROI, {}, defs::ROI{}); int nPortsPerModule =
shm()->rx_roi.xmin = -1; Parallel(&Module::getNumberofUDPInterfacesFromShm, {})
shm()->rx_roi.ymin = -1; .tsquash("Inconsistent number of udp ports set up per module");
shm()->rx_roi.xmax = -1; for (size_t iModule = 0; iModule < modules.size(); ++iModule) {
shm()->rx_roi.ymax = -1; modules[iModule]->setRxROI(std::vector<defs::ROI>(nPortsPerModule));
}
modules[0]->setRxROIMetadata(std::vector<defs::ROI>(1));
} }
void DetectorImpl::getBadChannels(const std::string &fname, void DetectorImpl::getBadChannels(const std::string &fname,

View File

@ -24,7 +24,7 @@ class detectorData;
class Module; class Module;
#define DETECTOR_SHMAPIVERSION 0x190809 #define DETECTOR_SHMAPIVERSION 0x190809
#define DETECTOR_SHMVERSION 0x220505 #define DETECTOR_SHMVERSION 0x250616
#define SHORT_STRING_LENGTH 50 #define SHORT_STRING_LENGTH 50
/** /**
@ -65,8 +65,6 @@ struct sharedDetector {
bool gapPixels; bool gapPixels;
/** high water mark of listening tcp port (only data) */ /** high water mark of listening tcp port (only data) */
int zmqHwm; int zmqHwm;
/** in shm for gui purposes */
defs::ROI rx_roi{};
}; };
class DetectorImpl : public virtual slsDetectorDefs { class DetectorImpl : public virtual slsDetectorDefs {
@ -303,8 +301,9 @@ class DetectorImpl : public virtual slsDetectorDefs {
std::vector<std::pair<std::string, uint16_t>> std::vector<std::pair<std::string, uint16_t>>
verifyUniqueRxHost(const std::vector<std::string> &names) const; verifyUniqueRxHost(const std::vector<std::string> &names) const;
defs::ROI getRxROI() const; defs::xy getPortGeometry() const;
void setRxROI(const defs::ROI arg); std::vector<defs::ROI> getRxROI(int module_id = -1) const;
void setRxROI(const std::vector<defs::ROI> &args);
void clearRxROI(); void clearRxROI();
void getBadChannels(const std::string &fname, Positions pos) const; void getBadChannels(const std::string &fname, Positions pos) const;
@ -422,12 +421,17 @@ class DetectorImpl : public virtual slsDetectorDefs {
*/ */
int kbhit(); int kbhit();
defs::xy getPortGeometry() const;
defs::xy calculatePosition(int moduleIndex, defs::xy geometry) const;
void verifyUniqueHost( void verifyUniqueHost(
bool isDet, std::vector<std::pair<std::string, uint16_t>> &hosts) const; bool isDet, std::vector<std::pair<std::string, uint16_t>> &hosts) const;
bool roisOverlap(const defs::ROI &a, const defs::ROI &b) const;
void validateROIs(const std::vector<defs::ROI> &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<defs::ROI> &portRois) const;
const int detectorIndex{0}; const int detectorIndex{0};
SharedMemory<sharedDetector> shm{0, -1}; SharedMemory<sharedDetector> shm{0, -1};
SharedMemory<CtbConfig> ctb_shm{0, -1, CtbConfig::shm_tag()}; SharedMemory<CtbConfig> ctb_shm{0, -1, CtbConfig::shm_tag()};

View File

@ -1521,17 +1521,94 @@ void Module::setRxArping(bool enable) {
sendToReceiver(F_SET_RECEIVER_ARPING, static_cast<int>(enable), nullptr); sendToReceiver(F_SET_RECEIVER_ARPING, static_cast<int>(enable), nullptr);
} }
defs::ROI Module::getRxROI() const { std::vector<defs::ROI> Module::getRxROI() const {
return sendToReceiver<slsDetectorDefs::ROI>(F_RECEIVER_GET_RECEIVER_ROI); 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<int>();
std::vector<ROI> retval(nPorts);
if (nPorts > 0)
client.Receive(retval);
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);
return retval;
} }
void Module::setRxROI(const slsDetectorDefs::ROI arg) { void Module::setRxROI(const std::vector<defs::ROI> &portRois) {
LOG(logDEBUG) << moduleIndex << ": " << arg; LOG(logDEBUG) << "Sending to receiver " << moduleIndex
sendToReceiver(F_RECEIVER_SET_RECEIVER_ROI, arg, nullptr); << " [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()) +
". Expected: " + 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<int>(portRois.size());
client.Send(size);
if (size > 0)
client.Send(portRois);
if (client.Receive<int>() == FAIL) {
throw ReceiverError("Receiver " + std::to_string(moduleIndex) +
" returned error: " + client.readErrorMessage());
}
} }
void Module::setRxROIMetadata(const slsDetectorDefs::ROI arg) { std::vector<slsDetectorDefs::ROI> Module::getRxROIMetadata() const {
sendToReceiver(F_RECEIVER_SET_RECEIVER_ROI_METADATA, arg, nullptr); 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<int>();
std::vector<slsDetectorDefs::ROI> 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<slsDetectorDefs::ROI> &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);
int size = static_cast<int>(args.size());
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<int>() == FAIL) {
throw ReceiverError("Receiver " + std::to_string(moduleIndex) +
" returned error: " + receiver.readErrorMessage());
}
} }
// File // File

View File

@ -301,9 +301,10 @@ class Module : public virtual slsDetectorDefs {
std::array<pid_t, NUM_RX_THREAD_IDS> getReceiverThreadIds() const; std::array<pid_t, NUM_RX_THREAD_IDS> getReceiverThreadIds() const;
bool getRxArping() const; bool getRxArping() const;
void setRxArping(bool enable); void setRxArping(bool enable);
defs::ROI getRxROI() const; std::vector<defs::ROI> getRxROI() const;
void setRxROI(const slsDetectorDefs::ROI arg); void setRxROI(const std::vector<slsDetectorDefs::ROI> &portRois);
void setRxROIMetadata(const slsDetectorDefs::ROI arg); void setRxROIMetadata(const std::vector<slsDetectorDefs::ROI> &args);
std::vector<slsDetectorDefs::ROI> getRxROIMetadata() const;
/************************************************** /**************************************************
* * * *

View File

@ -2769,22 +2769,8 @@ int InferAction::rx_realudpsocksize() {
int InferAction::rx_roi() { int InferAction::rx_roi() {
if (args.size() == 0) { throw RuntimeError("sls_detector is disabled for command: rx_roi. Use "
return slsDetectorDefs::GET_ACTION; "sls_detector_get or sls_detector_put");
}
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");
}
} }
int InferAction::rx_silent() { int InferAction::rx_silent() {

View File

@ -24,11 +24,16 @@ target_sources(tests PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/test-Module.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test-Module.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test-Pattern.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test-Pattern.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test-CtbConfig.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 target_include_directories(tests
PUBLIC PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../src>" "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../src>"

View File

@ -7,6 +7,7 @@
#include "sls/sls_detector_defs.h" #include "sls/sls_detector_defs.h"
#include "test-Caller-global.h" #include "test-Caller-global.h"
#include <filesystem>
#include <sstream> #include <sstream>
#include "sls/versionAPI.h" #include "sls/versionAPI.h"
@ -466,7 +467,6 @@ TEST_CASE("rx_arping", "[.cmdcall][.rx]") {
} }
} }
} }
TEST_CASE("rx_roi", "[.cmdcall]") { TEST_CASE("rx_roi", "[.cmdcall]") {
Detector det; Detector det;
Caller caller(&det); Caller caller(&det);
@ -477,35 +477,95 @@ TEST_CASE("rx_roi", "[.cmdcall]") {
} else { } else {
auto prev_val = det.getRxROI(); auto prev_val = det.getRxROI();
defs::xy detsize = det.getDetectorSize(); defs::xy detsize = det.getDetectorSize();
auto portSize = det.getPortSize()[0];
int delta = 50;
// 1d // 1d
if (det_type == defs::GOTTHARD || det_type == defs::GOTTHARD2 || if (det_type == defs::GOTTHARD2 || det_type == defs::MYTHEN3) {
det_type == defs::MYTHEN3) {
{ {
std::ostringstream oss; std::ostringstream oss;
caller.call("rx_roi", {"5", "10"}, -1, PUT, 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; std::ostringstream oss;
caller.call("rx_roi", {"10", "15"}, -1, PUT, 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)); REQUIRE_THROWS(caller.call("rx_roi", {"-1", "-1"}, -1, PUT));
REQUIRE_THROWS( // xmin > xmax
caller.call("rx_roi", {"10", "15", "25", "30"}, -1, PUT)); 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]"}, 0, PUT));
// vector of rois
// square brackets missing
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, -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));
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;
// separated by semicolon with quotes is allowed (skips
// cmdParser)
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
{
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 // 2d eiger, jungfrau, moench
else { else {
{ {
std::ostringstream oss; std::ostringstream oss;
caller.call("rx_roi", {"10", "15", "1", "5"}, -1, PUT, 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; std::ostringstream oss;
caller.call("rx_roi", {"10", "22", "18", "19"}, -1, PUT, 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; std::ostringstream oss;
@ -513,18 +573,215 @@ TEST_CASE("rx_roi", "[.cmdcall]") {
{"1", std::to_string(detsize.x - 5), "1", {"1", std::to_string(detsize.x - 5), "1",
std::to_string(detsize.y - 5)}, std::to_string(detsize.y - 5)},
-1, PUT, oss); -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::to_string(detsize.x - 5) +
std::string(", 1, ") + std::string(", 1, ") +
std::to_string(detsize.y - 5) + std::to_string(detsize.y - 5) +
std::string("]\n")); std::string("]]\n"));
} }
REQUIRE_THROWS(
caller.call("rx_roi", {"0", "0", "0", "0"}, -1, PUT));
REQUIRE_THROWS( REQUIRE_THROWS(
caller.call("rx_roi", {"-1", "-1", "-1", "-1"}, -1, PUT)); caller.call("rx_roi", {"-1", "-1", "-1", "-1"}, -1, PUT));
// 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]"}, 0, PUT));
// vector of rois
// square brackets missing
REQUIRE_THROWS(caller.call(
"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));
// 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));
int numinterfaces = det.getNumberofUDPInterfaces().tsquash(
"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);
// separated by space is allowed
REQUIRE_NOTHROW(caller.call(
"rx_roi",
{"[5, 10, 20, 30]",
"[" + stringMin + ", " + stringMax + ", 20, 30]"},
-1, PUT));
std::ostringstream oss;
// separated by semicolon with quotes is allowed (skips
// cmdParser)
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
{
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], [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");
}
}
}
// 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);
// 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 with quotes (skips
// cmdParser)
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 ((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)
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");
} else {
REQUIRE(oss1.str() ==
"rx_roi [[20, 30, " + stringMin + ", " +
std::to_string(portSize.y - 1) +
"]]\n");
}
}
}
}
}
// 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);
#ifdef HDF5C
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);
#endif
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) { 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);
} }
} }
} }

View File

@ -220,6 +220,7 @@ int ClientInterface::functionTable(){
flist[F_RECEIVER_SET_COLUMN] = &ClientInterface::set_column; flist[F_RECEIVER_SET_COLUMN] = &ClientInterface::set_column;
flist[F_GET_RECEIVER_DBIT_REORDER] = &ClientInterface::get_dbit_reorder; flist[F_GET_RECEIVER_DBIT_REORDER] = &ClientInterface::get_dbit_reorder;
flist[F_SET_RECEIVER_DBIT_REORDER] = &ClientInterface::set_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++) { for (int i = NUM_DET_FUNCTIONS + 1; i < NUM_REC_FUNCTIONS ; i++) {
@ -1693,19 +1694,37 @@ int ClientInterface::set_arping(Interface &socket) {
} }
int ClientInterface::get_receiver_roi(Interface &socket) { int ClientInterface::get_receiver_roi(Interface &socket) {
auto retval = impl()->getReceiverROI(); auto retvals = impl()->getPortROIs();
LOG(logDEBUG1) << "Receiver roi retval:" << ToString(retval); LOG(logDEBUG1) << "Receiver roi retval:" << ToString(retvals);
return socket.sendResult(retval); auto size = static_cast<int>(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);
return OK;
} }
int ClientInterface::set_receiver_roi(Interface &socket) { int ClientInterface::set_receiver_roi(Interface &socket) {
auto arg = socket.Receive<ROI>(); auto roiSize = socket.Receive<int>();
std::vector<ROI> args(roiSize);
if (roiSize > 0) {
socket.Receive(args);
}
if (roiSize != impl()->getNumberofUDPInterfaces()) {
throw RuntimeError("Invalid number of ROIs received: " +
std::to_string(roiSize) + ". Expected: " +
std::to_string(impl()->getNumberofUDPInterfaces()));
}
if (detType == CHIPTESTBOARD || detType == XILINX_CHIPTESTBOARD) if (detType == CHIPTESTBOARD || detType == XILINX_CHIPTESTBOARD)
functionNotImplemented(); functionNotImplemented();
LOG(logDEBUG1) << "Set Receiver ROI: " << ToString(arg); LOG(logDEBUG1) << "Set Receiver ROI: " << ToString(args);
verifyIdle(socket); verifyIdle(socket);
try { try {
impl()->setReceiverROI(arg); impl()->setPortROIs(args);
} catch (const std::exception &e) { } catch (const std::exception &e) {
throw RuntimeError("Could not set Receiver ROI [" + throw RuntimeError("Could not set Receiver ROI [" +
std::string(e.what()) + ']'); std::string(e.what()) + ']');
@ -1715,18 +1734,26 @@ int ClientInterface::set_receiver_roi(Interface &socket) {
} }
int ClientInterface::set_receiver_roi_metadata(Interface &socket) { int ClientInterface::set_receiver_roi_metadata(Interface &socket) {
auto arg = socket.Receive<ROI>(); auto roiSize = socket.Receive<int>();
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<ROI> rois(roiSize);
if (roiSize > 0) {
socket.Receive(rois);
}
if (detType == CHIPTESTBOARD || detType == XILINX_CHIPTESTBOARD) if (detType == CHIPTESTBOARD || detType == XILINX_CHIPTESTBOARD)
functionNotImplemented(); functionNotImplemented();
LOG(logDEBUG1) << "Set Receiver ROI Metadata: " << ToString(arg);
verifyIdle(socket); verifyIdle(socket);
LOG(logINFO) << "Setting ReceiverROI metadata[" << roiSize << ']';
try { try {
impl()->setReceiverROIMetadata(arg); impl()->setMultiROIMetadata(rois);
} catch (const std::exception &e) { } catch (const std::exception &e) {
throw RuntimeError("Could not set ReceiverROI metadata [" + throw RuntimeError("Could not set ReceiverROI metadata [" +
std::string(e.what()) + ']'); std::string(e.what()) + ']');
} }
return socket.Send(OK); return socket.Send(OK);
} }
@ -1812,4 +1839,16 @@ int ClientInterface::set_dbit_reorder(Interface &socket) {
return socket.Send(OK); return socket.Send(OK);
} }
int ClientInterface::get_roi_metadata(Interface &socket) {
if (detType == CHIPTESTBOARD || detType == XILINX_CHIPTESTBOARD)
functionNotImplemented();
auto retvals = impl()->getMultiROIMetadata();
LOG(logDEBUG1) << "Receiver ROI metadata retval:" << ToString(retvals);
auto size = static_cast<int>(retvals.size());
socket.Send(size);
if (size > 0)
socket.Send(retvals);
return OK;
}
} // namespace sls } // namespace sls

View File

@ -166,6 +166,7 @@ class ClientInterface : private virtual slsDetectorDefs {
int set_column(ServerInterface &socket); int set_column(ServerInterface &socket);
int get_dbit_reorder(ServerInterface &socket); int get_dbit_reorder(ServerInterface &socket);
int set_dbit_reorder(ServerInterface &socket); int set_dbit_reorder(ServerInterface &socket);
int get_roi_metadata(ServerInterface &socket);
Implementation *impl() { Implementation *impl() {
if (receiver != nullptr) { if (receiver != nullptr) {

View File

@ -48,10 +48,15 @@ void DataProcessor::SetUdpPortNumber(const uint16_t portNumber) {
void DataProcessor::SetActivate(bool enable) { activated = enable; } void DataProcessor::SetActivate(bool enable) { activated = enable; }
void DataProcessor::SetReceiverROI(ROI roi) { void DataProcessor::SetPortROI(ROI roi) {
receiverRoi = roi; portRoi = roi;
receiverRoiEnabled = receiverRoi.completeRoi() ? false : true; isPartiallyInRoi = portRoi.completeRoi() ? false : true;
receiverNoRoi = receiverRoi.noRoi(); isOutsideRoi = portRoi.noRoi();
}
void DataProcessor::setMultiROIMetadata(
const std::vector<slsDetectorDefs::ROI> &args) {
multiRoiMetadata = args;
} }
void DataProcessor::SetDataStreamEnable(bool enable) { void DataProcessor::SetDataStreamEnable(bool enable) {
@ -154,17 +159,17 @@ void DataProcessor::CreateFirstFiles(const std::string &fileNamePrefix,
CloseFiles(); CloseFiles();
// deactivated (half module/ single port or no roi), dont write file // deactivated (half module/ single port or no roi), dont write file
if (!activated || !detectorDataStream || receiverNoRoi) { if (!activated || !detectorDataStream || isOutsideRoi) {
return; return;
} }
#ifdef HDF5C #ifdef HDF5C
int nx = generalData->nPixelsX; int nx = generalData->nPixelsX;
int ny = generalData->nPixelsY; int ny = generalData->nPixelsY;
if (receiverRoiEnabled) { if (isPartiallyInRoi) {
nx = receiverRoi.xmax - receiverRoi.xmin + 1; nx = portRoi.xmax - portRoi.xmin + 1;
ny = receiverRoi.ymax - receiverRoi.ymin + 1; ny = portRoi.ymax - portRoi.ymin + 1;
if (receiverRoi.ymax == -1 || receiverRoi.ymin == -1) { if (portRoi.ymax == -1 || portRoi.ymin == -1) {
ny = 1; ny = 1;
} }
} }
@ -201,16 +206,11 @@ std::string DataProcessor::CreateVirtualFile(
const std::string &filePath, const std::string &fileNamePrefix, const std::string &filePath, const std::string &fileNamePrefix,
const uint64_t fileIndex, const bool overWriteEnable, const bool silentMode, const uint64_t fileIndex, const bool overWriteEnable, const bool silentMode,
const int modulePos, const int numModX, const int numModY, const int modulePos, const int numModX, const int numModY,
std::mutex *hdf5LibMutex) { std::mutex *hdf5LibMutex, bool gotthard25um) {
if (receiverRoiEnabled) { int ny = generalData->nPixelsY;
throw std::runtime_error( if (generalData->dynamicRange == 4)
"Skipping virtual hdf5 file since rx_roi is enabled."); ny /= 2;
}
bool gotthard25um = ((generalData->detType == GOTTHARD ||
generalData->detType == GOTTHARD2) &&
(numModX * numModY) == 2);
// 0 for infinite files // 0 for infinite files
uint32_t framesPerFile = uint32_t framesPerFile =
@ -224,10 +224,10 @@ std::string DataProcessor::CreateVirtualFile(
return masterFileUtility::CreateVirtualHDF5File( return masterFileUtility::CreateVirtualHDF5File(
filePath, fileNamePrefix, fileIndex, overWriteEnable, silentMode, filePath, fileNamePrefix, fileIndex, overWriteEnable, silentMode,
modulePos, generalData->numUDPInterfaces, framesPerFile, modulePos, generalData->numUDPInterfaces, framesPerFile,
generalData->nPixelsX, generalData->nPixelsY, generalData->dynamicRange, generalData->nPixelsX, ny, generalData->dynamicRange, numFramesCaught,
numFramesCaught, numModX, numModY, dataFile->GetPDataType(), numModX, numModY, dataFile->GetPDataType(),
dataFile->GetParameterNames(), dataFile->GetParameterDataTypes(), dataFile->GetParameterNames(), dataFile->GetParameterDataTypes(),
hdf5LibMutex, gotthard25um); hdf5LibMutex, gotthard25um, multiRoiMetadata);
} }
void DataProcessor::LinkFileInMaster(const std::string &masterFileName, void DataProcessor::LinkFileInMaster(const std::string &masterFileName,
@ -235,18 +235,14 @@ void DataProcessor::LinkFileInMaster(const std::string &masterFileName,
const bool silentMode, const bool silentMode,
std::mutex *hdf5LibMutex) { std::mutex *hdf5LibMutex) {
if (receiverRoiEnabled) {
throw std::runtime_error(
"Should not be here, roi with hdf5 virtual should throw.");
}
std::string fname{virtualFileName}, masterfname{masterFileName}; std::string fname{virtualFileName}, masterfname{masterFileName};
// if no virtual file, link data file // if no virtual file, link data file
if (virtualFileName.empty()) { if (virtualFileName.empty()) {
fname = dataFile->GetFileName(); fname = dataFile->GetFileName();
} }
masterFileUtility::LinkHDF5FileInMaster(masterfname, fname, masterFileUtility::LinkHDF5FileInMaster(
dataFile->GetParameterNames(), masterfname, fname, dataFile->GetParameterNames(), silentMode,
silentMode, hdf5LibMutex); hdf5LibMutex, multiRoiMetadata.size());
} }
#endif #endif
@ -301,7 +297,7 @@ void DataProcessor::ThreadExecution() {
// stream (if time/freq to stream) or free // stream (if time/freq to stream) or free
if (streamCurrentFrame) { if (streamCurrentFrame) {
// copy the complete image back if roi enabled // copy the complete image back if roi enabled
if (receiverRoiEnabled) { if (isPartiallyInRoi) {
memImage->size = generalData->imageSize; memImage->size = generalData->imageSize;
memcpy(memImage->data, &completeImageToStreamBeforeCropping[0], memcpy(memImage->data, &completeImageToStreamBeforeCropping[0],
generalData->imageSize); generalData->imageSize);
@ -381,7 +377,7 @@ void DataProcessor::ProcessAnImage(sls_receiver_header &header, size_t &size,
streamCurrentFrame = false; streamCurrentFrame = false;
} }
if (receiverRoiEnabled) { if (isPartiallyInRoi) {
// copy the complete image to stream before cropping // copy the complete image to stream before cropping
if (streamCurrentFrame) { if (streamCurrentFrame) {
memcpy(&completeImageToStreamBeforeCropping[0], data, memcpy(&completeImageToStreamBeforeCropping[0], data,
@ -687,12 +683,12 @@ void DataProcessor::ArrangeDbitData(size_t &size, char *data) {
} }
void DataProcessor::CropImage(size_t &size, char *data) { void DataProcessor::CropImage(size_t &size, char *data) {
LOG(logDEBUG) << "Cropping Image to ROI " << ToString(receiverRoi); LOG(logDEBUG1) << "Cropping Image to ROI " << ToString(portRoi);
int nPixelsX = generalData->nPixelsX; int nPixelsX = generalData->nPixelsX;
int xmin = receiverRoi.xmin; int xmin = portRoi.xmin;
int xmax = receiverRoi.xmax; int xmax = portRoi.xmax;
int ymin = receiverRoi.ymin; int ymin = portRoi.ymin;
int ymax = receiverRoi.ymax; int ymax = portRoi.ymax;
int xwidth = xmax - xmin + 1; int xwidth = xmax - xmin + 1;
int ywidth = ymax - ymin + 1; int ywidth = ymax - ymin + 1;
if (ymin == -1 || ymax == -1) { if (ymin == -1 || ymax == -1) {

View File

@ -39,7 +39,8 @@ class DataProcessor : private virtual slsDetectorDefs, public ThreadObject {
void SetUdpPortNumber(const uint16_t portNumber); void SetUdpPortNumber(const uint16_t portNumber);
void SetActivate(bool enable); void SetActivate(bool enable);
void SetReceiverROI(ROI roi); void SetPortROI(const ROI arg);
void setMultiROIMetadata(const std::vector<slsDetectorDefs::ROI> &args);
void SetDataStreamEnable(bool enable); void SetDataStreamEnable(bool enable);
void SetStreamingFrequency(uint32_t value); void SetStreamingFrequency(uint32_t value);
void SetStreamingTimerInMs(uint32_t value); void SetStreamingTimerInMs(uint32_t value);
@ -69,7 +70,7 @@ class DataProcessor : private virtual slsDetectorDefs, public ThreadObject {
const bool overWriteEnable, const bool overWriteEnable,
const bool silentMode, const int modulePos, const bool silentMode, const int modulePos,
const int numModX, const int numModY, const int numModX, const int numModY,
std::mutex *hdf5LibMutex); std::mutex *hdf5LibMutex, bool gotthard25um);
void LinkFileInMaster(const std::string &masterFileName, void LinkFileInMaster(const std::string &masterFileName,
const std::string &virtualFileName, const std::string &virtualFileName,
const bool silentMode, std::mutex *hdf5LibMutex); const bool silentMode, std::mutex *hdf5LibMutex);
@ -159,9 +160,11 @@ class DataProcessor : private virtual slsDetectorDefs, public ThreadObject {
uint16_t udpPortNumber{0}; uint16_t udpPortNumber{0};
bool dataStreamEnable; bool dataStreamEnable;
bool activated{false}; bool activated{false};
ROI receiverRoi{}; ROI portRoi{};
bool receiverRoiEnabled{false}; bool isPartiallyInRoi{false};
bool receiverNoRoi{false}; bool isOutsideRoi{false};
std::vector<ROI> multiRoiMetadata{};
std::unique_ptr<char[]> completeImageToStreamBeforeCropping; std::unique_ptr<char[]> completeImageToStreamBeforeCropping;
/** if 0, sending random images with a timer */ /** if 0, sending random images with a timer */
uint32_t streamingFrequency; uint32_t streamingFrequency;

View File

@ -53,7 +53,14 @@ void DataStreamer::SetAdditionalJsonHeader(
isAdditionalJsonUpdated = true; isAdditionalJsonUpdated = true;
} }
void DataStreamer::SetReceiverROI(ROI roi) { receiverRoi = roi; } void DataStreamer::SetPortROI(ROI roi) {
if (roi.completeRoi()) { // TODO: just not send zmq if not in roi?
portRoi =
ROI(0, generalData->nPixelsX - 1, 0, generalData->nPixelsY - 1);
} else {
portRoi = roi;
}
}
void DataStreamer::ResetParametersforNewAcquisition(const std::string &fname) { void DataStreamer::ResetParametersforNewAcquisition(const std::string &fname) {
StopRunning(); StopRunning();
@ -210,7 +217,7 @@ int DataStreamer::SendDataHeader(sls_detector_header header, uint32_t size,
isAdditionalJsonUpdated = false; isAdditionalJsonUpdated = false;
} }
zHeader.addJsonHeader = localAdditionalJsonHeader; zHeader.addJsonHeader = localAdditionalJsonHeader;
zHeader.rx_roi = receiverRoi.getIntArray(); zHeader.rx_roi = portRoi.getIntArray();
return zmqSocket->SendHeader(index, zHeader); return zmqSocket->SendHeader(index, zHeader);
} }

View File

@ -38,7 +38,7 @@ class DataStreamer : private virtual slsDetectorDefs, public ThreadObject {
void SetNumberofTotalFrames(uint64_t value); void SetNumberofTotalFrames(uint64_t value);
void void
SetAdditionalJsonHeader(const std::map<std::string, std::string> &json); SetAdditionalJsonHeader(const std::map<std::string, std::string> &json);
void SetReceiverROI(ROI roi); void SetPortROI(ROI roi);
void ResetParametersforNewAcquisition(const std::string &fname); void ResetParametersforNewAcquisition(const std::string &fname);
/** /**
@ -91,7 +91,7 @@ class DataStreamer : private virtual slsDetectorDefs, public ThreadObject {
uint64_t fileIndex{0}; uint64_t fileIndex{0};
bool flipRows{false}; bool flipRows{false};
std::map<std::string, std::string> additionalJsonHeader; std::map<std::string, std::string> additionalJsonHeader;
ROI receiverRoi{}; ROI portRoi{};
/** Used by streamer thread to update local copy (reduce number of locks /** Used by streamer thread to update local copy (reduce number of locks
* during streaming) */ * during streaming) */

View File

@ -155,6 +155,9 @@ void Implementation::setDetectorType(const detectorType d) {
break; break;
} }
// number of portrois should be equal to number of interfaces
ResetRois();
SetLocalNetworkParameters(); SetLocalNetworkParameters();
SetupFifoStructure(); SetupFifoStructure();
@ -184,7 +187,7 @@ void Implementation::SetupListener(int i) {
listener[i]->SetUdpPortNumber(udpPortNum[i]); listener[i]->SetUdpPortNumber(udpPortNum[i]);
listener[i]->SetEthernetInterface(eth[i]); listener[i]->SetEthernetInterface(eth[i]);
listener[i]->SetActivate(activated); listener[i]->SetActivate(activated);
listener[i]->SetNoRoi(portRois[i].noRoi()); listener[i]->SetIsOutsideRoi(portRois[i].noRoi());
listener[i]->SetDetectorDatastream(detectorDataStream[i]); listener[i]->SetDetectorDatastream(detectorDataStream[i]);
listener[i]->SetSilentMode(silentMode); listener[i]->SetSilentMode(silentMode);
} }
@ -194,7 +197,9 @@ void Implementation::SetupDataProcessor(int i) {
dataProcessor[i]->SetGeneralData(generalData); dataProcessor[i]->SetGeneralData(generalData);
dataProcessor[i]->SetUdpPortNumber(udpPortNum[i]); dataProcessor[i]->SetUdpPortNumber(udpPortNum[i]);
dataProcessor[i]->SetActivate(activated); dataProcessor[i]->SetActivate(activated);
dataProcessor[i]->SetReceiverROI(portRois[i]); dataProcessor[i]->SetPortROI(portRois[i]);
if (i == 0)
dataProcessor[0]->setMultiROIMetadata(multiRoiMetadata);
dataProcessor[i]->SetDataStreamEnable(dataStreamEnable); dataProcessor[i]->SetDataStreamEnable(dataStreamEnable);
dataProcessor[i]->SetStreamingFrequency(streamingFrequency); dataProcessor[i]->SetStreamingFrequency(streamingFrequency);
dataProcessor[i]->SetStreamingTimerInMs(streamingTimerInMs); dataProcessor[i]->SetStreamingTimerInMs(streamingTimerInMs);
@ -216,8 +221,7 @@ void Implementation::SetupDataStreamer(int i) {
dataStreamer[i]->SetFlipRows(flipRows); dataStreamer[i]->SetFlipRows(flipRows);
dataStreamer[i]->SetNumberofPorts(numPorts); dataStreamer[i]->SetNumberofPorts(numPorts);
dataStreamer[i]->SetNumberofTotalFrames(numberOfTotalFrames); dataStreamer[i]->SetNumberofTotalFrames(numberOfTotalFrames);
dataStreamer[i]->SetReceiverROI( dataStreamer[i]->SetPortROI(portRois[i]);
portRois[i].completeRoi() ? GetMaxROIPerPort() : portRois[i]);
} }
slsDetectorDefs::xy Implementation::getDetectorSize() const { slsDetectorDefs::xy Implementation::getDetectorSize() const {
@ -233,18 +237,13 @@ const slsDetectorDefs::xy Implementation::GetPortGeometry() const {
return portGeometry; 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) { void Implementation::setDetectorSize(const slsDetectorDefs::xy size) {
xy portGeometry = GetPortGeometry(); xy portGeometry = GetPortGeometry();
std::string log_message = "Detector Size (ports): ("; std::string log_message = "Detector Size (ports): (";
numModules = size; numModules = size;
numPorts.x = portGeometry.x * size.x; numPorts.x = portGeometry.x * numModules.x;
numPorts.y = portGeometry.y * size.y; numPorts.y = portGeometry.y * numModules.y;
if (quadEnable) { if (quadEnable) {
numPorts.x = 1; numPorts.x = 1;
numPorts.y = 2; numPorts.y = 2;
@ -401,97 +400,57 @@ void Implementation::setArping(const bool i,
} }
} }
slsDetectorDefs::ROI Implementation::getReceiverROI() const { std::vector<slsDetectorDefs::ROI> Implementation::getPortROIs() const {
return receiverRoi; return portRois;
} }
void Implementation::setReceiverROI(const slsDetectorDefs::ROI arg) { void Implementation::ResetRois() {
receiverRoi = arg; int numports = generalData->numUDPInterfaces;
std::vector<ROI> rois(numports);
std::vector<ROI> multiRoi(1);
setPortROIs(rois);
setMultiROIMetadata(multiRoi);
}
if (generalData->numUDPInterfaces == 1 || void Implementation::setPortROIs(const std::vector<defs::ROI> &args) {
generalData->detType == slsDetectorDefs::GOTTHARD2) { int nx = static_cast<int>(generalData->nPixelsX);
portRois[0] = arg; int ny = static_cast<int>(generalData->nPixelsY);
} else { // validate rois
slsDetectorDefs::xy nPortDim(generalData->nPixelsX, for (auto &it : args) {
generalData->nPixelsY); if (it.completeRoi() || it.noRoi()) {
continue; // valid
for (int iPort = 0; iPort != generalData->numUDPInterfaces; ++iPort) { }
// default init = complete roi if (it.xmin < 0 || it.xmax < 0 || it.xmin >= nx || it.xmax >= nx) {
slsDetectorDefs::ROI portRoi{}; throw RuntimeError("Invalid ROIvx coordinates: " + ToString(it));
}
// no roi if (ny > 1 &&
if (arg.noRoi()) { (it.ymin < 0 || it.ymax < 0 || it.ymin >= ny || it.ymax >= ny)) {
portRoi.setNoRoi(); throw RuntimeError("Invalid ROI y coordinates: " + ToString(it));
}
// 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;
} }
} }
portRois = args;
for (size_t i = 0; i != listener.size(); ++i) 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) 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) { for (size_t i = 0; i != dataStreamer.size(); ++i) {
dataStreamer[i]->SetReceiverROI( dataStreamer[i]->SetPortROI(portRois[i]);
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);
} }
LOG(logINFO) << "Rois (per port): " << ToString(portRois);
} }
void Implementation::setReceiverROIMetadata(const ROI arg) { void Implementation::setMultiROIMetadata(
receiverRoiMetadata = arg; const std::vector<slsDetectorDefs::ROI> &args) {
LOG(logINFO) << "receiver roi Metadata: " << ToString(receiverRoiMetadata); multiRoiMetadata = args;
if (dataProcessor.size() > 0)
dataProcessor[0]->setMultiROIMetadata(multiRoiMetadata);
LOG(logINFO) << "Multi ROI Metadata: " << ToString(multiRoiMetadata);
}
std::vector<slsDetectorDefs::ROI> Implementation::getMultiROIMetadata() const {
return multiRoiMetadata;
} }
/************************************************** /**************************************************
@ -787,8 +746,7 @@ void Implementation::stopReceiver() {
summary = (i == 0 ? "\n\tDeactivated Left Port" summary = (i == 0 ? "\n\tDeactivated Left Port"
: "\n\tDeactivated Right Port"); : "\n\tDeactivated Right Port");
} else if (portRois[i].noRoi()) { } else if (portRois[i].noRoi()) {
summary = (i == 0 ? "\n\tNo Roi on Left Port" summary = "\n\tNo Roi on Port[" + std::to_string(i) + ']';
: "\n\tNo Roi on Right Port");
} else { } else {
std::ostringstream os; std::ostringstream os;
os << "\n\tMissing Packets\t\t: " << mpMessage os << "\n\tMissing Packets\t\t: " << mpMessage
@ -958,7 +916,20 @@ void Implementation::StartMasterWriter() {
masterAttributes.framePadding = framePadding; masterAttributes.framePadding = framePadding;
masterAttributes.scanParams = scanParams; masterAttributes.scanParams = scanParams;
masterAttributes.totalFrames = numberOfTotalFrames; masterAttributes.totalFrames = numberOfTotalFrames;
masterAttributes.receiverRoi = receiverRoiMetadata; // complete ROI (for each port TODO?)
if (multiRoiMetadata.size() == 1 &&
multiRoiMetadata[0].completeRoi()) {
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.exptime = acquisitionTime;
masterAttributes.period = acquisitionPeriod; masterAttributes.period = acquisitionPeriod;
masterAttributes.burstMode = burstMode; masterAttributes.burstMode = burstMode;
@ -1019,14 +990,36 @@ void Implementation::StartMasterWriter() {
fileFormatType, &masterAttributes, &hdf5LibMutex); fileFormatType, &masterAttributes, &hdf5LibMutex);
} }
#ifdef HDF5C #ifdef HDF5C
// create virtual and master file
if (fileFormatType == HDF5) { 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; std::string virtualFileName;
// create virtual hdf5 file (if multiple files) // create virtual hdf5 file (if multiple files)
if (dataProcessor[0]->GetFilesInAcquisition() > 1 || if (dataProcessor[0]->GetFilesInAcquisition() > 1 ||
(numPorts.x * numPorts.y) > 1) { (numPorts.x * numPorts.y) > 1) {
virtualFileName = dataProcessor[0]->CreateVirtualFile( virtualFileName = dataProcessor[0]->CreateVirtualFile(
filePath, fileName, fileIndex, overwriteEnable, silentMode, filePath, fileName, fileIndex, overwriteEnable, silentMode,
modulePos, numPorts.x, numPorts.y, &hdf5LibMutex); modulePos, numPorts.x, numPorts.y, &hdf5LibMutex,
gotthard25um);
} }
// link file in master // link file in master
if (masterFileWriteEnable) { if (masterFileWriteEnable) {
@ -1087,8 +1080,9 @@ void Implementation::setNumberofUDPInterfaces(const int n) {
// fifo // fifo
SetupFifoStructure(); SetupFifoStructure();
// recalculate port rois
setReceiverROI(receiverRoi); // number of portrois should be equal to number of interfaces
ResetRois();
// create threads // create threads
for (int i = 0; i < generalData->numUDPInterfaces; ++i) { for (int i = 0; i < generalData->numUDPInterfaces; ++i) {

View File

@ -58,9 +58,10 @@ class Implementation : private virtual slsDetectorDefs {
bool getArping() const; bool getArping() const;
pid_t getArpingProcessId() const; pid_t getArpingProcessId() const;
void setArping(const bool i, const std::vector<std::string> ips); void setArping(const bool i, const std::vector<std::string> ips);
ROI getReceiverROI() const; std::vector<defs::ROI> getPortROIs() const;
void setReceiverROI(const ROI arg); void setPortROIs(const std::vector<defs::ROI> &args);
void setReceiverROIMetadata(const ROI arg); void setMultiROIMetadata(const std::vector<slsDetectorDefs::ROI> &args);
std::vector<slsDetectorDefs::ROI> getMultiROIMetadata() const;
/************************************************** /**************************************************
* * * *
@ -283,7 +284,7 @@ class Implementation : private virtual slsDetectorDefs {
void SetupFifoStructure(); void SetupFifoStructure();
const xy GetPortGeometry() const; const xy GetPortGeometry() const;
const ROI GetMaxROIPerPort() const; void ResetRois();
void ResetParametersforNewAcquisition(); void ResetParametersforNewAcquisition();
void CreateUDPSockets(); void CreateUDPSockets();
void SetupWriter(); void SetupWriter();
@ -308,10 +309,8 @@ class Implementation : private virtual slsDetectorDefs {
bool framePadding{true}; bool framePadding{true};
pid_t parentThreadId; pid_t parentThreadId;
pid_t tcpThreadId; pid_t tcpThreadId;
ROI receiverRoi{}; std::vector<slsDetectorDefs::ROI> portRois;
std::array<ROI, 2> portRois{}; std::vector<slsDetectorDefs::ROI> multiRoiMetadata;
// receiver roi for complete detector for metadata
ROI receiverRoiMetadata{};
// file parameters // file parameters
fileFormat fileFormatType{BINARY}; fileFormat fileFormatType{BINARY};

View File

@ -85,17 +85,17 @@ void Listener::SetEthernetInterface(const std::string e) {
void Listener::SetActivate(bool enable) { void Listener::SetActivate(bool enable) {
activated = enable; activated = enable;
disabledPort = (!activated || !detectorDataStream || noRoi); disabledPort = (!activated || !detectorDataStream || isOutsideRoi);
} }
void Listener::SetDetectorDatastream(bool enable) { void Listener::SetDetectorDatastream(bool enable) {
detectorDataStream = enable; detectorDataStream = enable;
disabledPort = (!activated || !detectorDataStream || noRoi); disabledPort = (!activated || !detectorDataStream || isOutsideRoi);
} }
void Listener::SetNoRoi(bool enable) { void Listener::SetIsOutsideRoi(bool enable) {
noRoi = enable; isOutsideRoi = enable;
disabledPort = (!activated || !detectorDataStream || noRoi); disabledPort = (!activated || !detectorDataStream || isOutsideRoi);
} }
void Listener::SetSilentMode(bool enable) { silentMode = enable; } void Listener::SetSilentMode(bool enable) { silentMode = enable; }

View File

@ -43,7 +43,7 @@ class Listener : private virtual slsDetectorDefs, public ThreadObject {
void SetEthernetInterface(const std::string e); void SetEthernetInterface(const std::string e);
void SetActivate(bool enable); void SetActivate(bool enable);
void SetDetectorDatastream(bool enable); void SetDetectorDatastream(bool enable);
void SetNoRoi(bool enable); void SetIsOutsideRoi(bool enable);
void SetSilentMode(bool enable); void SetSilentMode(bool enable);
void ResetParametersforNewAcquisition(); void ResetParametersforNewAcquisition();
@ -116,7 +116,7 @@ class Listener : private virtual slsDetectorDefs, public ThreadObject {
std::string eth; std::string eth;
bool activated{false}; bool activated{false};
bool detectorDataStream{true}; bool detectorDataStream{true};
bool noRoi{false}; bool isOutsideRoi{false};
bool silentMode; bool silentMode;
bool disabledPort{false}; bool disabledPort{false};

View File

@ -43,30 +43,30 @@ void MasterAttributes::WriteHDF5Attributes(H5::H5File *fd, H5::Group *group) {
WriteCommonHDF5Attributes(fd, group); WriteCommonHDF5Attributes(fd, group);
switch (detType) { switch (detType) {
case slsDetectorDefs::JUNGFRAU: case slsDetectorDefs::JUNGFRAU:
WriteJungfrauHDF5Attributes(fd, group); WriteJungfrauHDF5Attributes(group);
break; break;
case slsDetectorDefs::MOENCH: case slsDetectorDefs::MOENCH:
WriteMoenchHDF5Attributes(fd, group); WriteMoenchHDF5Attributes(group);
break; break;
case slsDetectorDefs::EIGER: case slsDetectorDefs::EIGER:
WriteEigerHDF5Attributes(fd, group); WriteEigerHDF5Attributes(group);
break; break;
case slsDetectorDefs::MYTHEN3: case slsDetectorDefs::MYTHEN3:
WriteMythen3HDF5Attributes(fd, group); WriteMythen3HDF5Attributes(group);
break; break;
case slsDetectorDefs::GOTTHARD2: case slsDetectorDefs::GOTTHARD2:
WriteGotthard2HDF5Attributes(fd, group); WriteGotthard2HDF5Attributes(group);
break; break;
case slsDetectorDefs::CHIPTESTBOARD: case slsDetectorDefs::CHIPTESTBOARD:
WriteCtbHDF5Attributes(fd, group); WriteCtbHDF5Attributes(group);
break; break;
case slsDetectorDefs::XILINX_CHIPTESTBOARD: case slsDetectorDefs::XILINX_CHIPTESTBOARD:
WriteXilinxCtbHDF5Attributes(fd, group); WriteXilinxCtbHDF5Attributes(group);
break; break;
default: default:
throw RuntimeError("Unknown Detector type to get master attributes"); throw RuntimeError("Unknown Detector type to get master attributes");
} }
WriteFinalHDF5Attributes(fd, group); WriteFinalHDF5Attributes(group);
} }
#endif #endif
@ -110,17 +110,6 @@ void MasterAttributes::GetCommonBinaryAttributes(
w->String(ToString(scanParams).c_str()); w->String(ToString(scanParams).c_str());
w->Key("Total Frames"); w->Key("Total Frames");
w->Uint64(totalFrames); 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( void MasterAttributes::GetFinalBinaryAttributes(
@ -165,6 +154,17 @@ void MasterAttributes::GetFinalBinaryAttributes(
w->EndObject(); w->EndObject();
} }
void MasterAttributes::GetBinaryRois(
rapidjson::PrettyWriter<rapidjson::StringBuffer> *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 #ifdef HDF5C
void MasterAttributes::WriteCommonHDF5Attributes(H5::H5File *fd, void MasterAttributes::WriteCommonHDF5Attributes(H5::H5File *fd,
H5::Group *group) { H5::Group *group) {
@ -287,38 +287,9 @@ void MasterAttributes::WriteCommonHDF5Attributes(H5::H5File *fd,
"Total Frames", H5::PredType::STD_U64LE, dataspace); "Total Frames", H5::PredType::STD_U64LE, dataspace);
dataset.write(&totalFrames, H5::PredType::STD_U64LE); 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, void MasterAttributes::WriteFinalHDF5Attributes(H5::Group *group) {
H5::Group *group) {
char c[1024]{}; char c[1024]{};
// Total Frames in file // Total Frames in file
{ {
@ -339,7 +310,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<char[1024]> 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::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::StrType strdatatype(H5::PredType::C_S1, 256); H5::StrType strdatatype(H5::PredType::C_S1, 256);
H5::DataSet dataset = H5::DataSet dataset =
@ -349,7 +333,7 @@ void MasterAttributes::WriteHDF5Exptime(H5::H5File *fd, H5::Group *group) {
dataset.write(c, strdatatype); 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::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::StrType strdatatype(H5::PredType::C_S1, 256); H5::StrType strdatatype(H5::PredType::C_S1, 256);
H5::DataSet dataset = H5::DataSet dataset =
@ -359,7 +343,7 @@ void MasterAttributes::WriteHDF5Period(H5::H5File *fd, H5::Group *group) {
dataset.write(c, strdatatype); 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::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::DataSet dataset = group->createDataSet( H5::DataSet dataset = group->createDataSet(
"Dynamic Range", H5::PredType::NATIVE_INT, dataspace); "Dynamic Range", H5::PredType::NATIVE_INT, dataspace);
@ -372,30 +356,28 @@ void MasterAttributes::WriteHDF5DynamicRange(H5::H5File *fd, H5::Group *group) {
attribute.write(strdatatype, c); 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::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::DataSet dataset = group->createDataSet( H5::DataSet dataset = group->createDataSet(
"Ten Giga Enable", H5::PredType::NATIVE_INT, dataspace); "Ten Giga Enable", H5::PredType::NATIVE_INT, dataspace);
dataset.write(&tenGiga, H5::PredType::NATIVE_INT); dataset.write(&tenGiga, H5::PredType::NATIVE_INT);
} }
void MasterAttributes::WriteHDF5NumUDPInterfaces(H5::H5File *fd, void MasterAttributes::WriteHDF5NumUDPInterfaces(H5::Group *group) {
H5::Group *group) {
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR); H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::DataSet dataset = group->createDataSet( H5::DataSet dataset = group->createDataSet(
"Number of UDP Interfaces", H5::PredType::NATIVE_INT, dataspace); "Number of UDP Interfaces", H5::PredType::NATIVE_INT, dataspace);
dataset.write(&numUDPInterfaces, H5::PredType::NATIVE_INT); 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::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::DataSet dataset = group->createDataSet( H5::DataSet dataset = group->createDataSet(
"Number of rows", H5::PredType::NATIVE_INT, dataspace); "Number of rows", H5::PredType::NATIVE_INT, dataspace);
dataset.write(&readNRows, H5::PredType::NATIVE_INT); dataset.write(&readNRows, H5::PredType::NATIVE_INT);
} }
void MasterAttributes::WriteHDF5ThresholdEnergy(H5::H5File *fd, void MasterAttributes::WriteHDF5ThresholdEnergy(H5::Group *group) {
H5::Group *group) {
char c[1024]{}; char c[1024]{};
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR); H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::DataSet dataset = group->createDataSet( H5::DataSet dataset = group->createDataSet(
@ -409,8 +391,7 @@ void MasterAttributes::WriteHDF5ThresholdEnergy(H5::H5File *fd,
attribute.write(strdatatype, c); attribute.write(strdatatype, c);
} }
void MasterAttributes::WriteHDF5ThresholdEnergies(H5::H5File *fd, void MasterAttributes::WriteHDF5ThresholdEnergies(H5::Group *group) {
H5::Group *group) {
char c[1024]{}; char c[1024]{};
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR); H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::StrType strdatatype(H5::PredType::C_S1, 1024); H5::StrType strdatatype(H5::PredType::C_S1, 1024);
@ -420,7 +401,7 @@ void MasterAttributes::WriteHDF5ThresholdEnergies(H5::H5File *fd,
dataset.write(c, strdatatype); dataset.write(c, strdatatype);
} }
void MasterAttributes::WriteHDF5SubExpTime(H5::H5File *fd, H5::Group *group) { void MasterAttributes::WriteHDF5SubExpTime(H5::Group *group) {
char c[1024]{}; char c[1024]{};
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR); H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::StrType strdatatype(H5::PredType::C_S1, 256); H5::StrType strdatatype(H5::PredType::C_S1, 256);
@ -430,7 +411,7 @@ void MasterAttributes::WriteHDF5SubExpTime(H5::H5File *fd, H5::Group *group) {
dataset.write(c, strdatatype); dataset.write(c, strdatatype);
} }
void MasterAttributes::WriteHDF5SubPeriod(H5::H5File *fd, H5::Group *group) { void MasterAttributes::WriteHDF5SubPeriod(H5::Group *group) {
char c[1024]{}; char c[1024]{};
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR); H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::StrType strdatatype(H5::PredType::C_S1, 256); H5::StrType strdatatype(H5::PredType::C_S1, 256);
@ -440,15 +421,14 @@ void MasterAttributes::WriteHDF5SubPeriod(H5::H5File *fd, H5::Group *group) {
dataset.write(c, strdatatype); 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::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::DataSet dataset = H5::DataSet dataset =
group->createDataSet("Quad", H5::PredType::NATIVE_INT, dataspace); group->createDataSet("Quad", H5::PredType::NATIVE_INT, dataspace);
dataset.write(&quad, H5::PredType::NATIVE_INT); dataset.write(&quad, H5::PredType::NATIVE_INT);
} }
void MasterAttributes::WriteHDF5RateCorrections(H5::H5File *fd, void MasterAttributes::WriteHDF5RateCorrections(H5::Group *group) {
H5::Group *group) {
char c[1024]{}; char c[1024]{};
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR); H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::StrType strdatatype(H5::PredType::C_S1, 1024); H5::StrType strdatatype(H5::PredType::C_S1, 1024);
@ -458,14 +438,14 @@ void MasterAttributes::WriteHDF5RateCorrections(H5::H5File *fd,
dataset.write(c, strdatatype); 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::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::DataSet dataset = group->createDataSet( H5::DataSet dataset = group->createDataSet(
"Counter Mask", H5::PredType::STD_U32LE, dataspace); "Counter Mask", H5::PredType::STD_U32LE, dataspace);
dataset.write(&counterMask, H5::PredType::STD_U32LE); 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) { for (int i = 0; i != 3; ++i) {
char c[1024]{}; char c[1024]{};
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR); H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
@ -477,8 +457,7 @@ void MasterAttributes::WriteHDF5ExptimeArray(H5::H5File *fd, H5::Group *group) {
} }
} }
void MasterAttributes::WriteHDF5GateDelayArray(H5::H5File *fd, void MasterAttributes::WriteHDF5GateDelayArray(H5::Group *group) {
H5::Group *group) {
for (int i = 0; i != 3; ++i) { for (int i = 0; i != 3; ++i) {
char c[1024]{}; char c[1024]{};
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR); H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
@ -490,14 +469,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::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::DataSet dataset = H5::DataSet dataset =
group->createDataSet("Gates", H5::PredType::STD_U32LE, dataspace); group->createDataSet("Gates", H5::PredType::STD_U32LE, dataspace);
dataset.write(&gates, H5::PredType::STD_U32LE); 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::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::StrType strdatatype(H5::PredType::C_S1, 256); H5::StrType strdatatype(H5::PredType::C_S1, 256);
H5::DataSet dataset = H5::DataSet dataset =
@ -507,82 +486,77 @@ void MasterAttributes::WriteHDF5BurstMode(H5::H5File *fd, H5::Group *group) {
dataset.write(c, strdatatype); 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::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::DataSet dataset = H5::DataSet dataset =
group->createDataSet("ADC Mask", H5::PredType::NATIVE_INT, dataspace); group->createDataSet("ADC Mask", H5::PredType::NATIVE_INT, dataspace);
dataset.write(&adcmask, H5::PredType::NATIVE_INT); 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::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::DataSet dataset = group->createDataSet( H5::DataSet dataset = group->createDataSet(
"Analog Flag", H5::PredType::NATIVE_INT, dataspace); "Analog Flag", H5::PredType::NATIVE_INT, dataspace);
dataset.write(&analog, H5::PredType::NATIVE_INT); dataset.write(&analog, H5::PredType::NATIVE_INT);
} }
void MasterAttributes::WriteHDF5AnalogSamples(H5::H5File *fd, void MasterAttributes::WriteHDF5AnalogSamples(H5::Group *group) {
H5::Group *group) {
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR); H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::DataSet dataset = group->createDataSet( H5::DataSet dataset = group->createDataSet(
"Analog Samples", H5::PredType::NATIVE_INT, dataspace); "Analog Samples", H5::PredType::NATIVE_INT, dataspace);
dataset.write(&analogSamples, H5::PredType::NATIVE_INT); 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::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::DataSet dataset = group->createDataSet( H5::DataSet dataset = group->createDataSet(
"Digital Flag", H5::PredType::NATIVE_INT, dataspace); "Digital Flag", H5::PredType::NATIVE_INT, dataspace);
dataset.write(&digital, H5::PredType::NATIVE_INT); dataset.write(&digital, H5::PredType::NATIVE_INT);
} }
void MasterAttributes::WriteHDF5DigitalSamples(H5::H5File *fd, void MasterAttributes::WriteHDF5DigitalSamples(H5::Group *group) {
H5::Group *group) {
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR); H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::DataSet dataset = group->createDataSet( H5::DataSet dataset = group->createDataSet(
"Digital Samples", H5::PredType::NATIVE_INT, dataspace); "Digital Samples", H5::PredType::NATIVE_INT, dataspace);
dataset.write(&digitalSamples, H5::PredType::NATIVE_INT); 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::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::DataSet dataset = group->createDataSet( H5::DataSet dataset = group->createDataSet(
"Dbit Offset", H5::PredType::NATIVE_INT, dataspace); "Dbit Offset", H5::PredType::NATIVE_INT, dataspace);
dataset.write(&dbitoffset, H5::PredType::NATIVE_INT); 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::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::DataSet dataset = group->createDataSet( H5::DataSet dataset = group->createDataSet(
"Dbit Reorder", H5::PredType::NATIVE_INT, dataspace); "Dbit Reorder", H5::PredType::NATIVE_INT, dataspace);
dataset.write(&dbitreorder, H5::PredType::NATIVE_INT); 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::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::DataSet dataset = group->createDataSet( H5::DataSet dataset = group->createDataSet(
"Dbit Bitset List", H5::PredType::STD_U64LE, dataspace); "Dbit Bitset List", H5::PredType::STD_U64LE, dataspace);
dataset.write(&dbitlist, H5::PredType::STD_U64LE); dataset.write(&dbitlist, H5::PredType::STD_U64LE);
} }
void MasterAttributes::WriteHDF5TransceiverMask(H5::H5File *fd, void MasterAttributes::WriteHDF5TransceiverMask(H5::Group *group) {
H5::Group *group) {
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR); H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::DataSet dataset = group->createDataSet( H5::DataSet dataset = group->createDataSet(
"Transceiver Mask", H5::PredType::NATIVE_INT, dataspace); "Transceiver Mask", H5::PredType::NATIVE_INT, dataspace);
dataset.write(&transceiverMask, H5::PredType::NATIVE_INT); dataset.write(&transceiverMask, H5::PredType::NATIVE_INT);
} }
void MasterAttributes::WriteHDF5TransceiverFlag(H5::H5File *fd, void MasterAttributes::WriteHDF5TransceiverFlag(H5::Group *group) {
H5::Group *group) {
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR); H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::DataSet dataset = group->createDataSet( H5::DataSet dataset = group->createDataSet(
"Transceiver Flag", H5::PredType::NATIVE_INT, dataspace); "Transceiver Flag", H5::PredType::NATIVE_INT, dataspace);
dataset.write(&transceiver, H5::PredType::NATIVE_INT); dataset.write(&transceiver, H5::PredType::NATIVE_INT);
} }
void MasterAttributes::WriteHDF5TransceiverSamples(H5::H5File *fd, void MasterAttributes::WriteHDF5TransceiverSamples(H5::Group *group) {
H5::Group *group) {
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR); H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
H5::DataSet dataset = group->createDataSet( H5::DataSet dataset = group->createDataSet(
"Transceiver Samples", H5::PredType::NATIVE_INT, dataspace); "Transceiver Samples", H5::PredType::NATIVE_INT, dataspace);
@ -592,6 +566,7 @@ void MasterAttributes::WriteHDF5TransceiverSamples(H5::H5File *fd,
void MasterAttributes::GetJungfrauBinaryAttributes( void MasterAttributes::GetJungfrauBinaryAttributes(
rapidjson::PrettyWriter<rapidjson::StringBuffer> *w) { rapidjson::PrettyWriter<rapidjson::StringBuffer> *w) {
GetBinaryRois(w);
w->Key("Exptime"); w->Key("Exptime");
w->String(ToString(exptime).c_str()); w->String(ToString(exptime).c_str());
w->Key("Period"); w->Key("Period");
@ -603,17 +578,18 @@ void MasterAttributes::GetJungfrauBinaryAttributes(
} }
#ifdef HDF5C #ifdef HDF5C
void MasterAttributes::WriteJungfrauHDF5Attributes(H5::H5File *fd, void MasterAttributes::WriteJungfrauHDF5Attributes(H5::Group *group) {
H5::Group *group) { MasterAttributes::WriteHDF5ROIs(group);
MasterAttributes::WriteHDF5Exptime(fd, group); MasterAttributes::WriteHDF5Exptime(group);
MasterAttributes::WriteHDF5Period(fd, group); MasterAttributes::WriteHDF5Period(group);
MasterAttributes::WriteHDF5NumUDPInterfaces(fd, group); MasterAttributes::WriteHDF5NumUDPInterfaces(group);
MasterAttributes::WriteHDF5ReadNRows(fd, group); MasterAttributes::WriteHDF5ReadNRows(group);
} }
#endif #endif
void MasterAttributes::GetMoenchBinaryAttributes( void MasterAttributes::GetMoenchBinaryAttributes(
rapidjson::PrettyWriter<rapidjson::StringBuffer> *w) { rapidjson::PrettyWriter<rapidjson::StringBuffer> *w) {
GetBinaryRois(w);
w->Key("Exptime"); w->Key("Exptime");
w->String(ToString(exptime).c_str()); w->String(ToString(exptime).c_str());
w->Key("Period"); w->Key("Period");
@ -625,17 +601,18 @@ void MasterAttributes::GetMoenchBinaryAttributes(
} }
#ifdef HDF5C #ifdef HDF5C
void MasterAttributes::WriteMoenchHDF5Attributes(H5::H5File *fd, void MasterAttributes::WriteMoenchHDF5Attributes(H5::Group *group) {
H5::Group *group) { MasterAttributes::WriteHDF5ROIs(group);
MasterAttributes::WriteHDF5Exptime(fd, group); MasterAttributes::WriteHDF5Exptime(group);
MasterAttributes::WriteHDF5Period(fd, group); MasterAttributes::WriteHDF5Period(group);
MasterAttributes::WriteHDF5NumUDPInterfaces(fd, group); MasterAttributes::WriteHDF5NumUDPInterfaces(group);
MasterAttributes::WriteHDF5ReadNRows(fd, group); MasterAttributes::WriteHDF5ReadNRows(group);
} }
#endif #endif
void MasterAttributes::GetEigerBinaryAttributes( void MasterAttributes::GetEigerBinaryAttributes(
rapidjson::PrettyWriter<rapidjson::StringBuffer> *w) { rapidjson::PrettyWriter<rapidjson::StringBuffer> *w) {
GetBinaryRois(w);
w->Key("Dynamic Range"); w->Key("Dynamic Range");
w->Uint(dynamicRange); w->Uint(dynamicRange);
w->Key("Ten Giga"); w->Key("Ten Giga");
@ -659,23 +636,24 @@ void MasterAttributes::GetEigerBinaryAttributes(
} }
#ifdef HDF5C #ifdef HDF5C
void MasterAttributes::WriteEigerHDF5Attributes(H5::H5File *fd, void MasterAttributes::WriteEigerHDF5Attributes(H5::Group *group) {
H5::Group *group) { MasterAttributes::WriteHDF5ROIs(group);
MasterAttributes::WriteHDF5DynamicRange(fd, group); MasterAttributes::WriteHDF5DynamicRange(group);
MasterAttributes::WriteHDF5TenGiga(fd, group); MasterAttributes::WriteHDF5TenGiga(group);
MasterAttributes::WriteHDF5Exptime(fd, group); MasterAttributes::WriteHDF5Exptime(group);
MasterAttributes::WriteHDF5Period(fd, group); MasterAttributes::WriteHDF5Period(group);
MasterAttributes::WriteHDF5ThresholdEnergy(fd, group); MasterAttributes::WriteHDF5ThresholdEnergy(group);
MasterAttributes::WriteHDF5SubExpTime(fd, group); MasterAttributes::WriteHDF5SubExpTime(group);
MasterAttributes::WriteHDF5SubPeriod(fd, group); MasterAttributes::WriteHDF5SubPeriod(group);
MasterAttributes::WriteHDF5SubQuad(fd, group); MasterAttributes::WriteHDF5SubQuad(group);
MasterAttributes::WriteHDF5ReadNRows(fd, group); MasterAttributes::WriteHDF5ReadNRows(group);
MasterAttributes::WriteHDF5RateCorrections(fd, group); MasterAttributes::WriteHDF5RateCorrections(group);
} }
#endif #endif
void MasterAttributes::GetMythen3BinaryAttributes( void MasterAttributes::GetMythen3BinaryAttributes(
rapidjson::PrettyWriter<rapidjson::StringBuffer> *w) { rapidjson::PrettyWriter<rapidjson::StringBuffer> *w) {
GetBinaryRois(w);
w->Key("Dynamic Range"); w->Key("Dynamic Range");
w->Uint(dynamicRange); w->Uint(dynamicRange);
w->Key("Ten Giga"); w->Key("Ten Giga");
@ -699,21 +677,22 @@ void MasterAttributes::GetMythen3BinaryAttributes(
} }
#ifdef HDF5C #ifdef HDF5C
void MasterAttributes::WriteMythen3HDF5Attributes(H5::H5File *fd, void MasterAttributes::WriteMythen3HDF5Attributes(H5::Group *group) {
H5::Group *group) { MasterAttributes::WriteHDF5ROIs(group);
MasterAttributes::WriteHDF5DynamicRange(fd, group); MasterAttributes::WriteHDF5DynamicRange(group);
MasterAttributes::WriteHDF5TenGiga(fd, group); MasterAttributes::WriteHDF5TenGiga(group);
MasterAttributes::WriteHDF5Period(fd, group); MasterAttributes::WriteHDF5Period(group);
MasterAttributes::WriteHDF5CounterMask(fd, group); MasterAttributes::WriteHDF5CounterMask(group);
MasterAttributes::WriteHDF5ExptimeArray(fd, group); MasterAttributes::WriteHDF5ExptimeArray(group);
MasterAttributes::WriteHDF5GateDelayArray(fd, group); MasterAttributes::WriteHDF5GateDelayArray(group);
MasterAttributes::WriteHDF5Gates(fd, group); MasterAttributes::WriteHDF5Gates(group);
MasterAttributes::WriteHDF5ThresholdEnergies(fd, group); MasterAttributes::WriteHDF5ThresholdEnergies(group);
} }
#endif #endif
void MasterAttributes::GetGotthard2BinaryAttributes( void MasterAttributes::GetGotthard2BinaryAttributes(
rapidjson::PrettyWriter<rapidjson::StringBuffer> *w) { rapidjson::PrettyWriter<rapidjson::StringBuffer> *w) {
GetBinaryRois(w);
w->Key("Exptime"); w->Key("Exptime");
w->String(ToString(exptime).c_str()); w->String(ToString(exptime).c_str());
w->Key("Period"); w->Key("Period");
@ -723,11 +702,11 @@ void MasterAttributes::GetGotthard2BinaryAttributes(
} }
#ifdef HDF5C #ifdef HDF5C
void MasterAttributes::WriteGotthard2HDF5Attributes(H5::H5File *fd, void MasterAttributes::WriteGotthard2HDF5Attributes(H5::Group *group) {
H5::Group *group) { MasterAttributes::WriteHDF5ROIs(group);
MasterAttributes::WriteHDF5Exptime(fd, group); MasterAttributes::WriteHDF5Exptime(group);
MasterAttributes::WriteHDF5Period(fd, group); MasterAttributes::WriteHDF5Period(group);
MasterAttributes::WriteHDF5BurstMode(fd, group); MasterAttributes::WriteHDF5BurstMode(group);
} }
#endif #endif
@ -764,22 +743,21 @@ void MasterAttributes::GetCtbBinaryAttributes(
} }
#ifdef HDF5C #ifdef HDF5C
void MasterAttributes::WriteCtbHDF5Attributes(H5::H5File *fd, void MasterAttributes::WriteCtbHDF5Attributes(H5::Group *group) {
H5::Group *group) { MasterAttributes::WriteHDF5Exptime(group);
MasterAttributes::WriteHDF5Exptime(fd, group); MasterAttributes::WriteHDF5Period(group);
MasterAttributes::WriteHDF5Period(fd, group); MasterAttributes::WriteHDF5TenGiga(group);
MasterAttributes::WriteHDF5TenGiga(fd, group); MasterAttributes::WriteHDF5AdcMask(group);
MasterAttributes::WriteHDF5AdcMask(fd, group); MasterAttributes::WriteHDF5AnalogFlag(group);
MasterAttributes::WriteHDF5AnalogFlag(fd, group); MasterAttributes::WriteHDF5AnalogSamples(group);
MasterAttributes::WriteHDF5AnalogSamples(fd, group); MasterAttributes::WriteHDF5DigitalFlag(group);
MasterAttributes::WriteHDF5DigitalFlag(fd, group); MasterAttributes::WriteHDF5DigitalSamples(group);
MasterAttributes::WriteHDF5DigitalSamples(fd, group); MasterAttributes::WriteHDF5DbitOffset(group);
MasterAttributes::WriteHDF5DbitOffset(fd, group); MasterAttributes::WriteHDF5DbitReorder(group);
MasterAttributes::WriteHDF5DbitReorder(fd, group); MasterAttributes::WriteHDF5DbitList(group);
MasterAttributes::WriteHDF5DbitList(fd, group); MasterAttributes::WriteHDF5TransceiverMask(group);
MasterAttributes::WriteHDF5TransceiverMask(fd, group); MasterAttributes::WriteHDF5TransceiverFlag(group);
MasterAttributes::WriteHDF5TransceiverFlag(fd, group); MasterAttributes::WriteHDF5TransceiverSamples(group);
MasterAttributes::WriteHDF5TransceiverSamples(fd, group);
} }
#endif #endif
@ -814,21 +792,20 @@ void MasterAttributes::GetXilinxCtbBinaryAttributes(
} }
#ifdef HDF5C #ifdef HDF5C
void MasterAttributes::WriteXilinxCtbHDF5Attributes(H5::H5File *fd, void MasterAttributes::WriteXilinxCtbHDF5Attributes(H5::Group *group) {
H5::Group *group) { MasterAttributes::WriteHDF5Exptime(group);
MasterAttributes::WriteHDF5Exptime(fd, group); MasterAttributes::WriteHDF5Period(group);
MasterAttributes::WriteHDF5Period(fd, group); MasterAttributes::WriteHDF5AdcMask(group);
MasterAttributes::WriteHDF5AdcMask(fd, group); MasterAttributes::WriteHDF5AnalogFlag(group);
MasterAttributes::WriteHDF5AnalogFlag(fd, group); MasterAttributes::WriteHDF5AnalogSamples(group);
MasterAttributes::WriteHDF5AnalogSamples(fd, group); MasterAttributes::WriteHDF5DigitalFlag(group);
MasterAttributes::WriteHDF5DigitalFlag(fd, group); MasterAttributes::WriteHDF5DigitalSamples(group);
MasterAttributes::WriteHDF5DigitalSamples(fd, group); MasterAttributes::WriteHDF5DbitOffset(group);
MasterAttributes::WriteHDF5DbitOffset(fd, group); MasterAttributes::WriteHDF5DbitReorder(group);
MasterAttributes::WriteHDF5DbitReorder(fd, group); MasterAttributes::WriteHDF5DbitList(group);
MasterAttributes::WriteHDF5DbitList(fd, group); MasterAttributes::WriteHDF5TransceiverMask(group);
MasterAttributes::WriteHDF5TransceiverMask(fd, group); MasterAttributes::WriteHDF5TransceiverFlag(group);
MasterAttributes::WriteHDF5TransceiverFlag(fd, group); MasterAttributes::WriteHDF5TransceiverSamples(group);
MasterAttributes::WriteHDF5TransceiverSamples(fd, group);
} }
#endif #endif
} // namespace sls } // namespace sls

View File

@ -57,7 +57,7 @@ class MasterAttributes {
uint32_t transceiverMask{0}; uint32_t transceiverMask{0};
uint32_t transceiver{0}; uint32_t transceiver{0};
uint32_t transceiverSamples{0}; uint32_t transceiverSamples{0};
slsDetectorDefs::ROI receiverRoi{}; std::vector<slsDetectorDefs::ROI> rois{};
uint32_t counterMask{0}; uint32_t counterMask{0};
std::array<ns, 3> exptimeArray{}; std::array<ns, 3> exptimeArray{};
std::array<ns, 3> gateDelayArray{}; std::array<ns, 3> gateDelayArray{};
@ -78,79 +78,81 @@ class MasterAttributes {
rapidjson::PrettyWriter<rapidjson::StringBuffer> *w); rapidjson::PrettyWriter<rapidjson::StringBuffer> *w);
void GetFinalBinaryAttributes( void GetFinalBinaryAttributes(
rapidjson::PrettyWriter<rapidjson::StringBuffer> *w); rapidjson::PrettyWriter<rapidjson::StringBuffer> *w);
void GetBinaryRois(rapidjson::PrettyWriter<rapidjson::StringBuffer> *w);
#ifdef HDF5C #ifdef HDF5C
void WriteCommonHDF5Attributes(H5::H5File *fd, H5::Group *group); void WriteCommonHDF5Attributes(H5::H5File *fd, H5::Group *group);
void WriteFinalHDF5Attributes(H5::H5File *fd, H5::Group *group); void WriteFinalHDF5Attributes(H5::Group *group);
void WriteHDF5Exptime(H5::H5File *fd, H5::Group *group); void WriteHDF5ROIs(H5::Group *group);
void WriteHDF5Period(H5::H5File *fd, H5::Group *group); void WriteHDF5Exptime(H5::Group *group);
void WriteHDF5DynamicRange(H5::H5File *fd, H5::Group *group); void WriteHDF5Period(H5::Group *group);
void WriteHDF5TenGiga(H5::H5File *fd, H5::Group *group); void WriteHDF5DynamicRange(H5::Group *group);
void WriteHDF5NumUDPInterfaces(H5::H5File *fd, H5::Group *group); void WriteHDF5TenGiga(H5::Group *group);
void WriteHDF5ReadNRows(H5::H5File *fd, H5::Group *group); void WriteHDF5NumUDPInterfaces(H5::Group *group);
void WriteHDF5ThresholdEnergy(H5::H5File *fd, H5::Group *group); void WriteHDF5ReadNRows(H5::Group *group);
void WriteHDF5ThresholdEnergies(H5::H5File *fd, H5::Group *group); void WriteHDF5ThresholdEnergy(H5::Group *group);
void WriteHDF5SubExpTime(H5::H5File *fd, H5::Group *group); void WriteHDF5ThresholdEnergies(H5::Group *group);
void WriteHDF5SubPeriod(H5::H5File *fd, H5::Group *group); void WriteHDF5SubExpTime(H5::Group *group);
void WriteHDF5SubQuad(H5::H5File *fd, H5::Group *group); void WriteHDF5SubPeriod(H5::Group *group);
void WriteHDF5RateCorrections(H5::H5File *fd, H5::Group *group); void WriteHDF5SubQuad(H5::Group *group);
void WriteHDF5CounterMask(H5::H5File *fd, H5::Group *group); void WriteHDF5RateCorrections(H5::Group *group);
void WriteHDF5ExptimeArray(H5::H5File *fd, H5::Group *group); void WriteHDF5CounterMask(H5::Group *group);
void WriteHDF5GateDelayArray(H5::H5File *fd, H5::Group *group); void WriteHDF5ExptimeArray(H5::Group *group);
void WriteHDF5Gates(H5::H5File *fd, H5::Group *group); void WriteHDF5GateDelayArray(H5::Group *group);
void WriteHDF5BurstMode(H5::H5File *fd, H5::Group *group); void WriteHDF5Gates(H5::Group *group);
void WriteHDF5AdcMask(H5::H5File *fd, H5::Group *group); void WriteHDF5BurstMode(H5::Group *group);
void WriteHDF5AnalogFlag(H5::H5File *fd, H5::Group *group); void WriteHDF5AdcMask(H5::Group *group);
void WriteHDF5AnalogSamples(H5::H5File *fd, H5::Group *group); void WriteHDF5AnalogFlag(H5::Group *group);
void WriteHDF5DigitalFlag(H5::H5File *fd, H5::Group *group); void WriteHDF5AnalogSamples(H5::Group *group);
void WriteHDF5DigitalSamples(H5::H5File *fd, H5::Group *group); void WriteHDF5DigitalFlag(H5::Group *group);
void WriteHDF5DbitOffset(H5::H5File *fd, H5::Group *group); void WriteHDF5DigitalSamples(H5::Group *group);
void WriteHDF5DbitList(H5::H5File *fd, H5::Group *group); void WriteHDF5DbitOffset(H5::Group *group);
void WriteHDF5DbitReorder(H5::H5File *fd, H5::Group *group); void WriteHDF5DbitList(H5::Group *group);
void WriteHDF5TransceiverMask(H5::H5File *fd, H5::Group *group); void WriteHDF5DbitReorder(H5::Group *group);
void WriteHDF5TransceiverFlag(H5::H5File *fd, H5::Group *group); void WriteHDF5TransceiverMask(H5::Group *group);
void WriteHDF5TransceiverSamples(H5::H5File *fd, H5::Group *group); void WriteHDF5TransceiverFlag(H5::Group *group);
void WriteHDF5TransceiverSamples(H5::Group *group);
#endif #endif
void GetJungfrauBinaryAttributes( void GetJungfrauBinaryAttributes(
rapidjson::PrettyWriter<rapidjson::StringBuffer> *w); rapidjson::PrettyWriter<rapidjson::StringBuffer> *w);
#ifdef HDF5C #ifdef HDF5C
void WriteJungfrauHDF5Attributes(H5::H5File *fd, H5::Group *group); void WriteJungfrauHDF5Attributes(H5::Group *group);
#endif #endif
void GetEigerBinaryAttributes( void GetEigerBinaryAttributes(
rapidjson::PrettyWriter<rapidjson::StringBuffer> *w); rapidjson::PrettyWriter<rapidjson::StringBuffer> *w);
#ifdef HDF5C #ifdef HDF5C
void WriteEigerHDF5Attributes(H5::H5File *fd, H5::Group *group); void WriteEigerHDF5Attributes(H5::Group *group);
#endif #endif
void GetMythen3BinaryAttributes( void GetMythen3BinaryAttributes(
rapidjson::PrettyWriter<rapidjson::StringBuffer> *w); rapidjson::PrettyWriter<rapidjson::StringBuffer> *w);
#ifdef HDF5C #ifdef HDF5C
void WriteMythen3HDF5Attributes(H5::H5File *fd, H5::Group *group); void WriteMythen3HDF5Attributes(H5::Group *group);
#endif #endif
void GetGotthard2BinaryAttributes( void GetGotthard2BinaryAttributes(
rapidjson::PrettyWriter<rapidjson::StringBuffer> *w); rapidjson::PrettyWriter<rapidjson::StringBuffer> *w);
#ifdef HDF5C #ifdef HDF5C
void WriteGotthard2HDF5Attributes(H5::H5File *fd, H5::Group *group); void WriteGotthard2HDF5Attributes(H5::Group *group);
#endif #endif
void GetMoenchBinaryAttributes( void GetMoenchBinaryAttributes(
rapidjson::PrettyWriter<rapidjson::StringBuffer> *w); rapidjson::PrettyWriter<rapidjson::StringBuffer> *w);
#ifdef HDF5C #ifdef HDF5C
void WriteMoenchHDF5Attributes(H5::H5File *fd, H5::Group *group); void WriteMoenchHDF5Attributes(H5::Group *group);
#endif #endif
void void
GetCtbBinaryAttributes(rapidjson::PrettyWriter<rapidjson::StringBuffer> *w); GetCtbBinaryAttributes(rapidjson::PrettyWriter<rapidjson::StringBuffer> *w);
#ifdef HDF5C #ifdef HDF5C
void WriteCtbHDF5Attributes(H5::H5File *fd, H5::Group *group); void WriteCtbHDF5Attributes(H5::Group *group);
#endif #endif
void GetXilinxCtbBinaryAttributes( void GetXilinxCtbBinaryAttributes(
rapidjson::PrettyWriter<rapidjson::StringBuffer> *w); rapidjson::PrettyWriter<rapidjson::StringBuffer> *w);
#ifdef HDF5C #ifdef HDF5C
void WriteXilinxCtbHDF5Attributes(H5::H5File *fd, H5::Group *group); void WriteXilinxCtbHDF5Attributes(H5::Group *group);
#endif #endif
}; };

View File

@ -49,7 +49,8 @@ std::string CreateMasterBinaryFile(const std::string &filePath,
void LinkHDF5FileInMaster(std::string &masterFileName, void LinkHDF5FileInMaster(std::string &masterFileName,
std::string &dataFilename, std::string &dataFilename,
std::vector<std::string> parameterNames, std::vector<std::string> parameterNames,
const bool silentMode, std::mutex *hdf5LibMutex) { const bool silentMode, std::mutex *hdf5LibMutex,
size_t multiRoiSize) {
std::lock_guard<std::mutex> lock(*hdf5LibMutex); std::lock_guard<std::mutex> lock(*hdf5LibMutex);
std::unique_ptr<H5::H5File> fd{nullptr}; std::unique_ptr<H5::H5File> fd{nullptr};
@ -67,27 +68,35 @@ void LinkHDF5FileInMaster(std::string &masterFileName,
fd = make_unique<H5::H5File>(dataFilename.c_str(), H5F_ACC_RDONLY, fd = make_unique<H5::H5File>(dataFilename.c_str(), H5F_ACC_RDONLY,
H5::FileCreatPropList::DEFAULT, flist); H5::FileCreatPropList::DEFAULT, flist);
// create link for data dataset for (size_t iRoi = 0; iRoi != multiRoiSize; ++iRoi) {
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");
}
// create link for parameter datasets // create link for data dataset
for (unsigned int i = 0; i < parameterNames.size(); ++i) { std::string datasetname = std::string(DATASET_NAME);
H5::DataSet pDset = fd->openDataSet(parameterNames[i].c_str()); if (multiRoiSize > 1)
linkname = std::string("/entry/data/") + parameterNames[i]; datasetname += ('_' + std::to_string(iRoi));
if (H5Lcreate_external(dataFilename.c_str(), H5::DataSet dset = fd->openDataSet(datasetname);
parameterNames[i].c_str(), std::string linkname = std::string("/entry/data/") + datasetname;
if (H5Lcreate_external(dataFilename.c_str(), datasetname.c_str(),
masterfd.getLocId(), linkname.c_str(), masterfd.getLocId(), linkname.c_str(),
H5P_DEFAULT, H5P_DEFAULT) < 0) { H5P_DEFAULT, H5P_DEFAULT) < 0) {
throw RuntimeError( 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];
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(),
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(); fd->close();
@ -160,33 +169,56 @@ std::string CreateMasterHDF5File(const std::string &filePath,
return fileName; 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( std::string CreateVirtualHDF5File(
const std::string &filePath, const std::string &fileNamePrefix, const std::string &filePath, const std::string &fileNamePrefix,
const uint64_t fileIndex, const bool overWriteEnable, const bool silentMode, const uint64_t fileIndex, const bool overWriteEnable, const bool silentMode,
const int modulePos, const int numUnitsPerReadout, const int modulePos, const int numUnitsPerReadout,
const uint32_t maxFramesPerFile, const uint32_t nPixelsX, const uint32_t maxFramesPerFile, const int nPixelsX, const int nPixelsY,
const uint32_t nPixelsY, const uint32_t dynamicRange, const uint32_t dynamicRange, const uint64_t numImagesCaught,
const uint64_t numImagesCaught, const int numModX, const int numModY, const int numModX, const int numModY, const H5::DataType dataType,
const H5::DataType dataType, const std::vector<std::string> parameterNames, const std::vector<std::string> parameterNames,
const std::vector<H5::DataType> parameterDataTypes, const std::vector<H5::DataType> parameterDataTypes,
std::mutex *hdf5LibMutex, bool gotthard25um) { std::mutex *hdf5LibMutex, bool gotthard25um,
std::vector<defs::ROI> multiRoi) {
bool completeRoi = false;
if (multiRoi.size() == 1 && multiRoi[0].completeRoi()) {
completeRoi = true;
}
// virtual file name // virtual file name
std::ostringstream osfn; std::ostringstream osfn;
osfn << filePath << "/" << fileNamePrefix << "_virtual" osfn << filePath << "/" << fileNamePrefix << "_virtual"
<< "_" << fileIndex << ".h5"; << "_" << fileIndex << ".h5";
std::string fileName = osfn.str(); std::string fileName = osfn.str();
unsigned int paraSize = parameterNames.size(); unsigned int paraSize = parameterNames.size();
uint64_t numModZ = numModX;
uint32_t nDimy = nPixelsY;
uint32_t nDimz = ((dynamicRange == 4) ? (nPixelsX / 2) : nPixelsX);
std::lock_guard<std::mutex> lock(*hdf5LibMutex); std::lock_guard<std::mutex> lock(*hdf5LibMutex);
std::unique_ptr<H5::H5File> fd{nullptr}; std::unique_ptr<H5::H5File> fd{nullptr};
try { try {
H5::Exception::dontPrint(); // to handle errors H5::Exception::dontPrint(); // to handle errors
H5Eset_auto(H5E_DEFAULT, (H5E_auto2_t)H5Eprint, stderr);
// file // file
H5::FileAccPropList fapl; H5::FileAccPropList fapl;
@ -205,134 +237,172 @@ std::string CreateVirtualHDF5File(
"version", H5::PredType::NATIVE_DOUBLE, dataspace_attr); "version", H5::PredType::NATIVE_DOUBLE, dataspace_attr);
attribute.write(H5::PredType::NATIVE_DOUBLE, &dValue); attribute.write(H5::PredType::NATIVE_DOUBLE, &dValue);
// dataspace for (size_t iRoi = 0; iRoi != multiRoi.size(); ++iRoi) {
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 auto currentRoi = multiRoi[iRoi];
H5::DSetCreatPropList plist; defs::xy detectorSize = {nPixelsX * numModX, nPixelsY * numModY};
uint64_t fill_value = -1; if (completeRoi) {
plist.setFillValue(dataType, &fill_value); currentRoi =
std::vector<H5::DSetCreatPropList> plistPara(paraSize); defs::ROI{0, detectorSize.x - 1, 0, detectorSize.y - 1};
// ignoring last fill (string) }
for (unsigned int i = 0; i != plistPara.size() - 1; ++i) { if (multiRoi[iRoi].completeRoi() && iRoi != 0)
plistPara[i].setFillValue(parameterDataTypes[i], &fill_value); throw RuntimeError(
} "Cannot have complete roi and multiple rois");
// hyperslab (files) // get detector shape and number of ports in roi
int numFiles = numImagesCaught / maxFramesPerFile; defs::xy portSize{nPixelsX, nPixelsY};
if (numImagesCaught % maxFramesPerFile) uint32_t nTotalPorts = numModX * numModY;
++numFiles; hsize_t roiWidth = detectorSize.x;
uint64_t framesSaved = 0; hsize_t roiHeight = detectorSize.y;
for (int iFile = 0; iFile < numFiles; ++iFile) { hsize_t nPortsInRoi = nTotalPorts;
if (!completeRoi) {
uint64_t nDimx = roiWidth = multiRoi[iRoi].width();
((numImagesCaught - framesSaved) > maxFramesPerFile) roiHeight = multiRoi[iRoi].height();
? maxFramesPerFile nPortsInRoi = GetNumPortsInRoi(multiRoi[iRoi], portSize);
: (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) {
strideBetweenBlocks[2] = 2;
} }
for (unsigned int iReadout = 0; iReadout < numModY * numModZ; // dataspace
++iReadout) { uint64_t nImages = numImagesCaught;
int numFiles = numImagesCaught / maxFramesPerFile;
if (numImagesCaught % maxFramesPerFile)
++numFiles;
// interleaving for g2 (startLocation is 0 and 1) 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);
// property list
H5::DSetCreatPropList plist;
uint64_t fill_value = -1;
plist.setFillValue(dataType, &fill_value);
std::vector<H5::DSetCreatPropList> plistPara(paraSize);
// ignoring last fill (string)
for (unsigned int i = 0; i != plistPara.size() - 1; ++i) {
plistPara[i].setFillValue(parameterDataTypes[i], &fill_value);
}
// 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)
nSrcFileImages = maxFramesPerFile;
hsize_t strideBetweenBlocks[DATA_RANK] = {1, 1, 1};
hsize_t numBlocks[DATA_RANK] = {1, 1, 1};
hsize_t strideBetweenBlocksPara[VDS_PARA_RANK] = {1, 1};
hsize_t numBlocksPara[VDS_PARA_RANK] = {1, 1};
hsize_t blockSizePara[VDS_PARA_RANK] = {nSrcFileImages, 1};
// following recalculated for every readout
hsize_t blockSize[DATA_RANK] = {nSrcFileImages,
static_cast<hsize_t>(nPixelsY),
static_cast<hsize_t>(nPixelsX)};
hsize_t startLocation[DATA_RANK] = {framesSaved, 0, 0};
hsize_t startLocationPara[VDS_PARA_RANK] = {framesSaved, 0};
// interleaving for g2
if (gotthard25um) { if (gotthard25um) {
startLocation[2] = iReadout; strideBetweenBlocks[2] = 2;
} }
vdsDataSpace.selectHyperslab(H5S_SELECT_SET, numBlocks, for (unsigned int iReadout = 0; iReadout < nTotalPorts;
startLocation, strideBetweenBlocks, ++iReadout) {
blockSize); auto globalPortRoi =
GetGlobalPortRoi(iReadout, portSize, numModY);
if (!globalPortRoi.overlap(currentRoi))
continue;
vdsDataSpacePara.selectHyperslab( // calculate start location (special for roi)
H5S_SELECT_SET, numBlocksPara, startLocationPara, int xmin = std::max(currentRoi.xmin, globalPortRoi.xmin);
strideBetweenBlocksPara, blockSizePara); 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;
// source file name // recalculating start location and block size
std::ostringstream os; if (!gotthard25um) {
os << filePath << "/" << fileNamePrefix << "_d" startLocation[1] = ymin - currentRoi.ymin;
<< (modulePos * numUnitsPerReadout + iReadout) << "_f" startLocation[2] = xmin - currentRoi.xmin;
<< iFile << '_' << fileIndex << ".h5"; blockSize[1] = portRoiHeight;
std::string srcFileName = os.str(); blockSize[2] = portRoiWidth;
LOG(logDEBUG1) << srcFileName; }
// interleaving for g2 (startLocation is 0 and 1) (g2 had no
// find relative path // roi)
std::string relative_srcFileName = srcFileName; else {
{ ++startLocation[2];
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) { vdsDataSpace.selectHyperslab(
H5::DataSet vdsDataSetPara(fd->createDataSet( H5S_SELECT_SET, numBlocks, startLocation,
parameterNames[p].c_str(), parameterDataTypes[p], strideBetweenBlocks, blockSize);
vdsDataSpacePara, plistPara[p]));
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] = {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);
// 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);
}
// map next readout
++startLocationPara[1];
}
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(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(
parameterDsetName.c_str(), parameterDataTypes[p],
vdsDataSpacePara, plistPara[p]));
}
} }
fd->close(); fd->close();

View File

@ -21,7 +21,8 @@ std::string CreateMasterBinaryFile(const std::string &filePath,
void LinkHDF5FileInMaster(std::string &masterFileName, void LinkHDF5FileInMaster(std::string &masterFileName,
std::string &dataFilename, std::string &dataFilename,
std::vector<std::string> parameterNames, std::vector<std::string> parameterNames,
const bool silentMode, std::mutex *hdf5LibMutex); const bool silentMode, std::mutex *hdf5LibMutex,
size_t multiRoiSize);
std::string CreateMasterHDF5File(const std::string &filePath, std::string CreateMasterHDF5File(const std::string &filePath,
const std::string &fileNamePrefix, const std::string &fileNamePrefix,
@ -29,17 +30,21 @@ std::string CreateMasterHDF5File(const std::string &filePath,
const bool overWriteEnable, const bool overWriteEnable,
const bool silentMode, MasterAttributes *attr, const bool silentMode, MasterAttributes *attr,
std::mutex *hdf5LibMutex); 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( std::string CreateVirtualHDF5File(
const std::string &filePath, const std::string &fileNamePrefix, const std::string &filePath, const std::string &fileNamePrefix,
const uint64_t fileIndex, const bool overWriteEnable, const bool silentMode, const uint64_t fileIndex, const bool overWriteEnable, const bool silentMode,
const int modulePos, const int numUnitsPerReadout, const int modulePos, const int numUnitsPerReadout,
const uint32_t maxFramesPerFile, const uint32_t nPixelsX, const uint32_t maxFramesPerFile, const int nPixelsX, const int nPixelsY,
const uint32_t nPixelsY, const uint32_t dynamicRange, const uint32_t dynamicRange, const uint64_t numImagesCaught,
const uint64_t numImagesCaught, const int numModX, const int numModY, const int numModX, const int numModY, const H5::DataType dataType,
const H5::DataType dataType, const std::vector<std::string> parameterNames, const std::vector<std::string> parameterNames,
const std::vector<H5::DataType> parameterDataTypes, const std::vector<H5::DataType> parameterDataTypes,
std::mutex *hdf5LibMutex, bool gotthard25um); std::mutex *hdf5LibMutex, bool gotthard25um,
std::vector<defs::ROI> multiRoi);
#endif #endif
} // namespace masterFileUtility } // namespace masterFileUtility

View File

@ -19,8 +19,8 @@ namespace sls {
// files // files
// versions // versions
#define HDF5_WRITER_VERSION (6.7) // 1 decimal places #define HDF5_WRITER_VERSION (7.0) // 1 decimal places
#define BINARY_WRITER_VERSION (7.3) // 1 decimal places #define BINARY_WRITER_VERSION (8.0) // 1 decimal places
#define MAX_FRAMES_PER_FILE 20000 #define MAX_FRAMES_PER_FILE 20000
#define SHORT_MAX_FRAMES_PER_FILE 100000 #define SHORT_MAX_FRAMES_PER_FILE 100000

View File

@ -230,6 +230,8 @@ class slsDetectorDefs {
ROI(int xmin, int xmax) : xmin(xmin), xmax(xmax){}; ROI(int xmin, int xmax) : xmin(xmin), xmax(xmax){};
ROI(int xmin, int xmax, int ymin, int ymax) ROI(int xmin, int xmax, int ymin, int ymax)
: xmin(xmin), xmax(xmax), ymin(ymin), ymax(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<int, 4> getIntArray() const { constexpr std::array<int, 4> getIntArray() const {
return std::array<int, 4>({xmin, xmax, ymin, ymax}); return std::array<int, 4>({xmin, xmax, ymin, ymax});
} }
@ -237,7 +239,8 @@ class slsDetectorDefs {
return (xmin == -1 && xmax == -1 && ymin == -1 && ymax == -1); return (xmin == -1 && xmax == -1 && ymin == -1 && ymax == -1);
} }
constexpr bool noRoi() const { 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() { void setNoRoi() {
xmin = 0; xmin = 0;
@ -245,6 +248,10 @@ class slsDetectorDefs {
ymin = 0; ymin = 0;
ymax = 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 { constexpr bool operator==(const ROI &other) const {
return ((xmin == other.xmin) && (xmax == other.xmax) && return ((xmin == other.xmin) && (xmax == other.xmax) &&
(ymin == other.ymin) && (ymax == other.ymax)); (ymin == other.ymin) && (ymax == other.ymax));

View File

@ -412,6 +412,7 @@ enum detFuncs {
F_RECEIVER_SET_COLUMN, F_RECEIVER_SET_COLUMN,
F_GET_RECEIVER_DBIT_REORDER, F_GET_RECEIVER_DBIT_REORDER,
F_SET_RECEIVER_DBIT_REORDER, F_SET_RECEIVER_DBIT_REORDER,
F_RECEIVER_GET_ROI_METADATA,
NUM_REC_FUNCTIONS 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_RECEIVER_SET_COLUMN: return "F_RECEIVER_SET_COLUMN";
case F_GET_RECEIVER_DBIT_REORDER: return "F_GET_RECEIVER_DBIT_REORDER"; 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_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"; case NUM_REC_FUNCTIONS: return "NUM_REC_FUNCTIONS";
default: return "Unknown Function"; default: return "Unknown Function";

View File

@ -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_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/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/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)

116
tests/scripts/test_roi.py Normal file
View File

@ -0,0 +1,116 @@
# 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'
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 = [
'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)
d = 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.')