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
17
18#include <algorithm>
19#include <cassert>
20#include <iostream>
21
22#include <fmt/format.h>
23
26#include "GPUCommonMath.h"
27#include "ITStracking/Cell.h"
32
33#ifdef WITH_OPENMP
34#include <omp.h>
35#endif
36
38
39namespace
40{
41float Sq(float q)
42{
43 return q * q;
44}
45} // namespace
46
47namespace o2
48{
49namespace its
50{
51
52constexpr int debugLevel{0};
53
54void TrackerTraits::computeLayerTracklets(const int iteration, int iROFslice, int iVertex)
55{
57
58#ifdef OPTIMISATION_OUTPUT
59 static int iter{0};
60 std::ofstream off(fmt::format("tracklets{}.txt", iter++));
61#endif
62
63 for (int iLayer = 0; iLayer < mTrkParams[iteration].TrackletsPerRoad(); ++iLayer) {
64 tf->getTracklets()[iLayer].clear();
65 tf->getTrackletsLabel(iLayer).clear();
66 if (iLayer > 0) {
67 std::fill(tf->getTrackletsLookupTable()[iLayer - 1].begin(), tf->getTrackletsLookupTable()[iLayer - 1].end(), 0);
68 }
69 }
70
71 const Vertex diamondVert({mTrkParams[iteration].Diamond[0], mTrkParams[iteration].Diamond[1], mTrkParams[iteration].Diamond[2]}, {25.e-6f, 0.f, 0.f, 25.e-6f, 0.f, 36.f}, 1, 1.f);
72 gsl::span<const Vertex> diamondSpan(&diamondVert, 1);
73 int startROF{mTrkParams[iteration].nROFsPerIterations > 0 ? iROFslice * mTrkParams[iteration].nROFsPerIterations : 0};
74 int endROF{gpu::GPUCommonMath::Min(mTrkParams[iteration].nROFsPerIterations > 0 ? (iROFslice + 1) * mTrkParams[iteration].nROFsPerIterations + mTrkParams[iteration].DeltaROF : tf->getNrof(), tf->getNrof())};
75 for (int rof0{startROF}; rof0 < endROF; ++rof0) {
76 gsl::span<const Vertex> primaryVertices = mTrkParams[iteration].UseDiamond ? diamondSpan : tf->getPrimaryVertices(rof0);
77 const int startVtx{iVertex >= 0 ? iVertex : 0};
78 const int endVtx{iVertex >= 0 ? o2::gpu::CAMath::Min(iVertex + 1, static_cast<int>(primaryVertices.size())) : static_cast<int>(primaryVertices.size())};
79 int minRof = o2::gpu::CAMath::Max(startROF, rof0 - mTrkParams[iteration].DeltaROF);
80 int maxRof = o2::gpu::CAMath::Min(endROF - 1, rof0 + mTrkParams[iteration].DeltaROF);
81#pragma omp parallel for num_threads(mNThreads)
82 for (int iLayer = 0; iLayer < mTrkParams[iteration].TrackletsPerRoad(); ++iLayer) {
83 gsl::span<const Cluster> layer0 = tf->getClustersOnLayer(rof0, iLayer);
84 if (layer0.empty()) {
85 continue;
86 }
87 float meanDeltaR{mTrkParams[iteration].LayerRadii[iLayer + 1] - mTrkParams[iteration].LayerRadii[iLayer]};
88
89 const int currentLayerClustersNum{static_cast<int>(layer0.size())};
90 for (int iCluster{0}; iCluster < currentLayerClustersNum; ++iCluster) {
91 const Cluster& currentCluster{layer0[iCluster]};
92 const int currentSortedIndex{tf->getSortedIndex(rof0, iLayer, iCluster)};
93
94 if (tf->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 auto& primaryVertex{primaryVertices[iV]};
101 if (primaryVertex.isFlagSet(2) && iteration != 3) {
102 continue;
103 }
104 const float resolution = o2::gpu::CAMath::Sqrt(Sq(mTrkParams[iteration].PVres) / primaryVertex.getNContributors() + Sq(tf->getPositionResolution(iLayer)));
105
106 const float tanLambda{(currentCluster.zCoordinate - primaryVertex.getZ()) * inverseR0};
107
108 const float zAtRmin{tanLambda * (tf->getMinR(iLayer + 1) - currentCluster.radius) + currentCluster.zCoordinate};
109 const float zAtRmax{tanLambda * (tf->getMaxR(iLayer + 1) - currentCluster.radius) + currentCluster.zCoordinate};
110
111 const float sqInverseDeltaZ0{1.f / (Sq(currentCluster.zCoordinate - primaryVertex.getZ()) + 2.e-8f)};
112 const float sigmaZ{o2::gpu::CAMath::Sqrt(Sq(resolution) * Sq(tanLambda) * ((Sq(inverseR0) + sqInverseDeltaZ0) * Sq(meanDeltaR) + 1.f) + Sq(meanDeltaR * tf->getMSangle(iLayer)))};
113
114 const int4 selectedBinsRect{getBinsRect(currentCluster, iLayer + 1, zAtRmin, zAtRmax,
115 sigmaZ * mTrkParams[iteration].NSigmaCut, tf->getPhiCut(iLayer))};
116 if (selectedBinsRect.x == 0 && selectedBinsRect.y == 0 && selectedBinsRect.z == 0 && selectedBinsRect.w == 0) {
117 continue;
118 }
119
120 int phiBinsNum{selectedBinsRect.w - selectedBinsRect.y + 1};
121
122 if (phiBinsNum < 0) {
123 phiBinsNum += mTrkParams[iteration].PhiBins;
124 }
125
126 for (int rof1{minRof}; rof1 <= maxRof; ++rof1) {
127 gsl::span<const Cluster> layer1 = tf->getClustersOnLayer(rof1, iLayer + 1);
128 if (layer1.empty()) {
129 continue;
130 }
131 for (int iPhiCount{0}; iPhiCount < phiBinsNum; iPhiCount++) {
132 int iPhiBin = (selectedBinsRect.y + iPhiCount) % mTrkParams[iteration].PhiBins;
133 const int firstBinIndex{tf->mIndexTableUtils.getBinIndex(selectedBinsRect.x, iPhiBin)};
134 const int maxBinIndex{firstBinIndex + selectedBinsRect.z - selectedBinsRect.x + 1};
135 if constexpr (debugLevel) {
136 if (firstBinIndex < 0 || firstBinIndex > tf->getIndexTable(rof1, iLayer + 1).size() ||
137 maxBinIndex < 0 || maxBinIndex > tf->getIndexTable(rof1, iLayer + 1).size()) {
138 std::cout << iLayer << "\t" << iCluster << "\t" << zAtRmin << "\t" << zAtRmax << "\t" << sigmaZ * mTrkParams[iteration].NSigmaCut << "\t" << tf->getPhiCut(iLayer) << std::endl;
139 std::cout << currentCluster.zCoordinate << "\t" << primaryVertex.getZ() << "\t" << currentCluster.radius << std::endl;
140 std::cout << tf->getMinR(iLayer + 1) << "\t" << currentCluster.radius << "\t" << currentCluster.zCoordinate << std::endl;
141 std::cout << "Illegal access to IndexTable " << firstBinIndex << "\t" << maxBinIndex << "\t" << selectedBinsRect.z << "\t" << selectedBinsRect.x << std::endl;
142 exit(1);
143 }
144 }
145 const int firstRowClusterIndex = tf->getIndexTable(rof1, iLayer + 1)[firstBinIndex];
146 const int maxRowClusterIndex = tf->getIndexTable(rof1, iLayer + 1)[maxBinIndex];
147 for (int iNextCluster{firstRowClusterIndex}; iNextCluster < maxRowClusterIndex; ++iNextCluster) {
148 if (iNextCluster >= (int)layer1.size()) {
149 break;
150 }
151
152 const Cluster& nextCluster{layer1[iNextCluster]};
153 if (tf->isClusterUsed(iLayer + 1, nextCluster.clusterId)) {
154 continue;
155 }
156
157 const float deltaPhi{gpu::GPUCommonMath::Abs(currentCluster.phi - nextCluster.phi)};
158 const float deltaZ{gpu::GPUCommonMath::Abs(tanLambda * (nextCluster.radius - currentCluster.radius) +
159 currentCluster.zCoordinate - nextCluster.zCoordinate)};
160
161#ifdef OPTIMISATION_OUTPUT
163 int currentId{currentCluster.clusterId};
164 int nextId{nextCluster.clusterId};
165 for (auto& lab1 : tf->getClusterLabels(iLayer, currentId)) {
166 for (auto& lab2 : tf->getClusterLabels(iLayer + 1, nextId)) {
167 if (lab1 == lab2 && lab1.isValid()) {
168 label = lab1;
169 break;
170 }
171 }
172 if (label.isValid()) {
173 break;
174 }
175 }
176 off << fmt::format("{}\t{:d}\t{}\t{}\t{}\t{}", iLayer, label.isValid(), (tanLambda * (nextCluster.radius - currentCluster.radius) + currentCluster.zCoordinate - nextCluster.zCoordinate) / sigmaZ, tanLambda, resolution, sigmaZ) << std::endl;
177#endif
178
179 if (deltaZ / sigmaZ < mTrkParams[iteration].NSigmaCut &&
180 (deltaPhi < tf->getPhiCut(iLayer) ||
181 gpu::GPUCommonMath::Abs(deltaPhi - constants::math::TwoPi) < tf->getPhiCut(iLayer))) {
182 if (iLayer > 0) {
183 tf->getTrackletsLookupTable()[iLayer - 1][currentSortedIndex]++;
184 }
185 const float phi{o2::gpu::GPUCommonMath::ATan2(currentCluster.yCoordinate - nextCluster.yCoordinate,
186 currentCluster.xCoordinate - nextCluster.xCoordinate)};
187 const float tanL{(currentCluster.zCoordinate - nextCluster.zCoordinate) /
188 (currentCluster.radius - nextCluster.radius)};
189 tf->getTracklets()[iLayer].emplace_back(currentSortedIndex, tf->getSortedIndex(rof1, iLayer + 1, iNextCluster), tanL, phi, rof0, rof1);
190 }
191 }
192 }
193 }
194 }
195 }
196 }
197 }
198 if (!tf->checkMemory(mTrkParams[iteration].MaxMemory)) {
199 return;
200 }
201
202#pragma omp parallel for num_threads(mNThreads)
203 for (int iLayer = 0; iLayer < mTrkParams[iteration].CellsPerRoad(); ++iLayer) {
205 auto& trkl{tf->getTracklets()[iLayer + 1]};
206 std::sort(trkl.begin(), trkl.end(), [](const Tracklet& a, const Tracklet& b) {
207 return a.firstClusterIndex < b.firstClusterIndex || (a.firstClusterIndex == b.firstClusterIndex && a.secondClusterIndex < b.secondClusterIndex);
208 });
210 auto& lut{tf->getTrackletsLookupTable()[iLayer]};
211 int id0{-1}, id1{-1};
212 std::vector<Tracklet> newTrk;
213 newTrk.reserve(trkl.size());
214 for (auto& trk : trkl) {
215 if (trk.firstClusterIndex == id0 && trk.secondClusterIndex == id1) {
216 lut[id0]--;
217 } else {
218 id0 = trk.firstClusterIndex;
219 id1 = trk.secondClusterIndex;
220 newTrk.push_back(trk);
221 }
222 }
223 trkl.swap(newTrk);
224
226 std::exclusive_scan(lut.begin(), lut.end(), lut.begin(), 0);
227 lut.push_back(trkl.size());
228 }
230 std::sort(tf->getTracklets()[0].begin(), tf->getTracklets()[0].end(), [](const Tracklet& a, const Tracklet& b) {
231 return a.firstClusterIndex < b.firstClusterIndex || (a.firstClusterIndex == b.firstClusterIndex && a.secondClusterIndex < b.secondClusterIndex);
232 });
233 int id0{-1}, id1{-1};
234 std::vector<Tracklet> newTrk;
235 newTrk.reserve(tf->getTracklets()[0].size());
236 for (auto& trk : tf->getTracklets()[0]) {
237 if (trk.firstClusterIndex != id0 || trk.secondClusterIndex != id1) {
238 id0 = trk.firstClusterIndex;
239 id1 = trk.secondClusterIndex;
240 newTrk.push_back(trk);
241 }
242 }
243 tf->getTracklets()[0].swap(newTrk);
244
246 if (tf->hasMCinformation()) {
247 for (int iLayer{0}; iLayer < mTrkParams[iteration].TrackletsPerRoad(); ++iLayer) {
248 for (auto& trk : tf->getTracklets()[iLayer]) {
250 int currentId{tf->getClusters()[iLayer][trk.firstClusterIndex].clusterId};
251 int nextId{tf->getClusters()[iLayer + 1][trk.secondClusterIndex].clusterId};
252 for (auto& lab1 : tf->getClusterLabels(iLayer, currentId)) {
253 for (auto& lab2 : tf->getClusterLabels(iLayer + 1, nextId)) {
254 if (lab1 == lab2 && lab1.isValid()) {
255 label = lab1;
256 break;
257 }
258 }
259 if (label.isValid()) {
260 break;
261 }
262 }
263 tf->getTrackletsLabel(iLayer).emplace_back(label);
264 }
265 }
266 }
267}
268
269void TrackerTraits::computeLayerCells(const int iteration)
270{
271#ifdef OPTIMISATION_OUTPUT
272 static int iter{0};
273 std::ofstream off(fmt::format("cells{}.txt", iter++));
274#endif
275
276 for (int iLayer = 0; iLayer < mTrkParams[iteration].CellsPerRoad(); ++iLayer) {
277 mTimeFrame->getCells()[iLayer].clear();
278 mTimeFrame->getCellsLabel(iLayer).clear();
279 if (iLayer > 0) {
280 mTimeFrame->getCellsLookupTable()[iLayer - 1].clear();
281 }
282 }
283
285#pragma omp parallel for num_threads(mNThreads)
286 for (int iLayer = 0; iLayer < mTrkParams[iteration].CellsPerRoad(); ++iLayer) {
287
288 if (tf->getTracklets()[iLayer + 1].empty() ||
289 tf->getTracklets()[iLayer].empty()) {
290 continue;
291 }
292
293#ifdef OPTIMISATION_OUTPUT
294 float resolution{o2::gpu::CAMath::Sqrt(0.5f * (mTrkParams[iteration].SystErrorZ2[iLayer] + mTrkParams[iteration].SystErrorZ2[iLayer + 1] + mTrkParams[iteration].SystErrorZ2[iLayer + 2] + mTrkParams[iteration].SystErrorY2[iLayer] + mTrkParams[iteration].SystErrorY2[iLayer + 1] + mTrkParams[iteration].SystErrorY2[iLayer + 2])) / mTrkParams[iteration].LayerResolution[iLayer]};
295 resolution = resolution > 1.e-12 ? resolution : 1.f;
296#endif
297 const int currentLayerTrackletsNum{static_cast<int>(tf->getTracklets()[iLayer].size())};
298 for (int iTracklet{0}; iTracklet < currentLayerTrackletsNum; ++iTracklet) {
299
300 const Tracklet& currentTracklet{tf->getTracklets()[iLayer][iTracklet]};
301 const int nextLayerClusterIndex{currentTracklet.secondClusterIndex};
302 const int nextLayerFirstTrackletIndex{
303 tf->getTrackletsLookupTable()[iLayer][nextLayerClusterIndex]};
304 const int nextLayerLastTrackletIndex{
305 tf->getTrackletsLookupTable()[iLayer][nextLayerClusterIndex + 1]};
306
307 if (nextLayerFirstTrackletIndex == nextLayerLastTrackletIndex) {
308 continue;
309 }
310
311 for (int iNextTracklet{nextLayerFirstTrackletIndex}; iNextTracklet < nextLayerLastTrackletIndex; ++iNextTracklet) {
312 if (tf->getTracklets()[iLayer + 1][iNextTracklet].firstClusterIndex != nextLayerClusterIndex) {
313 break;
314 }
315 const Tracklet& nextTracklet{tf->getTracklets()[iLayer + 1][iNextTracklet]};
316 const float deltaTanLambda{std::abs(currentTracklet.tanLambda - nextTracklet.tanLambda)};
317
318#ifdef OPTIMISATION_OUTPUT
319 bool good{tf->getTrackletsLabel(iLayer)[iTracklet] == tf->getTrackletsLabel(iLayer + 1)[iNextTracklet]};
320 float signedDelta{currentTracklet.tanLambda - nextTracklet.tanLambda};
321 off << fmt::format("{}\t{:d}\t{}\t{}\t{}\t{}", iLayer, good, signedDelta, signedDelta / (mTrkParams[iteration].CellDeltaTanLambdaSigma), tanLambda, resolution) << std::endl;
322#endif
323
324 if (deltaTanLambda / mTrkParams[iteration].CellDeltaTanLambdaSigma < mTrkParams[iteration].NSigmaCut) {
325
327 const int clusId[3]{
328 mTimeFrame->getClusters()[iLayer][currentTracklet.firstClusterIndex].clusterId,
329 mTimeFrame->getClusters()[iLayer + 1][nextTracklet.firstClusterIndex].clusterId,
330 mTimeFrame->getClusters()[iLayer + 2][nextTracklet.secondClusterIndex].clusterId};
331 const auto& cluster1_glo = mTimeFrame->getUnsortedClusters()[iLayer].at(clusId[0]);
332 const auto& cluster2_glo = mTimeFrame->getUnsortedClusters()[iLayer + 1].at(clusId[1]);
333 const auto& cluster3_tf = mTimeFrame->getTrackingFrameInfoOnLayer(iLayer + 2).at(clusId[2]);
334 auto track{buildTrackSeed(cluster1_glo, cluster2_glo, cluster3_tf)};
335
336 float chi2{0.f};
337 bool good{false};
338 for (int iC{2}; iC--;) {
339 const TrackingFrameInfo& trackingHit = mTimeFrame->getTrackingFrameInfoOnLayer(iLayer + iC).at(clusId[iC]);
340
341 if (!track.rotate(trackingHit.alphaTrackingFrame)) {
342 break;
343 }
344
345 if (!track.propagateTo(trackingHit.xTrackingFrame, getBz())) {
346 break;
347 }
348
349 constexpr float radl = 9.36f; // Radiation length of Si [cm]
350 constexpr float rho = 2.33f; // Density of Si [g/cm^3]
351 if (!track.correctForMaterial(mTrkParams[0].LayerxX0[iLayer + iC], mTrkParams[0].LayerxX0[iLayer] * radl * rho, true)) {
352 break;
353 }
354
355 auto predChi2{track.getPredictedChi2Quiet(trackingHit.positionTrackingFrame, trackingHit.covarianceTrackingFrame)};
356 if (!track.o2::track::TrackParCov::update(trackingHit.positionTrackingFrame, trackingHit.covarianceTrackingFrame)) {
357 break;
358 }
359 if (!iC && predChi2 > mTrkParams[iteration].MaxChi2ClusterAttachment) {
360 break;
361 }
362 good = !iC;
363 chi2 += predChi2;
364 }
365 if (!good) {
366 continue;
367 }
368 if (iLayer > 0 && (int)tf->getCellsLookupTable()[iLayer - 1].size() <= iTracklet) {
369 tf->getCellsLookupTable()[iLayer - 1].resize(iTracklet + 1, tf->getCells()[iLayer].size());
370 }
371 tf->getCells()[iLayer].emplace_back(iLayer, clusId[0], clusId[1], clusId[2],
372 iTracklet, iNextTracklet, track, chi2);
373 }
374 }
375 }
376 if (iLayer > 0) {
377 tf->getCellsLookupTable()[iLayer - 1].resize(currentLayerTrackletsNum + 1, tf->getCells()[iLayer].size());
378 }
379 }
380 if (!tf->checkMemory(mTrkParams[iteration].MaxMemory)) {
381 return;
382 }
383
385 if (tf->hasMCinformation()) {
386 for (int iLayer{0}; iLayer < mTrkParams[iteration].CellsPerRoad(); ++iLayer) {
387 for (auto& cell : tf->getCells()[iLayer]) {
388 MCCompLabel currentLab{tf->getTrackletsLabel(iLayer)[cell.getFirstTrackletIndex()]};
389 MCCompLabel nextLab{tf->getTrackletsLabel(iLayer + 1)[cell.getSecondTrackletIndex()]};
390 tf->getCellsLabel(iLayer).emplace_back(currentLab == nextLab ? currentLab : MCCompLabel());
391 }
392 }
393 }
394
395 if constexpr (debugLevel) {
396 for (int iLayer{0}; iLayer < mTrkParams[iteration].CellsPerRoad(); ++iLayer) {
397 std::cout << "Cells on layer " << iLayer << " " << tf->getCells()[iLayer].size() << std::endl;
398 }
399 }
400}
401
402void TrackerTraits::findCellsNeighbours(const int iteration)
403{
404#ifdef OPTIMISATION_OUTPUT
405 std::ofstream off(fmt::format("cellneighs{}.txt", iteration));
406#endif
407 for (int iLayer{0}; iLayer < mTrkParams[iteration].CellsPerRoad() - 1; ++iLayer) {
408 const int nextLayerCellsNum{static_cast<int>(mTimeFrame->getCells()[iLayer + 1].size())};
409 mTimeFrame->getCellsNeighboursLUT()[iLayer].clear();
410 mTimeFrame->getCellsNeighboursLUT()[iLayer].resize(nextLayerCellsNum, 0);
411 if (mTimeFrame->getCells()[iLayer + 1].empty() ||
412 mTimeFrame->getCellsLookupTable()[iLayer].empty()) {
413 mTimeFrame->getCellsNeighbours()[iLayer].clear();
414 continue;
415 }
416
417 int layerCellsNum{static_cast<int>(mTimeFrame->getCells()[iLayer].size())};
418 std::vector<std::pair<int, int>> cellsNeighbours;
419 cellsNeighbours.reserve(nextLayerCellsNum);
420
421 for (int iCell{0}; iCell < layerCellsNum; ++iCell) {
422
423 const auto& currentCellSeed{mTimeFrame->getCells()[iLayer][iCell]};
424 const int nextLayerTrackletIndex{currentCellSeed.getSecondTrackletIndex()};
425 const int nextLayerFirstCellIndex{mTimeFrame->getCellsLookupTable()[iLayer][nextLayerTrackletIndex]};
426 const int nextLayerLastCellIndex{mTimeFrame->getCellsLookupTable()[iLayer][nextLayerTrackletIndex + 1]};
427 for (int iNextCell{nextLayerFirstCellIndex}; iNextCell < nextLayerLastCellIndex; ++iNextCell) {
428
429 auto nextCellSeed{mTimeFrame->getCells()[iLayer + 1][iNextCell]};
430 if (nextCellSeed.getFirstTrackletIndex() != nextLayerTrackletIndex) {
431 break;
432 }
433
434 if (!nextCellSeed.rotate(currentCellSeed.getAlpha()) ||
435 !nextCellSeed.propagateTo(currentCellSeed.getX(), getBz())) {
436 continue;
437 }
438 float chi2 = currentCellSeed.getPredictedChi2(nextCellSeed);
439
440#ifdef OPTIMISATION_OUTPUT
441 bool good{mTimeFrame->getCellsLabel(iLayer)[iCell] == mTimeFrame->getCellsLabel(iLayer + 1)[iNextCell]};
442 off << fmt::format("{}\t{:d}\t{}", iLayer, good, chi2) << std::endl;
443#endif
444
445 if (chi2 > mTrkParams[0].MaxChi2ClusterAttachment) {
446 continue;
447 }
448
449 mTimeFrame->getCellsNeighboursLUT()[iLayer][iNextCell]++;
450 cellsNeighbours.push_back(std::make_pair(iCell, iNextCell));
451 const int currentCellLevel{currentCellSeed.getLevel()};
452
453 if (currentCellLevel >= nextCellSeed.getLevel()) {
454 mTimeFrame->getCells()[iLayer + 1][iNextCell].setLevel(currentCellLevel + 1);
455 }
456 }
457 }
458 std::sort(cellsNeighbours.begin(), cellsNeighbours.end(), [](const std::pair<int, int>& a, const std::pair<int, int>& b) {
459 return a.second < b.second;
460 });
461 mTimeFrame->getCellsNeighbours()[iLayer].clear();
462 mTimeFrame->getCellsNeighbours()[iLayer].reserve(cellsNeighbours.size());
463 for (auto& cellNeighboursIndex : cellsNeighbours) {
464 mTimeFrame->getCellsNeighbours()[iLayer].push_back(cellNeighboursIndex.first);
465 }
466 std::inclusive_scan(mTimeFrame->getCellsNeighboursLUT()[iLayer].begin(), mTimeFrame->getCellsNeighboursLUT()[iLayer].end(), mTimeFrame->getCellsNeighboursLUT()[iLayer].begin());
467 }
468}
469
470void TrackerTraits::processNeighbours(int iLayer, int iLevel, const std::vector<CellSeed>& currentCellSeed, const std::vector<int>& currentCellId, std::vector<CellSeed>& updatedCellSeeds, std::vector<int>& updatedCellsIds)
471{
472 if (iLevel < 2 || iLayer < 1) {
473 std::cout << "Error: layer " << iLayer << " or level " << iLevel << " cannot be processed by processNeighbours" << std::endl;
474 exit(1);
475 }
476 CA_DEBUGGER(std::cout << "Processing neighbours layer " << iLayer << " level " << iLevel << ", size of the cell seeds: " << currentCellSeed.size() << std::endl);
477 updatedCellSeeds.reserve(mTimeFrame->getCellsNeighboursLUT()[iLayer - 1].size());
478 updatedCellsIds.reserve(updatedCellSeeds.size());
479 auto propagator = o2::base::Propagator::Instance();
480#ifdef CA_DEBUG
481 int failed[5]{0, 0, 0, 0, 0}, attempts{0}, failedByMismatch{0};
482#endif
483
484#pragma omp parallel for num_threads(mNThreads)
485 for (unsigned int iCell = 0; iCell < currentCellSeed.size(); ++iCell) {
486 const CellSeed& currentCell{currentCellSeed[iCell]};
487 if (currentCell.getLevel() != iLevel) {
488 continue;
489 }
490 if (currentCellId.empty() && (mTimeFrame->isClusterUsed(iLayer, currentCell.getFirstClusterIndex()) ||
491 mTimeFrame->isClusterUsed(iLayer + 1, currentCell.getSecondClusterIndex()) ||
492 mTimeFrame->isClusterUsed(iLayer + 2, currentCell.getThirdClusterIndex()))) {
493 continue;
494 }
495 const int cellId = currentCellId.empty() ? iCell : currentCellId[iCell];
496 const int startNeighbourId{cellId ? mTimeFrame->getCellsNeighboursLUT()[iLayer - 1][cellId - 1] : 0};
497 const int endNeighbourId{mTimeFrame->getCellsNeighboursLUT()[iLayer - 1][cellId]};
498
499 for (int iNeighbourCell{startNeighbourId}; iNeighbourCell < endNeighbourId; ++iNeighbourCell) {
500 CA_DEBUGGER(attempts++);
501 const int neighbourCellId = mTimeFrame->getCellsNeighbours()[iLayer - 1][iNeighbourCell];
502 const CellSeed& neighbourCell = mTimeFrame->getCells()[iLayer - 1][neighbourCellId];
503 if (neighbourCell.getSecondTrackletIndex() != currentCell.getFirstTrackletIndex()) {
504 CA_DEBUGGER(failedByMismatch++);
505 continue;
506 }
507 if (mTimeFrame->isClusterUsed(iLayer - 1, neighbourCell.getFirstClusterIndex())) {
508 continue;
509 }
510 if (currentCell.getLevel() - 1 != neighbourCell.getLevel()) {
511 CA_DEBUGGER(failed[0]++);
512 continue;
513 }
515 CellSeed seed{currentCell};
516 auto& trHit = mTimeFrame->getTrackingFrameInfoOnLayer(iLayer - 1).at(neighbourCell.getFirstClusterIndex());
517
518 if (!seed.rotate(trHit.alphaTrackingFrame)) {
519 CA_DEBUGGER(failed[1]++);
520 continue;
521 }
522
523 if (!propagator->propagateToX(seed, trHit.xTrackingFrame, getBz(), o2::base::PropagatorImpl<float>::MAX_SIN_PHI, o2::base::PropagatorImpl<float>::MAX_STEP, mCorrType)) {
524 CA_DEBUGGER(failed[2]++);
525 continue;
526 }
527
528 if (mCorrType == o2::base::PropagatorF::MatCorrType::USEMatCorrNONE) {
529 float radl = 9.36f; // Radiation length of Si [cm]
530 float rho = 2.33f; // Density of Si [g/cm^3]
531 if (!seed.correctForMaterial(mTrkParams[0].LayerxX0[iLayer - 1], mTrkParams[0].LayerxX0[iLayer - 1] * radl * rho, true)) {
532 continue;
533 }
534 }
535
536 auto predChi2{seed.getPredictedChi2Quiet(trHit.positionTrackingFrame, trHit.covarianceTrackingFrame)};
537 if ((predChi2 > mTrkParams[0].MaxChi2ClusterAttachment) || predChi2 < 0.f) {
538 CA_DEBUGGER(failed[3]++);
539 continue;
540 }
541 seed.setChi2(seed.getChi2() + predChi2);
542 if (!seed.o2::track::TrackParCov::update(trHit.positionTrackingFrame, trHit.covarianceTrackingFrame)) {
543 CA_DEBUGGER(failed[4]++);
544 continue;
545 }
546 seed.getClusters()[iLayer - 1] = neighbourCell.getFirstClusterIndex();
547 seed.setLevel(neighbourCell.getLevel());
548 seed.setFirstTrackletIndex(neighbourCell.getFirstTrackletIndex());
549 seed.setSecondTrackletIndex(neighbourCell.getSecondTrackletIndex());
550#pragma omp critical
551 {
552 updatedCellsIds.push_back(neighbourCellId);
553 updatedCellSeeds.push_back(seed);
554 }
555 }
556 }
557#ifdef CA_DEBUG
558 std::cout << "\t\t- Found " << updatedCellSeeds.size() << " cell seeds out of " << attempts << " attempts" << std::endl;
559 std::cout << "\t\t\t> " << failed[0] << " failed because of level" << std::endl;
560 std::cout << "\t\t\t> " << failed[1] << " failed because of rotation" << std::endl;
561 std::cout << "\t\t\t> " << failed[2] << " failed because of propagation" << std::endl;
562 std::cout << "\t\t\t> " << failed[3] << " failed because of chi2 cut" << std::endl;
563 std::cout << "\t\t\t> " << failed[4] << " failed because of update" << std::endl;
564 std::cout << "\t\t\t> " << failedByMismatch << " failed because of mismatch" << std::endl;
565#endif
566}
567
568void TrackerTraits::findRoads(const int iteration)
569{
570 CA_DEBUGGER(std::cout << "Finding roads, iteration " << iteration << std::endl);
571 for (int startLevel{mTrkParams[iteration].CellsPerRoad()}; startLevel >= mTrkParams[iteration].CellMinimumLevel(); --startLevel) {
572 CA_DEBUGGER(std::cout << "\t > Processing level " << startLevel << std::endl);
573 const int minimumLayer{startLevel - 1};
574 std::vector<CellSeed> trackSeeds;
575 for (int startLayer{mTrkParams[iteration].CellsPerRoad() - 1}; startLayer >= minimumLayer; --startLayer) {
576 if ((mTrkParams[iteration].StartLayerMask & (1 << (startLayer + 2))) == 0) {
577 continue;
578 }
579 CA_DEBUGGER(std::cout << "\t\t > Starting processing layer " << startLayer << std::endl);
580 std::vector<int> lastCellId, updatedCellId;
581 std::vector<CellSeed> lastCellSeed, updatedCellSeed;
582
583 processNeighbours(startLayer, startLevel, mTimeFrame->getCells()[startLayer], lastCellId, updatedCellSeed, updatedCellId);
584
585 int level = startLevel;
586 for (int iLayer{startLayer - 1}; iLayer > 0 && level > 2; --iLayer) {
587 lastCellSeed.swap(updatedCellSeed);
588 lastCellId.swap(updatedCellId);
589 std::vector<CellSeed>().swap(updatedCellSeed);
590 updatedCellId.clear();
591 processNeighbours(iLayer, --level, lastCellSeed, lastCellId, updatedCellSeed, updatedCellId);
592 }
593 for (auto& seed : updatedCellSeed) {
594 if (seed.getQ2Pt() > 1.e3 || seed.getChi2() > mTrkParams[0].MaxChi2NDF * ((startLevel + 2) * 2 - 5)) {
595 continue;
596 }
597 trackSeeds.push_back(seed);
598 }
599 }
600
601 std::vector<TrackITSExt> tracks(trackSeeds.size());
602 std::atomic<size_t> trackIndex{0};
603#pragma omp parallel for num_threads(mNThreads)
604 for (size_t seedId = 0; seedId < trackSeeds.size(); ++seedId) {
605 const CellSeed& seed{trackSeeds[seedId]};
606 TrackITSExt temporaryTrack{seed};
607 temporaryTrack.resetCovariance();
608 temporaryTrack.setChi2(0);
609 for (int iL{0}; iL < 7; ++iL) {
610 temporaryTrack.setExternalClusterIndex(iL, seed.getCluster(iL), seed.getCluster(iL) != constants::its::UnusedIndex);
611 }
612
613 bool fitSuccess = fitTrack(temporaryTrack, 0, mTrkParams[0].NLayers, 1, mTrkParams[0].MaxChi2ClusterAttachment, mTrkParams[0].MaxChi2NDF);
614 if (!fitSuccess) {
615 continue;
616 }
617 temporaryTrack.getParamOut() = temporaryTrack.getParamIn();
618 temporaryTrack.resetCovariance();
619 temporaryTrack.setChi2(0);
620 fitSuccess = fitTrack(temporaryTrack, mTrkParams[0].NLayers - 1, -1, -1, mTrkParams[0].MaxChi2ClusterAttachment, mTrkParams[0].MaxChi2NDF, 50.f);
621 if (!fitSuccess || temporaryTrack.getPt() < mTrkParams[iteration].MinPt[mTrkParams[iteration].NLayers - temporaryTrack.getNClusters()]) {
622 continue;
623 }
624 tracks[trackIndex++] = temporaryTrack;
625 }
626
627 tracks.resize(trackIndex);
628 std::sort(tracks.begin(), tracks.end(), [](const TrackITSExt& a, const TrackITSExt& b) {
629 return a.getChi2() < b.getChi2();
630 });
631
632 for (auto& track : tracks) {
633 int nShared = 0;
634 bool isFirstShared{false};
635 for (int iLayer{0}; iLayer < mTrkParams[0].NLayers; ++iLayer) {
636 if (track.getClusterIndex(iLayer) == constants::its::UnusedIndex) {
637 continue;
638 }
639 nShared += int(mTimeFrame->isClusterUsed(iLayer, track.getClusterIndex(iLayer)));
640 isFirstShared |= !iLayer && mTimeFrame->isClusterUsed(iLayer, track.getClusterIndex(iLayer));
641 }
642
643 if (nShared > mTrkParams[0].ClusterSharing) {
644 continue;
645 }
646
647 std::array<int, 3> rofs{INT_MAX, INT_MAX, INT_MAX};
648 for (int iLayer{0}; iLayer < mTrkParams[0].NLayers; ++iLayer) {
649 if (track.getClusterIndex(iLayer) == constants::its::UnusedIndex) {
650 continue;
651 }
652 mTimeFrame->markUsedCluster(iLayer, track.getClusterIndex(iLayer));
653 int currentROF = mTimeFrame->getClusterROF(iLayer, track.getClusterIndex(iLayer));
654 for (int iR{0}; iR < 3; ++iR) {
655 if (rofs[iR] == INT_MAX) {
656 rofs[iR] = currentROF;
657 }
658 if (rofs[iR] == currentROF) {
659 break;
660 }
661 }
662 }
663 if (rofs[2] != INT_MAX) {
664 continue;
665 }
666 track.setUserField(0);
667 track.getParamOut().setUserField(0);
668 if (rofs[1] != INT_MAX) {
669 track.setNextROFbit();
670 }
671 mTimeFrame->getTracks(o2::gpu::CAMath::Min(rofs[0], rofs[1])).emplace_back(track);
672 }
673 }
674}
675
676void TrackerTraits::extendTracks(const int iteration)
677{
678 for (int rof{0}; rof < mTimeFrame->getNrof(); ++rof) {
679 for (auto& track : mTimeFrame->getTracks(rof)) {
680 auto backup{track};
681 bool success{false};
682 // the order here biases towards top extension, tracks should probably be fitted separately in the directions and then compared.
683 if ((mTrkParams[iteration].UseTrackFollowerMix || mTrkParams[iteration].UseTrackFollowerTop) && track.getLastClusterLayer() != mTrkParams[iteration].NLayers - 1) {
684 success = success || trackFollowing(&track, rof, true, iteration);
685 }
686 if ((mTrkParams[iteration].UseTrackFollowerMix || (mTrkParams[iteration].UseTrackFollowerBot && !success)) && track.getFirstClusterLayer() != 0) {
687 success = success || trackFollowing(&track, rof, false, iteration);
688 }
689 if (success) {
691 track.resetCovariance();
692 track.setChi2(0);
693 bool fitSuccess = fitTrack(track, 0, mTrkParams[iteration].NLayers, 1, mTrkParams[iteration].MaxChi2ClusterAttachment, mTrkParams[0].MaxChi2NDF);
694 if (!fitSuccess) {
695 track = backup;
696 continue;
697 }
698 track.getParamOut() = track;
699 track.resetCovariance();
700 track.setChi2(0);
701 fitSuccess = fitTrack(track, mTrkParams[iteration].NLayers - 1, -1, -1, mTrkParams[iteration].MaxChi2ClusterAttachment, mTrkParams[0].MaxChi2NDF, 50.);
702 if (!fitSuccess) {
703 track = backup;
704 continue;
705 }
707 mTimeFrame->mNExtendedUsedClusters += track.getNClusters() - backup.getNClusters();
708 auto pattern = track.getPattern();
709 auto diff = (pattern & ~backup.getPattern()) & 0xff;
710 pattern |= (diff << 24);
711 track.setPattern(pattern);
713 for (int iLayer{0}; iLayer < mTrkParams[iteration].NLayers; ++iLayer) {
714 if (track.getClusterIndex(iLayer) == constants::its::UnusedIndex) {
715 continue;
716 }
717 mTimeFrame->markUsedCluster(iLayer, track.getClusterIndex(iLayer));
718 }
719 }
720 }
721 }
722}
723
725{
726 if (!mTrkParams[0].FindShortTracks) {
727 return;
728 }
729 auto propagator = o2::base::Propagator::Instance();
731
732 for (auto& cell : mTimeFrame->getCells()[0]) {
733 auto& cluster3_glo = mTimeFrame->getClusters()[2][cell.getThirdClusterIndex()];
734 auto& cluster2_glo = mTimeFrame->getClusters()[1][cell.getSecondClusterIndex()];
735 auto& cluster1_glo = mTimeFrame->getClusters()[0][cell.getFirstClusterIndex()];
736 if (mTimeFrame->isClusterUsed(2, cluster1_glo.clusterId) ||
737 mTimeFrame->isClusterUsed(1, cluster2_glo.clusterId) ||
738 mTimeFrame->isClusterUsed(0, cluster3_glo.clusterId)) {
739 continue;
740 }
741
742 std::array<int, 3> rofs{
743 mTimeFrame->getClusterROF(2, cluster3_glo.clusterId),
744 mTimeFrame->getClusterROF(1, cluster2_glo.clusterId),
745 mTimeFrame->getClusterROF(0, cluster1_glo.clusterId)};
746 if (rofs[0] != rofs[1] && rofs[1] != rofs[2] && rofs[0] != rofs[2]) {
747 continue;
748 }
749
750 int rof{rofs[0]};
751 if (rofs[1] == rofs[2]) {
752 rof = rofs[2];
753 }
754
755 auto pvs{mTimeFrame->getPrimaryVertices(rof)};
756 auto pvsXAlpha{mTimeFrame->getPrimaryVerticesXAlpha(rof)};
757
758 const auto& cluster3_tf = mTimeFrame->getTrackingFrameInfoOnLayer(2).at(cluster3_glo.clusterId);
759 TrackITSExt temporaryTrack{buildTrackSeed(cluster1_glo, cluster2_glo, cluster3_tf)};
760 temporaryTrack.setExternalClusterIndex(0, cluster1_glo.clusterId, true);
761 temporaryTrack.setExternalClusterIndex(1, cluster2_glo.clusterId, true);
762 temporaryTrack.setExternalClusterIndex(2, cluster3_glo.clusterId, true);
763
765 bool fitSuccess = fitTrack(temporaryTrack, 1, -1, -1);
766 if (!fitSuccess) {
767 continue;
768 }
769 fitSuccess = false;
770
771 TrackITSExt bestTrack{temporaryTrack}, backup{temporaryTrack};
772 float bestChi2{std::numeric_limits<float>::max()};
773 for (int iV{0}; iV < (int)pvs.size(); ++iV) {
774 temporaryTrack = backup;
775 if (!temporaryTrack.rotate(pvsXAlpha[iV][1])) {
776 continue;
777 }
778 if (!propagator->propagateTo(temporaryTrack, pvsXAlpha[iV][0], true)) {
779 continue;
780 }
781
782 float pvRes{mTrkParams[0].PVres / o2::gpu::CAMath::Sqrt(float(pvs[iV].getNContributors()))};
783 const float posVtx[2]{0.f, pvs[iV].getZ()};
784 const float covVtx[3]{pvRes, 0.f, pvRes};
785 float chi2 = temporaryTrack.getPredictedChi2Quiet(posVtx, covVtx);
786 if (chi2 < bestChi2) {
787 if (!temporaryTrack.track::TrackParCov::update(posVtx, covVtx)) {
788 continue;
789 }
790 bestTrack = temporaryTrack;
791 bestChi2 = chi2;
792 }
793 }
794
795 bestTrack.resetCovariance();
796 bestTrack.setChi2(0.f);
797 fitSuccess = fitTrack(bestTrack, 0, mTrkParams[0].NLayers, 1, mTrkParams[0].MaxChi2ClusterAttachment, mTrkParams[0].MaxChi2NDF);
798 if (!fitSuccess) {
799 continue;
800 }
801 bestTrack.getParamOut() = bestTrack;
802 bestTrack.resetCovariance();
803 bestTrack.setChi2(0.f);
804 fitSuccess = fitTrack(bestTrack, mTrkParams[0].NLayers - 1, -1, -1, mTrkParams[0].MaxChi2ClusterAttachment, mTrkParams[0].MaxChi2NDF, 50.);
805 if (!fitSuccess) {
806 continue;
807 }
808 mTimeFrame->markUsedCluster(0, bestTrack.getClusterIndex(0));
809 mTimeFrame->markUsedCluster(1, bestTrack.getClusterIndex(1));
810 mTimeFrame->markUsedCluster(2, bestTrack.getClusterIndex(2));
811 mTimeFrame->getTracks(rof).emplace_back(bestTrack);
812 }
813}
814
815bool TrackerTraits::fitTrack(TrackITSExt& track, int start, int end, int step, float chi2clcut, float chi2ndfcut, float maxQoverPt, int nCl)
816{
817 auto propInstance = o2::base::Propagator::Instance();
818
819 for (int iLayer{start}; iLayer != end; iLayer += step) {
820 if (track.getClusterIndex(iLayer) == constants::its::UnusedIndex) {
821 continue;
822 }
823 const TrackingFrameInfo& trackingHit = mTimeFrame->getTrackingFrameInfoOnLayer(iLayer).at(track.getClusterIndex(iLayer));
824
825 if (!track.rotate(trackingHit.alphaTrackingFrame)) {
826 return false;
827 }
828
829 if (!propInstance->propagateToX(track, trackingHit.xTrackingFrame, getBz(), o2::base::PropagatorImpl<float>::MAX_SIN_PHI, o2::base::PropagatorImpl<float>::MAX_STEP, mCorrType)) {
830 return false;
831 }
832
833 if (mCorrType == o2::base::PropagatorF::MatCorrType::USEMatCorrNONE) {
834 constexpr float radl = 9.36f; // Radiation length of Si [cm]
835 constexpr float rho = 2.33f; // Density of Si [g/cm^3]
836 if (!track.correctForMaterial(mTrkParams[0].LayerxX0[iLayer], mTrkParams[0].LayerxX0[iLayer] * radl * rho, true)) {
837 continue;
838 }
839 }
840
841 auto predChi2{track.getPredictedChi2Quiet(trackingHit.positionTrackingFrame, trackingHit.covarianceTrackingFrame)};
842 if ((nCl >= 3 && predChi2 > chi2clcut) || predChi2 < 0.f) {
843 return false;
844 }
845 track.setChi2(track.getChi2() + predChi2);
846 if (!track.o2::track::TrackParCov::update(trackingHit.positionTrackingFrame, trackingHit.covarianceTrackingFrame)) {
847 return false;
848 }
849 nCl++;
850 }
851 return std::abs(track.getQ2Pt()) < maxQoverPt && track.getChi2() < chi2ndfcut * (nCl * 2 - 5);
852}
853
854bool TrackerTraits::trackFollowing(TrackITSExt* track, int rof, bool outward, const int iteration)
855{
856 auto propInstance = o2::base::Propagator::Instance();
857 const int step = -1 + outward * 2;
858 const int end = outward ? mTrkParams[iteration].NLayers - 1 : 0;
859 std::vector<TrackITSExt> hypotheses(1, *track); // possibly avoid reallocation
860 for (size_t iHypo{0}; iHypo < hypotheses.size(); ++iHypo) {
861 auto hypo{hypotheses[iHypo]};
862 int iLayer = static_cast<int>(outward ? hypo.getLastClusterLayer() : hypo.getFirstClusterLayer());
863 // per layer we add new hypotheses
864 while (iLayer != end) {
865 iLayer += step; // step through all layers until we reach the end, this allows for skipping on empty layers
866 const float r = mTrkParams[iteration].LayerRadii[iLayer];
867 // get an estimate of the trackinf-frame x for the next step
868 float x{-999};
869 if (!hypo.getXatLabR(r, x, mTimeFrame->getBz(), o2::track::DirAuto) || x <= 0.f) {
870 continue;
871 }
872 // estimate hypo's trk parameters at that x
873 auto& hypoParam{outward ? hypo.getParamOut() : hypo.getParamIn()};
874 if (!propInstance->propagateToX(hypoParam, x, mTimeFrame->getBz(), PropagatorF::MAX_SIN_PHI,
875 PropagatorF::MAX_STEP, mTrkParams[iteration].CorrType)) {
876 continue;
877 }
878
879 if (mTrkParams[iteration].CorrType == PropagatorF::MatCorrType::USEMatCorrNONE) { // account for material affects if propagator does not
880 constexpr float radl = 9.36f; // Radiation length of Si [cm]
881 constexpr float rho = 2.33f; // Density of Si [g/cm^3]
882 if (!hypoParam.correctForMaterial(mTrkParams[iteration].LayerxX0[iLayer], mTrkParams[iteration].LayerxX0[iLayer] * radl * rho, true)) {
883 continue;
884 }
885 }
886
887 // calculate the search window on this layer
888 const float phi{hypoParam.getPhi()};
889 const float ePhi{o2::gpu::CAMath::Sqrt(hypoParam.getSigmaSnp2() / hypoParam.getCsp2())};
890 const float z{hypoParam.getZ()};
891 const float eZ{o2::gpu::CAMath::Sqrt(hypoParam.getSigmaZ2())};
892 const int4 selectedBinsRect{getBinsRect(iLayer, phi, mTrkParams[iteration].TrackFollowerNSigmaCutPhi * ePhi, z, mTrkParams[iteration].TrackFollowerNSigmaCutZ * eZ)};
893 if (selectedBinsRect.x == 0 && selectedBinsRect.y == 0 && selectedBinsRect.z == 0 && selectedBinsRect.w == 0) {
894 continue;
895 }
896
897 int phiBinsNum{selectedBinsRect.w - selectedBinsRect.y + 1};
898
899 if (phiBinsNum < 0) {
900 phiBinsNum += mTrkParams[iteration].PhiBins;
901 }
902
903 gsl::span<const Cluster> layer1 = mTimeFrame->getClustersOnLayer(rof, iLayer);
904 if (layer1.empty()) {
905 continue;
906 }
907
908 // check all clusters in search windows for possible new hypotheses
909 for (int iPhiCount = 0; iPhiCount < phiBinsNum; iPhiCount++) {
910 int iPhiBin = (selectedBinsRect.y + iPhiCount) % mTrkParams[iteration].PhiBins;
911 const int firstBinIndex{mTimeFrame->mIndexTableUtils.getBinIndex(selectedBinsRect.x, iPhiBin)};
912 const int maxBinIndex{firstBinIndex + selectedBinsRect.z - selectedBinsRect.x + 1};
913 const int firstRowClusterIndex = mTimeFrame->getIndexTable(rof, iLayer)[firstBinIndex];
914 const int maxRowClusterIndex = mTimeFrame->getIndexTable(rof, iLayer)[maxBinIndex];
915
916 for (int iNextCluster{firstRowClusterIndex}; iNextCluster < maxRowClusterIndex; ++iNextCluster) {
917 if (iNextCluster >= (int)layer1.size()) {
918 break;
919 }
920 const Cluster& nextCluster{layer1[iNextCluster]};
921
922 if (mTimeFrame->isClusterUsed(iLayer, nextCluster.clusterId)) {
923 continue;
924 }
925
926 const TrackingFrameInfo& trackingHit = mTimeFrame->getTrackingFrameInfoOnLayer(iLayer).at(nextCluster.clusterId);
927
928 auto tbupdated{hypo};
929 auto& tbuParams = outward ? tbupdated.getParamOut() : tbupdated.getParamIn();
930 if (!tbuParams.rotate(trackingHit.alphaTrackingFrame)) {
931 continue;
932 }
933
934 if (!propInstance->propagateToX(tbuParams, trackingHit.xTrackingFrame, mTimeFrame->getBz(),
935 PropagatorF::MAX_SIN_PHI, PropagatorF::MAX_STEP, PropagatorF::MatCorrType::USEMatCorrNONE)) {
936 continue;
937 }
938
939 auto predChi2{tbuParams.getPredictedChi2Quiet(trackingHit.positionTrackingFrame, trackingHit.covarianceTrackingFrame)};
940 if (predChi2 >= track->getChi2() * mTrkParams[iteration].NSigmaCut) {
941 continue;
942 }
943
944 if (!tbuParams.o2::track::TrackParCov::update(trackingHit.positionTrackingFrame, trackingHit.covarianceTrackingFrame)) {
945 continue;
946 }
947 tbupdated.setChi2(tbupdated.getChi2() + predChi2);
948 tbupdated.setExternalClusterIndex(iLayer, nextCluster.clusterId, true);
949 hypotheses.emplace_back(tbupdated);
950 }
951 }
952 }
953 }
954
955 TrackITSExt* bestHypo{track};
956 bool swapped{false};
957 for (auto& hypo : hypotheses) {
958 if (hypo.isBetter(*bestHypo, track->getChi2() * mTrkParams[iteration].NSigmaCut)) {
959 bestHypo = &hypo;
960 swapped = true;
961 }
962 }
963 *track = *bestHypo;
964 return swapped;
965}
966
969track::TrackParCov TrackerTraits::buildTrackSeed(const Cluster& cluster1, const Cluster& cluster2, const TrackingFrameInfo& tf3)
970{
971 const float ca = o2::gpu::CAMath::Cos(tf3.alphaTrackingFrame), sa = o2::gpu::CAMath::Sin(tf3.alphaTrackingFrame);
972 const float x1 = cluster1.xCoordinate * ca + cluster1.yCoordinate * sa;
973 const float y1 = -cluster1.xCoordinate * sa + cluster1.yCoordinate * ca;
974 const float z1 = cluster1.zCoordinate;
975 const float x2 = cluster2.xCoordinate * ca + cluster2.yCoordinate * sa;
976 const float y2 = -cluster2.xCoordinate * sa + cluster2.yCoordinate * ca;
977 const float z2 = cluster2.zCoordinate;
978 const float x3 = tf3.xTrackingFrame;
979 const float y3 = tf3.positionTrackingFrame[0];
980 const float z3 = tf3.positionTrackingFrame[1];
981
982 const bool zeroField{std::abs(getBz()) < o2::constants::math::Almost0};
983 const float tgp = zeroField ? o2::gpu::CAMath::ATan2(y3 - y1, x3 - x1) : 1.f;
984 const float crv = zeroField ? 1.f : math_utils::computeCurvature(x3, y3, x2, y2, x1, y1);
985 const float snp = zeroField ? tgp / o2::gpu::CAMath::Sqrt(1.f + tgp * tgp) : crv * (x3 - math_utils::computeCurvatureCentreX(x3, y3, x2, y2, x1, y1));
986 const float tgl12 = math_utils::computeTanDipAngle(x1, y1, x2, y2, z1, z2);
987 const float tgl23 = math_utils::computeTanDipAngle(x2, y2, x3, y3, z2, z3);
988 const float q2pt = zeroField ? 1.f / o2::track::kMostProbablePt : crv / (getBz() * o2::constants::math::B2C);
989 const float q2pt2 = crv * crv;
990 const float sg2q2pt = track::kC1Pt2max * (q2pt2 > 0.0005 ? (q2pt2 < 1 ? q2pt2 : 1) : 0.0005);
991 return track::TrackParCov(tf3.xTrackingFrame, tf3.alphaTrackingFrame,
992 {y3, z3, snp, 0.5f * (tgl12 + tgl23), q2pt},
993 {tf3.covarianceTrackingFrame[0],
994 tf3.covarianceTrackingFrame[1], tf3.covarianceTrackingFrame[2],
995 0.f, 0.f, track::kCSnp2max,
996 0.f, 0.f, 0.f, track::kCTgl2max,
997 0.f, 0.f, 0.f, 0.f, sg2q2pt});
998}
999
1001{
1002 mBz = bz;
1003 mTimeFrame->setBz(bz);
1004}
1005
1007
1009{
1010#ifdef WITH_OPENMP
1011 mNThreads = n > 0 ? n : 1;
1012#else
1013 mNThreads = 1;
1014#endif
1015}
1016
1021
1026
1028{
1029 return mTimeFrame->getNumberOfCells();
1030}
1031
1036
1037} // namespace its
1038} // namespace o2
Base track model for the Barrel, params only, w/o covariance.
#define CA_DEBUGGER(x)
Definition Definitions.h:34
#define failed(...)
Definition Utils.h:42
useful math constants
GPUd() value_type estimateLTFast(o2 static GPUd() float estimateLTIncrement(const o2 PropagatorImpl * Instance(bool uninitialized=false)
Definition Propagator.h:143
gsl::span< const Vertex > getPrimaryVertices(int rofId) const
Definition TimeFrame.h:355
void fillPrimaryVerticesXandAlpha()
bool isClusterUsed(int layer, int clusterId) const
Definition TimeFrame.h:570
IndexTableUtils mIndexTableUtils
Definition TimeFrame.h:264
std::vector< std::vector< int > > & getCellsLookupTable()
Definition TimeFrame.h:650
void markUsedCluster(int layer, int clusterId)
Definition TimeFrame.h:580
std::vector< std::vector< CellSeed > > & getCells()
Definition TimeFrame.h:648
std::vector< std::vector< Cluster > > & getClusters()
Definition TimeFrame.h:638
gsl::span< int > getIndexTable(int rofId, int layerId)
Definition TimeFrame.h:529
float getBz() const
Definition TimeFrame.h:223
std::vector< std::vector< Cluster > > & getUnsortedClusters()
Definition TimeFrame.h:643
int getNumberOfTracklets() const
Definition TimeFrame.h:705
int getNumberOfClusters() const
Definition TimeFrame.h:687
int getClusterROF(int iLayer, int iCluster)
Definition TimeFrame.h:485
std::vector< MCCompLabel > & getCellsLabel(int layer)
Definition TimeFrame.h:142
std::vector< TrackITSExt > & getTracks(int rofId)
Definition TimeFrame.h:169
std::vector< std::vector< int > > & getCellsNeighboursLUT()
Definition TimeFrame.h:656
gsl::span< Cluster > getClustersOnLayer(int rofId, int layerId)
Definition TimeFrame.h:413
int getNrof() const
Definition TimeFrame.h:395
std::vector< std::vector< int > > & getCellsNeighbours()
Definition TimeFrame.h:655
const std::vector< TrackingFrameInfo > & getTrackingFrameInfoOnLayer(int layerId) const
Definition TimeFrame.h:499
gsl::span< const std::array< float, 2 > > getPrimaryVerticesXAlpha(int rofId) const
Definition TimeFrame.h:376
int getNumberOfCells() const
Definition TimeFrame.h:696
void setBz(float bz)
Definition TimeFrame.h:222
virtual void findRoads(const int iteration)
virtual void processNeighbours(int iLayer, int iLevel, const std::vector< CellSeed > &currentCellSeed, const std::vector< int > &currentCellId, std::vector< CellSeed > &updatedCellSeed, std::vector< int > &updatedCellId)
virtual void extendTracks(const int iteration)
virtual int getTFNumberOfCells() const
virtual void adoptTimeFrame(TimeFrame *tf)
virtual void computeLayerTracklets(const int iteration, int iROFslice, int iVertex)
virtual void setBz(float bz)
virtual int getTFNumberOfTracklets() const
virtual void findCellsNeighbours(const int iteration)
virtual int getTFNumberOfClusters() const
virtual void findShortPrimaries()
const int4 getBinsRect(const Cluster &, int layer, float z1, float z2, float maxdeltaz, float maxdeltaphi) const noexcept
std::vector< TrackingParameters > mTrkParams
o2::base::PropagatorImpl< float >::MatCorrType mCorrType
virtual bool trackFollowing(TrackITSExt *track, int rof, bool outward, const int iteration)
virtual void computeLayerCells(const int iteration)
GLdouble n
Definition glcorearb.h:1982
GLint GLenum GLint x
Definition glcorearb.h:403
GLuint GLfloat GLfloat GLfloat GLfloat y1
Definition glcorearb.h:5034
GLuint GLuint end
Definition glcorearb.h:469
GLuint GLfloat GLfloat GLfloat x1
Definition glcorearb.h:5034
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
GLuint GLsizei const GLchar * label
Definition glcorearb.h:2519
GLboolean r
Definition glcorearb.h:1233
GLuint start
Definition glcorearb.h:469
GLboolean GLboolean GLboolean GLboolean a
Definition glcorearb.h:1233
GLdouble GLdouble GLdouble z
Definition glcorearb.h:843
constexpr float Almost0
constexpr float B2C
constexpr int UnusedIndex
Definition Constants.h:52
constexpr float TwoPi
Definition Constants.h:44
constexpr int debugLevel
TrackParCovF TrackParCov
Definition Track.h:33
constexpr float kMostProbablePt
value_T rho
Definition TrackUtils.h:36
constexpr float kC1Pt2max
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
std::unique_ptr< GPUReconstructionTimeframe > tf
int32_t w
float yCoordinate
Definition Cluster.h:45
float zCoordinate
Definition Cluster.h:46
float xCoordinate
Definition Cluster.h:44
std::array< uint16_t, 5 > pattern