MaCh3  2.6.1
Reference Guide
GetPenaltyTermModule.cpp
Go to the documentation of this file.
1 // MaCh3 includes
2 #include "Manager/Manager.h"
7 
9 // ROOT includes
10 #include "TFile.h"
11 #include "TBranch.h"
12 #include "TCanvas.h"
13 #include "TLine.h"
14 #include "TLegend.h"
15 #include "TString.h"
16 #include "TStyle.h"
17 #include "TMatrixT.h"
18 #include "TMatrixDSym.h"
19 #include "TVectorD.h"
20 #include "TObject.h"
21 #include "TChain.h"
22 #include "TH1.h"
23 #include "TColor.h"
24 #include "TObjString.h"
25 #include "TROOT.h"
27 
28 namespace M3{
29 
31 
33  m_parser = std::make_unique<MaCh3ArgumentParser>("penterm", "1.0", argparse::default_arguments::help);
34  m_parser->add_description("Calculate penalty term for selected parameters, for every step");
35  m_parser->add_argument("inputfile")
36  .help("Root file to analyse.")
37  .metavar("INPUTFILE")
38  .required();
39  m_parser->add_argument("config")
40  .help("Config file.")
41  .metavar("CONFIG")
42  .required();
43  return m_parser.get();
44  }
45 
46  int GetPenaltyTermModule::Run()//int argc, char *argv[])
47  {
50  std::string inputFile = m_parser->get<std::string>("inputfile");
51  std::string config = m_parser->get<std::string>("config");
52  this->GetPenaltyTerm(inputFile, config);
53 
54  return 0;
55  }
56 
68  void GetPenaltyTermModule::ReadCovFile(const std::string& inputFile,
69  std::vector <double>& Prior,
70  std::vector <bool>& isFlat,
71  std::vector<std::string>& ParamNames,
72  std::vector<std::vector<double>>& invCovMatrix,
73  int& nParams)
74  {
75  // Now read the MCMC file
76  TFile *TempFile = M3::Open(inputFile, "open", __FILE__, __LINE__);
77 
78  // Get the matrix
79  TDirectory* CovarianceFolder = TempFile->Get<TDirectory>("CovarianceFolder");
80  TMatrixDSym *CovMatrix = M3::GetCovMatrixFromChain(CovarianceFolder);
81 
82  // Get the settings for the MCMC
83  TMacro *Config = TempFile->Get<TMacro>("MaCh3_Config");
84  if (Config == nullptr) {
85  MACH3LOG_ERROR("Didn't find MaCh3_Config tree in MCMC file! {}", inputFile);
86  TempFile->ls();
87  throw MaCh3Exception(__FILE__ , __LINE__ );
88  }
89 
90  YAML::Node Settings = TMacroToYAML(*Config);
91 
92  //CW: Get the Covariance matrix
93  std::vector<std::string> CovPos = GetFromManager<std::vector<std::string>>(Settings["General"]["Systematics"]["XsecCovFile"], {"none"}, __FILE__, __LINE__);
94  if(CovPos.back() == "none")
95  {
96  MACH3LOG_WARN("Couldn't find Cov branch in output");
97  M3::Utils::PrintConfig(Settings);
98  throw MaCh3Exception(__FILE__ , __LINE__ );
99  }
100 
101  //KS:Most inputs are in ${MACH3}/inputs/blarb.root
102  if (std::getenv("MACH3") != nullptr) {
103  MACH3LOG_INFO("Found MACH3 environment variable: {}", std::getenv("MACH3"));
104  for(unsigned int i = 0; i < CovPos.size(); i++)
105  CovPos[i].insert(0, std::string(std::getenv("MACH3"))+"/");
106  }
107 
108  YAML::Node CovFile;
109  CovFile["Systematics"] = YAML::Node(YAML::NodeType::Sequence);
110  for(unsigned int i = 0; i < CovPos.size(); i++)
111  {
112  YAML::Node YAMLDocTemp = M3OpenConfig(CovPos[i]);
113  for (const auto& item : YAMLDocTemp["Systematics"]) {
114  CovFile["Systematics"].push_back(item);
115  }
116  }
117 
118  nParams = CovMatrix->GetNrows();
119 
120  auto systematics = CovFile["Systematics"];
121  for (auto it = systematics.begin(); it != systematics.end(); ++it)
122  {
123  auto const &param = *it;
124 
125  ParamNames.push_back(param["Systematic"]["Names"]["FancyName"].as<std::string>());
126  Prior.push_back( param["Systematic"]["ParameterValues"]["PreFitValue"].as<double>() );
127 
128  bool flat = false;
129  if (param["Systematic"]["FlatPrior"]) { flat = param["Systematic"]["FlatPrior"].as<bool>(); }
130  isFlat.push_back( flat );
131  }
132 
133  CovMatrix->Invert();
134  //KS: Let's use double as it is faster than TMatrix
135  invCovMatrix.resize(nParams, std::vector<double>(nParams, -999));
136 
137  #ifdef MULTITHREAD
138  #pragma omp parallel for collapse(2)
139  #endif
140  for (int i = 0; i < nParams; i++)
141  {
142  for (int j = 0; j < nParams; ++j)
143  {
144  invCovMatrix[i][j] = (*CovMatrix)(i,j);
145  }
146  }
147 
148  TempFile->Close();
149  delete TempFile;
150  }
151 
163  void GetPenaltyTermModule::LoadSettings(YAML::Node& Settings,
164  std::vector<std::string>& SetsNames,
165  std::vector<std::string>& FancyTitle,
166  std::vector<std::vector<bool>>& isRelevantParam,
167  const std::vector<std::string>& ParamNames,
168  const int nParams)
169  {
170  std::vector<std::string> node = Settings["GetPenaltyTerm"]["PenaltySets"].as<std::vector<std::string>>();
171  std::vector<std::vector<std::string>> RemoveNames;
172  std::vector<bool> Exclude;
173 
174  for (unsigned int i = 0; i < node.size(); i++)
175  {
176  std::string ParName = node[i];
177  SetsNames.push_back(ParName);
178 
179  const auto& Set = Settings["GetPenaltyTerm"][ParName];
180 
181  RemoveNames.push_back(Set[0].as<std::vector<std::string>>());
182  Exclude.push_back(Set[1].as<bool>());
183  FancyTitle.push_back(Set[2].as<std::string>());
184  }
185 
186  const int NSets = int(SetsNames.size());
187 
188  isRelevantParam.resize(NSets);
189  //Loop over sets in the config
190  for(int i = 0; i < NSets; i++)
191  {
192  isRelevantParam[i].resize(nParams);
193  int counter = 0;
194  //Loop over parameters in the Covariance object
195  for (int j = 0; j < nParams; j++)
196  {
197  isRelevantParam[i][j] = false;
198 
199  //KS: Here we loop over all names and if parameters wasn't matched then we set it is relevant.
200  if(Exclude[i])
201  {
202  bool found = false;
203  for (unsigned int k = 0; k < RemoveNames[i].size(); k++)
204  {
205  if (ParamNames[j].rfind(RemoveNames[i][k], 0) == 0)
206  {
207  found = true;
208  }
209  }
210  if(!found)
211  {
212  isRelevantParam[i][j] = true;
213  counter++;
214  }
215  }
216  //KS: Here is much simpler, if parameter matched then it is relevant
217  else
218  {
219  for (unsigned int k = 0; k < RemoveNames[i].size(); k++)
220  {
221  if (ParamNames[j].rfind(RemoveNames[i][k], 0) == 0)
222  {
223  isRelevantParam[i][j] = true;
224  counter++;
225  break;
226  }
227  }
228  }
229  }
230  MACH3LOG_INFO(" Found {} params for set {}", counter, SetsNames[i]);
231  }
232  }
233 
242  void GetPenaltyTermModule::GetPenaltyTerm(const std::string& inputFile, const std::string& configFile)
243  {
244  auto canvas = std::make_unique<TCanvas>("canvas", "canvas", 0, 0, 1024, 1024);
245  canvas->SetGrid();
246  canvas->SetTickx();
247  canvas->SetTicky();
248 
249  canvas->SetBottomMargin(0.1f);
250  canvas->SetTopMargin(0.02f);
251  canvas->SetRightMargin(0.08f);
252  canvas->SetLeftMargin(0.15f);
253 
254  gStyle->SetOptTitle(0);
255  gStyle->SetOptStat(0);
256  gStyle->SetPalette(51);
257 
258  std::vector <double> Prior;
259  std::vector <bool> isFlat;
260  std::vector<std::string> ParamNames;
261  std::vector<std::vector<double>> invCovMatrix;
262  int nParams;
263  this->ReadCovFile(inputFile, Prior, isFlat, ParamNames, invCovMatrix, nParams);
264 
265  std::vector<TString> BranchNames;
266 
267  // Open the Chain
268  TChain* Chain = new TChain("posteriors","");
269  Chain->Add(inputFile.c_str());
270 
271  // Get the list of branches
272  TObjArray* brlis = Chain->GetListOfBranches();
273 
274  // Get the number of branches
275  int nBranches = brlis->GetEntries();
276  int RelevantBranches = 0;
277  for (int i = 0; i < nBranches; i++)
278  {
279  // Get the TBranch and its name
280  TBranch* br = static_cast<TBranch*>(brlis->At(i));
281  if(!br){
282  MACH3LOG_ERROR("Invalid branch at position {}", i);
283  throw MaCh3Exception(__FILE__,__LINE__);
284  }
285  TString bname = br->GetName();
286 
287  // If we're on beam systematics
288  if(bname.BeginsWith("param_"))
289  {
290  BranchNames.push_back(bname);
291  RelevantBranches++;
292  }
293  }
294 
295  // Set all the branches to off
296  Chain->SetBranchStatus("*", false);
297 
298  std::vector<double> fParProp(RelevantBranches);
299  // Turn on the branches which we want for parameters
300  for (int i = 0; i < RelevantBranches; ++i)
301  {
302  Chain->SetBranchStatus(BranchNames[i].Data(), true);
303  Chain->SetBranchAddress(BranchNames[i].Data(), &fParProp[i]);
304  }
305 
306  YAML::Node Settings = M3OpenConfig(configFile);
307  std::vector<std::string> SetsNames;
308  std::vector<std::string> FancyTitle;
309  std::vector<std::vector<bool>> isRelevantParam;
310 
311  this->LoadSettings(Settings, SetsNames, FancyTitle, isRelevantParam, ParamNames, nParams);
312 
313  const int NSets = int(SetsNames.size());
314  int AllEvents = int(Chain->GetEntries());
315  std::vector<std::unique_ptr<TH1D>> hLogL(NSets);
316  for (int i = 0; i < NSets; i++) {
317  std::string NameTemp = "LogL_" + SetsNames[i];
318  hLogL[i] = std::make_unique<TH1D>(NameTemp.c_str(), NameTemp.c_str(), AllEvents, 0, AllEvents);
319  hLogL[i]->SetLineColor(kBlue);
320  }
321  std::vector<double> logL(NSets, 0.0);
322  for(int n = 0; n < AllEvents; ++n)
323  {
324  if(n%10000 == 0) M3::Utils::PrintProgressBar(n, AllEvents);
325 
326  Chain->GetEntry(n);
327 
328  for(int k = 0; k < NSets; ++k) logL[k] = 0.;
329  #ifdef MULTITHREAD
330  // The per-thread array
331  double *logL_private = nullptr;
332 
333  // Declare the omp parallel region
334  // The parallel region needs to stretch beyond the for loop!
335  #pragma omp parallel private(logL_private)
336  {
337  logL_private = new double[NSets];
338  for(int k = 0; k < NSets; ++k) logL_private[k] = 0.;
339 
340  #pragma omp for
341  for (int i = 0; i < nParams; i++)
342  {
343  for (int j = 0; j <= i; ++j)
344  {
345  //check if flat prior
346  if (!isFlat[i] && !isFlat[j])
347  {
348  for(int k = 0; k < NSets; ++k)
349  {
350  //Check if parameter is relevant for this set
351  if (isRelevantParam[k][i] && isRelevantParam[k][j])
352  {
353  //KS: Since matrix is symmetric we can calculate non diagonal elements only once and multiply by 2, can bring up to factor speed decrease.
354  int scale = 1;
355  if(i != j) scale = 2;
356  logL_private[k] += scale * 0.5*(fParProp[i] - Prior[i])*(fParProp[j] - Prior[j])*invCovMatrix[i][j];
357  }
358  }
359  }
360  }
361  }
362  // Now we can write the individual arrays from each thread to the main array
363  for(int k = 0; k < NSets; ++k)
364  {
365  #pragma omp atomic
366  logL[k] += logL_private[k];
367  }
368  //Delete private arrays
369  delete[] logL_private;
370  }//End omp range
371 
372  #else
373  for (int i = 0; i < nParams; i++)
374  {
375  for (int j = 0; j <= i; ++j)
376  {
377  //check if flat prior
378  if (!isFlat[i] && !isFlat[j])
379  {
380  for(int k = 0; k < NSets; ++k)
381  {
382  //Check if parameter is relevant for this set
383  if (isRelevantParam[k][i] && isRelevantParam[k][j])
384  {
385  //KS: Since matrix is symmetric we can calculate non diagonal elements only once and multiply by 2, can bring up to factor speed decrease.
386  int scale = 1;
387  if(i != j) scale = 2;
388  logL[k] += scale * 0.5*(fParProp[i] - Prior[i])*(fParProp[j] - Prior[j])*invCovMatrix[i][j];
389  }
390  }
391  }
392  }
393  }
394  #endif // end MULTITHREAD
395  for(int k = 0; k < NSets; ++k)
396  {
397  hLogL[k]->SetBinContent(n, logL[k]);
398  }
399  }//End loop over steps
400 
401  // Directory for posteriors
402  std::string OutputName = inputFile + "_PenaltyTerm" +".root";
403  TFile *OutputFile = M3::Open(OutputName, "recreate", __FILE__, __LINE__);
404  TDirectory *PenaltyTermDir = OutputFile->mkdir("PenaltyTerm");
405 
406  canvas->Print(Form("%s_PenaltyTerm.pdf[",inputFile.c_str()), "pdf");
407  for(int i = 0; i < NSets; i++)
408  {
409  const double Maximum = hLogL[i]->GetMaximum();
410  hLogL[i]->GetYaxis()->SetRangeUser(0., Maximum*1.2);
411  hLogL[i]->SetTitle(FancyTitle[i].c_str());
412  hLogL[i]->GetXaxis()->SetTitle("Step");
413  hLogL[i]->GetYaxis()->SetTitle(FancyTitle[i].c_str());
414  hLogL[i]->GetYaxis()->SetTitleOffset(1.4f);
415 
416  hLogL[i]->Draw("");
417 
418  PenaltyTermDir->cd();
419  hLogL[i]->Write();
420 
421  canvas->Print(Form("%s_PenaltyTerm.pdf",inputFile.c_str()), "pdf");
422  }
423  canvas->Print(Form("%s_PenaltyTerm.pdf]",inputFile.c_str()), "pdf");
424  delete Chain;
425 
426  OutputFile->Close();
427  delete OutputFile;
428  }
429 }
#define _MaCh3_Safe_Include_Start_
KS: Avoiding warning checking for headers.
Definition: Core.h:126
#define _MaCh3_Safe_Include_End_
Module for extracting penalty terms from systematic chains.
#define MACH3LOG_ERROR
Definition: MaCh3Logger.h:37
#define MACH3LOG_INFO
Definition: MaCh3Logger.h:35
void SetMaCh3LoggerFormat()
Set messaging format of the logger.
Definition: MaCh3Logger.h:60
#define MACH3LOG_WARN
Definition: MaCh3Logger.h:36
bool isFlat(TSpline3_red *&spl)
CW: Helper function used in the constructor, tests to see if the spline is flat.
YAML::Node TMacroToYAML(const TMacro &macro)
KS: Convert a ROOT TMacro object to a YAML node.
Definition: YamlHelper.h:152
#define M3OpenConfig(filename)
Macro to simplify calling LoadYaml with file and line info.
Definition: YamlHelper.h:590
void LoadSettings(YAML::Node &Settings, std::vector< std::string > &SetsNames, std::vector< std::string > &FancyTitle, std::vector< std::vector< bool >> &isRelevantParam, const std::vector< std::string > &ParamNames, const int nParams)
Load penalty term sets from YAML configuration.
MaCh3ArgumentParser * get_parser() override
Get the argument parser for this module.
void ReadCovFile(const std::string &inputFile, std::vector< double > &Prior, std::vector< bool > &isFlat, std::vector< std::string > &ParamNames, std::vector< std::vector< double >> &invCovMatrix, int &nParams)
Read covariance matrix and parameter information from file.
void GetPenaltyTerm(const std::string &inputFile, const std::string &configFile)
Calculate and plot penalty terms for parameter sets.
int Run() override
Execute the penalty term extraction.
virtual ~GetPenaltyTermModule()
Destructor.
Extended ArgumentParser with MaCh3-specific functionality.
Definition: m3argparse.hpp:17
std::unique_ptr< MaCh3ArgumentParser > m_parser
Argument parser for this plugin.
Definition: plugin.hpp:44
Custom exception class used throughout MaCh3.
void PrintConfig(const YAML::Node &node)
KS: Print Yaml config using logger.
Definition: Monitor.cpp:311
void PrintProgressBar(const Long64_t Done, const Long64_t All)
KS: Simply print progress bar.
Definition: Monitor.cpp:229
void MaCh3Welcome()
KS: Prints welcome message with MaCh3 logo.
Definition: Monitor.cpp:13
Main namespace for MaCh3 software.
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.
TMatrixDSym * GetCovMatrixFromChain(TDirectory *TempFile)
KS: Retrieve the cross-section covariance matrix from the given TDirectory. Historically,...