MaCh3  2.8.0
Reference Guide
Namespaces | Classes | Typedefs | Enumerations | Functions | Variables
M3 Namespace Reference

Main namespace for MaCh3 software. More...

Namespaces

 detail
 Implementation details only for experts.
 
 Plotting
 Flexible, experiment-agnostic plotting utilities for MaCh3.
 
 rand
 
 Utils
 Utility helpers used across MaCh3.
 

Classes

class  DynamicPlugin
 Manages the lifecycle of a dynamically loaded plugin. More...
 
class  MaCh3Program
 Main program class that manages modules, plugins, and command-line parsing. More...
 
class  MaCh3ArgumentParser
 Extended ArgumentParser with MaCh3-specific functionality. More...
 
class  IPlugin
 Interface for MaCh3 plugins and modules. More...
 
class  PluginBase
 Base class for core modules in MaCh3. More...
 
class  DiagMCMCModule
 Module for performing diagnostic analysis on MCMC chains. More...
 
class  GetPenaltyTermModule
 Module for extracting specific penalty terms from MCMC chains. More...
 
class  ProcessMCMCModule
 Module for processing MCMC chains and producing various diagnostic plots. More...
 

Typedefs

using float_t = double
 
using int_t = int
 
using uint_t = unsigned
 
typedef IPlugin IModule
 Alias for IPlugin, used for core modules. More...
 
typedef PluginBase IModuleBase
 Alias for IPluginBase, used for core modules. More...
 

Enumerations

enum  kInfCrit { kBIC , kDIC , kWAIC , kInfCrits }
 KS: Different Information Criterion tests mostly based Gelman paper. More...
 
enum class  BiasFunction { kGaussian , kVonMises , kGeneralisedGaussian }
 
enum  kReweightType {
  kGaussian , kGaussian , kTGraph , kTGraph2D ,
  kReweightTypes
}
 Types of chain reweighting available. More...
 

Functions

template<typename T >
constexpr T fmaf_t (T x, T y, T z)
 Function template for fused multiply-add. More...
 
int GetNThreads ()
 number of threads which we need for example for TRandom3 More...
 
void AddPath (std::string &FilePath)
 Prepends the MACH3 environment path to FilePath if it is not already present. More...
 
TFile * Open (const std::string &Name, const std::string &Type, const std::string &File, const int Line)
 Opens a ROOT file with the given name and mode. More...
 
void ScaleHistogram (TH1 *Sample_Hist, const double scale)
 Scale histogram to get divided by bin width. More...
 
void CheckBinningMatch (const TH1D *Hist1, const TH1D *Hist2, const std::string &File, const int Line)
 KS: Helper function check if data and MC binning matches. More...
 
void CheckBinningMatch (const TH2D *Hist1, const TH2D *Hist2, const std::string &File, const int Line)
 KS: Helper function check if data and MC binning matches. More...
 
void CheckBinningMatch (TH2Poly *Hist1, TH2Poly *Hist2, const std::string &File, const int Line)
 KS: Helper function check if data and MC binning matches. More...
 
YAML::Node PolyToYaml (TH2Poly *Hist, const std::string &YamlName, const std::string &File, const int Line)
 KS: Convert TH2Poly into yaml config accepted by MaCh3. More...
 
template<typename ObjectType >
std::unique_ptr< ObjectType > Clone (const ObjectType *obj, const std::string &name="")
 KS: Creates a copy of a ROOT-like object and wraps it in a smart pointer. More...
 
bool CaseInsentiveMatch (std::string Text, std::string Pattern)
 Matches a string against a simple wildcard Pattern using regex. Is not case sensitive. More...
 
bool CaseInsensitiveMatchAny (std::string Text, const std::vector< std::string > &Patterns)
 Matches a string against a simple wildcard Pattern using regex. Is not case sensitive. More...
 
double * MatrixMult (double *A, double *B, int n)
 CW: Multi-threaded matrix multiplication. More...
 
double ** MatrixMult (double **A, double **B, int n)
 CW: Multi-threaded matrix multiplication. More...
 
TMatrixD MatrixMult (TMatrixD A, TMatrixD B)
 CW: Multi-threaded matrix multiplication. More...
 
void MatrixVectorMulti (double *_restrict_ VecMulti, double **_restrict_ matrix, const double *_restrict_ vector, const int n)
 KS: Custom function to perform multiplication of matrix and vector with multithreading. More...
 
double MatrixVectorMultiSingle (double **_restrict_ matrix, const double *_restrict_ vector, const int Length, const int i)
 KS: Custom function to perform multiplication of matrix and single element which is thread safe. More...
 
void FixSampleNamesQuotes (std::string &yamlStr)
 KS: Yaml emitter has problem and drops "", if you have special signs in you like * then there is problem. This bit hacky code adds these "". More...
 
void AddTuneValues (YAML::Node &root, const std::vector< double > &Values, const std::string &Tune, const std::vector< std::string > &FancyNames={})
 KS: Add Tune values to YAML covariance matrix. More...
 
void MakeCorrelationMatrix (YAML::Node &root, const std::vector< double > &Values, const std::vector< double > &Errors, const std::vector< std::vector< double >> &Correlation, const std::string &OutYAMLName, const std::vector< std::string > &FancyNames={})
 KS: Replace correlation matrix and tune values in YAML covariance matrix. More...
 
TMacro * GetConfigMacroFromChain (TDirectory *CovarianceFolder)
 KS: We store configuration macros inside the chain. In the past, multiple configs were stored, which required error-prone hardcoding like "Config_xsec_cov". Therefore, this code maintains backward compatibility by checking the number of macros present and using a hardcoded name only if necessary. More...
 
TMatrixDSym * GetCovMatrixFromChain (TDirectory *TempFile)
 KS: Retrieve the cross-section covariance matrix from the given TDirectory. Historically, multiple covariance matrices could be stored, requiring fragile hardcoded paths like "CovarianceFolder/xsec_cov". This function maintains backward compatibility by: More...
 
std::vector< std::vector< double > > GetCholeskyDecomposedMatrix (const TMatrixDSym &matrix, const std::string &matrixName)
 Computes Cholesky decomposition of a symmetric positive definite matrix using custom function which can be even 20 times faster. More...
 
bool CanDecomposeMatrix (const TMatrixDSym &matrix)
 Checks if a matrix can be Cholesky decomposed. More...
 
int MakeMatrixPosDef (TMatrixDSym *cov)
 Makes sure that matrix is positive-definite by adding a small number to on-diagonal elements. More...
 
void DumpParamHandlerToFile (const int _fNumPar, const std::vector< double > &_fPreFitValue, const std::vector< double > &_fError, const std::vector< double > &_fLowBound, const std::vector< double > &_fUpBound, const std::vector< double > &_fIndivStepScale, const std::vector< std::string > &_fFancyNames, const std::vector< bool > &_fFlatPrior, const std::vector< SplineParameter > &SplineParams, TMatrixDSym *covMatrix, TH2D *CorrMatrix, const std::string &Name)
 Dump Matrix to ROOT file, useful when we need to pass matrix info to another fitting group. More...
 
void DebugPCA (const double sum, const TMatrixD &temp, const TMatrixD &eigen_vectors, const TVectorD &eigen_values, const TMatrixD &TransferMat, const TMatrixD &TransferMatT, const int NumPar, const int FirstPCAdpar, const int LastPCAdpar, const int nKeptPCApars, const double eigen_threshold)
 KS: Let's dump all useful matrices to properly validate PCA. More...
 
M3::BiasFunction ParseBiasFunction (const std::string &biasFunctionName)
 
std::string BiasFunction_ToString (const M3::BiasFunction &biasFunction)
 

Variables

constexpr static const char * float_t_str_repr = "D"
 
constexpr static const double _BAD_DOUBLE_ = -999.99
 Default value used for double initialisation. More...
 
constexpr static const int _BAD_INT_ = -999
 Default value used for int initialisation. More...
 
constexpr static const double _DEFAULT_RETURN_VAL_ = -999999.123456
 
constexpr static const double Unity_D = 1.
 Some commonly used variables to which we set pointers to. More...
 
constexpr static const float Unity_F = 1.
 
constexpr static const float_t Unity = Unity_D
 
constexpr static const double Zero_D = 0.
 
constexpr static const float Zero_F = 0.
 
constexpr static const float_t Zero = Zero_D
 
constexpr static const double KinematicLowBound = std::numeric_limits<double>::lowest()
 When parameter has no bound this serves as it. Lowest possible value the system. More...
 
constexpr static const double KinematicUpBound = std::numeric_limits<double>::max()
 When parameter has no bound this serves as it. Highest possible value the system. More...
 
constexpr static const double _LARGE_LOGL_ = 1234567890.0
 Large Likelihood is used it parameter go out of physical boundary, this indicates in MCMC that such step should be removed. More...
 
