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;
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);
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
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
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
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 }