|
| 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