Skip to content

Commit f4293b5

Browse files
authored
add plotBcOccupancyQa macro for BC occupancy QA
1 parent b9c3aea commit f4293b5

1 file changed

Lines changed: 272 additions & 0 deletions

File tree

Lines changed: 272 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,272 @@
1+
// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2+
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3+
// All rights not expressly granted are reserved.
4+
//
5+
// This software is distributed under the terms of the GNU General Public
6+
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7+
//
8+
// In applying this license CERN does not waive the privileges and immunities
9+
// granted to it by virtue of its status as an Intergovernmental Organization
10+
// or submit itself to any jurisdiction.
11+
12+
/// \file plotBcOccupancyQa.C
13+
/// \brief Plots and summary of the BC occupancy QA (output of o2-analysis-bc-occupancy-qa)
14+
///
15+
/// Usage:
16+
/// root -l -b -q 'plotBcOccupancyQa.C("AnalysisResults.root")'
17+
/// root -l -b -q 'plotBcOccupancyQa.C("AnalysisResults.root", "bcOccupancyQa.pdf", "bc-occupancy-qa-task")'
18+
///
19+
/// \author Igor Altsybeev <Igor.Altsybeev@cern.ch>
20+
21+
#include <TCanvas.h>
22+
#include <TDirectory.h>
23+
#include <TFile.h>
24+
#include <TH1.h>
25+
#include <TH2.h>
26+
#include <TKey.h>
27+
#include <TLegend.h>
28+
#include <TProfile.h>
29+
#include <TString.h>
30+
#include <TStyle.h>
31+
32+
#include <algorithm>
33+
#include <cstdio>
34+
#include <memory>
35+
#include <string>
36+
#include <vector>
37+
38+
namespace bcoccqa
39+
{
40+
TDirectory* gDir = nullptr;
41+
42+
// histogram from the task directory (or from one of its subdirectories), detached from the file
43+
template <typename T>
44+
T* getHist(const char* name)
45+
{
46+
TObject* obj = gDir->Get(name);
47+
if (!obj) {
48+
for (TObject* key : *gDir->GetListOfKeys()) {
49+
if (auto* sub = dynamic_cast<TDirectory*>(static_cast<TKey*>(key)->ReadObj())) {
50+
obj = sub->Get(name);
51+
if (obj) {
52+
break;
53+
}
54+
}
55+
}
56+
}
57+
auto* h = dynamic_cast<T*>(obj);
58+
if (!h) {
59+
std::printf("histogram %s not found\n", name);
60+
return nullptr;
61+
}
62+
h->SetDirectory(nullptr);
63+
return h;
64+
}
65+
66+
// fraction of BCs per bin: numerator / denominator (binomial errors)
67+
TH1D* makeRatio(const TH1* num, const TH1* den, const char* name, const char* title)
68+
{
69+
auto* r = static_cast<TH1D*>(num->Clone(name));
70+
r->SetTitle(title);
71+
r->Divide(num, den, 1., 1., "B");
72+
return r;
73+
}
74+
75+
// upper edge of the last filled bin (with 10% margin), to zoom the occupancy axes (e.g. for pp)
76+
double upperEdgeOfFilledRange(const TH1* h)
77+
{
78+
int last = 1;
79+
for (int i = h->GetNbinsX(); i >= 1; i--) {
80+
if (h->GetBinContent(i) > 0) {
81+
last = i;
82+
break;
83+
}
84+
}
85+
return std::min(h->GetXaxis()->GetXmax(), 1.1 * h->GetXaxis()->GetBinUpEdge(last));
86+
}
87+
} // namespace bcoccqa
88+
89+
void plotBcOccupancyQa(const char* fileName = "AnalysisResults.root", const char* outPdf = "bcOccupancyQa.pdf", const char* dirName = "bc-occupancy-qa-task")
90+
{
91+
using namespace bcoccqa;
92+
TH1::AddDirectory(kFALSE);
93+
gStyle->SetOptStat(0);
94+
gStyle->SetPalette(kViridis);
95+
gStyle->SetPaperSize(30., 20.); // landscape pages, same aspect ratio as the canvas
96+
97+
std::unique_ptr<TFile> f(TFile::Open(fileName, "READ"));
98+
if (!f || f->IsZombie()) {
99+
std::printf("cannot open %s\n", fileName);
100+
return;
101+
}
102+
gDir = f->GetDirectory(dirName);
103+
if (!gDir) {
104+
std::printf("directory %s not found in %s\n", dirName, fileName);
105+
return;
106+
}
107+
108+
auto* hBcCounter = getHist<TH1>("hBcCounter");
109+
auto* hNumCollsInBC = getHist<TH1>("hNumCollsInBC");
110+
auto* hBcInTF = getHist<TH1>("hBcInTF");
111+
auto* hBcInTFDefined = getHist<TH1>("hBcInTFOccupancyDefined");
112+
auto* hOccTracks = getHist<TH1>("hOccupancyByTracks");
113+
auto* hOccFT0C = getHist<TH1>("hOccupancyByFT0C");
114+
auto* hOccTracksVsFT0C = getHist<TH2>("hOccupancyByTracksVsFT0C");
115+
auto* hMedianTime = getHist<TH1>("hMedianTime");
116+
auto* pOccVsBcInTF = getHist<TProfile>("pOccupancyByTracksVsBcInTF");
117+
auto* pOccVsBcInOrbit = getHist<TProfile>("pOccupancyByTracksVsBcInOrbit");
118+
auto* hFlags = getHist<TH1>("hOccupancyFlags");
119+
auto* hFlagsVsOcc = getHist<TH2>("hOccupancyFlagsVsOccupancyByTracks");
120+
auto* hBcIndexCheck = getHist<TH1>("hBcIndexCheck");
121+
122+
// ### summary
123+
std::printf("\n=== BC occupancy QA: %s ===\n", fileName);
124+
if (hBcCounter) {
125+
double nAll = hBcCounter->GetBinContent(1), nDef = hBcCounter->GetBinContent(2);
126+
std::printf("BCs: %.0f, with calculated occupancy: %.0f (%.2f%%)\n", nAll, nDef, nAll > 0 ? 100. * nDef / nAll : 0.);
127+
}
128+
if (hOccTracks && hOccFT0C) {
129+
std::printf("mean occupancy: by ITS tracks %.1f, by FT0C %.1f\n", hOccTracks->GetMean(), hOccFT0C->GetMean());
130+
}
131+
if (hNumCollsInBC) {
132+
double nAll = hNumCollsInBC->GetEntries();
133+
std::printf("BCs with >= 1 collision: %.4f%%, with >= 2 collisions: %.4f%%\n",
134+
nAll > 0 ? 100. * hNumCollsInBC->Integral(hNumCollsInBC->FindBin(1), hNumCollsInBC->GetNbinsX() + 1) / nAll : 0.,
135+
nAll > 0 ? 100. * hNumCollsInBC->Integral(hNumCollsInBC->FindBin(2), hNumCollsInBC->GetNbinsX() + 1) / nAll : 0.);
136+
}
137+
if (hFlags && hFlags->GetBinContent(1) > 0) {
138+
std::printf("fraction of BCs (with calculated occupancy) passing each flag:\n");
139+
for (int i = 2; i <= hFlags->GetNbinsX(); i++) {
140+
std::printf(" %-28s %.4f\n", hFlags->GetXaxis()->GetBinLabel(i), hFlags->GetBinContent(i) / hFlags->GetBinContent(1));
141+
}
142+
}
143+
144+
if (hBcIndexCheck) {
145+
// all rows and all found BCs should be found at the right place
146+
const bool ok = hBcIndexCheck->GetBinContent(2) == hBcIndexCheck->GetBinContent(1) && hBcIndexCheck->GetBinContent(5) == hBcIndexCheck->GetBinContent(4);
147+
std::printf("lookup by global BC (BcOccAllIndex): rows found %.0f / %.0f, BCs of aod::BCs found %.0f / %.0f (not found %.0f), with the same global BC %.0f -> %s\n",
148+
hBcIndexCheck->GetBinContent(2), hBcIndexCheck->GetBinContent(1), hBcIndexCheck->GetBinContent(4), hBcIndexCheck->GetBinContent(3),
149+
hBcIndexCheck->GetBinContent(6), hBcIndexCheck->GetBinContent(5), ok ? "OK" : "MISMATCH");
150+
}
151+
152+
// ### plots
153+
const double maxOccTracks = hOccTracks ? upperEdgeOfFilledRange(hOccTracks) : 0.;
154+
const double maxOccFT0C = hOccFT0C ? upperEdgeOfFilledRange(hOccFT0C) : 0.;
155+
TCanvas c("c", "BC occupancy QA", 1200, 800);
156+
c.Print(Form("%s[", outPdf));
157+
auto newPage = [&c](int nx, int ny) {
158+
c.Clear();
159+
c.Divide(nx, ny);
160+
};
161+
162+
// page 1: BC counters and the cross-check of the lookup by global BC
163+
newPage(3, 1);
164+
if (hBcCounter) {
165+
c.cd(1)->SetLeftMargin(0.15);
166+
hBcCounter->SetTitle("number of BCs");
167+
hBcCounter->Draw("hist text");
168+
}
169+
if (hNumCollsInBC) {
170+
c.cd(2)->SetLogy();
171+
hNumCollsInBC->SetTitle("all BCs;number of collisions found in the BC;N BCs");
172+
hNumCollsInBC->Draw("hist");
173+
}
174+
if (hBcIndexCheck) {
175+
c.cd(3)->SetBottomMargin(0.3);
176+
c.cd(3)->SetLogy(); // rows of BcOccsAll vs (much fewer) BCs of aod::BCs
177+
hBcIndexCheck->SetTitle("lookup in BcOccsAll by global BC;;counts");
178+
hBcIndexCheck->GetXaxis()->LabelsOption("v");
179+
hBcIndexCheck->SetMinimum(0.5);
180+
hBcIndexCheck->Draw("hist text");
181+
}
182+
c.Print(outPdf);
183+
184+
// page 2: occupancy distributions
185+
newPage(2, 2);
186+
if (hOccTracks) {
187+
c.cd(1)->SetLogy();
188+
hOccTracks->SetTitle("occupancy by ITS tracks;occupancy by ITS tracks;N BCs");
189+
hOccTracks->GetXaxis()->SetRangeUser(0., maxOccTracks);
190+
hOccTracks->Draw("hist");
191+
}
192+
if (hOccFT0C) {
193+
c.cd(2)->SetLogy();
194+
hOccFT0C->SetTitle("occupancy by FT0C;occupancy by FT0C amplitudes;N BCs");
195+
hOccFT0C->GetXaxis()->SetRangeUser(0., maxOccFT0C);
196+
hOccFT0C->Draw("hist");
197+
}
198+
if (hOccTracksVsFT0C) {
199+
c.cd(3)->SetLogz();
200+
hOccTracksVsFT0C->SetTitle("occupancy: ITS tracks vs FT0C;occupancy by FT0C amplitudes;occupancy by ITS tracks");
201+
hOccTracksVsFT0C->GetXaxis()->SetRangeUser(0., maxOccFT0C);
202+
hOccTracksVsFT0C->GetYaxis()->SetRangeUser(0., maxOccTracks);
203+
hOccTracksVsFT0C->Draw("colz");
204+
}
205+
if (hMedianTime) {
206+
c.cd(4)->SetLogy();
207+
hMedianTime->SetTitle("median time of the occupancy;#Deltat (#mus);N BCs");
208+
hMedianTime->Draw("hist");
209+
}
210+
c.Print(outPdf);
211+
212+
// page 3: occupancy flags
213+
newPage(2, 1);
214+
if (hFlags && hFlags->GetBinContent(1) > 0) {
215+
c.cd(1)->SetBottomMargin(0.3);
216+
auto* hFlagsFrac = static_cast<TH1*>(hFlags->Clone("hFlagsFrac"));
217+
hFlagsFrac->Scale(1. / hFlags->GetBinContent(1));
218+
hFlagsFrac->SetTitle("fraction of BCs passing each flag;;fraction of BCs");
219+
hFlagsFrac->GetXaxis()->LabelsOption("v");
220+
hFlagsFrac->SetMinimum(0.);
221+
hFlagsFrac->SetMaximum(1.1);
222+
hFlagsFrac->Draw("hist text");
223+
}
224+
if (hFlagsVsOcc) {
225+
// fraction of BCs passing each flag vs occupancy
226+
c.cd(2);
227+
TLegend* leg = new TLegend(0.45, 0.6, 0.89, 0.89);
228+
TH1D* hAll = hFlagsVsOcc->ProjectionY("hFlagsAll", 1, 1);
229+
const int colors[] = {kRed + 1, kOrange + 7, kGreen + 2, kAzure + 2, kBlue + 2, kMagenta + 1, kBlack};
230+
bool first = true;
231+
for (int i = 2; i <= hFlagsVsOcc->GetNbinsX(); i++) {
232+
TH1D* hPass = hFlagsVsOcc->ProjectionY(Form("hFlagPass%d", i), i, i);
233+
TH1D* hFrac = makeRatio(hPass, hAll, Form("hFlagFrac%d", i), "fraction of BCs passing the flags vs occupancy;occupancy by ITS tracks;fraction of BCs");
234+
hFrac->SetLineColor(colors[(i - 2) % 7]);
235+
hFrac->SetMarkerColor(colors[(i - 2) % 7]);
236+
hFrac->SetMarkerStyle(20);
237+
hFrac->SetMarkerSize(0.4);
238+
hFrac->SetMinimum(0.);
239+
hFrac->SetMaximum(1.1);
240+
hFrac->GetXaxis()->SetRangeUser(0., maxOccTracks);
241+
hFrac->Draw(first ? "p" : "p same");
242+
leg->AddEntry(hFrac, hFlagsVsOcc->GetXaxis()->GetBinLabel(i), "p");
243+
first = false;
244+
}
245+
leg->Draw();
246+
}
247+
c.Print(outPdf);
248+
249+
// page 4: BC position in the TF and in the orbit
250+
newPage(1, 3);
251+
if (hBcInTF && hBcInTFDefined) {
252+
c.cd(1);
253+
TH1D* hFracDefined = makeRatio(hBcInTFDefined, hBcInTF, "hFracDefined", "fraction of BCs with calculated occupancy;BC in TF;fraction");
254+
hFracDefined->SetMinimum(0.);
255+
hFracDefined->SetMaximum(1.1);
256+
hFracDefined->Draw("hist");
257+
}
258+
if (pOccVsBcInTF) {
259+
c.cd(2);
260+
pOccVsBcInTF->SetTitle("mean occupancy vs BC in TF;BC in TF;mean occupancy by ITS tracks");
261+
pOccVsBcInTF->Draw();
262+
}
263+
if (pOccVsBcInOrbit) {
264+
c.cd(3);
265+
pOccVsBcInOrbit->SetTitle("mean occupancy vs BC in orbit;BC in orbit;mean occupancy by ITS tracks");
266+
pOccVsBcInOrbit->Draw("hist"); // 3564 bins: error bars would hide the pattern
267+
}
268+
c.Print(outPdf);
269+
270+
c.Print(Form("%s]", outPdf));
271+
std::printf("plots saved in %s\n", outPdf);
272+
}

0 commit comments

Comments
 (0)