18#include "TObjString.h"
21#include "yaml-cpp/yaml.h"
41template<
typename T,
typename... Args>
53template<
typename... Args>
70template<
typename T,
typename... Args>
78 return FindFromManagerHelper<T>(node[key], args...);
82template<
typename T,
typename... Args>
85 return FindFromManagerHelper<T>(node, args...);
94 return YAML::Load(yaml_string);
95 }
catch (
const YAML::ParserException& e) {
108 YAML::Emitter emitter;
110 return emitter.c_str();
119 std::stringstream ss;
122 TList* linesList = macro.GetListOfLines();
128 TIter nextLine(linesList);
129 TObject *obj =
nullptr;
130 while ((obj = nextLine())) {
131 TObjString* line =
dynamic_cast<TObjString*
>(obj);
136 ss << line->GetString() << std::endl;
161inline TMacro
YAMLtoTMacro(
const YAML::Node& yaml_node,
const std::string& name) {
167 TMacro macro(name.c_str(), name.c_str());
168 macro.AddLine(macro_string.c_str());
182 if (node1.Type() != node2.Type()) {
187 if (node1.IsScalar() && node2.IsScalar()) {
188 return node1.as<std::string>() == node2.as<std::string>();
192 if (node1.IsSequence() && node2.IsSequence()) {
193 if (node1.size() != node2.size()) {
196 for (std::size_t i = 0; i < node1.size(); ++i) {
205 if (node1.IsMap() && node2.IsMap()) {
206 if (node1.size() != node2.size()) {
209 for (
auto it1 = node1.begin(); it1 != node1.end(); ++it1) {
210 auto key = it1->first.as<std::string>();
225template <
typename TValue>
244template <
typename... Args>
255 char* demangledName = abi::__cxa_demangle(mangledName.c_str(),
nullptr,
nullptr, &status);
256 std::string result = (status == 0) ? demangledName : mangledName;
264template<
typename Type>
265Type
Get(
const YAML::Node& node,
const std::string File,
const int Line) {
269 return node.as<Type>();
270 }
catch (
const YAML::BadConversion& e) {
273 MACH3LOG_ERROR(
"While trying to access variable {}", nodeAsString);
275 }
catch (
const YAML::InvalidNode& e) {
276 std::string key =
"<unknown>";
277 const std::string msg = e.what();
278 const std::string search =
"first invalid key: \"";
279 auto start = msg.find(search);
280 if (start != std::string::npos) {
281 start += search.length();
282 auto end = msg.find(
"\"", start);
283 if (end != std::string::npos) {
284 key = msg.substr(start, end - start);
297template<
typename Type>
298Type
GetFromManager(
const YAML::Node& node, Type defval,
const std::string File =
"",
const int Line = 1) {
305 return node.as<Type>();
306 }
catch (
const YAML::BadConversion& e) {
309 MACH3LOG_ERROR(
"While trying to access variable {}", nodeAsString);
325inline YAML::Node
LoadYamlConfig(
const std::string& filename,
const std::string& File,
const int Line) {
328 if (!(filename.length() >= 5 && filename.compare(filename.length() - 5, 5,
".yaml") == 0) &&
329 !(filename.length() >= 4 && filename.compare(filename.length() - 4, 4,
".yml") == 0)) {
335 YAML::Node yamlNode = YAML::LoadFile(filename);
338 std::ifstream fileStream(filename);
339 std::stringstream buffer;
340 buffer << fileStream.rdbuf();
341 std::string fileContent = buffer.str();
345 std::regex linePattern(R
"(^\s*-(?![\d\s\.]).*)");
347 std::istringstream contentStream(fileContent);
348 std::string lineconfig;
352 int flowListDepth = 0;
354 while (std::getline(contentStream, lineconfig)) {
356 if (lineconfig.find(
"---") != std::string::npos) {
362 for (
char c : lineconfig) {
363 if (c ==
'[') flowListDepth++;
364 else if (c ==
']') flowListDepth = std::max(0, flowListDepth - 1);
368 if (flowListDepth == 0 && std::regex_match(lineconfig, linePattern)) {
369 MACH3LOG_ERROR(
"Warning: Missing space or tab after '-' at line {}: {}\n", lineNumber, lineconfig);
378 }
catch (
const std::exception& e) {
389inline const YAML::Node &
Cnode(
const YAML::Node &n) {
409 return b.IsNull() ? a : b;
420 auto c = YAML::Node(YAML::NodeType::Map);
422 if (n.first.IsScalar()) {
423 const std::string & key = n.first.Scalar();
424 auto t = (
Cnode(b)[key]);
430 c[n.first] = n.second;
434 if (!n.first.IsScalar() || !
Cnode(c)[n.first.Scalar()]) {
435 c[n.first] = n.second;
454inline std::vector<double>
ParseBounds(
const YAML::Node& node,
const std::string& File,
const int Line) {
456 std::vector<double> bounds;
458 if (!node || !node.IsSequence() || (node.size() != 1 && node.size() != 2)) {
459 MACH3LOG_ERROR(
"Bounds must be a sequence of 1 or 2 elements, got size {}",
static_cast<int>(node.size()));
463 if (node.size() == 1) {
464 const YAML::Node& val = node[0];
466 if (!val || val.IsNull() || (val.IsScalar() && val.Scalar().empty())) {
467 MACH3LOG_ERROR(
"Single-element bounds must contain a valid numeric value.");
469 }
else if (val.IsScalar()) {
471 const double center = val.as<
double>();
472 if (std::floor(center) != center) {
473 MACH3LOG_ERROR(
"Invalid center value in Bounds[0]: '{}'. Expected an integer (e.g., 0 or 1).",
static_cast<std::string
>(val.Scalar()));
476 bounds = {center - 0.5, center + 0.5};
477 }
catch (
const YAML::BadConversion& e) {
478 MACH3LOG_ERROR(
"Invalid value in Bounds[0]: '{}'. Expected a number.",
static_cast<std::string
>(val.Scalar()));
486 for (std::size_t i = 0; i < 2; ++i) {
487 const YAML::Node& val = node[i];
489 if (!val || val.IsNull() || (val.IsScalar() && val.Scalar().empty())) {
491 }
else if (val.IsScalar()) {
493 bounds.push_back(val.as<
double>());
494 }
catch (
const YAML::BadConversion& e) {
495 MACH3LOG_ERROR(
"Invalid value in Bounds[{}]: '{}'. Expected a number or empty string.",
496 static_cast<int>(i),
static_cast<std::string
>(val.Scalar()));
500 MACH3LOG_ERROR(
"Invalid type in Bounds[{}]",
static_cast<int>(i));
538inline std::vector<std::vector<double>>
Parse2DBounds(
const YAML::Node& node,
const std::string& File,
const int Line) {
540 std::vector<std::vector<double>> bounds;
541 if (!node || !node.IsSequence()) {
547 if (node.size() == 2 && node[0].IsScalar()) {
550 for (std::size_t i = 0; i < node.size(); ++i) {
551 const YAML::Node& subnode = node[i];
552 bounds.push_back(
ParseBounds(subnode, File, Line));
560#define M3OpenConfig(filename) LoadYamlConfig((filename), __FILE__, __LINE__)
561#define GetBounds(filename) ParseBounds((filename), __FILE__, __LINE__)
562#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...
const YAML::Node & Cnode(const YAML::Node &n)
KS: Convenience wrapper to return a YAML node as-is.
YAML::Node MergeNodes(YAML::Node a, YAML::Node b)
KS: Recursively merges two YAML nodes.
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 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.
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::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.
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.
Custom exception class for MaCh3 errors.
static constexpr const double KinematicLowBound
When parameter has no bound this serves as it. Lowest possible value the system.
static constexpr const double KinematicUpBound
When parameter has no bound this serves as it. Highest possible value the system.