|
| 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 CheckDigits.C |
| 13 | +/// \brief Simple macro to check TRK digits |
| 14 | + |
| 15 | +#if !defined(__CLING__) || defined(__ROOTCLING__) |
| 16 | +#include <algorithm> |
| 17 | +#include <cmath> |
| 18 | +#include <map> |
| 19 | +#include <TCanvas.h> |
| 20 | +#include <TFile.h> |
| 21 | +#include <TH1D.h> |
| 22 | +#include <TH2F.h> |
| 23 | +#include <TLatex.h> |
| 24 | +#include <TString.h> |
| 25 | +#include <TTree.h> |
| 26 | +#include <TStyle.h> |
| 27 | + |
| 28 | +#include "TRKBase/GeometryTGeo.h" |
| 29 | +#include "DataFormatsITSMFT/Digit.h" |
| 30 | +#include "MathUtils/Utils.h" |
| 31 | +#include "DetectorsBase/GeometryManager.h" |
| 32 | + |
| 33 | +#include "DataFormatsITSMFT/ROFRecord.h" |
| 34 | +#include "CommonDataFormat/InteractionRecord.h" |
| 35 | +#include "SimulationDataFormat/DigitizationContext.h" |
| 36 | + |
| 37 | +#endif |
| 38 | + |
| 39 | +namespace |
| 40 | +{ |
| 41 | +constexpr double DigitBits = 16.; |
| 42 | +constexpr double BunchCrossingNS = 25.; |
| 43 | +constexpr int ReadoutCycleBC = 18; |
| 44 | +constexpr int ReadoutCycleSimBC = 18; |
| 45 | +constexpr double ReadoutCycleSeconds = ReadoutCycleBC * BunchCrossingNS * 1.e-9; |
| 46 | +} // namespace |
| 47 | + |
| 48 | +void CheckBandwidth(std::string digifile = "trkdigits.root", std::string inputGeom = "o2sim_geometry.root", std::string collContextFile = "collisioncontext.root") |
| 49 | +{ |
| 50 | + gStyle->SetPalette(55); |
| 51 | + gStyle->SetOptStat(0); |
| 52 | + |
| 53 | + auto drawSummary = [](double averageValue, double peakValue, const char* unit) { |
| 54 | + TLatex latex; |
| 55 | + latex.SetNDC(); |
| 56 | + latex.SetTextSize(0.03); |
| 57 | + latex.SetTextAlign(13); |
| 58 | + latex.DrawLatex(0.04, 0.05, Form("avg: %.3f %s", averageValue, unit)); |
| 59 | + latex.DrawLatex(0.34, 0.05, Form("peak: %.3f %s", peakValue, unit)); |
| 60 | + }; |
| 61 | + |
| 62 | + auto drawCollisionSummary = [](double averageValue, double nonEmptyAverageValue, double peakValue) { |
| 63 | + TLatex latex; |
| 64 | + latex.SetNDC(); |
| 65 | + latex.SetTextSize(0.03); |
| 66 | + latex.SetTextAlign(13); |
| 67 | + latex.DrawLatex(0.04, 0.025, Form("avg: %.3f collisions/ROF", averageValue)); |
| 68 | + latex.DrawLatex(0.42, 0.025, Form("peak: %.3f collisions/ROF", peakValue)); |
| 69 | + latex.DrawLatex(0.04, 0.06, Form("avg non-empty: %.3f collisions/ROF", nonEmptyAverageValue)); |
| 70 | + }; |
| 71 | + |
| 72 | + using namespace o2::base; |
| 73 | + using namespace o2::trk; |
| 74 | + |
| 75 | + TFile* f = TFile::Open("CheckBandwidth.root", "recreate"); |
| 76 | + |
| 77 | + // Geometry |
| 78 | + o2::base::GeometryManager::loadGeometry(inputGeom); |
| 79 | + auto* gman = o2::trk::GeometryTGeo::Instance(); |
| 80 | + gman->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::L2G)); |
| 81 | + |
| 82 | + // Collision Context |
| 83 | + TFile* ccFile = TFile::Open(collContextFile.data()); |
| 84 | + auto* digiContext = (o2::steer::DigitizationContext*)ccFile->Get("DigitizationContext"); |
| 85 | + const o2::InteractionRecord firstSampledIR{0, digiContext->getFirstOrbitForSampling()}; |
| 86 | + std::vector<unsigned int> collisionsPerROF; |
| 87 | + |
| 88 | + for (const auto& record : digiContext->getEventRecords()) { |
| 89 | + auto nbc = record.differenceInBC(firstSampledIR); |
| 90 | + if (record.getTimeOffsetWrtBC() < 0. && nbc > 0) { |
| 91 | + --nbc; |
| 92 | + } |
| 93 | + if (nbc < 0) { |
| 94 | + continue; |
| 95 | + } |
| 96 | + |
| 97 | + const size_t rofID = nbc / ReadoutCycleSimBC; |
| 98 | + if (rofID >= collisionsPerROF.size()) { |
| 99 | + collisionsPerROF.resize(rofID + 1, 0u); |
| 100 | + } |
| 101 | + ++collisionsPerROF[rofID]; |
| 102 | + } |
| 103 | + |
| 104 | + // Digits |
| 105 | + TFile* digFile = TFile::Open(digifile.data()); |
| 106 | + TTree* digTree = (TTree*)digFile->Get("o2sim"); |
| 107 | + const int nDigitTreeEntries = digTree->GetEntries(); |
| 108 | + |
| 109 | + std::vector<o2::itsmft::Digit>* digArr = nullptr; |
| 110 | + digTree->SetBranchAddress("TRKDigit", &digArr); |
| 111 | + |
| 112 | + // Get Read Out Frame arrays |
| 113 | + std::vector<o2::itsmft::ROFRecord>* ROFRecordArrray = nullptr; |
| 114 | + digTree->SetBranchAddress("TRKDigitROF", &ROFRecordArrray); |
| 115 | + std::vector<o2::itsmft::ROFRecord>& ROFRecordArrrayRef = *ROFRecordArrray; |
| 116 | + |
| 117 | + digTree->GetEntry(0); |
| 118 | + |
| 119 | + if (nDigitTreeEntries > 1) { |
| 120 | + LOG(warning) << "Digit tree has " << nDigitTreeEntries << " entries, but this macro processes entry 0 only."; |
| 121 | + } |
| 122 | + |
| 123 | + std::vector<unsigned long long> digitsPerChip(gman->getNumberOfChips(), 0ull); |
| 124 | + std::vector<unsigned int> maxDigitsPerROFPerChip(gman->getNumberOfChips(), 0u); |
| 125 | + std::vector<unsigned int> digitsInCurrentROFPerChip(gman->getNumberOfChips(), 0u); |
| 126 | + |
| 127 | + const int nROFRec = (int)ROFRecordArrrayRef.size(); |
| 128 | + const int nCollisionROFBins = std::max(nROFRec, static_cast<int>(collisionsPerROF.size())); |
| 129 | + |
| 130 | + if (nCollisionROFBins > 0) { |
| 131 | + auto* hCollisionsPerROF = new TH1D("h_collisions_per_rof", "Collisions per ROF;ROF id;N collisions", nCollisionROFBins, -0.5, nCollisionROFBins - 0.5); |
| 132 | + double totalCollisionsPerROF = 0.; |
| 133 | + double peakCollisionsPerROF = 0.; |
| 134 | + int nNonEmptyROFs = 0; |
| 135 | + |
| 136 | + for (int rofID = 0; rofID < nCollisionROFBins; ++rofID) { |
| 137 | + const double nCollisions = rofID < static_cast<int>(collisionsPerROF.size()) ? collisionsPerROF[rofID] : 0.; |
| 138 | + hCollisionsPerROF->SetBinContent(rofID + 1, nCollisions); |
| 139 | + totalCollisionsPerROF += nCollisions; |
| 140 | + peakCollisionsPerROF = std::max(peakCollisionsPerROF, nCollisions); |
| 141 | + if (nCollisions > 0.) { |
| 142 | + ++nNonEmptyROFs; |
| 143 | + } |
| 144 | + } |
| 145 | + |
| 146 | + auto* canvCollisionsPerROF = new TCanvas("canvCollisionsPerROF", "Collisions per ROF", 1050, 1050); |
| 147 | + canvCollisionsPerROF->SetTopMargin(0.08); |
| 148 | + hCollisionsPerROF->Draw("hist"); |
| 149 | + drawCollisionSummary(totalCollisionsPerROF / nCollisionROFBins, |
| 150 | + nNonEmptyROFs > 0 ? totalCollisionsPerROF / nNonEmptyROFs : 0., |
| 151 | + peakCollisionsPerROF); |
| 152 | + canvCollisionsPerROF->SaveAs("trk_collisions_per_rof.png"); |
| 153 | + } |
| 154 | + |
| 155 | + unsigned int rofIndex = 0; |
| 156 | + unsigned int rofNEntries = 0; |
| 157 | + |
| 158 | + // LOOP on : ROFRecord array |
| 159 | + for (unsigned int iROF = 0; iROF < ROFRecordArrrayRef.size(); iROF++) { |
| 160 | + std::vector<int> touchedChips; |
| 161 | + |
| 162 | + rofIndex = ROFRecordArrrayRef[iROF].getFirstEntry(); |
| 163 | + rofNEntries = ROFRecordArrrayRef[iROF].getNEntries(); |
| 164 | + |
| 165 | + // LOOP on : digits array |
| 166 | + for (unsigned int iDigit = rofIndex; iDigit < rofIndex + rofNEntries; iDigit++) { |
| 167 | + if (iDigit % 1000 == 0) |
| 168 | + std::cout << "Reading digit " << iDigit << " / " << digArr->size() << std::endl; |
| 169 | + |
| 170 | + Int_t iDetID = (*digArr)[iDigit].getChipIndex(); |
| 171 | + Int_t disk = gman->getDisk(iDetID); |
| 172 | + Int_t subDetID = gman->getSubDetID(iDetID); |
| 173 | + |
| 174 | + if (subDetID == 1 && disk == -1) { |
| 175 | + if (digitsInCurrentROFPerChip[iDetID] == 0) { |
| 176 | + touchedChips.push_back(iDetID); |
| 177 | + } |
| 178 | + digitsPerChip[iDetID]++; |
| 179 | + ++digitsInCurrentROFPerChip[iDetID]; |
| 180 | + } |
| 181 | + |
| 182 | + } // end loop on digits array |
| 183 | + |
| 184 | + for (const auto chipID : touchedChips) { |
| 185 | + maxDigitsPerROFPerChip[chipID] = std::max(maxDigitsPerROFPerChip[chipID], digitsInCurrentROFPerChip[chipID]); |
| 186 | + digitsInCurrentROFPerChip[chipID] = 0; |
| 187 | + } |
| 188 | + |
| 189 | + } // end loop on ROFRecords array |
| 190 | + |
| 191 | + const double rofNorm = nROFRec > 0 ? 1. / nROFRec : 0.; |
| 192 | + const double bitsToMbps = ReadoutCycleSeconds > 0. ? DigitBits / ReadoutCycleSeconds / 1.e6 : 0.; |
| 193 | + const int nMLOTLayers = gman->getNumberOfLayersMLOT(); |
| 194 | + |
| 195 | + for (int layer = 0; layer < nMLOTLayers; ++layer) { |
| 196 | + int nStaves = gman->extractNumberOfStavesMLOT(layer); |
| 197 | + std::map<int, std::vector<std::pair<double, int>>> chipsPerStave; |
| 198 | + std::vector<int> sensorIdPerChip(gman->getNumberOfChips(), -1); |
| 199 | + int maxSensorsPerStave = 0; |
| 200 | + |
| 201 | + for (int chipID = 0; chipID < gman->getNumberOfChips(); ++chipID) { |
| 202 | + if (gman->getSubDetID(chipID) != 1 || gman->getLayer(chipID) != layer) { |
| 203 | + continue; |
| 204 | + } |
| 205 | + const int staveID = gman->getStave(chipID); |
| 206 | + const auto sensorCenter = gman->getMatrixL2G(chipID)(o2::math_utils::Point3D<float>(0.f, 0.f, 0.f)); |
| 207 | + chipsPerStave[staveID].push_back({sensorCenter.Z(), chipID}); |
| 208 | + } |
| 209 | + |
| 210 | + for (auto& [staveID, chips] : chipsPerStave) { |
| 211 | + std::sort(chips.begin(), chips.end(), [](const auto& left, const auto& right) { |
| 212 | + if (std::abs(left.first - right.first) > 1.e-4) { |
| 213 | + return left.first < right.first; |
| 214 | + } |
| 215 | + return left.second < right.second; |
| 216 | + }); |
| 217 | + |
| 218 | + for (size_t sensorIndex = 0; sensorIndex < chips.size(); ++sensorIndex) { |
| 219 | + sensorIdPerChip[chips[sensorIndex].second] = sensorIndex; |
| 220 | + } |
| 221 | + |
| 222 | + maxSensorsPerStave = std::max(maxSensorsPerStave, static_cast<int>(chips.size())); |
| 223 | + } |
| 224 | + |
| 225 | + if (maxSensorsPerStave == 0) { |
| 226 | + continue; |
| 227 | + } |
| 228 | + |
| 229 | + auto* hDigitsPerROF = new TH2F(Form("h_digits_per_rof_layer%d", layer), |
| 230 | + Form("Layer %d average digits per ROF;stave id;sensor id in stave;digits / ROF", layer), |
| 231 | + nStaves, -0.5, nStaves - 0.5, maxSensorsPerStave, -0.5, maxSensorsPerStave - 0.5); |
| 232 | + auto* hMaxDigitsPerROF = new TH2F(Form("h_max_digits_per_rof_layer%d", layer), |
| 233 | + Form("Layer %d max digits in one ROF;stave id;sensor id in stave;max digits / ROF", layer), |
| 234 | + nStaves, -0.5, nStaves - 0.5, maxSensorsPerStave, -0.5, maxSensorsPerStave - 0.5); |
| 235 | + auto* hBandwidth = new TH2F(Form("h_bandwidth_layer%d", layer), |
| 236 | + Form("Layer %d bandwidth map;stave id;sensor id in stave;bandwidth (Mbit/s)", layer), |
| 237 | + nStaves, -0.5, nStaves - 0.5, maxSensorsPerStave, -0.5, maxSensorsPerStave - 0.5); |
| 238 | + double totalAvgDigitsPerROF = 0.; |
| 239 | + double totalMaxDigitsPerROF = 0.; |
| 240 | + double totalBandwidthMbps = 0.; |
| 241 | + double peakAvgDigitsPerROF = 0.; |
| 242 | + double peakMaxDigitsPerROF = 0.; |
| 243 | + double peakBandwidthMbps = 0.; |
| 244 | + int nFilledSensors = 0; |
| 245 | + |
| 246 | + for (int chipID = 0; chipID < gman->getNumberOfChips(); ++chipID) { |
| 247 | + if (gman->getSubDetID(chipID) != 1 || gman->getLayer(chipID) != layer) { |
| 248 | + continue; |
| 249 | + } |
| 250 | + |
| 251 | + const int staveID = gman->getStave(chipID); |
| 252 | + const int sensorID = sensorIdPerChip[chipID]; |
| 253 | + const double avgDigitsPerROF = digitsPerChip[chipID] * rofNorm; |
| 254 | + const double maxDigitsPerROF = maxDigitsPerROFPerChip[chipID]; |
| 255 | + const double bandwidthMbps = avgDigitsPerROF * bitsToMbps; |
| 256 | + |
| 257 | + if (sensorID >= 0) { |
| 258 | + hDigitsPerROF->Fill(staveID, sensorID, avgDigitsPerROF); |
| 259 | + hMaxDigitsPerROF->Fill(staveID, sensorID, maxDigitsPerROF); |
| 260 | + hBandwidth->Fill(staveID, sensorID, bandwidthMbps); |
| 261 | + totalAvgDigitsPerROF += avgDigitsPerROF; |
| 262 | + totalMaxDigitsPerROF += maxDigitsPerROF; |
| 263 | + totalBandwidthMbps += bandwidthMbps; |
| 264 | + peakAvgDigitsPerROF = std::max(peakAvgDigitsPerROF, avgDigitsPerROF); |
| 265 | + peakMaxDigitsPerROF = std::max(peakMaxDigitsPerROF, maxDigitsPerROF); |
| 266 | + peakBandwidthMbps = std::max(peakBandwidthMbps, bandwidthMbps); |
| 267 | + ++nFilledSensors; |
| 268 | + } |
| 269 | + } |
| 270 | + |
| 271 | + auto* canvLayer = new TCanvas(Form("canvBandwidthLayer%d", layer), Form("Layer %d bandwidth", layer), 1050, 1050); |
| 272 | + canvLayer->SetTopMargin(0.08); |
| 273 | + canvLayer->SetRightMargin(0.18); |
| 274 | + const double avgDigitsPerROFLayer = nFilledSensors > 0 ? totalAvgDigitsPerROF / nFilledSensors : 0.; |
| 275 | + const double avgMaxDigitsPerROFLayer = nFilledSensors > 0 ? totalMaxDigitsPerROF / nFilledSensors : 0.; |
| 276 | + const double avgBandwidthMbps = nFilledSensors > 0 ? totalBandwidthMbps / nFilledSensors : 0.; |
| 277 | + hBandwidth->GetZaxis()->SetRangeUser(0., avgBandwidthMbps > 0. ? 3. * avgBandwidthMbps : 1.); |
| 278 | + hBandwidth->Draw("colz"); |
| 279 | + drawSummary(avgBandwidthMbps, peakBandwidthMbps, "Mbit/s"); |
| 280 | + canvLayer->SaveAs(Form("trk_layer%d_bandwidth_map.png", layer)); |
| 281 | + |
| 282 | + auto* canvLayerDigits = new TCanvas(Form("canvDigitsLayer%d", layer), Form("Layer %d digits per ROF", layer), 1050, 1050); |
| 283 | + canvLayerDigits->SetTopMargin(0.08); |
| 284 | + canvLayerDigits->SetRightMargin(0.18); |
| 285 | + hDigitsPerROF->Draw("colz"); |
| 286 | + drawSummary(avgDigitsPerROFLayer, peakAvgDigitsPerROF, "digits/ROF"); |
| 287 | + canvLayerDigits->SaveAs(Form("trk_layer%d_digits_per_rof_map.png", layer)); |
| 288 | + |
| 289 | + auto* canvLayerMaxDigits = new TCanvas(Form("canvMaxDigitsLayer%d", layer), Form("Layer %d max digits per ROF", layer), 1050, 1050); |
| 290 | + canvLayerMaxDigits->SetTopMargin(0.08); |
| 291 | + canvLayerMaxDigits->SetRightMargin(0.18); |
| 292 | + hMaxDigitsPerROF->Draw("colz"); |
| 293 | + drawSummary(avgMaxDigitsPerROFLayer, peakMaxDigitsPerROF, "digits/ROF"); |
| 294 | + canvLayerMaxDigits->SaveAs(Form("trk_layer%d_max_digits_per_rof_map.png", layer)); |
| 295 | + } |
| 296 | + |
| 297 | + f->Write(); |
| 298 | + f->Close(); |
| 299 | +} |
0 commit comments