Crombie Tools
PlotPreparer.h
Go to the documentation of this file.
1 /**
2  @file PlotPreparer.h
3 
4  Header of PlotPreparer class.
5 
6  @author Daniel Abercrombie <dabercro@mit.edu>
7 */
8 
9 #ifndef CROMBIE_PLOTTOOLS_PLOTPREPARER_H
10 #define CROMBIE_PLOTTOOLS_PLOTPREPARER_H 1
11 
12 #include <sstream>
13 #include <map>
14 #include <vector>
15 #include <utility>
16 #include <cmath>
17 
18 #include "TProfile.h"
19 #include "TTreeFormula.h"
20 
21 #include "ParallelRunner.h"
22 #include "PlotUtils.h"
23 
24 /**
25  @ingroup plotgroup
26  @class EnvelopeInfo
27  Similar to PlotInfo, but slightly different information for envelopes
28 */
29 
30 class EnvelopeInfo {
31  public:
32  EnvelopeInfo(TProfile* hist, Double_t& env_expr, Int_t renorm_idx)
33  : hist{hist}, env_expr{env_expr}, renorm_idx{renorm_idx} {}
34 
35  TProfile* hist;
36  Double_t& env_expr;
37  Int_t renorm_idx;
38 };
39 
40 /**
41  @ingroup plotgroup
42  @class PlotInfo
43  Structure for holding information about plots
44 */
45 
46 class PlotInfo {
47  public:
48  PlotInfo(TH1D* hist, Double_t& expr, Double_t& cut, Double_t& weight, Double_t eventsper)
49  : hist{hist}, expr{expr}, cut{cut}, weight{weight}, eventsper{eventsper} {}
50  /* ~PlotInfo() { delete hist; } // ??? Causes crash, and I really don't know why */
51  ~PlotInfo() { for (auto* p : envs) delete p; envs.clear(); }
52 
53  TH1D* hist; ///< The histogram that everything else is filling
54  Double_t& expr; ///< Reference to the expression filling the plot
55  Double_t& cut; ///< Reference to the cut
56  Double_t& weight; ///< Reference to the weight
57  Double_t eventsper; ///< Holds the desired normalization of the bin for this plot
58  std::vector<EnvelopeInfo*> envs; ///< Holds the different possible envelopes for this plot
59 };
60 
61 /**
62  @ingroup plotgroup
63  @class PlotPreparer
64  Class used for making lots of plots in a single pass over files.
65  Will usually be inherited by some other class that wants to make lots of plots.
66 */
67 
68 class PlotPreparer : public ParallelRunner {
69  public:
70  // Use default constructor
71  virtual ~PlotPreparer ();
72 
73  /// Add a histogram to plot
74  void AddHist ( TString FileBase, Int_t NumXBins, Double_t *XBins, TString dataExpr, TString mcExpr, TString cut, TString dataWeight, TString mcWeight );
75  /// Add a histogram to plot
76  void AddHist ( TString FileBase, Int_t NumXBins, Double_t MinX, Double_t MaxX, TString dataExpr, TString mcExpr, TString cut, TString dataWeight, TString mcWeight );
77 
78  /// Start tracking branches for a given envelope
79  void StartEnvelope ( Bool_t is_up ) { env_up = is_up; }
80  void AddEnvelopeWeight ( TString weight, Int_t index = 1 ) { env_branches.push_back(make_pair(weight, index)); }
81 
82  protected:
83  // Don't mask the FileConfigReader functions of the same name
85  /// Get the HistList for a given file name, and type
86  std::vector<TH1D*> GetHistList ( TString FileBase, FileType type );
87 
88  /// A flag indicating whether or not the plots have been prepared by this class
89  bool fPrepared {false};
90 
91  private:
92  /// A map containing pointers to all the histograms on the free store, mapped by output file and filetype
93  std::map<TString, std::map<FileType, std::vector<TH1D*>>> fHistograms;
94  /// A map from filename to map containing all the formulas and results of expressions
95  std::map<TString, std::map<TString, std::pair<TTreeFormula*, Double_t>>> fFormulas;
96 
97  /// A vector of all the plots that are being made, mapped by input file names
98  std::map<TString, std::vector<PlotInfo*>> fPlots;
99 
100  /// A vector of all the plots that are being made, mapped by output file names and process name
101  std::map<TString, std::map<TString, std::vector<PlotInfo*>>> fOutPlots;
102 
103  /// A function to clear the histograms map
104  void ClearHists ();
105 
106  /// Prepare all of the plots if none have been prepared yet
107  void PreparePlots ();
108 
109  /// Runs all plots over a single file
110  void RunFile (FileInfo& info) override;
111 
112  /// Scales the plots according to the stored file infos
113  void ScalePlots ();
114 
115  /// Says is envelope goes up or down for a given output file
116  std::map<TString, Bool_t> output_is_up;
117 
118  Bool_t env_up; ///< Tells whether envelope is up or down for upcoming plot
119  std::vector<std::pair<TString, Int_t>> env_branches; ///< Vector to temporarily hold branch names and renormalization indices
120 };
121 
123  ClearHists();
124 }
125 
126 void
128  fHistograms.clear();
129  for (auto& file : fPlots) {
130  for (auto plot : file.second)
131  delete plot;
132 
133  file.second.resize(0);
134  }
135  fPlots.clear();
136  // fOutPlots doesn't own anything
137  fOutPlots.clear();
138 
139  for (auto formulas : fFormulas)
140  for (auto form : formulas.second)
141  delete form.second.first;
142  fFormulas.clear();
143 
144  fPrepared = false;
145 }
146 
147 void
148 PlotPreparer::AddHist(TString FileBase, Int_t NumXBins, Double_t MinX, Double_t MaxX, TString dataExpr, TString mcExpr, TString cut, TString dataWeight, TString mcWeight)
149 {
150  bool reset_per = (fEventsPer == 0);
151  if (reset_per)
152  SetEventsPer((MaxX - MinX)/NumXBins);
153 
154  Double_t XBins[NumXBins+1];
155  ConvertToArray(NumXBins, MinX, MaxX, XBins);
156  AddHist(FileBase, NumXBins, XBins, dataExpr, mcExpr, cut, dataWeight, mcWeight);
157 
158  if (reset_per)
159  SetEventsPer(0);
160 }
161 
162 void
163 PlotPreparer::AddHist(TString FileBase, Int_t NumXBins, Double_t* XBins, TString dataExpr, TString mcExpr, TString cut, TString dataWeight, TString mcWeight)
164 {
165  DisplayFunc(__func__);
166  Message(eDebug, "File Name:", FileBase);
167  Message(eDebug, "Data expr:", dataExpr);
168  Message(eDebug, "MC expr:", mcExpr);
169  Message(eDebug, "Cut:", cut);
170  Message(eDebug, "Data cut:", dataWeight);
171  Message(eDebug, "MC cut:", mcWeight);
172 
173  if (fHistograms.find(FileBase) == fHistograms.end())
174  fHistograms[FileBase] = {};
175 
176  auto& hists = fHistograms[FileBase];
177 
178  // Track if this is an up or down envelope
179  if (env_branches.size())
180  output_is_up[FileBase] = env_up;
181 
182  for (auto type : gFileTypes) {
183  if (hists.find(type) == hists.end())
184  hists[type] = {};
185 
186  auto& hist_list = hists[type];
187 
188  auto exprs = (type == FileType::kData) ?
189  std::vector<TString>{dataExpr, cut, dataWeight} : std::vector<TString>{mcExpr, cut, mcWeight};
190  auto expr = exprs[0];
191  auto weight = exprs[2];
192 
193  // Include the branches for the envelope calculation
194  for (auto env : env_branches)
195  exprs.push_back(env.first);
196 
197  const auto& infos = *(GetFileInfo(type));
198  for (auto info : infos) {
199 
200  auto& outplots = fOutPlots[FileBase][info->fTreeName];
201  auto& inputname = info->fFileName;
202  auto& plots = fPlots[inputname];
203  auto& formulas = fFormulas[inputname];
204 
205  for (auto& expr : exprs) {
206  if (formulas.find(expr) == formulas.end()) {
207  Message(eDebug, inputname, "Adding formula expression:", expr);
208  formulas[expr] = std::make_pair<TTreeFormula*, Double_t>(nullptr, {});
209  }
210  }
211 
212  auto tempname = TempHistName();
213  PlotInfo* tempinfo = new PlotInfo(new TH1D(tempname, tempname, NumXBins, XBins), formulas[expr].second, formulas[cut].second, formulas[weight].second, fEventsPer);
214  for (auto env : env_branches) {
215  auto tempname = TempHistName();
216  tempinfo->envs.push_back(new EnvelopeInfo(new TProfile(tempname, tempname, NumXBins, XBins), formulas[env.first].second, env.second));
217  }
218 
219  plots.push_back(tempinfo);
220  hist_list.push_back(tempinfo->hist);
221  outplots.push_back(tempinfo);
222  }
223  }
224  env_branches.clear();
225 }
226 
227 std::vector<TH1D*>
228 PlotPreparer::GetHistList (TString FileBase, FileType type) {
229  PreparePlots();
230  Message(eDebug, "Getting hists for FileName", FileBase, "and type", type);
231  return fHistograms.at(FileBase).at(type);
232 }
233 
234 void
236  if (fPrepared)
237  return;
238  fPrepared = true;
239 
240  RunThreads();
241  ScalePlots();
242 
243  // Do envelope calculations
244  for (auto& env : output_is_up) {
245  // env.first holds the output file name
246  // env.second holds the bool of whether this is up
247 
248  for (auto& procs : fOutPlots[env.first]) {
249  // procs.first holds the process name
250  // procs.second holds the list of PlotInfo for this process
251 
252  // Build a map of processes to up and down envelopes
253  std::vector<TProfile*> profiles;
254  for (auto *prof_info : fOutPlots[env.first][procs.first][0]->envs) {
255  TProfile* temp_scale = static_cast<TProfile*>(prof_info->hist->Clone(TempHistName()));
256  temp_scale->Reset("M");
257  profiles.push_back(temp_scale);
258  }
259  for (auto* hist : procs.second) {
260  for (unsigned i_prof = 0; i_prof < hist->envs.size(); ++i_prof)
261  profiles[i_prof]->Add(hist->envs[i_prof]->hist);
262  }
263  // Get the max or minimum for each bin
264  for (int i_bin = 1; i_bin <= profiles[0]->GetNbinsX(); ++i_bin) {
265  double scale = 1.0;
266  for (auto* prof : profiles) {
267  auto check = prof->GetBinContent(i_bin);
268  if ((check > scale) == env.second)
269  scale = check;
270  }
271  // Scale each bin in these histograms for processes
272  for (auto* hist : procs.second) {
273  auto content = hist->hist->GetBinContent(i_bin);
274  auto error = hist->hist->GetBinError(i_bin);
275  hist->hist->SetBinContent(i_bin, content * scale);
276  hist->hist->SetBinError(i_bin, error * scale);
277  }
278  }
279  for (auto* prof : profiles)
280  delete prof;
281  profiles.clear();
282  }
283  }
284 }
285 
286 void
288  auto filename = info.fFileName;
289 
290  root_lock.Lock();
291  auto* inputfile = TFile::Open(filename);
292  TTree* inputtree = fTreeName.Contains("/") ? static_cast<TTree*>(inputfile->Get(fTreeName)) : static_cast<TTree*>(inputfile->FindObjectAny(fTreeName));
293  root_lock.UnLock();
294 
295  std::set<TString> needed;
296 
297  auto& formulas = fFormulas[filename];
298  for (auto& formula : formulas) {
299  root_lock.Lock();
300  delete formula.second.first;
301  formula.second.first = new TTreeFormula(formula.first, formula.first, inputtree);
302  root_lock.UnLock();
303  AddNecessaryBranches(needed, inputtree, formula.first);
304  }
305 
306  inputtree->SetBranchStatus("*", 0);
307  for (auto need : needed)
308  inputtree->SetBranchStatus(need, 1);
309 
310  auto nentries = inputtree->GetEntries();
311  auto& plots = fPlots[filename];
312 
313  for (decltype(nentries) i_entry = 0; i_entry < nentries; ++i_entry) {
314  inputtree->GetEntry(i_entry);
315 
316  for (auto& formula : formulas)
317  if (formula.second.first) {
318  formula.second.second = formula.second.first->EvalInstance();
319  }
320 
321  for (auto plot : plots) {
322  if (plot->cut) {
323  if (std::isnan(plot->weight)) {
324  output_lock.Lock();
325  Message(eError, "For file", filename, "row", i_entry, "NaN weight", plot->weight, "and expr", plot->expr);
326  output_lock.UnLock();
327  }
328  plot->hist->Fill(plot->expr, plot->weight);
329  for (auto* env : plot->envs)
330  env->hist->Fill(plot->expr, env->env_expr, plot->weight);
331  }
332  }
333  }
334 
335  root_lock.Lock();
336  inputfile->Close();
337  root_lock.UnLock();
338 }
339 
341  DisplayFunc(__func__);
342  for (auto type : gFileTypes) {
343  const auto& infos = *(GetFileInfo(type));
344  for (auto* info : infos) {
345 
346  Message(eDebug, "Scaling plots from", info->fFileName);
347  auto& plots = fPlots[info->fFileName];
348 
349  for (auto plot : plots) {
350  auto* hist = plot->hist;
351  auto tempname = TempHistName();
352  /* TH1D* tempHist = static_cast<TH1D*>(hist->Clone(TempHistName())); */
353 
354  /* for (Int_t iBin = 1; iBin != tempHist->GetNbinsX() + 1; ++iBin) */
355  /* tempHist->SetBinContent(iBin, tempHist->GetBinWidth(iBin)/plot->eventsper); */
356  /* SetZeroError(tempHist); */
357 
358  /* Division(hist, tempHist); */
359 
360  /* delete tempHist; */
361 
362  if (info->fXSec > 0) {
363  hist->Scale(info->fXSecWeight);
364  for (auto* env : plot->envs) {
365  auto denom = info->fRenormHistogram.GetBinContent(std::min(env->renorm_idx,
366  info->fRenormHistogram.GetNbinsX()));
367  if (denom)
368  env->hist->Scale(info->fRenormHistogram.GetBinContent(1)/denom);
369  }
370  }
371  }
372  }
373  }
374 }
375 
376 #endif