Project
Loading...
Searching...
No Matches
Tracker.cxx
Go to the documentation of this file.
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.
15
16#include "ITStracking/Tracker.h"
21
22#include <cassert>
23#include <algorithm>
24#include <limits>
25#include <format>
26#include <cstdlib>
27#include <string>
28
29namespace o2::its
30{
32
33template <int NLayers>
35{
36}
37
38template <int NLayers>
39float Tracker<NLayers>::clustersToVertices(const LogFunc& logger)
40{
41 mTraits->updateTrackingParameters(mTrkParams);
42 // The seeding-vertex passes are prepended to mTrkParams so they occupy [0, nSeedingPasses)
43 int nSeedingPasses{0};
44 while (nSeedingPasses < (int)mTrkParams.size() &&
45 mTrkParams[nSeedingPasses].PassFlags[IterationStep::SeedingVertexPass]) {
46 ++nSeedingPasses;
47 }
48 if (nSeedingPasses == 0) {
49 return 0.f;
50 }
51 logger(std::format("==== ITS {} Seeding-vertex pass ====", mTraits->getName()));
52 float total{0.f};
53 for (int it = 0; it < nSeedingPasses; ++it) {
54 mMemoryPool->setMaxMemory(mTrkParams[it].MaxMemory);
55 const bool refineBeam = it == 0 && !mTimeFrame->isBeamOverridden();
56 const int maxBootstrap = refineBeam ? constants::MaxBootstrapPasses : 1;
57 if (it > 0) {
58 ROFMaskTable<NLayers> upcMask{mTimeFrame->getROFOverlapTable()};
59 const auto& vtxLookup = mTimeFrame->getROFVertexLookupTableView();
60 const int threshold = mTrkParams[it].VertPerRofThreshold;
61 int nEnabled = 0, nTotal = 0;
62 for (int layer = 0; layer < NLayers; ++layer) {
63 const int nRofs = mTimeFrame->getROFOverlapTableView().getLayer(layer).mNROFsTF;
64 for (int rof = 0; rof < nRofs; ++rof) {
65 // Same predicate as skipROF(), applied earlier.
66 const bool empty = (int)vtxLookup.getVertices(layer, rof).getEntries() <= threshold;
67 upcMask.setROFEnabled(layer, rof, empty ? 1u : 0u);
68 if (layer == 1) {
69 nTotal++;
70 nEnabled += empty;
71 }
72 }
73 }
74 mTimeFrame->setSeedingUPCMask(std::move(upcMask));
75 mTimeFrame->useSeedingUPCMask();
76 logger(std::format(" - Seeding pass {}: UPC pass on {}/{} ROFs without vertices",
77 it, nEnabled, nTotal));
78 }
79 for (int pass = 0; pass < maxBootstrap; ++pass) {
80 const float prevBeamX = mTimeFrame->getBeamX();
81 const float prevBeamY = mTimeFrame->getBeamY();
82 total += evaluateTask(&Tracker::initialiseTimeFrame, StateNames[mCurStep = TFInit], it, logger, it);
83 total += evaluateTask(&Tracker::computeTracklets, StateNames[mCurStep = Trackleting], it, logger, it, -1);
84 const int nTracklets = mTraits->getTFNumberOfTracklets();
85 total += evaluateTask(&Tracker::computeCells, StateNames[mCurStep = Celling], it, logger, it);
86 total += evaluateTask(&Tracker::computeVertexCandidates, StateNames[mCurStep = CellLinearising], it, logger, it);
87 logger(std::format(" - Seeding pass {}.{}: {} tracklets, {} cells, {} lines", it, pass,
88 nTracklets, mTraits->getTFNumberOfCells(),
89 mTimeFrame->getNLinesTotal()));
90 total += evaluateTask(&Tracker::computeVertices, StateNames[mCurStep = SeedingVertices], it, logger, it);
91 if (!refineBeam) {
92 continue;
93 }
94 total += evaluateTask(&Tracker::computeBeamFromVertices, StateNames[mCurStep = BeamPositioning], it, logger, it);
95 const float dx = mTimeFrame->getBeamX() - prevBeamX;
96 const float dy = mTimeFrame->getBeamY() - prevBeamY;
97 if (dx * dx + dy * dy < constants::BeamConvergence2) {
98 logger(std::format(" - Beam bootstrap converged after pass {} (beam shift < 50 um)", pass));
99 break;
100 }
101 }
102 }
103 if (nSeedingPasses > 1) {
104 mTimeFrame->useMultiplictyMask();
105 }
106 return total;
107}
108
109template <int NLayers>
110float Tracker<NLayers>::clustersToTracks(const LogFunc& logger, const LogFunc& error)
111{
112 LogFunc evalLog = [](const std::string&) {};
113
114 float total{0};
115 mTraits->updateTrackingParameters(mTrkParams);
116
117 int maxNvertices{-1};
118 int firstTrackingIteration{0};
119 while (firstTrackingIteration < (int)mTrkParams.size() &&
120 mTrkParams[firstTrackingIteration].PassFlags[IterationStep::SeedingVertexPass]) {
121 ++firstTrackingIteration;
122 }
123 if (firstTrackingIteration < (int)mTrkParams.size() && mTrkParams[firstTrackingIteration].PerPrimaryVertexProcessing) {
124 maxNvertices = mTimeFrame->getROFVertexLookupTableView().getMaxVerticesPerROF();
125 }
126
127 int iteration{firstTrackingIteration}, iVertex{0};
128 auto handleException = [&](const auto& err) {
129 if (mTrkParams[iteration].MaxMemory == std::numeric_limits<size_t>::max()) {
130 LOGP(error, "Allocation failed in {} in iteration {} iVtx={} ({:.2f} GB of host artefacts, no host limit set), check the detector status and/or the selections.",
131 StateNames[mCurStep], iteration, iVertex,
132 (double)mTimeFrame->getArtefactsMemory() / GB);
133 } else {
134 LOGP(error, "Too much memory in {} in iteration {} iVtx={}: {:.2f} GB. Current limit is {:.2f} GB, check the detector status and/or the selections.",
135 StateNames[mCurStep], iteration, iVertex,
136 (double)mTimeFrame->getArtefactsMemory() / GB,
137 (double)mTrkParams[iteration].MaxMemory / GB);
138 }
139 if (typeid(err) != typeid(std::bad_alloc)) { // only print if the exceptions is different from what is expected
140 LOGP(error, "Exception: {}", err.what());
141 }
142 if (mTrkParams[iteration].DropTFUponFailure) {
143 mMemoryPool->print();
144 mTimeFrame->wipe();
145 mTimeFrame->getCapacityEstimator().reset();
146 ++mNumberOfDroppedTFs;
147 error(std::format("...Dropping TimeSlice {} (out of {} dropped {})...", mTimeSlice, mTimeFrameCounter, mNumberOfDroppedTFs));
148 } else {
149 throw err;
150 }
151 };
152
153 try {
154 for (iteration = firstTrackingIteration; iteration < (int)mTrkParams.size(); ++iteration) {
155 mMemoryPool->setMaxMemory(mTrkParams[iteration].MaxMemory);
156 if (mTrkParams[iteration].PassFlags[IterationStep::UseUPCMask]) {
157 mTimeFrame->useUPCMask();
158 }
159 float timeFrame{0.}, timeTracklets{0.}, timeCells{0.}, timeNeighbours{0.}, timeRoads{0.};
160 size_t nTracklets{0}, nCells{0}, nNeighbours{0};
161 int nTracks{-static_cast<int>(mTimeFrame->getNumberOfTracks())};
162 iVertex = std::min(maxNvertices, 0);
163 logger(std::format("==== ITS {} Tracking iteration {} summary ====", mTraits->getName(), iteration));
164 total += timeFrame = evaluateTask(&Tracker::initialiseTimeFrame, StateNames[mCurStep = TFInit], iteration, evalLog, iteration);
165 logger(std::format(" - TimeFrame initialisation completed in {:.2f} ms", timeFrame));
166 do {
167 timeTracklets += evaluateTask(&Tracker::computeTracklets, StateNames[mCurStep = Trackleting], iteration, evalLog, iteration, iVertex);
168 nTracklets += mTraits->getTFNumberOfTracklets();
169 timeCells += evaluateTask(&Tracker::computeCells, StateNames[mCurStep = Celling], iteration, evalLog, iteration);
170 nCells += mTraits->getTFNumberOfCells();
171 timeNeighbours += evaluateTask(&Tracker::findCellsNeighbours, StateNames[mCurStep = Neighbouring], iteration, evalLog, iteration);
172 nNeighbours += mTimeFrame->getNumberOfNeighbours();
173 timeRoads += evaluateTask(&Tracker::findRoads, StateNames[mCurStep = Roading], iteration, evalLog, iteration);
174 } while (++iVertex < maxNvertices);
175 logger(std::format(" - Tracklet finding: {} tracklets found in {:.2f} ms", nTracklets, timeTracklets));
176 logger(std::format(" - Cell finding: {} cells found in {:.2f} ms", nCells, timeCells));
177 logger(std::format(" - Neighbours finding: {} neighbours found in {:.2f} ms", nNeighbours, timeNeighbours));
178 logger(std::format(" - Track finding: {} tracks found in {:.2f} ms", nTracks + mTimeFrame->getNumberOfTracks(), timeRoads));
179 if (mTrkParams[iteration].PassFlags[IterationStep::TrackFollowerTop] || mTrkParams[iteration].PassFlags[IterationStep::TrackFollowerBot]) {
180 logger(std::format(" - Integrated track extension: {} tracks accepted using {} clusters", mTimeFrame->getNExtendedTracks(), mTimeFrame->getNExtendedClusters()));
181 }
182 total += timeTracklets + timeCells + timeNeighbours + timeRoads;
183 }
184 } catch (const BoundedMemoryResource::MemoryLimitExceeded& err) {
185 handleException(err);
186 return -1.f;
187 } catch (const std::bad_alloc& err) {
188 handleException(err);
189 return -1.f;
190 } catch (const std::exception& err) {
191 error(std::format("Uncaught exception, all bets are off... {}", err.what()));
192 // clear tracks explicitly since if not fatalising on exception this may contain partial output
193 mTimeFrame->getTracks().clear();
194 return -1.f;
195 }
196
197 if (mTimeFrame->hasMCinformation()) {
198 computeTracksMClabels();
199 }
200 rectifyClusterIndices();
201 sortTracks();
202
203 ++mTimeFrameCounter;
204 mTotalTime += total;
205
206 return total;
207}
208
209template <int NLayers>
211{
212 for (auto& track : mTimeFrame->getTracks()) {
213 std::vector<std::pair<MCCompLabel, size_t>> occurrences;
214 occurrences.clear();
215
216 for (int iCluster = 0; iCluster < TrackITSExt::MaxClusters; ++iCluster) {
217 const int index = track.getClusterIndex(iCluster);
219 continue;
220 }
221 auto labels = mTimeFrame->getClusterLabels(iCluster, index);
222 bool found{false};
223 for (size_t iOcc{0}; iOcc < occurrences.size(); ++iOcc) {
224 std::pair<o2::MCCompLabel, size_t>& occurrence = occurrences[iOcc];
225 for (const auto& label : labels) {
226 if (label == occurrence.first) {
227 ++occurrence.second;
228 found = true;
229 // break; // uncomment to stop to the first hit
230 }
231 }
232 }
233 if (!found) {
234 for (const auto& label : labels) {
235 occurrences.emplace_back(label, 1);
236 }
237 }
238 }
239 std::sort(std::begin(occurrences), std::end(occurrences), [](auto e1, auto e2) {
240 return e1.second > e2.second;
241 });
242
243 auto maxOccurrencesValue = occurrences[0].first;
244 uint32_t pattern = track.getPattern();
245 // set fake clusters pattern
246 for (int ic{TrackITSExt::MaxClusters}; ic--;) {
247 auto clid = track.getClusterIndex(ic);
248 if (clid != constants::UnusedIndex) {
249 auto labelsSpan = mTimeFrame->getClusterLabels(ic, clid);
250 for (const auto& currentLabel : labelsSpan) {
251 if (currentLabel == maxOccurrencesValue) {
252 pattern |= 0x1 << (16 + ic); // set bit if correct
253 break;
254 }
255 }
256 }
257 }
258 track.setPattern(pattern);
259 if (occurrences[0].second < track.getNumberOfClusters()) {
260 maxOccurrencesValue.setFakeFlag();
261 }
262 mTimeFrame->getTracksLabel().emplace_back(maxOccurrencesValue);
263 }
264}
265
266template <int NLayers>
268{
269 for (auto& track : mTimeFrame->getTracks()) {
270 for (int iCluster = 0; iCluster < TrackITSExt::MaxClusters; ++iCluster) {
271 const int index = track.getClusterIndex(iCluster);
273 track.setExternalClusterIndex(iCluster, mTimeFrame->getClusterExternalIndex(iCluster, index));
274 }
275 }
276 }
277}
278
279template <int NLayers>
280void Tracker<NLayers>::sortTracks()
281{
282 auto& trks = mTimeFrame->getTracks();
283 bounded_vector<size_t> indices(trks.size(), mMemoryPool.get());
284 std::iota(indices.begin(), indices.end(), 0);
285 std::sort(indices.begin(), indices.end(), [&trks](size_t i, size_t j) {
286 // provide tracks sorted by lower-bound
287 const auto& a = trks[i];
288 const auto& b = trks[j];
289 const auto aLower = a.getTimeStamp().getTimeStamp() - a.getTimeStamp().getTimeStampError();
290 const auto bLower = b.getTimeStamp().getTimeStamp() - b.getTimeStamp().getTimeStampError();
291 if (aLower != bLower) {
292 return aLower < bLower;
293 }
294 return a.isBetter(b, 1e9); // then sort tracks in quality
295 });
296 bounded_vector<TrackITSExt> sortedTrks(mMemoryPool.get());
297 sortedTrks.reserve(trks.size());
298 for (size_t idx : indices) {
299 sortedTrks.push_back(trks[idx]);
300 }
301 trks.swap(sortedTrks);
302 if (mTimeFrame->hasMCinformation()) {
303 auto& trksLabels = mTimeFrame->getTracksLabel();
304 bounded_vector<MCCompLabel> sortedLabels(mMemoryPool.get());
305 sortedLabels.reserve(trksLabels.size());
306 for (size_t idx : indices) {
307 sortedLabels.push_back(trksLabels[idx]);
308 }
309 trksLabels.swap(sortedLabels);
310 }
311}
312
313template <int NLayers>
315{
316 mTimeFrame = &tf;
317 mTraits->adoptTimeFrame(&tf);
318}
319
320template <int NLayers>
321void Tracker<NLayers>::addTimingStatCurStep(int iteration, double timeMs)
322{
323 if (iteration < 0) {
324 return;
325 }
326 if (mTimingStats.size() < (iteration + 1)) {
327 mTimingStats.resize(iteration + 1);
328 }
329 mTimingStats[iteration][mCurStep].add(timeMs);
330}
331
332template <int NLayers>
334{
335 auto avgTF = mTotalTime * 1.e-3 / ((mTimeFrameCounter > 0) ? (double)mTimeFrameCounter : -1.0);
336 auto avgTFwithDropped = mTotalTime * 1.e-3 / (((mTimeFrameCounter + mNumberOfDroppedTFs) > 0) ? (double)(mTimeFrameCounter + mNumberOfDroppedTFs) : -1.0);
337 LOGP(info, "Tracker summary: Processed {} TFs (dropped {}) in TOT={:.2f} s, AVG/TF={:.2f} ({:.2f}) s", mTimeFrameCounter, mNumberOfDroppedTFs, mTotalTime * 1.e-3, avgTF, avgTFwithDropped);
338 for (size_t iteration = 0; iteration < mTimingStats.size(); ++iteration) {
339 for (size_t state = 0; state < NSteps; ++state) {
340 const auto& stats = mTimingStats[iteration][state];
341 if (!stats.calls) {
342 continue;
343 }
344 LOGP(info, " - iter {} {}: calls={} total={:.2f} ms avg={:.2f} ms", iteration, StateNames[state], stats.calls, stats.totalTimeMs, stats.averageTimeMs());
345 }
346 }
347}
348
349template class Tracker<7>;
350// ALICE3 upgrade
351#ifdef ENABLE_UPGRADES
352template class Tracker<11>;
353template class Tracker<13>;
354#endif
355
356} // namespace o2::its
int32_t i
#define GB
Definition Utils.h:40
SurfaceTrackState state
std::vector< o2::MCCompLabel > labels
uint32_t j
Definition RawData.h:0
static constexpr int MaxClusters
< heavy version of TrackITS, with clusters embedded
Definition TrackITS.h:207
Tracker(TrackerTraits< NLayers > *traits)
Definition Tracker.cxx:34
void adoptTimeFrame(TimeFrame< NLayers > &tf)
Definition Tracker.cxx:314
void computeTracksMClabels()
Definition Tracker.cxx:210
float clustersToTracks(const LogFunc &=[](const std::string &s) { std::cout<< s<< '\n';}, const LogFunc &=[](const std::string &s) { std::cerr<< s<< '\n';})
Definition Tracker.cxx:110
float clustersToVertices(const LogFunc &=[](const std::string &s) { std::cout<< s<< '\n';})
Definition Tracker.cxx:39
GLuint index
Definition glcorearb.h:781
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
GLuint GLsizei const GLchar * label
Definition glcorearb.h:2519
GLsizei GLenum const void * indices
Definition glcorearb.h:400
GLenum GLuint GLint GLint layer
Definition glcorearb.h:1310
GLboolean GLboolean GLboolean GLboolean a
Definition glcorearb.h:1233
constexpr int UnusedIndex
Definition Constants.h:32
constexpr int MaxBootstrapPasses
Definition Constants.h:44
constexpr float GB
Definition Constants.h:27
constexpr float BeamConvergence2
Definition Constants.h:45
const bool const int TrackITSInternal< NLayers > & track
void empty(int)
std::unique_ptr< GPUReconstructionTimeframe > tf
std::array< uint16_t, 5 > pattern