constexpr static const double _LOW_MC_BOUND_ = .00001
 MC prediction lower bound in bin to identify problematic binning definitions and handle LogL calculation. More...
 
constexpr static const double DefSplineKnotUpBound = 9999
 Default value for spline knot capping, default mean not capping is being applied. More...
 
constexpr static const double DefSplineKnotLowBound = -9999
 Default value for spline knot capping, default mean not capping is being applied. More...
 
constexpr static const int UnderOverFlowBin = -1
 Mark bin which is overflow or underflow in MaCh3 binning. More...
 
constexpr double UmbrellaGaussianNormFactor = 0.906402477055
 

Detailed Description

Main namespace for MaCh3 software.

Typedef Documentation

◆ float_t

typedef double M3::float_t

Definition at line 37 of file Core.h.

◆ IModule

Alias for IPlugin, used for core modules.

Definition at line 31 of file plugin.hpp.

◆ IModuleBase

Alias for IPluginBase, used for core modules.

Definition at line 51 of file plugin.hpp.

◆ int_t

using M3::int_t = typedef int

Definition at line 38 of file Core.h.

◆ uint_t

using M3::uint_t = typedef unsigned

Definition at line 39 of file Core.h.

Enumeration Type Documentation

◆ BiasFunction

enum M3::BiasFunction
strong
Enumerator
kGaussian 
kVonMises 
kGeneralisedGaussian 

Definition at line 15 of file MulticanonicalMCMCHandler.h.

15  {
16  kGaussian,
17  kVonMises,
19  };
@ kGaussian
Assumes gaussian prior.

◆ kInfCrit

KS: Different Information Criterion tests mostly based Gelman paper.

Enumerator
kBIC 

Bayesian Information Criterion.

kDIC 

Deviance Information Criterion.

kWAIC 

Watanabe-Akaike information criterion.

kInfCrits 

This only enumerates.

Definition at line 32 of file StatisticalUtils.h.

32  {
33  kBIC,
34  kDIC,
35  kWAIC,
36  kInfCrits
37  };
@ kWAIC
Watanabe-Akaike information criterion.
@ kInfCrits
This only enumerates.
@ kBIC
Bayesian Information Criterion.
@ kDIC
Deviance Information Criterion.

◆ kReweightType

Types of chain reweighting available.

Enumerator
kGaussian 

Assumes gaussian prior.

kGaussian 
kTGraph 

Calculates Likelihood based on TGraph.

kTGraph2D 

Calculates Likelihood based on TGraph2D.

kReweightTypes 

This only enumerates.

Definition at line 33 of file ReweightMCMC.cpp.

33  {
34  kGaussian,
35  kTGraph,
36  kTGraph2D,
38  };
@ kReweightTypes
This only enumerates.
@ kTGraph
Calculates Likelihood based on TGraph.
@ kTGraph2D
Calculates Likelihood based on TGraph2D.

Function Documentation

◆ AddPath()

void M3::AddPath ( std::string &  FilePath)

Prepends the MACH3 environment path to FilePath if it is not already present.

Parameters
FilePathReference to the file path string to be modified.

Definition at line 382 of file Monitor.cpp.

382  {
383 // ***************************************************************************
384  //KS:Most inputs are in ${MACH3}/inputs/blarb.root
385  if (std::getenv("MACH3") == nullptr) {
386  MACH3LOG_ERROR("MACH3 is not defined");
387  MACH3LOG_ERROR("Please source your setup script");
388  MACH3LOG_ERROR("Read more: https://mach3-software.github.io/MaCh3/FAQ.html");
389  throw MaCh3Exception(__FILE__, __LINE__);
390  }
391 
392  std::string MaCh3Path = std::string(std::getenv("MACH3")) + "/";
393  // Check if FilePath does NOT start with MaCh3Path
394  if (FilePath.find(MaCh3Path) != 0) {
395  FilePath.insert(0, MaCh3Path);
396  }
397 }
#define MACH3LOG_ERROR
Definition: MaCh3Logger.h:37
Custom exception class used throughout MaCh3.

◆ AddTuneValues()

void M3::AddTuneValues ( YAML::Node &  root,
const std::vector< double > &  Values,
const std::string &  Tune,
const std::vector< std::string > &  FancyNames = {} 
)
inline

KS: Add Tune values to YAML covariance matrix.

Parameters
rootThe root YAML node to be updated.
ValuesThe values to add for the specified tune.
TuneThe name of the tune (e.g., "PostFit").
FancyNamesOptional list of fancy names to match systematics (must match Values size if provided).

Definition at line 232 of file ParameterHandlerUtils.h.

235  {}) {
236 // *************************************
237  YAML::Node NodeCopy = YAML::Clone(root);
238  YAML::Node systematics = NodeCopy["Systematics"];
239 
240  if (!systematics || !systematics.IsSequence()) {
241  MACH3LOG_ERROR("'Systematics' node is missing or not a sequence in the YAML copy");
242  throw MaCh3Exception(__FILE__, __LINE__);
243  }
244 
245  if (!FancyNames.empty() && FancyNames.size() != Values.size()) {
246  MACH3LOG_ERROR("Mismatch in sizes: FancyNames has {}, but Values has {}", FancyNames.size(), Values.size());
247  throw MaCh3Exception(__FILE__, __LINE__);
248  }
249 
250  if (FancyNames.empty() && systematics.size() != Values.size()) {
251  MACH3LOG_ERROR("Mismatch in sizes: Values has {}, but YAML 'Systematics' has {} entries",
252  Values.size(), systematics.size());
253  throw MaCh3Exception(__FILE__, __LINE__);
254  }
255 
256  if (!FancyNames.empty()) {
257  for (std::size_t i = 0; i < FancyNames.size(); ++i) {
258  bool matched = false;
259  for (std::size_t j = 0; j < systematics.size(); ++j) {
260  YAML::Node systematicNode = systematics[j]["Systematic"];
261  if (!systematicNode) continue;
262  auto nameNode = systematicNode["Names"];
263  if (!nameNode || !nameNode["FancyName"]) continue;
264  if (nameNode["FancyName"].as<std::string>() == FancyNames[i]) {
265  if (!systematicNode["ParameterValues"]) {
266  MACH3LOG_ERROR("Missing 'ParameterValues' for matched FancyName '{}'", FancyNames[i]);
267  throw MaCh3Exception(__FILE__, __LINE__);
268  }
269  systematicNode["ParameterValues"][Tune] = M3::Utils::FormatDouble(Values[i], 4);
270  matched = true;
271  break;
272  }
273  }
274  if (!matched) {
275  MACH3LOG_ERROR("Could not find a matching FancyName '{}' in the systematics", FancyNames[i]);
276  throw MaCh3Exception(__FILE__, __LINE__);
277  }
278  }
279  } else {
280  for (std::size_t i = 0; i < systematics.size(); ++i) {
281  YAML::Node systematicNode = systematics[i]["Systematic"];
282  if (!systematicNode || !systematicNode["ParameterValues"]) {
283  MACH3LOG_ERROR("Missing 'Systematic' or 'ParameterValues' entry at index {}", i);
284  throw MaCh3Exception(__FILE__, __LINE__);
285  }
286  systematicNode["ParameterValues"][Tune] = M3::Utils::FormatDouble(Values[i], 4);
287  }
288  }
289 
290  // Convert updated copy to string
291  std::string YAMLString = YAMLtoSTRING(NodeCopy);
292  FixSampleNamesQuotes(YAMLString);
293  // Write to output file
294  std::string OutName = "UpdatedMatrixWithTune" + Tune + ".yaml";
295  std::ofstream outFile(OutName);
296  if (!outFile) {
297  MACH3LOG_ERROR("Failed to open file for writing: {}", OutName);
298  throw MaCh3Exception(__FILE__, __LINE__);
299  }
300 
301  outFile << YAMLString;
302  outFile.close();
303 }
std::string YAMLtoSTRING(const YAML::Node &node)
KS: Convert a YAML node to a string representation.
Definition: YamlHelper.h:111
std::string FormatDouble(const double value, const int precision)
Convert double into string for precision, useful for playing with yaml if you don't want to have in c...
std::unique_ptr< ObjectType > Clone(const ObjectType *obj, const std::string &name="")
KS: Creates a copy of a ROOT-like object and wraps it in a smart pointer.
void FixSampleNamesQuotes(std::string &yamlStr)
KS: Yaml emitter has problem and drops "", if you have special signs in you like * then there is prob...

◆ BiasFunction_ToString()

std::string M3::BiasFunction_ToString ( const M3::BiasFunction &  biasFunction)
inline

Definition at line 34 of file MulticanonicalMCMCHandler.h.

34  {
35  switch (biasFunction) {
37  return "gaussian";
39  return "vonMises";
41  return "generalisedGaussian";
42  default:
43  throw MaCh3Exception(__FILE__, __LINE__, "Unknown multicanonical bias function");
44  }
45  }

