v1.0.0-rc.151 (#61)
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 11m34s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 12m52s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 12m54s
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 9m48s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 12m50s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 13m54s
Build Packages / build:rpm (rocky8) (push) Successful in 12m46s
Build Packages / build:rpm (rocky9) (push) Successful in 11m56s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 10m34s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 9m54s
Build Packages / DIALS test (push) Successful in 13m1s
Build Packages / XDS test (durin plugin) (push) Successful in 8m32s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 8m44s
Build Packages / XDS test (neggia plugin) (push) Successful in 8m3s
Build Packages / Generate python client (push) Successful in 13s
Build Packages / Build documentation (push) Successful in 47s
Build Packages / Create release (push) Skipped
Build Packages / Unit tests (push) Successful in 43m38s

* jfjoch_broker: For PSI EIGER detector allow to disable individual half-modules by putting empty hostname

Reviewed-on: #61
Co-authored-by: Filip Leonarski <filip.leonarski@psi.ch>
Co-committed-by: Filip Leonarski <filip.leonarski@psi.ch>
This commit was merged in pull request #61.
This commit is contained in:
2026-06-16 14:13:29 +02:00
committed by leonarski_f
parent 90e804acd7
commit ef52dac2ee
133 changed files with 273 additions and 167 deletions
+91 -35
View File
@@ -7,10 +7,24 @@
#include "../common/Definitions.h"
#include "SLSDetectorWrapper.h"
namespace {
// Value reported for temperature / high voltage of an inactive (excluded)
// half-module, so that the position in the logical vector is preserved.
constexpr int64_t kInactiveModulePlaceholder = -1;
}
SLSDetectorWrapper::SLSDetectorWrapper() {
logger.Info("SLS detector package {} client {}", det.getPackageVersion(), det.getClientVersion());
}
std::vector<int64_t> SLSDetectorWrapper::MapToLogical(const std::vector<int64_t>& sls_values,
int64_t placeholder) const {
std::vector<int64_t> out(n_logical_units, placeholder);
for (size_t s = 0; (s < sls_values.size()) && (s < sls_to_logical.size()); s++)
out[sls_to_logical[s]] = sls_values[s];
return out;
}
void SLSDetectorWrapper::Initialize(DiffractionExperiment& experiment,
const std::vector<AcquisitionDeviceNetConfig>& net_config) {
if (experiment.GetDetectorType() == DetectorType::DECTRIS)
@@ -20,16 +34,47 @@ void SLSDetectorWrapper::Initialize(DiffractionExperiment& experiment,
det_type = experiment.GetDetectorSetup().GetDetectorType();
try {
// Per-(half-)module hostnames in logical order.
// EIGER: one entry per half-module, logical index = 2 * module + half
// JUNGFRAU: one entry per module
// An empty entry marks an inactive half-module: it is excluded from the
// slsDetectorPackage (never connected, never configured) but keeps its
// slot in the logical numbering.
auto module_hostname = experiment.GetDetectorModuleHostname();
if (!module_hostname.empty())
det.setHostname(module_hostname);
else
n_logical_units = static_cast<int>(module_hostname.size());
std::vector<std::string> active_hostname;
sls_to_logical.clear();
for (int k = 0; k < n_logical_units; k++) {
if (!module_hostname[k].empty()) {
active_hostname.push_back(module_hostname[k]);
sls_to_logical.push_back(k);
} else {
logger.Info("Logical half-module {} is inactive (empty hostname) - excluded from detector", k);
}
}
if (active_hostname.empty())
throw JFJochException(JFJochExceptionCategory::Detector,
"Detector hostname not provided");
"No active module hostname provided");
det.setHostname(active_hostname);
// Reverse map: logical index -> SLS index (-1 if inactive).
std::vector<int> logical_to_sls(n_logical_units, -1);
for (size_t s = 0; s < sls_to_logical.size(); s++)
logical_to_sls[sls_to_logical[s]] = static_cast<int>(s);
auto mod_cfg = experiment.GetDetectorModuleConfig(net_config);
if (det_type == DetectorType::JUNGFRAU) {
if (n_logical_units != experiment.GetModulesNum())
throw JFJochException(JFJochExceptionCategory::Detector,
"Hostname vector size must equal module count for JUNGFRAU");
if (sls_to_logical.size() != static_cast<size_t>(n_logical_units))
throw JFJochException(JFJochExceptionCategory::Detector,
"Inactive modules are not supported for JUNGFRAU");
if (det.size() != experiment.GetModulesNum()) {
logger.Error("Discrepancy in module number between DAQ and detector");
throw JFJochException(JFJochExceptionCategory::Detector,
@@ -85,8 +130,12 @@ void SLSDetectorWrapper::Initialize(DiffractionExperiment& experiment,
}
} else if (det_type == DetectorType::EIGER) {
if (det.size() != 2 * experiment.GetModulesNum()) {
logger.Error("Discrepancy in module number between DAQ and detector");
if (n_logical_units != 2 * experiment.GetModulesNum())
throw JFJochException(JFJochExceptionCategory::Detector,
"Hostname vector size must equal 2 x module count for EIGER");
if (det.size() != sls_to_logical.size()) {
logger.Error("Discrepancy in active module number between DAQ ({}) and detector ({})",
sls_to_logical.size(), det.size());
throw JFJochException(JFJochExceptionCategory::Detector,
"Discrepancy in module number between DAQ and detector");
}
@@ -104,24 +153,32 @@ void SLSDetectorWrapper::Initialize(DiffractionExperiment& experiment,
auto trim_files = experiment.GetDetectorSetup().GetTrimFileNames();
for (int i = 0; i < mod_cfg.size(); i++) {
logger.Info("Configure network for module {}", i);
auto &cfg = mod_cfg[i];
det.setDestinationUDPPort(16384 + (cfg.data_stream<<8) + cfg.module_id_in_data_stream * 2, 2 * i);
det.setDestinationUDPPort2(16384 + (cfg.data_stream<<8) + cfg.module_id_in_data_stream * 2, 2 * i);
det.setDestinationUDPPort(16384 + (cfg.data_stream<<8) + cfg.module_id_in_data_stream * 2 + 1, 2 * i + 1);
det.setDestinationUDPPort2(16384 + (cfg.data_stream<<8) + cfg.module_id_in_data_stream * 2 + 1, 2 * i + 1);
for (int h = 0; h < 2; h++) {
int logical = 2 * i + h;
int s = logical_to_sls[logical];
if (s < 0) {
logger.Info("Skip inactive half-module {} (no slsDetectorPackage configuration)", logical);
continue;
}
det.setSourceUDPIP(sls::IpAddr(cfg.ipv4_src_addr_1), {2 * i, 2 * i + 1});
det.setDestinationUDPIP(sls::IpAddr(cfg.ipv4_dest_addr_1), {2 * i, 2 * i + 1});
det.setDestinationUDPMAC(sls::MacAddr(cfg.mac_addr_dest_1), {2 * i, 2 * i + 1});
//det.setRow(static_cast<uint32_t>(cfg.module_id_in_data_stream * 2), {2 * i});
//det.setRow(static_cast<uint32_t>(cfg.module_id_in_data_stream * 2 + 1), {2 * i + 1});
logger.Info("Configure network for half-module {} (SLS index {})", logical, s);
if (!trim_files.empty()) {
det.loadTrimbits(trim_files[2 * i], {2 * i});
det.loadTrimbits(trim_files[2 * i + 1], {2 * i + 1});
// The UDP destination port carries the LOGICAL module id and
// half, so the surviving modules land at the correct place in
// the assembled image regardless of the SLS index shift.
uint16_t port = 16384 + (cfg.data_stream << 8) + cfg.module_id_in_data_stream * 2 + h;
det.setDestinationUDPPort(port, s);
det.setDestinationUDPPort2(port, s);
det.setSourceUDPIP(sls::IpAddr(cfg.ipv4_src_addr_1), {s});
det.setDestinationUDPIP(sls::IpAddr(cfg.ipv4_dest_addr_1), {s});
det.setDestinationUDPMAC(sls::MacAddr(cfg.mac_addr_dest_1), {s});
//det.setRow(static_cast<uint32_t>(cfg.module_id_in_data_stream * 2 + h), {s});
if (!trim_files.empty() && (logical < static_cast<int>(trim_files.size())))
det.loadTrimbits(trim_files[logical], {s});
}
}
}
@@ -136,15 +193,11 @@ void SLSDetectorWrapper::Initialize(DiffractionExperiment& experiment,
void SLSDetectorWrapper::Start(const DiffractionExperiment& experiment) {
logger.Info("Start");
if (det_type == DetectorType::JUNGFRAU) {
if (det.size() != experiment.GetModulesNum())
throw JFJochException(JFJochExceptionCategory::Detector,
"Discrepancy in module number between DAQ and detector");
} else if (det_type == DetectorType::EIGER) {
if (det.size() != 2 * experiment.GetModulesNum())
throw JFJochException(JFJochExceptionCategory::Detector,
"Discrepancy in module number between DAQ and detector");
if (det.size() != sls_to_logical.size())
throw JFJochException(JFJochExceptionCategory::Detector,
"Discrepancy in module number between DAQ and detector");
if (det_type == DetectorType::EIGER) {
auto energy_threshold_ev = experiment.GetEigerThreshold_keV() * 1000.0f;
if (det.getThresholdEnergy().squash(0) != energy_threshold_ev)
det.setThresholdEnergy(energy_threshold_ev);
@@ -303,10 +356,13 @@ std::string SLSDetectorWrapper::GetDetectorServerVersion() const {
std::vector<int64_t> SLSDetectorWrapper::GetFPGATemperatures() const {
try {
auto result = det.getTemperature(slsDetectorDefs::TEMPERATURE_FPGA);
std::vector<int64_t> ret;
std::vector<int64_t> sls_values;
sls_values.reserve(result.size());
for (int i = 0; i < result.size(); i++)
ret.push_back(result[i]);
return ret;
sls_values.push_back(result[i]);
// Report at the logical (Jungfraujoch) module position; inactive
// half-modules are filled with a placeholder.
return MapToLogical(sls_values, kInactiveModulePlaceholder);
} catch (std::exception &e) {
throw JFJochException(JFJochExceptionCategory::Detector, e.what());
}
@@ -315,10 +371,10 @@ std::vector<int64_t> SLSDetectorWrapper::GetFPGATemperatures() const {
std::vector<int64_t> SLSDetectorWrapper::GetHighVoltage() const {
try {
auto result = det.getHighVoltage();
std::vector<int64_t> ret;
std::vector<int64_t> sls_values;
for (int i : result)
ret.push_back(i);
return ret;
sls_values.push_back(i);
return MapToLogical(sls_values, kInactiveModulePlaceholder);
} catch (std::exception &e) {
throw JFJochException(JFJochExceptionCategory::Detector, e.what());
}
@@ -418,4 +474,4 @@ void SLSDetectorWrapper::Configure(const DiffractionExperiment &experiment) {
void SLSDetectorWrapper::LoadPixelMask(PixelMask &mask) {
// Do nothing
}
}