18 #include "TObjString.h"
21 #include "yaml-cpp/yaml.h"
47 template<
typename T,
typename... Args>
59 template<
typename... Args>
76 template<
typename T,
typename... Args>
84 return FindFromManagerHelper<T>(node[key], args...);
88 template<
typename T,
typename... Args>
91 return FindFromManagerHelper<T>(node, args...);
100 return YAML::Load(yaml_string);
101 }
catch (
const YAML::ParserException& e) {
114 YAML::Emitter emitter;
116 return emitter.c_str();
125 std::stringstream ss;
128 TList* linesList = macro.GetListOfLines();
134 TIter nextLine(linesList);
135 TObject *obj =
nullptr;
136 while ((obj = nextLine())) {
137 TObjString* line =
dynamic_cast<TObjString*
>(obj);
142 ss << line->GetString() << std::endl;
167 inline TMacro
YAMLtoTMacro(
const YAML::Node& yaml_node,
const std::string& name) {
173 TMacro macro(name.c_str(), name.c_str());
174 macro.AddLine(macro_string.c_str());
186 inline bool compareYAMLNodes(
const YAML::Node& node1,
const YAML::Node& node2,
bool Mute =
false) {
189 if (node1.Type() != node2.Type()) {
194 if (node1.IsScalar() && node2.IsScalar()) {
195 auto v1 = node1.as<std::string>();
196 auto v2 = node2.as<std::string>();
198 if (!Mute)
MACH3LOG_WARN(
"Scalar value mismatch: '{}' != '{}'", v1, v2);
205 if (node1.IsSequence() && node2.IsSequence()) {
206 if (node1.size() != node2.size()) {
209 for (std::size_t i = 0; i < node1.size(); ++i) {
218 if (node1.IsMap() && node2.IsMap()) {
219 if (node1.size() != node2.size()) {
221 node1.size(), node2.size());
224 for (
auto it1 = node1.begin(); it1 != node1.end(); ++it1) {
225 auto key = it1->first.as<std::string>();
239 if (!Mute)
MACH3LOG_WARN(
"Unsupported YAML node type encountered");
248 template <
typename TValue>
268 template <
typename... Args>
279 char* demangledName = abi::__cxa_demangle(mangledName.c_str(),
nullptr,
nullptr, &status);
280 std::string result = (status == 0) ? demangledName : mangledName;
290 template<
typename Type>
291 Type
Get(
const YAML::Node& node,
const std::string File,
const int Line) {
295 return node.as<Type>();
296 }
catch (
const YAML::BadConversion& e) {
299 MACH3LOG_ERROR(
"While trying to access variable \"{}\"", nodeAsString);
300 if (!node || node.IsNull()) {
301 MACH3LOG_ERROR(
"Requested node does not exist (null or undefined)");
304 }
catch (
const YAML::InvalidNode& e) {
305 std::string key =
"<unknown>";
306 const std::string msg = e.what();
307 const std::string search =
"first invalid key: \"";
308 auto start = msg.find(search);
309 if (start != std::string::npos) {
310 start += search.length();
311 auto end = msg.find(
"\"", start);
312 if (end != std::string::npos) {
313 key = msg.substr(start, end - start);
328 template<
typename Type>
329 Type
GetFromManager(
const YAML::Node& node,
const Type defval,
const std::string File =
"",
const int Line = 1) {
336 return node.as<Type>();
337 }
catch (
const YAML::BadConversion& e) {
340 MACH3LOG_ERROR(
"While trying to access variable {}", nodeAsString);
356 inline YAML::Node
LoadYamlConfig(
const std::string& filename,
const std::string& File,
const int Line) {
359 if (!(filename.length() >= 5 && filename.compare(filename.length() - 5, 5,
".yaml") == 0) &&
360 !(filename.length() >= 4 && filename.compare(filename.length() - 4, 4,
".yml") == 0)) {
366 YAML::Node yamlNode = YAML::LoadFile(filename);
369 std::ifstream fileStream(filename);
370 std::stringstream buffer;
371 buffer << fileStream.rdbuf();
372 std::string fileContent = buffer.str();
376 std::regex linePattern(R
"(^\s*-(?![\d\s\.]).*)");
378 std::istringstream contentStream(fileContent);
379 std::string lineconfig;
383 int flowListDepth = 0;
385 while (std::getline(contentStream, lineconfig)) {
387 if (lineconfig.find(
"---") != std::string::npos) {
393 for (
char c : lineconfig) {
394 if (c ==
'[') flowListDepth++;
395 else if (c ==
']') flowListDepth = std::max(0, flowListDepth - 1);
399 if (flowListDepth == 0 && std::regex_match(lineconfig, linePattern)) {
400 MACH3LOG_ERROR(
"Warning: Missing space or tab after '-' at line {}: {}\n", lineNumber, lineconfig);
407 }
catch (
const std::exception& e) {
418 inline const YAML::Node &
Cnode(
const YAML::Node &n) {
434 inline YAML::Node
MergeNodes(
const YAML::Node& a,
const YAML::Node& b) {
438 return b.IsNull() ? a : b;
449 auto c = YAML::Node(YAML::NodeType::Map);
451 if (n.first.IsScalar()) {
452 const std::string & key = n.first.Scalar();
453 auto t = (
Cnode(b)[key]);
459 c[n.first] = n.second;
463 if (!n.first.IsScalar() || !
Cnode(c)[n.first.Scalar()]) {
464 c[n.first] = n.second;
483 inline std::vector<double>
ParseBounds(
const YAML::Node& node,
const std::string& File,
const int Line) {
485 std::vector<double> bounds;
487 if (!node || !node.IsSequence() || (node.size() != 1 && node.size() != 2)) {
488 MACH3LOG_ERROR(
"Bounds must be a sequence of 1 or 2 elements, got size {}",
static_cast<int>(node.size()));
492 if (node.size() == 1) {
493 const YAML::Node& val = node[0];
495 if (!val || val.IsNull() || (val.IsScalar() && val.Scalar().empty())) {
496 MACH3LOG_ERROR(
"Single-element bounds must contain a valid numeric value.");
498 }
else if (val.IsScalar()) {
500 const double center = val.as<
double>();
501 if (std::floor(center) != center) {
502 MACH3LOG_ERROR(
"Invalid center value in Bounds[0]: '{}'. Expected an integer (e.g., 0 or 1).",
static_cast<std::string
>(val.Scalar()));
505 bounds = {center - 0.5, center + 0.5};
506 }
catch (
const YAML::BadConversion& e) {
507 MACH3LOG_ERROR(
"Invalid value in Bounds[0]: '{}'. Expected a number.",
static_cast<std::string
>(val.Scalar()));
515 for (std::size_t i = 0; i < 2; ++i) {
516 const YAML::Node& val = node[i];
518 if (!val || val.IsNull() || (val.IsScalar() && val.Scalar().empty())) {
520 }
else if (val.IsScalar()) {
522 bounds.push_back(val.as<
double>());
523 }
catch (
const YAML::BadConversion& e) {
524 MACH3LOG_ERROR(
"Invalid value in Bounds[{}]: '{}'. Expected a number or empty string.",
525 static_cast<int>(i),
static_cast<std::string
>(val.Scalar()));
529 MACH3LOG_ERROR(
"Invalid type in Bounds[{}]",
static_cast<int>(i));
567 inline std::vector<std::vector<double>>
Parse2DBounds(
const YAML::Node& node,
const std::string& File,
const int Line) {
569 std::vector<std::vector<double>> bounds;
570 if (!node || !node.IsSequence()) {
576 if (node.size() == 2 && node[0].IsScalar()) {
579 for (std::size_t i = 0; i < node.size(); ++i) {
580 const YAML::Node& subnode = node[i];
581 bounds.push_back(
ParseBounds(subnode, File, Line));
589 #define M3OpenConfig(filename) LoadYamlConfig((filename), __FILE__, __LINE__)
590 #define GetBounds(filename) ParseBounds((filename), __FILE__, __LINE__)
591 #define Get2DBounds(filename) Parse2DBounds((filename), __FILE__, __LINE__)
KS: Core MaCh3 definitions and compile-time configuration utilities.
#define _MaCh3_Safe_Include_Start_
KS: Avoiding warning checking for headers.
#define _MaCh3_Safe_Include_End_
KS: Restore warning checking after including external headers.
Defines the custom exception class used throughout MaCh3.
void OverrideConfig(YAML::Node node, std::string const &key, TValue val)
Overrides the configuration settings based on provided arguments.
T FindFromManagerHelper(const YAML::Node &node)
T FindFromManager(const YAML::Node &node, Args... args)
Wrapper function to call the recursive helper.
TMacro YAMLtoTMacro(const YAML::Node &yaml_node, const std::string &name)
Convert a YAML node to a ROOT TMacro object.
bool CheckNodeExistsHelper(const T &node)
Use this like this CheckNodeExists(config, "LikelihoodOptions", "TestStatistic"); KS: Base case for r...
YAML::Node STRINGtoYAML(const std::string &yaml_string)
Function to convert a YAML string to a YAML node.
std::string DemangleTypeName(const std::string &mangledName)
Function to demangle type names.
std::vector< double > ParseBounds(const YAML::Node &node, const std::string &File, const int Line)
KS: Get bounds from YAML for example for selection cuts.
YAML::Node LoadYamlConfig(const std::string &filename, const std::string &File, const int Line)
Open YAML file.
YAML::Node TMacroToYAML(const TMacro ¯o)
KS: Convert a ROOT TMacro object to a YAML node.
Type GetFromManager(const YAML::Node &node, const Type defval, const std::string File="", const int Line=1)
Get content of config file if node is not found take default value specified.
std::vector< std::vector< double > > Parse2DBounds(const YAML::Node &node, const std::string &File, const int Line)
KS: Get 2D bounds from YAML for example for selection cuts.
std::string TMacroToString(const TMacro ¯o)
KS: Convert a ROOT TMacro object to a string representation.
YAML::Node MergeNodes(const YAML::Node &a, const YAML::Node &b)
KS: Recursively merges two YAML nodes.
std::string YAMLtoSTRING(const YAML::Node &node)
KS: Convert a YAML node to a string representation.
Type Get(const YAML::Node &node, const std::string File, const int Line)
Get content of config file.
bool compareYAMLNodes(const YAML::Node &node1, const YAML::Node &node2, bool Mute=false)
Compare if yaml nodes are identical.
bool CheckNodeExists(const YAML::Node &node, Args... args)
KS: Wrapper function to call the recursive helper.
const YAML::Node & Cnode(const YAML::Node &n)
KS: Convenience wrapper to return a YAML node as-is.
Custom exception class used throughout MaCh3.
constexpr static const double KinematicLowBound
When parameter has no bound this serves as it. Lowest possible value the system.
constexpr static const double KinematicUpBound
When parameter has no bound this serves as it. Highest possible value the system.