◆ CanDecomposeMatrix()

bool M3::CanDecomposeMatrix ( const TMatrixDSym &  matrix)
inline

Checks if a matrix can be Cholesky decomposed.

Parameters
matrixInput symmetric matrix to test

Definition at line 543 of file ParameterHandlerUtils.h.

543  {
544 // *************************************
545  TDecompChol chdcmp(matrix);
546  return chdcmp.Decompose();
547 }

◆ CaseInsensitiveMatchAny()

bool M3::CaseInsensitiveMatchAny ( std::string  Text,
const std::vector< std::string > &  Patterns 
)
inline

Matches a string against a simple wildcard Pattern using regex. Is not case sensitive.

Parameters
TextInput string to test.
PatternsCollection wildcard patterns to match against.

Definition at line 65 of file ParameterHandlerUtils.h.

65  {
66  for (size_t i = 0; i < Patterns.size(); i++) {
67  if (M3::CaseInsentiveMatch(Text, Patterns[i])) {
68  return true;
69  }
70  }
71  return false;
72 }
bool CaseInsentiveMatch(std::string Text, std::string Pattern)
Matches a string against a simple wildcard Pattern using regex. Is not case sensitive.

◆ CaseInsentiveMatch()

bool M3::CaseInsentiveMatch ( std::string  Text,
std::string  Pattern 
)
inline

Matches a string against a simple wildcard Pattern using regex. Is not case sensitive.

Parameters
TextInput string to test.
PatternWildcard pattern to match against.

Definition at line 44 of file ParameterHandlerUtils.h.

44  {
45  // Make a copy and to lower case to not be case sensitive
46  std::transform(Text.begin(), Text.end(), Text.begin(), ::tolower);
47 
48  // Convert to low case to not be case sensitive
49  std::transform(Pattern.begin(), Pattern.end(), Pattern.begin(), ::tolower);
50  try {
51  // Replace '*' in the Pattern with '.*' for regex matching
52  std::string RegexPattern = "^" + std::regex_replace(Pattern, std::regex("\\*"), ".*") + "$";
53  std::regex Regex(RegexPattern);
54  return std::regex_match(Text, Regex);
55  }
56  catch (const std::regex_error& e) {
57  MACH3LOG_ERROR("Regex error: {}", e.what());
58  return false;
59  }
60 }

◆ CheckBinningMatch() [1/3]

void M3::CheckBinningMatch ( const TH1D *  Hist1,
const TH1D *  Hist2,
const std::string &  File,
const int  Line 
)

KS: Helper function check if data and MC binning matches.

Definition at line 810 of file HistogramUtils.cpp.

810  {
811 // ***************************************************************************
812  if (Hist1->GetNbinsX() != Hist2->GetNbinsX()) {
813  MACH3LOG_ERROR("Number of bins does not match for TH1D: {} vs {}", Hist1->GetNbinsX(), Hist2->GetNbinsX());
814  throw MaCh3Exception(File, Line);
815  }
816  for (int i = 1; i <= Hist1->GetNbinsX(); ++i) {
817  if (std::fabs(Hist1->GetXaxis()->GetBinLowEdge(i) - Hist2->GetXaxis()->GetBinLowEdge(i)) > 0.001 ||
818  std::fabs(Hist1->GetXaxis()->GetBinUpEdge(i) - Hist2->GetXaxis()->GetBinUpEdge(i)) > 0.001) {
819  MACH3LOG_ERROR("Bin edges do not match for TH1D at bin {}", i);
820  throw MaCh3Exception(File, Line);
821  }
822  }
823 }

◆ CheckBinningMatch() [2/3]

void M3::CheckBinningMatch ( const TH2D *  Hist1,
const TH2D *  Hist2,
const std::string &  File,
const int  Line 
)

KS: Helper function check if data and MC binning matches.

Definition at line 826 of file HistogramUtils.cpp.

826  {
827 // ***************************************************************************
828  if (Hist1->GetNbinsX() != Hist2->GetNbinsX() || Hist1->GetNbinsY() != Hist2->GetNbinsY()) {
829  MACH3LOG_ERROR("Number of bins does not match for TH2D");
830  throw MaCh3Exception(File, Line);
831  }
832 
833  for (int i = 1; i <= Hist1->GetNbinsX(); ++i) {
834  if (std::fabs(Hist1->GetXaxis()->GetBinLowEdge(i) - Hist2->GetXaxis()->GetBinLowEdge(i)) > 0.001 ||
835  std::fabs(Hist1->GetXaxis()->GetBinUpEdge(i) - Hist2->GetXaxis()->GetBinUpEdge(i)) > 0.001) {
836  MACH3LOG_ERROR("X bin edges do not match for TH2D at bin {}", i);
837  throw MaCh3Exception(File, Line);
838  }
839  }
840  for (int j = 1; j <= Hist1->GetNbinsY(); ++j) {
841  if (std::fabs(Hist1->GetYaxis()->GetBinLowEdge(j) - Hist2->GetYaxis()->GetBinLowEdge(j)) > 0.001 ||
842  std::fabs(Hist1->GetYaxis()->GetBinUpEdge(j) - Hist2->GetYaxis()->GetBinUpEdge(j)) > 0.001) {
843  MACH3LOG_ERROR("Y bin edges do not match for TH2D at bin {}", j);
844  throw MaCh3Exception(File, Line);
845  }
846  }
847 }

◆ CheckBinningMatch() [3/3]

void M3::CheckBinningMatch ( TH2Poly *  Hist1,
TH2Poly *  Hist2,
const std::string &  File,
const int  Line 
)

KS: Helper function check if data and MC binning matches.

Definition at line 851 of file HistogramUtils.cpp.

851  {
852 // ***************************************************************************
853  int NBins1 = Hist1->GetNumberOfBins();
854  int NBins2 = Hist2->GetNumberOfBins();
855  if (NBins1 != NBins2) {
856  MACH3LOG_ERROR("Number of bins does not match for TH2Poly: {} vs {}", NBins1, NBins2);
857  throw MaCh3Exception(File, Line);
858  }
859  for (int j = 1; j <= NBins1; j++)
860  {
861  //KS: There is weird offset between bin content and GetBins so this is correct, in spite of looking funny
862  TH2PolyBin* polybin1 = static_cast<TH2PolyBin*>(Hist1->GetBins()->At(j - 1));
863  TH2PolyBin* polybin2 = static_cast<TH2PolyBin*>(Hist2->GetBins()->At(j - 1));
864 
865  if( std::fabs(polybin2->GetXMin() - polybin1->GetXMin()) > 0.001 ||
866  std::fabs(polybin2->GetXMax() - polybin1->GetXMax()) > 0.001 ||
867  std::fabs(polybin2->GetYMin() - polybin1->GetYMin()) > 0.001 ||
868  std::fabs(polybin2->GetYMax() - polybin1->GetYMax()) > 0.001 )
869  {
870  MACH3LOG_ERROR("Binning doesn't match", Hist1->GetTitle());
871  MACH3LOG_ERROR("data x min {} x max {} y min {} y max {}", polybin2->GetXMin(), polybin2->GetXMax(), polybin2->GetYMin(), polybin2->GetYMax());
872  MACH3LOG_ERROR("mc x min {} x max {} y min {} y max {}", polybin1->GetXMin(), polybin1->GetXMax(), polybin1->GetYMin(), polybin1->GetYMax());
873  throw MaCh3Exception(File , Line );
874  }
875  }
876 }

◆ Clone()

template<typename ObjectType >
std::unique_ptr<ObjectType> M3::Clone ( const ObjectType *  obj,
const std::string &  name = "" 
)

KS: Creates a copy of a ROOT-like object and wraps it in a smart pointer.

Template Parameters
ObjectTypeThe type of the object to clone for example TH1D or TH2Poly.
Parameters
objPointer to the object to clone.
nameOptional argument allowing to set new name of cloned object
Returns
std::unique_ptr<ObjectType> Owning pointer to the cloned object.

Definition at line 154 of file HistogramUtils.h.

154  {
155  std::string cloneName = name.empty() ? obj->GetName() : name;
156 
157  std::unique_ptr<ObjectType> Hist(static_cast<ObjectType*>(obj->Clone(cloneName.c_str())));
158  // Disable ROOT memory management because it causes lot of headache especially as smart pointers are much smarter
159  Hist->SetDirectory(nullptr);
160 
161  return Hist;
162 }

◆ DebugPCA()

void M3::DebugPCA ( const double  sum,
const TMatrixD &  temp,
const TMatrixD &  eigen_vectors,
const TVectorD &  eigen_values,
const TMatrixD &  TransferMat,
const TMatrixD &  TransferMatT,
const int  NumPar,
const int  FirstPCAdpar,
const int  LastPCAdpar,
const int  nKeptPCApars,
const double  eigen_threshold 
)
inline

