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