MaCh3  2.6.0
Reference Guide
Namespaces | 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.
 
 Utils
 Utility helpers used across MaCh3.
 

Typedefs

using float_t = double
 
using int_t = int
 
using uint_t = unsigned
 

Enumerations

enum class  BiasFunction { kGaussian , kVonMises , kGeneralisedGaussian }
 
enum  kInfCrit { kBIC , kDIC , kWAIC , kInfCrits }
 KS: Different Information Criterion tests mostly based Gelman paper. More...
 
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...
 
int GetThreadIndex ()
 thread index inside parallel loop 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...
 

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...
 

Detailed Description

Main namespace for MaCh3 software.

Typedef Documentation

◆ float_t

typedef double M3::float_t

Definition at line 37 of file Core.h.

◆ 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 233 of file ParameterHandlerUtils.h.

236  {}) {
237 // *************************************
238  YAML::Node NodeCopy = YAML::Clone(root);
239  YAML::Node systematics = NodeCopy["Systematics"];
240 
241  if (!systematics || !systematics.IsSequence()) {
242  MACH3LOG_ERROR("'Systematics' node is missing or not a sequence in the YAML copy");
243  throw MaCh3Exception(__FILE__, __LINE__);
244  }
245 
246  if (!FancyNames.empty() && FancyNames.size() != Values.size()) {
247  MACH3LOG_ERROR("Mismatch in sizes: FancyNames has {}, but Values has {}", FancyNames.size(), Values.size());
248  throw MaCh3Exception(__FILE__, __LINE__);
249  }
250 
251  if (FancyNames.empty() && systematics.size() != Values.size()) {
252  MACH3LOG_ERROR("Mismatch in sizes: Values has {}, but YAML 'Systematics' has {} entries",
253  Values.size(), systematics.size());
254  throw MaCh3Exception(__FILE__, __LINE__);
255  }
256 
257  if (!FancyNames.empty()) {
258  for (std::size_t i = 0; i < FancyNames.size(); ++i) {
259  bool matched = false;
260  for (std::size_t j = 0; j < systematics.size(); ++j) {
261  YAML::Node systematicNode = systematics[j]["Systematic"];
262  if (!systematicNode) continue;
263  auto nameNode = systematicNode["Names"];
264  if (!nameNode || !nameNode["FancyName"]) continue;
265  if (nameNode["FancyName"].as<std::string>() == FancyNames[i]) {
266  if (!systematicNode["ParameterValues"]) {
267  MACH3LOG_ERROR("Missing 'ParameterValues' for matched FancyName '{}'", FancyNames[i]);
268  throw MaCh3Exception(__FILE__, __LINE__);
269  }
270  systematicNode["ParameterValues"][Tune] = M3::Utils::FormatDouble(Values[i], 4);
271  matched = true;
272  break;
273  }
274  }
275  if (!matched) {
276  MACH3LOG_ERROR("Could not find a matching FancyName '{}' in the systematics", FancyNames[i]);
277  throw MaCh3Exception(__FILE__, __LINE__);
278  }
279  }
280  } else {
281  for (std::size_t i = 0; i < systematics.size(); ++i) {
282  YAML::Node systematicNode = systematics[i]["Systematic"];
283  if (!systematicNode || !systematicNode["ParameterValues"]) {
284  MACH3LOG_ERROR("Missing 'Systematic' or 'ParameterValues' entry at index {}", i);
285  throw MaCh3Exception(__FILE__, __LINE__);
286  }
287  systematicNode["ParameterValues"][Tune] = M3::Utils::FormatDouble(Values[i], 4);
288  }
289  }
290 
291  // Convert updated copy to string
292  std::string YAMLString = YAMLtoSTRING(NodeCopy);
293  FixSampleNamesQuotes(YAMLString);
294  // Write to output file
295  std::string OutName = "UpdatedMatrixWithTune" + Tune + ".yaml";
296  std::ofstream outFile(OutName);
297  if (!outFile) {
298  MACH3LOG_ERROR("Failed to open file for writing: {}", OutName);
299  throw MaCh3Exception(__FILE__, __LINE__);
300  }
301 
302  outFile << YAMLString;
303  outFile.close();
304 }
std::string YAMLtoSTRING(const YAML::Node &node)
KS: Convert a YAML node to a string representation.
Definition: YamlHelper.h:112
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...

◆ 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 544 of file ParameterHandlerUtils.h.

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

◆ 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 66 of file ParameterHandlerUtils.h.

66  {
67  for (size_t i = 0; i < Patterns.size(); i++) {
68  if (M3::CaseInsentiveMatch(Text, Patterns[i])) {
69  return true;
70  }
71  }
72  return false;
73 }
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 45 of file ParameterHandlerUtils.h.

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

◆ 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 821 of file HistogramUtils.cpp.