KS: Let's dump all useful matrices to properly validate PCA.

Definition at line 709 of file ParameterHandlerUtils.h.

719  {
720 // ********************************************
721  #pragma GCC diagnostic push
722  #pragma GCC diagnostic ignored "-Wfloat-conversion"
723  int originalErrorWarning = gErrorIgnoreLevel;
724  gErrorIgnoreLevel = kFatal;
725 
726  TDirectory *ogdir = gDirectory;
727 
728  TFile *PCA_Debug = new TFile("Debug_PCA.root", "RECREATE");
729  PCA_Debug->cd();
730 
731  bool PlotText = true;
732  //KS: If we have more than 200 plot becomes unreadable :(
733  if(NumPar > 200) PlotText = false;
734 
735  auto heigen_values = std::make_unique<TH1D>("eigen_values", "Eigen Values", eigen_values.GetNrows(), 0.0, eigen_values.GetNrows());
736  heigen_values->SetDirectory(nullptr);
737  auto heigen_cumulative = std::make_unique<TH1D>("heigen_cumulative", "heigen_cumulative", eigen_values.GetNrows(), 0.0, eigen_values.GetNrows());
738  heigen_cumulative->SetDirectory(nullptr);
739  auto heigen_frac = std::make_unique<TH1D>("heigen_fractional", "heigen_fractional", eigen_values.GetNrows(), 0.0, eigen_values.GetNrows());
740  heigen_frac->SetDirectory(nullptr);
741  heigen_values->GetXaxis()->SetTitle("Eigen Vector");
742  heigen_values->GetYaxis()->SetTitle("Eigen Value");
743 
744  double Cumulative = 0;
745  for(int i = 0; i < eigen_values.GetNrows(); i++)
746  {
747  heigen_values->SetBinContent(i+1, (eigen_values)(i));
748  heigen_cumulative->SetBinContent(i+1, (eigen_values)(i)/sum + Cumulative);
749  heigen_frac->SetBinContent(i+1, (eigen_values)(i)/sum);
750  Cumulative += (eigen_values)(i)/sum;
751  }
752  heigen_values->Write("heigen_values");
753  eigen_values.Write("eigen_values");
754  heigen_cumulative->Write("heigen_values_cumulative");
755  heigen_frac->Write("heigen_values_frac");
756 
757  TH2D* heigen_vectors = new TH2D(eigen_vectors);
758  heigen_vectors->GetXaxis()->SetTitle("Parameter in Normal Base");
759  heigen_vectors->GetYaxis()->SetTitle("Parameter in Decomposed Base");
760  heigen_vectors->Write("heigen_vectors");
761  eigen_vectors.Write("eigen_vectors");
762 
763  TH2D* SubsetPCA = new TH2D(temp);
764  SubsetPCA->GetXaxis()->SetTitle("Parameter in Normal Base");
765  SubsetPCA->GetYaxis()->SetTitle("Parameter in Decomposed Base");
766 
767  SubsetPCA->Write("hSubsetPCA");
768  temp.Write("SubsetPCA");
769  TH2D* hTransferMat = new TH2D(TransferMat);
770  hTransferMat->GetXaxis()->SetTitle("Parameter in Normal Base");
771  hTransferMat->GetYaxis()->SetTitle("Parameter in Decomposed Base");
772  TH2D* hTransferMatT = new TH2D(TransferMatT);
773 
774  hTransferMatT->GetXaxis()->SetTitle("Parameter in Decomposed Base");
775  hTransferMatT->GetYaxis()->SetTitle("Parameter in Normal Base");
776 
777  hTransferMat->Write("hTransferMat");
778  TransferMat.Write("TransferMat");
779  hTransferMatT->Write("hTransferMatT");
780  TransferMatT.Write("TransferMatT");
781 
782  auto c1 = std::make_unique<TCanvas>("c1", " ", 0, 0, 1024, 1024);
783  c1->SetBottomMargin(0.1);
784  c1->SetTopMargin(0.05);
785  c1->SetRightMargin(0.05);
786  c1->SetLeftMargin(0.12);
787  c1->SetGrid();
788 
789  gStyle->SetPaintTextFormat("4.1f");
790  gStyle->SetOptFit(0);
791  gStyle->SetOptStat(0);
792  // Make pretty correlation colors (red to blue)
793  constexpr int NRGBs = 5;
794  TColor::InitializeColors();
795  Double_t stops[NRGBs] = { 0.00, 0.25, 0.50, 0.75, 1.00 };
796  Double_t red[NRGBs] = { 0.00, 0.25, 1.00, 1.00, 0.50 };
797  Double_t green[NRGBs] = { 0.00, 0.25, 1.00, 0.25, 0.00 };
798  Double_t blue[NRGBs] = { 0.50, 1.00, 1.00, 0.25, 0.00 };
799  TColor::CreateGradientColorTable(5, stops, red, green, blue, 255);
800  gStyle->SetNumberContours(255);
801 
802  double maxz = 0;
803  double minz = 0;
804 
805  c1->Print("Debug_PCA.pdf[");
806  auto EigenLine = std::make_unique<TLine>(nKeptPCApars, 0, nKeptPCApars, heigen_cumulative->GetMaximum());
807  EigenLine->SetLineColor(kPink);
808  EigenLine->SetLineWidth(2);
809  EigenLine->SetLineStyle(kSolid);
810 
811  auto text = std::make_unique<TText>(0.5, 0.5, Form("Threshold = %g", eigen_threshold));
812  text->SetTextFont (43);
813  text->SetTextSize (40);
814 
815  heigen_values->SetLineColor(kRed);
816  heigen_values->SetLineWidth(2);
817  heigen_cumulative->SetLineColor(kGreen);
818  heigen_cumulative->SetLineWidth(2);
819  heigen_frac->SetLineColor(kBlue);
820  heigen_frac->SetLineWidth(2);
821 
822  c1->SetLogy();
823  heigen_values->SetMaximum(heigen_cumulative->GetMaximum()+heigen_cumulative->GetMaximum()*0.4);
824  heigen_values->Draw();
825  heigen_frac->Draw("SAME");
826  heigen_cumulative->Draw("SAME");
827  EigenLine->Draw("Same");
828  text->DrawTextNDC(0.42, 0.84,Form("Threshold = %g", eigen_threshold));
829 
830  auto leg = std::make_unique<TLegend>(0.2, 0.2, 0.6, 0.5);
831  leg->SetTextSize(0.04);
832  leg->AddEntry(heigen_values.get(), "Absolute", "l");
833  leg->AddEntry(heigen_frac.get(), "Fractional", "l");
834  leg->AddEntry(heigen_cumulative.get(), "Cumulative", "l");
835 
836  leg->SetLineColor(0);
837  leg->SetLineStyle(0);
838  leg->SetFillColor(0);
839  leg->SetFillStyle(0);
840  leg->Draw("Same");
841 
842  c1->Print("Debug_PCA.pdf");
843  c1->SetRightMargin(0.15);
844  c1->SetLogy(0);
845 
846  heigen_vectors->SetMarkerSize(0.2);
847  minz = heigen_vectors->GetMinimum();
848  if (fabs(0-maxz)>fabs(0-minz)) heigen_vectors->GetZaxis()->SetRangeUser(0-fabs(0-maxz),0+fabs(0-maxz));
849  else heigen_vectors->GetZaxis()->SetRangeUser(0-fabs(0-minz),0+fabs(0-minz));
850  if(PlotText) heigen_vectors->Draw("COLZ TEXT");
851  else heigen_vectors->Draw("COLZ");
852 
853  auto Eigen_Line = std::make_unique<TLine>(0, nKeptPCApars, LastPCAdpar - FirstPCAdpar, nKeptPCApars);
854  Eigen_Line->SetLineColor(kGreen);
855  Eigen_Line->SetLineWidth(2);
856  Eigen_Line->SetLineStyle(kDotted);
857  Eigen_Line->Draw("SAME");
858  c1->Print("Debug_PCA.pdf");
859 
860  SubsetPCA->SetMarkerSize(0.2);
861  minz = SubsetPCA->GetMinimum();
862  if (fabs(0-maxz)>fabs(0-minz)) SubsetPCA->GetZaxis()->SetRangeUser(0-fabs(0-maxz),0+fabs(0-maxz));
863  else SubsetPCA->GetZaxis()->SetRangeUser(0-fabs(0-minz),0+fabs(0-minz));
864  if(PlotText) SubsetPCA->Draw("COLZ TEXT");
865  else SubsetPCA->Draw("COLZ");
866  c1->Print("Debug_PCA.pdf");
867  delete SubsetPCA;
868 
869  hTransferMat->SetMarkerSize(0.15);
870  minz = hTransferMat->GetMinimum();
871  if (fabs(0-maxz)>fabs(0-minz)) hTransferMat->GetZaxis()->SetRangeUser(0-fabs(0-maxz),0+fabs(0-maxz));
872  else hTransferMat->GetZaxis()->SetRangeUser(0-fabs(0-minz),0+fabs(0-minz));
873  if(PlotText) hTransferMat->Draw("COLZ TEXT");
874  else hTransferMat->Draw("COLZ");
875  c1->Print("Debug_PCA.pdf");
876  delete hTransferMat;
877 
878  hTransferMatT->SetMarkerSize(0.15);
879  minz = hTransferMatT->GetMinimum();
880  if (fabs(0-maxz)>fabs(0-minz)) hTransferMatT->GetZaxis()->SetRangeUser(0-fabs(0-maxz),0+fabs(0-maxz));
881  else hTransferMatT->GetZaxis()->SetRangeUser(0-fabs(0-minz),0+fabs(0-minz));
882  if(PlotText) hTransferMatT->Draw("COLZ TEXT");
883  else hTransferMatT->Draw("COLZ");
884  c1->Print( "Debug_PCA.pdf");
885  delete hTransferMatT;
886 
887  delete heigen_vectors;
888 
889  c1->Print("Debug_PCA.pdf]");
890  PCA_Debug->Close();
891  delete PCA_Debug;
892  gErrorIgnoreLevel = originalErrorWarning;
893  ogdir->cd(); // go back to original directory
894  #pragma GCC diagnostic pop
895 }

