18 #include "TObjString.h"
21 #include "yaml-cpp/yaml.h"
42 template<
typename T,
typename... Args>
54 template<
typename... Args>
71 template<
typename T,
typename... Args>
79 return FindFromManagerHelper<T>(node[key], args...);
83 template<
typename T,
typename... Args>
86 return FindFromManagerHelper<T>(node, args...);
95 return YAML::Load(yaml_string);
96 }
catch (
const YAML::ParserException& e) {
109 YAML::Emitter emitter;
111 return emitter.c_str();
120 std::stringstream ss;
123 TList* linesList = macro.GetListOfLines();
129 TIter nextLine(linesList);
130 TObject *obj =
nullptr;
131 while ((obj = nextLine())) {
132 TObjString* line =
dynamic_cast<TObjString*
>(obj);
137 ss << line->GetString() << std::endl;
162 inline TMacro
YAMLtoTMacro(
const YAML::Node& yaml_node,
const std::string& name) {
168 TMacro macro(name.c_str(), name.c_str());
169 macro.AddLine(macro_string.c_str());
183 if (node1.Type() != node2.Type()) {
188 if (node1.IsScalar() && node2.IsScalar()) {
189 return node1.as<std::string>() == node2.as<std::string>();
193 if (node1.IsSequence() && node2.IsSequence()) {
194 if (node1.size() != node2.size()) {
197 for (std::size_t i = 0; i < node1.size(); ++i) {
206 if (node1.IsMap() && node2.IsMap()) {
207 if (node1.size() != node2.size()) {
210 for (
auto it1 = node1.begin(); it1 != node1.end(); ++it1) {
211 auto key = it1->first.as<std::string>();
226 template <
typename TValue>
245 template <
typename... Args>
256 char* demangledName = abi::__cxa_demangle(mangledName.c_str(),
nullptr,
nullptr, &status);
257 std::string result = (status == 0) ? demangledName : mangledName;
265 template<
typename Type>
266 Type
Get(
const YAML::Node& node,
const std::string File,
const int Line) {
270 return node.as<Type>();
271 }
catch (
const YAML::BadConversion& e) {
274 MACH3LOG_ERROR(
"While trying to access variable {}", nodeAsString);
276 }
catch (
const YAML::InvalidNode& e) {
277 std::string key =
"<unknown>";
278 const std::string msg = e.what();
279 const std::string search =
"first invalid key: \"";
280 auto start = msg.find(search);
281 if (start != std::string::npos) {
282 start += search.length();
283 auto end = msg.find(
"\"", start);
284 if (end != std::string::npos) {
285 key = msg.substr(start, end - start);
298 template<
typename Type>
299 Type
GetFromManager(
const YAML::Node& node, Type defval,
const std::string File =
"",
const int Line = 1) {
306 return node.as<Type>();
307 }
catch (
const YAML::BadConversion& e) {
310 MACH3LOG_ERROR(
"While trying to access variable {}", nodeAsString);
326 inline YAML::Node
LoadYamlConfig(
const std::string& filename,
const std::string& File,
const int Line) {
329 if (!(filename.length() >= 5 && filename.compare(filename.length() - 5, 5,
".yaml") == 0) &&
330 !(filename.length() >= 4 && filename.compare(filename.length() - 4, 4,
".yml") == 0)) {
336 YAML::Node yamlNode = YAML::LoadFile(filename);
339 std::ifstream fileStream(filename);
340 std::stringstream buffer;
341 buffer << fileStream.rdbuf();
342 std::string fileContent = buffer.str();
346 std::regex linePattern(R
"(^\s*-(?![\d\s\.]).*)");
348 std::istringstream contentStream(fileContent);
349 std::string lineconfig;
353 int flowListDepth = 0;
355 while (std::getline(contentStream, lineconfig)) {
357 if (lineconfig.find(
"---") != std::string::npos) {
363 for (
char c : lineconfig) {
364 if (c ==
'[') flowListDepth++;
365 else if (c ==
']') flowListDepth = std::max(0, flowListDepth - 1);
369 if (flowListDepth == 0 && std::regex_match(lineconfig, linePattern)) {
370 MACH3LOG_ERROR(
"Warning: Missing space or tab after '-' at line {}: {}\n", lineNumber, lineconfig);
379 }
catch (
const std::exception& e) {
390 inline const YAML::Node &
Cnode(
const YAML::Node &n) {
410 return b.IsNull() ? a : b;
421 auto c = YAML::Node(YAML::NodeType::Map);
423 if (n.first.IsScalar()) {
424 const std::string & key = n.first.Scalar();
425 auto t = (
Cnode(b)[key]);
431 c[n.first] = n.second;
435 if (!n.first.IsScalar() || !
Cnode(c)[n.first.Scalar()]) {
436 c[n.first] = n.second;
455 inline std::vector<double>
ParseBounds(
const YAML::Node& node,
const std::string& File,
const int Line) {
457 std::vector<double> bounds;
459 if (!node || !node.IsSequence() || (node.size() != 1 && node.size() != 2)) {
460 MACH3LOG_ERROR(
"Bounds must be a sequence of 1 or 2 elements, got size {}",
static_cast<int>(node.size()));
464 if (node.size() == 1) {
465 const YAML::Node& val = node[0];
467 if (!val || val.IsNull() || (val.IsScalar() && val.Scalar().empty())) {
468 MACH3LOG_ERROR(
"Single-element bounds must contain a valid numeric value.");
470 }
else if (val.IsScalar()) {
472 const double center = val.as<
double>();
473 if (std::floor(center) != center) {
474 MACH3LOG_ERROR(
"Invalid center value in Bounds[0]: '{}'. Expected an integer (e.g., 0 or 1).",
static_cast<std::string
>(val.Scalar()));
477 bounds = {center - 0.5, center + 0.5};
478 }
catch (
const YAML::BadConversion& e) {
479 MACH3LOG_ERROR(
"Invalid value in Bounds[0]: '{}'. Expected a number.",
static_cast<std::string
>(val.Scalar()));
487 for (std::size_t i = 0; i < 2; ++i) {
488 const YAML::Node& val = node[i];
490 if (!val || val.IsNull() || (val.IsScalar() && val.Scalar().empty())) {
492 }
else if (val.IsScalar()) {
494 bounds.push_back(val.as<
double>());
495 }
catch (
const YAML::BadConversion& e) {
496 MACH3LOG_ERROR(
"Invalid value in Bounds[{}]: '{}'. Expected a number or empty string.",
497 static_cast<int>(i),
static_cast<std::string
>(val.Scalar()));
501 MACH3LOG_ERROR(
"Invalid type in Bounds[{}]",
static_cast<int>(i));
539 inline std::vector<std::vector<double>>
Parse2DBounds(
const YAML::Node& node,
const std::string& File,
const int Line) {
541 std::vector<std::vector<double>> bounds;
542 if (!node || !node.IsSequence()) {
548 if (node.size() == 2 && node[0].IsScalar()) {
551 for (std::size_t i = 0; i < node.size(); ++i) {
552 const YAML::Node& subnode = node[i];
553 bounds.push_back(
ParseBounds(subnode, File, Line));
561 #define M3OpenConfig(filename) LoadYamlConfig((filename), __FILE__, __LINE__)
562 #define GetBounds(filename) ParseBounds((filename), __FILE__, __LINE__)
563 #define Get2DBounds(filename) Parse2DBounds((filename), __FILE__, __LINE__)
#define _MaCh3_Safe_Include_Start_
KS: Avoiding warning checking for headers.
#define _MaCh3_Safe_Include_End_
KS: Restore warning checking after including external headers.
Type GetFromManager(const YAML::Node &node, Type defval, const std::string File="", const int Line=1)
Get content of config file if node is not found take default value specified.
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 MergeNodes(YAML::Node a, YAML::Node b)
KS: Recursively merges two YAML nodes.
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.
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.
std::string YAMLtoSTRING(const YAML::Node &node)
KS: Convert a YAML node to a string representation.
bool compareYAMLNodes(const YAML::Node &node1, const YAML::Node &node2)
Compare if yaml nodes are identical.
Type Get(const YAML::Node &node, const std::string File, const int Line)
Get content of config file.
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 for MaCh3 errors.
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.