821  {
822 // ***************************************************************************
823  if (Hist1->GetNbinsX() != Hist2->GetNbinsX()) {
824  MACH3LOG_ERROR("Number of bins does not match for TH1D: {} vs {}", Hist1->GetNbinsX(), Hist2->GetNbinsX());
825  throw MaCh3Exception(File, Line);
826  }
827  for (int i = 1; i <= Hist1->GetNbinsX(); ++i) {
828  if (std::fabs(Hist1->GetXaxis()->GetBinLowEdge(i) - Hist2->GetXaxis()->GetBinLowEdge(i)) > 0.001 ||
829  std::fabs(Hist1->GetXaxis()->GetBinUpEdge(i) - Hist2->GetXaxis()->GetBinUpEdge(i)) > 0.001) {
830  MACH3LOG_ERROR("Bin edges do not match for TH1D at bin {}", i);
831  throw MaCh3Exception(File, Line);
832  }
833  }
834 }

◆ 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 837 of file HistogramUtils.cpp.

837  {
838 // ***************************************************************************
839  if (Hist1->GetNbinsX() != Hist2->GetNbinsX() || Hist1->GetNbinsY() != Hist2->GetNbinsY()) {
840  MACH3LOG_ERROR("Number of bins does not match for TH2D");
841  throw MaCh3Exception(File, Line);
842  }
843 
844  for (int i = 1; i <= Hist1->GetNbinsX(); ++i) {
845  if (std::fabs(Hist1->GetXaxis()->GetBinLowEdge(i) - Hist2->GetXaxis()->GetBinLowEdge(i)) > 0.001 ||
846  std::fabs(Hist1->GetXaxis()->GetBinUpEdge(i) - Hist2->GetXaxis()->GetBinUpEdge(i)) > 0.001) {
847  MACH3LOG_ERROR("X bin edges do not match for TH2D at bin {}", i);
848  throw MaCh3Exception(File, Line);
849  }
850  }
851  for (int j = 1; j <= Hist1->GetNbinsY(); ++j) {
852  if (std::fabs(Hist1->GetYaxis()->GetBinLowEdge(j) - Hist2->GetYaxis()->GetBinLowEdge(j)) > 0.001 ||
853  std::fabs(Hist1->GetYaxis()->GetBinUpEdge(j) - Hist2->GetYaxis()->GetBinUpEdge(j)) > 0.001) {
854  MACH3LOG_ERROR("Y bin edges do not match for TH2D at bin {}", j);
855  throw MaCh3Exception(File, Line);
856  }
857  }
858 }

◆ 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 862 of file HistogramUtils.cpp.

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

◆ 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 155 of file HistogramUtils.h.

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

◆ 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 710 of file ParameterHandlerUtils.h.

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

◆ 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 610 of file ParameterHandlerUtils.h.

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

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

◆ fmaf_t()

template<typename T >
constexpr T M3::fmaf_t ( x,
y,
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 508 of file ParameterHandlerUtils.h.

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

◆ 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 428 of file ParameterHandlerUtils.h.

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

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

◆ 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 }

◆ GetThreadIndex()

int M3::GetThreadIndex ( )
inline

thread index inside parallel loop

Definition at line 86 of file Monitor.h.

86  {
87  #ifdef MULTITHREAD
88  return omp_get_thread_num();
89  #else
90  return 0;
91  #endif
92  }

◆ 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 314 of file ParameterHandlerUtils.h.

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

◆ 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 552 of file ParameterHandlerUtils.h.

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

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

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

◆ MatrixMult() [3/3]

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

CW: Multi-threaded matrix multiplication.

Definition at line 144 of file ParameterHandlerUtils.h.

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

◆ 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 158 of file ParameterHandlerUtils.h.

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

◆ 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 183 of file ParameterHandlerUtils.h.

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

◆ 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 782 of file HistogramUtils.cpp.

782  {
783 // **************************************************************************
784  TFile* OutFile = new TFile(Name.c_str(), Type.c_str());
785 
786  // Check if the file is successfully opened and usable
787  if (OutFile->IsZombie()) {
788  MACH3LOG_ERROR("Failed to open file: {}", Name);
789  std::string lowerType = Type;
790  std::transform(lowerType.begin(), lowerType.end(), lowerType.begin(), ::tolower);
791  if (lowerType == "recreate") {
792  MACH3LOG_ERROR("Check if directory exist");
793  }
794  delete OutFile;
795  throw MaCh3Exception(File, Line);
796  }
797  return OutFile;
798 }

◆ 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 891 of file HistogramUtils.cpp.

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

◆ ScaleHistogram()

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

Scale histogram to get divided by bin width.

Definition at line 801 of file HistogramUtils.cpp.

801  {
802 // ***************************************************************************
803  for (int j = 0; j <= Sample_Hist->GetNbinsX(); ++j)
804  {
805  double num = Sample_Hist->GetBinContent(j);
806  double numErr = Sample_Hist->GetBinError(j);
807  double den = Sample_Hist->GetBinWidth(j);
808  double value = 0.;
809  double valueErr = 0.;
810  if (den != 0)
811  {
812  value = num/(den/scale);
813  valueErr = numErr/(den/scale);
814  Sample_Hist->SetBinContent(j,value);
815  Sample_Hist->SetBinError(j,valueErr);
816  }
817  }
818 }

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.

◆ 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.