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 const auto& seed{trackSeeds[iSeed]};
768 temporaryTrack.resetCovariance();
769 temporaryTrack.setChi2(0);
770 for (
int iL{0}; iL < nLayers; ++iL) {
771 temporaryTrack.setExternalClusterIndex(iL, seed.getCluster(iL), seed.getCluster(iL) != constants::UnusedIndex);
774 bool fitSuccess = fitTrack(temporaryTrack, 0, mTrkParams[0].NLayers, 1, mTrkParams[0].MaxChi2ClusterAttachment, mTrkParams[0].MaxChi2NDF);
779 temporaryTrack.getParamOut() = temporaryTrack.getParamIn();
780 temporaryTrack.resetCovariance();
781 temporaryTrack.setChi2(0);
782 fitSuccess = fitTrack(temporaryTrack, mTrkParams[0].NLayers - 1, -1, -1, mTrkParams[0].MaxChi2ClusterAttachment, mTrkParams[0].MaxChi2NDF, 50.f);
783 if (!fitSuccess || temporaryTrack.getPt() < mTrkParams[iteration].MinPt[mTrkParams[iteration].NLayers - temporaryTrack.getNClusters()]) {
787 if constexpr (
decltype(Tag)
::value == PassMode::OnePass::value) {
788 tracks.push_back(temporaryTrack);
789 }
else if constexpr (
decltype(Tag)
::value == PassMode::TwoPassCount::value) {
791 }
else if constexpr (
decltype(Tag)
::value == PassMode::TwoPassInsert::value) {
792 tracks[
offset] = temporaryTrack;
794 static_assert(
false,
"Unknown mode!");
799 const int nSeeds =
static_cast<int>(trackSeeds.size());
800 if (mTaskArena->max_concurrency() <= 1) {
801 for (
int iSeed{0}; iSeed < nSeeds; ++iSeed) {
806 tbb::parallel_for(0, nSeeds, [&](
const int iSeed) {
810 std::exclusive_scan(perSeedCount.begin(), perSeedCount.end(), perSeedCount.begin(), 0);
811 auto totalTracks{perSeedCount.back()};
812 if (totalTracks == 0) {
815 tracks.resize(totalTracks);
817 tbb::parallel_for(0, nSeeds, [&](
const int iSeed) {
818 if (perSeedCount[iSeed] == perSeedCount[iSeed + 1]) {
826 tbb::parallel_sort(tracks.begin(), tracks.end(), [](
const auto&
a,
const auto&
b) {
827 return a.getChi2() < b.getChi2();
831 for (
auto& track : tracks) {
833 bool isFirstShared{
false};
834 int firstLayer{-1}, firstCluster{-1};
835 for (
int iLayer{0}; iLayer < mTrkParams[0].NLayers; ++iLayer) {
836 if (track.getClusterIndex(iLayer) == constants::UnusedIndex) {
839 bool isShared = mTimeFrame->isClusterUsed(iLayer, track.getClusterIndex(iLayer));
840 nShared +=
int(isShared);
841 if (firstLayer < 0) {
842 firstCluster = track.getClusterIndex(iLayer);
843 isFirstShared = isShared && mTrkParams[0].AllowSharingFirstCluster && std::find(firstClusters[iLayer].begin(), firstClusters[iLayer].
end(), firstCluster) != firstClusters[iLayer].end();
849 if (nShared -
int(isFirstShared && mTrkParams[0].AllowSharingFirstCluster) > mTrkParams[0].ClusterSharing) {
853 std::array<int, 3> rofs{INT_MAX, INT_MAX, INT_MAX};
854 for (
int iLayer{0}; iLayer < mTrkParams[0].NLayers; ++iLayer) {
855 if (track.getClusterIndex(iLayer) == constants::UnusedIndex) {
858 mTimeFrame->markUsedCluster(iLayer, track.getClusterIndex(iLayer));
859 int currentROF = mTimeFrame->getClusterROF(iLayer, track.getClusterIndex(iLayer));
860 for (
int iR{0}; iR < 3; ++iR) {
861 if (rofs[iR] == INT_MAX) {
862 rofs[iR] = currentROF;
864 if (rofs[iR] == currentROF) {
869 if (rofs[2] != INT_MAX) {
872 track.setUserField(0);
873 track.getParamOut().setUserField(0);
874 if (rofs[1] != INT_MAX) {
875 track.setNextROFbit();
877 mTimeFrame->getTracks(o2::gpu::CAMath::Min(rofs[0], rofs[1])).emplace_back(track);
879 firstClusters[firstLayer].push_back(firstCluster);
881 sharedFirstClusters[firstLayer].push_back(firstCluster);
887 for (
int iLayer{0}; iLayer < mTrkParams[0].NLayers; ++iLayer) {
888 std::sort(sharedFirstClusters[iLayer].begin(), sharedFirstClusters[iLayer].
end());
891 for (
int iROF{0}; iROF < mTimeFrame->getNrof(); ++iROF) {
892 for (
auto& track : mTimeFrame->getTracks(iROF)) {
893 int firstLayer{mTrkParams[0].NLayers}, firstCluster{constants::UnusedIndex};
894 for (
int iLayer{0}; iLayer < mTrkParams[0].NLayers; ++iLayer) {
895 if (track.getClusterIndex(iLayer) == constants::UnusedIndex) {
899 firstCluster = track.getClusterIndex(iLayer);
902 if (std::binary_search(sharedFirstClusters[firstLayer].begin(), sharedFirstClusters[firstLayer].
end(), firstCluster)) {
903 track.setSharedClusters();
909template <
int nLayers>
912 for (
int rof{0}; rof < mTimeFrame->getNrof(); ++rof) {
913 for (
auto& track : mTimeFrame->getTracks(rof)) {
917 if ((mTrkParams[iteration].UseTrackFollowerMix || mTrkParams[iteration].UseTrackFollowerTop) && track.getLastClusterLayer() != mTrkParams[iteration].NLayers - 1) {
918 success = success || trackFollowing(&track, rof,
true, iteration);
920 if ((mTrkParams[iteration].UseTrackFollowerMix || (mTrkParams[iteration].UseTrackFollowerBot && !success)) && track.getFirstClusterLayer() != 0) {
921 success = success || trackFollowing(&track, rof,
false, iteration);
925 track.resetCovariance();
927 bool fitSuccess = fitTrack(track, 0, mTrkParams[iteration].NLayers, 1, mTrkParams[iteration].MaxChi2ClusterAttachment, mTrkParams[0].MaxChi2NDF);
932 track.getParamOut() = track;
933 track.resetCovariance();
935 fitSuccess = fitTrack(track, mTrkParams[iteration].NLayers - 1, -1, -1, mTrkParams[iteration].MaxChi2ClusterAttachment, mTrkParams[0].MaxChi2NDF, 50.);
940 mTimeFrame->mNExtendedTracks++;
941 mTimeFrame->mNExtendedUsedClusters += track.getNClusters() - backup.getNClusters();
942 auto pattern = track.getPattern();
943 auto diff = (
pattern & ~backup.getPattern()) & 0xff;
947 for (
int iLayer{0}; iLayer < mTrkParams[iteration].NLayers; ++iLayer) {
948 if (track.getClusterIndex(iLayer) == constants::UnusedIndex) {
951 mTimeFrame->markUsedCluster(iLayer, track.getClusterIndex(iLayer));
958template <
int nLayers>
962 mTimeFrame->fillPrimaryVerticesXandAlpha();
964 for (
auto& cell : mTimeFrame->getCells()[0]) {
965 auto& cluster3_glo = mTimeFrame->getClusters()[2][cell.getThirdClusterIndex()];
966 auto& cluster2_glo = mTimeFrame->getClusters()[1][cell.getSecondClusterIndex()];
967 auto& cluster1_glo = mTimeFrame->getClusters()[0][cell.getFirstClusterIndex()];
968 if (mTimeFrame->isClusterUsed(2, cluster1_glo.clusterId) ||
969 mTimeFrame->isClusterUsed(1, cluster2_glo.clusterId) ||
970 mTimeFrame->isClusterUsed(0, cluster3_glo.clusterId)) {
974 std::array<int, 3> rofs{
975 mTimeFrame->getClusterROF(2, cluster3_glo.clusterId),
976 mTimeFrame->getClusterROF(1, cluster2_glo.clusterId),
977 mTimeFrame->getClusterROF(0, cluster1_glo.clusterId)};
978 if (rofs[0] != rofs[1] && rofs[1] != rofs[2] && rofs[0] != rofs[2]) {
983 if (rofs[1] == rofs[2]) {
987 auto pvs{mTimeFrame->getPrimaryVertices(rof)};
988 auto pvsXAlpha{mTimeFrame->getPrimaryVerticesXAlpha(rof)};
990 const auto& cluster3_tf = mTimeFrame->getTrackingFrameInfoOnLayer(2)[cluster3_glo.clusterId];
991 TrackITSExt temporaryTrack{buildTrackSeed(cluster1_glo, cluster2_glo, cluster3_tf)};
992 temporaryTrack.setExternalClusterIndex(0, cluster1_glo.clusterId,
true);
993 temporaryTrack.setExternalClusterIndex(1, cluster2_glo.clusterId,
true);
994 temporaryTrack.setExternalClusterIndex(2, cluster3_glo.clusterId,
true);
997 bool fitSuccess = fitTrack(temporaryTrack, 1, -1, -1);
1003 TrackITSExt bestTrack{temporaryTrack}, backup{temporaryTrack};
1004 float bestChi2{std::numeric_limits<float>::max()};
1005 for (
int iV{0}; iV < (
int)pvs.size(); ++iV) {
1006 temporaryTrack = backup;
1007 if (!temporaryTrack.rotate(pvsXAlpha[iV][1])) {
1010 if (!propagator->propagateTo(temporaryTrack, pvsXAlpha[iV][0],
true)) {
1014 float pvRes{mTrkParams[0].PVres / o2::gpu::CAMath::Sqrt(
float(pvs[iV].getNContributors()))};
1015 const float posVtx[2]{0.f, pvs[iV].getZ()};
1016 const float covVtx[3]{pvRes, 0.f, pvRes};
1017 float chi2 = temporaryTrack.getPredictedChi2Quiet(posVtx, covVtx);
1018 if (chi2 < bestChi2) {
1019 if (!temporaryTrack.track::TrackParCov::update(posVtx, covVtx)) {
1022 bestTrack = temporaryTrack;
1027 bestTrack.resetCovariance();
1028 bestTrack.setChi2(0.f);
1029 fitSuccess = fitTrack(bestTrack, 0, mTrkParams[0].NLayers, 1, mTrkParams[0].MaxChi2ClusterAttachment, mTrkParams[0].MaxChi2NDF);
1033 bestTrack.getParamOut() = bestTrack;
1034 bestTrack.resetCovariance();
1035 bestTrack.setChi2(0.f);
1036 fitSuccess = fitTrack(bestTrack, mTrkParams[0].NLayers - 1, -1, -1, mTrkParams[0].MaxChi2ClusterAttachment, mTrkParams[0].MaxChi2NDF, 50.);
1040 mTimeFrame->markUsedCluster(0, bestTrack.getClusterIndex(0));
1041 mTimeFrame->markUsedCluster(1, bestTrack.getClusterIndex(1));
1042 mTimeFrame->markUsedCluster(2, bestTrack.getClusterIndex(2));
1043 mTimeFrame->getTracks(rof).emplace_back(bestTrack);
1047template <
int nLayers>
1052 for (
int iLayer{
start}; iLayer !=
end; iLayer += step) {
1053 if (track.getClusterIndex(iLayer) == constants::UnusedIndex) {
1056 const TrackingFrameInfo& trackingHit = mTimeFrame->getTrackingFrameInfoOnLayer(iLayer)[track.getClusterIndex(iLayer)];
1058 if (!track.rotate(trackingHit.alphaTrackingFrame)) {
1066 if (mTrkParams[0].CorrType == o2::base::PropagatorF::MatCorrType::USEMatCorrNONE) {
1067 if (!track.correctForMaterial(mTrkParams[0].LayerxX0[iLayer], mTrkParams[0].LayerxX0[iLayer] * constants::Radl * constants::Rho,
true)) {
1072 auto predChi2{track.getPredictedChi2Quiet(trackingHit.positionTrackingFrame, trackingHit.covarianceTrackingFrame)};
1073 if ((nCl >= 3 && predChi2 > chi2clcut) || predChi2 < 0.f) {
1076 track.setChi2(track.getChi2() + predChi2);
1077 if (!track.o2::track::TrackParCov::update(trackingHit.positionTrackingFrame, trackingHit.covarianceTrackingFrame)) {
1082 return std::abs(track.getQ2Pt()) < maxQoverPt && track.getChi2() < chi2ndfcut * (nCl * 2 - 5);
1085template <
int nLayers>
1089 const int step = -1 + outward * 2;
1090 const int end = outward ? mTrkParams[iteration].NLayers - 1 : 0;
1092 for (
size_t iHypo{0}; iHypo < hypotheses.size(); ++iHypo) {
1093 auto hypo{hypotheses[iHypo]};
1094 int iLayer =
static_cast<int>(outward ? hypo.getLastClusterLayer() : hypo.getFirstClusterLayer());
1096 while (iLayer !=
end) {
1098 const float r = mTrkParams[iteration].LayerRadii[iLayer];
1105 auto& hypoParam{outward ? hypo.getParamOut() : hypo.getParamIn()};
1106 if (!propInstance->propagateToX(hypoParam,
x, mTimeFrame->getBz(), PropagatorF::MAX_SIN_PHI,
1107 PropagatorF::MAX_STEP, mTrkParams[iteration].CorrType)) {
1111 if (mTrkParams[iteration].CorrType == PropagatorF::MatCorrType::USEMatCorrNONE) {
1112 if (!hypoParam.correctForMaterial(mTrkParams[iteration].LayerxX0[iLayer], mTrkParams[iteration].LayerxX0[iLayer] * constants::Radl * constants::Rho,
true)) {
1118 const float phi{hypoParam.getPhi()};
1119 const float ePhi{o2::gpu::CAMath::Sqrt(hypoParam.getSigmaSnp2() / hypoParam.getCsp2())};
1120 const float z{hypoParam.getZ()};
1121 const float eZ{o2::gpu::CAMath::Sqrt(hypoParam.getSigmaZ2())};
1122 const int4 selectedBinsRect{getBinsRect(iLayer, phi, mTrkParams[iteration].TrackFollowerNSigmaCutPhi * ePhi,
z, mTrkParams[iteration].TrackFollowerNSigmaCutZ * eZ)};
1123 if (selectedBinsRect.x == 0 && selectedBinsRect.y == 0 && selectedBinsRect.z == 0 && selectedBinsRect.w == 0) {
1127 int phiBinsNum{selectedBinsRect.
w - selectedBinsRect.y + 1};
1129 if (phiBinsNum < 0) {
1130 phiBinsNum += mTrkParams[iteration].PhiBins;
1133 gsl::span<const Cluster> layer1 = mTimeFrame->getClustersOnLayer(rof, iLayer);
1134 if (layer1.empty()) {
1139 for (
int iPhiCount = 0; iPhiCount < phiBinsNum; iPhiCount++) {
1140 int iPhiBin = (selectedBinsRect.y + iPhiCount) % mTrkParams[iteration].PhiBins;
1141 const int firstBinIndex{mTimeFrame->mIndexTableUtils.getBinIndex(selectedBinsRect.x, iPhiBin)};
1142 const int maxBinIndex{firstBinIndex + selectedBinsRect.z - selectedBinsRect.x + 1};
1143 const int firstRowClusterIndex = mTimeFrame->getIndexTable(rof, iLayer)[firstBinIndex];
1144 const int maxRowClusterIndex = mTimeFrame->getIndexTable(rof, iLayer)[maxBinIndex];
1146 for (
int iNextCluster{firstRowClusterIndex}; iNextCluster < maxRowClusterIndex; ++iNextCluster) {
1147 if (iNextCluster >= (
int)layer1.size()) {
1150 const Cluster& nextCluster{layer1[iNextCluster]};
1152 if (mTimeFrame->isClusterUsed(iLayer, nextCluster.clusterId)) {
1156 const TrackingFrameInfo& trackingHit = mTimeFrame->getTrackingFrameInfoOnLayer(iLayer)[nextCluster.clusterId];
1158 auto tbupdated{hypo};
1159 auto& tbuParams = outward ? tbupdated.getParamOut() : tbupdated.getParamIn();
1164 if (!propInstance->propagateToX(tbuParams, trackingHit.
xTrackingFrame, mTimeFrame->getBz(),
1165 PropagatorF::MAX_SIN_PHI, PropagatorF::MAX_STEP, PropagatorF::MatCorrType::USEMatCorrNONE)) {
1170 if (predChi2 >= track->getChi2() * mTrkParams[iteration].NSigmaCut) {
1177 tbupdated.setChi2(tbupdated.getChi2() + predChi2);
1178 tbupdated.setExternalClusterIndex(iLayer, nextCluster.clusterId,
true);
1179 hypotheses.emplace_back(tbupdated);
1186 bool swapped{
false};
1187 for (
auto& hypo : hypotheses) {
1188 if (hypo.isBetter(*bestHypo, track->getChi2() * mTrkParams[iteration].NSigmaCut)) {
1199template <
int nLayers>
1202 float ca{-999.f}, sa{-999.f};
1213 float tgp{1.f}, crv{1.f}, snp{-999.f}, tgl12{-999.f}, tgl23{-999.f}, q2pt{1.f /
track::kMostProbablePt}, q2pt2{1.f}, sg2q2pt{-999.f};
1215 tgp = o2::gpu::CAMath::ATan2(y3 -
y1, x3 -
x1);
1216 snp = tgp / o2::gpu::CAMath::Sqrt(1.f + tgp * tgp);
1218 crv = math_utils::computeCurvature(x3, y3, x2, y2,
x1,
y1);
1219 snp = crv * (
x3 - math_utils::computeCurvatureCentreX(x3, y3, x2, y2,
x1,
y1));
1223 tgl12 = math_utils::computeTanDipAngle(
x1,
y1, x2, y2, z1, z2);
1224 tgl23 = math_utils::computeTanDipAngle(x2, y2, x3, y3, z2, z3);
1225 sg2q2pt =
track::kC1Pt2max * (q2pt2 > 0.0005f ? (q2pt2 < 1.f ? q2pt2 : 1.f) : 0.0005f);
1226 return {tf3.
xTrackingFrame, tf3.
alphaTrackingFrame, {
y3, z3, snp, 0.5f * (tgl12 + tgl23), 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}};
1229template <
int nLayers>
1233 mIsZeroField = std::abs(mBz) < 0.01;
1234 mTimeFrame->setBz(bz);
1237template <
int nLayers>
1243template <
int nLayers>
1246#if defined(OPTIMISATION_OUTPUT) || defined(CA_DEBUG)
1247 mTaskArena = std::make_shared<tbb::task_arena>(1);
1249 if (arena ==
nullptr) {
1250 mTaskArena = std::make_shared<tbb::task_arena>(std::abs(
n));
1251 LOGP(info,
"Setting tracker with {} threads.",
n);
1254 LOGP(info,
"Attaching tracker to calling thread's arena");