85 const int startVtx = iVertex >= 0 ? iVertex : 0;
86 const int endVtx = iVertex >= 0 ? o2::gpu::CAMath::Min(iVertex + 1,
int(primaryVertices.size())) :
int(primaryVertices.
size());
87 if (endVtx <= startVtx) {
92 auto&
tracklets = mTimeFrame->getTracklets()[iLayer];
93 auto layer0 = mTimeFrame->getClustersOnLayer(pivotROF, iLayer);
98 const float meanDeltaR = mTrkParams[iteration].LayerRadii[iLayer + 1] - mTrkParams[iteration].LayerRadii[iLayer];
100 for (
int iCluster = 0; iCluster <
int(layer0.size()); ++iCluster) {
101 const Cluster& currentCluster = layer0[iCluster];
102 const int currentSortedIndex = mTimeFrame->getSortedIndex(pivotROF, iLayer, iCluster);
103 if (mTimeFrame->isClusterUsed(iLayer, currentCluster.clusterId)) {
106 const float inverseR0 = 1.f / currentCluster.radius;
108 for (
int iV = startVtx; iV < endVtx; ++iV) {
109 const auto& pv = primaryVertices[iV];
114 const float resolution = o2::gpu::CAMath::Sqrt(math_utils::Sq(mTimeFrame->getPositionResolution(iLayer)) + math_utils::Sq(mTrkParams[iteration].PVres) /
float(pv.getNContributors()));
115 const float tanLambda = (currentCluster.zCoordinate - pv.getZ()) * inverseR0;
116 const float zAtRmin = tanLambda * (mTimeFrame->getMinR(iLayer + 1) - currentCluster.radius) + currentCluster.zCoordinate;
117 const float zAtRmax = tanLambda * (mTimeFrame->getMaxR(iLayer + 1) - currentCluster.radius) + currentCluster.zCoordinate;
118 const float sqInvDeltaZ0 = 1.f / (math_utils::Sq(currentCluster.zCoordinate - pv.getZ()) + constants::Tolerance);
119 const float sigmaZ = o2::gpu::CAMath::Sqrt(
120 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)));
122 auto bins = getBinsRect(currentCluster, iLayer + 1, zAtRmin, zAtRmax, sigmaZ * mTrkParams[iteration].NSigmaCut, mTimeFrame->getPhiCut(iLayer));
126 int phiBinsNum =
bins.w -
bins.y + 1;
127 if (phiBinsNum < 0) {
128 phiBinsNum += mTrkParams[iteration].PhiBins;
131 for (
int targetROF{minROF}; targetROF <= maxROF; ++targetROF) {
132 if (!mTimeFrame->mMultiplicityCutMask[targetROF]) {
135 auto layer1 = mTimeFrame->getClustersOnLayer(targetROF, iLayer + 1);
136 if (layer1.empty()) {
139 for (
int iPhi = 0; iPhi < phiBinsNum; ++iPhi) {
140 const int iPhiBin = (
bins.y + iPhi) % mTrkParams[iteration].PhiBins;
141 const int firstBinIdx = mTimeFrame->mIndexTableUtils.getBinIndex(
bins.x, iPhiBin);
142 const int maxBinIdx = firstBinIdx + (
bins.z -
bins.x) + 1;
143 const int firstRow = mTimeFrame->getIndexTable(targetROF, iLayer + 1)[firstBinIdx];
144 const int lastRow = mTimeFrame->getIndexTable(targetROF, iLayer + 1)[maxBinIdx];
145 for (
int iNext = firstRow; iNext < lastRow; ++iNext) {
146 if (iNext >=
int(layer1.size())) {
149 const Cluster& nextCluster = layer1[iNext];
150 if (mTimeFrame->isClusterUsed(iLayer + 1, nextCluster.clusterId)) {
153 float deltaPhi = o2::gpu::GPUCommonMath::Abs(currentCluster.phi - nextCluster.phi);
154 float deltaZ = o2::gpu::GPUCommonMath::Abs((tanLambda * (nextCluster.radius - currentCluster.radius)) + currentCluster.zCoordinate - nextCluster.zCoordinate);
156#ifdef OPTIMISATION_OUTPUT
158 int currentId{currentCluster.clusterId};
159 int nextId{nextCluster.clusterId};
160 for (
auto& lab1 : mTimeFrame->getClusterLabels(iLayer, currentId)) {
161 for (
auto& lab2 : mTimeFrame->getClusterLabels(iLayer + 1, nextId)) {
162 if (lab1 == lab2 && lab1.isValid()) {
167 if (
label.isValid()) {
171 off << std::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;
174 if (deltaZ / sigmaZ < mTrkParams[iteration].NSigmaCut &&
175 ((deltaPhi < mTimeFrame->getPhiCut(iLayer) || o2::gpu::GPUCommonMath::Abs(deltaPhi -
o2::constants::math::TwoPI) < mTimeFrame->getPhiCut(iLayer)))) {
176 const float phi{o2::gpu::CAMath::ATan2(currentCluster.yCoordinate - nextCluster.yCoordinate, currentCluster.xCoordinate - nextCluster.xCoordinate)};
177 const float tanL = (currentCluster.zCoordinate - nextCluster.zCoordinate) / (currentCluster.radius - nextCluster.radius);
178 if constexpr (
decltype(Tag)
::value == PassMode::OnePass::value) {
179 tracklets.emplace_back(currentSortedIndex, mTimeFrame->getSortedIndex(targetROF, iLayer + 1, iNext), tanL,
phi, pivotROF, targetROF);
180 }
else if constexpr (
decltype(Tag)
::value == PassMode::TwoPassCount::value) {
182 }
else if constexpr (
decltype(Tag)
::value == PassMode::TwoPassInsert::value) {
184 tracklets[
idx] = Tracklet(currentSortedIndex, mTimeFrame->getSortedIndex(targetROF, iLayer + 1, iNext), tanL, phi, pivotROF, targetROF);
196 if (mTaskArena->max_concurrency() <= 1) {
197 for (
int pivotROF{startROF}; pivotROF < endROF; ++pivotROF) {
198 for (
int iLayer{0}; iLayer < mTrkParams[iteration].TrackletsPerRoad(); ++iLayer) {
203 bounded_vector<bounded_vector<int>> perROFCount(mTrkParams[iteration].
TrackletsPerRoad(), bounded_vector<int>(endROF - startROF + 1, 0, mMemoryPool.get()), mMemoryPool.get());
205 tbb::blocked_range2d<int, int>(0, mTrkParams[iteration].
TrackletsPerRoad(), 1,
206 startROF, endROF, 1),
207 [&](
auto const& Range) {
208 for (
int iLayer{Range.rows().
begin()}; iLayer < Range.rows().
end(); ++iLayer) {
209 for (
int pivotROF = Range.cols().begin(); pivotROF < Range.cols().end(); ++pivotROF) {
210 perROFCount[iLayer][pivotROF - startROF] = forTracklets(
PassMode::TwoPassCount{}, iLayer, pivotROF, 0, dummy);
215 tbb::parallel_for(0, mTrkParams[iteration].
TrackletsPerRoad(), [&](
const int iLayer) {
216 std::exclusive_scan(perROFCount[iLayer].
begin(), perROFCount[iLayer].
end(), perROFCount[iLayer].
begin(), 0);
217 mTimeFrame->getTracklets()[iLayer].resize(perROFCount[iLayer].back());
221 tbb::blocked_range2d<int, int>(0, mTrkParams[iteration].
TrackletsPerRoad(), 1,
222 startROF, endROF, 1),
223 [&](
auto const& Range) {
224 for (
int iLayer{Range.rows().
begin()}; iLayer < Range.rows().
end(); ++iLayer) {
225 if (perROFCount[iLayer].back() == 0) {
228 for (
int pivotROF = Range.cols().begin(); pivotROF < Range.cols().end(); ++pivotROF) {
229 int baseIdx = perROFCount[iLayer][pivotROF - startROF];
230 if (baseIdx == perROFCount[iLayer][pivotROF - startROF + 1]) {
240 tbb::parallel_for(0, mTrkParams[iteration].
TrackletsPerRoad(), [&](
const int iLayer) {
242 auto& trkl{mTimeFrame->getTracklets()[iLayer]};
243 tbb::parallel_sort(trkl.begin(), trkl.end(), [](
const Tracklet&
a,
const Tracklet&
b) ->
bool {
244 if (a.firstClusterIndex != b.firstClusterIndex) {
245 return a.firstClusterIndex < b.firstClusterIndex;
247 return a.secondClusterIndex <
b.secondClusterIndex;
250 trkl.erase(std::unique(trkl.begin(), trkl.end(), [](
const Tracklet&
a,
const Tracklet&
b) ->
bool {
251 return a.firstClusterIndex == b.firstClusterIndex && a.secondClusterIndex == b.secondClusterIndex;
254 trkl.shrink_to_fit();
256 auto& lut{mTimeFrame->getTrackletsLookupTable()[iLayer - 1]};
258 for (
const auto& tkl : trkl) {
259 lut[tkl.firstClusterIndex + 1]++;
261 std::inclusive_scan(lut.begin(), lut.end(), lut.begin());
267 if (mTimeFrame->hasMCinformation() && mTrkParams[iteration].createArtefactLabels) {
268 tbb::parallel_for(0, mTrkParams[iteration].
TrackletsPerRoad(), [&](
const int iLayer) {
269 for (
auto& trk : mTimeFrame->getTracklets()[iLayer]) {
271 int currentId{mTimeFrame->getClusters()[iLayer][trk.firstClusterIndex].clusterId};
272 int nextId{mTimeFrame->getClusters()[iLayer + 1][trk.secondClusterIndex].clusterId};
273 for (
const auto& lab1 : mTimeFrame->getClusterLabels(iLayer, currentId)) {
274 for (
const auto& lab2 : mTimeFrame->getClusterLabels(iLayer + 1, nextId)) {
275 if (lab1 == lab2 && lab1.isValid()) {
280 if (
label.isValid()) {
284 mTimeFrame->getTrackletsLabel(iLayer).emplace_back(
label);
291template <
int nLayers>
294#ifdef OPTIMISATION_OUTPUT
296 std::ofstream off(std::format(
"cells{}.txt", iter++));
299 for (
int iLayer = 0; iLayer < mTrkParams[iteration].CellsPerRoad(); ++iLayer) {
304 if (mTimeFrame->hasMCinformation() && mTrkParams[iteration].createArtefactLabels) {
309 mTaskArena->execute([&] {
311 const Tracklet& currentTracklet{mTimeFrame->getTracklets()[iLayer][iTracklet]};
313 const int nextLayerFirstTrackletIndex{mTimeFrame->getTrackletsLookupTable()[iLayer][nextLayerClusterIndex]};
314 const int nextLayerLastTrackletIndex{mTimeFrame->getTrackletsLookupTable()[iLayer][nextLayerClusterIndex + 1]};
316 for (
int iNextTracklet{nextLayerFirstTrackletIndex}; iNextTracklet < nextLayerLastTrackletIndex; ++iNextTracklet) {
317 const Tracklet& nextTracklet{mTimeFrame->getTracklets()[iLayer + 1][iNextTracklet]};
318 const auto& nextLbl = mTimeFrame->getTrackletsLabel(iLayer + 1)[iNextTracklet];
319 if (mTimeFrame->getTracklets()[iLayer + 1][iNextTracklet].firstClusterIndex != nextLayerClusterIndex) {
322 if (mTrkParams[iteration].DeltaROF && currentTracklet.getSpanRof(nextTracklet) > mTrkParams[iteration].DeltaROF) {
325 const float deltaTanLambda{std::abs(currentTracklet.tanLambda - nextTracklet.tanLambda)};
327#ifdef OPTIMISATION_OUTPUT
328 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]};
329 resolution = resolution > 1.e-12 ? resolution : 1.f;
330 bool good{mTimeFrame->getTrackletsLabel(iLayer)[iTracklet] == mTimeFrame->getTrackletsLabel(iLayer + 1)[iNextTracklet]};
331 float signedDelta{currentTracklet.
tanLambda - nextTracklet.tanLambda};
332 off << std::format(
"{}\t{:d}\t{}\t{}\t{}\t{}", iLayer, good, signedDelta, signedDelta / (mTrkParams[iteration].CellDeltaTanLambdaSigma), tanLambda, resolution) << std::endl;
335 if (deltaTanLambda / mTrkParams[iteration].CellDeltaTanLambdaSigma < mTrkParams[iteration].NSigmaCut) {
339 mTimeFrame->getClusters()[iLayer][currentTracklet.firstClusterIndex].clusterId,
340 mTimeFrame->getClusters()[iLayer + 1][nextTracklet.firstClusterIndex].clusterId,
341 mTimeFrame->getClusters()[iLayer + 2][nextTracklet.secondClusterIndex].clusterId};
342 const auto& cluster1_glo = mTimeFrame->getUnsortedClusters()[iLayer][clusId[0]];
343 const auto& cluster2_glo = mTimeFrame->getUnsortedClusters()[iLayer + 1][clusId[1]];
344 const auto& cluster3_tf = mTimeFrame->getTrackingFrameInfoOnLayer(iLayer + 2)[clusId[2]];
345 auto track{buildTrackSeed(cluster1_glo, cluster2_glo, cluster3_tf)};
349 for (
int iC{2}; iC--;) {
350 const TrackingFrameInfo& trackingHit = mTimeFrame->getTrackingFrameInfoOnLayer(iLayer + iC)[clusId[iC]];
360 if (!track.correctForMaterial(mTrkParams[0].LayerxX0[iLayer + iC], mTrkParams[0].LayerxX0[iLayer] * constants::Radl * constants::Rho,
true)) {
365 if (!iC && predChi2 > mTrkParams[iteration].MaxChi2ClusterAttachment) {
377 if constexpr (
decltype(Tag)
::value == PassMode::OnePass::value) {
378 layerCells.emplace_back(iLayer, clusId[0], clusId[1], clusId[2], iTracklet, iNextTracklet, track, chi2);
380 }
else if constexpr (
decltype(Tag)
::value == PassMode::TwoPassCount::value) {
382 }
else if constexpr (
decltype(Tag)
::value == PassMode::TwoPassInsert::value) {
383 layerCells[
offset++] =
CellSeedN(iLayer, clusId[0], clusId[1], clusId[2], iTracklet, iNextTracklet, track, chi2);
385 static_assert(
false,
"Unknown mode!");
393 tbb::parallel_for(0, mTrkParams[iteration].CellsPerRoad(), [&](
const int iLayer) {
394 if (mTimeFrame->getTracklets()[iLayer + 1].empty() ||
395 mTimeFrame->getTracklets()[iLayer].empty()) {
399 auto& layerCells = mTimeFrame->getCells()[iLayer];
400 const int currentLayerTrackletsNum{
static_cast<int>(mTimeFrame->getTracklets()[iLayer].size())};
402 if (mTaskArena->max_concurrency() <= 1) {
403 for (
int iTracklet{0}; iTracklet < currentLayerTrackletsNum; ++iTracklet) {
404 perTrackletCount[iTracklet] = forTrackletCells(
PassMode::OnePass{}, iLayer, layerCells, iTracklet);
406 std::exclusive_scan(perTrackletCount.begin(), perTrackletCount.end(), perTrackletCount.begin(), 0);
408 tbb::parallel_for(0, currentLayerTrackletsNum, [&](
const int iTracklet) {
412 std::exclusive_scan(perTrackletCount.begin(), perTrackletCount.end(), perTrackletCount.begin(), 0);
413 auto totalCells{perTrackletCount.back()};
414 if (totalCells == 0) {
417 layerCells.resize(totalCells);
419 tbb::parallel_for(0, currentLayerTrackletsNum, [&](
const int iTracklet) {
420 int offset = perTrackletCount[iTracklet];
421 if (
offset == perTrackletCount[iTracklet + 1]) {
429 auto& lut = mTimeFrame->getCellsLookupTable()[iLayer - 1];
430 lut.resize(currentLayerTrackletsNum + 1);
431 std::copy_n(perTrackletCount.begin(), currentLayerTrackletsNum + 1, lut.begin());
436 if (mTimeFrame->hasMCinformation() && mTrkParams[iteration].createArtefactLabels) {
437 tbb::parallel_for(0, mTrkParams[iteration].CellsPerRoad(), [&](
const int iLayer) {
438 mTimeFrame->getCellsLabel(iLayer).reserve(mTimeFrame->getCells()[iLayer].size());
439 for (
const auto& cell : mTimeFrame->getCells()[iLayer]) {
440 MCCompLabel currentLab{mTimeFrame->getTrackletsLabel(iLayer)[cell.getFirstTrackletIndex()]};
441 MCCompLabel nextLab{mTimeFrame->getTrackletsLabel(iLayer + 1)[cell.getSecondTrackletIndex()]};
442 mTimeFrame->getCellsLabel(iLayer).emplace_back(currentLab == nextLab ? currentLab :
MCCompLabel());
449template <
int nLayers>
452#ifdef OPTIMISATION_OUTPUT
453 std::ofstream off(std::format(
"cellneighs{}.txt", iteration));
457 int cell{-1}, nextCell{-1},
level{-1};
460 mTaskArena->execute([&] {
461 for (
int iLayer{0}; iLayer < mTrkParams[iteration].NeighboursPerRoad(); ++iLayer) {
464 if (mTimeFrame->getCells()[iLayer + 1].empty() ||
465 mTimeFrame->getCellsLookupTable()[iLayer].empty()) {
469 int nCells{
static_cast<int>(mTimeFrame->getCells()[iLayer].size())};
472 auto forCellNeighbour = [&](
auto Tag,
int iCell,
int offset = 0) ->
int {
473 const auto& currentCellSeed{mTimeFrame->getCells()[iLayer][iCell]};
474 const int nextLayerTrackletIndex{currentCellSeed.getSecondTrackletIndex()};
475 const int nextLayerFirstCellIndex{mTimeFrame->getCellsLookupTable()[iLayer][nextLayerTrackletIndex]};
476 const int nextLayerLastCellIndex{mTimeFrame->getCellsLookupTable()[iLayer][nextLayerTrackletIndex + 1]};
477 int foundNextCells{0};
478 for (
int iNextCell{nextLayerFirstCellIndex}; iNextCell < nextLayerLastCellIndex; ++iNextCell) {
479 auto nextCellSeed{mTimeFrame->getCells()[iLayer + 1][iNextCell]};
480 if (nextCellSeed.getFirstTrackletIndex() != nextLayerTrackletIndex) {
484 if (mTrkParams[iteration].DeltaROF) {
485 const auto& trkl00 = mTimeFrame->getTracklets()[iLayer][currentCellSeed.getFirstTrackletIndex()];
486 const auto& trkl01 = mTimeFrame->getTracklets()[iLayer + 1][currentCellSeed.getSecondTrackletIndex()];
487 const auto& trkl10 = mTimeFrame->getTracklets()[iLayer + 1][nextCellSeed.getFirstTrackletIndex()];
488 const auto& trkl11 = mTimeFrame->getTracklets()[iLayer + 2][nextCellSeed.getSecondTrackletIndex()];
489 if ((std::max({trkl00.getMaxRof(), trkl01.getMaxRof(), trkl10.getMaxRof(), trkl11.getMaxRof()}) -
490 std::min({trkl00.getMinRof(), trkl01.getMinRof(), trkl10.getMinRof(), trkl11.getMinRof()})) > mTrkParams[0].DeltaROF) {
495 if (!nextCellSeed.rotate(currentCellSeed.getAlpha()) ||
496 !nextCellSeed.propagateTo(currentCellSeed.getX(), getBz())) {
499 float chi2 = currentCellSeed.getPredictedChi2(nextCellSeed);
501#ifdef OPTIMISATION_OUTPUT
502 bool good{mTimeFrame->getCellsLabel(iLayer)[iCell] == mTimeFrame->getCellsLabel(iLayer + 1)[iNextCell]};
503 off << std::format(
"{}\t{:d}\t{}", iLayer, good, chi2) << std::endl;
506 if (chi2 > mTrkParams[0].MaxChi2ClusterAttachment) {
510 if constexpr (
decltype(Tag)
::value == PassMode::OnePass::value) {
511 cellsNeighbours.emplace_back(iCell, iNextCell, currentCellSeed.getLevel() + 1);
512 }
else if constexpr (
decltype(Tag)
::value == PassMode::TwoPassCount::value) {
514 }
else if constexpr (
decltype(Tag)
::value == PassMode::TwoPassInsert::value) {
515 cellsNeighbours[
offset++] = {iCell, iNextCell, currentCellSeed.getLevel() + 1};
517 static_assert(
false,
"Unknown mode!");
520 return foundNextCells;
523 if (mTaskArena->max_concurrency() <= 1) {
524 for (
int iCell{0}; iCell < nCells; ++iCell) {
529 tbb::parallel_for(0, nCells, [&](
const int iCell) {
533 std::exclusive_scan(perCellCount.begin(), perCellCount.end(), perCellCount.begin(), 0);
534 int totalCellNeighbours = perCellCount.back();
535 if (totalCellNeighbours == 0) {
539 cellsNeighbours.resize(totalCellNeighbours);
541 tbb::parallel_for(0, nCells, [&](
const int iCell) {
542 int offset = perCellCount[iCell];
543 if (
offset == perCellCount[iCell + 1]) {
550 if (cellsNeighbours.empty()) {
554 tbb::parallel_sort(cellsNeighbours.begin(), cellsNeighbours.end(), [](
const auto&
a,
const auto&
b) {
555 return a.nextCell < b.nextCell;
558 auto& cellsNeighbourLUT = mTimeFrame->getCellsNeighboursLUT()[iLayer];
559 cellsNeighbourLUT.assign(mTimeFrame->getCells()[iLayer + 1].size(), 0);
560 for (
const auto& neigh : cellsNeighbours) {
561 ++cellsNeighbourLUT[neigh.nextCell];
563 std::inclusive_scan(cellsNeighbourLUT.begin(), cellsNeighbourLUT.end(), cellsNeighbourLUT.begin());
565 mTimeFrame->getCellsNeighbours()[iLayer].reserve(cellsNeighbours.size());
566 std::ranges::transform(cellsNeighbours, std::back_inserter(mTimeFrame->getCellsNeighbours()[iLayer]), [](
const auto& neigh) { return neigh.cell; });
568 for (
auto it = cellsNeighbours.begin(); it != cellsNeighbours.end();) {
569 int cellIdx = it->nextCell;
570 int maxLvl = it->level;
571 while (++it != cellsNeighbours.end() && it->nextCell == cellIdx) {
572 maxLvl = std::max(maxLvl, it->level);
574 mTimeFrame->getCells()[iLayer + 1][cellIdx].setLevel(maxLvl);
580template <
int nLayers>
583 CA_DEBUGGER(std::cout <<
"Processing neighbours layer " << iLayer <<
" level " << iLevel <<
", size of the cell seeds: " << currentCellSeed.size() << std::endl);
587 int failed[5]{0, 0, 0, 0, 0}, attempts{0}, failedByMismatch{0};
590 mTaskArena->execute([&] {
591 auto forCellNeighbours = [&](
auto Tag,
int iCell,
int offset = 0) ->
int {
592 const auto& currentCell{currentCellSeed[iCell]};
594 if constexpr (
decltype(Tag)
::value != PassMode::TwoPassInsert::value) {
595 if (currentCell.getLevel() != iLevel) {
598 if (currentCellId.empty() && (mTimeFrame->isClusterUsed(iLayer, currentCell.getFirstClusterIndex()) ||
599 mTimeFrame->isClusterUsed(iLayer + 1, currentCell.getSecondClusterIndex()) ||
600 mTimeFrame->isClusterUsed(iLayer + 2, currentCell.getThirdClusterIndex()))) {
605 const int cellId = currentCellId.empty() ? iCell : currentCellId[iCell];
606 const int startNeighbourId{cellId ? mTimeFrame->getCellsNeighboursLUT()[iLayer - 1][cellId - 1] : 0};
607 const int endNeighbourId{mTimeFrame->getCellsNeighboursLUT()[iLayer - 1][cellId]};
609 for (
int iNeighbourCell{startNeighbourId}; iNeighbourCell < endNeighbourId; ++iNeighbourCell) {
611 const int neighbourCellId = mTimeFrame->getCellsNeighbours()[iLayer - 1][iNeighbourCell];
612 const auto& neighbourCell = mTimeFrame->getCells()[iLayer - 1][neighbourCellId];
613 if (neighbourCell.getSecondTrackletIndex() != currentCell.getFirstTrackletIndex()) {
617 if (mTimeFrame->isClusterUsed(iLayer - 1, neighbourCell.getFirstClusterIndex())) {
620 if (currentCell.getLevel() - 1 != neighbourCell.getLevel()) {
627 const auto& trHit = mTimeFrame->getTrackingFrameInfoOnLayer(iLayer - 1)[neighbourCell.getFirstClusterIndex()];
629 if (!seed.rotate(trHit.alphaTrackingFrame)) {
639 if (mTrkParams[0].CorrType == o2::base::PropagatorF::MatCorrType::USEMatCorrNONE) {
640 if (!seed.correctForMaterial(mTrkParams[0].LayerxX0[iLayer - 1], mTrkParams[0].LayerxX0[iLayer - 1] * constants::Radl * constants::Rho,
true)) {
645 auto predChi2{seed.getPredictedChi2Quiet(trHit.positionTrackingFrame, trHit.covarianceTrackingFrame)};
646 if ((predChi2 > mTrkParams[0].MaxChi2ClusterAttachment) || predChi2 < 0.f) {
650 seed.setChi2(seed.getChi2() + predChi2);
651 if (!seed.o2::track::TrackParCov::update(trHit.positionTrackingFrame, trHit.covarianceTrackingFrame)) {
656 if constexpr (
decltype(Tag)
::value != PassMode::TwoPassCount::value) {
657 seed.getClusters()[iLayer - 1] = neighbourCell.getFirstClusterIndex();
658 seed.setLevel(neighbourCell.getLevel());
659 seed.setFirstTrackletIndex(neighbourCell.getFirstTrackletIndex());
660 seed.setSecondTrackletIndex(neighbourCell.getSecondTrackletIndex());
663 if constexpr (
decltype(Tag)
::value == PassMode::OnePass::value) {
664 updatedCellSeeds.push_back(seed);
665 updatedCellsIds.push_back(neighbourCellId);
666 }
else if constexpr (
decltype(Tag)
::value == PassMode::TwoPassCount::value) {
668 }
else if constexpr (
decltype(Tag)
::value == PassMode::TwoPassInsert::value) {
669 updatedCellSeeds[
offset] = seed;
670 updatedCellsIds[
offset++] = neighbourCellId;
672 static_assert(
false,
"Unknown mode!");
678 const int nCells =
static_cast<int>(currentCellSeed.size());
679 if (mTaskArena->max_concurrency() <= 1) {
680 for (
int iCell{0}; iCell < nCells; ++iCell) {
685 tbb::parallel_for(0, nCells, [&](
const int iCell) {
689 std::exclusive_scan(perCellCount.begin(), perCellCount.end(), perCellCount.begin(), 0);
690 auto totalNeighbours{perCellCount.back()};
691 if (totalNeighbours == 0) {
694 updatedCellSeeds.resize(totalNeighbours);
695 updatedCellsIds.resize(totalNeighbours);
697 tbb::parallel_for(0, nCells, [&](
const int iCell) {
698 int offset = perCellCount[iCell];
699 if (
offset == perCellCount[iCell + 1]) {
708 std::cout <<
"\t\t- Found " << updatedCellSeeds.size() <<
" cell seeds out of " << attempts <<
" attempts" << std::endl;
709 std::cout <<
"\t\t\t> " <<
failed[0] <<
" failed because of level" << std::endl;
710 std::cout <<
"\t\t\t> " <<
failed[1] <<
" failed because of rotation" << std::endl;
711 std::cout <<
"\t\t\t> " <<
failed[2] <<
" failed because of propagation" << std::endl;
712 std::cout <<
"\t\t\t> " <<
failed[3] <<
" failed because of chi2 cut" << std::endl;
713 std::cout <<
"\t\t\t> " <<
failed[4] <<
" failed because of update" << std::endl;
714 std::cout <<
"\t\t\t> " << failedByMismatch <<
" failed because of mismatch" << std::endl;
718template <
int nLayers>
723 firstClusters.resize(mTrkParams[iteration].NLayers);
724 sharedFirstClusters.resize(mTrkParams[iteration].NLayers);
725 for (
int startLevel{mTrkParams[iteration].CellsPerRoad()}; startLevel >= mTrkParams[iteration].CellMinimumLevel(); --startLevel) {
727 auto seedFilter = [&](
const auto& seed) {
728 return seed.getQ2Pt() <= 1.e3 && seed.getChi2() <= mTrkParams[0].MaxChi2NDF * ((startLevel + 2) * 2 - 5);
732 for (
int startLayer{mTrkParams[iteration].NeighboursPerRoad()}; startLayer >= startLevel - 1; --startLayer) {
733 if ((mTrkParams[iteration].StartLayerMask & (1 << (startLayer + 2))) == 0) {
740 processNeighbours(startLayer, startLevel, mTimeFrame->getCells()[startLayer], lastCellId, updatedCellSeed, updatedCellId);
742 int level = startLevel;
743 for (
int iLayer{startLayer - 1}; iLayer > 0 &&
level > 2; --iLayer) {
744 lastCellSeed.swap(updatedCellSeed);
745 lastCellId.swap(updatedCellId);
748 processNeighbours(iLayer, --
level, lastCellSeed, lastCellId, updatedCellSeed, updatedCellId);
753 if (!updatedCellSeed.empty()) {
754 trackSeeds.reserve(trackSeeds.size() + std::count_if(updatedCellSeed.begin(), updatedCellSeed.end(), seedFilter));
755 std::copy_if(updatedCellSeed.begin(), updatedCellSeed.end(), std::back_inserter(trackSeeds), seedFilter);
759 if (trackSeeds.empty()) {
764 mTaskArena->execute([&] {
765 auto forSeed = [&](
auto Tag,
int iSeed,
int offset = 0) {
766 TrackITSExt temporaryTrack = seedTrackForRefit(trackSeeds[iSeed]);
768 bool fitSuccess = fitTrack(temporaryTrack, 0, mTrkParams[0].NLayers, 1, mTrkParams[0].MaxChi2ClusterAttachment, mTrkParams[0].MaxChi2NDF,
o2::constants::math::VeryBig, 0, &linRef);
772 temporaryTrack.getParamOut() = temporaryTrack.getParamIn();
773 linRef = temporaryTrack.getParamOut();
774 temporaryTrack.resetCovariance();
776 temporaryTrack.setChi2(0);
777 fitSuccess = fitTrack(temporaryTrack, mTrkParams[0].NLayers - 1, -1, -1, mTrkParams[0].MaxChi2ClusterAttachment, mTrkParams[0].MaxChi2NDF, 50.f, 0, &linRef);
778 if (!fitSuccess || temporaryTrack.getPt() < mTrkParams[iteration].MinPt[mTrkParams[iteration].NLayers - temporaryTrack.getNClusters()]) {
781 if constexpr (
decltype(Tag)
::value == PassMode::OnePass::value) {
782 tracks.push_back(temporaryTrack);
783 }
else if constexpr (
decltype(Tag)
::value == PassMode::TwoPassCount::value) {
785 }
else if constexpr (
decltype(Tag)
::value == PassMode::TwoPassInsert::value) {
786 tracks[
offset] = temporaryTrack;
788 static_assert(
false,
"Unknown mode!");
793 const int nSeeds =
static_cast<int>(trackSeeds.size());
794 if (mTaskArena->max_concurrency() <= 1) {
795 for (
int iSeed{0}; iSeed < nSeeds; ++iSeed) {
800 tbb::parallel_for(0, nSeeds, [&](
const int iSeed) {
804 std::exclusive_scan(perSeedCount.begin(), perSeedCount.end(), perSeedCount.begin(), 0);
805 auto totalTracks{perSeedCount.back()};
806 if (totalTracks == 0) {
809 tracks.resize(totalTracks);
811 tbb::parallel_for(0, nSeeds, [&](
const int iSeed) {
812 if (perSeedCount[iSeed] == perSeedCount[iSeed + 1]) {
820 tbb::parallel_sort(tracks.begin(), tracks.end(), [](
const auto&
a,
const auto&
b) {
821 return a.getChi2() < b.getChi2();
825 for (
auto& track : tracks) {
827 bool isFirstShared{
false};
828 int firstLayer{-1}, firstCluster{-1};
829 for (
int iLayer{0}; iLayer < mTrkParams[0].NLayers; ++iLayer) {
830 if (track.getClusterIndex(iLayer) == constants::UnusedIndex) {
833 bool isShared = mTimeFrame->isClusterUsed(iLayer, track.getClusterIndex(iLayer));
834 nShared +=
int(isShared);
835 if (firstLayer < 0) {
836 firstCluster = track.getClusterIndex(iLayer);
837 isFirstShared = isShared && mTrkParams[0].AllowSharingFirstCluster && std::find(firstClusters[iLayer].begin(), firstClusters[iLayer].
end(), firstCluster) != firstClusters[iLayer].end();
843 if (nShared -
int(isFirstShared && mTrkParams[0].AllowSharingFirstCluster) > mTrkParams[0].ClusterSharing) {
847 std::array<int, 3> rofs{INT_MAX, INT_MAX, INT_MAX};
848 for (
int iLayer{0}; iLayer < mTrkParams[0].NLayers; ++iLayer) {
849 if (track.getClusterIndex(iLayer) == constants::UnusedIndex) {
852 mTimeFrame->markUsedCluster(iLayer, track.getClusterIndex(iLayer));
853 int currentROF = mTimeFrame->getClusterROF(iLayer, track.getClusterIndex(iLayer));
854 for (
int iR{0}; iR < 3; ++iR) {
855 if (rofs[iR] == INT_MAX) {
856 rofs[iR] = currentROF;
858 if (rofs[iR] == currentROF) {
863 if (rofs[2] != INT_MAX) {
866 track.setUserField(0);
867 track.getParamOut().setUserField(0);
868 if (rofs[1] != INT_MAX) {
869 track.setNextROFbit();
871 mTimeFrame->getTracks(o2::gpu::CAMath::Min(rofs[0], rofs[1])).emplace_back(track);
873 firstClusters[firstLayer].push_back(firstCluster);
875 sharedFirstClusters[firstLayer].push_back(firstCluster);
881 for (
int iLayer{0}; iLayer < mTrkParams[0].NLayers; ++iLayer) {
882 std::sort(sharedFirstClusters[iLayer].begin(), sharedFirstClusters[iLayer].
end());
885 for (
int iROF{0}; iROF < mTimeFrame->getNrof(); ++iROF) {
886 for (
auto& track : mTimeFrame->getTracks(iROF)) {
887 int firstLayer{mTrkParams[0].NLayers}, firstCluster{constants::UnusedIndex};
888 for (
int iLayer{0}; iLayer < mTrkParams[0].NLayers; ++iLayer) {
889 if (track.getClusterIndex(iLayer) == constants::UnusedIndex) {
893 firstCluster = track.getClusterIndex(iLayer);
896 if (std::binary_search(sharedFirstClusters[firstLayer].begin(), sharedFirstClusters[firstLayer].
end(), firstCluster)) {
897 track.setSharedClusters();
903template <
int nLayers>
906 for (
int rof{0}; rof < mTimeFrame->getNrof(); ++rof) {
907 for (
auto& track : mTimeFrame->getTracks(rof)) {
911 if ((mTrkParams[iteration].UseTrackFollowerMix || mTrkParams[iteration].UseTrackFollowerTop) && track.getLastClusterLayer() != mTrkParams[iteration].NLayers - 1) {
912 success = success || trackFollowing(&track, rof,
true, iteration);
914 if ((mTrkParams[iteration].UseTrackFollowerMix || (mTrkParams[iteration].UseTrackFollowerBot && !success)) && track.getFirstClusterLayer() != 0) {
915 success = success || trackFollowing(&track, rof,
false, iteration);
919 track.resetCovariance();
921 bool fitSuccess = fitTrack(track, 0, mTrkParams[iteration].NLayers, 1, mTrkParams[iteration].MaxChi2ClusterAttachment, mTrkParams[0].MaxChi2NDF);
926 track.getParamOut() = track;
927 track.resetCovariance();
929 fitSuccess = fitTrack(track, mTrkParams[iteration].NLayers - 1, -1, -1, mTrkParams[iteration].MaxChi2ClusterAttachment, mTrkParams[0].MaxChi2NDF, 50.);
934 mTimeFrame->mNExtendedTracks++;
935 mTimeFrame->mNExtendedUsedClusters += track.getNClusters() - backup.getNClusters();
936 auto pattern = track.getPattern();
937 auto diff = (
pattern & ~backup.getPattern()) & 0xff;
941 for (
int iLayer{0}; iLayer < mTrkParams[iteration].NLayers; ++iLayer) {
942 if (track.getClusterIndex(iLayer) == constants::UnusedIndex) {
945 mTimeFrame->markUsedCluster(iLayer, track.getClusterIndex(iLayer));
952template <
int nLayers>
956 mTimeFrame->fillPrimaryVerticesXandAlpha();
958 for (
auto& cell : mTimeFrame->getCells()[0]) {
959 auto& cluster3_glo = mTimeFrame->getClusters()[2][cell.getThirdClusterIndex()];
960 auto& cluster2_glo = mTimeFrame->getClusters()[1][cell.getSecondClusterIndex()];
961 auto& cluster1_glo = mTimeFrame->getClusters()[0][cell.getFirstClusterIndex()];
962 if (mTimeFrame->isClusterUsed(2, cluster1_glo.clusterId) ||
963 mTimeFrame->isClusterUsed(1, cluster2_glo.clusterId) ||
964 mTimeFrame->isClusterUsed(0, cluster3_glo.clusterId)) {
968 std::array<int, 3> rofs{
969 mTimeFrame->getClusterROF(2, cluster3_glo.clusterId),
970 mTimeFrame->getClusterROF(1, cluster2_glo.clusterId),
971 mTimeFrame->getClusterROF(0, cluster1_glo.clusterId)};
972 if (rofs[0] != rofs[1] && rofs[1] != rofs[2] && rofs[0] != rofs[2]) {
977 if (rofs[1] == rofs[2]) {
981 auto pvs{mTimeFrame->getPrimaryVertices(rof)};
982 auto pvsXAlpha{mTimeFrame->getPrimaryVerticesXAlpha(rof)};
984 const auto& cluster3_tf = mTimeFrame->getTrackingFrameInfoOnLayer(2)[cluster3_glo.clusterId];
985 TrackITSExt temporaryTrack{buildTrackSeed(cluster1_glo, cluster2_glo, cluster3_tf)};
986 temporaryTrack.setExternalClusterIndex(0, cluster1_glo.clusterId,
true);
987 temporaryTrack.setExternalClusterIndex(1, cluster2_glo.clusterId,
true);
988 temporaryTrack.setExternalClusterIndex(2, cluster3_glo.clusterId,
true);
991 bool fitSuccess = fitTrack(temporaryTrack, 1, -1, -1);
997 TrackITSExt bestTrack{temporaryTrack}, backup{temporaryTrack};
998 float bestChi2{std::numeric_limits<float>::max()};
999 for (
int iV{0}; iV < (
int)pvs.size(); ++iV) {
1000 temporaryTrack = backup;
1001 if (!temporaryTrack.rotate(pvsXAlpha[iV][1])) {
1004 if (!propagator->propagateTo(temporaryTrack, pvsXAlpha[iV][0],
true)) {
1008 float pvRes{mTrkParams[0].PVres / o2::gpu::CAMath::Sqrt(
float(pvs[iV].getNContributors()))};
1009 const float posVtx[2]{0.f, pvs[iV].getZ()};
1010 const float covVtx[3]{pvRes, 0.f, pvRes};
1011 float chi2 = temporaryTrack.getPredictedChi2Quiet(posVtx, covVtx);
1012 if (chi2 < bestChi2) {
1013 if (!temporaryTrack.track::TrackParCov::update(posVtx, covVtx)) {
1016 bestTrack = temporaryTrack;
1021 bestTrack.resetCovariance();
1022 bestTrack.setChi2(0.f);
1023 fitSuccess = fitTrack(bestTrack, 0, mTrkParams[0].NLayers, 1, mTrkParams[0].MaxChi2ClusterAttachment, mTrkParams[0].MaxChi2NDF);
1027 bestTrack.getParamOut() = bestTrack;
1028 bestTrack.resetCovariance();
1029 bestTrack.setChi2(0.f);
1030 fitSuccess = fitTrack(bestTrack, mTrkParams[0].NLayers - 1, -1, -1, mTrkParams[0].MaxChi2ClusterAttachment, mTrkParams[0].MaxChi2NDF, 50.);
1034 mTimeFrame->markUsedCluster(0, bestTrack.getClusterIndex(0));
1035 mTimeFrame->markUsedCluster(1, bestTrack.getClusterIndex(1));
1036 mTimeFrame->markUsedCluster(2, bestTrack.getClusterIndex(2));
1037 mTimeFrame->getTracks(rof).emplace_back(bestTrack);
1041template <
int nLayers>
1046 for (
int iLayer{
start}; iLayer !=
end; iLayer += step) {
1047 if (track.getClusterIndex(iLayer) == constants::UnusedIndex) {
1050 const TrackingFrameInfo& trackingHit = mTimeFrame->getTrackingFrameInfoOnLayer(iLayer)[track.getClusterIndex(iLayer)];
1052 if (!track.rotate(trackingHit.alphaTrackingFrame, *linRef, getBz())) {
1058 if (mTrkParams[0].CorrType == o2::base::PropagatorF::MatCorrType::USEMatCorrNONE) {
1059 if (!track.correctForMaterial(*linRef, mTrkParams[0].LayerxX0[iLayer], mTrkParams[0].LayerxX0[iLayer] * constants::Radl * constants::Rho,
true)) {
1064 if (!track.rotate(trackingHit.alphaTrackingFrame)) {
1070 if (mTrkParams[0].CorrType == o2::base::PropagatorF::MatCorrType::USEMatCorrNONE) {
1071 if (!track.correctForMaterial(mTrkParams[0].LayerxX0[iLayer], mTrkParams[0].LayerxX0[iLayer] * constants::Radl * constants::Rho,
true)) {
1076 auto predChi2{track.getPredictedChi2Quiet(trackingHit.positionTrackingFrame, trackingHit.covarianceTrackingFrame)};
1077 if ((nCl >= 3 && predChi2 > chi2clcut) || predChi2 < 0.f) {
1080 track.setChi2(track.getChi2() + predChi2);
1081 if (!track.o2::track::TrackParCov::update(trackingHit.positionTrackingFrame, trackingHit.covarianceTrackingFrame)) {
1084 if (linRef && mTrkParams[0].ShiftRefToCluster) {
1085 linRef->setY(trackingHit.positionTrackingFrame[0]);
1086 linRef->setZ(trackingHit.positionTrackingFrame[1]);
1090 return std::abs(track.getQ2Pt()) < maxQoverPt && track.getChi2() < chi2ndfcut * (nCl * 2 - 5);
1093template <
int nLayers>
1097 const int step = -1 + outward * 2;
1098 const int end = outward ? mTrkParams[iteration].NLayers - 1 : 0;
1100 for (
size_t iHypo{0}; iHypo < hypotheses.size(); ++iHypo) {
1101 auto hypo{hypotheses[iHypo]};
1102 int iLayer =
static_cast<int>(outward ? hypo.getLastClusterLayer() : hypo.getFirstClusterLayer());
1104 while (iLayer !=
end) {
1106 const float r = mTrkParams[iteration].LayerRadii[iLayer];
1113 auto& hypoParam{outward ? hypo.getParamOut() : hypo.getParamIn()};
1114 if (!propInstance->propagateToX(hypoParam,
x, mTimeFrame->getBz(), PropagatorF::MAX_SIN_PHI,
1115 PropagatorF::MAX_STEP, mTrkParams[iteration].CorrType)) {
1119 if (mTrkParams[iteration].CorrType == PropagatorF::MatCorrType::USEMatCorrNONE) {
1120 if (!hypoParam.correctForMaterial(mTrkParams[iteration].LayerxX0[iLayer], mTrkParams[iteration].LayerxX0[iLayer] * constants::Radl * constants::Rho,
true)) {
1126 const float phi{hypoParam.getPhi()};
1127 const float ePhi{o2::gpu::CAMath::Sqrt(hypoParam.getSigmaSnp2() / hypoParam.getCsp2())};
1128 const float z{hypoParam.getZ()};
1129 const float eZ{o2::gpu::CAMath::Sqrt(hypoParam.getSigmaZ2())};
1130 const int4 selectedBinsRect{getBinsRect(iLayer, phi, mTrkParams[iteration].TrackFollowerNSigmaCutPhi * ePhi,
z, mTrkParams[iteration].TrackFollowerNSigmaCutZ * eZ)};
1131 if (selectedBinsRect.x == 0 && selectedBinsRect.y == 0 && selectedBinsRect.z == 0 && selectedBinsRect.w == 0) {
1135 int phiBinsNum{selectedBinsRect.
w - selectedBinsRect.y + 1};
1137 if (phiBinsNum < 0) {
1138 phiBinsNum += mTrkParams[iteration].PhiBins;
1141 gsl::span<const Cluster> layer1 = mTimeFrame->getClustersOnLayer(rof, iLayer);
1142 if (layer1.empty()) {
1147 for (
int iPhiCount = 0; iPhiCount < phiBinsNum; iPhiCount++) {
1148 int iPhiBin = (selectedBinsRect.y + iPhiCount) % mTrkParams[iteration].PhiBins;
1149 const int firstBinIndex{mTimeFrame->mIndexTableUtils.getBinIndex(selectedBinsRect.x, iPhiBin)};
1150 const int maxBinIndex{firstBinIndex + selectedBinsRect.z - selectedBinsRect.x + 1};
1151 const int firstRowClusterIndex = mTimeFrame->getIndexTable(rof, iLayer)[firstBinIndex];
1152 const int maxRowClusterIndex = mTimeFrame->getIndexTable(rof, iLayer)[maxBinIndex];
1154 for (
int iNextCluster{firstRowClusterIndex}; iNextCluster < maxRowClusterIndex; ++iNextCluster) {
1155 if (iNextCluster >= (
int)layer1.size()) {
1158 const Cluster& nextCluster{layer1[iNextCluster]};
1160 if (mTimeFrame->isClusterUsed(iLayer, nextCluster.clusterId)) {
1164 const TrackingFrameInfo& trackingHit = mTimeFrame->getTrackingFrameInfoOnLayer(iLayer)[nextCluster.clusterId];
1166 auto tbupdated{hypo};
1167 auto& tbuParams = outward ? tbupdated.getParamOut() : tbupdated.getParamIn();
1172 if (!propInstance->propagateToX(tbuParams, trackingHit.
xTrackingFrame, mTimeFrame->getBz(),
1173 PropagatorF::MAX_SIN_PHI, PropagatorF::MAX_STEP, PropagatorF::MatCorrType::USEMatCorrNONE)) {
1178 if (predChi2 >= track->getChi2() * mTrkParams[iteration].NSigmaCut) {
1185 tbupdated.setChi2(tbupdated.getChi2() + predChi2);
1186 tbupdated.setExternalClusterIndex(iLayer, nextCluster.clusterId,
true);
1187 hypotheses.emplace_back(tbupdated);
1194 bool swapped{
false};
1195 for (
auto& hypo : hypotheses) {
1196 if (hypo.isBetter(*bestHypo, track->getChi2() * mTrkParams[iteration].NSigmaCut)) {
1206template <
int nLayers>
1210 int lrMin = nLayers, lrMax = 0, lrMid = 0;
1211 for (
int iL = 0; iL < nLayers; ++iL) {
1212 const int idx = seed.getCluster(iL);
1213 temporaryTrack.setExternalClusterIndex(iL, idx, idx != constants::UnusedIndex);
1214 if (idx != constants::UnusedIndex) {
1215 lrMin = o2::gpu::CAMath::Min(lrMin, iL);
1216 lrMax = o2::gpu::CAMath::Max(lrMax, iL);
1219 int ncl = temporaryTrack.getNClusters();
1220 if (ncl < mTrkParams[0].ReseedIfShorter) {
1221 if (ncl == mTrkParams[0].NLayers) {
1223 lrMax = mTrkParams[0].NLayers - 1;
1224 lrMid = (lrMin + lrMax) / 2;
1227 float midR = 0.5 * (mTrkParams[0].LayerRadii[lrMax] + mTrkParams[0].LayerRadii[lrMin]), dstMidR = o2::gpu::GPUCommonMath::Abs(midR - mTrkParams[0].LayerRadii[lrMid]);
1228 for (
int iL = lrMid + 1; iL < lrMax; ++iL) {
1229 auto dst = o2::gpu::GPUCommonMath::Abs(midR - mTrkParams[0].LayerRadii[iL]);
1230 if (
dst < dstMidR) {
1236 const auto& cluster0_tf = mTimeFrame->getTrackingFrameInfoOnLayer(lrMin)[seed.getCluster(lrMin)];
1237 const auto& cluster1_gl = mTimeFrame->getUnsortedClusters()[lrMid][seed.getCluster(lrMid)];
1238 const auto& cluster2_gl = mTimeFrame->getUnsortedClusters()[lrMax][seed.getCluster(lrMax)];
1239 temporaryTrack.getParamIn() = buildTrackSeed(cluster2_gl, cluster1_gl, cluster0_tf,
true);
1241 temporaryTrack.resetCovariance();
1243 return temporaryTrack;
1248template <
int nLayers>
1251 const float sign =
reverse ? -1.f : 1.f;
1254 o2::gpu::CAMath::SinCos(tf3.alphaTrackingFrame, sa, ca);
1256 const float x1 = cluster1.xCoordinate * ca + cluster1.yCoordinate * sa;
1257 const float y1 = -cluster1.xCoordinate * sa + cluster1.yCoordinate * ca;
1258 const float x2 = cluster2.xCoordinate * ca + cluster2.yCoordinate * sa;
1259 const float y2 = -cluster2.xCoordinate * sa + cluster2.yCoordinate * ca;
1260 const float x3 = tf3.xTrackingFrame;
1261 const float y3 = tf3.positionTrackingFrame[0];
1263 float snp, q2pt, q2pt2;
1265 const float tgp = o2::gpu::CAMath::ATan2(y3 -
y1, x3 -
x1);
1266 snp = sign * tgp / o2::gpu::CAMath::Sqrt(1.f + tgp * tgp);
1270 const float crv = math_utils::computeCurvature(x3, y3, x2, y2,
x1,
y1);
1271 snp = sign * crv * (
x3 - math_utils::computeCurvatureCentreX(x3, y3, x2, y2,
x1,
y1));
1276 const float tgl = 0.5f * (math_utils::computeTanDipAngle(
x1,
y1, x2, y2, cluster1.zCoordinate, cluster2.zCoordinate) +
1277 math_utils::computeTanDipAngle(x2, y2, x3, y3, cluster2.zCoordinate, tf3.positionTrackingFrame[1]));
1278 const float sg2q2pt =
track::kC1Pt2max * (q2pt2 > 0.0005f ? (q2pt2 < 1.f ? q2pt2 : 1.f) : 0.0005f);
1280 return {
x3, tf3.alphaTrackingFrame, {
y3, tf3.positionTrackingFrame[1], snp, tgl, q2pt}, {tf3.covarianceTrackingFrame[0], tf3.covarianceTrackingFrame[1], tf3.covarianceTrackingFrame[2], 0.f, 0.f,
track::kCSnp2max, 0.f, 0.f, 0.f,
track::kCTgl2max, 0.f, 0.f, 0.f, 0.f, sg2q2pt}};
1283template <
int nLayers>
1287 mIsZeroField = std::abs(mBz) < 0.01;
1288 mTimeFrame->setBz(bz);
1291template <
int nLayers>
1297template <
int nLayers>
1300#if defined(OPTIMISATION_OUTPUT) || defined(CA_DEBUG)
1301 mTaskArena = std::make_shared<tbb::task_arena>(1);
1303 if (arena ==
nullptr) {
1304 mTaskArena = std::make_shared<tbb::task_arena>(std::abs(
n));
1305 LOGP(info,
"Setting tracker with {} threads.",
n);
1308 LOGP(info,
"Attaching tracker to calling thread's arena");