◆ DumpParamHandlerToFile()

void M3::DumpParamHandlerToFile ( const int  _fNumPar,
const std::vector< double > &  _fPreFitValue,
const std::vector< double > &  _fError,
const std::vector< double > &  _fLowBound,
const std::vector< double > &  _fUpBound,
const std::vector< double > &  _fIndivStepScale,
const std::vector< std::string > &  _fFancyNames,
const std::vector< bool > &  _fFlatPrior,
const std::vector< SplineParameter > &  SplineParams,
TMatrixDSym *  covMatrix,
TH2D *  CorrMatrix,
const std::string &  Name 
)
inline

Dump Matrix to ROOT file, useful when we need to pass matrix info to another fitting group.

Warning
This is mostly used for backward compatibility

Definition at line 609 of file ParameterHandlerUtils.h.

620  {
621 // ********************************************
622  TFile* outputFile = new TFile(Name.c_str(), "RECREATE");
623 
624  TObjArray* param_names = new TObjArray();
625  TObjArray* spline_interpolation = new TObjArray();
626  TObjArray* spline_names = new TObjArray();
627 
628  TVectorD* param_prior = new TVectorD(_fNumPar);
629  TVectorD* flat_prior = new TVectorD(_fNumPar);
630  TVectorD* stepscale = new TVectorD(_fNumPar);
631  TVectorD* param_lb = new TVectorD(_fNumPar);
632  TVectorD* param_ub = new TVectorD(_fNumPar);
633 
634  TVectorD* param_knot_weight_lb = new TVectorD(_fNumPar);
635  TVectorD* param_knot_weight_ub = new TVectorD(_fNumPar);
636  TVectorD* error = new TVectorD(_fNumPar);
637 
638  for(int i = 0; i < _fNumPar; ++i)
639  {
640  TObjString* nameObj = new TObjString(_fFancyNames[i].c_str());
641  param_names->AddLast(nameObj);
642 
643  TObjString* splineType = new TObjString("TSpline3");
644  spline_interpolation->AddLast(splineType);
645 
646  TObjString* splineName = new TObjString("");
647  spline_names->AddLast(splineName);
648 
649  (*param_prior)[i] = _fPreFitValue[i];
650  (*flat_prior)[i] = _fFlatPrior[i];
651  (*stepscale)[i] = _fIndivStepScale[i];
652  (*error)[i] = _fError[i];
653 
654  (*param_lb)[i] = _fLowBound[i];
655  (*param_ub)[i] = _fUpBound[i];
656 
657  //Default values
658  (*param_knot_weight_lb)[i] = -9999;
659  (*param_knot_weight_ub)[i] = +9999;
660  }
661 
662  for (size_t SplineIndex = 0; SplineIndex < SplineParams.size(); SplineIndex++ ) {
663  auto SystIndex = SplineParams[SplineIndex].index;
664 
665  (*param_knot_weight_lb)[SystIndex] = SplineParams.at(SplineIndex)._SplineKnotLowBound;
666  (*param_knot_weight_ub)[SystIndex] = SplineParams.at(SplineIndex)._SplineKnotUpBound;
667 
668  TObjString* splineType = new TObjString(SplineInterpolation_ToString(SplineParams.at(SplineIndex)._SplineInterpolationType).c_str());
669  spline_interpolation->AddAt(splineType, SystIndex);
670 
671  TObjString* splineName = new TObjString(SplineParams[SplineIndex]._fSplineNames.c_str());
672  spline_names->AddAt(splineName, SystIndex);
673  }
674  param_names->Write("xsec_param_names", TObject::kSingleKey);
675  delete param_names;
676  spline_interpolation->Write("xsec_spline_interpolation", TObject::kSingleKey);
677  delete spline_interpolation;
678  spline_names->Write("xsec_spline_names", TObject::kSingleKey);
679  delete spline_names;
680 
681  param_prior->Write("xsec_param_prior");
682  delete param_prior;
683  flat_prior->Write("xsec_flat_prior");
684  delete flat_prior;
685  stepscale->Write("xsec_stepscale");
686  delete stepscale;
687  param_lb->Write("xsec_param_lb");
688  delete param_lb;
689  param_ub->Write("xsec_param_ub");
690  delete param_ub;
691 
692  param_knot_weight_lb->Write("xsec_param_knot_weight_lb");
693  delete param_knot_weight_lb;
694  param_knot_weight_ub->Write("xsec_param_knot_weight_ub");
695  delete param_knot_weight_ub;
696  error->Write("xsec_error");
697  delete error;
698 
699  covMatrix->Write("xsec_cov");
700  CorrMatrix->Write("hcov");
701 
702  outputFile->Close();
703  delete outputFile;
704 }
std::string SplineInterpolation_ToString(const SplineInterpolation i)
Convert a LLH type to a string.
Flat representation of a spline index entry.
Definition: SplineCommon.h:33

◆ FixSampleNamesQuotes()

void M3::FixSampleNamesQuotes ( std::string &  yamlStr)
inline

KS: Yaml emitter has problem and drops "", if you have special signs in you like * then there is problem. This bit hacky code adds these "".

Parameters
yamlStrThe YAML string to be processed (modified in-place).

Definition at line 197 of file ParameterHandlerUtils.h.

197  {
198 // *************************************
199  std::stringstream input(yamlStr);
200  std::string line;
201  std::string fixedYaml;
202  std::regex sampleNamesRegex(R"(SampleNames:\s*\[([^\]]+)\])");
203 
204  while (std::getline(input, line)) {
205  std::smatch match;
206  if (std::regex_search(line, match, sampleNamesRegex)) {
207  std::string contents = match[1]; // inside the brackets
208  std::stringstream ss(contents);
209  std::string item;
210  std::vector<std::string> quotedItems;
211 
212  while (std::getline(ss, item, ',')) {
213  item = std::regex_replace(item, std::regex(R"(^\s+|\s+$)"), ""); // trim
214  quotedItems.push_back("\"" + item + "\"");
215  }
216 
217  std::string replacement = "SampleNames: [" + fmt::format("{}", fmt::join(quotedItems, ", ")) + "]";
218  line = std::regex_replace(line, sampleNamesRegex, replacement);
219  }
220  fixedYaml += line + "\n";
221  }
222 
223  yamlStr = fixedYaml;
224 }
std::string join(const Container &values, std::string_view separator=" ")
Join all values in a container into a single string.
Definition: TablePrinter.h:36

◆ fmaf_t()

template<typename T >
constexpr T M3::fmaf_t ( T  x,
T  y,
T  z 
)
constexpr

Function template for fused multiply-add.

Definition at line 45 of file Core.h.

45  {
46  #ifdef _LOW_MEMORY_STRUCTS_
47  return std::fmaf(x, y, z);
48  #else
49  return std::fma(x, y, z);
50  #endif
51  }

◆ GetCholeskyDecomposedMatrix()

std::vector<std::vector<double> > M3::GetCholeskyDecomposedMatrix ( const TMatrixDSym &  matrix,
const std::string &  matrixName 
)
inline

Computes Cholesky decomposition of a symmetric positive definite matrix using custom function which can be even 20 times faster.

Parameters
matrixInput symmetric positive definite matrix
matrixNameIdentifier for error reporting

Definition at line 507 of file ParameterHandlerUtils.h.

