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