Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2023-10-25 09:32:59

0001 #include <cassert>  // you may want to replace all assertions by clear error messages
0002 #include <cstdlib>
0003 
0004 #include <vector>
0005 #include <iostream>
0006 #include <fstream>
0007 #include <string>
0008 
0009 #include "TLine.h"
0010 #include "TLatex.h"
0011 #include "TString.h"
0012 #include "TGraphErrors.h"
0013 #include "TH1.h"
0014 
0015 #include "Alignment/OfflineValidation/plugins/ColorParser.C"
0016 #include "Alignment/OfflineValidation/plugins/StyleParser.C"
0017 #include "Alignment/OfflineValidation/interface/Trend.h"
0018 
0019 using namespace std;
0020 namespace fs = boost::filesystem;
0021 namespace pt = boost::property_tree;
0022 
0023 Run2Lumi::Run2Lumi(fs::path file, int first, int last, float convertUnit)
0024     : firstRun(first), lastRun(last), convertUnit(convertUnit) {
0025   assert(first < last);
0026 
0027   assert(fs::exists(file));
0028 
0029   ifstream f(file);
0030   int run;
0031   while (f >> run >> runs[run])
0032     ;
0033   f.close();
0034 }
0035 
0036 float Run2Lumi::operator()(int run1, int run2) const
0037 
0038 {
0039   float sum = 0.;
0040   for (auto& run : runs) {
0041     if (run.first < run1)
0042       continue;
0043     if (run.first >= run2)
0044       break;
0045     sum += run.second;
0046   }
0047   return sum / convertUnit;  // conversion from e.g. /pb to /fb
0048 }
0049 
0050 float Run2Lumi::operator()(int run) const { return operator()(firstRun, run); }
0051 
0052 float Run2Lumi::operator()() const { return operator()(firstRun, lastRun); }
0053 
0054 template <typename T>
0055 void CopyStyle(T* objIn, T* objOut) {
0056   objOut->SetLineColor(objIn->GetLineColor());
0057   objOut->SetMarkerColor(objIn->GetMarkerColor());
0058   objOut->SetFillColorAlpha(objIn->GetFillColor(), 0.2);  // TODO??
0059 
0060   objOut->SetLineStyle(objIn->GetLineStyle());
0061   objOut->SetMarkerStyle(objIn->GetMarkerStyle());
0062   objOut->SetFillStyle(objIn->GetFillStyle());
0063 
0064   objOut->SetLineWidth(objIn->GetLineWidth());
0065   objOut->SetMarkerSize(objIn->GetMarkerSize());
0066 }
0067 
0068 TGraph* Run2Lumi::operator()(TGraph* gIn) const {
0069   assert(gIn != nullptr);
0070 
0071   vector<float> x, y, ex, ey;
0072   int n = gIn->GetN();
0073   for (int i = 0; i < n - 1; ++i) {
0074     int currentRun = gIn->GetPointX(i);
0075     if (currentRun < firstRun)
0076       continue;
0077     if (currentRun >= lastRun)
0078       break;
0079 
0080     int nextRun = gIn->GetPointX(i + 1);
0081 
0082     auto lumi_edge = operator()(firstRun, currentRun), lumi_width = operator()(currentRun, nextRun);
0083     x.push_back(lumi_edge + lumi_width / 2);
0084     ex.push_back(lumi_width / 2);
0085 
0086     auto point = gIn->GetPointY(i), error = gIn->GetErrorY(i);
0087     y.push_back(point);
0088     ey.push_back(error);
0089   }
0090 
0091   auto N = x.size();
0092   assert(N == y.size() && N == ex.size() && N == ey.size());
0093   TGraph* gOut = new TGraphErrors(N, x.data(), y.data(), ex.data(), ey.data());
0094   gOut->SetTitle(gIn->GetTitle());
0095   CopyStyle(gIn, gOut);
0096   return gOut;
0097 }
0098 
0099 TH1* Run2Lumi::operator()(TH1* hIn) const {
0100   vector<float> edges, contents, errors;
0101   edges.push_back(0);
0102   int N = hIn->GetNbinsX();
0103   for (int i = 1; i <= N; ++i) {
0104     auto nextRun = hIn->GetBinLowEdge(i + 1);
0105     if (nextRun < firstRun)
0106       continue;
0107     if (nextRun >= lastRun)
0108       break;
0109 
0110     edges.push_back(operator()(nextRun));
0111 
0112     auto content = hIn->GetBinContent(i), error = hIn->GetBinError(i);
0113     contents.push_back(content);
0114     errors.push_back(error);
0115   }
0116 
0117   N = edges.size() - 1;
0118   TString name = hIn->GetName();
0119   name += "_byLumi";
0120   TH1* hOut = new TH1F(name, hIn->GetTitle(), N, edges.data());
0121   for (int i = 1; i <= N; ++i) {
0122     hOut->SetBinContent(i, contents[i - 1]);
0123     hOut->SetBinError(i, errors[i - 1]);
0124   }
0125   CopyStyle(hIn, hOut);
0126   return hOut;
0127 }
0128 
0129 Trend::Trend(const char* name,
0130              const char* dir,
0131              const char* title,
0132              const char* ytitle,
0133              float ymin,
0134              float ymax,
0135              pt::ptree& json,
0136              const Run2Lumi& GetLumiFunctor,
0137              const char* lumiAxisType)
0138     : c(name, title, 2000, 800),
0139       outputDir(Form("%s", dir)),
0140       lgd(0.7, 0.65, 0.97, 0.89, "", "NDC"),
0141       JSON(json),
0142       GetLumi(GetLumiFunctor),
0143       lumiType(lumiAxisType) {
0144   if (JSON.count("CMSlabel"))
0145     CMS = Form("#scale[1.1]{#bf{CMS}} #it{%s}", JSON.get<string>("CMSlabel").data());
0146 
0147   if (JSON.get_child("trends").count("TitleCanvas"))
0148     lumi = Form("#scale[0.8]{%s}", JSON.get_child("trends").get<string>("TitleCanvas").data());
0149 
0150   assert(ymin < ymax);
0151   float xmax = GetLumi(GetLumi.firstRun, GetLumi.lastRun);
0152   if (JSON.get_child("trends").count("plotUnit"))
0153     plotUnit = JSON.get_child("trends").get<string>("plotUnit");
0154   const char* axistitles = Form(";%s luminosity  [%s^{-1} ];%s", lumiType, plotUnit.c_str(), ytitle);
0155   auto frame = c.DrawFrame(0., ymin, xmax, ymax, axistitles);
0156   frame->GetYaxis()->SetTitleOffset(0.8);
0157   frame->GetYaxis()->SetTickLength(0.01);
0158   frame->GetXaxis()->SetLabelSize(fontsize);
0159   frame->GetXaxis()->SetTitleSize(fontsize);
0160   frame->GetYaxis()->SetLabelSize(fontsize);
0161   frame->GetYaxis()->SetTitleSize(fontsize);
0162   lgd.SetTextSize(fontsize);
0163 
0164   if (ymax > 0 && ymin < 0) {
0165     TLine l;
0166     l.SetLineColor(kBlack);
0167     l.SetLineStyle(kDashed);
0168     l.DrawLine(0., 0., xmax, 0.);
0169   }
0170 
0171   c.SetTicks(1, 1);
0172   c.SetRightMargin(0.015);
0173   c.SetLeftMargin(0.07);
0174   c.SetTopMargin(0.07);
0175 
0176   // plot vertical lines (typically pixel template transitions)
0177   pt::ptree lines = JSON.get_child("trends.lines");
0178   for (auto& type : lines) {
0179     auto line = type.second.get_child_optional("line");
0180     auto runs = type.second.get_child_optional("runs");
0181     if (!line || !runs)
0182       continue;
0183 
0184     auto v = new TLine;
0185 
0186     auto style = line->get_optional<string>("style");
0187     if (style)
0188       v->SetLineStyle(StyleParser(*style));
0189 
0190     auto color = line->get_optional<string>("color");
0191     if (color)
0192       v->SetLineColor(ColorParser(*color));
0193 
0194     auto width = line->get_optional<int>("width");
0195     if (width)
0196       v->SetLineWidth(*width);
0197 
0198     auto title = line->get_optional<string>("title");
0199     if (title)
0200       lgd.AddEntry(v, title->c_str(), "l");
0201 
0202     for (auto& run : *runs) {
0203       auto currentRun = run.second.get_value<int>();
0204 
0205       auto lumi = GetLumi(GetLumi.firstRun, currentRun);
0206 
0207       if (lumi > 0)
0208         v->DrawLine(lumi, ymin, lumi, ymax);
0209     }
0210   }
0211 }
0212 
0213 void Trend::operator()(TObject* obj, TString drawOpt, TString lgdOpt, bool fullRange) {
0214   c.cd();
0215 
0216   TString classname = obj->ClassName();
0217   if (classname.Contains("TGraph")) {
0218     auto g = dynamic_cast<TGraph*>(obj);
0219     int n = g->GetN();
0220 
0221     if (fullRange) {
0222       g->Set(n);
0223       g->SetPoint(n, GetLumi.lastRun, 0);
0224     }
0225     g = GetLumi(g);
0226     g->Draw("same" + drawOpt);
0227   } else if (classname.Contains("TH1")) {
0228     auto h = dynamic_cast<TH1*>(obj);
0229     // TODO: full range?
0230     h = GetLumi(h);
0231     h->Draw("same" + drawOpt);
0232   } else {
0233     cerr << "No implementation for `" << classname << "`\n";
0234     exit(EXIT_FAILURE);
0235   }
0236 
0237   TString name = c.GetName();
0238   name.ReplaceAll("vs_run", "vs_lumi");
0239   c.SetName(name);
0240 
0241   TString title = obj->GetTitle();
0242   if (title == "")
0243     return;
0244   lgd.AddEntry(obj, "", lgdOpt);
0245 }
0246 
0247 Trend::~Trend() {
0248   c.cd();
0249   lgd.Draw();
0250 
0251   float l = c.GetLeftMargin(), t = c.GetTopMargin(), r = c.GetRightMargin(), lumiTextOffset = 0.2;
0252 
0253   TLatex latex;
0254   latex.SetNDC();
0255   latex.SetTextFont(42);
0256 
0257   latex.SetTextAlign(11);
0258   latex.DrawLatex(l, 1 - t + lumiTextOffset * t, CMS);
0259 
0260   latex.SetTextAlign(31);
0261   latex.DrawLatex(1 - r, 1 - t + lumiTextOffset * t, lumi);
0262 
0263   // plot labels
0264   latex.SetTextAlign(13);
0265   auto totLumi = GetLumi();
0266   assert(totLumi > 0);
0267   auto posY = 0.88;
0268   pt::ptree lines = JSON.get_child("trends.lines");
0269   for (auto& type : lines) {
0270     auto labels = type.second.get_child_optional("labels");
0271     auto runs = type.second.get_child_optional("runs");
0272     if (!labels || !runs)
0273       continue;
0274 
0275     auto runIt = runs->begin();
0276     auto labelIt = labels->begin();
0277     while (runIt != runs->end() && labelIt != labels->end()) {
0278       auto currentRun = runIt->second.get_value<int>();
0279       auto label = labelIt->second.get_value<string>();
0280 
0281       auto lumi = max(GetLumi(currentRun), (float)0.01);
0282       auto posX = l + (lumi / totLumi) / (l + 1 + r) + 0.02;
0283 
0284       label = "#scale[0.8]{" + label + "}";
0285       latex.DrawLatex(posX, posY, label.c_str());
0286 
0287       ++runIt;
0288       ++labelIt;
0289     }
0290     posY -= 0.06;
0291   }
0292 
0293   c.RedrawAxis();
0294   c.SaveAs(Form("%s/%s.pdf", outputDir, c.GetName()), Form("Title:%s", c.GetTitle()));
0295 }