Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 11:57:19

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