507  {
508 // *************************************
509  const Int_t n = matrix.GetNrows();
510  std::vector<std::vector<double>> L(n, std::vector<double>(n, 0.0));
511 
512  for (Int_t j = 0; j < n; ++j) {
513  // Compute diagonal element (must be serial)
514  double sum_diag = matrix(j, j);
515  for (Int_t k = 0; k < j; ++k) {
516  sum_diag -= L[j][k] * L[j][k];
517  }
518  const double tol = 1e-15;
519  if (sum_diag <= tol) {
520  MACH3LOG_ERROR("Cholesky decomposition failed for {} (non-positive diagonal)", matrixName);
521  throw MaCh3Exception(__FILE__, __LINE__);
522  }
523  L[j][j] = std::sqrt(sum_diag);
524 
525  // Compute the rest of the column in parallel
526  #ifdef MULTITHREAD
527  #pragma omp parallel for
528  #endif
529  for (Int_t i = j + 1; i < n; ++i) {
530  double sum = matrix(i, j);
531  for (Int_t k = 0; k < j; ++k) {
532  sum -= L[i][k] * L[j][k];
533  }
534  L[i][j] = sum / L[j][j];
535  }
536  }
537  return L;
538 }

◆ GetConfigMacroFromChain()

TMacro* M3::GetConfigMacroFromChain ( TDirectory *  CovarianceFolder)
inline

KS: We store configuration macros inside the chain. In the past, multiple configs were stored, which required error-prone hardcoding like "Config_xsec_cov". Therefore, this code maintains backward compatibility by checking the number of macros present and using a hardcoded name only if necessary.

Definition at line 427 of file ParameterHandlerUtils.h.

427  {
428 // *************************************
429  if (!CovarianceFolder) {
430  MACH3LOG_ERROR("Null TDirectory passed to {}", __func__);
431  throw MaCh3Exception(__FILE__, __LINE__);
432  }
433 
434  TMacro* foundMacro = nullptr;
435  int macroCount = 0;
436 
437  TIter next(CovarianceFolder->GetListOfKeys());
438  TKey* key;
439  while ((key = dynamic_cast<TKey*>(next()))) {
440  if (std::string(key->GetClassName()) == "TMacro") {
441  ++macroCount;
442  if (macroCount == 1) {
443  foundMacro = dynamic_cast<TMacro*>(key->ReadObj());
444  }
445  }
446  }
447 
448  if (macroCount == 1 && foundMacro) {
449  MACH3LOG_INFO("Found single TMacro in directory: using it.");
450  return foundMacro;
451  } else {
452  MACH3LOG_WARN("Found {} TMacro objects. Using hardcoded macro name: Config_xsec_cov.", macroCount);
453  TMacro* fallback = CovarianceFolder->Get<TMacro>("Config_xsec_cov");
454  if (!fallback) {
455  MACH3LOG_WARN("Fallback macro 'Config_xsec_cov' not found in directory.");
456  }
457  return fallback;
458  }
459 }
#define MACH3LOG_INFO
Definition: MaCh3Logger.h:35
#define MACH3LOG_WARN
Definition: MaCh3Logger.h:36

◆ GetCovMatrixFromChain()

TMatrixDSym* M3::GetCovMatrixFromChain ( TDirectory *  TempFile)
inline

KS: Retrieve the cross-section covariance matrix from the given TDirectory. Historically, multiple covariance matrices could be stored, requiring fragile hardcoded paths like "CovarianceFolder/xsec_cov". This function maintains backward compatibility by:

  • Using the single matrix present if only one exists,
  • Otherwise falling back to the hardcoded path. This avoids error-prone assumptions while supporting both old and new formats.

Definition at line 468 of file ParameterHandlerUtils.h.

468  {
469 // *************************************
470  if (!TempFile) {
471  MACH3LOG_ERROR("Null TDirectory passed to {}.", __func__);
472  throw MaCh3Exception(__FILE__, __LINE__);
473  }
474 
475  TMatrixDSym* foundMatrix = nullptr;
476  int matrixCount = 0;
477 
478  TIter next(TempFile->GetListOfKeys());
479  TKey* key;
480  while ((key = dynamic_cast<TKey*>(next()))) {
481  std::string className = key->GetClassName();
482  if (className.find("TMatrix") != std::string::npos) {
483  ++matrixCount;
484  if (matrixCount == 1) {
485  foundMatrix = dynamic_cast<TMatrixDSym*>(key->ReadObj());
486  }
487  }
488  }
489 
490  if (matrixCount == 1 && foundMatrix) {
491  MACH3LOG_INFO("Found single TMatrixDSym in directory: using it.");
492  return foundMatrix;
493  } else {
494  MACH3LOG_WARN("Found {} TMatrixDSym objects. Using hardcoded path: xsec_cov.", matrixCount);
495  TMatrixDSym* fallback = TempFile->Get<TMatrixDSym>("xsec_cov");
496  if (!fallback) {
497  MACH3LOG_WARN("Fallback matrix 'xsec_cov' not found.");
498  }
499  return fallback;
500  }
501 }

◆ GetNThreads()

int M3::GetNThreads ( )

number of threads which we need for example for TRandom3

Definition at line 372 of file Monitor.cpp.

372  {
373 // ***************************************************************************
374  #ifdef MULTITHREAD
375  return omp_get_max_threads();
376  #else
377  return 1;
378  #endif
379 }

◆ MakeCorrelationMatrix()

void M3::MakeCorrelationMatrix ( YAML::Node &  root,
const std::vector< double > &  Values,
const std::vector< double > &  Errors,
const std::vector< std::vector< double >> &  Correlation,
const std::string &  OutYAMLName,
const std::vector< std::string > &  FancyNames = {} 
)
inline

KS: Replace correlation matrix and tune values in YAML covariance matrix.

Parameters
rootThe root YAML node to be updated.
ValuesThe new values for each systematic.
ErrorsThe new errors for each systematic.
CorrelationThe new correlation matrix (must be square and match Values size).
OutYAMLNameThe output filename for the updated YAML.
FancyNamesOptional list of fancy names to match systematics (must match Values size if provided).

Definition at line 313 of file ParameterHandlerUtils.h.

318  {}) {
319 // *************************************
320  if (Values.size() != Errors.size() || Values.size() != Correlation.size()) {
321  MACH3LOG_ERROR("Size mismatch between Values, Errors, and Correlation matrix");
322  throw MaCh3Exception(__FILE__, __LINE__);
323  }
324 
325  for (const auto& row : Correlation) {
326  if (row.size() != Correlation.size()) {
327  MACH3LOG_ERROR("Correlation matrix is not square");
328  throw MaCh3Exception(__FILE__, __LINE__);
329  }
330  }
331 
332  YAML::Node NodeCopy = YAML::Clone(root);
333  YAML::Node systematics = NodeCopy["Systematics"];
334 
335  if (!systematics || !systematics.IsSequence()) {
336  MACH3LOG_ERROR("'Systematics' node is missing or not a sequence");
337  throw MaCh3Exception(__FILE__, __LINE__);
338  }
339 
340  if (!FancyNames.empty() && FancyNames.size() != Values.size()) {
341  MACH3LOG_ERROR("FancyNames size ({}) does not match Values size ({})", FancyNames.size(), Values.size());
342  throw MaCh3Exception(__FILE__, __LINE__);
343  }
344 
345  // Map from FancyName to Systematic node
346  std::unordered_map<std::string, YAML::Node> nameToNode;
347  for (std::size_t i = 0; i < systematics.size(); ++i) {
348  YAML::Node syst = systematics[i]["Systematic"];
349  if (!syst || !syst["Names"] || !syst["Names"]["FancyName"]) continue;
350  std::string name = syst["Names"]["FancyName"].as<std::string>();
351  nameToNode[name] = syst;
352  }
353 
354  if (!FancyNames.empty()) {
355  for (std::size_t i = 0; i < FancyNames.size(); ++i) {
356  const std::string& name_i = FancyNames[i];
357  auto it_i = nameToNode.find(name_i);
358  if (it_i == nameToNode.end()) {
359  MACH3LOG_ERROR("Could not find FancyName '{}' in YAML", name_i);
360  throw MaCh3Exception(__FILE__, __LINE__);
361  }
362  YAML::Node& syst_i = it_i->second;
363 
364  syst_i["ParameterValues"]["PreFitValue"] = M3::Utils::FormatDouble(Values[i], 4);
365  syst_i["Error"] = M3::Utils::FormatDouble(Errors[i], 4);
366 
367  YAML::Node correlationsNode = YAML::Node(YAML::NodeType::Sequence);
368  for (std::size_t j = 0; j < FancyNames.size(); ++j) {
369  if (i == j) continue;
370  // KS: Skip if value close to 0
371  if (std::abs(Correlation[i][j]) < 1e-8) continue;
372  YAML::Node singleEntry;
373  singleEntry[FancyNames[j]] = M3::Utils::FormatDouble(Correlation[i][j], 4);
374  correlationsNode.push_back(singleEntry);
375  }
376  syst_i["Correlations"] = correlationsNode;
377  }
378  } else {
379  if (systematics.size() != Values.size()) {
380  MACH3LOG_ERROR("Mismatch in sizes: Values has {}, but YAML 'Systematics' has {} entries",
381  Values.size(), systematics.size());
382  throw MaCh3Exception(__FILE__, __LINE__);
383  }
384 
385  for (std::size_t i = 0; i < systematics.size(); ++i) {
386  YAML::Node syst = systematics[i]["Systematic"];
387  if (!syst) {
388  MACH3LOG_ERROR("Missing 'Systematic' node at index {}", i);
389  throw MaCh3Exception(__FILE__, __LINE__);
390  }
391 
392  syst["ParameterValues"]["PreFitValue"] = M3::Utils::FormatDouble(Values[i], 4);
393  syst["Error"] = M3::Utils::FormatDouble(Errors[i], 4);
394 
395  YAML::Node correlationsNode = YAML::Node(YAML::NodeType::Sequence);
396  for (std::size_t j = 0; j < Correlation[i].size(); ++j) {
397  if (i == j) continue;
398  // KS: Skip if value close to 0
399  if (std::abs(Correlation[i][j]) < 1e-8) continue;
400  YAML::Node singleEntry;
401  const std::string& otherName = systematics[j]["Systematic"]["Names"]["FancyName"].as<std::string>();
402  singleEntry[otherName] = M3::Utils::FormatDouble(Correlation[i][j], 4);
403  correlationsNode.push_back(singleEntry);
404  }
405  syst["Correlations"] = correlationsNode;
406  }
407  }
408 
409  // Convert and write
410  std::string YAMLString = YAMLtoSTRING(NodeCopy);
411  FixSampleNamesQuotes(YAMLString);
412  std::ofstream outFile(OutYAMLName);
413  if (!outFile) {
414  MACH3LOG_ERROR("Failed to open file for writing: {}", OutYAMLName);
415  throw MaCh3Exception(__FILE__, __LINE__);
416  }
417 
418  outFile << YAMLString;
419  outFile.close();
420 }

