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

View File

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

View File

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

View File

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

View File

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

View File

@ -350,25 +350,25 @@ void SlsQt2DPlot::showSpectrogram(bool on) {
Update();
}
void SlsQt2DPlot::EnableRoiBox(std::array<int, 4> roi) {
if (roiBox == nullptr) {
roiBox = new QwtPlotShapeItem();
}
roiBox->setPen(QColor(Qt::yellow), 2.0, Qt::SolidLine);
void SlsQt2DPlot::EnableRoiBoxes(std::vector<slsDetectorDefs::ROI> roi) {
roiBoxes.clear();
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)
QRect myRect(QPoint(roi[0], roi[2]), QPoint(roi[1] - 1, roi[3] - 1));
roiBox->setRect(QRectF(myRect));
roiBox->attach(this);
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));
}
replot();
}
void SlsQt2DPlot::DisableRoiBox() {
if (roiBox != nullptr) {
roiBox->detach();
replot();
void SlsQt2DPlot::DisableRoiBoxes() {
for (auto &r : roiBoxes) {
r->detach();
}
replot();
}
} // namespace sls

View File

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

View File

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

View File

@ -21,6 +21,8 @@ class Caller {
UdpDestination getUdpEntry();
int GetLevelAndInsertIntoArgs(std::string levelSeparatedCommand);
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) {
if (value.equal())

View File

@ -2193,20 +2193,6 @@ return 0
}
__rx_roi() {
FCN_RETURN=""
if [[ ${IS_GET} -eq 0 ]]; then
if [[ "${cword}" == "2" ]]; then
FCN_RETURN=""
fi
if [[ "${cword}" == "3" ]]; then
FCN_RETURN=""
fi
if [[ "${cword}" == "4" ]]; then
FCN_RETURN=""
fi
if [[ "${cword}" == "5" ]]; then
FCN_RETURN=""
fi
fi
return 0
}
__rx_silent() {

View File

@ -2117,20 +2117,6 @@ return 0
}
__rx_roi() {
FCN_RETURN=""
if [[ ${IS_GET} -eq 0 ]]; then
if [[ "${cword}" == "2" ]]; then
FCN_RETURN=""
fi
if [[ "${cword}" == "3" ]]; then
FCN_RETURN=""
fi
if [[ "${cword}" == "4" ]]; then
FCN_RETURN=""
fi
if [[ "${cword}" == "5" ]]; then
FCN_RETURN=""
fi
fi
return 0
}
__rx_silent() {

View File

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

View File

@ -8831,25 +8831,8 @@ rx_roi:
store_result_in_t: true
PUT:
args:
- arg_types:
- int
- int
argc: 2
cast_input: []
check_det_id: false
convert_det_id: true
function: ''
input: []
input_types: []
output: []
require_det_id: false
store_result_in_t: false
- arg_types:
- int
- int
- int
- int
argc: 4
- arg_types: []
argc: -1
cast_input: []
check_det_id: false
convert_det_id: true

View File

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

View File

@ -19,14 +19,6 @@ class detectorData {
databytes(databytes), dynamicRange(dynamicRange),
completeImage(completeImage){};
detectorData(double progressIndex, std::string fileName, int nx, int ny,
char *data, int databytes, int dynamicRange,
uint64_t fileIndex, bool completeImage,
std::array<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
*/
@ -62,7 +54,6 @@ class detectorData {
int databytes;
int dynamicRange;
bool completeImage;
std::array<int, 4> rxRoi{{-1, -1, -1, -1}};
};
} // namespace sls

View File

@ -21,6 +21,8 @@ class Caller {
UdpDestination getUdpEntry();
int GetLevelAndInsertIntoArgs(std::string levelSeparatedCommand);
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) {
if (value.equal())

View File

@ -719,49 +719,133 @@ std::string Caller::rx_zmqip(int action) {
}
return os.str();
}
std::string Caller::rx_roi(int action) {
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) {
os << "[xmin] [xmax] [ymin] [ymax]\n\tRegion of interest in "
"receiver.\n\tOnly allowed at multi module level and without gap "
"pixels."
<< '\n';
os << helpMessage;
} else if (action == defs::GET_ACTION) {
if (!args.empty()) {
WrongNumberOfParameters(0);
}
if (det_id == -1) {
auto t = det->getRxROI();
os << t << '\n';
} else {
auto t = det->getIndividualRxROIs(std::vector<int>{det_id});
os << t << '\n';
}
auto t = det->getRxROI(det_id);
os << ToString(t) << '\n';
} else if (action == defs::PUT_ACTION) {
defs::ROI t;
// 2 or 4 arguments
if (args.size() != 2 && args.size() != 4) {
WrongNumberOfParameters(2);
}
if (args.size() == 2 || args.size() == 4) {
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) {
throw RuntimeError("Cannot execute receiver ROI at module level");
throw RuntimeError("Cannot set receiver ROI at module level");
}
det->setRxROI(t);
os << t << '\n';
// Support multiple args with bracketed ROIs, or single arg with
// 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 {
throw RuntimeError("Unknown action");
}
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::ostringstream os;
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);
}
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 {
return pimpl->getNumberOfChannels();
}
@ -1367,13 +1387,13 @@ void Detector::setRxArping(bool value, Positions pos) {
pimpl->Parallel(&Module::setRxArping, pos, value);
}
Result<defs::ROI> Detector::getIndividualRxROIs(Positions pos) const {
return pimpl->Parallel(&Module::getRxROI, pos);
std::vector<defs::ROI> Detector::getRxROI(int module_id) const {
return pimpl->getRxROI(module_id);
}
defs::ROI Detector::getRxROI() const { return pimpl->getRxROI(); }
void Detector::setRxROI(const defs::ROI value) { pimpl->setRxROI(value); }
void Detector::setRxROI(const std::vector<defs::ROI> &args) {
pimpl->setRxROI(args);
}
void Detector::clearRxROI() { pimpl->clearRxROI(); }

View File

@ -130,10 +130,6 @@ void DetectorImpl::initializeDetectorStructure() {
shm()->gapPixels = false;
// zmqlib default
shm()->zmqHwm = -1;
shm()->rx_roi.xmin = -1;
shm()->rx_roi.xmax = -1;
shm()->rx_roi.ymin = -1;
shm()->rx_roi.ymax = -1;
}
void DetectorImpl::initializeMembers(bool verify) {
@ -539,7 +535,6 @@ void DetectorImpl::readFrameFromReceiver() {
bool quadEnable = false;
// to flip image
bool eiger = false;
std::array<int, 4> rxRoi = shm()->rx_roi.getIntArray();
std::vector<bool> runningList(zmqSocket.size());
std::vector<bool> connectList(zmqSocket.size());
@ -736,7 +731,7 @@ void DetectorImpl::readFrameFromReceiver() {
thisData = new detectorData(currentProgress, currentFileName,
nDetActualPixelsX, nDetActualPixelsY,
callbackImage, imagesize, dynamicRange,
currentFileIndex, completeImage, rxRoi);
currentFileIndex, completeImage);
try {
dataReady(
thisData, currentFrameIndex,
@ -1548,31 +1543,6 @@ void DetectorImpl::setDefaultDac(defs::dacIndex index, int defaultValue,
Parallel(&Module::setDefaultDac, pos, index, defaultValue, sett);
}
defs::xy DetectorImpl::getPortGeometry() const {
defs::xy portGeometry(1, 1);
switch (shm()->detType) {
case EIGER:
portGeometry.x = modules[0]->getNumberofUDPInterfacesFromShm();
break;
case JUNGFRAU:
case MOENCH:
portGeometry.y = modules[0]->getNumberofUDPInterfacesFromShm();
break;
default:
break;
}
return portGeometry;
}
defs::xy DetectorImpl::calculatePosition(int moduleIndex,
defs::xy geometry) const {
defs::xy pos{};
int maxYMods = shm()->numberOfModules.y;
pos.y = (moduleIndex % maxYMods) * geometry.y;
pos.x = (moduleIndex / maxYMods) * geometry.x;
return pos;
}
void DetectorImpl::verifyUniqueDetHost(const uint16_t port,
std::vector<int> positions) const {
// 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 ||
shm()->detType == defs::XILINX_CHIPTESTBOARD) {
throw RuntimeError("RxRoi not implemented for this Detector");
@ -1704,75 +1674,164 @@ defs::ROI DetectorImpl::getRxROI() const {
if (modules.size() == 0) {
throw RuntimeError("No Modules added");
}
// complete detector in roi
auto t = Parallel(&Module::getRxROI, {});
if (t.equal() && t.front().completeRoi()) {
LOG(logDEBUG) << "no roi";
return defs::ROI(0, shm()->numberOfChannels.x - 1, 0,
shm()->numberOfChannels.y - 1);
if (module_id >= (int)modules.size()) {
throw RuntimeError("Invalid module id: " + std::to_string(module_id));
}
if (module_id >= 0) {
return modules[module_id]->getRxROI();
}
defs::xy numChansPerMod = modules[0]->getNumberOfChannels();
bool is2D = (numChansPerMod.y > 1 ? true : false);
defs::xy geometry = getPortGeometry();
defs::ROI retval{};
for (size_t iModule = 0; iModule != modules.size(); ++iModule) {
defs::ROI moduleRoi = modules[iModule]->getRxROI();
if (moduleRoi.noRoi()) {
LOG(logDEBUG) << iModule << ": no roi";
} else {
// expand complete roi
if (moduleRoi.completeRoi()) {
moduleRoi.xmin = 0;
moduleRoi.xmax = numChansPerMod.x;
if (is2D) {
moduleRoi.ymin = 0;
moduleRoi.ymax = numChansPerMod.y;
}
}
LOG(logDEBUG) << iModule << ": " << moduleRoi;
// get roi at detector level
defs::xy pos = calculatePosition(iModule, geometry);
defs::ROI moduleFullRoi{};
moduleFullRoi.xmin = numChansPerMod.x * pos.x + moduleRoi.xmin;
moduleFullRoi.xmax = numChansPerMod.x * pos.x + moduleRoi.xmax;
if (is2D) {
moduleFullRoi.ymin = numChansPerMod.y * pos.y + moduleRoi.ymin;
moduleFullRoi.ymax = numChansPerMod.y * pos.y + moduleRoi.ymax;
}
LOG(logDEBUG) << iModule << ": (full roi)" << moduleFullRoi;
// get min and max
if (retval.xmin == -1 || moduleFullRoi.xmin < retval.xmin) {
LOG(logDEBUG) << iModule << ": xmin updated";
retval.xmin = moduleFullRoi.xmin;
}
if (retval.xmax == -1 || moduleFullRoi.xmax > retval.xmax) {
LOG(logDEBUG) << iModule << ": xmax updated";
retval.xmax = moduleFullRoi.xmax;
}
if (retval.ymin == -1 || moduleFullRoi.ymin < retval.ymin) {
LOG(logDEBUG) << iModule << ": ymin updated";
retval.ymin = moduleFullRoi.ymin;
}
if (retval.ymax == -1 || moduleFullRoi.ymax > retval.ymax) {
LOG(logDEBUG) << iModule << ": ymax updated";
retval.ymax = moduleFullRoi.ymax;
}
}
LOG(logDEBUG) << iModule << ": (retval): " << retval;
}
if (retval.ymin == -1) {
retval.ymin = 0;
retval.ymax = 0;
}
return retval;
return modules[0]->getRxROIMetadata();
}
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 ||
shm()->detType == defs::XILINX_CHIPTESTBOARD) {
throw RuntimeError("RxRoi not implemented for this Detector");
@ -1780,118 +1839,41 @@ void DetectorImpl::setRxROI(const defs::ROI arg) {
if (modules.size() == 0) {
throw RuntimeError("No Modules added");
}
if (arg.noRoi()) {
throw RuntimeError("Invalid Roi of size 0.");
}
if (arg.completeRoi()) {
throw RuntimeError("Did you mean the clear roi command (API: "
"clearRxROI, cmd: rx_clearroi)?");
}
if (arg.xmin > arg.xmax || arg.ymin > arg.ymax) {
throw RuntimeError(
"Invalid Receiver Roi. xmin/ymin exceeds xmax/ymax.");
if (args.empty()) {
return clearRxROI();
}
defs::xy numChansPerMod = modules[0]->getNumberOfChannels();
bool is2D = (numChansPerMod.y > 1 ? true : false);
defs::xy geometry = getPortGeometry();
validateROIs(args);
int nPortsPerModule =
Parallel(&Module::getNumberofUDPInterfacesFromShm, {})
.tsquash("Inconsistent number of udp ports set up per module");
if (!is2D && ((arg.ymin != -1 && arg.ymin != 0) ||
(arg.ymax != -1 && arg.ymax != 0))) {
throw RuntimeError(
"Invalid Receiver roi. Cannot set 2d roi for a 1d detector.");
}
for (size_t iModule = 0; iModule < modules.size(); ++iModule) {
auto moduleGlobalRoi = getModuleROI(iModule);
// at most 2 rois per module (for each port)
std::vector<defs::ROI> portRois(nPortsPerModule);
if (arg.xmin < 0 || arg.xmax >= shm()->numberOfChannels.x ||
(is2D && (arg.ymin < 0 || arg.ymax >= shm()->numberOfChannels.y))) {
throw RuntimeError("Invalid Receiver Roi. Outside detector range.");
}
for (size_t iModule = 0; iModule != modules.size(); ++iModule) {
// default init = complete roi
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);
// check overlap with module
for (const auto &arg : args) {
if (arg.overlap(moduleGlobalRoi)) {
convertGlobalRoiToPortLevel(arg, moduleGlobalRoi, portRois);
}
}
modules[iModule]->setRxROI(portRois);
}
}
modules[iModule]->setRxROI(moduleRoi);
}
// updating shm rx_roi for gui purposes
shm()->rx_roi = arg;
// metadata
if (arg.completeRoi()) {
modules[0]->setRxROIMetadata(defs::ROI(0, shm()->numberOfChannels.x - 1,
0,
shm()->numberOfChannels.y - 1));
} else {
modules[0]->setRxROIMetadata(arg);
}
modules[0]->setRxROIMetadata(args);
}
void DetectorImpl::clearRxROI() {
Parallel(&Module::setRxROI, {}, defs::ROI{});
shm()->rx_roi.xmin = -1;
shm()->rx_roi.ymin = -1;
shm()->rx_roi.xmax = -1;
shm()->rx_roi.ymax = -1;
int nPortsPerModule =
Parallel(&Module::getNumberofUDPInterfacesFromShm, {})
.tsquash("Inconsistent number of udp ports set up per module");
for (size_t iModule = 0; iModule < modules.size(); ++iModule) {
modules[iModule]->setRxROI(std::vector<defs::ROI>(nPortsPerModule));
}
modules[0]->setRxROIMetadata(std::vector<defs::ROI>(1));
}
void DetectorImpl::getBadChannels(const std::string &fname,

View File

@ -24,7 +24,7 @@ class detectorData;
class Module;
#define DETECTOR_SHMAPIVERSION 0x190809
#define DETECTOR_SHMVERSION 0x220505
#define DETECTOR_SHMVERSION 0x250616
#define SHORT_STRING_LENGTH 50
/**
@ -65,8 +65,6 @@ struct sharedDetector {
bool gapPixels;
/** high water mark of listening tcp port (only data) */
int zmqHwm;
/** in shm for gui purposes */
defs::ROI rx_roi{};
};
class DetectorImpl : public virtual slsDetectorDefs {
@ -303,8 +301,9 @@ class DetectorImpl : public virtual slsDetectorDefs {
std::vector<std::pair<std::string, uint16_t>>
verifyUniqueRxHost(const std::vector<std::string> &names) const;
defs::ROI getRxROI() const;
void setRxROI(const defs::ROI arg);
defs::xy getPortGeometry() const;
std::vector<defs::ROI> getRxROI(int module_id = -1) const;
void setRxROI(const std::vector<defs::ROI> &args);
void clearRxROI();
void getBadChannels(const std::string &fname, Positions pos) const;
@ -422,12 +421,17 @@ class DetectorImpl : public virtual slsDetectorDefs {
*/
int kbhit();
defs::xy getPortGeometry() const;
defs::xy calculatePosition(int moduleIndex, defs::xy geometry) const;
void verifyUniqueHost(
bool isDet, std::vector<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};
SharedMemory<sharedDetector> shm{0, -1};
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);
}
defs::ROI Module::getRxROI() const {
return sendToReceiver<slsDetectorDefs::ROI>(F_RECEIVER_GET_RECEIVER_ROI);
std::vector<defs::ROI> Module::getRxROI() const {
LOG(logDEBUG1) << "Getting receiver ROI for Module " << moduleIndex;
// check number of ports
if (!shm()->useReceiverFlag) {
throw RuntimeError("No receiver to get ROI.");
}
auto client = ReceiverSocket(shm()->rxHostname, shm()->rxTCPPort);
client.Send(F_RECEIVER_GET_RECEIVER_ROI);
client.setFnum(F_RECEIVER_GET_RECEIVER_ROI);
auto nPorts = client.Receive<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) {
LOG(logDEBUG) << moduleIndex << ": " << arg;
sendToReceiver(F_RECEIVER_SET_RECEIVER_ROI, arg, nullptr);
void Module::setRxROI(const std::vector<defs::ROI> &portRois) {
LOG(logDEBUG) << "Sending to receiver " << moduleIndex
<< " [roi: " << ToString(portRois) << ']';
if (!shm()->useReceiverFlag) {
throw RuntimeError("No receiver to set ROI.");
}
if ((int)portRois.size() != shm()->numUDPInterfaces) {
throw RuntimeError(
"Invalid number of ROIs: " + std::to_string(portRois.size()) +
". 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) {
sendToReceiver(F_RECEIVER_SET_RECEIVER_ROI_METADATA, arg, nullptr);
std::vector<slsDetectorDefs::ROI> Module::getRxROIMetadata() const {
LOG(logDEBUG1) << "Getting receiver ROI metadata for Module "
<< moduleIndex;
// check number of ports
if (!shm()->useReceiverFlag) {
throw RuntimeError("No receiver to get ROI metadata.");
}
auto client = ReceiverSocket(shm()->rxHostname, shm()->rxTCPPort);
client.Send(F_RECEIVER_GET_ROI_METADATA);
client.setFnum(F_RECEIVER_GET_ROI_METADATA);
auto size = client.Receive<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

View File

@ -301,9 +301,10 @@ class Module : public virtual slsDetectorDefs {
std::array<pid_t, NUM_RX_THREAD_IDS> getReceiverThreadIds() const;
bool getRxArping() const;
void setRxArping(bool enable);
defs::ROI getRxROI() const;
void setRxROI(const slsDetectorDefs::ROI arg);
void setRxROIMetadata(const slsDetectorDefs::ROI arg);
std::vector<defs::ROI> getRxROI() const;
void setRxROI(const std::vector<slsDetectorDefs::ROI> &portRois);
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() {
if (args.size() == 0) {
return slsDetectorDefs::GET_ACTION;
}
if (args.size() == 2) {
return slsDetectorDefs::PUT_ACTION;
}
if (args.size() == 4) {
return slsDetectorDefs::PUT_ACTION;
}
else {
throw RuntimeError("Could not infer action: Wrong number of arguments");
}
throw RuntimeError("sls_detector is disabled for command: rx_roi. Use "
"sls_detector_get or sls_detector_put");
}
int InferAction::rx_silent() {

View File

@ -24,11 +24,16 @@ target_sources(tests PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/test-Module.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test-Pattern.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test-CtbConfig.cpp
)
# HDF5 file
if (SLS_USE_HDF5)
target_compile_definitions(tests
PUBLIC
-DHDF5C ${HDF5_DEFINITIONS}
)
endif (SLS_USE_HDF5)
target_include_directories(tests
PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../src>"

View File

@ -7,6 +7,7 @@
#include "sls/sls_detector_defs.h"
#include "test-Caller-global.h"
#include <filesystem>
#include <sstream>
#include "sls/versionAPI.h"
@ -466,7 +467,6 @@ TEST_CASE("rx_arping", "[.cmdcall][.rx]") {
}
}
}
TEST_CASE("rx_roi", "[.cmdcall]") {
Detector det;
Caller caller(&det);
@ -477,35 +477,95 @@ TEST_CASE("rx_roi", "[.cmdcall]") {
} else {
auto prev_val = det.getRxROI();
defs::xy detsize = det.getDetectorSize();
auto portSize = det.getPortSize()[0];
int delta = 50;
// 1d
if (det_type == defs::GOTTHARD || det_type == defs::GOTTHARD2 ||
det_type == defs::MYTHEN3) {
if (det_type == defs::GOTTHARD2 || det_type == defs::MYTHEN3) {
{
std::ostringstream oss;
caller.call("rx_roi", {"5", "10"}, -1, PUT, oss);
REQUIRE(oss.str() == "rx_roi [5, 10]\n");
REQUIRE(oss.str() == "rx_roi [[5, 10]]\n");
}
{
std::ostringstream oss;
caller.call("rx_roi", {"10", "15"}, -1, PUT, oss);
REQUIRE(oss.str() == "rx_roi [10, 15]\n");
REQUIRE(oss.str() == "rx_roi [[10, 15]]\n");
}
REQUIRE_THROWS(caller.call("rx_roi", {"0", "0"}, -1, PUT));
REQUIRE_THROWS(caller.call("rx_roi", {"-1", "-1"}, -1, PUT));
REQUIRE_THROWS(
caller.call("rx_roi", {"10", "15", "25", "30"}, -1, PUT));
// xmin > xmax
REQUIRE_THROWS(caller.call("rx_roi", {"[12, 8, -1, -1]"}, -1, PUT));
// outside detector bounds
REQUIRE_THROWS(caller.call(
"rx_roi",
{"[95," + std::to_string(detsize.x + 5) + ", -1, -1]"}, -1,
PUT));
// module level not allowed
REQUIRE_THROWS(caller.call("rx_roi", {"[5, 10, -1, -1]"}, 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 {
{
std::ostringstream oss;
caller.call("rx_roi", {"10", "15", "1", "5"}, -1, PUT, oss);
REQUIRE(oss.str() == "rx_roi [10, 15, 1, 5]\n");
REQUIRE(oss.str() == "rx_roi [[10, 15, 1, 5]]\n");
}
{
std::ostringstream oss;
caller.call("rx_roi", {"10", "22", "18", "19"}, -1, PUT, oss);
REQUIRE(oss.str() == "rx_roi [10, 22, 18, 19]\n");
REQUIRE(oss.str() == "rx_roi [[10, 22, 18, 19]]\n");
}
{
std::ostringstream oss;
@ -513,17 +573,214 @@ TEST_CASE("rx_roi", "[.cmdcall]") {
{"1", std::to_string(detsize.x - 5), "1",
std::to_string(detsize.y - 5)},
-1, PUT, oss);
REQUIRE(oss.str() == std::string("rx_roi [1, ") +
REQUIRE(oss.str() == std::string("rx_roi [[1, ") +
std::to_string(detsize.x - 5) +
std::string(", 1, ") +
std::to_string(detsize.y - 5) +
std::string("]\n"));
std::string("]]\n"));
}
REQUIRE_THROWS(
caller.call("rx_roi", {"0", "0", "0", "0"}, -1, PUT));
REQUIRE_THROWS(
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) {
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_GET_RECEIVER_DBIT_REORDER] = &ClientInterface::get_dbit_reorder;
flist[F_SET_RECEIVER_DBIT_REORDER] = &ClientInterface::set_dbit_reorder;
flist[F_RECEIVER_GET_ROI_METADATA] = &ClientInterface::get_roi_metadata;
for (int i = NUM_DET_FUNCTIONS + 1; i < NUM_REC_FUNCTIONS ; i++) {
@ -1693,19 +1694,37 @@ int ClientInterface::set_arping(Interface &socket) {
}
int ClientInterface::get_receiver_roi(Interface &socket) {
auto retval = impl()->getReceiverROI();
LOG(logDEBUG1) << "Receiver roi retval:" << ToString(retval);
return socket.sendResult(retval);
auto retvals = impl()->getPortROIs();
LOG(logDEBUG1) << "Receiver roi retval:" << ToString(retvals);
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) {
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)
functionNotImplemented();
LOG(logDEBUG1) << "Set Receiver ROI: " << ToString(arg);
LOG(logDEBUG1) << "Set Receiver ROI: " << ToString(args);
verifyIdle(socket);
try {
impl()->setReceiverROI(arg);
impl()->setPortROIs(args);
} catch (const std::exception &e) {
throw RuntimeError("Could not set Receiver ROI [" +
std::string(e.what()) + ']');
@ -1715,18 +1734,26 @@ int ClientInterface::set_receiver_roi(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)
functionNotImplemented();
LOG(logDEBUG1) << "Set Receiver ROI Metadata: " << ToString(arg);
verifyIdle(socket);
LOG(logINFO) << "Setting ReceiverROI metadata[" << roiSize << ']';
try {
impl()->setReceiverROIMetadata(arg);
impl()->setMultiROIMetadata(rois);
} catch (const std::exception &e) {
throw RuntimeError("Could not set ReceiverROI metadata [" +
std::string(e.what()) + ']');
}
return socket.Send(OK);
}
@ -1812,4 +1839,16 @@ int ClientInterface::set_dbit_reorder(Interface &socket) {
return socket.Send(OK);
}
int ClientInterface::get_roi_metadata(Interface &socket) {
if (detType == CHIPTESTBOARD || detType == XILINX_CHIPTESTBOARD)
functionNotImplemented();
auto retvals = impl()->getMultiROIMetadata();
LOG(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

View File

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

View File

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

View File

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

View File

@ -53,7 +53,14 @@ void DataStreamer::SetAdditionalJsonHeader(
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) {
StopRunning();
@ -210,7 +217,7 @@ int DataStreamer::SendDataHeader(sls_detector_header header, uint32_t size,
isAdditionalJsonUpdated = false;
}
zHeader.addJsonHeader = localAdditionalJsonHeader;
zHeader.rx_roi = receiverRoi.getIntArray();
zHeader.rx_roi = portRoi.getIntArray();
return zmqSocket->SendHeader(index, zHeader);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -49,7 +49,8 @@ std::string CreateMasterBinaryFile(const std::string &filePath,
void LinkHDF5FileInMaster(std::string &masterFileName,
std::string &dataFilename,
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::unique_ptr<H5::H5File> fd{nullptr};
@ -67,11 +68,15 @@ void LinkHDF5FileInMaster(std::string &masterFileName,
fd = make_unique<H5::H5File>(dataFilename.c_str(), H5F_ACC_RDONLY,
H5::FileCreatPropList::DEFAULT, flist);
for (size_t iRoi = 0; iRoi != multiRoiSize; ++iRoi) {
// create link for data dataset
H5::DataSet dset = fd->openDataSet(DATASET_NAME);
std::string linkname =
std::string("/entry/data/") + std::string(DATASET_NAME);
if (H5Lcreate_external(dataFilename.c_str(), DATASET_NAME,
std::string datasetname = std::string(DATASET_NAME);
if (multiRoiSize > 1)
datasetname += ('_' + std::to_string(iRoi));
H5::DataSet dset = fd->openDataSet(datasetname);
std::string linkname = std::string("/entry/data/") + datasetname;
if (H5Lcreate_external(dataFilename.c_str(), datasetname.c_str(),
masterfd.getLocId(), linkname.c_str(),
H5P_DEFAULT, H5P_DEFAULT) < 0) {
throw RuntimeError(
@ -80,16 +85,20 @@ void LinkHDF5FileInMaster(std::string &masterFileName,
// create link for parameter datasets
for (unsigned int i = 0; i < parameterNames.size(); ++i) {
H5::DataSet pDset = fd->openDataSet(parameterNames[i].c_str());
linkname = std::string("/entry/data/") + parameterNames[i];
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(),
parameterNames[i].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();
masterfd.close();
} catch (const H5::Exception &error) {
@ -160,33 +169,56 @@ std::string CreateMasterHDF5File(const std::string &filePath,
return fileName;
}
defs::ROI GetGlobalPortRoi(const int iPort, const defs::xy portSize,
const int numPortsY) {
defs::xy portPos = {(iPort / numPortsY), (iPort % numPortsY)};
const int xmin = portSize.x * portPos.x;
const int xmax = xmin + portSize.x - 1;
const int ymin = portSize.y * portPos.y;
const int ymax = ymin + portSize.y - 1;
return defs::ROI{xmin, xmax, ymin, ymax};
}
int GetNumPortsInRoi(const defs::ROI roi, const defs::xy portSize) {
if (portSize.x == 0 || portSize.y == 0) {
throw RuntimeError("Port width or height cannot be zero");
}
int iPortXMin = roi.xmin / portSize.x;
int iPortXMax = roi.xmax / portSize.x;
int iPortYMin = roi.ymin / portSize.y;
int iPortYMax = roi.ymax / portSize.y;
return ((iPortXMax - iPortXMin + 1) * (iPortYMax - iPortYMin + 1));
}
/** Will not be called if dynamic range is 4 and roi enabled */
std::string CreateVirtualHDF5File(
const std::string &filePath, const std::string &fileNamePrefix,
const uint64_t fileIndex, const bool overWriteEnable, const bool silentMode,
const int modulePos, const int numUnitsPerReadout,
const uint32_t maxFramesPerFile, const uint32_t nPixelsX,
const uint32_t nPixelsY, const uint32_t dynamicRange,
const uint64_t numImagesCaught, const int numModX, const int numModY,
const H5::DataType dataType, const std::vector<std::string> parameterNames,
const uint32_t maxFramesPerFile, const int nPixelsX, const int nPixelsY,
const uint32_t dynamicRange, const uint64_t numImagesCaught,
const int numModX, const int numModY, const H5::DataType dataType,
const std::vector<std::string> parameterNames,
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
std::ostringstream osfn;
osfn << filePath << "/" << fileNamePrefix << "_virtual"
<< "_" << fileIndex << ".h5";
std::string fileName = osfn.str();
unsigned int paraSize = parameterNames.size();
uint64_t numModZ = numModX;
uint32_t nDimy = nPixelsY;
uint32_t nDimz = ((dynamicRange == 4) ? (nPixelsX / 2) : nPixelsX);
std::lock_guard<std::mutex> lock(*hdf5LibMutex);
std::unique_ptr<H5::H5File> fd{nullptr};
try {
H5::Exception::dontPrint(); // to handle errors
H5Eset_auto(H5E_DEFAULT, (H5E_auto2_t)H5Eprint, stderr);
// file
H5::FileAccPropList fapl;
@ -205,11 +237,38 @@ std::string CreateVirtualHDF5File(
"version", H5::PredType::NATIVE_DOUBLE, dataspace_attr);
attribute.write(H5::PredType::NATIVE_DOUBLE, &dValue);
for (size_t iRoi = 0; iRoi != multiRoi.size(); ++iRoi) {
auto currentRoi = multiRoi[iRoi];
defs::xy detectorSize = {nPixelsX * numModX, nPixelsY * numModY};
if (completeRoi) {
currentRoi =
defs::ROI{0, detectorSize.x - 1, 0, detectorSize.y - 1};
}
if (multiRoi[iRoi].completeRoi() && iRoi != 0)
throw RuntimeError(
"Cannot have complete roi and multiple rois");
// get detector shape and number of ports in roi
defs::xy portSize{nPixelsX, nPixelsY};
uint32_t nTotalPorts = numModX * numModY;
hsize_t roiWidth = detectorSize.x;
hsize_t roiHeight = detectorSize.y;
hsize_t nPortsInRoi = nTotalPorts;
if (!completeRoi) {
roiWidth = multiRoi[iRoi].width();
roiHeight = multiRoi[iRoi].height();
nPortsInRoi = GetNumPortsInRoi(multiRoi[iRoi], portSize);
}
// dataspace
hsize_t vdsDims[DATA_RANK] = {numImagesCaught, numModY * nDimy,
numModZ * nDimz};
hsize_t vdsDimsPara[VDS_PARA_RANK] = {numImagesCaught,
numModY * numModZ};
uint64_t nImages = numImagesCaught;
int numFiles = numImagesCaught / maxFramesPerFile;
if (numImagesCaught % maxFramesPerFile)
++numFiles;
hsize_t vdsDims[DATA_RANK] = {nImages, roiHeight, roiWidth};
hsize_t vdsDimsPara[VDS_PARA_RANK] = {nImages, nPortsInRoi};
H5::DataSpace vdsDataSpace(DATA_RANK, vdsDims, nullptr);
H5::DataSpace vdsDataSpacePara(VDS_PARA_RANK, vdsDimsPara, nullptr);
@ -224,43 +283,63 @@ std::string CreateVirtualHDF5File(
}
// hyperslab (files)
int numFiles = numImagesCaught / maxFramesPerFile;
if (numImagesCaught % maxFramesPerFile)
++numFiles;
uint64_t framesSaved = 0;
for (int iFile = 0; iFile < numFiles; ++iFile) {
for (int iFile = 0; iFile != numFiles; ++iFile) {
uint64_t nDimx =
((numImagesCaught - framesSaved) > maxFramesPerFile)
? maxFramesPerFile
: (numImagesCaught - framesSaved);
// images in src file
uint64_t nSrcFileImages = numImagesCaught - framesSaved;
if ((numImagesCaught - framesSaved) > maxFramesPerFile)
nSrcFileImages = maxFramesPerFile;
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 numBlocks[DATA_RANK] = {1, 1, 1};
hsize_t strideBetweenBlocksPara[VDS_PARA_RANK] = {1, 1};
hsize_t numBlocksPara[VDS_PARA_RANK] = {nDimx, 1};
hsize_t blockSizePara[VDS_PARA_RANK] = {1, 1};
hsize_t numBlocksPara[VDS_PARA_RANK] = {1, 1};
hsize_t blockSizePara[VDS_PARA_RANK] = {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) {
strideBetweenBlocks[2] = 2;
}
for (unsigned int iReadout = 0; iReadout < numModY * numModZ;
for (unsigned int iReadout = 0; iReadout < nTotalPorts;
++iReadout) {
auto globalPortRoi =
GetGlobalPortRoi(iReadout, portSize, numModY);
if (!globalPortRoi.overlap(currentRoi))
continue;
// interleaving for g2 (startLocation is 0 and 1)
if (gotthard25um) {
startLocation[2] = iReadout;
// calculate start location (special for roi)
int xmin = std::max(currentRoi.xmin, globalPortRoi.xmin);
int xmax = std::min(currentRoi.xmax, globalPortRoi.xmax);
int ymin = std::max(currentRoi.ymin, globalPortRoi.ymin);
int ymax = std::min(currentRoi.ymax, globalPortRoi.ymax);
hsize_t portRoiHeight = ymax - ymin + 1;
hsize_t portRoiWidth = xmax - xmin + 1;
// recalculating start location and block size
if (!gotthard25um) {
startLocation[1] = ymin - currentRoi.ymin;
startLocation[2] = xmin - currentRoi.xmin;
blockSize[1] = portRoiHeight;
blockSize[2] = portRoiWidth;
}
// interleaving for g2 (startLocation is 0 and 1) (g2 had no
// roi)
else {
++startLocation[2];
}
vdsDataSpace.selectHyperslab(H5S_SELECT_SET, numBlocks,
startLocation, strideBetweenBlocks,
blockSize);
vdsDataSpace.selectHyperslab(
H5S_SELECT_SET, numBlocks, startLocation,
strideBetweenBlocks, blockSize);
vdsDataSpacePara.selectHyperslab(
H5S_SELECT_SET, numBlocksPara, startLocationPara,
@ -284,23 +363,15 @@ std::string CreateVirtualHDF5File(
}
// source dataspace
hsize_t srcDims[DATA_RANK] = {nDimx, nDimy, nDimz};
hsize_t srcDimsMax[DATA_RANK] = {H5S_UNLIMITED, nDimy, nDimz};
hsize_t srcDims[DATA_RANK] = {nSrcFileImages, portRoiHeight,
portRoiWidth};
hsize_t srcDimsMax[DATA_RANK] = {
H5S_UNLIMITED, portRoiHeight, portRoiWidth};
H5::DataSpace srcDataSpace(DATA_RANK, srcDims, srcDimsMax);
hsize_t srcDimsPara[PARA_RANK] = {nDimx};
hsize_t srcDimsPara[PARA_RANK] = {nSrcFileImages};
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(),
@ -311,29 +382,28 @@ std::string CreateVirtualHDF5File(
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;
}
}
// map next readout
++startLocationPara[1];
}
framesSaved += nDimx;
framesSaved += nSrcFileImages;
}
// datasets
std::string datasetname = std::string(DATASET_NAME);
// suffix '_[iRoi]' for multiple rois
if (multiRoi.size() > 1)
datasetname += ('_' + std::to_string(iRoi));
H5::DataSet vdsDataSet(
fd->createDataSet(DATASET_NAME, dataType, vdsDataSpace, plist));
fd->createDataSet(datasetname, dataType, vdsDataSpace, plist));
for (unsigned int p = 0; p < paraSize; ++p) {
std::string parameterDsetName = parameterNames[p];
// suffix '_[iRoi]' for multiple rois
if (multiRoi.size() > 1)
parameterDsetName += ('_' + std::to_string(iRoi));
H5::DataSet vdsDataSetPara(fd->createDataSet(
parameterNames[p].c_str(), parameterDataTypes[p],
parameterDsetName.c_str(), parameterDataTypes[p],
vdsDataSpacePara, plistPara[p]));
}
}
fd->close();
} catch (const H5::Exception &error) {

View File

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

View File

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

View File

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

View File

@ -412,6 +412,7 @@ enum detFuncs {
F_RECEIVER_SET_COLUMN,
F_GET_RECEIVER_DBIT_REORDER,
F_SET_RECEIVER_DBIT_REORDER,
F_RECEIVER_GET_ROI_METADATA,
NUM_REC_FUNCTIONS
};
@ -820,6 +821,7 @@ const char* getFunctionNameFromEnum(enum detFuncs func) {
case F_RECEIVER_SET_COLUMN: return "F_RECEIVER_SET_COLUMN";
case F_GET_RECEIVER_DBIT_REORDER: return "F_GET_RECEIVER_DBIT_REORDER";
case F_SET_RECEIVER_DBIT_REORDER: return "F_SET_RECEIVER_DBIT_REORDER";
case F_RECEIVER_GET_ROI_METADATA: return "F_RECEIVER_GET_ROI_METADATA";
case NUM_REC_FUNCTIONS: return "NUM_REC_FUNCTIONS";
default: return "Unknown Function";

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_frame_synchronizer.py ${CMAKE_BINARY_DIR}/bin/test_frame_synchronizer.py COPYONLY)
configure_file(scripts/utils_for_test.py ${CMAKE_BINARY_DIR}/bin/utils_for_test.py COPYONLY)
configure_file(scripts/test_roi.py ${CMAKE_BINARY_DIR}/bin/test_roi.py COPYONLY)

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.')