Skip to content

Commit 369a7bb

Browse files
committed
Add macro to check bandwidth for MLOT
1 parent 74f7f81 commit 369a7bb

File tree

2 files changed

+311
-0
lines changed

2 files changed

+311
-0
lines changed

Detectors/Upgrades/ALICE3/TRK/macros/test/CMakeLists.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,18 @@
99
# granted to it by virtue of its status as an Intergovernmental Organization
1010
# or submit itself to any jurisdiction.
1111

12+
13+
o2_add_test_root_macro(CheckBandwidth.C
14+
PUBLIC_LINK_LIBRARIES O2::ITSMFTBase
15+
O2::ITSMFTSimulation
16+
O2::TRKBase
17+
O2::TRKSimulation
18+
O2::MathUtils
19+
O2::SimulationDataFormat
20+
O2::DetectorsBase
21+
O2::Steer
22+
LABELS trk COMPILE_ONLY)
23+
1224
o2_add_test_root_macro(CheckDigits.C
1325
PUBLIC_LINK_LIBRARIES O2::ITSMFTBase
1426
O2::ITSMFTSimulation
Lines changed: 299 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,299 @@
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

Comments
 (0)