CMS 3D CMS Logo

jetHtPlotter.cc
Go to the documentation of this file.
1 // framework includes
4 
5 // C++ includes
6 #include <iostream> // Input/output stream. Needed for cout.
7 #include <vector>
8 
9 // Root includes
10 #include "TFile.h"
11 #include "TString.h"
12 #include "TH1D.h"
13 #include "TProfile.h"
14 #include "TGraphErrors.h"
15 #include "TLegend.h"
16 #include "TLine.h"
17 #include "TSystem.h"
18 #include "TMath.h"
19 #include "TLatex.h"
20 
21 // AllInOneTool includes
22 #include "Options.h"
23 
24 // Include a drawing helper class
25 #include "JetHtPlotConfiguration.h"
26 #include "JDrawer.h"
27 
28 // Maximum number of compared files implemented in current code
29 const int kMaxFiles = 4;
30 
31 /*
32  * Draw a histogram to canvas
33  *
34  * Arguments:
35  * TH1D *histogram[kMaxFiles] = Input histogram and comparison histogram
36  * const char *saveName = Name given for saved figures
37  * bool saveFigures = True: Save figures to file, False: Do not save figures
38  * TString comment[kMaxFiles] = Text written to legend
39  * int legendPosition = Position index of legend: 0 = Right top, 1 = Middle bottom
40  * bool normalize = Normalize the distributions to one so that shapes can be compared
41  * bool logScale = Use logarithmic scale for y-axis
42  * int color[kMaxFiles] = Color used for each files
43  */
44 void drawSingleHistogram(TH1D *histogram[kMaxFiles],
45  const char *saveName,
46  bool saveFigures,
47  TString comment[kMaxFiles],
48  int legendPosition,
49  bool normalize,
50  bool logScale,
51  int color[kMaxFiles]) {
52  // Create and setup the histogram drawer
53  const auto &drawer = std::make_unique<JDrawer>();
54  drawer->SetLogY(logScale);
55  drawer->SetTopMargin(0.08);
56 
57  // The first histogram in the array is always included, draw it
58  histogram[0]->SetLineColor(color[0]);
59  if (normalize)
60  histogram[0]->Scale(1.0 / histogram[0]->Integral());
61  drawer->DrawHistogram(histogram[0]);
62 
63  // Draw all the remaining histograms in the array. Calculate how many were drawn
64  int nHistograms = 1;
65  for (int iFile = 1; iFile < kMaxFiles; iFile++) {
66  if (histogram[iFile]) {
67  nHistograms++;
68  histogram[iFile]->SetLineColor(color[iFile]);
69  if (normalize)
70  histogram[iFile]->Scale(1.0 / histogram[iFile]->Integral());
71  histogram[iFile]->Draw("Same");
72  }
73  }
74 
75  // Create a legend with size depending on the number of histograms
76  double legendX1 = 0.6;
77  double legendY1 = 0.9 - 0.07 * nHistograms;
78  double legendX2 = 0.9;
79  double legendY2 = 0.9;
80  if (legendPosition == 1) {
81  legendX1 = 0.35;
82  legendY1 = 0.4 - 0.07 * nHistograms + 0.07 * (nHistograms / 4);
83  legendX2 = 0.65;
84  legendY2 = 0.4 + 0.07 * (nHistograms / 4);
85  }
86  TLegend *legend = new TLegend(legendX1, legendY1, legendX2, legendY2);
87  legend->SetFillStyle(0);
88  legend->SetBorderSize(0);
89  legend->SetTextSize(0.05);
90  legend->SetTextFont(62);
91 
92  // Add all the histograms to the legend and draw it
93  legend->AddEntry(histogram[0], comment[0], "l");
94  for (int iFile = 1; iFile < kMaxFiles; iFile++) {
95  if (histogram[iFile]) {
96  legend->AddEntry(histogram[iFile], comment[iFile], "l");
97  }
98  }
99  legend->Draw();
100 
101  // Save the drawn figure to a file
102  if (saveFigures)
103  gPad->GetCanvas()->SaveAs(Form("output/%s.pdf", saveName));
104 }
105 
106 /*
107  * Find a good range for the y-axes of the histograms
108  *
109  * Arguments:
110  * TH1D *histogram[kMaxFiles] = Histogram array from which the Y-axis range is searched
111  *
112  * return:
113  * Tuple containing the minimum and maximum zoom for the histogram Y-axis
114  */
115 std::tuple<double, double> findHistogramYaxisRange(TH1D *histogram[kMaxFiles]) {
116  // Find the smallest minimum and largest maximum from the histograms
117  double minValue = histogram[0]->GetMinimum();
118  double maxValue = histogram[0]->GetMaximum();
119 
120  double newMinValue, newMaxValue;
121 
122  for (int iFile = 1; iFile < kMaxFiles; iFile++) {
123  if (histogram[iFile]) {
124  newMinValue = histogram[iFile]->GetMinimum();
125  newMaxValue = histogram[iFile]->GetMaximum();
126 
127  if (newMinValue < minValue)
128  minValue = newMinValue;
129  if (newMaxValue > maxValue)
130  maxValue = newMaxValue;
131  }
132  }
133 
134  // Add some margin below the minimum and over the maximum
135  double margin = 0.075;
136  double totalSpan = maxValue - minValue;
137  minValue = minValue - margin * totalSpan;
138  if (minValue < 0)
139  minValue = 0;
140  maxValue = maxValue + margin * totalSpan;
141 
142  // Return the minimum and maximum values
143  return std::make_tuple(minValue, maxValue);
144 }
145 
146 /*
147  * Construct vectors of ptHat files and the ptHat value in each of those files
148  *
149  * Arguments:
150  * const char* inputFile = File containing the list of ptHat separated files and ptHat bin in each file
151  *
152  * return:
153  * Tuple containing list of runs, luminosities, and histogram names within the validation files
154  */
155 std::tuple<std::vector<std::string>, std::vector<int>> ptHatFilesAndValues(const char *inputFile) {
156  // Create vectors for ptHat files and values
157  std::vector<std::string> ptHatFileList;
158  std::vector<int> ptHatList;
159 
160  // Helper variables to read the file
161  std::string lineInFile;
162 
163  // Open the input file for reading
164  std::ifstream ptHatFile(inputFile);
165 
166  // Go through the file line by line. Each line has one file and information about the ptHat in the file.
167  while (std::getline(ptHatFile, lineInFile)) {
168  auto stringStream = std::istringstream{lineInFile};
169  auto wordString = std::string{};
170 
171  // Find the file name and ptHat in that file
172  stringStream >> wordString;
173  ptHatFileList.push_back(wordString);
174  stringStream >> wordString;
175  ptHatList.push_back(std::stoi(wordString));
176  }
177 
178  // After all the vectors are filled, return them
179  return std::make_tuple(ptHatFileList, ptHatList);
180 }
181 
182 /*
183  * Get a selected histogram combining different pThat bins
184  */
185 TH1 *ptHatCombinedHistogram(std::vector<TFile *> ptHatFiles, std::vector<int> ptHatValues, const char *histogramName) {
186  // Weight for bins: 30to50 50to80 80to120 120to170 170to300 300to470 470to600
187  double ptHatWeights[] = {
188  138800000,
189  19110000,
190  2735000,
191  466200,
192  117200,
193  7763,
194  641.0,
195  // 600to800 800to1000 1000to1400 1400to1800 1800to2400 2400to3200 3200toInf
196  185.7,
197  32.02,
198  9.375,
199  0.8384,
200  0.1133,
201  0.006746,
202  0.0001623};
203  const int nPtHat = 14;
204  int ptHatBoundaries[] = {30, 50, 80, 120, 170, 300, 470, 600, 800, 1000, 1400, 1800, 2400, 3200};
205 
206  TFile *openFile = ptHatFiles.at(0);
207  TH1 *combinedHistogram = (TH1 *)openFile->Get(histogramName)->Clone(Form("%sClone", histogramName));
208  TH1 *currentHistogram;
209  combinedHistogram->Reset("ICES");
210  int ptHatIndex = -1;
211 
212  const int nFiles = ptHatFiles.size();
213 
214  for (int iFile = 0; iFile < nFiles; iFile++) {
215  ptHatIndex = -1;
216  for (int iPtHat = 0; iPtHat < nPtHat; iPtHat++) {
217  if (ptHatValues.at(iFile) == ptHatBoundaries[iPtHat]) {
218  ptHatIndex = iPtHat;
219  break;
220  }
221  }
222 
223  if (ptHatIndex < 0) {
224  std::cout << "Could not find pT hat boundary " << ptHatValues.at(iFile) << " for file " << ptHatFiles.at(iFile)
225  << std::endl;
226  std::cout << "Please check your input! It needs to be in the form <fileName> <ptHatBoundary>" << std::endl;
227  return nullptr;
228  }
229 
230  openFile = ptHatFiles.at(iFile);
231  currentHistogram = (TH1 *)openFile->Get(histogramName);
232  combinedHistogram->Add(currentHistogram, ptHatWeights[ptHatIndex]);
233  }
234 
235  return combinedHistogram;
236 }
237 
238 /*
239  * Construct vectors of runs, luminosities, and histogram names within the validation files from an input file
240  * containing a list of runs and luminosities attached to each one
241  *
242  * Arguments:
243  * const char* inputFile = File containing the run and luminosity lists
244  * const char* iovListMode = List mode for IOVs. Tells if every run in the IOV list is it's own IOV or a border run in a set of runs for IOV.
245  *
246  * return:
247  * Tuple containing list of runs, luminosities, histogram names and legend strings within the validation files
248  */
249 std::tuple<std::vector<int>, std::vector<double>, std::vector<TString>, std::vector<TString>> runAndLumiLists(
250  const char *inputFile, const char *iovListMode) {
251  // Create vectors for each list
252  std::vector<int> iovVector;
253  std::vector<double> lumiPerIov;
254  std::vector<TString> iovNames;
255  std::vector<TString> iovLegend;
256 
257  // Helper variables to read the file
258  std::string lineInFile;
259  int thisIov;
260  double thisLumi;
261 
262  // Load the iovList
263  std::ifstream iovList(edm::FileInPath(inputFile).fullPath().c_str());
264  if (!iovList.good()) {
265  edm::LogError("jetHTPlotter") << __PRETTY_FUNCTION__ << "\n Input file: " << inputFile
266  << " is corrupt or not existing";
267  return std::make_tuple(iovVector, lumiPerIov, iovNames, iovLegend);
268  }
269 
270  // Go through the file line by line. Each line has an IOV boundary and luminosity for this IOV.
271  while (std::getline(iovList, lineInFile)) {
272  // Read the iov and luminosity from the file
273  std::istringstream lineStream(lineInFile);
274  lineStream >> thisIov;
275  lineStream >> thisLumi;
276 
277  // Push the extracted numbers to vectors
278  iovVector.push_back(thisIov);
279  lumiPerIov.push_back(thisLumi);
280  }
281 
282  // Create names for the different IOV:s
283  for (std::vector<int>::size_type i = 1; i < iovVector.size(); i++) {
284  iovNames.push_back(Form("iov%d-%d", iovVector.at(i - 1), iovVector.at(i) - 1));
285  }
286 
287  // For the legend naming, use just the run if specified in iovListMode
288  TString listModeParser = iovListMode;
289  if (listModeParser.EqualTo("iov", TString::kIgnoreCase)) {
290  for (std::vector<int>::size_type i = 1; i < iovVector.size(); i++) {
291  iovLegend.push_back(Form("IOV %d-%d", iovVector.at(i - 1), iovVector.at(i) - 1));
292  }
293  } else {
294  for (std::vector<int>::size_type i = 0; i < iovVector.size() - 1; i++) {
295  iovLegend.push_back(Form("Run %d", iovVector.at(i)));
296  }
297  }
298 
299  // Add the iov integrated histograms after the histograms per IOV
300  iovNames.push_back("all");
301  iovNames.push_back("central");
302  iovLegend.push_back("All");
303  iovLegend.push_back("Central");
304 
305  // After all the vectors are filled, return them
306  return std::make_tuple(iovVector, lumiPerIov, iovNames, iovLegend);
307 }
308 
309 /*
310  * Scale the x-axis of a given graph by integrated luminosity. The error on x-axis represents the luminosity of each run.
311  *
312  * Arguments:
313  * TGraphErrors *runGraph = Graph containing dxy or dz error trends as a function of run index
314  * std::vector<double> lumiPerIov = Vector showing luminosities for each run. Indices must match with the graph
315  * bool skipMissingRuns = If there is no data for a run in the runlist, do not assign luminosity for it
316  *
317  * Return: std::vector<double> New luminosity list where skipped runs are set to zero
318  *
319  */
320 std::vector<double> scaleGraphByLuminosity(TGraphErrors *runGraph,
321  std::vector<double> lumiPerIov,
322  bool skipMissingRuns) {
323  // Read the number of runs from the graph by run number
324  int nRuns = runGraph->GetN();
325 
326  // Helper variables
327  std::vector<double> xAxisValues, yAxisValues, xAxisErrors, yAxisErrors;
328 
329  int iRun = 0;
330  int offset = 0;
331  double lumiFactor = 1000; // Scale factor value to have luminosity expressed in fb^-1
332 
333  double runIndex, yValue;
334  double xValue = 0;
335  double epsilon = 1e-5;
336 
337  std::vector<double> lumiPerIovWithSkips;
338 
339  // Loop over all runs, remove zeros and for runs with content, replace x-axis index by luminosity
340  while (iRun < nRuns) {
341  runGraph->GetPoint(iRun, runIndex, yValue);
342 
343  if (lumiPerIov.at(iRun + offset) == 0 || (yValue < epsilon && skipMissingRuns)) {
344  nRuns--;
345  runGraph->RemovePoint(iRun);
346  offset++;
347 
348  // Fill vector where lumi for skipped runs is set to zero
349  lumiPerIovWithSkips.push_back(0);
350  } else {
351  xValue += lumiPerIov.at(iRun + offset) / lumiFactor;
352  xAxisValues.push_back(xValue - (lumiPerIov.at(iRun + offset) / (lumiFactor * 2)));
353  xAxisErrors.push_back(lumiPerIov.at(iRun + offset) / (lumiFactor * 2));
354  yAxisValues.push_back(yValue);
355  yAxisErrors.push_back(runGraph->GetErrorY(iRun));
356 
357  // Fill vector where lumi for skipped runs is set to zero
358  lumiPerIovWithSkips.push_back(lumiPerIov.at(iRun + offset));
359 
360  iRun++;
361  }
362  } // Loop over all runs in original histogram
363 
364  // Delete remaining old content and replace it with new one calculated from luminosities
365  runGraph->GetHistogram()->Delete();
366  runGraph->SetHistogram(nullptr);
367  for (int iRun = 0; iRun < nRuns; iRun++) {
368  runGraph->SetPoint(iRun, xAxisValues.at(iRun), yAxisValues.at(iRun));
369  runGraph->SetPointError(iRun, xAxisErrors.at(iRun), yAxisErrors.at(iRun));
370  }
371 
372  return lumiPerIovWithSkips;
373 }
374 
375 /*
376  * Get the total luminosity upto a given run
377  *
378  * std::vector<double> lumiPerIov = Vector containing luminosity information
379  * std::vector<int> iovVector = Vector containing run information
380  * in runNumber = Run upto which the luminosity is calculated
381  */
382 double luminosityBeforeRun(std::vector<double> lumiPerIov, std::vector<int> iovVector, int runNumber) {
383  double lumiFactor = 1000; // Scale factor value to have luminosity expressed in fb^-1
384 
385  int nRuns = lumiPerIov.size();
386  double luminosityBefore = 0;
387 
388  for (int iRun = 0; iRun < nRuns; iRun++) {
389  if (runNumber <= iovVector.at(iRun))
390  return luminosityBefore;
391 
392  luminosityBefore += lumiPerIov.at(iRun) / lumiFactor;
393  }
394 
395  return luminosityBefore;
396 }
397 
398 /*
399  * Macro for plotting figures for the study of jet HT sample
400  */
401 void jetHtPlotter(std::string configurationFileName) {
402  // ======================================================
403  // ================== Configuration =====================
404  // ======================================================
405 
406  JetHtPlotConfiguration *configurationGiver = new JetHtPlotConfiguration();
407  configurationGiver->readJsonFile(configurationFileName);
408  //configurationGiver->printConfiguration();
409 
410  enum enumHistogramType { kDz, kDzError, kDxy, kDxyError, knHistogramTypes };
411  TString histogramName[knHistogramTypes] = {"dz", "dzerr", "dxy", "dxyerr"};
412  TString histogramXaxis[knHistogramTypes] = {
413  "d_{z} (#mum)", "#sigma(d_{z}) (#mum)", "d_{xy} (#mum)", "#sigma(d_{xy}) (#mum)"};
414  enum enumProfileType {
415  kDzErrorVsPt,
416  kDzErrorVsPhi,
417  kDzErrorVsEta,
418  kDxyErrorVsPt,
419  kDxyErrorVsPhi,
420  kDxyErrorVsEta,
421  kDzErrorVsPtWide,
422  kDxyErrorVsPtWide,
423  knProfileTypes
424  };
425  enum enumTrendType { kDzErrorTrend, kDxyErrorTrend, knTrendTypes };
426  TString profileName[knProfileTypes] = {"dzErrVsPt",
427  "dzErrVsPhi",
428  "dzErrVsEta",
429  "dxyErrVsPt",
430  "dxyErrVsPhi",
431  "dxyErrVsEta",
432  "dzErrVsPtWide",
433  "dxyErrVsPtWide"};
434  TString profileXaxis[knProfileTypes] = {
435  "p_{T} (GeV)", "#varphi", "#eta", "p_{T} (GeV)", "#varphi", "#eta", "p_{T} bin", "p_{T} bin"};
436  TString profileYaxis[knProfileTypes] = {"d_{z}", "d_{z}", "d_{z}", "d_{xy}", "d_{xy}", "d_{xy}", "d_{z}", "d_{xy}"};
437  TString trendName[] = {"dzErr", "dxyErr"};
438  bool drawHistogram[knHistogramTypes];
439  bool drawProfile[knProfileTypes];
440  bool drawTrend[knTrendTypes];
441 
442  bool drawTrackQA = configurationGiver->drawTrackQA(); // Draw track and vertex QA figures
443  drawHistogram[kDz] = configurationGiver->drawHistogram(kDz); // Draw the dz histograms
444  drawHistogram[kDzError] = configurationGiver->drawHistogram(kDzError); // Draw the dz error histograms
445  drawProfile[kDzErrorVsPt] = configurationGiver->drawProfile(kDzErrorVsPt); // Draw mean dz error as a function of pT
446  drawProfile[kDzErrorVsPhi] =
447  configurationGiver->drawProfile(kDzErrorVsPhi); // Draw mean dz error as a function of phi
448  drawProfile[kDzErrorVsEta] =
449  configurationGiver->drawProfile(kDzErrorVsEta); // Draw mean dz error as a function of eta
450  drawProfile[kDzErrorVsPtWide] =
451  configurationGiver->drawProfile(kDzErrorVsPtWide); // Draw mean dz error in wide pT bins
452  drawHistogram[kDxy] = configurationGiver->drawHistogram(kDxy); // Draw the dxy histograms
453  drawHistogram[kDxyError] = configurationGiver->drawHistogram(kDxyError); // Draw the dxy error histograms
454  drawProfile[kDxyErrorVsPt] =
455  configurationGiver->drawProfile(kDxyErrorVsPt); // Draw the dxy error as a function of pT
456  drawProfile[kDxyErrorVsPhi] =
457  configurationGiver->drawProfile(kDxyErrorVsPhi); // Draw the dxy error as a function of phi
458  drawProfile[kDxyErrorVsEta] =
459  configurationGiver->drawProfile(kDxyErrorVsEta); // Draw the dxy error as a function of eta
460  drawProfile[kDxyErrorVsPtWide] =
461  configurationGiver->drawProfile(kDxyErrorVsPtWide); // Draw mean dxy error in wide pT bins
462  bool drawReferenceProfile = configurationGiver->drawReferenceProfile(); // Draw reference profile to single IOV plots
463  bool drawCentralEtaSummaryProfile =
464  configurationGiver->drawCentralEtaSummaryProfile(); // Draw central eta histograms to all runs summary profiles
465  drawTrend[kDzErrorTrend] = configurationGiver->drawTrend(kDzErrorTrend); // Draw the trend plots for dz errors
466  drawTrend[kDxyErrorTrend] = configurationGiver->drawTrend(kDxyErrorTrend); // Draw the trend plots for dxy errors
467 
468  const int nMaxLegendColumns = 3;
469  double profileLegendShiftTotalX =
470  configurationGiver->profileLegendShiftTotalX(); // Total legend position shift in x-direction for profile plots
471  double profileLegendShiftTotalY =
472  configurationGiver->profileLegendShiftTotalY(); // Total legend position shift in y-direction for profile plots
473  double profileLegendShiftColumnX[nMaxLegendColumns];
474  double profileLegendShiftColumnY[nMaxLegendColumns];
475  for (int iColumn = 0; iColumn < nMaxLegendColumns; iColumn++) {
476  profileLegendShiftColumnX[iColumn] = configurationGiver->profileLegendShiftColumnX(
477  iColumn); // Columnwise legend position shift in x-direction for profile plots
478  profileLegendShiftColumnY[iColumn] = configurationGiver->profileLegendShiftColumnY(
479  iColumn); // Columnwise legend position shift in x-direction for profile plots
480  }
481  double profileLegendTextSize = configurationGiver->profileLegendTextSize(); // Legend text size for profile plots
482  int profileLegendTextFont = configurationGiver->profileLegendTextFont(); // Legend text font for profile plots
483  TString legendTextForAllRuns =
484  configurationGiver->legendTextForAllRuns(); // Legend text referring to all runs in the file
485 
486  double trendLegendShiftTotalX =
487  configurationGiver->trendLegendShiftTotalX(); // Total legend position shift in x-direction for trend plots
488  double trendLegendShiftTotalY =
489  configurationGiver->trendLegendShiftTotalY(); // Total legend position shift in y-direction for trend plots
490  double trendLegendTextSize = configurationGiver->trendLegendTextSize(); // Legend text size for trend plots
491  int trendLegendTextFont = configurationGiver->trendLegendTextFont(); // Legend text font for trend plots
492 
493  bool drawTrendTag = configurationGiver->drawTrendTag(); // Draw manual tags to the trend plots
494  std::vector<std::string> trendTagText = configurationGiver->trendTagText(); // Drawn tag texts for trend plots
495  std::vector<double> trendTagPositionX = configurationGiver->trendTagPositionX(); // Trend tag x-positions
496  std::vector<double> trendTagPositionY = configurationGiver->trendTagPositionY(); // Trend tag y-positions
497  double trendTagTextSize = configurationGiver->trendTagTextSize(); // Tag text size for trend plots
498  int trendTagTextFont = configurationGiver->trendTagTextFont(); // Tag text font for trend plots
499 
500  int trendCanvasHeight = configurationGiver->trendCanvasHeight(); // Canvas height for trend plots
501  int trendCanvasWidth = configurationGiver->trendCanvasWidth(); // Canvas width for trend plots
502  double trendMarginLeft = configurationGiver->trendMarginLeft(); // Left margin in trend plots
503  double trendMarginRight = configurationGiver->trendMarginRight(); // Right margin in trend plots
504  double trendMarginTop = configurationGiver->trendMarginTop(); // Top margin in trend plots
505  double trendMarginBottom = configurationGiver->trendMarginBottom(); // Bottom margin in trend plots
506  double trendTitleOffsetX = configurationGiver->trendTitleOffsetX(); // x-axis title offset in trend plots
507  double trendTitleOffsetY = configurationGiver->trendTitleOffsetY(); // y-axis title offset in trend plots
508  double trendTitleSizeX = configurationGiver->trendTitleSizeX(); // x-axis title size in trend plots
509  double trendTitleSizeY = configurationGiver->trendTitleSizeY(); // y-axis title size in trend plots
510  double trendLabelOffsetX = configurationGiver->trendLabelOffsetX(); // x-axis label offset in trend plots
511  double trendLabelOffsetY = configurationGiver->trendLabelOffsetY(); // y-axis label offset in trend plots
512  double trendLabelSizeX = configurationGiver->trendLabelSizeX(); // x-axis label size in trend plots
513  double trendLabelSizeY = configurationGiver->trendLabelSizeY(); // y-axis label size in trend plots
514 
515  bool drawPlotsForEachIOV =
516  configurationGiver
517  ->drawPlotsForEachIOV(); // True = Draw profile and histogram plots for every IOV. False = only draw average over all runs
518  bool useLuminosityForTrends =
519  configurationGiver
520  ->useLuminosityForTrends(); // True = Draw trends as a function of luminosity. False = Draw trends as a function of run index
521  bool skipRunsWithNoData =
522  configurationGiver
523  ->skipRunsWithNoData(); // True = Do not draw empty space if run in list is missing data. False = Draw empty space
524 
525  int colors[] = {kBlue, kRed, kGreen + 2, kMagenta, kCyan, kViolet + 3, kOrange, kPink - 7, kSpring + 3, kAzure - 7};
526  int nIovInOnePlot = configurationGiver->nIovInOnePlot(); // Define how many iov:s are drawn to the same plot
527 
528  double profileZoomLow[knProfileTypes];
529  double profileZoomHigh[knProfileTypes];
530  double trendZoomLow[knTrendTypes];
531  double trendZoomHigh[knTrendTypes];
532 
533  for (int iProfile = 0; iProfile < knProfileTypes; iProfile++) {
534  profileZoomLow[iProfile] = configurationGiver->profileZoomLow(iProfile);
535  profileZoomHigh[iProfile] = configurationGiver->profileZoomHigh(iProfile);
536  }
537  for (int iTrend = 0; iTrend < knTrendTypes; iTrend++) {
538  trendZoomLow[iTrend] = configurationGiver->trendZoomLow(iTrend);
539  trendZoomHigh[iTrend] = configurationGiver->trendZoomHigh(iTrend);
540  }
541 
542  const std::vector<double> widePtBinBorders = configurationGiver->widePtBinBorders();
543  const int nWidePtBins = widePtBinBorders.size();
544 
545  bool normalizeQAplots = configurationGiver->normalizeQAplots(); // Divide in QA plot yield by its integral
546  bool saveFigures = true;
547  const char *saveComment = configurationGiver->saveComment();
548 
549  int compareFiles = configurationGiver->nInputFiles();
550  if (compareFiles == 0)
551  return; // Cannot do plotting without files!
552  if (compareFiles > kMaxFiles)
553  compareFiles = kMaxFiles; // Four is maximum number of files in current implementation
554 
555  // If we have more then one file, we should not draw more than one IOV per plot and plot all the files instead
556  if (compareFiles > 1)
557  nIovInOnePlot = 1;
558 
559  // Read the input file names. If file names end with .txt, they are assumed to be lists of files in different ptHat bins
560  TString inputFileName[kMaxFiles];
561  bool loadFromList[kMaxFiles] = {false, false, false, false};
562  TString legendComment[kMaxFiles];
563  int fileColor[kMaxFiles];
564  int fileMarkerStyle[kMaxFiles];
565  int fileMarkerSize[kMaxFiles];
566  bool copyErrorColor[kMaxFiles];
567 
568  for (int iFile = 0; iFile < kMaxFiles; iFile++) {
569  inputFileName[iFile] = configurationGiver->inputFile(iFile);
570  if (inputFileName[iFile].EndsWith("txt"))
571  loadFromList[iFile] = true;
572  legendComment[iFile] = configurationGiver->legendComment(iFile); // Text written to the legend for each file
573  fileColor[iFile] = configurationGiver->markerColor(iFile); // Color of markers related to this file
574  fileMarkerStyle[iFile] = configurationGiver->markerStyle(iFile); // Style for markers related to this file
575  fileMarkerSize[iFile] = configurationGiver->markerSize(iFile); // Size for markers related to this file
576  copyErrorColor[iFile] =
577  configurationGiver->copyErrorColor(iFile); // Copy the marker color for error bars for this file
578  }
579 
580  // Prepare an IOV list that can be used with the slide generation script
581  bool makeIovListForSlides = configurationGiver->makeIovListForSlides();
582  const char *iovListForSlides = configurationGiver->iovListForSlides();
583 
584  // Helper variable to ensure that each IOV is added exactly once to the list
585  int profileIndexForIovList = 0;
586  for (int iProfile = 0; iProfile < knProfileTypes; iProfile++) {
587  if (drawProfile[iProfile]) {
588  profileIndexForIovList = iProfile;
589  break;
590  }
591  }
592 
593  TString plotTitle = " "; // Title given to the plot
594 
595  // Year boundary runs
596  bool drawYearLines = configurationGiver->drawYearLines(); // Draw lines between data taking years
597  std::vector<int> linePosition = configurationGiver->runsForLines(); // Positions of the above lines
598  int yearLineColor = configurationGiver->yearLineColor(); // Color of the above lines
599  int yearLineWidth = configurationGiver->yearLineWidth(); // Width of the above lines
600  int yearLineStyle = configurationGiver->yearLineStyle(); // Style of the above lines
601 
602  // ======================================================
603  // ================ Configuration done ==================
604  // ======================================================
605 
606  // =======================================================
607  // Make sure that the output folder for figures exists
608  // =======================================================
609 
610  if (saveFigures) {
611  TString outputFolderStatus = gSystem->GetFromPipe("if [ -d output ]; then echo true; else echo false; fi");
612  if (outputFolderStatus == "false") {
613  gSystem->Exec("mkdir output");
614  }
615  }
616 
617  // ===============================================================
618  // Read different ptHat files for combining those with weights
619  // ===============================================================
620 
621  // List for all the different ptHat files to be combined
622  std::vector<std::string> ptHatFileNameList[kMaxFiles];
623  std::vector<TFile *> ptHatFileList[kMaxFiles];
624  std::vector<int> ptHatList[kMaxFiles];
625  int nFiles;
626 
627  for (int iInput = 0; iInput < kMaxFiles; iInput++) {
628  if (loadFromList[iInput]) {
629  std::tie(ptHatFileNameList[iInput], ptHatList[iInput]) = ptHatFilesAndValues(inputFileName[iInput]);
630 
631  // Open all files
632  nFiles = ptHatFileNameList[iInput].size();
633  for (int iFile = 0; iFile < nFiles; iFile++) {
634  ptHatFileList[iInput].push_back(TFile::Open(ptHatFileNameList[iInput].at(iFile).data()));
635  }
636  }
637  }
638 
639  // ===============================================
640  // Read the run and luminosity list
641  // ===============================================
642 
643  // Luminosity per run file
644  const char *iovAndLumiFile = configurationGiver->lumiPerIovFile();
645  const char *iovListMode = configurationGiver->iovListMode();
646 
647  // Create a vector for a new iovList
648  std::vector<int> iovVector;
649  std::vector<double> lumiPerIov;
650  std::vector<double> lumiPerIovWithSkips;
651  std::vector<TString> iovNames;
652  std::vector<TString> iovLegend;
653 
654  std::tie(iovVector, lumiPerIov, iovNames, iovLegend) = runAndLumiLists(iovAndLumiFile, iovListMode);
655  // protection against empty input
656  if (iovVector.empty()) {
657  edm::LogError("jetHTPlotter") << __PRETTY_FUNCTION__ << "\n The list of input IOVs is empty. Exiting!";
658  return;
659  }
660 
661  // For the IOV legend, remove the two last entries and replace them with user defined names
662  iovLegend.pop_back();
663  iovLegend.pop_back();
664  iovLegend.push_back(legendTextForAllRuns);
665  iovLegend.push_back(Form("%s |#eta| < 1", legendTextForAllRuns.Data()));
666 
667  // ===============================================
668  // IOV list for slides
669  // ===============================================
670 
671  // If we are preparing an iov list for slides, make a file for that
672  std::ofstream iovFileForSlides;
673  if (makeIovListForSlides)
674  iovFileForSlides.open(iovListForSlides);
675 
676  // ===============================================
677  // Create histograms and read them from a file
678  // ===============================================
679 
680  // Open the input files
681  TFile *inputFile[kMaxFiles];
682  for (int iFile = 0; iFile < kMaxFiles; iFile++) {
683  if (compareFiles > iFile && !loadFromList[iFile])
684  inputFile[iFile] = TFile::Open(inputFileName[iFile]);
685  }
686 
687  // Define the histograms that will be read from the file
688  const int nIov = iovNames.size();
689  TH1D *hVertex[kMaxFiles];
690  TH1D *hTracksPerVertex[kMaxFiles];
691  TH1D *hTrackPt[kMaxFiles];
692  TH1D *hTrackEta[kMaxFiles];
693  TH1D *hTrackPhi[kMaxFiles];
694  TH1D *jetHtHistograms[kMaxFiles][knHistogramTypes][nIov];
695  TProfile *jetHtProfiles[kMaxFiles][knProfileTypes][nIov];
696  TGraphErrors *gBigTrend[kMaxFiles][knTrendTypes][nWidePtBins];
697 
698  // Initialize everything to NULL
699  for (int iFile = 0; iFile < kMaxFiles; iFile++) {
700  hVertex[iFile] = nullptr;
701  hTracksPerVertex[iFile] = nullptr;
702  hTrackPt[iFile] = nullptr;
703  hTrackEta[iFile] = nullptr;
704  hTrackPhi[iFile] = nullptr;
705  for (int iIov = 0; iIov < nIov; iIov++) {
706  for (int iHistogramType = 0; iHistogramType < knHistogramTypes; iHistogramType++) {
707  jetHtHistograms[iFile][iHistogramType][iIov] = nullptr;
708  } // histogram type loop
709  for (int iProfileType = 0; iProfileType < knProfileTypes; iProfileType++) {
710  jetHtProfiles[iFile][iProfileType][iIov] = nullptr;
711  } // profile type loop
712  } // iov loop for reading histograms from file
713  for (int iTrend = 0; iTrend < knTrendTypes; iTrend++) {
714  for (int iWidePt = 0; iWidePt < nWidePtBins; iWidePt++) {
715  gBigTrend[iFile][iTrend][iWidePt] = nullptr;
716  } // Trend loop
717  } // Wide pT bin loop
718  } // file loop
719 
720  // Read the histograms from the file
721  for (int iFile = 0; iFile < compareFiles; iFile++) {
722  if (loadFromList[iFile]) {
723  // Alternative loading for ptHat combined values
724 
725  hVertex[iFile] = (TH1D *)ptHatCombinedHistogram(ptHatFileList[iFile], ptHatList[iFile], "jetHTAnalyzer/all_nvtx");
726  hTracksPerVertex[iFile] =
727  (TH1D *)ptHatCombinedHistogram(ptHatFileList[iFile], ptHatList[iFile], "jetHTAnalyzer/h_ntrks");
728  hTrackPt[iFile] =
729  (TH1D *)ptHatCombinedHistogram(ptHatFileList[iFile], ptHatList[iFile], "jetHTAnalyzer/h_probePt");
730  hTrackEta[iFile] =
731  (TH1D *)ptHatCombinedHistogram(ptHatFileList[iFile], ptHatList[iFile], "jetHTAnalyzer/h_probeEta");
732  hTrackPhi[iFile] =
733  (TH1D *)ptHatCombinedHistogram(ptHatFileList[iFile], ptHatList[iFile], "jetHTAnalyzer/h_probePhi");
734  for (int iIov = nIov - 2; iIov < nIov - 1; iIov++) {
735  for (int iHistogramType = 0; iHistogramType < knHistogramTypes; iHistogramType++) {
736  if (drawHistogram[iHistogramType]) {
737  jetHtHistograms[iFile][iHistogramType][iIov] = (TH1D *)ptHatCombinedHistogram(
738  ptHatFileList[iFile],
739  ptHatList[iFile],
740  Form("jetHTAnalyzer/%s_%s", iovNames.at(iIov).Data(), histogramName[iHistogramType].Data()));
741  } // if for drawing histogram
742  } // histogram type loop
743  for (int iProfileType = 0; iProfileType < knProfileTypes; iProfileType++) {
744  if (drawProfile[iProfileType] || (drawTrend[kDzErrorTrend] && iProfileType == kDzErrorVsPtWide) ||
745  (drawTrend[kDxyErrorTrend] && iProfileType == kDxyErrorVsPtWide)) {
746  jetHtProfiles[iFile][iProfileType][iIov] = (TProfile *)ptHatCombinedHistogram(
747  ptHatFileList[iFile],
748  ptHatList[iFile],
749  Form("jetHTAnalyzer/%s_%s", iovNames.at(iIov).Data(), profileName[iProfileType].Data()));
750  } // if for drawing profile
751  } // profile type loop
752  } // iov loop for reading histograms from file
753 
754  } else {
755  // Regular histogram loading
756 
757  hVertex[iFile] = (TH1D *)inputFile[iFile]->Get("jetHTAnalyzer/all_nvtx");
758  hTracksPerVertex[iFile] = (TH1D *)inputFile[iFile]->Get("jetHTAnalyzer/h_ntrks");
759  hTrackPt[iFile] = (TH1D *)inputFile[iFile]->Get("jetHTAnalyzer/h_probePt");
760  hTrackEta[iFile] = (TH1D *)inputFile[iFile]->Get("jetHTAnalyzer/h_probeEta");
761  hTrackPhi[iFile] = (TH1D *)inputFile[iFile]->Get("jetHTAnalyzer/h_probePhi");
762  for (int iIov = 0; iIov < nIov; iIov++) {
763  for (int iHistogramType = 0; iHistogramType < knHistogramTypes; iHistogramType++) {
764  if (drawHistogram[iHistogramType]) {
765  jetHtHistograms[iFile][iHistogramType][iIov] = (TH1D *)inputFile[iFile]->Get(
766  Form("jetHTAnalyzer/%s_%s", iovNames.at(iIov).Data(), histogramName[iHistogramType].Data()));
767  } // if for drawing histogram
768  } // histogram type loop
769  for (int iProfileType = 0; iProfileType < knProfileTypes; iProfileType++) {
770  if (drawProfile[iProfileType] || (drawTrend[kDzErrorTrend] && iProfileType == kDzErrorVsPtWide) ||
771  (drawTrend[kDxyErrorTrend] && iProfileType == kDxyErrorVsPtWide)) {
772  jetHtProfiles[iFile][iProfileType][iIov] = (TProfile *)inputFile[iFile]->Get(
773  Form("jetHTAnalyzer/%s_%s", iovNames.at(iIov).Data(), profileName[iProfileType].Data()));
774  } // if for drawing profile
775  } // profile type loop
776  } // iov loop for reading histograms from file
777  } // Regular histogram loading
778  } // Loop over files
779 
780  // Collect the information for the trend graphs
781  const int nRuns = iovVector.size() - 1;
782  double yValueDz[nRuns];
783  double yErrorDz[nRuns];
784  double yValueDxy[nRuns];
785  double yErrorDxy[nRuns];
786  double xValue[nRuns];
787  double xError[nRuns];
788  TString commentEntry = "";
789  if (drawTrend[kDzErrorTrend] || drawTrend[kDxyErrorTrend]) {
790  for (int iFile = 0; iFile < compareFiles; iFile++) {
791  for (int iWidePt = 0; iWidePt < nWidePtBins; iWidePt++) {
792  for (int iRun = 0; iRun < nRuns; iRun++) {
793  xValue[iRun] = iRun;
794  xError[iRun] = 0;
795  if (jetHtProfiles[iFile][kDzErrorVsPtWide][iRun] == nullptr) {
796  yValueDz[iRun] = 0;
797  yErrorDz[iRun] = 0;
798  } else {
799  yValueDz[iRun] = jetHtProfiles[iFile][kDzErrorVsPtWide][iRun]->GetBinContent(iWidePt + 1);
800  yErrorDz[iRun] = jetHtProfiles[iFile][kDzErrorVsPtWide][iRun]->GetBinError(iWidePt + 1);
801  }
802  if (jetHtProfiles[iFile][kDxyErrorVsPtWide][iRun] == nullptr) {
803  yValueDxy[iRun] = 0;
804  yErrorDxy[iRun] = 0;
805  } else {
806  yValueDxy[iRun] = jetHtProfiles[iFile][kDxyErrorVsPtWide][iRun]->GetBinContent(iWidePt + 1);
807  yErrorDxy[iRun] = jetHtProfiles[iFile][kDxyErrorVsPtWide][iRun]->GetBinError(iWidePt + 1);
808  }
809  } // Run loop
810 
811  gBigTrend[iFile][kDzErrorTrend][iWidePt] = new TGraphErrors(nRuns, xValue, yValueDz, xError, yErrorDz);
812  gBigTrend[iFile][kDxyErrorTrend][iWidePt] = new TGraphErrors(nRuns, xValue, yValueDxy, xError, yErrorDxy);
813 
814  // Change x-axis to processed luminosity
815  if (useLuminosityForTrends) {
816  lumiPerIovWithSkips =
817  scaleGraphByLuminosity(gBigTrend[iFile][kDzErrorTrend][iWidePt], lumiPerIov, skipRunsWithNoData);
818  scaleGraphByLuminosity(gBigTrend[iFile][kDxyErrorTrend][iWidePt], lumiPerIov, skipRunsWithNoData);
819  }
820 
821  } // Wide pT bin loop
822  } // File loop
823  } // If for drawing trends
824 
825  // ===============================================
826  // Draw the plots
827  // ===============================================
828 
829  const auto &drawer = std::make_unique<JDrawer>();
830  TLegend *legend[nMaxLegendColumns];
831  int columnOrder[nMaxLegendColumns];
832  bool noIovFound = true;
833  bool canvasDrawn;
834  bool doNotDrawEta;
835  double minZoomY, maxZoomY;
836  int nDrawnHistograms, nLeftLegend, nRightLegend;
837  double legendX1, legendX2, legendY1, legendY2;
838  int iLegend = 0;
839  int skipColor = 0;
840  int nNullHistograms;
841  int iHistogram;
842  TString legendString;
843  TH1D *histogramSearchArray[kMaxFiles];
844  for (int iFile = 0; iFile < kMaxFiles; iFile++) {
845  histogramSearchArray[iFile] = nullptr;
846  }
847 
848  // Draw track and vertex histograms
849  if (drawTrackQA) {
851  hVertex, Form("vertex%s", saveComment), saveFigures, legendComment, 0, normalizeQAplots, false, fileColor);
852  drawSingleHistogram(hTracksPerVertex,
853  Form("tracksPerVertex%s", saveComment),
854  saveFigures,
855  legendComment,
856  0,
857  normalizeQAplots,
858  false,
859  fileColor);
861  hTrackPt, Form("trackPt%s", saveComment), saveFigures, legendComment, 0, normalizeQAplots, true, fileColor);
863  hTrackEta, Form("trackEta%s", saveComment), saveFigures, legendComment, 1, normalizeQAplots, false, fileColor);
865  hTrackPhi, Form("trackPhi%s", saveComment), saveFigures, legendComment, 1, normalizeQAplots, false, fileColor);
866  }
867 
868  // Draw dz and dxy histograms
869  for (int iIov = 0; iIov < nIov; iIov++) {
870  if (!drawPlotsForEachIOV && iIov < nIov - 2)
871  continue;
872  for (int iHistogramType = 0; iHistogramType < knHistogramTypes; iHistogramType++) {
873  if (drawHistogram[iHistogramType]) {
874  double legendX1 = 0.6;
875  double legendY1 = 0.9 - 0.07 * compareFiles;
876  double legendX2 = 0.9;
877  double legendY2 = 0.9;
878  if (iHistogramType == kDxy || iHistogramType == kDz) {
879  legendX1 = 0.4;
880  legendY1 = 0.4 - 0.07 * compareFiles + 0.07 * (compareFiles / 4);
881  legendX2 = 0.7;
882  legendY2 = 0.4 + 0.07 * (compareFiles / 4);
883  }
884 
885  legend[0] = new TLegend(legendX1, legendY1, legendX2, legendY2);
886  legend[0]->SetFillStyle(0);
887  legend[0]->SetBorderSize(0);
888  legend[0]->SetTextSize(0.05);
889  legend[0]->SetTextFont(62);
890 
891  if (jetHtHistograms[0][iHistogramType][iIov] != nullptr) {
892  for (int iFile = 0; iFile < compareFiles; iFile++) {
893  histogramSearchArray[iFile] = jetHtHistograms[iFile][iHistogramType][iIov];
894  }
895 
896  std::tie(minZoomY, maxZoomY) = findHistogramYaxisRange(histogramSearchArray);
897  jetHtHistograms[0][iHistogramType][iIov]->GetYaxis()->SetRangeUser(minZoomY, maxZoomY);
898  jetHtHistograms[0][iHistogramType][iIov]->SetLineColor(fileColor[0]);
899 
900  drawer->DrawHistogram(jetHtHistograms[0][iHistogramType][iIov],
901  histogramXaxis[iHistogramType],
902  "Tracks",
903  iovLegend.at(iIov).Data());
904  legend[0]->AddEntry(jetHtHistograms[0][iHistogramType][iIov], legendComment[0], "l");
905 
906  for (int iFile = 1; iFile < compareFiles; iFile++) {
907  if (jetHtHistograms[iFile][iHistogramType][iIov] != nullptr) {
908  jetHtHistograms[iFile][iHistogramType][iIov]->SetLineColor(fileColor[iFile]);
909  jetHtHistograms[iFile][iHistogramType][iIov]->Draw("same");
910  legend[0]->AddEntry(jetHtHistograms[iFile][iHistogramType][iIov], legendComment[iFile], "l");
911  }
912  }
913 
914  legend[0]->Draw();
915 
916  // Save the figures
917  if (saveFigures) {
918  gPad->GetCanvas()->SaveAs(Form(
919  "output/%s%s_%s.pdf", histogramName[iHistogramType].Data(), saveComment, iovNames.at(iIov).Data()));
920  }
921 
922  } else {
923  std::cout << "No histogram found for: "
924  << Form("%s_%s", iovNames.at(iIov).Data(), histogramName[iHistogramType].Data()) << std::endl;
925  }
926  } // if for drawing histogram
927  } // histogram type loop
928  }
929 
930  // Draw dz and dxy profiles
931  for (int iProfileType = 0; iProfileType < knProfileTypes; iProfileType++) {
932  if (drawProfile[iProfileType]) {
933  // Set the style for IOV integrated histograms
934  for (int iFile = 0; iFile < compareFiles; iFile++) {
935  jetHtProfiles[iFile][iProfileType][nIov - 2]->SetLineColor(fileColor[iFile]);
936  jetHtProfiles[iFile][iProfileType][nIov - 2]->SetLineWidth(2);
937  jetHtProfiles[iFile][iProfileType][nIov - 2]->SetLineStyle(2);
938  jetHtProfiles[iFile][iProfileType][nIov - 2]->GetYaxis()->SetRangeUser(profileZoomLow[iProfileType],
939  profileZoomHigh[iProfileType]);
940  }
941 
942  // Drawing plots for each IOV.
943  if (drawPlotsForEachIOV) {
944  for (int iIov = 0; iIov < nIov - 2; iIov = iIov + nIovInOnePlot) {
945  noIovFound = true;
946  iLegend = 0;
947  canvasDrawn = false;
948  nNullHistograms = 0;
949 
950  // If we have more than one file, draw all files to the same figure. Otherwise use the nIovInOnePlot variable for the single file.
951  // Set up the IOV:s or files to be drawn to the current plot
952  for (int iFile = 0; iFile < compareFiles; iFile++) {
953  skipColor = 0;
954  for (int iSamePlot = 0; iSamePlot < nIovInOnePlot; iSamePlot++) {
955  if (iIov + iSamePlot >= nIov - 2)
956  break; // Do not draw again all or central references
957  if (jetHtProfiles[iFile][iProfileType][iIov + iSamePlot] != nullptr) {
958  if (nIovInOnePlot > 1) {
959  if (colors[iFile + iSamePlot] == fileColor[0])
960  skipColor++;
961  jetHtProfiles[iFile][iProfileType][iIov + iSamePlot]->SetLineColor(colors[skipColor + iSamePlot]);
962  } else {
963  jetHtProfiles[iFile][iProfileType][iIov + iSamePlot]->SetLineColor(fileColor[iFile + iSamePlot]);
964  }
965  jetHtProfiles[iFile][iProfileType][iIov + iSamePlot]->SetLineWidth(2);
966  noIovFound = false;
967  } else {
968  std::cout << "No histogram found for: "
969  << Form("%s_%s", iovNames.at(iIov).Data(), profileName[iProfileType].Data()) << std::endl;
970  nNullHistograms++;
971  }
972  }
973  }
974 
975  if (noIovFound)
976  continue;
977 
978  // Setup legends. There are four different configuration.
979  // 1) Draw several files in one plot, include reference distribution from all runs
980  // 2) Draw several files in one plot, do not include reference distribution from all runs
981  // 3) Draw several IOVs in one plot, include reference distribution from all runs
982  // 4) Draw several IOVs in one plot, do not include reference distribution from all runs
983  // Each setup needs slightly different configuration for the legends to look good
984 
985  // First determine the number of drawns histograms and how many of them should be drawn to left and right, if the legend is split
986  nDrawnHistograms = drawReferenceProfile * compareFiles + nIovInOnePlot * compareFiles - nNullHistograms;
987  nLeftLegend = TMath::Ceil(nDrawnHistograms / 2.0);
988  nRightLegend = TMath::Floor(nDrawnHistograms / 2.0);
989 
990  // Make adjustments to the number of drawn histograms in some special cases
991  if (!drawReferenceProfile) {
992  if (compareFiles > 1) {
993  nLeftLegend = 1;
994  nRightLegend = nDrawnHistograms;
995  }
996  if (nIovInOnePlot > 1) {
997  if (nLeftLegend > nRightLegend) {
998  nRightLegend++;
999  } else {
1000  nLeftLegend++;
1001  }
1002  }
1003  }
1004 
1005  // The order of columns changes for different configurations. Define it here
1006  columnOrder[0] = 0;
1007  columnOrder[1] = 1;
1008  columnOrder[2] = 2;
1009  if (compareFiles > 1) {
1010  columnOrder[0] = 1;
1011  columnOrder[1] = 2;
1012  columnOrder[2] = 0;
1013  if (!drawReferenceProfile) {
1014  columnOrder[0] = 1;
1015  columnOrder[1] = 0;
1016  columnOrder[2] = 2;
1017  }
1018  }
1019 
1020  // Define three different legends. Their position is determined by the specific configuration
1021  legendX1 = 0.19 + 0.24 * drawReferenceProfile * (compareFiles > 1) + profileLegendShiftTotalX +
1022  profileLegendShiftColumnX[columnOrder[0]];
1023  legendY1 = 0.9 - (profileLegendTextSize + 0.02) * nLeftLegend + profileLegendShiftTotalY +
1024  profileLegendShiftColumnY[columnOrder[0]];
1025  legendX2 = 0.41 + 0.24 * drawReferenceProfile * (compareFiles > 1) + profileLegendShiftTotalX +
1026  profileLegendShiftColumnX[columnOrder[0]];
1027  legendY2 = 0.9 + profileLegendShiftTotalY + profileLegendShiftColumnY[columnOrder[0]];
1028  ;
1029  legend[0] = new TLegend(legendX1, legendY1, legendX2, legendY2);
1030  legend[0]->SetFillStyle(0);
1031  legend[0]->SetBorderSize(0);
1032  legend[0]->SetTextSize(profileLegendTextSize);
1033  legend[0]->SetTextFont(profileLegendTextFont);
1034 
1035  legendX1 = 0.55 - 0.24 * !drawReferenceProfile * (compareFiles > 1) + profileLegendShiftTotalX +
1036  profileLegendShiftColumnX[columnOrder[1]];
1037  legendY1 = 0.9 - (profileLegendTextSize + 0.02) * nRightLegend + profileLegendShiftTotalY +
1038  profileLegendShiftColumnY[columnOrder[1]];
1039  legendX2 = 0.77 - 0.24 * !drawReferenceProfile * (compareFiles > 1) + profileLegendShiftTotalX +
1040  profileLegendShiftColumnX[columnOrder[1]];
1041  legendY2 = 0.9 + profileLegendShiftTotalY + profileLegendShiftColumnY[columnOrder[1]];
1042  legend[1] = new TLegend(legendX1, legendY1, legendX2, legendY2);
1043  legend[1]->SetFillStyle(0);
1044  legend[1]->SetBorderSize(0);
1045  legend[1]->SetTextSize(profileLegendTextSize);
1046  legend[1]->SetTextFont(profileLegendTextFont);
1047 
1048  legendX1 = 0.13 + profileLegendShiftTotalX + profileLegendShiftColumnX[columnOrder[2]];
1049  legendY1 = 0.9 - (profileLegendTextSize + 0.02) * nLeftLegend + profileLegendShiftTotalY +
1050  profileLegendShiftColumnY[columnOrder[2]];
1051  legendX2 = 0.49 + profileLegendShiftTotalX + profileLegendShiftColumnX[columnOrder[2]];
1052  legendY2 = 0.9 + profileLegendShiftTotalY + profileLegendShiftColumnY[columnOrder[2]];
1053  legend[2] = new TLegend(legendX1, legendY1, legendX2, legendY2);
1054  legend[2]->SetFillStyle(0);
1055  legend[2]->SetBorderSize(0);
1056  legend[2]->SetTextSize(profileLegendTextSize);
1057  legend[2]->SetTextFont(profileLegendTextFont);
1058 
1059  // First, draw the reference over all runs to the plot
1060  if (drawReferenceProfile) {
1061  for (int iFile = 0; iFile < compareFiles; iFile++) {
1062  if (jetHtProfiles[iFile][iProfileType][nIov - 2] != nullptr) {
1063  if (!canvasDrawn) {
1064  drawer->DrawHistogram(jetHtProfiles[iFile][iProfileType][nIov - 2],
1065  profileXaxis[iProfileType],
1066  Form("#LT#sigma(%s)#GT (#mum)", profileYaxis[iProfileType].Data()),
1067  " ",
1068  "HIST,C");
1069  canvasDrawn = true;
1070  } else {
1071  jetHtProfiles[iFile][iProfileType][nIov - 2]->Draw("same,HIST,C");
1072  }
1073  legendString = legendTextForAllRuns.Data();
1074  if (nIovInOnePlot > 1)
1075  legendString.Append(Form(" (%s)", legendComment[iFile].Data()));
1076  legend[0]->AddEntry(jetHtProfiles[iFile][iProfileType][nIov - 2], legendString.Data(), "l");
1077  legend[2]->AddEntry((TObject *)nullptr, Form("%s:", legendComment[iFile].Data()), "");
1078  }
1079  }
1080  }
1081 
1082  // If we draw several histograms per IOV, add the alignment to the legend if not included in the reference
1083  if (!drawReferenceProfile && (nIovInOnePlot > 1)) {
1084  legend[0]->AddEntry((TObject *)nullptr, legendComment[0].Data(), "");
1085  }
1086 
1087  // Draw defined number of different IOVs to the plot
1088  for (int iFile = 0; iFile < compareFiles; iFile++) {
1089  iHistogram = 0; // This variable takes into account null histograms in case of legend splitting
1090  for (int iSamePlot = 0; iSamePlot < nIovInOnePlot; iSamePlot++) {
1091  if (iIov + iSamePlot >= nIov - 2)
1092  break; // Do not draw again all or central references
1093  if (jetHtProfiles[iFile][iProfileType][iIov + iSamePlot] != nullptr) {
1094  if (!canvasDrawn) {
1095  drawer->DrawHistogram(jetHtProfiles[iFile][iProfileType][iIov + iSamePlot],
1096  profileXaxis[iProfileType],
1097  Form("#LT#sigma(%s)#GT (#mum)", profileYaxis[iProfileType].Data()),
1098  " ");
1099  canvasDrawn = true;
1100  } else {
1101  jetHtProfiles[iFile][iProfileType][iIov + iSamePlot]->Draw("same");
1102  }
1103 
1104  // Different legend texts if drawing several files or several IOVs in one plot
1105  if (compareFiles > 1) {
1106  legendString = iovLegend.at(iIov + iSamePlot).Data();
1107  if (!drawReferenceProfile)
1108  legendString.Append(Form(" (%s)", legendComment[iFile].Data()));
1109  legend[1]->AddEntry(jetHtProfiles[iFile][iProfileType][iIov + iSamePlot], legendString.Data(), "l");
1110  } else {
1111  if (iHistogram + 1 == nLeftLegend)
1112  iLegend = 1;
1113  legend[iLegend]->AddEntry(
1114  jetHtProfiles[iFile][iProfileType][iIov + iSamePlot], iovLegend.at(iIov + iSamePlot), "l");
1115  }
1116  iHistogram++;
1117  }
1118  }
1119  }
1120 
1121  // Draw the legends
1122  legend[0]->Draw();
1123  legend[1]->Draw();
1124  if (drawReferenceProfile && compareFiles > 1)
1125  legend[2]->Draw();
1126 
1127  // Save the figures
1128  if (saveFigures) {
1129  gPad->GetCanvas()->SaveAs(Form("output/%s%s_iov%d-%d.pdf",
1130  profileName[iProfileType].Data(),
1131  saveComment,
1132  iovVector.at(iIov),
1133  iovVector.at(std::min(iIov + nIovInOnePlot, nIov - 2)) - 1));
1134  }
1135 
1136  // Add the current IOV to the IOV list to be used with the slide generation script
1137  if (makeIovListForSlides && (iProfileType == profileIndexForIovList)) {
1138  iovFileForSlides << Form("%d-%d",
1139  iovVector.at(iIov),
1140  iovVector.at(std::min(iIov + nIovInOnePlot, nIov - 2)) - 1)
1141  << "\n";
1142  }
1143 
1144  } // iov loop for drawing
1145  } // if for drawing profiles for each IOV
1146 
1147  // First, setup the legends for the all runs plots
1148  doNotDrawEta = (!drawCentralEtaSummaryProfile || iProfileType == kDxyErrorVsEta || iProfileType == kDzErrorVsEta);
1149 
1150  // The order of columns changes for different configurations. Define it here
1151  columnOrder[0] = 1;
1152  columnOrder[1] = 2;
1153  columnOrder[2] = 0;
1154  if (doNotDrawEta) {
1155  columnOrder[0] = 1;
1156  columnOrder[1] = 0;
1157  columnOrder[2] = 2;
1158  }
1159 
1160  // Define three different legends. Their position is determined by the specific configuration
1161  legendX1 = 0.48 + profileLegendShiftTotalX + profileLegendShiftColumnX[columnOrder[0]];
1162  legendY1 = 0.9 - (profileLegendTextSize + 0.02) * compareFiles + profileLegendShiftTotalY +
1163  profileLegendShiftColumnY[columnOrder[0]];
1164  legendX2 = 0.7 + profileLegendShiftTotalX + profileLegendShiftColumnX[columnOrder[0]];
1165  legendY2 = 0.9 + profileLegendShiftTotalY + profileLegendShiftColumnY[columnOrder[0]];
1166  legend[0] = new TLegend(legendX1, legendY1, legendX2, legendY2);
1167  legend[0]->SetFillStyle(0);
1168  legend[0]->SetBorderSize(0);
1169  legend[0]->SetTextSize(profileLegendTextSize);
1170  legend[0]->SetTextFont(profileLegendTextFont);
1171 
1172  legendX1 = 0.65 - 0.25 * doNotDrawEta + profileLegendShiftTotalX + profileLegendShiftColumnX[columnOrder[1]];
1173  legendY1 = 0.9 - (profileLegendTextSize + 0.02) * compareFiles + profileLegendShiftTotalY +
1174  profileLegendShiftColumnY[columnOrder[1]];
1175  legendX2 = 0.87 - 0.25 * doNotDrawEta + profileLegendShiftTotalX + profileLegendShiftColumnX[columnOrder[1]];
1176  legendY2 = 0.9 + profileLegendShiftTotalY + profileLegendShiftColumnY[columnOrder[1]];
1177  legend[1] = new TLegend(legendX1, legendY1, legendX2, legendY2);
1178  legend[1]->SetFillStyle(0);
1179  legend[1]->SetBorderSize(0);
1180  legend[1]->SetTextSize(profileLegendTextSize);
1181  legend[1]->SetTextFont(profileLegendTextFont);
1182 
1183  legendX1 = 0.18 + profileLegendShiftTotalX + profileLegendShiftColumnX[columnOrder[2]];
1184  legendY1 = 0.9 - (profileLegendTextSize + 0.02) * compareFiles + profileLegendShiftTotalY +
1185  profileLegendShiftColumnY[columnOrder[2]];
1186  legendX2 = 0.54 + profileLegendShiftTotalX + profileLegendShiftColumnX[columnOrder[2]];
1187  legendY2 = 0.9 + profileLegendShiftTotalY + profileLegendShiftColumnY[columnOrder[2]];
1188  legend[2] = new TLegend(legendX1, legendY1, legendX2, legendY2);
1189  legend[2]->SetFillStyle(0);
1190  legend[2]->SetBorderSize(0);
1191  legend[2]->SetTextSize(profileLegendTextSize);
1192  legend[2]->SetTextFont(profileLegendTextFont);
1193 
1194  // First, draw histograms from all runs to the plot
1195  canvasDrawn = false;
1196  for (int iFile = 0; iFile < compareFiles; iFile++) {
1197  if (jetHtProfiles[iFile][iProfileType][nIov - 2] != nullptr) {
1198  jetHtProfiles[iFile][iProfileType][nIov - 2]->SetLineStyle(
1199  1); // Reset the line style after IOV specific plots
1200  if (!canvasDrawn) {
1201  drawer->DrawHistogram(jetHtProfiles[iFile][iProfileType][nIov - 2],
1202  profileXaxis[iProfileType],
1203  Form("#LT#sigma(%s)#GT (#mum)", profileYaxis[iProfileType].Data()),
1204  plotTitle);
1205  canvasDrawn = true;
1206  } else {
1207  jetHtProfiles[iFile][iProfileType][nIov - 2]->Draw("same");
1208  }
1209  legendString = legendTextForAllRuns.Data();
1210  if (doNotDrawEta)
1211  legendString.Append(Form(" (%s)", legendComment[iFile].Data()));
1212  legend[1]->AddEntry(jetHtProfiles[iFile][iProfileType][nIov - 2], legendString.Data(), "l");
1213  legend[2]->AddEntry((TObject *)nullptr, Form("%s:", legendComment[iFile].Data()), "");
1214  }
1215  }
1216 
1217  // If there is no canvas, nothing can be done. Break out of the if-statement
1218  if (!canvasDrawn)
1219  break;
1220 
1221  // If we want to draw the central eta as reference, draw them as a dashed line
1222  if (!doNotDrawEta) {
1223  for (int iFile = 0; iFile < compareFiles; iFile++) {
1224  if (jetHtProfiles[iFile][iProfileType][nIov - 1] != nullptr) {
1225  jetHtProfiles[iFile][iProfileType][nIov - 1]->SetLineColor(fileColor[iFile]);
1226  jetHtProfiles[iFile][iProfileType][nIov - 1]->SetLineWidth(2);
1227  jetHtProfiles[iFile][iProfileType][nIov - 1]->SetLineStyle(2);
1228  jetHtProfiles[iFile][iProfileType][nIov - 1]->Draw("same,HIST,C");
1229  legend[0]->AddEntry(jetHtProfiles[iFile][iProfileType][nIov - 1], "|#eta| < 1", "l");
1230  }
1231  }
1232  }
1233 
1234  legend[1]->Draw();
1235  if (!doNotDrawEta) {
1236  legend[0]->Draw();
1237  legend[2]->Draw();
1238  }
1239 
1240  // Save the figures
1241  if (saveFigures) {
1242  gPad->GetCanvas()->SaveAs(Form("output/%s%s_allIovs.pdf", profileName[iProfileType].Data(), saveComment));
1243  }
1244  } // if for drawing profile
1245  } // profile type loop
1246 
1247  // Close the output file
1248  if (makeIovListForSlides)
1249  iovFileForSlides.close();
1250 
1251  // Trend plots
1252  TLegend *trendLegend;
1253  drawer->SetCanvasSize(trendCanvasWidth, trendCanvasHeight);
1254  drawer->SetLeftMargin(trendMarginLeft);
1255  drawer->SetRightMargin(trendMarginRight);
1256  drawer->SetTopMargin(trendMarginTop);
1257  drawer->SetBottomMargin(trendMarginBottom);
1258  drawer->SetTitleOffsetX(trendTitleOffsetX);
1259  drawer->SetTitleOffsetY(trendTitleOffsetY);
1260  drawer->SetTitleSizeX(trendTitleSizeX);
1261  drawer->SetTitleSizeY(trendTitleSizeY);
1262  drawer->SetLabelOffsetX(trendLabelOffsetX);
1263  drawer->SetLabelOffsetY(trendLabelOffsetY);
1264  drawer->SetLabelSizeX(trendLabelSizeX);
1265  drawer->SetLabelSizeY(trendLabelSizeY);
1266  double lumiX;
1267  TLine *lumiLine;
1268 
1269  // Writed for adding tags to trend plots
1270  TLatex *tagWriter = new TLatex();
1271  tagWriter->SetTextFont(trendTagTextFont);
1272  tagWriter->SetTextSize(trendTagTextSize);
1273 
1274  TString xTitle = "Run index";
1275  if (useLuminosityForTrends)
1276  xTitle = "Delivered luminosity (1/fb)";
1277 
1278  for (int iTrend = 0; iTrend < knTrendTypes; iTrend++) {
1279  if (!drawTrend[iTrend])
1280  continue;
1281  for (int iWidePt = 0; iWidePt < nWidePtBins; iWidePt++) {
1282  legendX1 = 0.65 + trendLegendShiftTotalX;
1283  legendY1 = 0.83 - (profileLegendTextSize + 0.02) * compareFiles + trendLegendShiftTotalY;
1284  legendX2 = 0.9 + trendLegendShiftTotalX;
1285  legendY2 = 0.9 + trendLegendShiftTotalY;
1286  trendLegend = new TLegend(legendX1, legendY1, legendX2, legendY2);
1287  trendLegend->SetFillStyle(0);
1288  trendLegend->SetBorderSize(0);
1289  trendLegend->SetTextSize(trendLegendTextSize);
1290  trendLegend->SetTextFont(trendLegendTextFont);
1291  trendLegend->SetHeader(
1292  Form("%s error trend for p_{T} > %.0f GeV", profileYaxis[iTrend + 6].Data(), widePtBinBorders.at(iWidePt)));
1293 
1294  for (int iFile = 0; iFile < compareFiles; iFile++) {
1295  gBigTrend[iFile][iTrend][iWidePt]->SetMarkerColor(fileColor[iFile]);
1296  gBigTrend[iFile][iTrend][iWidePt]->SetMarkerStyle(fileMarkerStyle[iFile]);
1297  gBigTrend[iFile][iTrend][iWidePt]->SetMarkerSize(fileMarkerSize[iFile]);
1298  if (copyErrorColor[iFile])
1299  gBigTrend[iFile][iTrend][iWidePt]->SetLineColor(fileColor[iFile]);
1300 
1301  if (iFile == 0) {
1302  drawer->DrawGraphCustomAxes(gBigTrend[iFile][iTrend][iWidePt],
1303  0,
1304  nRuns,
1305  trendZoomLow[iTrend],
1306  trendZoomHigh[iTrend],
1307  xTitle,
1308  Form("#LT #sigma(%s) #GT", profileYaxis[iTrend + 6].Data()),
1309  " ",
1310  "ap");
1311  } else {
1312  gBigTrend[iFile][iTrend][iWidePt]->Draw("p,same");
1313  }
1314 
1315  trendLegend->AddEntry(gBigTrend[iFile][iTrend][iWidePt], legendComment[iFile].Data(), "p");
1316 
1317  } // File loop
1318 
1319  trendLegend->Draw();
1320 
1321  // Draw lines for different data taking years
1322  if (drawYearLines) {
1323  for (int thisRun : linePosition) {
1324  lumiX = luminosityBeforeRun(lumiPerIovWithSkips, iovVector, thisRun);
1325  lumiLine = new TLine(lumiX, trendZoomLow[iTrend], lumiX, trendZoomHigh[iTrend]);
1326  lumiLine->SetLineColor(yearLineColor);
1327  lumiLine->SetLineWidth(yearLineWidth);
1328  lumiLine->SetLineStyle(yearLineStyle);
1329  lumiLine->Draw();
1330  }
1331  }
1332 
1333  // Draw all defined tags
1334  if (drawTrendTag) {
1335  for (std::vector<std::string>::size_type iTag = 0; iTag < trendTagText.size(); iTag++) {
1336  tagWriter->DrawLatexNDC(
1337  trendTagPositionX.at(iTag), trendTagPositionY.at(iTag), trendTagText.at(iTag).c_str());
1338  }
1339  }
1340 
1341  // Save the figures
1342  if (saveFigures) {
1343  gPad->GetCanvas()->SaveAs(Form(
1344  "output/%sTrendPtOver%.0f%s.pdf", trendName[iTrend].Data(), widePtBinBorders.at(iWidePt), saveComment));
1345  }
1346 
1347  } // Wide pT loop
1348  } // Trend type loop
1349 }
1350 
1351 /*
1352  * Main program
1353  */
1354 int main(int argc, char **argv) {
1355  //==== Read command line arguments =====
1357  options.helper(argc, argv);
1358  options.parser(argc, argv);
1359 
1360  // Run the program
1361  jetHtPlotter(options.config);
1362 }
std::vector< std::string > trendTagText() const
bool drawProfile(const int iProfile) const
double profileLegendShiftColumnY(const int iColumn) const
std::vector< double > trendTagPositionX() const
std::vector< int > runsForLines() const
double trendZoomLow(const int iTrend) const
void drawSingleHistogram(TH1D *histogram[kMaxFiles], const char *saveName, bool saveFigures, TString comment[kMaxFiles], int legendPosition, bool normalize, bool logScale, int color[kMaxFiles])
Definition: jetHtPlotter.cc:44
bool copyErrorColor(const int iFile) const
int markerStyle(const int iFile) const
void jetHtPlotter(std::string configurationFileName)
Log< level::Error, false > LogError
uint16_t size_type
std::tuple< std::vector< std::string >, std::vector< int > > ptHatFilesAndValues(const char *inputFile)
const char * iovListForSlides() const
double trendZoomHigh(const int iTrend) const
double luminosityBeforeRun(std::vector< double > lumiPerIov, std::vector< int > iovVector, int runNumber)
const int kMaxFiles
Definition: jetHtPlotter.cc:29
bool drawTrend(const int iTrend) const
std::string legendComment(const int iComment) const
Double_t margin
bool drawHistogram(const int iHistogram) const
TH1 * ptHatCombinedHistogram(std::vector< TFile *> ptHatFiles, std::vector< int > ptHatValues, const char *histogramName)
int markerColor(const int iFile) const
std::vector< double > scaleGraphByLuminosity(TGraphErrors *runGraph, std::vector< double > lumiPerIov, bool skipMissingRuns)
const char * lumiPerIovFile() const
int markerSize(const int iFile) const
double profileLegendShiftColumnX(const int iColumn) const
std::tuple< double, double > findHistogramYaxisRange(TH1D *histogram[kMaxFiles])
std::string legendTextForAllRuns() const
float normalize(float in)
Definition: MLPFModel.cc:207
char data[epos_bytes_allocation]
Definition: EPOS_Wrapper.h:80
Definition: colors.py:1
const char * iovListMode() const
int main(int argc, char **argv)
double profileZoomHigh(const int iProfile) const
const char * saveComment() const
std::tuple< std::vector< int >, std::vector< double >, std::vector< TString >, std::vector< TString > > runAndLumiLists(const char *inputFile, const char *iovListMode)
std::vector< double > widePtBinBorders() const
void readJsonFile(const std::string fileName)
std::vector< double > trendTagPositionY() const
double profileZoomLow(const int iProfile) const
T * Get(Args... args)
Definition: Trend.h:122
std::string inputFile(const int iFile) const