CMS 3D CMS Logo

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