Files
Jungfraujoch/broker/JFJochBrokerParser.cpp

251 lines
10 KiB
C++

// Copyright (2019-2023) Paul Scherrer Institute
// SPDX-License-Identifier: GPL-3.0-or-later
#include "JFJochBrokerParser.h"
#include "JFJochBroker.h"
inline bool CHECK_ARRAY(const nlohmann::json &j, const std::string& tag) {
if (j.contains(tag)) {
if (!j[tag].is_array())
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, tag + " must be array");
return true;
} else
return false;
}
inline bool CHECK_OBJECT(const nlohmann::json &j, const std::string& tag) {
if (j.contains(tag)) {
if (!j[tag].is_object())
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, tag + " must be object");
return true;
} else
return false;
}
inline int64_t GET_I64(const nlohmann::json &j, const std::string& tag, int64_t def) {
if (j.contains(tag)) {
if (!j[tag].is_number_integer())
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, tag + " must be integer");
try {
return j[tag].get<int64_t>();
} catch (std::exception &e) {
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, tag + ": " + e.what());
}
} else
return def;
}
inline bool GET_BOOL(const nlohmann::json &j, const std::string& tag, bool def) {
if (j.contains(tag)) {
if (!j[tag].is_boolean())
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, tag + " must be integer");
try {
return j[tag].get<bool>();
} catch (std::exception &e) {
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, tag + ": " + e.what());
}
} else
return def;
}
inline std::string GET_STR(const nlohmann::json &j, const std::string& tag) {
if (j.contains(tag)) {
if (!j[tag].is_string())
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, tag + " must be string");
try {
return j[tag].get<std::string>();
} catch (std::exception &e) {
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, tag + ": " + e.what());
}
} else
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, tag + " is compulsory");
}
inline int64_t GET_I64(const nlohmann::json &j, const std::string& tag) {
if (j.contains(tag)) {
if (!j[tag].is_number_integer())
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, tag + " must be integer");
try {
return j[tag].get<int64_t>();
} catch (std::exception &e) {
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, tag + ": " + e.what());
}
} else
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, tag + " is compulsory");
}
inline std::vector<std::string> GET_STR_ARR(const nlohmann::json &j, const std::string& tag) {
std::vector<std::string> ret;
if (CHECK_ARRAY(j, tag)) {
try {
for (const auto &iter: j[tag])
ret.push_back(iter.get<std::string>());
} catch (std::exception &e) {
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, tag + ": " + e.what());
}
}
return ret;
}
DetectorModuleGeometry::Direction GET_DIRECTION(const nlohmann::json &j, const std::string& tag) {
if (j.contains(tag)) {
if (!j[tag].is_string())
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, tag + " must be string");
if (j[tag] == "Xp")
return DetectorModuleGeometry::Direction::Xpos;
if (j[tag] == "Xn")
return DetectorModuleGeometry::Direction::Xneg;
if (j[tag] == "Yp")
return DetectorModuleGeometry::Direction::Ypos;
if (j[tag] == "Yn")
return DetectorModuleGeometry::Direction::Yneg;
else
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"Allowed values for direction: Xp, Xn, Yp, Yn");
} else
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, tag + " is compulsory");
}
inline int64_t TimeToUs(const std::string &unit) {
if ((unit == "us") || unit.empty()) return 1L;
else if (unit == "ms") return 1000L;
else if ((unit == "s") || (unit == "sec")) return 1000*1000L;
else
throw JFJochException(JFJochExceptionCategory::WrongUnit,
"Only us, ms and s (or sec) are viable units for time");
}
inline std::chrono::microseconds GET_TIME(const nlohmann::json &j, const std::string& tag) {
if (j.contains(tag)) {
if (j[tag].is_number())
return std::chrono::microseconds (std::lround(j[tag].get<double>() * 1000.0 * 1000.0));
else if (j[tag].is_string()) {
std::string::size_type pos;
auto text = j[tag].get<std::string>();
// Check if floating point
pos = text.find_first_of('.');
if (pos != std::string::npos)
throw JFJochException(JFJochExceptionCategory::WrongNumber,
"Time must be provided as <integer> {s|ms|us|Hz} - no floating point allowed");
// Convert integer part
int64_t val = std::stol(text, &pos);
if (pos == 0)
throw JFJochException(JFJochExceptionCategory::WrongNumber,
"Time must be provided as <integer> {s|ms|us|Hz}");
pos = text.find_first_not_of(' ', pos);
if (pos != std::string::npos) {
if (text.substr(pos) == "Hz")
val = 1000*1000L / val;
else
val *= TimeToUs(text.substr(pos));
}
return std::chrono::microseconds(val);
} else
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, tag + " must be number in seconds or string with time units s|ms|us");
} else
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, tag + " is compulsory");
}
DetectorGeometry ParseStandardDetectorGeometry(const nlohmann::json &j) {
int32_t nmodules = GET_I64(j, "nmodules");
int32_t gap_x = GET_I64(j, "gap_x", 8);
int32_t gap_y = GET_I64(j, "gap_y", 36);
int32_t h_stacking = GET_I64(j, "horizontal_stacking", 2);
bool mirror_y = GET_BOOL(j, "mirror_y", true);
return {nmodules, h_stacking, gap_x, gap_y, mirror_y};
}
DetectorGeometry ParseCustomDetectorGeometry(const nlohmann::json &j) {
std::vector<DetectorModuleGeometry> modules;
for (const auto &iter: j) {
if (!iter.is_object())
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"custom_geometry element must be JSON object");
int64_t x0 = GET_I64(iter, "x0");
int64_t y0 = GET_I64(iter, "y0");
auto fast = GET_DIRECTION(iter, "fast_axis");
auto slow = GET_DIRECTION(iter, "slow_axis");
modules.emplace_back(x0, y0, fast, slow);
}
return {modules};
}
DetectorGeometry ParseDetectorGeometry(const nlohmann::json &j) {
if (CHECK_OBJECT(j, "standard_geometry"))
return ParseStandardDetectorGeometry(j["standard_geometry"]);
else if (CHECK_ARRAY(j, "custom_geometry"))
return ParseCustomDetectorGeometry(j["custom_geometry"]);
else
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"It is compulsory to have either standard_detector or custom_detector declared.");
}
DetectorSetup ParseDetectorSetup(const nlohmann::json &j) {
if (!j.is_object())
throw JFJochException(JFJochExceptionCategory::JSON, "Expecting JSON object for detector setup");
DetectorGeometry geom = ParseDetectorGeometry(j);
std::string description = GET_STR(j, "description");
auto module_hostname = GET_STR_ARR(j, "module_hostname");
auto gain_files = GET_STR_ARR(j, "gain_files");
DetectorSetup setup(geom, description, module_hostname);
if (!gain_files.empty())
setup.LoadGain(gain_files);
return setup;
}
void ParseDetectorSetup(const nlohmann::json &j, const std::string& tag, JFJochBroker& broker) {
if (CHECK_ARRAY(j, tag)) {
for (const auto &iter : j[tag])
broker.AddDetectorSetup(ParseDetectorSetup(iter));
} else
throw JFJochException(JFJochExceptionCategory::JSON, "Detector setup not found");
}
void ParseFacilityConfiguration(const nlohmann::json &input, const std::string& tag, DiffractionExperiment &experiment) {
if (CHECK_OBJECT(input, tag)) {
auto j = input[tag];
experiment.SourceName(GET_STR(j, "source_name"));
experiment.SourceNameShort(GET_STR(j, "source_name_short"));
experiment.InstrumentName(GET_STR(j, "instrument_name"));
experiment.InstrumentNameShort(GET_STR(j, "instrument_name_short"));
experiment.DataStreams(GET_I64(j, "datastreams"));
experiment.PedestalG0Frames(GET_I64(j, "pedestal_g0_frames"));
experiment.PedestalG1Frames(GET_I64(j, "pedestal_g1_frames"));
experiment.PedestalG2Frames(GET_I64(j, "pedestal_g2_frames"));
experiment.FrameTime(GET_TIME(j, "frame_time_us"), GET_TIME(j, "count_time_us"));
experiment.SpotFindingPeriod(GET_TIME(j, "spot_finding_period_us"));
experiment.PreviewPeriod(GET_TIME(j, "preview_period_us"));
experiment.IPv4BaseAddr(GET_STR(j, "detector_ipv4"));
} else
throw JFJochException(JFJochExceptionCategory::JSON, "Default configuration not found");
}
void ParseBrokerConfiguration(const nlohmann::json &input, const std::string& tag, JFJochBroker& broker) {
if (CHECK_OBJECT(input, tag)) {
auto j = input[tag];
if (j.contains("receiver_addr"))
broker.Services().Receiver(GET_STR(j, "receiver_addr"));
if (CHECK_ARRAY(j, "writer")) {
for (const auto &iter: j["writer"]) {
broker.Services().Writer(GET_STR(iter, "addr_grpc"), GET_STR(iter, "addr_zmq"));
}
}
if (j.contains("detector_addr"))
broker.Services().Detector(GET_STR(j, "detector_addr"));
} else
throw JFJochException(JFJochExceptionCategory::JSON, "Service configuration not found");
}