Project
Loading...
Searching...
No Matches
TrackerTraits.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 <algorithm>
17#include <iterator>
18#include <ranges>
19#include <cmath>
20#include <type_traits>
21
22#include <oneapi/tbb/blocked_range.h>
23#include <oneapi/tbb/parallel_sort.h>
24
27#include "GPUCommonMath.h"
29#include "ITStracking/Cell.h"
37
38namespace o2::its
39{
40
41struct PassMode {
42 using OnePass = std::integral_constant<int, 0>;
43 using TwoPassCount = std::integral_constant<int, 1>;
44 using TwoPassInsert = std::integral_constant<int, 2>;
45};
46
47template <int NLayers>
48void TrackerTraits<NLayers>::computeLayerTracklets(const int iteration, int iVertex)
49{
50 for (int iLayer = 0; iLayer < mTrkParams[iteration].TrackletsPerRoad(); ++iLayer) {
51 mTimeFrame->getTracklets()[iLayer].clear();
52 mTimeFrame->getTrackletsLabel(iLayer).clear();
53 if (iLayer > 0) {
54 std::fill(mTimeFrame->getTrackletsLookupTable()[iLayer - 1].begin(), mTimeFrame->getTrackletsLookupTable()[iLayer - 1].end(), 0);
55 }
56 }
57
58 const Vertex diamondVert(mTrkParams[iteration].Diamond, mTrkParams[iteration].DiamondCov, 1, 1.f);
59 gsl::span<const Vertex> diamondSpan(&diamondVert, 1);
60
61 mTaskArena->execute([&] {
62 auto forTracklets = [&](auto Tag, int iLayer, int pivotROF, int base, int& offset) -> int {
63 if (!mTimeFrame->getROFMaskView().isROFEnabled(iLayer, pivotROF)) {
64 return 0;
65 }
66 gsl::span<const Vertex> primaryVertices = mTrkParams[iteration].UseDiamond ? diamondSpan : mTimeFrame->getPrimaryVertices(iLayer, pivotROF);
67 if (primaryVertices.empty()) {
68 return 0;
69 }
70 const int startVtx = iVertex >= 0 ? iVertex : 0;
71 const int endVtx = iVertex >= 0 ? o2::gpu::CAMath::Min(iVertex + 1, int(primaryVertices.size())) : int(primaryVertices.size());
72 if (endVtx <= startVtx || (iVertex + 1) > primaryVertices.size()) {
73 return 0;
74 }
75
76 // does this layer have any overlap with the next layer
77 const auto& rofOverlap = mTimeFrame->getROFOverlapTableView().getOverlap(iLayer, iLayer + 1, pivotROF);
78 if (!rofOverlap.getEntries()) {
79 return 0;
80 }
81
82 int localCount = 0;
83 auto& tracklets = mTimeFrame->getTracklets()[iLayer];
84 auto layer0 = mTimeFrame->getClustersOnLayer(pivotROF, iLayer);
85 if (layer0.empty()) {
86 return 0;
87 }
88
89 const float meanDeltaR = mTrkParams[iteration].LayerRadii[iLayer + 1] - mTrkParams[iteration].LayerRadii[iLayer];
90
91 for (int iCluster = 0; iCluster < int(layer0.size()); ++iCluster) {
92 const Cluster& currentCluster = layer0[iCluster];
93 const int currentSortedIndex = mTimeFrame->getSortedIndex(pivotROF, iLayer, iCluster);
94 if (mTimeFrame->isClusterUsed(iLayer, currentCluster.clusterId)) {
95 continue;
96 }
97 const float inverseR0 = 1.f / currentCluster.radius;
98
99 for (int iV = startVtx; iV < endVtx; ++iV) {
100 const auto& pv = primaryVertices[iV];
101 if (!mTimeFrame->getROFVertexLookupTableView().isVertexCompatible(iLayer, pivotROF, pv)) {
102 continue;
103 }
104 if ((pv.isFlagSet(Vertex::Flags::UPCMode) && iteration != 3) || (iteration == 3 && !pv.isFlagSet(Vertex::Flags::UPCMode))) {
105 continue;
106 }
107 const float resolution = o2::gpu::CAMath::Sqrt(math_utils::Sq(mTimeFrame->getPositionResolution(iLayer)) + math_utils::Sq(mTrkParams[iteration].PVres) / float(pv.getNContributors()));
108 const float tanLambda = (currentCluster.zCoordinate - pv.getZ()) * inverseR0;
109 const float zAtRmin = tanLambda * (mTimeFrame->getMinR(iLayer + 1) - currentCluster.radius) + currentCluster.zCoordinate;
110 const float zAtRmax = tanLambda * (mTimeFrame->getMaxR(iLayer + 1) - currentCluster.radius) + currentCluster.zCoordinate;
111 const float sqInvDeltaZ0 = 1.f / (math_utils::Sq(currentCluster.zCoordinate - pv.getZ()) + constants::Tolerance);
112 const float sigmaZ = o2::gpu::CAMath::Sqrt(
113 math_utils::Sq(resolution) * math_utils::Sq(tanLambda) * ((math_utils::Sq(inverseR0) + sqInvDeltaZ0) * math_utils::Sq(meanDeltaR) + 1.f) + math_utils::Sq(meanDeltaR * mTimeFrame->getMSangle(iLayer)));
114 const auto bins = o2::its::getBinsRect(currentCluster, iLayer + 1, zAtRmin, zAtRmax,
115 sigmaZ * mTrkParams[iteration].NSigmaCut, mTimeFrame->getPhiCut(iLayer),
116 mTimeFrame->getIndexTableUtils());
117 if (bins.x < 0) {
118 continue;
119 }
120 int phiBinsNum = bins.w - bins.y + 1;
121 if (phiBinsNum < 0) {
122 phiBinsNum += mTrkParams[iteration].PhiBins;
123 }
124
125 for (int targetROF = rofOverlap.getFirstEntry(); targetROF < rofOverlap.getEntriesBound(); ++targetROF) {
126 if (!mTimeFrame->getROFMaskView().isROFEnabled(iLayer + 1, targetROF)) {
127 continue;
128 }
129 auto layer1 = mTimeFrame->getClustersOnLayer(targetROF, iLayer + 1);
130 if (layer1.empty()) {
131 continue;
132 }
133 const auto ts = mTimeFrame->getROFOverlapTableView().getTimeStamp(iLayer, pivotROF, iLayer + 1, targetROF);
134 if (!ts.isCompatible(pv.getTimeStamp())) {
135 continue;
136 }
137 const auto& targetIndexTable = mTimeFrame->getIndexTable(targetROF, iLayer + 1);
138 const int zBinRange = (bins.z - bins.x) + 1;
139 for (int iPhi = 0; iPhi < phiBinsNum; ++iPhi) {
140 const int iPhiBin = (bins.y + iPhi) % mTrkParams[iteration].PhiBins;
141 const int firstBinIdx = mTimeFrame->getIndexTableUtils().getBinIndex(bins.x, iPhiBin);
142 const int maxBinIdx = firstBinIdx + zBinRange;
143 const int firstRow = targetIndexTable[firstBinIdx];
144 const int lastRow = targetIndexTable[maxBinIdx];
145 for (int iNext = firstRow; iNext < lastRow; ++iNext) {
146 if (iNext >= int(layer1.size())) {
147 break;
148 }
149 const Cluster& nextCluster = layer1[iNext];
150 if (mTimeFrame->isClusterUsed(iLayer + 1, nextCluster.clusterId)) {
151 continue;
152 }
153 const float deltaZ = o2::gpu::CAMath::Abs((tanLambda * (nextCluster.radius - currentCluster.radius)) + currentCluster.zCoordinate - nextCluster.zCoordinate);
154
155 if (deltaZ / sigmaZ < mTrkParams[iteration].NSigmaCut &&
156 math_utils::isPhiDifferenceBelow(currentCluster.phi, nextCluster.phi, mTimeFrame->getPhiCut(iLayer))) {
157 const float phi{o2::gpu::CAMath::ATan2(currentCluster.yCoordinate - nextCluster.yCoordinate, currentCluster.xCoordinate - nextCluster.xCoordinate)};
158 const float tanL = (currentCluster.zCoordinate - nextCluster.zCoordinate) / (currentCluster.radius - nextCluster.radius);
159 if constexpr (decltype(Tag)::value == PassMode::OnePass::value) {
160 tracklets.emplace_back(currentSortedIndex, mTimeFrame->getSortedIndex(targetROF, iLayer + 1, iNext), tanL, phi, ts);
161 } else if constexpr (decltype(Tag)::value == PassMode::TwoPassCount::value) {
162 ++localCount;
163 } else if constexpr (decltype(Tag)::value == PassMode::TwoPassInsert::value) {
164 const int idx = base + offset++;
165 tracklets[idx] = Tracklet(currentSortedIndex, mTimeFrame->getSortedIndex(targetROF, iLayer + 1, iNext), tanL, phi, ts);
166 }
167 }
168 }
169 }
170 }
171 }
172 }
173 return localCount;
174 };
175
176 int dummy{0};
177 if (mTaskArena->max_concurrency() <= 1) {
178 for (int iLayer{0}; iLayer < mTrkParams[iteration].TrackletsPerRoad(); ++iLayer) {
179 const int startROF = 0, endROF = mTimeFrame->getROFOverlapTableView().getLayer(iLayer).mNROFsTF;
180 for (int pivotROF{startROF}; pivotROF < endROF; ++pivotROF) {
181 forTracklets(PassMode::OnePass{}, iLayer, pivotROF, 0, dummy);
182 }
183 }
184 } else {
185 tbb::parallel_for(0, mTrkParams[iteration].TrackletsPerRoad(), [&](const int iLayer) {
186 const int startROF = 0, endROF = mTimeFrame->getROFOverlapTableView().getLayer(iLayer).mNROFsTF;
187 bounded_vector<int> perROFCount((endROF - startROF) + 1, mMemoryPool.get());
188 tbb::parallel_for(startROF, endROF, [&](const int pivotROF) {
189 perROFCount[pivotROF - startROF] = forTracklets(PassMode::TwoPassCount{}, iLayer, pivotROF, 0, dummy);
190 });
191 std::exclusive_scan(perROFCount.begin(), perROFCount.end(), perROFCount.begin(), 0);
192 const int nTracklets = perROFCount.back();
193 mTimeFrame->getTracklets()[iLayer].resize(nTracklets);
194 if (nTracklets == 0) {
195 return;
196 }
197 tbb::parallel_for(startROF, endROF, [&](const int pivotROF) {
198 int baseIdx = perROFCount[pivotROF - startROF];
199 if (baseIdx == perROFCount[pivotROF + 1 - startROF]) {
200 return;
201 }
202 int localIdx = 0;
203 forTracklets(PassMode::TwoPassInsert{}, iLayer, pivotROF, baseIdx, localIdx);
204 });
205 });
206 }
207
208 tbb::parallel_for(0, mTrkParams[iteration].TrackletsPerRoad(), [&](const int iLayer) {
210 // duplicates can exist simply since we evaluate per vertex
211 auto& trkl{mTimeFrame->getTracklets()[iLayer]};
212 std::sort(trkl.begin(), trkl.end());
213 trkl.erase(std::unique(trkl.begin(), trkl.end()), trkl.end());
214 trkl.shrink_to_fit();
215 if (iLayer > 0) {
216 auto& lut{mTimeFrame->getTrackletsLookupTable()[iLayer - 1]};
217 if (!trkl.empty()) {
218 for (const auto& tkl : trkl) {
219 lut[tkl.firstClusterIndex + 1]++;
220 }
221 std::inclusive_scan(lut.begin(), lut.end(), lut.begin());
222 }
223 }
224 });
225
227 if (mTimeFrame->hasMCinformation() && mTrkParams[iteration].createArtefactLabels) {
228 tbb::parallel_for(0, mTrkParams[iteration].TrackletsPerRoad(), [&](const int iLayer) {
229 for (auto& trk : mTimeFrame->getTracklets()[iLayer]) {
231 int currentId{mTimeFrame->getClusters()[iLayer][trk.firstClusterIndex].clusterId};
232 int nextId{mTimeFrame->getClusters()[iLayer + 1][trk.secondClusterIndex].clusterId};
233 for (const auto& lab1 : mTimeFrame->getClusterLabels(iLayer, currentId)) {
234 for (const auto& lab2 : mTimeFrame->getClusterLabels(iLayer + 1, nextId)) {
235 if (lab1 == lab2 && lab1.isValid()) {
236 label = lab1;
237 break;
238 }
239 }
240 if (label.isValid()) {
241 break;
242 }
243 }
244 mTimeFrame->getTrackletsLabel(iLayer).emplace_back(label);
245 }
246 });
247 }
248 });
249}
250
251template <int NLayers>
253{
254 for (int iLayer = 0; iLayer < mTrkParams[iteration].CellsPerRoad(); ++iLayer) {
255 deepVectorClear(mTimeFrame->getCells()[iLayer]);
256 if (iLayer > 0) {
257 deepVectorClear(mTimeFrame->getCellsLookupTable()[iLayer - 1]);
258 }
259 if (mTimeFrame->hasMCinformation() && mTrkParams[iteration].createArtefactLabels) {
260 deepVectorClear(mTimeFrame->getCellsLabel(iLayer));
261 }
262 }
263
264 mTaskArena->execute([&] {
265 auto forTrackletCells = [&](auto Tag, int iLayer, bounded_vector<CellSeed>& layerCells, int iTracklet, int offset = 0) -> int {
266 const Tracklet& currentTracklet{mTimeFrame->getTracklets()[iLayer][iTracklet]};
267 const int nextLayerClusterIndex{currentTracklet.secondClusterIndex};
268 const int nextLayerFirstTrackletIndex{mTimeFrame->getTrackletsLookupTable()[iLayer][nextLayerClusterIndex]};
269 const int nextLayerLastTrackletIndex{mTimeFrame->getTrackletsLookupTable()[iLayer][nextLayerClusterIndex + 1]};
270 int foundCells{0};
271 for (int iNextTracklet{nextLayerFirstTrackletIndex}; iNextTracklet < nextLayerLastTrackletIndex; ++iNextTracklet) {
272 const Tracklet& nextTracklet{mTimeFrame->getTracklets()[iLayer + 1][iNextTracklet]};
273 if (mTimeFrame->getTracklets()[iLayer + 1][iNextTracklet].firstClusterIndex != nextLayerClusterIndex) {
274 break;
275 }
276 if (!currentTracklet.getTimeStamp().isCompatible(nextTracklet.getTimeStamp())) {
277 continue;
278 }
279
280 const float deltaTanLambdaSigma = std::abs(currentTracklet.tanLambda - nextTracklet.tanLambda) / mTrkParams[iteration].CellDeltaTanLambdaSigma;
281 if (deltaTanLambdaSigma < mTrkParams[iteration].NSigmaCut) {
282
284 const int clusId[3]{
285 mTimeFrame->getClusters()[iLayer][currentTracklet.firstClusterIndex].clusterId,
286 mTimeFrame->getClusters()[iLayer + 1][nextTracklet.firstClusterIndex].clusterId,
287 mTimeFrame->getClusters()[iLayer + 2][nextTracklet.secondClusterIndex].clusterId};
288 const auto& cluster1_glo = mTimeFrame->getUnsortedClusters()[iLayer][clusId[0]];
289 const auto& cluster2_glo = mTimeFrame->getUnsortedClusters()[iLayer + 1][clusId[1]];
290 const auto& cluster3_tf = mTimeFrame->getTrackingFrameInfoOnLayer(iLayer + 2)[clusId[2]];
291 auto track{o2::its::track::buildTrackSeed(cluster1_glo, cluster2_glo, cluster3_tf, mBz)};
292
293 float chi2{0.f};
294 bool good{false};
295 for (int iC{2}; iC--;) {
296 const TrackingFrameInfo& trackingHit = mTimeFrame->getTrackingFrameInfoOnLayer(iLayer + iC)[clusId[iC]];
297
298 if (!track.rotate(trackingHit.alphaTrackingFrame)) {
299 break;
300 }
301
302 if (!track.propagateTo(trackingHit.xTrackingFrame, getBz())) {
303 break;
304 }
305
306 if (!track.correctForMaterial(mTrkParams[iteration].LayerxX0[iLayer + iC], mTrkParams[iteration].LayerxX0[iLayer + iC] * constants::Radl * constants::Rho, true)) {
307 break;
308 }
309
310 const auto predChi2{track.getPredictedChi2Quiet(trackingHit.positionTrackingFrame, trackingHit.covarianceTrackingFrame)};
311 if (!iC && predChi2 > mTrkParams[iteration].MaxChi2ClusterAttachment) {
312 break;
313 }
314
315 if (!track.o2::track::TrackParCov::update(trackingHit.positionTrackingFrame, trackingHit.covarianceTrackingFrame)) {
316 break;
317 }
318
319 good = !iC;
320 chi2 += predChi2;
321 }
322 if (good) {
323 TimeEstBC ts = currentTracklet.getTimeStamp();
324 ts += nextTracklet.getTimeStamp();
325 if constexpr (decltype(Tag)::value == PassMode::OnePass::value) {
326 layerCells.emplace_back(iLayer, clusId[0], clusId[1], clusId[2], iTracklet, iNextTracklet, track, chi2, ts);
327 ++foundCells;
328 } else if constexpr (decltype(Tag)::value == PassMode::TwoPassCount::value) {
329 ++foundCells;
330 } else if constexpr (decltype(Tag)::value == PassMode::TwoPassInsert::value) {
331 layerCells[offset++] = CellSeed(iLayer, clusId[0], clusId[1], clusId[2], iTracklet, iNextTracklet, track, chi2, ts);
332 } else {
333 static_assert(false, "Unknown mode!");
334 }
335 }
336 }
337 }
338 return foundCells;
339 };
340
341 for (int iLayer = 0; iLayer < mTrkParams[iteration].CellsPerRoad(); ++iLayer) {
342 if (mTimeFrame->getTracklets()[iLayer + 1].empty() ||
343 mTimeFrame->getTracklets()[iLayer].empty()) {
344 if (iLayer < mTrkParams[iteration].TrackletsPerRoad()) {
345 deepVectorClear(mTimeFrame->getTracklets()[iLayer]);
346 deepVectorClear(mTimeFrame->getTrackletsLabel(iLayer));
347 }
348 continue;
349 }
350
351 auto& layerCells = mTimeFrame->getCells()[iLayer];
352 const int currentLayerTrackletsNum{static_cast<int>(mTimeFrame->getTracklets()[iLayer].size())};
353 bounded_vector<int> perTrackletCount(currentLayerTrackletsNum + 1, 0, mMemoryPool.get());
354 if (mTaskArena->max_concurrency() <= 1) {
355 for (int iTracklet{0}; iTracklet < currentLayerTrackletsNum; ++iTracklet) {
356 perTrackletCount[iTracklet] = forTrackletCells(PassMode::OnePass{}, iLayer, layerCells, iTracklet);
357 }
358 std::exclusive_scan(perTrackletCount.begin(), perTrackletCount.end(), perTrackletCount.begin(), 0);
359 } else {
360 tbb::parallel_for(0, currentLayerTrackletsNum, [&](const int iTracklet) {
361 perTrackletCount[iTracklet] = forTrackletCells(PassMode::TwoPassCount{}, iLayer, layerCells, iTracklet);
362 });
363
364 std::exclusive_scan(perTrackletCount.begin(), perTrackletCount.end(), perTrackletCount.begin(), 0);
365 auto totalCells{perTrackletCount.back()};
366 if (totalCells == 0) {
367 if (iLayer > 0) {
368 auto& lut = mTimeFrame->getCellsLookupTable()[iLayer - 1];
369 lut.resize(currentLayerTrackletsNum + 1);
370 std::fill(lut.begin(), lut.end(), 0);
371 }
372 deepVectorClear(mTimeFrame->getTracklets()[iLayer]);
373 deepVectorClear(mTimeFrame->getTrackletsLabel(iLayer));
374 continue;
375 }
376 layerCells.resize(totalCells);
377
378 tbb::parallel_for(0, currentLayerTrackletsNum, [&](const int iTracklet) {
379 int offset = perTrackletCount[iTracklet];
380 if (offset == perTrackletCount[iTracklet + 1]) {
381 return;
382 }
383 forTrackletCells(PassMode::TwoPassInsert{}, iLayer, layerCells, iTracklet, offset);
384 });
385 }
386
387 if (iLayer > 0) {
388 auto& lut = mTimeFrame->getCellsLookupTable()[iLayer - 1];
389 lut.resize(currentLayerTrackletsNum + 1);
390 std::copy_n(perTrackletCount.begin(), currentLayerTrackletsNum + 1, lut.begin());
391 }
392
393 if (mTimeFrame->hasMCinformation() && mTrkParams[iteration].createArtefactLabels) {
394 auto& labels = mTimeFrame->getCellsLabel(iLayer);
395 labels.reserve(layerCells.size());
396 for (const auto& cell : layerCells) {
397 MCCompLabel currentLab{mTimeFrame->getTrackletsLabel(iLayer)[cell.getFirstTrackletIndex()]};
398 MCCompLabel nextLab{mTimeFrame->getTrackletsLabel(iLayer + 1)[cell.getSecondTrackletIndex()]};
399 labels.emplace_back(currentLab == nextLab ? currentLab : MCCompLabel());
400 }
401 }
402
403 // Once layer i cells are built and labelled, the corresponding tracklet artefacts are no longer needed.
404 deepVectorClear(mTimeFrame->getTracklets()[iLayer]);
405 deepVectorClear(mTimeFrame->getTrackletsLabel(iLayer));
406 }
407 });
408
409 // Clear the trailing tracklet artefacts that are not consumed as the first leg of a cell.
410 for (int iLayer = mTrkParams[iteration].CellsPerRoad(); iLayer < mTrkParams[iteration].TrackletsPerRoad(); ++iLayer) {
411 deepVectorClear(mTimeFrame->getTracklets()[iLayer]);
412 deepVectorClear(mTimeFrame->getTrackletsLabel(iLayer));
413 }
414}
415
416template <int NLayers>
418{
419 struct Neighbor {
420 int cell{-1}, nextCell{-1}, level{-1};
421 };
422
423 mTaskArena->execute([&] {
424 for (int iLayer{0}; iLayer < mTrkParams[iteration].NeighboursPerRoad(); ++iLayer) {
425 deepVectorClear(mTimeFrame->getCellsNeighbours()[iLayer]);
426 deepVectorClear(mTimeFrame->getCellsNeighboursLUT()[iLayer]);
427 if (mTimeFrame->getCells()[iLayer + 1].empty() ||
428 mTimeFrame->getCellsLookupTable()[iLayer].empty()) {
429 continue;
430 }
431
432 int nCells{static_cast<int>(mTimeFrame->getCells()[iLayer].size())};
433 bounded_vector<Neighbor> cellsNeighbours(mMemoryPool.get());
434
435 auto forCellNeighbour = [&](auto Tag, int iCell, int offset = 0) -> int {
436 const auto& currentCellSeed{mTimeFrame->getCells()[iLayer][iCell]};
437 const int nextLayerTrackletIndex{currentCellSeed.getSecondTrackletIndex()};
438 const int nextLayerFirstCellIndex{mTimeFrame->getCellsLookupTable()[iLayer][nextLayerTrackletIndex]};
439 const int nextLayerLastCellIndex{mTimeFrame->getCellsLookupTable()[iLayer][nextLayerTrackletIndex + 1]};
440 int foundNextCells{0};
441 for (int iNextCell{nextLayerFirstCellIndex}; iNextCell < nextLayerLastCellIndex; ++iNextCell) {
442 auto nextCellSeed{mTimeFrame->getCells()[iLayer + 1][iNextCell]};
443 if (nextCellSeed.getFirstTrackletIndex() != nextLayerTrackletIndex || !currentCellSeed.getTimeStamp().isCompatible(nextCellSeed.getTimeStamp())) {
444 break;
445 }
446
447 if (!nextCellSeed.rotate(currentCellSeed.getAlpha()) ||
448 !nextCellSeed.propagateTo(currentCellSeed.getX(), getBz())) {
449 continue;
450 }
451
452 float chi2 = currentCellSeed.getPredictedChi2(nextCellSeed);
453 if (chi2 > mTrkParams[iteration].MaxChi2ClusterAttachment) {
454 continue;
455 }
456
457 if constexpr (decltype(Tag)::value == PassMode::OnePass::value) {
458 cellsNeighbours.emplace_back(iCell, iNextCell, currentCellSeed.getLevel() + 1);
459 } else if constexpr (decltype(Tag)::value == PassMode::TwoPassCount::value) {
460 ++foundNextCells;
461 } else if constexpr (decltype(Tag)::value == PassMode::TwoPassInsert::value) {
462 cellsNeighbours[offset++] = {iCell, iNextCell, currentCellSeed.getLevel() + 1};
463 } else {
464 static_assert(false, "Unknown mode!");
465 }
466 }
467 return foundNextCells;
468 };
469
470 if (mTaskArena->max_concurrency() <= 1) {
471 for (int iCell{0}; iCell < nCells; ++iCell) {
472 forCellNeighbour(PassMode::OnePass{}, iCell);
473 }
474 } else {
475 bounded_vector<int> perCellCount(nCells + 1, 0, mMemoryPool.get());
476 tbb::parallel_for(0, nCells, [&](const int iCell) {
477 perCellCount[iCell] = forCellNeighbour(PassMode::TwoPassCount{}, iCell);
478 });
479
480 std::exclusive_scan(perCellCount.begin(), perCellCount.end(), perCellCount.begin(), 0);
481 int totalCellNeighbours = perCellCount.back();
482 if (totalCellNeighbours == 0) {
483 deepVectorClear(mTimeFrame->getCellsNeighbours()[iLayer]);
484 continue;
485 }
486 cellsNeighbours.resize(totalCellNeighbours);
487
488 tbb::parallel_for(0, nCells, [&](const int iCell) {
489 int offset = perCellCount[iCell];
490 if (offset == perCellCount[iCell + 1]) {
491 return;
492 }
493 forCellNeighbour(PassMode::TwoPassInsert{}, iCell, offset);
494 });
495 }
496
497 if (cellsNeighbours.empty()) {
498 continue;
499 }
500
501 tbb::parallel_sort(cellsNeighbours.begin(), cellsNeighbours.end(), [](const auto& a, const auto& b) {
502 return a.nextCell < b.nextCell;
503 });
504
505 auto& cellsNeighbourLUT = mTimeFrame->getCellsNeighboursLUT()[iLayer];
506 cellsNeighbourLUT.assign(mTimeFrame->getCells()[iLayer + 1].size(), 0);
507 for (const auto& neigh : cellsNeighbours) {
508 ++cellsNeighbourLUT[neigh.nextCell];
509 }
510 std::inclusive_scan(cellsNeighbourLUT.begin(), cellsNeighbourLUT.end(), cellsNeighbourLUT.begin());
511
512 mTimeFrame->getCellsNeighbours()[iLayer].reserve(cellsNeighbours.size());
513 std::ranges::transform(cellsNeighbours, std::back_inserter(mTimeFrame->getCellsNeighbours()[iLayer]), [](const auto& neigh) { return neigh.cell; });
514
515 for (auto it = cellsNeighbours.begin(); it != cellsNeighbours.end();) {
516 int cellIdx = it->nextCell;
517 int maxLvl = it->level;
518 while (++it != cellsNeighbours.end() && it->nextCell == cellIdx) {
519 maxLvl = std::max(maxLvl, it->level);
520 }
521 mTimeFrame->getCells()[iLayer + 1][cellIdx].setLevel(maxLvl);
522 }
523
524 // clear cells LUT
525 deepVectorClear(mTimeFrame->getCellsLookupTable()[iLayer]);
526 }
527 });
528}
529
530template <int NLayers>
531template <typename InputSeed>
532void TrackerTraits<NLayers>::processNeighbours(int iteration, int iLayer, int iLevel, const bounded_vector<InputSeed>& currentCellSeed, const bounded_vector<int>& currentCellId, bounded_vector<TrackSeedN>& updatedCellSeeds, bounded_vector<int>& updatedCellsIds)
533{
534 auto propagator = o2::base::Propagator::Instance();
535
536 mTaskArena->execute([&] {
537 auto forCellNeighbours = [&](auto Tag, int iCell, int offset = 0) -> int {
538 const auto& currentCell{currentCellSeed[iCell]};
539
540 if constexpr (decltype(Tag)::value != PassMode::TwoPassInsert::value) {
541 if (currentCell.getLevel() != iLevel) {
542 return 0;
543 }
544 if (currentCellId.empty() && (mTimeFrame->isClusterUsed(iLayer, currentCell.getFirstClusterIndex()) ||
545 mTimeFrame->isClusterUsed(iLayer + 1, currentCell.getSecondClusterIndex()) ||
546 mTimeFrame->isClusterUsed(iLayer + 2, currentCell.getThirdClusterIndex()))) {
547 return 0;
548 }
549 }
550
551 const int cellId = currentCellId.empty() ? iCell : currentCellId[iCell];
552 const int startNeighbourId{cellId ? mTimeFrame->getCellsNeighboursLUT()[iLayer - 1][cellId - 1] : 0};
553 const int endNeighbourId{mTimeFrame->getCellsNeighboursLUT()[iLayer - 1][cellId]};
554 int foundSeeds{0};
555 for (int iNeighbourCell{startNeighbourId}; iNeighbourCell < endNeighbourId; ++iNeighbourCell) {
556 const int neighbourCellId = mTimeFrame->getCellsNeighbours()[iLayer - 1][iNeighbourCell];
557 const auto& neighbourCell = mTimeFrame->getCells()[iLayer - 1][neighbourCellId];
558 if (neighbourCell.getSecondTrackletIndex() != currentCell.getFirstTrackletIndex()) {
559 continue;
560 }
561 if (!currentCell.getTimeStamp().isCompatible(neighbourCell.getTimeStamp())) {
562 continue;
563 }
564 if (currentCell.getLevel() - 1 != neighbourCell.getLevel()) {
565 continue;
566 }
567 if (mTimeFrame->isClusterUsed(iLayer - 1, neighbourCell.getFirstClusterIndex())) {
568 continue;
569 }
570
572 TrackSeedN seed{currentCell};
573 seed.getTimeStamp() = currentCell.getTimeStamp();
574 seed.getTimeStamp() += neighbourCell.getTimeStamp();
575 const auto& trHit = mTimeFrame->getTrackingFrameInfoOnLayer(iLayer - 1)[neighbourCell.getFirstClusterIndex()];
576
577 if (!seed.rotate(trHit.alphaTrackingFrame)) {
578 continue;
579 }
580
581 if (!propagator->propagateToX(seed, trHit.xTrackingFrame, getBz(), o2::base::PropagatorImpl<float>::MAX_SIN_PHI, o2::base::PropagatorImpl<float>::MAX_STEP, mTrkParams[iteration].CorrType)) {
582 continue;
583 }
584
585 if (mTrkParams[iteration].CorrType == o2::base::PropagatorF::MatCorrType::USEMatCorrNONE) {
586 if (!seed.correctForMaterial(mTrkParams[iteration].LayerxX0[iLayer - 1], mTrkParams[iteration].LayerxX0[iLayer - 1] * constants::Radl * constants::Rho, true)) {
587 continue;
588 }
589 }
590
591 auto predChi2{seed.getPredictedChi2Quiet(trHit.positionTrackingFrame, trHit.covarianceTrackingFrame)};
592 if ((predChi2 > mTrkParams[iteration].MaxChi2ClusterAttachment) || predChi2 < 0.f) {
593 continue;
594 }
595 seed.setChi2(seed.getChi2() + predChi2);
596 if (!seed.o2::track::TrackParCov::update(trHit.positionTrackingFrame, trHit.covarianceTrackingFrame)) {
597 continue;
598 }
599
600 if constexpr (decltype(Tag)::value != PassMode::TwoPassCount::value) {
601 seed.getClusters()[iLayer - 1] = neighbourCell.getFirstClusterIndex();
602 seed.setLevel(neighbourCell.getLevel());
603 seed.setFirstTrackletIndex(neighbourCell.getFirstTrackletIndex());
604 seed.setSecondTrackletIndex(neighbourCell.getSecondTrackletIndex());
605 }
606
607 if constexpr (decltype(Tag)::value == PassMode::OnePass::value) {
608 updatedCellSeeds.push_back(seed);
609 updatedCellsIds.push_back(neighbourCellId);
610 } else if constexpr (decltype(Tag)::value == PassMode::TwoPassCount::value) {
611 ++foundSeeds;
612 } else if constexpr (decltype(Tag)::value == PassMode::TwoPassInsert::value) {
613 updatedCellSeeds[offset] = seed;
614 updatedCellsIds[offset++] = neighbourCellId;
615 } else {
616 static_assert(false, "Unknown mode!");
617 }
618 }
619 return foundSeeds;
620 };
621
622 const int nCells = static_cast<int>(currentCellSeed.size());
623 if (mTaskArena->max_concurrency() <= 1) {
624 for (int iCell{0}; iCell < nCells; ++iCell) {
625 forCellNeighbours(PassMode::OnePass{}, iCell);
626 }
627 } else {
628 bounded_vector<int> perCellCount(nCells + 1, 0, mMemoryPool.get());
629 tbb::parallel_for(0, nCells, [&](const int iCell) {
630 perCellCount[iCell] = forCellNeighbours(PassMode::TwoPassCount{}, iCell);
631 });
632
633 std::exclusive_scan(perCellCount.begin(), perCellCount.end(), perCellCount.begin(), 0);
634 auto totalNeighbours{perCellCount.back()};
635 if (totalNeighbours == 0) {
636 return;
637 }
638 updatedCellSeeds.resize(totalNeighbours);
639 updatedCellsIds.resize(totalNeighbours);
640
641 tbb::parallel_for(0, nCells, [&](const int iCell) {
642 int offset = perCellCount[iCell];
643 if (offset == perCellCount[iCell + 1]) {
644 return;
645 }
646 forCellNeighbours(PassMode::TwoPassInsert{}, iCell, offset);
647 });
648 }
649 });
650}
651
652template <int NLayers>
653void TrackerTraits<NLayers>::findRoads(const int iteration)
654{
655 bounded_vector<bounded_vector<int>> firstClusters(mTrkParams[iteration].NLayers, bounded_vector<int>(mMemoryPool.get()), mMemoryPool.get());
656 bounded_vector<bounded_vector<int>> sharedFirstClusters(mTrkParams[iteration].NLayers, bounded_vector<int>(mMemoryPool.get()), mMemoryPool.get());
657 firstClusters.resize(mTrkParams[iteration].NLayers);
658 sharedFirstClusters.resize(mTrkParams[iteration].NLayers);
659 const auto propagator = o2::base::Propagator::Instance();
660 const TrackingFrameInfo* tfInfos[NLayers]{};
661 const Cluster* unsortedClusters[NLayers]{};
662 for (int iLayer = 0; iLayer < NLayers; ++iLayer) {
663 tfInfos[iLayer] = mTimeFrame->getTrackingFrameInfoOnLayer(iLayer).data();
664 unsortedClusters[iLayer] = mTimeFrame->getUnsortedClusters()[iLayer].data();
665 }
666 for (int startLevel{mTrkParams[iteration].CellsPerRoad()}; startLevel >= mTrkParams[iteration].CellMinimumLevel(); --startLevel) {
667
668 auto seedFilter = [&](const auto& seed) {
669 return seed.getQ2Pt() <= 1.e3 && seed.getChi2() <= mTrkParams[iteration].MaxChi2NDF * ((startLevel + 2) * 2 - 5);
670 };
671
672 bounded_vector<TrackSeedN> trackSeeds(mMemoryPool.get());
673 for (int startLayer{mTrkParams[iteration].NeighboursPerRoad()}; startLayer >= startLevel - 1; --startLayer) {
674 if ((mTrkParams[iteration].StartLayerMask & (1 << (startLayer + 2))) == 0) {
675 continue;
676 }
677
678 bounded_vector<int> lastCellId(mMemoryPool.get()), updatedCellId(mMemoryPool.get());
679 bounded_vector<TrackSeedN> lastCellSeed(mMemoryPool.get()), updatedCellSeed(mMemoryPool.get());
680
681 processNeighbours(iteration, startLayer, startLevel, mTimeFrame->getCells()[startLayer], lastCellId, updatedCellSeed, updatedCellId);
682
683 int level = startLevel;
684 for (int iLayer{startLayer - 1}; iLayer > 0 && level > 2; --iLayer) {
685 lastCellSeed.swap(updatedCellSeed);
686 lastCellId.swap(updatedCellId);
687 deepVectorClear(updatedCellSeed);
688 deepVectorClear(updatedCellId);
689 processNeighbours(iteration, iLayer, --level, lastCellSeed, lastCellId, updatedCellSeed, updatedCellId);
690 }
691 deepVectorClear(lastCellId);
692 deepVectorClear(lastCellSeed);
693
694 if (!updatedCellSeed.empty()) {
695 trackSeeds.reserve(trackSeeds.size() + std::count_if(updatedCellSeed.begin(), updatedCellSeed.end(), seedFilter));
696 std::copy_if(updatedCellSeed.begin(), updatedCellSeed.end(), std::back_inserter(trackSeeds), seedFilter);
697 }
698 }
699
700 if (trackSeeds.empty()) {
701 continue;
702 }
703
704 bounded_vector<TrackITSExt> tracks(mMemoryPool.get());
705 mTaskArena->execute([&] {
706 auto forSeed = [&](auto Tag, int iSeed, int offset = 0) {
707 TrackITSExt temporaryTrack;
708 bool refitSuccess = track::refitTrack<NLayers>(trackSeeds[iSeed],
709 temporaryTrack,
710 mTrkParams[iteration].MaxChi2ClusterAttachment,
711 mTrkParams[iteration].MaxChi2NDF,
712 mBz,
713 tfInfos,
714 unsortedClusters,
715 mTrkParams[iteration].LayerxX0.data(),
716 mTrkParams[iteration].LayerRadii.data(),
717 mTrkParams[iteration].MinPt.data(),
718 propagator,
719 mTrkParams[iteration].CorrType,
720 mTrkParams[iteration].ReseedIfShorter,
721 mTrkParams[iteration].ShiftRefToCluster,
722 mTrkParams[iteration].RepeatRefitOut);
723
724 if (refitSuccess) {
725 if constexpr (decltype(Tag)::value == PassMode::OnePass::value) {
726 tracks.push_back(temporaryTrack);
727 } else if constexpr (decltype(Tag)::value == PassMode::TwoPassCount::value) {
728 // nothing to do
729 } else if constexpr (decltype(Tag)::value == PassMode::TwoPassInsert::value) {
730 tracks[offset] = temporaryTrack;
731 } else {
732 static_assert(false, "Unknown mode!");
733 }
734 return 1;
735 }
736 return 0;
737 };
738
739 const int nSeeds = static_cast<int>(trackSeeds.size());
740 if (mTaskArena->max_concurrency() <= 1) {
741 for (int iSeed{0}; iSeed < nSeeds; ++iSeed) {
742 forSeed(PassMode::OnePass{}, iSeed);
743 }
744 } else {
745 // The double-pass allows us to avoid sizeable memory spikes
746 bounded_vector<int> perSeedCount(nSeeds + 1, 0, mMemoryPool.get());
747 tbb::parallel_for(0, nSeeds, [&](const int iSeed) {
748 perSeedCount[iSeed] = forSeed(PassMode::TwoPassCount{}, iSeed);
749 });
750
751 std::exclusive_scan(perSeedCount.begin(), perSeedCount.end(), perSeedCount.begin(), 0);
752 auto totalTracks{perSeedCount.back()};
753 if (totalTracks == 0) {
754 return;
755 }
756 tracks.resize(totalTracks);
757
758 tbb::parallel_for(0, nSeeds, [&](const int iSeed) {
759 if (perSeedCount[iSeed] == perSeedCount[iSeed + 1]) {
760 return;
761 }
762 forSeed(PassMode::TwoPassInsert{}, iSeed, perSeedCount[iSeed]);
763 });
764 }
765
766 deepVectorClear(trackSeeds);
767 });
768
769 std::sort(tracks.begin(), tracks.end(), [](const auto& a, const auto& b) {
770 return a.getChi2() < b.getChi2();
771 });
772
773 acceptTracks(iteration, tracks, firstClusters, sharedFirstClusters);
774 }
775 markTracks(iteration, sharedFirstClusters);
776}
777
778template <int NLayers>
780{
781 const float smallestROFHalf = mTimeFrame->getROFOverlapTableView().getClockLayer().mROFLength * 0.5f;
782 for (auto& track : tracks) {
783 int nShared = 0;
784 bool isFirstShared{false};
785 int firstLayer{-1}, firstCluster{-1};
786 for (int iLayer{0}; iLayer < mTrkParams[iteration].NLayers; ++iLayer) {
787 if (track.getClusterIndex(iLayer) == constants::UnusedIndex) {
788 continue;
789 }
790 bool isShared = mTimeFrame->isClusterUsed(iLayer, track.getClusterIndex(iLayer));
791 nShared += int(isShared);
792 if (firstLayer < 0) {
793 firstCluster = track.getClusterIndex(iLayer);
794 isFirstShared = isShared && mTrkParams[iteration].AllowSharingFirstCluster && std::find(firstClusters[iLayer].begin(), firstClusters[iLayer].end(), firstCluster) != firstClusters[iLayer].end();
795 firstLayer = iLayer;
796 }
797 }
798
800 if (nShared - int(isFirstShared && mTrkParams[iteration].AllowSharingFirstCluster) > mTrkParams[iteration].ClusterSharing) {
801 continue;
802 }
803
804 bool firstCls{true}, nominalCompatible{true};
805 TimeEstBC nominalTS, expandedTS;
806 for (int iLayer{0}; iLayer < mTrkParams[iteration].NLayers; ++iLayer) {
807 if (track.getClusterIndex(iLayer) == constants::UnusedIndex) {
808 continue;
809 }
810 mTimeFrame->markUsedCluster(iLayer, track.getClusterIndex(iLayer));
811 int currentROF = mTimeFrame->getClusterROF(iLayer, track.getClusterIndex(iLayer));
812 const auto nominalROFTS = mTimeFrame->getROFOverlapTableView().getLayer(iLayer).getROFTimeBounds(currentROF);
813 const auto expandedROFTS = mTimeFrame->getROFOverlapTableView().getLayer(iLayer).getROFTimeBounds(currentROF, true);
814 if (firstCls) {
815 firstCls = false;
816 nominalTS = nominalROFTS;
817 expandedTS = expandedROFTS;
818 } else {
819 if (nominalCompatible) {
820 if (nominalTS.isCompatible(nominalROFTS)) {
821 nominalTS += nominalROFTS;
822 } else {
823 nominalCompatible = false;
824 }
825 }
826 if (!expandedTS.isCompatible(expandedROFTS)) {
827 LOGP(fatal, "TS {}+/-{} are incompatible with {}+/-{}, this should not happen!", expandedROFTS.getTimeStamp(), expandedROFTS.getTimeStampError(), expandedTS.getTimeStamp(), expandedTS.getTimeStampError());
828 }
829 expandedTS += expandedROFTS;
830 }
831 }
832 track.getTimeStamp() = (nominalCompatible ? nominalTS : expandedTS).makeSymmetrical();
833 // this is a sanity clamp
834 // we cannot be worse than the clock so we clamp to this
835 if (track.getTimeStamp().getTimeStampError() > smallestROFHalf) {
836 track.getTimeStamp().setTimeStampError(smallestROFHalf);
837 }
838 track.setUserField(0);
839 track.getParamOut().setUserField(0);
840 mTimeFrame->getTracks().emplace_back(track);
841
842 if (mTrkParams[iteration].AllowSharingFirstCluster) {
843 firstClusters[firstLayer].push_back(firstCluster);
844 if (isFirstShared) {
845 sharedFirstClusters[firstLayer].push_back(firstCluster);
846 }
847 }
848 }
849}
850
851template <int NLayers>
853{
854 if (mTrkParams[iteration].AllowSharingFirstCluster) {
856 for (int iLayer{0}; iLayer < mTrkParams[iteration].NLayers; ++iLayer) {
857 std::sort(sharedFirstClusters[iLayer].begin(), sharedFirstClusters[iLayer].end());
858 }
859
860 for (auto& track : mTimeFrame->getTracks()) {
861 int firstLayer{mTrkParams[iteration].NLayers}, firstCluster{constants::UnusedIndex};
862 for (int iLayer{0}; iLayer < mTrkParams[iteration].NLayers; ++iLayer) {
863 if (track.getClusterIndex(iLayer) == constants::UnusedIndex) {
864 continue;
865 }
866 firstLayer = iLayer;
867 firstCluster = track.getClusterIndex(iLayer);
868 break;
869 }
870 if (std::binary_search(sharedFirstClusters[firstLayer].begin(), sharedFirstClusters[firstLayer].end(), firstCluster)) {
871 track.setSharedClusters();
872 }
873 }
874 }
875}
876
877template <int NLayers>
879{
880 mBz = bz;
881 mTimeFrame->setBz(bz);
882}
883
884template <int NLayers>
885void TrackerTraits<NLayers>::setNThreads(int n, std::shared_ptr<tbb::task_arena>& arena)
886{
887#if defined(OPTIMISATION_OUTPUT)
888 mTaskArena = std::make_shared<tbb::task_arena>(1);
889#else
890 if (arena == nullptr) {
891 mTaskArena = std::make_shared<tbb::task_arena>(std::abs(n));
892 LOGP(info, "Setting tracker with {} threads.", n);
893 } else {
894 mTaskArena = arena;
895 }
896#endif
897}
898
899template class TrackerTraits<7>;
902// ALICE3 upgrade
903#ifdef ENABLE_UPGRADES
904template class TrackerTraits<11>;
907#endif
908
909} // namespace o2::its
std::vector< std::string > labels
Base track model for the Barrel, params only, w/o covariance.
int32_t lastRow
bounded_vector< float > bins
useful math constants
Shared host/device helpers for ITS tracker trait implementations.
GPUd() value_type estimateLTFast(o2 static GPUd() float estimateLTIncrement(const o2 PropagatorImpl * Instance(bool uninitialized=false)
Definition Propagator.h:178
CellSeed: connections of three clusters.
Definition Cell.h:68
virtual void findRoads(const int iteration)
void acceptTracks(int iteration, bounded_vector< TrackITSExt > &tracks, bounded_vector< bounded_vector< int > > &firstClusters, bounded_vector< bounded_vector< int > > &sharedFirstClusters)
void markTracks(int iteration, bounded_vector< bounded_vector< int > > &sharedFirstClusters)
virtual void findCellsNeighbours(const int iteration)
virtual void computeLayerCells(const int iteration)
virtual void setBz(float bz)
void setNThreads(int n, std::shared_ptr< tbb::task_arena > &arena)
void processNeighbours(int iteration, int iLayer, int iLevel, const bounded_vector< InputSeed > &currentCellSeed, const bounded_vector< int > &currentCellId, bounded_vector< TrackSeedN > &updatedCellSeed, bounded_vector< int > &updatedCellId)
virtual void computeLayerTracklets(const int iteration, int iVertex)
GLdouble n
Definition glcorearb.h:1982
GLuint GLuint end
Definition glcorearb.h:469
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
GLsizei const GLfloat * value
Definition glcorearb.h:819
GLintptr offset
Definition glcorearb.h:660
GLuint GLsizei const GLchar * label
Definition glcorearb.h:2519
GLboolean GLboolean GLboolean GLboolean a
Definition glcorearb.h:1233
constexpr int UnusedIndex
Definition Constants.h:32
constexpr float Radl
Definition Constants.h:34
constexpr float Tolerance
Definition Constants.h:30
constexpr float Rho
Definition Constants.h:35
void deepVectorClear(std::vector< T > &vec)
std::pmr::vector< T > bounded_vector
float yCoordinate
Definition Cluster.h:48
float zCoordinate
Definition Cluster.h:49
float xCoordinate
Definition Cluster.h:47
std::integral_constant< int, 0 > OnePass
std::integral_constant< int, 1 > TwoPassCount
std::integral_constant< int, 2 > TwoPassInsert
std::array< float, 2 > positionTrackingFrame
Definition Cluster.h:75
std::array< float, 3 > covarianceTrackingFrame
Definition Cluster.h:76
std::vector< Tracklet64 > tracklets