Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 11:56:54

0001 // framework includes
0002 #include "FWCore/ParameterSet/interface/FileInPath.h"
0003 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0004 
0005 // C++ includes
0006 #include <iostream>  // Input/output stream. Needed for cout.
0007 #include <vector>
0008 
0009 // Root includes
0010 #include "TFile.h"
0011 #include "TString.h"
0012 #include "TH1D.h"
0013 #include "TProfile.h"
0014 #include "TGraphErrors.h"
0015 #include "TLegend.h"
0016 #include "TLine.h"
0017 #include "TSystem.h"
0018 #include "TMath.h"
0019 #include "TLatex.h"
0020 
0021 // AllInOneTool includes
0022 #include "Options.h"
0023 
0024 // Include a drawing helper class
0025 #include "JetHtPlotConfiguration.h"
0026 #include "JDrawer.h"
0027 
0028 // Maximum number of compared files implemented in current code
0029 const int kMaxFiles = 4;
0030 
0031 /*
0032  *  Draw a histogram to canvas
0033  *
0034  *  Arguments:
0035  *    TH1D *histogram[kMaxFiles] = Input histogram and comparison histogram
0036  *    const char *saveName = Name given for saved figures
0037  *    bool saveFigures = True: Save figures to file, False: Do not save figures
0038  *    TString comment[kMaxFiles] = Text written to legend
0039  *    int legendPosition = Position index of legend: 0 = Right top, 1 = Middle bottom
0040  *    bool normalize = Normalize the distributions to one so that shapes can be compared
0041  *    bool logScale = Use logarithmic scale for y-axis
0042  *    int color[kMaxFiles] = Color used for each files
0043  */
0044 void drawSingleHistogram(TH1D *histogram[kMaxFiles],
0045                          const char *saveName,
0046                          bool saveFigures,
0047                          TString comment[kMaxFiles],
0048                          int legendPosition,
0049                          bool normalize,
0050                          bool logScale,
0051                          int color[kMaxFiles]) {
0052   // Create and setup the histogram drawer
0053   const auto &drawer = std::make_unique<JDrawer>();
0054   drawer->SetLogY(logScale);
0055   drawer->SetTopMargin(0.08);
0056 
0057   // The first histogram in the array is always included, draw it
0058   histogram[0]->SetLineColor(color[0]);
0059   if (normalize)
0060     histogram[0]->Scale(1.0 / histogram[0]->Integral());
0061   drawer->DrawHistogram(histogram[0]);
0062 
0063   // Draw all the remaining histograms in the array. Calculate how many were drawn
0064   int nHistograms = 1;
0065   for (int iFile = 1; iFile < kMaxFiles; iFile++) {
0066     if (histogram[iFile]) {
0067       nHistograms++;
0068       histogram[iFile]->SetLineColor(color[iFile]);
0069       if (normalize)
0070         histogram[iFile]->Scale(1.0 / histogram[iFile]->Integral());
0071       histogram[iFile]->Draw("Same");
0072     }
0073   }
0074 
0075   // Create a legend with size depending on the number of histograms
0076   double legendX1 = 0.6;
0077   double legendY1 = 0.9 - 0.07 * nHistograms;
0078   double legendX2 = 0.9;
0079   double legendY2 = 0.9;
0080   if (legendPosition == 1) {
0081     legendX1 = 0.35;
0082     legendY1 = 0.4 - 0.07 * nHistograms + 0.07 * (nHistograms / 4);
0083     legendX2 = 0.65;
0084     legendY2 = 0.4 + 0.07 * (nHistograms / 4);
0085   }
0086   TLegend *legend = new TLegend(legendX1, legendY1, legendX2, legendY2);
0087   legend->SetFillStyle(0);
0088   legend->SetBorderSize(0);
0089   legend->SetTextSize(0.05);
0090   legend->SetTextFont(62);
0091 
0092   // Add all the histograms to the legend and draw it
0093   legend->AddEntry(histogram[0], comment[0], "l");
0094   for (int iFile = 1; iFile < kMaxFiles; iFile++) {
0095     if (histogram[iFile]) {
0096       legend->AddEntry(histogram[iFile], comment[iFile], "l");
0097     }
0098   }
0099   legend->Draw();
0100 
0101   // Save the drawn figure to a file
0102   if (saveFigures)
0103     gPad->GetCanvas()->SaveAs(Form("output/%s.pdf", saveName));
0104 }
0105 
0106 /*
0107  *  Find a good range for the y-axes of the histograms
0108  *
0109  *  Arguments:
0110  *   TH1D *histogram[kMaxFiles] = Histogram array from which the Y-axis range is searched
0111  *
0112  *  return:
0113  *   Tuple containing the minimum and maximum zoom for the histogram Y-axis
0114  */
0115 std::tuple<double, double> findHistogramYaxisRange(TH1D *histogram[kMaxFiles]) {
0116   // Find the smallest minimum and largest maximum from the histograms
0117   double minValue = histogram[0]->GetMinimum();
0118   double maxValue = histogram[0]->GetMaximum();
0119 
0120   double newMinValue, newMaxValue;
0121 
0122   for (int iFile = 1; iFile < kMaxFiles; iFile++) {
0123     if (histogram[iFile]) {
0124       newMinValue = histogram[iFile]->GetMinimum();
0125       newMaxValue = histogram[iFile]->GetMaximum();
0126 
0127       if (newMinValue < minValue)
0128         minValue = newMinValue;
0129       if (newMaxValue > maxValue)
0130         maxValue = newMaxValue;
0131     }
0132   }
0133 
0134   // Add some margin below the minimum and over the maximum
0135   double margin = 0.075;
0136   double totalSpan = maxValue - minValue;
0137   minValue = minValue - margin * totalSpan;
0138   if (minValue < 0)
0139     minValue = 0;
0140   maxValue = maxValue + margin * totalSpan;
0141 
0142   // Return the minimum and maximum values
0143   return std::make_tuple(minValue, maxValue);
0144 }
0145 
0146 /*
0147  *  Construct vectors of ptHat files and the ptHat value in each of those files
0148  *
0149  *  Arguments:
0150  *   const char* inputFile = File containing the list of ptHat separated files and ptHat bin in each file
0151  *
0152  *  return:
0153  *   Tuple containing list of runs, luminosities, and histogram names within the validation files
0154  */
0155 std::tuple<std::vector<std::string>, std::vector<int>> ptHatFilesAndValues(const char *inputFile) {
0156   // Create vectors for ptHat files and values
0157   std::vector<std::string> ptHatFileList;
0158   std::vector<int> ptHatList;
0159 
0160   // Helper variables to read the file
0161   std::string lineInFile;
0162 
0163   // Open the input file for reading
0164   std::ifstream ptHatFile(inputFile);
0165 
0166   // Go through the file line by line. Each line has one file and information about the ptHat in the file.
0167   while (std::getline(ptHatFile, lineInFile)) {
0168     auto stringStream = std::istringstream{lineInFile};
0169     auto wordString = std::string{};
0170 
0171     // Find the file name and ptHat in that file
0172     stringStream >> wordString;
0173     ptHatFileList.push_back(wordString);
0174     stringStream >> wordString;
0175     ptHatList.push_back(std::stoi(wordString));
0176   }
0177 
0178   // After all the vectors are filled, return them
0179   return std::make_tuple(ptHatFileList, ptHatList);
0180 }
0181 
0182 /*
0183  * Get a selected histogram combining different pThat bins
0184  */
0185 TH1 *ptHatCombinedHistogram(std::vector<TFile *> ptHatFiles, std::vector<int> ptHatValues, const char *histogramName) {
0186   // Weight for bins:       30to50     50to80      80to120    120to170    170to300    300to470    470to600
0187   double ptHatWeights[] = {
0188       138800000,
0189       19110000,
0190       2735000,
0191       466200,
0192       117200,
0193       7763,
0194       641.0,
0195       //                       600to800   800to1000  1000to1400  1400to1800  1800to2400  2400to3200  3200toInf
0196       185.7,
0197       32.02,
0198       9.375,
0199       0.8384,
0200       0.1133,
0201       0.006746,
0202       0.0001623};
0203   const int nPtHat = 14;
0204   int ptHatBoundaries[] = {30, 50, 80, 120, 170, 300, 470, 600, 800, 1000, 1400, 1800, 2400, 3200};
0205 
0206   TFile *openFile = ptHatFiles.at(0);
0207   TH1 *combinedHistogram = (TH1 *)openFile->Get(histogramName)->Clone(Form("%sClone", histogramName));
0208   TH1 *currentHistogram;
0209   combinedHistogram->Reset("ICES");
0210   int ptHatIndex = -1;
0211 
0212   const int nFiles = ptHatFiles.size();
0213 
0214   for (int iFile = 0; iFile < nFiles; iFile++) {
0215     ptHatIndex = -1;
0216     for (int iPtHat = 0; iPtHat < nPtHat; iPtHat++) {
0217       if (ptHatValues.at(iFile) == ptHatBoundaries[iPtHat]) {
0218         ptHatIndex = iPtHat;
0219         break;
0220       }
0221     }
0222 
0223     if (ptHatIndex < 0) {
0224       std::cout << "Could not find pT hat boundary " << ptHatValues.at(iFile) << " for file " << ptHatFiles.at(iFile)
0225                 << std::endl;
0226       std::cout << "Please check your input! It needs to be in the form <fileName> <ptHatBoundary>" << std::endl;
0227       return nullptr;
0228     }
0229 
0230     openFile = ptHatFiles.at(iFile);
0231     currentHistogram = (TH1 *)openFile->Get(histogramName);
0232     combinedHistogram->Add(currentHistogram, ptHatWeights[ptHatIndex]);
0233   }
0234 
0235   return combinedHistogram;
0236 }
0237 
0238 /*
0239  *  Construct vectors of runs, luminosities, and histogram names within the validation files from an input file
0240  *  containing a list of runs and luminosities attached to each one
0241  *
0242  *  Arguments:
0243  *   const char* inputFile = File containing the run and luminosity lists
0244  *   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.
0245  *
0246  *  return:
0247  *   Tuple containing list of runs, luminosities, histogram names and legend strings within the validation files
0248  */
0249 std::tuple<std::vector<int>, std::vector<double>, std::vector<TString>, std::vector<TString>> runAndLumiLists(
0250     const char *inputFile, const char *iovListMode) {
0251   // Create vectors for each list
0252   std::vector<int> iovVector;
0253   std::vector<double> lumiPerIov;
0254   std::vector<TString> iovNames;
0255   std::vector<TString> iovLegend;
0256 
0257   // Helper variables to read the file
0258   std::string lineInFile;
0259   int thisIov;
0260   double thisLumi;
0261 
0262   // Load the iovList
0263   std::ifstream iovList(edm::FileInPath(inputFile).fullPath().c_str());
0264   if (!iovList.good()) {
0265     edm::LogError("jetHTPlotter") << __PRETTY_FUNCTION__ << "\n Input file: " << inputFile
0266                                   << " is corrupt or not existing";
0267     return std::make_tuple(iovVector, lumiPerIov, iovNames, iovLegend);
0268   }
0269 
0270   // Go through the file line by line. Each line has an IOV boundary and luminosity for this IOV.
0271   while (std::getline(iovList, lineInFile)) {
0272     // Read the iov and luminosity from the file
0273     std::istringstream lineStream(lineInFile);
0274     lineStream >> thisIov;
0275     lineStream >> thisLumi;
0276 
0277     // Push the extracted numbers to vectors
0278     iovVector.push_back(thisIov);
0279     lumiPerIov.push_back(thisLumi);
0280   }
0281 
0282   // Create names for the different IOV:s
0283   for (std::vector<int>::size_type i = 1; i < iovVector.size(); i++) {
0284     iovNames.push_back(Form("iov%d-%d", iovVector.at(i - 1), iovVector.at(i) - 1));
0285   }
0286 
0287   // For the legend naming, use just the run if specified in iovListMode
0288   TString listModeParser = iovListMode;
0289   if (listModeParser.EqualTo("iov", TString::kIgnoreCase)) {
0290     for (std::vector<int>::size_type i = 1; i < iovVector.size(); i++) {
0291       iovLegend.push_back(Form("IOV %d-%d", iovVector.at(i - 1), iovVector.at(i) - 1));
0292     }
0293   } else {
0294     for (std::vector<int>::size_type i = 0; i < iovVector.size() - 1; i++) {
0295       iovLegend.push_back(Form("Run %d", iovVector.at(i)));
0296     }
0297   }
0298 
0299   // Add the iov integrated histograms after the histograms per IOV
0300   iovNames.push_back("all");
0301   iovNames.push_back("central");
0302   iovLegend.push_back("All");
0303   iovLegend.push_back("Central");
0304 
0305   // After all the vectors are filled, return them
0306   return std::make_tuple(iovVector, lumiPerIov, iovNames, iovLegend);
0307 }
0308 
0309 /*
0310  *  Scale the x-axis of a given graph by integrated luminosity. The error on x-axis represents the luminosity of each run.
0311  *
0312  *  Arguments:
0313  *   TGraphErrors *runGraph = Graph containing dxy or dz error trends as a function of run index
0314  *   std::vector<double> lumiPerIov = Vector showing luminosities for each run. Indices must match with the graph
0315  *   bool skipMissingRuns = If there is no data for a run in the runlist, do not assign luminosity for it
0316  *
0317  *  Return: std::vector<double> New luminosity list where skipped runs are set to zero
0318  *
0319  */
0320 std::vector<double> scaleGraphByLuminosity(TGraphErrors *runGraph,
0321                                            std::vector<double> lumiPerIov,
0322                                            bool skipMissingRuns) {
0323   // Read the number of runs from the graph by run number
0324   int nRuns = runGraph->GetN();
0325 
0326   // Helper variables
0327   std::vector<double> xAxisValues, yAxisValues, xAxisErrors, yAxisErrors;
0328 
0329   int iRun = 0;
0330   int offset = 0;
0331   double lumiFactor = 1000;  // Scale factor value to have luminosity expressed in fb^-1
0332 
0333   double runIndex, yValue;
0334   double xValue = 0;
0335   double epsilon = 1e-5;
0336 
0337   std::vector<double> lumiPerIovWithSkips;
0338 
0339   // Loop over all runs, remove zeros and for runs with content, replace x-axis index by luminosity
0340   while (iRun < nRuns) {
0341     runGraph->GetPoint(iRun, runIndex, yValue);
0342 
0343     if (lumiPerIov.at(iRun + offset) == 0 || (yValue < epsilon && skipMissingRuns)) {
0344       nRuns--;
0345       runGraph->RemovePoint(iRun);
0346       offset++;
0347 
0348       // Fill vector where lumi for skipped runs is set to zero
0349       lumiPerIovWithSkips.push_back(0);
0350     } else {
0351       xValue += lumiPerIov.at(iRun + offset) / lumiFactor;
0352       xAxisValues.push_back(xValue - (lumiPerIov.at(iRun + offset) / (lumiFactor * 2)));
0353       xAxisErrors.push_back(lumiPerIov.at(iRun + offset) / (lumiFactor * 2));
0354       yAxisValues.push_back(yValue);
0355       yAxisErrors.push_back(runGraph->GetErrorY(iRun));
0356 
0357       // Fill vector where lumi for skipped runs is set to zero
0358       lumiPerIovWithSkips.push_back(lumiPerIov.at(iRun + offset));
0359 
0360       iRun++;
0361     }
0362   }  // Loop over all runs in original histogram
0363 
0364   // Delete remaining old content and replace it with new one calculated from luminosities
0365   runGraph->GetHistogram()->Delete();
0366   runGraph->SetHistogram(nullptr);
0367   for (int iRun = 0; iRun < nRuns; iRun++) {
0368     runGraph->SetPoint(iRun, xAxisValues.at(iRun), yAxisValues.at(iRun));
0369     runGraph->SetPointError(iRun, xAxisErrors.at(iRun), yAxisErrors.at(iRun));
0370   }
0371 
0372   return lumiPerIovWithSkips;
0373 }
0374 
0375 /*
0376  * Get the total luminosity upto a given run
0377  *
0378  *  std::vector<double> lumiPerIov = Vector containing luminosity information
0379  *  std::vector<int> iovVector = Vector containing run information
0380  *  in runNumber = Run upto which the luminosity is calculated
0381  */
0382 double luminosityBeforeRun(std::vector<double> lumiPerIov, std::vector<int> iovVector, int runNumber) {
0383   double lumiFactor = 1000;  // Scale factor value to have luminosity expressed in fb^-1
0384 
0385   int nRuns = lumiPerIov.size();
0386   double luminosityBefore = 0;
0387 
0388   for (int iRun = 0; iRun < nRuns; iRun++) {
0389     if (runNumber <= iovVector.at(iRun))
0390       return luminosityBefore;
0391 
0392     luminosityBefore += lumiPerIov.at(iRun) / lumiFactor;
0393   }
0394 
0395   return luminosityBefore;
0396 }
0397 
0398 /*
0399  * Macro for plotting figures for the study of jet HT sample
0400  */
0401 void jetHtPlotter(std::string configurationFileName) {
0402   // ======================================================
0403   // ================== Configuration =====================
0404   // ======================================================
0405 
0406   JetHtPlotConfiguration *configurationGiver = new JetHtPlotConfiguration();
0407   configurationGiver->readJsonFile(configurationFileName);
0408   //configurationGiver->printConfiguration();
0409 
0410   enum enumHistogramType { kDz, kDzError, kDxy, kDxyError, knHistogramTypes };
0411   TString histogramName[knHistogramTypes] = {"dz", "dzerr", "dxy", "dxyerr"};
0412   TString histogramXaxis[knHistogramTypes] = {
0413       "d_{z} (#mum)", "#sigma(d_{z}) (#mum)", "d_{xy} (#mum)", "#sigma(d_{xy}) (#mum)"};
0414   enum enumProfileType {
0415     kDzErrorVsPt,
0416     kDzErrorVsPhi,
0417     kDzErrorVsEta,
0418     kDxyErrorVsPt,
0419     kDxyErrorVsPhi,
0420     kDxyErrorVsEta,
0421     kDzErrorVsPtWide,
0422     kDxyErrorVsPtWide,
0423     knProfileTypes
0424   };
0425   enum enumTrendType { kDzErrorTrend, kDxyErrorTrend, knTrendTypes };
0426   TString profileName[knProfileTypes] = {"dzErrVsPt",
0427                                          "dzErrVsPhi",
0428                                          "dzErrVsEta",
0429                                          "dxyErrVsPt",
0430                                          "dxyErrVsPhi",
0431                                          "dxyErrVsEta",
0432                                          "dzErrVsPtWide",
0433                                          "dxyErrVsPtWide"};
0434   TString profileXaxis[knProfileTypes] = {
0435       "p_{T} (GeV)", "#varphi", "#eta", "p_{T} (GeV)", "#varphi", "#eta", "p_{T} bin", "p_{T} bin"};
0436   TString profileYaxis[knProfileTypes] = {"d_{z}", "d_{z}", "d_{z}", "d_{xy}", "d_{xy}", "d_{xy}", "d_{z}", "d_{xy}"};
0437   TString trendName[] = {"dzErr", "dxyErr"};
0438   bool drawHistogram[knHistogramTypes];
0439   bool drawProfile[knProfileTypes];
0440   bool drawTrend[knTrendTypes];
0441 
0442   bool drawTrackQA = configurationGiver->drawTrackQA();                       // Draw track and vertex QA figures
0443   drawHistogram[kDz] = configurationGiver->drawHistogram(kDz);                // Draw the dz histograms
0444   drawHistogram[kDzError] = configurationGiver->drawHistogram(kDzError);      // Draw the dz error histograms
0445   drawProfile[kDzErrorVsPt] = configurationGiver->drawProfile(kDzErrorVsPt);  // Draw mean dz error as a function of pT
0446   drawProfile[kDzErrorVsPhi] =
0447       configurationGiver->drawProfile(kDzErrorVsPhi);  // Draw mean dz error as a function of phi
0448   drawProfile[kDzErrorVsEta] =
0449       configurationGiver->drawProfile(kDzErrorVsEta);  // Draw mean dz error as a function of eta
0450   drawProfile[kDzErrorVsPtWide] =
0451       configurationGiver->drawProfile(kDzErrorVsPtWide);                    // Draw mean dz error in wide pT bins
0452   drawHistogram[kDxy] = configurationGiver->drawHistogram(kDxy);            // Draw the dxy histograms
0453   drawHistogram[kDxyError] = configurationGiver->drawHistogram(kDxyError);  // Draw the dxy error histograms
0454   drawProfile[kDxyErrorVsPt] =
0455       configurationGiver->drawProfile(kDxyErrorVsPt);  // Draw the dxy error as a function of pT
0456   drawProfile[kDxyErrorVsPhi] =
0457       configurationGiver->drawProfile(kDxyErrorVsPhi);  // Draw the dxy error as a function of phi
0458   drawProfile[kDxyErrorVsEta] =
0459       configurationGiver->drawProfile(kDxyErrorVsEta);  // Draw the dxy error as a function of eta
0460   drawProfile[kDxyErrorVsPtWide] =
0461       configurationGiver->drawProfile(kDxyErrorVsPtWide);                  // Draw mean dxy error in wide pT bins
0462   bool drawReferenceProfile = configurationGiver->drawReferenceProfile();  // Draw reference profile to single IOV plots
0463   bool drawCentralEtaSummaryProfile =
0464       configurationGiver->drawCentralEtaSummaryProfile();  // Draw central eta histograms to all runs summary profiles
0465   drawTrend[kDzErrorTrend] = configurationGiver->drawTrend(kDzErrorTrend);    // Draw the trend plots for dz errors
0466   drawTrend[kDxyErrorTrend] = configurationGiver->drawTrend(kDxyErrorTrend);  // Draw the trend plots for dxy errors
0467 
0468   const int nMaxLegendColumns = 3;
0469   double profileLegendShiftTotalX =
0470       configurationGiver->profileLegendShiftTotalX();  // Total legend position shift in x-direction for profile plots
0471   double profileLegendShiftTotalY =
0472       configurationGiver->profileLegendShiftTotalY();  // Total legend position shift in y-direction for profile plots
0473   double profileLegendShiftColumnX[nMaxLegendColumns];
0474   double profileLegendShiftColumnY[nMaxLegendColumns];
0475   for (int iColumn = 0; iColumn < nMaxLegendColumns; iColumn++) {
0476     profileLegendShiftColumnX[iColumn] = configurationGiver->profileLegendShiftColumnX(
0477         iColumn);  // Columnwise legend position shift in x-direction for profile plots
0478     profileLegendShiftColumnY[iColumn] = configurationGiver->profileLegendShiftColumnY(
0479         iColumn);  // Columnwise legend position shift in x-direction for profile plots
0480   }
0481   double profileLegendTextSize = configurationGiver->profileLegendTextSize();  // Legend text size for profile plots
0482   int profileLegendTextFont = configurationGiver->profileLegendTextFont();     // Legend text font for profile plots
0483   TString legendTextForAllRuns =
0484       configurationGiver->legendTextForAllRuns();  // Legend text referring to all runs in the file
0485 
0486   double trendLegendShiftTotalX =
0487       configurationGiver->trendLegendShiftTotalX();  // Total legend position shift in x-direction for trend plots
0488   double trendLegendShiftTotalY =
0489       configurationGiver->trendLegendShiftTotalY();  // Total legend position shift in y-direction for trend plots
0490   double trendLegendTextSize = configurationGiver->trendLegendTextSize();  // Legend text size for trend plots
0491   int trendLegendTextFont = configurationGiver->trendLegendTextFont();     // Legend text font for trend plots
0492 
0493   bool drawTrendTag = configurationGiver->drawTrendTag();                      // Draw manual tags to the trend plots
0494   std::vector<std::string> trendTagText = configurationGiver->trendTagText();  // Drawn tag texts for trend plots
0495   std::vector<double> trendTagPositionX = configurationGiver->trendTagPositionX();  // Trend tag x-positions
0496   std::vector<double> trendTagPositionY = configurationGiver->trendTagPositionY();  // Trend tag y-positions
0497   double trendTagTextSize = configurationGiver->trendTagTextSize();                 // Tag text size for trend plots
0498   int trendTagTextFont = configurationGiver->trendTagTextFont();                    // Tag text font for trend plots
0499 
0500   int trendCanvasHeight = configurationGiver->trendCanvasHeight();     // Canvas height for trend plots
0501   int trendCanvasWidth = configurationGiver->trendCanvasWidth();       // Canvas width for trend plots
0502   double trendMarginLeft = configurationGiver->trendMarginLeft();      // Left margin in trend plots
0503   double trendMarginRight = configurationGiver->trendMarginRight();    // Right margin in trend plots
0504   double trendMarginTop = configurationGiver->trendMarginTop();        // Top margin in trend plots
0505   double trendMarginBottom = configurationGiver->trendMarginBottom();  // Bottom margin in trend plots
0506   double trendTitleOffsetX = configurationGiver->trendTitleOffsetX();  // x-axis title offset in trend plots
0507   double trendTitleOffsetY = configurationGiver->trendTitleOffsetY();  // y-axis title offset in trend plots
0508   double trendTitleSizeX = configurationGiver->trendTitleSizeX();      // x-axis title size in trend plots
0509   double trendTitleSizeY = configurationGiver->trendTitleSizeY();      // y-axis title size in trend plots
0510   double trendLabelOffsetX = configurationGiver->trendLabelOffsetX();  // x-axis label offset in trend plots
0511   double trendLabelOffsetY = configurationGiver->trendLabelOffsetY();  // y-axis label offset in trend plots
0512   double trendLabelSizeX = configurationGiver->trendLabelSizeX();      // x-axis label size in trend plots
0513   double trendLabelSizeY = configurationGiver->trendLabelSizeY();      // y-axis label size in trend plots
0514 
0515   bool drawPlotsForEachIOV =
0516       configurationGiver
0517           ->drawPlotsForEachIOV();  // True = Draw profile and histogram plots for every IOV. False = only draw average over all runs
0518   bool useLuminosityForTrends =
0519       configurationGiver
0520           ->useLuminosityForTrends();  // True = Draw trends as a function of luminosity. False = Draw trends as a function of run index
0521   bool skipRunsWithNoData =
0522       configurationGiver
0523           ->skipRunsWithNoData();  // True = Do not draw empty space if run in list is missing data. False = Draw empty space
0524 
0525   int colors[] = {kBlue, kRed, kGreen + 2, kMagenta, kCyan, kViolet + 3, kOrange, kPink - 7, kSpring + 3, kAzure - 7};
0526   int nIovInOnePlot = configurationGiver->nIovInOnePlot();  // Define how many iov:s are drawn to the same plot
0527 
0528   double profileZoomLow[knProfileTypes];
0529   double profileZoomHigh[knProfileTypes];
0530   double trendZoomLow[knTrendTypes];
0531   double trendZoomHigh[knTrendTypes];
0532 
0533   for (int iProfile = 0; iProfile < knProfileTypes; iProfile++) {
0534     profileZoomLow[iProfile] = configurationGiver->profileZoomLow(iProfile);
0535     profileZoomHigh[iProfile] = configurationGiver->profileZoomHigh(iProfile);
0536   }
0537   for (int iTrend = 0; iTrend < knTrendTypes; iTrend++) {
0538     trendZoomLow[iTrend] = configurationGiver->trendZoomLow(iTrend);
0539     trendZoomHigh[iTrend] = configurationGiver->trendZoomHigh(iTrend);
0540   }
0541 
0542   const std::vector<double> widePtBinBorders = configurationGiver->widePtBinBorders();
0543   const int nWidePtBins = widePtBinBorders.size();
0544 
0545   bool normalizeQAplots = configurationGiver->normalizeQAplots();  // Divide in QA plot yield by its integral
0546   bool saveFigures = true;
0547   const char *saveComment = configurationGiver->saveComment();
0548 
0549   int compareFiles = configurationGiver->nInputFiles();
0550   if (compareFiles == 0)
0551     return;  // Cannot do plotting without files!
0552   if (compareFiles > kMaxFiles)
0553     compareFiles = kMaxFiles;  // Four is maximum number of files in current implementation
0554 
0555   // If we have more then one file, we should not draw more than one IOV per plot and plot all the files instead
0556   if (compareFiles > 1)
0557     nIovInOnePlot = 1;
0558 
0559   // Read the input file names. If file names end with .txt, they are assumed to be lists of files in different ptHat bins
0560   TString inputFileName[kMaxFiles];
0561   bool loadFromList[kMaxFiles] = {false, false, false, false};
0562   TString legendComment[kMaxFiles];
0563   int fileColor[kMaxFiles];
0564   int fileMarkerStyle[kMaxFiles];
0565   int fileMarkerSize[kMaxFiles];
0566   bool copyErrorColor[kMaxFiles];
0567 
0568   for (int iFile = 0; iFile < kMaxFiles; iFile++) {
0569     inputFileName[iFile] = configurationGiver->inputFile(iFile);
0570     if (inputFileName[iFile].EndsWith("txt"))
0571       loadFromList[iFile] = true;
0572     legendComment[iFile] = configurationGiver->legendComment(iFile);  // Text written to the legend for each file
0573     fileColor[iFile] = configurationGiver->markerColor(iFile);        // Color of markers related to this file
0574     fileMarkerStyle[iFile] = configurationGiver->markerStyle(iFile);  // Style for markers related to this file
0575     fileMarkerSize[iFile] = configurationGiver->markerSize(iFile);    // Size for markers related to this file
0576     copyErrorColor[iFile] =
0577         configurationGiver->copyErrorColor(iFile);  // Copy the marker color for error bars for this file
0578   }
0579 
0580   // Prepare an IOV list that can be used with the slide generation script
0581   bool makeIovListForSlides = configurationGiver->makeIovListForSlides();
0582   const char *iovListForSlides = configurationGiver->iovListForSlides();
0583 
0584   // Helper variable to ensure that each IOV is added exactly once to the list
0585   int profileIndexForIovList = 0;
0586   for (int iProfile = 0; iProfile < knProfileTypes; iProfile++) {
0587     if (drawProfile[iProfile]) {
0588       profileIndexForIovList = iProfile;
0589       break;
0590     }
0591   }
0592 
0593   TString plotTitle = " ";  // Title given to the plot
0594 
0595   // Year boundary runs
0596   bool drawYearLines = configurationGiver->drawYearLines();            // Draw lines between data taking years
0597   std::vector<int> linePosition = configurationGiver->runsForLines();  // Positions of the above lines
0598   int yearLineColor = configurationGiver->yearLineColor();             // Color of the above lines
0599   int yearLineWidth = configurationGiver->yearLineWidth();             // Width of the above lines
0600   int yearLineStyle = configurationGiver->yearLineStyle();             // Style of the above lines
0601 
0602   // ======================================================
0603   // ================ Configuration done ==================
0604   // ======================================================
0605 
0606   // =======================================================
0607   //   Make sure that the output folder for figures exists
0608   // =======================================================
0609 
0610   if (saveFigures) {
0611     TString outputFolderStatus = gSystem->GetFromPipe("if [ -d output ]; then echo true; else echo false; fi");
0612     if (outputFolderStatus == "false") {
0613       gSystem->Exec("mkdir output");
0614     }
0615   }
0616 
0617   // ===============================================================
0618   //   Read different ptHat files for combining those with weights
0619   // ===============================================================
0620 
0621   // List for all the different ptHat files to be combined
0622   std::vector<std::string> ptHatFileNameList[kMaxFiles];
0623   std::vector<TFile *> ptHatFileList[kMaxFiles];
0624   std::vector<int> ptHatList[kMaxFiles];
0625   int nFiles;
0626 
0627   for (int iInput = 0; iInput < kMaxFiles; iInput++) {
0628     if (loadFromList[iInput]) {
0629       std::tie(ptHatFileNameList[iInput], ptHatList[iInput]) = ptHatFilesAndValues(inputFileName[iInput]);
0630 
0631       // Open all files
0632       nFiles = ptHatFileNameList[iInput].size();
0633       for (int iFile = 0; iFile < nFiles; iFile++) {
0634         ptHatFileList[iInput].push_back(TFile::Open(ptHatFileNameList[iInput].at(iFile).data()));
0635       }
0636     }
0637   }
0638 
0639   // ===============================================
0640   //        Read the run and luminosity list
0641   // ===============================================
0642 
0643   // Luminosity per run file
0644   const char *iovAndLumiFile = configurationGiver->lumiPerIovFile();
0645   const char *iovListMode = configurationGiver->iovListMode();
0646 
0647   // Create a vector for a new iovList
0648   std::vector<int> iovVector;
0649   std::vector<double> lumiPerIov;
0650   std::vector<double> lumiPerIovWithSkips;
0651   std::vector<TString> iovNames;
0652   std::vector<TString> iovLegend;
0653 
0654   std::tie(iovVector, lumiPerIov, iovNames, iovLegend) = runAndLumiLists(iovAndLumiFile, iovListMode);
0655   // protection against empty input
0656   if (iovVector.empty()) {
0657     edm::LogError("jetHTPlotter") << __PRETTY_FUNCTION__ << "\n The list of input IOVs is empty. Exiting!";
0658     return;
0659   }
0660 
0661   // For the IOV legend, remove the two last entries and replace them with user defined names
0662   iovLegend.pop_back();
0663   iovLegend.pop_back();
0664   iovLegend.push_back(legendTextForAllRuns);
0665   iovLegend.push_back(Form("%s  |#eta| < 1", legendTextForAllRuns.Data()));
0666 
0667   // ===============================================
0668   //                IOV list for slides
0669   // ===============================================
0670 
0671   // If we are preparing an iov list for slides, make a file for that
0672   std::ofstream iovFileForSlides;
0673   if (makeIovListForSlides)
0674     iovFileForSlides.open(iovListForSlides);
0675 
0676   // ===============================================
0677   //   Create histograms and read them from a file
0678   // ===============================================
0679 
0680   // Open the input files
0681   TFile *inputFile[kMaxFiles];
0682   for (int iFile = 0; iFile < kMaxFiles; iFile++) {
0683     if (compareFiles > iFile && !loadFromList[iFile])
0684       inputFile[iFile] = TFile::Open(inputFileName[iFile]);
0685   }
0686 
0687   // Define the histograms that will be read from the file
0688   const int nIov = iovNames.size();
0689   TH1D *hVertex[kMaxFiles];
0690   TH1D *hTracksPerVertex[kMaxFiles];
0691   TH1D *hTrackPt[kMaxFiles];
0692   TH1D *hTrackEta[kMaxFiles];
0693   TH1D *hTrackPhi[kMaxFiles];
0694   TH1D *jetHtHistograms[kMaxFiles][knHistogramTypes][nIov];
0695   TProfile *jetHtProfiles[kMaxFiles][knProfileTypes][nIov];
0696   TGraphErrors *gBigTrend[kMaxFiles][knTrendTypes][nWidePtBins];
0697 
0698   // Initialize everything to NULL
0699   for (int iFile = 0; iFile < kMaxFiles; iFile++) {
0700     hVertex[iFile] = nullptr;
0701     hTracksPerVertex[iFile] = nullptr;
0702     hTrackPt[iFile] = nullptr;
0703     hTrackEta[iFile] = nullptr;
0704     hTrackPhi[iFile] = nullptr;
0705     for (int iIov = 0; iIov < nIov; iIov++) {
0706       for (int iHistogramType = 0; iHistogramType < knHistogramTypes; iHistogramType++) {
0707         jetHtHistograms[iFile][iHistogramType][iIov] = nullptr;
0708       }  // histogram type loop
0709       for (int iProfileType = 0; iProfileType < knProfileTypes; iProfileType++) {
0710         jetHtProfiles[iFile][iProfileType][iIov] = nullptr;
0711       }  // profile type loop
0712     }    // iov loop for reading histograms from file
0713     for (int iTrend = 0; iTrend < knTrendTypes; iTrend++) {
0714       for (int iWidePt = 0; iWidePt < nWidePtBins; iWidePt++) {
0715         gBigTrend[iFile][iTrend][iWidePt] = nullptr;
0716       }  // Trend loop
0717     }    // Wide pT bin loop
0718   }      // file loop
0719 
0720   // Read the histograms from the file
0721   for (int iFile = 0; iFile < compareFiles; iFile++) {
0722     if (loadFromList[iFile]) {
0723       // Alternative loading for ptHat combined values
0724 
0725       hVertex[iFile] = (TH1D *)ptHatCombinedHistogram(ptHatFileList[iFile], ptHatList[iFile], "jetHTAnalyzer/all_nvtx");
0726       hTracksPerVertex[iFile] =
0727           (TH1D *)ptHatCombinedHistogram(ptHatFileList[iFile], ptHatList[iFile], "jetHTAnalyzer/h_ntrks");
0728       hTrackPt[iFile] =
0729           (TH1D *)ptHatCombinedHistogram(ptHatFileList[iFile], ptHatList[iFile], "jetHTAnalyzer/h_probePt");
0730       hTrackEta[iFile] =
0731           (TH1D *)ptHatCombinedHistogram(ptHatFileList[iFile], ptHatList[iFile], "jetHTAnalyzer/h_probeEta");
0732       hTrackPhi[iFile] =
0733           (TH1D *)ptHatCombinedHistogram(ptHatFileList[iFile], ptHatList[iFile], "jetHTAnalyzer/h_probePhi");
0734       for (int iIov = nIov - 2; iIov < nIov - 1; iIov++) {
0735         for (int iHistogramType = 0; iHistogramType < knHistogramTypes; iHistogramType++) {
0736           if (drawHistogram[iHistogramType]) {
0737             jetHtHistograms[iFile][iHistogramType][iIov] = (TH1D *)ptHatCombinedHistogram(
0738                 ptHatFileList[iFile],
0739                 ptHatList[iFile],
0740                 Form("jetHTAnalyzer/%s_%s", iovNames.at(iIov).Data(), histogramName[iHistogramType].Data()));
0741           }  // if for drawing histogram
0742         }    // histogram type loop
0743         for (int iProfileType = 0; iProfileType < knProfileTypes; iProfileType++) {
0744           if (drawProfile[iProfileType] || (drawTrend[kDzErrorTrend] && iProfileType == kDzErrorVsPtWide) ||
0745               (drawTrend[kDxyErrorTrend] && iProfileType == kDxyErrorVsPtWide)) {
0746             jetHtProfiles[iFile][iProfileType][iIov] = (TProfile *)ptHatCombinedHistogram(
0747                 ptHatFileList[iFile],
0748                 ptHatList[iFile],
0749                 Form("jetHTAnalyzer/%s_%s", iovNames.at(iIov).Data(), profileName[iProfileType].Data()));
0750           }  // if for drawing profile
0751         }    // profile type loop
0752       }      // iov loop for reading histograms from file
0753 
0754     } else {
0755       // Regular histogram loading
0756 
0757       hVertex[iFile] = (TH1D *)inputFile[iFile]->Get("jetHTAnalyzer/all_nvtx");
0758       hTracksPerVertex[iFile] = (TH1D *)inputFile[iFile]->Get("jetHTAnalyzer/h_ntrks");
0759       hTrackPt[iFile] = (TH1D *)inputFile[iFile]->Get("jetHTAnalyzer/h_probePt");
0760       hTrackEta[iFile] = (TH1D *)inputFile[iFile]->Get("jetHTAnalyzer/h_probeEta");
0761       hTrackPhi[iFile] = (TH1D *)inputFile[iFile]->Get("jetHTAnalyzer/h_probePhi");
0762       for (int iIov = 0; iIov < nIov; iIov++) {
0763         for (int iHistogramType = 0; iHistogramType < knHistogramTypes; iHistogramType++) {
0764           if (drawHistogram[iHistogramType]) {
0765             jetHtHistograms[iFile][iHistogramType][iIov] = (TH1D *)inputFile[iFile]->Get(
0766                 Form("jetHTAnalyzer/%s_%s", iovNames.at(iIov).Data(), histogramName[iHistogramType].Data()));
0767           }  // if for drawing histogram
0768         }    // histogram type loop
0769         for (int iProfileType = 0; iProfileType < knProfileTypes; iProfileType++) {
0770           if (drawProfile[iProfileType] || (drawTrend[kDzErrorTrend] && iProfileType == kDzErrorVsPtWide) ||
0771               (drawTrend[kDxyErrorTrend] && iProfileType == kDxyErrorVsPtWide)) {
0772             jetHtProfiles[iFile][iProfileType][iIov] = (TProfile *)inputFile[iFile]->Get(
0773                 Form("jetHTAnalyzer/%s_%s", iovNames.at(iIov).Data(), profileName[iProfileType].Data()));
0774           }  // if for drawing profile
0775         }    // profile type loop
0776       }      // iov loop for reading histograms from file
0777     }        // Regular histogram loading
0778   }          // Loop over files
0779 
0780   // Collect the information for the trend graphs
0781   const int nRuns = iovVector.size() - 1;
0782   double yValueDz[nRuns];
0783   double yErrorDz[nRuns];
0784   double yValueDxy[nRuns];
0785   double yErrorDxy[nRuns];
0786   double xValue[nRuns];
0787   double xError[nRuns];
0788   TString commentEntry = "";
0789   if (drawTrend[kDzErrorTrend] || drawTrend[kDxyErrorTrend]) {
0790     for (int iFile = 0; iFile < compareFiles; iFile++) {
0791       for (int iWidePt = 0; iWidePt < nWidePtBins; iWidePt++) {
0792         for (int iRun = 0; iRun < nRuns; iRun++) {
0793           xValue[iRun] = iRun;
0794           xError[iRun] = 0;
0795           if (jetHtProfiles[iFile][kDzErrorVsPtWide][iRun] == nullptr) {
0796             yValueDz[iRun] = 0;
0797             yErrorDz[iRun] = 0;
0798           } else {
0799             yValueDz[iRun] = jetHtProfiles[iFile][kDzErrorVsPtWide][iRun]->GetBinContent(iWidePt + 1);
0800             yErrorDz[iRun] = jetHtProfiles[iFile][kDzErrorVsPtWide][iRun]->GetBinError(iWidePt + 1);
0801           }
0802           if (jetHtProfiles[iFile][kDxyErrorVsPtWide][iRun] == nullptr) {
0803             yValueDxy[iRun] = 0;
0804             yErrorDxy[iRun] = 0;
0805           } else {
0806             yValueDxy[iRun] = jetHtProfiles[iFile][kDxyErrorVsPtWide][iRun]->GetBinContent(iWidePt + 1);
0807             yErrorDxy[iRun] = jetHtProfiles[iFile][kDxyErrorVsPtWide][iRun]->GetBinError(iWidePt + 1);
0808           }
0809         }  // Run loop
0810 
0811         gBigTrend[iFile][kDzErrorTrend][iWidePt] = new TGraphErrors(nRuns, xValue, yValueDz, xError, yErrorDz);
0812         gBigTrend[iFile][kDxyErrorTrend][iWidePt] = new TGraphErrors(nRuns, xValue, yValueDxy, xError, yErrorDxy);
0813 
0814         // Change x-axis to processed luminosity
0815         if (useLuminosityForTrends) {
0816           lumiPerIovWithSkips =
0817               scaleGraphByLuminosity(gBigTrend[iFile][kDzErrorTrend][iWidePt], lumiPerIov, skipRunsWithNoData);
0818           scaleGraphByLuminosity(gBigTrend[iFile][kDxyErrorTrend][iWidePt], lumiPerIov, skipRunsWithNoData);
0819         }
0820 
0821       }  // Wide pT bin loop
0822     }    // File loop
0823   }      // If for drawing trends
0824 
0825   // ===============================================
0826   //                  Draw the plots
0827   // ===============================================
0828 
0829   const auto &drawer = std::make_unique<JDrawer>();
0830   TLegend *legend[nMaxLegendColumns];
0831   int columnOrder[nMaxLegendColumns];
0832   bool noIovFound = true;
0833   bool canvasDrawn;
0834   bool doNotDrawEta;
0835   double minZoomY, maxZoomY;
0836   int nDrawnHistograms, nLeftLegend, nRightLegend;
0837   double legendX1, legendX2, legendY1, legendY2;
0838   int iLegend = 0;
0839   int skipColor = 0;
0840   int nNullHistograms;
0841   int iHistogram;
0842   TString legendString;
0843   TH1D *histogramSearchArray[kMaxFiles];
0844   for (int iFile = 0; iFile < kMaxFiles; iFile++) {
0845     histogramSearchArray[iFile] = nullptr;
0846   }
0847 
0848   // Draw track and vertex histograms
0849   if (drawTrackQA) {
0850     drawSingleHistogram(
0851         hVertex, Form("vertex%s", saveComment), saveFigures, legendComment, 0, normalizeQAplots, false, fileColor);
0852     drawSingleHistogram(hTracksPerVertex,
0853                         Form("tracksPerVertex%s", saveComment),
0854                         saveFigures,
0855                         legendComment,
0856                         0,
0857                         normalizeQAplots,
0858                         false,
0859                         fileColor);
0860     drawSingleHistogram(
0861         hTrackPt, Form("trackPt%s", saveComment), saveFigures, legendComment, 0, normalizeQAplots, true, fileColor);
0862     drawSingleHistogram(
0863         hTrackEta, Form("trackEta%s", saveComment), saveFigures, legendComment, 1, normalizeQAplots, false, fileColor);
0864     drawSingleHistogram(
0865         hTrackPhi, Form("trackPhi%s", saveComment), saveFigures, legendComment, 1, normalizeQAplots, false, fileColor);
0866   }
0867 
0868   // Draw dz and dxy histograms
0869   for (int iIov = 0; iIov < nIov; iIov++) {
0870     if (!drawPlotsForEachIOV && iIov < nIov - 2)
0871       continue;
0872     for (int iHistogramType = 0; iHistogramType < knHistogramTypes; iHistogramType++) {
0873       if (drawHistogram[iHistogramType]) {
0874         double legendX1 = 0.6;
0875         double legendY1 = 0.9 - 0.07 * compareFiles;
0876         double legendX2 = 0.9;
0877         double legendY2 = 0.9;
0878         if (iHistogramType == kDxy || iHistogramType == kDz) {
0879           legendX1 = 0.4;
0880           legendY1 = 0.4 - 0.07 * compareFiles + 0.07 * (compareFiles / 4);
0881           legendX2 = 0.7;
0882           legendY2 = 0.4 + 0.07 * (compareFiles / 4);
0883         }
0884 
0885         legend[0] = new TLegend(legendX1, legendY1, legendX2, legendY2);
0886         legend[0]->SetFillStyle(0);
0887         legend[0]->SetBorderSize(0);
0888         legend[0]->SetTextSize(0.05);
0889         legend[0]->SetTextFont(62);
0890 
0891         if (jetHtHistograms[0][iHistogramType][iIov] != nullptr) {
0892           for (int iFile = 0; iFile < compareFiles; iFile++) {
0893             histogramSearchArray[iFile] = jetHtHistograms[iFile][iHistogramType][iIov];
0894           }
0895 
0896           std::tie(minZoomY, maxZoomY) = findHistogramYaxisRange(histogramSearchArray);
0897           jetHtHistograms[0][iHistogramType][iIov]->GetYaxis()->SetRangeUser(minZoomY, maxZoomY);
0898           jetHtHistograms[0][iHistogramType][iIov]->SetLineColor(fileColor[0]);
0899 
0900           drawer->DrawHistogram(jetHtHistograms[0][iHistogramType][iIov],
0901                                 histogramXaxis[iHistogramType],
0902                                 "Tracks",
0903                                 iovLegend.at(iIov).Data());
0904           legend[0]->AddEntry(jetHtHistograms[0][iHistogramType][iIov], legendComment[0], "l");
0905 
0906           for (int iFile = 1; iFile < compareFiles; iFile++) {
0907             if (jetHtHistograms[iFile][iHistogramType][iIov] != nullptr) {
0908               jetHtHistograms[iFile][iHistogramType][iIov]->SetLineColor(fileColor[iFile]);
0909               jetHtHistograms[iFile][iHistogramType][iIov]->Draw("same");
0910               legend[0]->AddEntry(jetHtHistograms[iFile][iHistogramType][iIov], legendComment[iFile], "l");
0911             }
0912           }
0913 
0914           legend[0]->Draw();
0915 
0916           // Save the figures
0917           if (saveFigures) {
0918             gPad->GetCanvas()->SaveAs(Form(
0919                 "output/%s%s_%s.pdf", histogramName[iHistogramType].Data(), saveComment, iovNames.at(iIov).Data()));
0920           }
0921 
0922         } else {
0923           std::cout << "No histogram found for: "
0924                     << Form("%s_%s", iovNames.at(iIov).Data(), histogramName[iHistogramType].Data()) << std::endl;
0925         }
0926       }  // if for drawing histogram
0927     }    // histogram type loop
0928   }
0929 
0930   // Draw dz and dxy profiles
0931   for (int iProfileType = 0; iProfileType < knProfileTypes; iProfileType++) {
0932     if (drawProfile[iProfileType]) {
0933       // Set the style for IOV integrated histograms
0934       for (int iFile = 0; iFile < compareFiles; iFile++) {
0935         jetHtProfiles[iFile][iProfileType][nIov - 2]->SetLineColor(fileColor[iFile]);
0936         jetHtProfiles[iFile][iProfileType][nIov - 2]->SetLineWidth(2);
0937         jetHtProfiles[iFile][iProfileType][nIov - 2]->SetLineStyle(2);
0938         jetHtProfiles[iFile][iProfileType][nIov - 2]->GetYaxis()->SetRangeUser(profileZoomLow[iProfileType],
0939                                                                                profileZoomHigh[iProfileType]);
0940       }
0941 
0942       // Drawing plots for each IOV.
0943       if (drawPlotsForEachIOV) {
0944         for (int iIov = 0; iIov < nIov - 2; iIov = iIov + nIovInOnePlot) {
0945           noIovFound = true;
0946           iLegend = 0;
0947           canvasDrawn = false;
0948           nNullHistograms = 0;
0949 
0950           // If we have more than one file, draw all files to the same figure. Otherwise use the nIovInOnePlot variable for the single file.
0951           // Set up the IOV:s or files to be drawn to the current plot
0952           for (int iFile = 0; iFile < compareFiles; iFile++) {
0953             skipColor = 0;
0954             for (int iSamePlot = 0; iSamePlot < nIovInOnePlot; iSamePlot++) {
0955               if (iIov + iSamePlot >= nIov - 2)
0956                 break;  // Do not draw again all or central references
0957               if (jetHtProfiles[iFile][iProfileType][iIov + iSamePlot] != nullptr) {
0958                 if (nIovInOnePlot > 1) {
0959                   if (colors[iFile + iSamePlot] == fileColor[0])
0960                     skipColor++;
0961                   jetHtProfiles[iFile][iProfileType][iIov + iSamePlot]->SetLineColor(colors[skipColor + iSamePlot]);
0962                 } else {
0963                   jetHtProfiles[iFile][iProfileType][iIov + iSamePlot]->SetLineColor(fileColor[iFile + iSamePlot]);
0964                 }
0965                 jetHtProfiles[iFile][iProfileType][iIov + iSamePlot]->SetLineWidth(2);
0966                 noIovFound = false;
0967               } else {
0968                 std::cout << "No histogram found for: "
0969                           << Form("%s_%s", iovNames.at(iIov).Data(), profileName[iProfileType].Data()) << std::endl;
0970                 nNullHistograms++;
0971               }
0972             }
0973           }
0974 
0975           if (noIovFound)
0976             continue;
0977 
0978           // Setup legends. There are four different configuration.
0979           // 1) Draw several files in one plot, include reference distribution from all runs
0980           // 2) Draw several files in one plot, do not include reference distribution from all runs
0981           // 3) Draw several IOVs in one plot, include reference distribution from all runs
0982           // 4) Draw several IOVs in one plot, do not include reference distribution from all runs
0983           // Each setup needs slightly different configuration for the legends to look good
0984 
0985           // First determine the number of drawns histograms and how many of them should be drawn to left and right, if the legend is split
0986           nDrawnHistograms = drawReferenceProfile * compareFiles + nIovInOnePlot * compareFiles - nNullHistograms;
0987           nLeftLegend = TMath::Ceil(nDrawnHistograms / 2.0);
0988           nRightLegend = TMath::Floor(nDrawnHistograms / 2.0);
0989 
0990           // Make adjustments to the number of drawn histograms in some special cases
0991           if (!drawReferenceProfile) {
0992             if (compareFiles > 1) {
0993               nLeftLegend = 1;
0994               nRightLegend = nDrawnHistograms;
0995             }
0996             if (nIovInOnePlot > 1) {
0997               if (nLeftLegend > nRightLegend) {
0998                 nRightLegend++;
0999               } 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 =====
1356   AllInOneConfig::Options options;
1357   options.helper(argc, argv);
1358   options.parser(argc, argv);
1359 
1360   // Run the program
1361   jetHtPlotter(options.config);
1362 }