◆ MakeMatrixPosDef()

int M3::MakeMatrixPosDef ( TMatrixDSym *  cov)
inline

Makes sure that matrix is positive-definite by adding a small number to on-diagonal elements.

Definition at line 551 of file ParameterHandlerUtils.h.

551  {
552 // *************************************
553  //DB Save original warning state and then increase it in this function to suppress 'matrix not positive definite' messages
554  //Means we no longer need to overload
555  int originalErrorWarning = gErrorIgnoreLevel;
556  gErrorIgnoreLevel = kFatal;
557 
558  //DB Loop 1000 times adding 1e-9 which tops out at 1e-6 shift on the diagonal before throwing error
559  constexpr int MaxAttempts = 1e5;
560  const int matrixSize = cov->GetNrows();
561  int iAttempt = 0;
562  bool CanDecomp = false;
563 
564  // HW: We'll store the diagonal first to prevent inflating the matrix too much!
565  std::vector<double> original_diagonal(matrixSize, 0.0);
566  for (int iVar = 0 ; iVar < matrixSize; iVar++) {
567  original_diagonal[iVar] = (*cov)(iVar, iVar);
568  }
569 
570  int attempts = 0;
571 
572  for (iAttempt = 0; iAttempt < MaxAttempts; iAttempt++) {
573  if (CanDecomposeMatrix(*cov)) {
574  CanDecomp = true;
575  attempts = iAttempt;
576  break;
577  }
578  else {
579  #ifdef MULTITHREAD
580  #pragma omp parallel for
581  #endif
582  for (int iVar = 0 ; iVar < matrixSize; iVar++) {
583  if( (*cov)(iVar, iVar)/10 > original_diagonal[iVar]) {
584  MACH3LOG_DEBUG("Diagonal element {} has been shifted too much (> original value/10). Stopping further shifts.", iVar);
585  original_diagonal[iVar] = 0; // Prevent further shifts for this element
586  continue;
587  }
588  (*cov)(iVar, iVar) += 1e-9;
589  }
590  }
591  }
592 
593  if (!CanDecomp) {
594  MACH3LOG_ERROR("Tried {} times to shift diagonal but still can not decompose the matrix", MaxAttempts);
595  MACH3LOG_ERROR("This indicates that something is wrong with the input matrix");
596  throw MaCh3Exception(__FILE__ , __LINE__ );
597  }
598 
599  //DB Resetting warning level
600  gErrorIgnoreLevel = originalErrorWarning;
601  return attempts;
602 }
#define MACH3LOG_DEBUG
Definition: MaCh3Logger.h:34
bool CanDecomposeMatrix(const TMatrixDSym &matrix)
Checks if a matrix can be Cholesky decomposed.

◆ MatrixMult() [1/3]

double** M3::MatrixMult ( double **  A,
double **  B,
int  n 
)
inline

CW: Multi-threaded matrix multiplication.

Definition at line 107 of file ParameterHandlerUtils.h.

107  {
108  // First make into monolithic array
109  double *A_mon = new double[n*n];
110  double *B_mon = new double[n*n];
111 
112  #ifdef MULTITHREAD
113  #pragma omp parallel for
114  #endif
115  for (int i = 0; i < n; ++i) {
116  for (int j = 0; j < n; ++j) {
117  A_mon[i*n+j] = A[i][j];
118  B_mon[i*n+j] = B[i][j];
119  }
120  }
121  //CW: Now call the monolithic calculator
122  double *C_mon = MatrixMult(A_mon, B_mon, n);
123  delete A_mon;
124  delete B_mon;
125 
126  // Return the double pointer
127  double **C = new double*[n];
128  #ifdef MULTITHREAD
129  #pragma omp parallel for
130  #endif
131  for (int i = 0; i < n; ++i) {
132  C[i] = new double[n];
133  for (int j = 0; j < n; ++j) {
134  C[i][j] = C_mon[i*n+j];
135  }
136  }
137  delete C_mon;
138 
139  return C;
140 }
TMatrixD MatrixMult(TMatrixD A, TMatrixD B)
CW: Multi-threaded matrix multiplication.

◆ MatrixMult() [2/3]

double* M3::MatrixMult ( double *  A,
double *  B,
int  n 
)
inline

CW: Multi-threaded matrix multiplication.

Definition at line 75 of file ParameterHandlerUtils.h.

75  {
76  //CW: First transpose to increse cache hits
77  double *BT = new double[n*n];
78  #ifdef MULTITHREAD
79  #pragma omp parallel for
80  #endif
81  for (int i = 0; i < n; i++) {
82  for (int j = 0; j < n; j++) {
83  BT[j*n+i] = B[i*n+j];
84  }
85  }
86 
87  // Now multiply
88  double *C = new double[n*n];
89  #ifdef MULTITHREAD
90  #pragma omp parallel for
91  #endif
92  for (int i = 0; i < n; i++) {
93  for (int j = 0; j < n; j++) {
94  double sum = 0;
95  for (int k = 0; k < n; k++) {
96  sum += A[i*n+k]*BT[j*n+k];
97  }
98  C[i*n+j] = sum;
99  }
100  }
101  delete BT;
102 
103  return C;
104 }

◆ MatrixMult() [3/3]

TMatrixD M3::MatrixMult ( TMatrixD  A,
TMatrixD  B 
)
inline

CW: Multi-threaded matrix multiplication.

Definition at line 143 of file ParameterHandlerUtils.h.

144 {
145  double *C_mon = MatrixMult(A.GetMatrixArray(), B.GetMatrixArray(), A.GetNcols());
146  TMatrixD C;
147  C.Use(A.GetNcols(), A.GetNrows(), C_mon);
148  return C;
149 }

◆ MatrixVectorMulti()

void M3::MatrixVectorMulti ( double *_restrict_  VecMulti,
double **_restrict_  matrix,
const double *_restrict_  vector,
const int  n 
)
inline

KS: Custom function to perform multiplication of matrix and vector with multithreading.

Parameters
VecMultiOutput Vector, VecMulti = matrix x vector
matrixThis matrix is used for multiplication VecMulti = matrix x vector
vectorThis vector is used for multiplication VecMulti = matrix x vector
nthis is size of matrix and vector, we assume matrix is symmetric

Definition at line 157 of file ParameterHandlerUtils.h.

157  {
158 // ********************************************
159  #ifdef MULTITHREAD
160  #pragma omp parallel for
161  #endif
162  for (int i = 0; i < n; ++i)
163  {
164  double result = 0.0;
165  #ifdef MULTITHREAD
166  #pragma omp simd
167  #endif
168  for (int j = 0; j < n; ++j)
169  {
170  result += matrix[i][j]*vector[j];
171  }
172  VecMulti[i] = result;
173  }
174 }

◆ MatrixVectorMultiSingle()

double M3::MatrixVectorMultiSingle ( double **_restrict_  matrix,
const double *_restrict_  vector,
const int  Length,
const int  i 
)
inline

