MaCh3 2.2.1
Reference Guide
Loading...
Searching...
No Matches
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
34std::vector <double> nominal;
35std::vector <bool> isFlat;
36std::vector<TString> BranchNames;
37std::vector<std::string> ParamNames;
38int size;
39
40double** invCovMatrix;
41
42void 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");
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
128void 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 = YAML::LoadFile(configFile.c_str());
186
187 std::vector<std::string> SetsNames;
188 std::vector<std::vector<std::string>> RemoveNames;
189 std::vector<bool> Exclude;
190 std::vector<std::string> FancyTittle;
191
192 std::vector<std::vector<bool>> isRelevantParam;
193 std::vector<std::string> node = Settings["GetPenaltyTerm"]["PenaltySets"].as<std::vector<std::string>>();
194 for (unsigned int i = 0; i < node.size(); i++)
195 {
196 std::string ParName = node[i];
197 SetsNames.push_back(ParName);
198
199 const auto& Set = Settings["GetPenaltyTerm"][ParName];
200
201 RemoveNames.push_back(Set[0].as<std::vector<std::string>>());
202 Exclude.push_back(Set[1].as<bool>());
203 FancyTittle.push_back(Set[2].as<std::string>());
204 }
205
206 const int NSets = int(SetsNames.size());
207
208 isRelevantParam.resize(NSets);
209 //Loop over sets in the config
210 for(int i = 0; i < NSets; i++)
211 {
212 isRelevantParam[i].resize(size);
213 int counter = 0;
214 //Loop over parameters in the Covariance object
215 for (int j = 0; j < size; j++)
216 {
217 isRelevantParam[i][j] = false;
218
219 //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
220 if(Exclude[i])
221 {
222 bool found = false;
223 for (unsigned int k = 0; k < RemoveNames[i].size(); k++)
224 {
225 if (ParamNames[j].rfind(RemoveNames[i][k], 0) == 0)
226 {
227 found = true;
228 }
229 }
230 if(!found)
231 {
232 isRelevantParam[i][j] = true;
233 counter++;
234 }
235 }
236 //KS: Here is much simpler, if parameter matched then it is relevant
237 else
238 {
239 for (unsigned int k = 0; k < RemoveNames[i].size(); k++)
240 {
241 if (ParamNames[j].rfind(RemoveNames[i][k], 0) == 0)
242 {
243 isRelevantParam[i][j] = true;
244 counter++;
245 break;
246 }
247 }
248 }
249 }
250 MACH3LOG_INFO(" Found {} params for set {}", counter, SetsNames[i]);
251 }
252
253 int AllEvents = int(Chain->GetEntries());
254 std::vector<std::unique_ptr<TH1D>> hLogL(NSets);
255 for (int i = 0; i < NSets; i++) {
256 std::string NameTemp = "LogL_" + SetsNames[i];
257 hLogL[i] = std::make_unique<TH1D>(NameTemp.c_str(), NameTemp.c_str(), AllEvents, 0, AllEvents);
258 hLogL[i]->SetLineColor(kBlue);
259 }
260 std::vector<double> logL(NSets, 0.0);
261 for(int n = 0; n < AllEvents; ++n)
262 {
263 if(n%10000 == 0) MaCh3Utils::PrintProgressBar(n, AllEvents);
264
265 Chain->GetEntry(n);
266
267 for(int k = 0; k < NSets; ++k) logL[k] = 0.;
268#ifdef MULTITHREAD
269 // The per-thread array
270 double *logL_private = nullptr;
271
272 // Declare the omp parallel region
273 // The parallel region needs to stretch beyond the for loop!
274 #pragma omp parallel private(logL_private)
275 {
276 logL_private = new double[NSets]();
277 for(int k = 0; k < NSets; ++k) logL_private[k] = 0.;
278
279 #pragma omp for
280 for (int i = 0; i < size; i++)
281 {
282 for (int j = 0; j <= i; ++j)
283 {
284 //check if flat prior
285 if (!isFlat[i] && !isFlat[j])
286 {
287 for(int k = 0; k < NSets; ++k)
288 {
289 //Check if parameter is relevant for this set
290 if (isRelevantParam[k][i] && isRelevantParam[k][j])
291 {
292 //KS: Since matrix is symmetric we can calculate non diagonal elements only once and multiply by 2, can bring up to factor speed decrease.
293 int scale = 1;
294 if(i != j) scale = 2;
295 logL_private[k] += scale * 0.5*(fParProp[i] - nominal[i])*(fParProp[j] - nominal[j])*invCovMatrix[i][j];
296 }
297 }
298 }
299 }
300 }
301 // Now we can write the individual arrays from each thread to the main array
302 for(int k = 0; k < NSets; ++k)
303 {
304 #pragma omp atomic
305 logL[k] += logL_private[k];
306 }
307 //Delete private arrays
308 delete[] logL_private;
309 }//End omp range
310
311#else
312 for (int i = 0; i < size; i++)
313 {
314 for (int j = 0; j <= i; ++j)
315 {
316 //check if flat prior
317 if (!isFlat[i] && !isFlat[j])
318 {
319 for(int k = 0; k < NSets; ++k)
320 {
321 //Check if parameter is relevant for this set
322 if (isRelevantParam[k][i] && isRelevantParam[k][j])
323 {
324 //KS: Since matrix is symmetric we can calculate non diagonal elements only once and multiply by 2, can bring up to factor speed decrease.
325 int scale = 1;
326 if(i != j) scale = 2;
327 logL[k] += scale * 0.5*(fParProp[i] - nominal[i])*(fParProp[j] - nominal[j])*invCovMatrix[i][j];
328 }
329 }
330 }
331 }
332 }
333#endif
334 for(int k = 0; k < NSets; ++k)
335 {
336 hLogL[k]->SetBinContent(n, logL[k]);
337 }
338 }//End loop over steps
339
340 // Directory for posteriors
341 std::string OutputName = inputFile + "_PenaltyTerm" +".root";
342 TFile* OutputFile = new TFile(OutputName.c_str(), "recreate");
343 TDirectory *PenaltyTermDir = OutputFile->mkdir("PenaltyTerm");
344
345 canvas->Print(Form("%s_PenaltyTerm.pdf[",inputFile.c_str()), "pdf");
346 for(int i = 0; i < NSets; i++)
347 {
348 const double Maximum = hLogL[i]->GetMaximum();
349 hLogL[i]->GetYaxis()->SetRangeUser(0., Maximum*1.2);
350 hLogL[i]->SetTitle(FancyTittle[i].c_str());
351 hLogL[i]->GetXaxis()->SetTitle("Step");
352 hLogL[i]->GetYaxis()->SetTitle(FancyTittle[i].c_str());
353 hLogL[i]->GetYaxis()->SetTitleOffset(1.4f);
354
355 hLogL[i]->Draw("");
356
357 PenaltyTermDir->cd();
358 hLogL[i]->Write();
359
360 canvas->Print(Form("%s_PenaltyTerm.pdf",inputFile.c_str()), "pdf");
361 }
362 canvas->Print(Form("%s_PenaltyTerm.pdf]",inputFile.c_str()), "pdf");
363 delete Chain;
364
365 for (int i = 0; i < size; i++)
366 {
367 delete[] invCovMatrix[i];
368 }
369 delete[] invCovMatrix;
370 OutputFile->Close();
371 delete OutputFile;
372}
373
374int main(int argc, char *argv[])
375{
378 if (argc != 3 )
379 {
380 MACH3LOG_WARN("Something went wrong ");
381 MACH3LOG_WARN("./GetPenaltyTerm root_file_to_analyse.root ");
382 throw MaCh3Exception(__FILE__ , __LINE__ );
383 }
384 std::string filename = argv[1];
385 std::string config = argv[2];
386 GetPenaltyTerm(filename, config);
387
388 return 0;
389}
#define _MaCh3_Safe_Include_Start_
KS: Avoiding warning checking for headers.
Definition: Core.h:106
#define _MaCh3_Safe_Include_End_
KS: Restore warning checking after including external headers.
Definition: Core.h:117
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:25
#define MACH3LOG_INFO
Definition: MaCh3Logger.h:23
void SetMaCh3LoggerFormat()
Set messaging format of the logger.
Definition: MaCh3Logger.h:30
#define MACH3LOG_WARN
Definition: MaCh3Logger.h:24
std::string config
Definition: ProcessMCMC.cpp:30
YAML::Node TMacroToYAML(const TMacro &macro)
KS: Convert a ROOT TMacro object to a YAML node.
Definition: YamlHelper.h:146
#define M3OpenConfig(filename)
Macro to simplify calling LoadYaml with file and line info.
Definition: YamlHelper.h:560
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:212
void PrintConfig(const YAML::Node &node)
KS: Print Yaml config using logger.
Definition: Monitor.cpp:294
void MaCh3Welcome()
KS: Prints welcome message with MaCh3 logo.
Definition: Monitor.cpp:11