File indexing completed on 2023-03-17 10:40:35
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;
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);
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
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
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
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 }