KS: Custom function to perform multiplication of matrix and single element which is thread safe.

Parameters
matrixThis matrix is used for multiplication VecMulti = matrix x vector
vectorThis vector is used for multiplication VecMulti = matrix x vector
Lengththis is size of matrix and vector, we assume matrix is symmetric
iElement of matrix that we want to multiply

Definition at line 182 of file ParameterHandlerUtils.h.

182  {
183 // ********************************************
184  double Element = 0.0;
185  #ifdef MULTITHREAD
186  #pragma omp simd
187  #endif
188  for (int j = 0; j < Length; ++j) {
189  Element += matrix[i][j]*vector[j];
190  }
191  return Element;
192 }

◆ Open()

TFile * M3::Open ( const std::string &  Name,
const std::string &  Type,
const std::string &  File,
const int  Line 
)

Opens a ROOT file with the given name and mode.

This function wraps ROOT’s TFile constructor and checks whether the file was opened successfully and give some useful debugging information

Parameters
NameThe name or path of the file to open.
TypeThe file open mode (e.g., "READ", "RECREATE", "UPDATE").
FileThe name of the file where the exception occurred.
LineThe line number where the exception occurred.
Returns
Pointer to the opened ROOT file.

Definition at line 771 of file HistogramUtils.cpp.

771  {
772 // **************************************************************************
773  TFile* OutFile = new TFile(Name.c_str(), Type.c_str());
774 
775  // Check if the file is successfully opened and usable
776  if (OutFile->IsZombie()) {
777  MACH3LOG_ERROR("Failed to open file: {}", Name);
778  std::string lowerType = Type;
779  std::transform(lowerType.begin(), lowerType.end(), lowerType.begin(), ::tolower);
780  if (lowerType == "recreate") {
781  MACH3LOG_ERROR("Check if directory exist");
782  }
783  delete OutFile;
784  throw MaCh3Exception(File, Line);
785  }
786  return OutFile;
787 }

◆ ParseBiasFunction()

M3::BiasFunction M3::ParseBiasFunction ( const std::string &  biasFunctionName)
inline

Definition at line 21 of file MulticanonicalMCMCHandler.h.

21  {
22  if (biasFunctionName == "gaussian") {
24  }
25  if (biasFunctionName == "vonMises") {
27  }
28  if (biasFunctionName == "generalisedGaussian") {
30  }
31  throw MaCh3Exception(__FILE__, __LINE__, "Unknown multicanonical bias function: " + biasFunctionName);
32  }

◆ PolyToYaml()

YAML::Node M3::PolyToYaml ( TH2Poly *  Hist,
const std::string &  YamlName,
const std::string &  File,
const int  Line 
)

KS: Convert TH2Poly into yaml config accepted by MaCh3.

Definition at line 880 of file HistogramUtils.cpp.

880  {
881 // ***************************************************************************
882  if (!Hist) {
883  MACH3LOG_ERROR("Null TH2Poly pointer");
884  throw MaCh3Exception(File, Line);
885  }
886 
887  YAML::Node bins(YAML::NodeType::Sequence);
888  bins.SetStyle(YAML::EmitterStyle::Flow);
889  const int NBins = Hist->GetNumberOfBins();
890 
891  for (int j = 1; j <= NBins; j++)
892  {
893  TH2PolyBin* polybin = static_cast<TH2PolyBin*>(Hist->GetBins()->At(j - 1));
894 
895  double xmin = polybin->GetXMin();
896  double xmax = polybin->GetXMax();
897  double ymin = polybin->GetYMin();
898  double ymax = polybin->GetYMax();
899 
900  YAML::Node xNode(YAML::NodeType::Sequence);
901  xNode.SetStyle(YAML::EmitterStyle::Flow);
902  xNode.push_back(xmin);
903  xNode.push_back(xmax);
904 
905  YAML::Node yNode(YAML::NodeType::Sequence);
906  yNode.SetStyle(YAML::EmitterStyle::Flow);
907  yNode.push_back(ymin);
908  yNode.push_back(ymax);
909 
910  YAML::Node bin(YAML::NodeType::Sequence);
911  bin.SetStyle(YAML::EmitterStyle::Flow);
912  bin.push_back(xNode);
913  bin.push_back(yNode);
914 
915  bins.push_back(bin);
916  }
917 
918  YAML::Node result;
919  result[YamlName] = bins;
920 
921  return result;
922 }

◆ ScaleHistogram()

void M3::ScaleHistogram ( TH1 *  Sample_Hist,
const double  scale 
)

Scale histogram to get divided by bin width.

Definition at line 790 of file HistogramUtils.cpp.

790  {
791 // ***************************************************************************
792  for (int j = 0; j <= Sample_Hist->GetNbinsX(); ++j)
793  {
794  double num = Sample_Hist->GetBinContent(j);
795  double numErr = Sample_Hist->GetBinError(j);
796  double den = Sample_Hist->GetBinWidth(j);
797  double value = 0.;
798  double valueErr = 0.;
799  if (den != 0)
800  {
801  value = num/(den/scale);
802  valueErr = numErr/(den/scale);
803  Sample_Hist->SetBinContent(j,value);
804  Sample_Hist->SetBinError(j,valueErr);
805  }
806  }
807 }

Variable Documentation

◆ _BAD_DOUBLE_

constexpr static const double M3::_BAD_DOUBLE_ = -999.99
staticconstexpr

Default value used for double initialisation.

Definition at line 53 of file Core.h.

◆ _BAD_INT_

constexpr static const int M3::_BAD_INT_ = -999
staticconstexpr

Default value used for int initialisation.

Definition at line 55 of file Core.h.

◆ _DEFAULT_RETURN_VAL_

constexpr static const double M3::_DEFAULT_RETURN_VAL_ = -999999.123456
staticconstexpr

Definition at line 56 of file Core.h.

◆ _LARGE_LOGL_

constexpr static const double M3::_LARGE_LOGL_ = 1234567890.0
staticconstexpr

Large Likelihood is used it parameter go out of physical boundary, this indicates in MCMC that such step should be removed.

Definition at line 80 of file Core.h.

◆ _LOW_MC_BOUND_

constexpr static const double M3::_LOW_MC_BOUND_ = .00001
staticconstexpr

MC prediction lower bound in bin to identify problematic binning definitions and handle LogL calculation.

Definition at line 83 of file Core.h.

◆ DefSplineKnotLowBound

constexpr static const double M3::DefSplineKnotLowBound = -9999
staticconstexpr

Default value for spline knot capping, default mean not capping is being applied.

Definition at line 88 of file Core.h.

◆ DefSplineKnotUpBound

constexpr static const double M3::DefSplineKnotUpBound = 9999
staticconstexpr

Default value for spline knot capping, default mean not capping is being applied.

Definition at line 86 of file Core.h.

◆ float_t_str_repr

constexpr static const char* M3::float_t_str_repr = "D"
staticconstexpr

Definition at line 40 of file Core.h.

◆ KinematicLowBound

constexpr static const double M3::KinematicLowBound = std::numeric_limits<double>::lowest()
staticconstexpr

When parameter has no bound this serves as it. Lowest possible value the system.

Definition at line 75 of file Core.h.

◆ KinematicUpBound

constexpr static const double M3::KinematicUpBound = std::numeric_limits<double>::max()
staticconstexpr

When parameter has no bound this serves as it. Highest possible value the system.

Definition at line 77 of file Core.h.

◆ UmbrellaGaussianNormFactor

constexpr double M3::UmbrellaGaussianNormFactor = 0.906402477055
constexpr

Normalisation constant for the n=2 umbrella sampling Gaussian.

The factor comes from: 2n / Gamma(1/(2n)) with n = 2: 4 / Gamma(1/4) = 0.906402477055

Definition at line 53 of file MulticanonicalMCMCHandler.h.

◆ UnderOverFlowBin

constexpr static const int M3::UnderOverFlowBin = -1
staticconstexpr

Mark bin which is overflow or underflow in MaCh3 binning.

Definition at line 91 of file Core.h.

◆ Unity

constexpr static const float_t M3::Unity = Unity_D
staticconstexpr

Definition at line 64 of file Core.h.

◆ Unity_D

constexpr static const double M3::Unity_D = 1.
staticconstexpr

Some commonly used variables to which we set pointers to.

Definition at line 59 of file Core.h.

◆ Unity_F

constexpr static const float M3::Unity_F = 1.
staticconstexpr

Definition at line 60 of file Core.h.

◆ Zero

constexpr static const float_t M3::Zero = Zero_D
staticconstexpr

Definition at line 71 of file Core.h.

◆ Zero_D

constexpr static const double M3::Zero_D = 0.
staticconstexpr

Definition at line 66 of file Core.h.

◆ Zero_F

constexpr static const float M3::Zero_F = 0.
staticconstexpr

Definition at line 67 of file Core.h.