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);
217 [&](
auto const& Layers) {
218 for (
int iLayer{Layers.begin()}; iLayer < Layers.end(); ++iLayer) {
219 std::exclusive_scan(perROFCount[iLayer].
begin(), perROFCount[iLayer].
end(), perROFCount[iLayer].
begin(), 0);
220 mTimeFrame->getTracklets()[iLayer].resize(perROFCount[iLayer].back());
225 tbb::blocked_range2d<int, int>(0, mTrkParams[iteration].
TrackletsPerRoad(), 1,
226 startROF, endROF, 1),
227 [&](
auto const& Range) {
228 for (
int iLayer{Range.rows().
begin()}; iLayer < Range.rows().
end(); ++iLayer) {
229 if (perROFCount[iLayer].back() == 0) {
232 for (
int pivotROF = Range.cols().begin(); pivotROF < Range.cols().end(); ++pivotROF) {
233 int baseIdx = perROFCount[iLayer][pivotROF - startROF];
234 if (baseIdx == perROFCount[iLayer][pivotROF - startROF + 1]) {
246 [&](
const tbb::blocked_range<int>& Layers) {
247 for (
int iLayer = Layers.begin(); iLayer < Layers.end(); ++iLayer) {
249 auto& trkl{mTimeFrame->getTracklets()[iLayer]};
250 tbb::parallel_sort(trkl.begin(), trkl.end(), [](
const Tracklet&
a,
const Tracklet&
b) ->
bool {
251 if (a.firstClusterIndex != b.firstClusterIndex) {
252 return a.firstClusterIndex < b.firstClusterIndex;
254 return a.secondClusterIndex <
b.secondClusterIndex;
257 trkl.erase(std::unique(trkl.begin(), trkl.end(), [](
const Tracklet&
a,
const Tracklet&
b) ->
bool {
258 return a.firstClusterIndex == b.firstClusterIndex && a.secondClusterIndex == b.secondClusterIndex;
261 trkl.shrink_to_fit();
263 auto& lut{mTimeFrame->getTrackletsLookupTable()[iLayer - 1]};
265 for (
const auto& tkl : trkl) {
266 lut[tkl.firstClusterIndex + 1]++;
268 std::inclusive_scan(lut.begin(), lut.end(), lut.begin());
275 if (mTimeFrame->hasMCinformation() && mTrkParams[iteration].createArtefactLabels) {
278 [&](
const tbb::blocked_range<int>& Layers) {
279 for (
int iLayer = Layers.begin(); iLayer < Layers.end(); ++iLayer) {
280 for (
auto& trk : mTimeFrame->getTracklets()[iLayer]) {
282 int currentId{mTimeFrame->getClusters()[iLayer][trk.firstClusterIndex].clusterId};
283 int nextId{mTimeFrame->getClusters()[iLayer + 1][trk.secondClusterIndex].clusterId};
284 for (
const auto& lab1 : mTimeFrame->getClusterLabels(iLayer, currentId)) {
285 for (
const auto& lab2 : mTimeFrame->getClusterLabels(iLayer + 1, nextId)) {
286 if (lab1 == lab2 && lab1.isValid()) {
291 if (
label.isValid()) {
295 mTimeFrame->getTrackletsLabel(iLayer).emplace_back(
label);
303template <
int nLayers>
306#ifdef OPTIMISATION_OUTPUT
308 std::ofstream off(std::format(
"cells{}.txt", iter++));
311 for (
int iLayer = 0; iLayer < mTrkParams[iteration].CellsPerRoad(); ++iLayer) {
316 if (mTimeFrame->hasMCinformation() && mTrkParams[iteration].createArtefactLabels) {
321 mTaskArena->execute([&] {
323 const Tracklet& currentTracklet{mTimeFrame->getTracklets()[iLayer][iTracklet]};
325 const int nextLayerFirstTrackletIndex{mTimeFrame->getTrackletsLookupTable()[iLayer][nextLayerClusterIndex]};
326 const int nextLayerLastTrackletIndex{mTimeFrame->getTrackletsLookupTable()[iLayer][nextLayerClusterIndex + 1]};
328 for (
int iNextTracklet{nextLayerFirstTrackletIndex}; iNextTracklet < nextLayerLastTrackletIndex; ++iNextTracklet) {
329 const Tracklet& nextTracklet{mTimeFrame->getTracklets()[iLayer + 1][iNextTracklet]};
330 const auto& nextLbl = mTimeFrame->getTrackletsLabel(iLayer + 1)[iNextTracklet];
331 if (mTimeFrame->getTracklets()[iLayer + 1][iNextTracklet].firstClusterIndex != nextLayerClusterIndex) {
334 if (mTrkParams[iteration].DeltaROF && currentTracklet.getSpanRof(nextTracklet) > mTrkParams[iteration].DeltaROF) {
337 const float deltaTanLambda{std::abs(currentTracklet.tanLambda - nextTracklet.tanLambda)};
339#ifdef OPTIMISATION_OUTPUT
340 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]};
341 resolution = resolution > 1.e-12 ? resolution : 1.f;
342 bool good{mTimeFrame->getTrackletsLabel(iLayer)[iTracklet] == mTimeFrame->getTrackletsLabel(iLayer + 1)[iNextTracklet]};
343 float signedDelta{currentTracklet.
tanLambda - nextTracklet.tanLambda};
344 off << std::format(
"{}\t{:d}\t{}\t{}\t{}\t{}", iLayer, good, signedDelta, signedDelta / (mTrkParams[iteration].CellDeltaTanLambdaSigma), tanLambda, resolution) << std::endl;
347 if (deltaTanLambda / mTrkParams[iteration].CellDeltaTanLambdaSigma < mTrkParams[iteration].NSigmaCut) {
351 mTimeFrame->getClusters()[iLayer][currentTracklet.firstClusterIndex].clusterId,
352 mTimeFrame->getClusters()[iLayer + 1][nextTracklet.firstClusterIndex].clusterId,
353 mTimeFrame->getClusters()[iLayer + 2][nextTracklet.secondClusterIndex].clusterId};
354 const auto& cluster1_glo = mTimeFrame->getUnsortedClusters()[iLayer][clusId[0]];
355 const auto& cluster2_glo = mTimeFrame->getUnsortedClusters()[iLayer + 1][clusId[1]];
356 const auto& cluster3_tf = mTimeFrame->getTrackingFrameInfoOnLayer(iLayer + 2)[clusId[2]];
357 auto track{buildTrackSeed(cluster1_glo, cluster2_glo, cluster3_tf)};
361 for (
int iC{2}; iC--;) {
362 const TrackingFrameInfo& trackingHit = mTimeFrame->getTrackingFrameInfoOnLayer(iLayer + iC)[clusId[iC]];
372 if (!track.correctForMaterial(mTrkParams[0].LayerxX0[iLayer + iC], mTrkParams[0].LayerxX0[iLayer] * constants::Radl * constants::Rho,
true)) {
377 if (!iC && predChi2 > mTrkParams[iteration].MaxChi2ClusterAttachment) {
389 if constexpr (
decltype(Tag)
::value == PassMode::OnePass::value) {
390 layerCells.emplace_back(iLayer, clusId[0], clusId[1], clusId[2], iTracklet, iNextTracklet, track, chi2);
392 }
else if constexpr (
decltype(Tag)
::value == PassMode::TwoPassCount::value) {
394 }
else if constexpr (
decltype(Tag)
::value == PassMode::TwoPassInsert::value) {
395 layerCells[
offset++] =
CellSeedN(iLayer, clusId[0], clusId[1], clusId[2], iTracklet, iNextTracklet, track, chi2);
397 static_assert(
false,
"Unknown mode!");
406 tbb::blocked_range<int>(0, mTrkParams[iteration].CellsPerRoad()),
407 [&](
const tbb::blocked_range<int>& Layers) {
408 for (
int iLayer = Layers.begin(); iLayer < Layers.end(); ++iLayer) {
409 if (mTimeFrame->getTracklets()[iLayer + 1].empty() ||
410 mTimeFrame->getTracklets()[iLayer].empty()) {
414 auto& layerCells = mTimeFrame->getCells()[iLayer];
415 const int currentLayerTrackletsNum{
static_cast<int>(mTimeFrame->getTracklets()[iLayer].size())};
417 if (mTaskArena->max_concurrency() <= 1) {
418 for (
int iTracklet{0}; iTracklet < currentLayerTrackletsNum; ++iTracklet) {
419 perTrackletCount[iTracklet] = forTrackletCells(
PassMode::OnePass{}, iLayer, layerCells, iTracklet);
421 std::exclusive_scan(perTrackletCount.begin(), perTrackletCount.end(), perTrackletCount.begin(), 0);
424 tbb::blocked_range<int>(0, currentLayerTrackletsNum),
425 [&](
const tbb::blocked_range<int>& Tracklets) {
426 for (
int iTracklet = Tracklets.begin(); iTracklet < Tracklets.end(); ++iTracklet) {
431 std::exclusive_scan(perTrackletCount.begin(), perTrackletCount.end(), perTrackletCount.begin(), 0);
432 auto totalCells{perTrackletCount.back()};
433 if (totalCells == 0) {
436 layerCells.resize(totalCells);
439 tbb::blocked_range<int>(0, currentLayerTrackletsNum),
440 [&](
const tbb::blocked_range<int>& Tracklets) {
441 for (
int iTracklet = Tracklets.begin(); iTracklet < Tracklets.end(); ++iTracklet) {
442 int offset = perTrackletCount[iTracklet];
443 if (
offset == perTrackletCount[iTracklet + 1]) {
452 auto& lut = mTimeFrame->getCellsLookupTable()[iLayer - 1];
453 lut.resize(currentLayerTrackletsNum + 1);
454 std::copy_n(perTrackletCount.begin(), currentLayerTrackletsNum + 1, lut.begin());
461 if (mTimeFrame->hasMCinformation() && mTrkParams[iteration].createArtefactLabels) {
463 tbb::blocked_range<int>(0, mTrkParams[iteration].CellsPerRoad()),
464 [&](
const tbb::blocked_range<int>& Layers) {
465 for (
int iLayer = Layers.begin(); iLayer < Layers.end(); ++iLayer) {
466 mTimeFrame->getCellsLabel(iLayer).reserve(mTimeFrame->getCells()[iLayer].size());
467 for (
const auto& cell : mTimeFrame->getCells()[iLayer]) {
468 MCCompLabel currentLab{mTimeFrame->getTrackletsLabel(iLayer)[cell.getFirstTrackletIndex()]};
469 MCCompLabel nextLab{mTimeFrame->getTrackletsLabel(iLayer + 1)[cell.getSecondTrackletIndex()]};
470 mTimeFrame->getCellsLabel(iLayer).emplace_back(currentLab == nextLab ? currentLab :
MCCompLabel());
477template <
int nLayers>
480#ifdef OPTIMISATION_OUTPUT
481 std::ofstream off(std::format(
"cellneighs{}.txt", iteration));
485 int cell{-1}, nextCell{-1},
level{-1};
488 mTaskArena->execute([&] {
489 for (
int iLayer{0}; iLayer < mTrkParams[iteration].NeighboursPerRoad(); ++iLayer) {
492 if (mTimeFrame->getCells()[iLayer + 1].empty() ||
493 mTimeFrame->getCellsLookupTable()[iLayer].empty()) {
497 int nCells{
static_cast<int>(mTimeFrame->getCells()[iLayer].size())};
500 auto forCellNeighbour = [&](
auto Tag,
int iCell,
int offset = 0) ->
int {
501 const auto& currentCellSeed{mTimeFrame->getCells()[iLayer][iCell]};
502 const int nextLayerTrackletIndex{currentCellSeed.getSecondTrackletIndex()};
503 const int nextLayerFirstCellIndex{mTimeFrame->getCellsLookupTable()[iLayer][nextLayerTrackletIndex]};
504 const int nextLayerLastCellIndex{mTimeFrame->getCellsLookupTable()[iLayer][nextLayerTrackletIndex + 1]};
505 int foundNextCells{0};
506 for (
int iNextCell{nextLayerFirstCellIndex}; iNextCell < nextLayerLastCellIndex; ++iNextCell) {
507 auto nextCellSeed{mTimeFrame->getCells()[iLayer + 1][iNextCell]};
508 if (nextCellSeed.getFirstTrackletIndex() != nextLayerTrackletIndex) {
512 if (mTrkParams[iteration].DeltaROF) {
513 const auto& trkl00 = mTimeFrame->getTracklets()[iLayer][currentCellSeed.getFirstTrackletIndex()];
514 const auto& trkl01 = mTimeFrame->getTracklets()[iLayer + 1][currentCellSeed.getSecondTrackletIndex()];
515 const auto& trkl10 = mTimeFrame->getTracklets()[iLayer + 1][nextCellSeed.getFirstTrackletIndex()];
516 const auto& trkl11 = mTimeFrame->getTracklets()[iLayer + 2][nextCellSeed.getSecondTrackletIndex()];
517 if ((std::max({trkl00.getMaxRof(), trkl01.getMaxRof(), trkl10.getMaxRof(), trkl11.getMaxRof()}) -
518 std::min({trkl00.getMinRof(), trkl01.getMinRof(), trkl10.getMinRof(), trkl11.getMinRof()})) > mTrkParams[0].DeltaROF) {
523 if (!nextCellSeed.rotate(currentCellSeed.getAlpha()) ||
524 !nextCellSeed.propagateTo(currentCellSeed.getX(), getBz())) {
527 float chi2 = currentCellSeed.getPredictedChi2(nextCellSeed);
529#ifdef OPTIMISATION_OUTPUT
530 bool good{mTimeFrame->getCellsLabel(iLayer)[iCell] == mTimeFrame->getCellsLabel(iLayer + 1)[iNextCell]};
531 off << std::format(
"{}\t{:d}\t{}", iLayer, good, chi2) << std::endl;
534 if (chi2 > mTrkParams[0].MaxChi2ClusterAttachment) {
538 if constexpr (
decltype(Tag)
::value == PassMode::OnePass::value) {
539 cellsNeighbours.emplace_back(iCell, iNextCell, currentCellSeed.getLevel() + 1);
540 }
else if constexpr (
decltype(Tag)
::value == PassMode::TwoPassCount::value) {
542 }
else if constexpr (
decltype(Tag)
::value == PassMode::TwoPassInsert::value) {
543 cellsNeighbours[
offset++] = {iCell, iNextCell, currentCellSeed.getLevel() + 1};
545 static_assert(
false,
"Unknown mode!");
548 return foundNextCells;
551 if (mTaskArena->max_concurrency() <= 1) {
552 for (
int iCell{0}; iCell < nCells; ++iCell) {
558 tbb::blocked_range<int>(0, nCells),
559 [&](
const tbb::blocked_range<int>& Cells) {
560 for (
int iCell = Cells.begin(); iCell < Cells.end(); ++iCell) {
565 std::exclusive_scan(perCellCount.begin(), perCellCount.end(), perCellCount.begin(), 0);
566 int totalCellNeighbours = perCellCount.back();
567 if (totalCellNeighbours == 0) {
571 cellsNeighbours.resize(totalCellNeighbours);
574 tbb::blocked_range<int>(0, nCells),
575 [&](
const tbb::blocked_range<int>& Cells) {
576 for (
int iCell = Cells.begin(); iCell < Cells.end(); ++iCell) {
577 int offset = perCellCount[iCell];
578 if (
offset == perCellCount[iCell + 1]) {
586 if (cellsNeighbours.empty()) {
590 tbb::parallel_sort(cellsNeighbours.begin(), cellsNeighbours.end(), [](
const auto&
a,
const auto&
b) {
591 return a.nextCell < b.nextCell;
594 auto& cellsNeighbourLUT = mTimeFrame->getCellsNeighboursLUT()[iLayer];
595 cellsNeighbourLUT.assign(mTimeFrame->getCells()[iLayer + 1].size(), 0);
596 for (
const auto& neigh : cellsNeighbours) {
597 ++cellsNeighbourLUT[neigh.nextCell];
599 std::inclusive_scan(cellsNeighbourLUT.begin(), cellsNeighbourLUT.end(), cellsNeighbourLUT.begin());
601 mTimeFrame->getCellsNeighbours()[iLayer].reserve(cellsNeighbours.size());
602 std::ranges::transform(cellsNeighbours, std::back_inserter(mTimeFrame->getCellsNeighbours()[iLayer]), [](
const auto& neigh) { return neigh.cell; });
604 for (
auto it = cellsNeighbours.begin(); it != cellsNeighbours.end();) {
605 int cellIdx = it->nextCell;
606 int maxLvl = it->level;
607 while (++it != cellsNeighbours.end() && it->nextCell == cellIdx) {
608 maxLvl = std::max(maxLvl, it->level);
610 o2::gpu::CAMath::AtomicMax(mTimeFrame->getCells()[iLayer + 1][cellIdx].getLevelPtr(), maxLvl);
616template <
int nLayers>
619 CA_DEBUGGER(std::cout <<
"Processing neighbours layer " << iLayer <<
" level " << iLevel <<
", size of the cell seeds: " << currentCellSeed.size() << std::endl);
623 int failed[5]{0, 0, 0, 0, 0}, attempts{0}, failedByMismatch{0};
626 mTaskArena->execute([&] {
627 auto forCellNeighbours = [&](
auto Tag,
int iCell,
int offset = 0) ->
int {
628 const auto& currentCell{currentCellSeed[iCell]};
630 if constexpr (
decltype(Tag)
::value != PassMode::TwoPassInsert::value) {
631 if (currentCell.getLevel() != iLevel) {
634 if (currentCellId.empty() && (mTimeFrame->isClusterUsed(iLayer, currentCell.getFirstClusterIndex()) ||
635 mTimeFrame->isClusterUsed(iLayer + 1, currentCell.getSecondClusterIndex()) ||
636 mTimeFrame->isClusterUsed(iLayer + 2, currentCell.getThirdClusterIndex()))) {
641 const int cellId = currentCellId.empty() ? iCell : currentCellId[iCell];
642 const int startNeighbourId{cellId ? mTimeFrame->getCellsNeighboursLUT()[iLayer - 1][cellId - 1] : 0};
643 const int endNeighbourId{mTimeFrame->getCellsNeighboursLUT()[iLayer - 1][cellId]};
645 for (
int iNeighbourCell{startNeighbourId}; iNeighbourCell < endNeighbourId; ++iNeighbourCell) {
647 const int neighbourCellId = mTimeFrame->getCellsNeighbours()[iLayer - 1][iNeighbourCell];
648 const auto& neighbourCell = mTimeFrame->getCells()[iLayer - 1][neighbourCellId];
649 if (neighbourCell.getSecondTrackletIndex() != currentCell.getFirstTrackletIndex()) {
653 if (mTimeFrame->isClusterUsed(iLayer - 1, neighbourCell.getFirstClusterIndex())) {
656 if (currentCell.getLevel() - 1 != neighbourCell.getLevel()) {
663 const auto& trHit = mTimeFrame->getTrackingFrameInfoOnLayer(iLayer - 1)[neighbourCell.getFirstClusterIndex()];
665 if (!seed.rotate(trHit.alphaTrackingFrame)) {
675 if (mTrkParams[0].CorrType == o2::base::PropagatorF::MatCorrType::USEMatCorrNONE) {
676 if (!seed.correctForMaterial(mTrkParams[0].LayerxX0[iLayer - 1], mTrkParams[0].LayerxX0[iLayer - 1] * constants::Radl * constants::Rho,
true)) {
681 auto predChi2{seed.getPredictedChi2Quiet(trHit.positionTrackingFrame, trHit.covarianceTrackingFrame)};
682 if ((predChi2 > mTrkParams[0].MaxChi2ClusterAttachment) || predChi2 < 0.f) {
686 seed.setChi2(seed.getChi2() + predChi2);
687 if (!seed.o2::track::TrackParCov::update(trHit.positionTrackingFrame, trHit.covarianceTrackingFrame)) {
692 if constexpr (
decltype(Tag)
::value != PassMode::TwoPassCount::value) {
693 seed.getClusters()[iLayer - 1] = neighbourCell.getFirstClusterIndex();
694 seed.setLevel(neighbourCell.getLevel());
695 seed.setFirstTrackletIndex(neighbourCell.getFirstTrackletIndex());
696 seed.setSecondTrackletIndex(neighbourCell.getSecondTrackletIndex());
699 if constexpr (
decltype(Tag)
::value == PassMode::OnePass::value) {
700 updatedCellSeeds.push_back(seed);
701 updatedCellsIds.push_back(neighbourCellId);
702 }
else if constexpr (
decltype(Tag)
::value == PassMode::TwoPassCount::value) {
704 }
else if constexpr (
decltype(Tag)
::value == PassMode::TwoPassInsert::value) {
705 updatedCellSeeds[
offset] = seed;
706 updatedCellsIds[
offset++] = neighbourCellId;
708 static_assert(
false,
"Unknown mode!");
714 const int nCells =
static_cast<int>(currentCellSeed.size());
715 if (mTaskArena->max_concurrency() <= 1) {
716 for (
int iCell{0}; iCell < nCells; ++iCell) {
722 tbb::blocked_range<int>(0, nCells),
723 [&](
const tbb::blocked_range<int>& Cells) {
724 for (
int iCell = Cells.begin(); iCell < Cells.end(); ++iCell) {
729 std::exclusive_scan(perCellCount.begin(), perCellCount.end(), perCellCount.begin(), 0);
730 auto totalNeighbours{perCellCount.back()};
731 if (totalNeighbours == 0) {
734 updatedCellSeeds.resize(totalNeighbours);
735 updatedCellsIds.resize(totalNeighbours);
738 tbb::blocked_range<int>(0, nCells),
739 [&](
const tbb::blocked_range<int>& Cells) {
740 for (
int iCell = Cells.begin(); iCell < Cells.end(); ++iCell) {
741 int offset = perCellCount[iCell];
742 if (
offset == perCellCount[iCell + 1]) {
752 std::cout <<
"\t\t- Found " << updatedCellSeeds.size() <<
" cell seeds out of " << attempts <<
" attempts" << std::endl;
753 std::cout <<
"\t\t\t> " <<
failed[0] <<
" failed because of level" << std::endl;
754 std::cout <<
"\t\t\t> " <<
failed[1] <<
" failed because of rotation" << std::endl;
755 std::cout <<
"\t\t\t> " <<
failed[2] <<
" failed because of propagation" << std::endl;
756 std::cout <<
"\t\t\t> " <<
failed[3] <<
" failed because of chi2 cut" << std::endl;
757 std::cout <<
"\t\t\t> " <<
failed[4] <<
" failed because of update" << std::endl;
758 std::cout <<
"\t\t\t> " << failedByMismatch <<
" failed because of mismatch" << std::endl;
762template <
int nLayers>
765 CA_DEBUGGER(std::cout <<
"Finding roads, iteration " << iteration << std::endl);
767 for (
int startLevel{mTrkParams[iteration].CellsPerRoad()}; startLevel >= mTrkParams[iteration].CellMinimumLevel(); --startLevel) {
768 CA_DEBUGGER(std::cout <<
"\t > Processing level " << startLevel << std::endl);
769 auto seedFilter = [&](
const auto& seed) {
770 return seed.getQ2Pt() <= 1.e3 && seed.getChi2() <= mTrkParams[0].MaxChi2NDF * ((startLevel + 2) * 2 - 5);
773 for (
int startLayer{mTrkParams[iteration].CellsPerRoad() - 1}; startLayer >= startLevel - 1; --startLayer) {
774 if ((mTrkParams[iteration].StartLayerMask & (1 << (startLayer + 2))) == 0) {
777 CA_DEBUGGER(std::cout <<
"\t\t > Starting processing layer " << startLayer << std::endl);
781 processNeighbours(startLayer, startLevel, mTimeFrame->getCells()[startLayer], lastCellId, updatedCellSeed, updatedCellId);
783 int level = startLevel;
784 for (
int iLayer{startLayer - 1}; iLayer > 0 &&
level > 2; --iLayer) {
785 lastCellSeed.swap(updatedCellSeed);
786 lastCellId.swap(updatedCellId);
789 processNeighbours(iLayer, --
level, lastCellSeed, lastCellId, updatedCellSeed, updatedCellId);
794 if (!updatedCellSeed.empty()) {
795 trackSeeds.reserve(trackSeeds.size() + std::count_if(updatedCellSeed.begin(), updatedCellSeed.end(), seedFilter));
796 std::copy_if(updatedCellSeed.begin(), updatedCellSeed.end(), std::back_inserter(trackSeeds), seedFilter);
800 if (trackSeeds.empty()) {
805 mTaskArena->execute([&] {
806 auto forSeed = [&](
auto Tag,
int iSeed,
int offset = 0) {
807 const auto& seed{trackSeeds[iSeed]};
809 temporaryTrack.resetCovariance();
810 temporaryTrack.setChi2(0);
811 for (
int iL{0}; iL < nLayers; ++iL) {
812 temporaryTrack.setExternalClusterIndex(iL, seed.getCluster(iL), seed.getCluster(iL) != constants::UnusedIndex);
815 bool fitSuccess = fitTrack(temporaryTrack, 0, mTrkParams[0].NLayers, 1, mTrkParams[0].MaxChi2ClusterAttachment, mTrkParams[0].MaxChi2NDF);
820 temporaryTrack.getParamOut() = temporaryTrack.getParamIn();
821 temporaryTrack.resetCovariance();
822 temporaryTrack.setChi2(0);
823 fitSuccess = fitTrack(temporaryTrack, mTrkParams[0].NLayers - 1, -1, -1, mTrkParams[0].MaxChi2ClusterAttachment, mTrkParams[0].MaxChi2NDF, 50.f);
824 if (!fitSuccess || temporaryTrack.getPt() < mTrkParams[iteration].MinPt[mTrkParams[iteration].NLayers - temporaryTrack.getNClusters()]) {
828 if constexpr (
decltype(Tag)
::value == PassMode::OnePass::value) {
829 tracks.push_back(temporaryTrack);
830 }
else if constexpr (
decltype(Tag)
::value == PassMode::TwoPassCount::value) {
832 }
else if constexpr (
decltype(Tag)
::value == PassMode::TwoPassInsert::value) {
833 tracks[
offset] = temporaryTrack;
835 static_assert(
false,
"Unknown mode!");
840 const int nSeeds =
static_cast<int>(trackSeeds.size());
841 if (mTaskArena->max_concurrency() <= 1) {
842 for (
int iSeed{0}; iSeed < nSeeds; ++iSeed) {
848 tbb::blocked_range<int>(0, nSeeds),
849 [&](
const tbb::blocked_range<int>& Seeds) {
850 for (
int iSeed = Seeds.begin(); iSeed < Seeds.end(); ++iSeed) {
855 std::exclusive_scan(perSeedCount.begin(), perSeedCount.end(), perSeedCount.begin(), 0);
856 auto totalTracks{perSeedCount.back()};
857 if (totalTracks == 0) {
860 tracks.resize(totalTracks);
863 tbb::blocked_range<int>(0, nSeeds),
864 [&](
const tbb::blocked_range<int>& Seeds) {
865 for (
int iSeed = Seeds.begin(); iSeed < Seeds.end(); ++iSeed) {
866 if (perSeedCount[iSeed] == perSeedCount[iSeed + 1]) {
875 tbb::parallel_sort(tracks.begin(), tracks.end(), [](
const auto&
a,
const auto&
b) {
876 return a.getChi2() < b.getChi2();
880 for (
auto& track : tracks) {
882 bool isFirstShared{
false};
883 for (
int iLayer{0}; iLayer < mTrkParams[0].NLayers; ++iLayer) {
884 if (track.getClusterIndex(iLayer) == constants::UnusedIndex) {
887 nShared +=
int(mTimeFrame->isClusterUsed(iLayer, track.getClusterIndex(iLayer)));
888 isFirstShared |= !iLayer && mTimeFrame->isClusterUsed(iLayer, track.getClusterIndex(iLayer));
891 if (nShared > mTrkParams[0].ClusterSharing) {
895 std::array<int, 3> rofs{INT_MAX, INT_MAX, INT_MAX};
896 for (
int iLayer{0}; iLayer < mTrkParams[0].NLayers; ++iLayer) {
897 if (track.getClusterIndex(iLayer) == constants::UnusedIndex) {
900 mTimeFrame->markUsedCluster(iLayer, track.getClusterIndex(iLayer));
901 int currentROF = mTimeFrame->getClusterROF(iLayer, track.getClusterIndex(iLayer));
902 for (
int iR{0}; iR < 3; ++iR) {
903 if (rofs[iR] == INT_MAX) {
904 rofs[iR] = currentROF;
906 if (rofs[iR] == currentROF) {
911 if (rofs[2] != INT_MAX) {
914 track.setUserField(0);
915 track.getParamOut().setUserField(0);
916 if (rofs[1] != INT_MAX) {
917 track.setNextROFbit();
919 mTimeFrame->getTracks(o2::gpu::CAMath::Min(rofs[0], rofs[1])).emplace_back(track);
924template <
int nLayers>
927 for (
int rof{0}; rof < mTimeFrame->getNrof(); ++rof) {
928 for (
auto& track : mTimeFrame->getTracks(rof)) {
932 if ((mTrkParams[iteration].UseTrackFollowerMix || mTrkParams[iteration].UseTrackFollowerTop) && track.getLastClusterLayer() != mTrkParams[iteration].NLayers - 1) {
933 success = success || trackFollowing(&track, rof,
true, iteration);
935 if ((mTrkParams[iteration].UseTrackFollowerMix || (mTrkParams[iteration].UseTrackFollowerBot && !success)) && track.getFirstClusterLayer() != 0) {
936 success = success || trackFollowing(&track, rof,
false, iteration);
940 track.resetCovariance();
942 bool fitSuccess = fitTrack(track, 0, mTrkParams[iteration].NLayers, 1, mTrkParams[iteration].MaxChi2ClusterAttachment, mTrkParams[0].MaxChi2NDF);
947 track.getParamOut() = track;
948 track.resetCovariance();
950 fitSuccess = fitTrack(track, mTrkParams[iteration].NLayers - 1, -1, -1, mTrkParams[iteration].MaxChi2ClusterAttachment, mTrkParams[0].MaxChi2NDF, 50.);
955 mTimeFrame->mNExtendedTracks++;
956 mTimeFrame->mNExtendedUsedClusters += track.getNClusters() - backup.getNClusters();
957 auto pattern = track.getPattern();
958 auto diff = (
pattern & ~backup.getPattern()) & 0xff;
962 for (
int iLayer{0}; iLayer < mTrkParams[iteration].NLayers; ++iLayer) {
963 if (track.getClusterIndex(iLayer) == constants::UnusedIndex) {
966 mTimeFrame->markUsedCluster(iLayer, track.getClusterIndex(iLayer));
973template <
int nLayers>
977 mTimeFrame->fillPrimaryVerticesXandAlpha();
979 for (
auto& cell : mTimeFrame->getCells()[0]) {
980 auto& cluster3_glo = mTimeFrame->getClusters()[2][cell.getThirdClusterIndex()];
981 auto& cluster2_glo = mTimeFrame->getClusters()[1][cell.getSecondClusterIndex()];
982 auto& cluster1_glo = mTimeFrame->getClusters()[0][cell.getFirstClusterIndex()];
983 if (mTimeFrame->isClusterUsed(2, cluster1_glo.clusterId) ||
984 mTimeFrame->isClusterUsed(1, cluster2_glo.clusterId) ||
985 mTimeFrame->isClusterUsed(0, cluster3_glo.clusterId)) {
989 std::array<int, 3> rofs{
990 mTimeFrame->getClusterROF(2, cluster3_glo.clusterId),
991 mTimeFrame->getClusterROF(1, cluster2_glo.clusterId),
992 mTimeFrame->getClusterROF(0, cluster1_glo.clusterId)};
993 if (rofs[0] != rofs[1] && rofs[1] != rofs[2] && rofs[0] != rofs[2]) {
998 if (rofs[1] == rofs[2]) {
1002 auto pvs{mTimeFrame->getPrimaryVertices(rof)};
1003 auto pvsXAlpha{mTimeFrame->getPrimaryVerticesXAlpha(rof)};
1005 const auto& cluster3_tf = mTimeFrame->getTrackingFrameInfoOnLayer(2)[cluster3_glo.clusterId];
1006 TrackITSExt temporaryTrack{buildTrackSeed(cluster1_glo, cluster2_glo, cluster3_tf)};
1007 temporaryTrack.setExternalClusterIndex(0, cluster1_glo.clusterId,
true);
1008 temporaryTrack.setExternalClusterIndex(1, cluster2_glo.clusterId,
true);
1009 temporaryTrack.setExternalClusterIndex(2, cluster3_glo.clusterId,
true);
1012 bool fitSuccess = fitTrack(temporaryTrack, 1, -1, -1);
1018 TrackITSExt bestTrack{temporaryTrack}, backup{temporaryTrack};
1019 float bestChi2{std::numeric_limits<float>::max()};
1020 for (
int iV{0}; iV < (
int)pvs.size(); ++iV) {
1021 temporaryTrack = backup;
1022 if (!temporaryTrack.rotate(pvsXAlpha[iV][1])) {
1025 if (!propagator->propagateTo(temporaryTrack, pvsXAlpha[iV][0],
true)) {
1029 float pvRes{mTrkParams[0].PVres / o2::gpu::CAMath::Sqrt(
float(pvs[iV].getNContributors()))};
1030 const float posVtx[2]{0.f, pvs[iV].getZ()};
1031 const float covVtx[3]{pvRes, 0.f, pvRes};
1032 float chi2 = temporaryTrack.getPredictedChi2Quiet(posVtx, covVtx);
1033 if (chi2 < bestChi2) {
1034 if (!temporaryTrack.track::TrackParCov::update(posVtx, covVtx)) {
1037 bestTrack = temporaryTrack;
1042 bestTrack.resetCovariance();
1043 bestTrack.setChi2(0.f);
1044 fitSuccess = fitTrack(bestTrack, 0, mTrkParams[0].NLayers, 1, mTrkParams[0].MaxChi2ClusterAttachment, mTrkParams[0].MaxChi2NDF);
1048 bestTrack.getParamOut() = bestTrack;
1049 bestTrack.resetCovariance();
1050 bestTrack.setChi2(0.f);
1051 fitSuccess = fitTrack(bestTrack, mTrkParams[0].NLayers - 1, -1, -1, mTrkParams[0].MaxChi2ClusterAttachment, mTrkParams[0].MaxChi2NDF, 50.);
1055 mTimeFrame->markUsedCluster(0, bestTrack.getClusterIndex(0));
1056 mTimeFrame->markUsedCluster(1, bestTrack.getClusterIndex(1));
1057 mTimeFrame->markUsedCluster(2, bestTrack.getClusterIndex(2));
1058 mTimeFrame->getTracks(rof).emplace_back(bestTrack);
1062template <
int nLayers>
1067 for (
int iLayer{
start}; iLayer !=
end; iLayer += step) {
1068 if (track.getClusterIndex(iLayer) == constants::UnusedIndex) {
1071 const TrackingFrameInfo& trackingHit = mTimeFrame->getTrackingFrameInfoOnLayer(iLayer)[track.getClusterIndex(iLayer)];
1073 if (!track.rotate(trackingHit.alphaTrackingFrame)) {
1081 if (mTrkParams[0].CorrType == o2::base::PropagatorF::MatCorrType::USEMatCorrNONE) {
1082 if (!track.correctForMaterial(mTrkParams[0].LayerxX0[iLayer], mTrkParams[0].LayerxX0[iLayer] * constants::Radl * constants::Rho,
true)) {
1087 auto predChi2{track.getPredictedChi2Quiet(trackingHit.positionTrackingFrame, trackingHit.covarianceTrackingFrame)};
1088 if ((nCl >= 3 && predChi2 > chi2clcut) || predChi2 < 0.f) {
1091 track.setChi2(track.getChi2() + predChi2);
1092 if (!track.o2::track::TrackParCov::update(trackingHit.positionTrackingFrame, trackingHit.covarianceTrackingFrame)) {
1097 return std::abs(track.getQ2Pt()) < maxQoverPt && track.getChi2() < chi2ndfcut * (nCl * 2 - 5);
1100template <
int nLayers>
1104 const int step = -1 + outward * 2;
1105 const int end = outward ? mTrkParams[iteration].NLayers - 1 : 0;
1107 for (
size_t iHypo{0}; iHypo < hypotheses.size(); ++iHypo) {
1108 auto hypo{hypotheses[iHypo]};
1109 int iLayer =
static_cast<int>(outward ? hypo.getLastClusterLayer() : hypo.getFirstClusterLayer());
1111 while (iLayer !=
end) {
1113 const float r = mTrkParams[iteration].LayerRadii[iLayer];
1120 auto& hypoParam{outward ? hypo.getParamOut() : hypo.getParamIn()};
1121 if (!propInstance->propagateToX(hypoParam,
x, mTimeFrame->getBz(), PropagatorF::MAX_SIN_PHI,
1122 PropagatorF::MAX_STEP, mTrkParams[iteration].CorrType)) {
1126 if (mTrkParams[iteration].CorrType == PropagatorF::MatCorrType::USEMatCorrNONE) {
1127 if (!hypoParam.correctForMaterial(mTrkParams[iteration].LayerxX0[iLayer], mTrkParams[iteration].LayerxX0[iLayer] * constants::Radl * constants::Rho,
true)) {
1133 const float phi{hypoParam.getPhi()};
1134 const float ePhi{o2::gpu::CAMath::Sqrt(hypoParam.getSigmaSnp2() / hypoParam.getCsp2())};
1135 const float z{hypoParam.getZ()};
1136 const float eZ{o2::gpu::CAMath::Sqrt(hypoParam.getSigmaZ2())};
1137 const int4 selectedBinsRect{getBinsRect(iLayer, phi, mTrkParams[iteration].TrackFollowerNSigmaCutPhi * ePhi,
z, mTrkParams[iteration].TrackFollowerNSigmaCutZ * eZ)};
1138 if (selectedBinsRect.x == 0 && selectedBinsRect.y == 0 && selectedBinsRect.z == 0 && selectedBinsRect.w == 0) {
1142 int phiBinsNum{selectedBinsRect.
w - selectedBinsRect.y + 1};
1144 if (phiBinsNum < 0) {
1145 phiBinsNum += mTrkParams[iteration].PhiBins;
1148 gsl::span<const Cluster> layer1 = mTimeFrame->getClustersOnLayer(rof, iLayer);
1149 if (layer1.empty()) {
1154 for (
int iPhiCount = 0; iPhiCount < phiBinsNum; iPhiCount++) {
1155 int iPhiBin = (selectedBinsRect.y + iPhiCount) % mTrkParams[iteration].PhiBins;
1156 const int firstBinIndex{mTimeFrame->mIndexTableUtils.getBinIndex(selectedBinsRect.x, iPhiBin)};
1157 const int maxBinIndex{firstBinIndex + selectedBinsRect.z - selectedBinsRect.x + 1};
1158 const int firstRowClusterIndex = mTimeFrame->getIndexTable(rof, iLayer)[firstBinIndex];
1159 const int maxRowClusterIndex = mTimeFrame->getIndexTable(rof, iLayer)[maxBinIndex];
1161 for (
int iNextCluster{firstRowClusterIndex}; iNextCluster < maxRowClusterIndex; ++iNextCluster) {
1162 if (iNextCluster >= (
int)layer1.size()) {
1165 const Cluster& nextCluster{layer1[iNextCluster]};
1167 if (mTimeFrame->isClusterUsed(iLayer, nextCluster.clusterId)) {
1171 const TrackingFrameInfo& trackingHit = mTimeFrame->getTrackingFrameInfoOnLayer(iLayer)[nextCluster.clusterId];
1173 auto tbupdated{hypo};
1174 auto& tbuParams = outward ? tbupdated.getParamOut() : tbupdated.getParamIn();
1179 if (!propInstance->propagateToX(tbuParams, trackingHit.
xTrackingFrame, mTimeFrame->getBz(),
1180 PropagatorF::MAX_SIN_PHI, PropagatorF::MAX_STEP, PropagatorF::MatCorrType::USEMatCorrNONE)) {
1185 if (predChi2 >= track->getChi2() * mTrkParams[iteration].NSigmaCut) {
1192 tbupdated.setChi2(tbupdated.getChi2() + predChi2);
1193 tbupdated.setExternalClusterIndex(iLayer, nextCluster.clusterId,
true);
1194 hypotheses.emplace_back(tbupdated);
1201 bool swapped{
false};
1202 for (
auto& hypo : hypotheses) {
1203 if (hypo.isBetter(*bestHypo, track->getChi2() * mTrkParams[iteration].NSigmaCut)) {
1214template <
int nLayers>
1217 float ca{-999.f}, sa{-999.f};
1228 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};
1230 tgp = o2::gpu::CAMath::ATan2(y3 -
y1, x3 -
x1);
1231 snp = tgp / o2::gpu::CAMath::Sqrt(1.f + tgp * tgp);
1233 crv = math_utils::computeCurvature(x3, y3, x2, y2,
x1,
y1);
1234 snp = crv * (
x3 - math_utils::computeCurvatureCentreX(x3, y3, x2, y2,
x1,
y1));
1238 tgl12 = math_utils::computeTanDipAngle(
x1,
y1, x2, y2, z1, z2);
1239 tgl23 = math_utils::computeTanDipAngle(x2, y2, x3, y3, z2, z3);
1240 sg2q2pt =
track::kC1Pt2max * (q2pt2 > 0.0005f ? (q2pt2 < 1.f ? q2pt2 : 1.f) : 0.0005f);
1241 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}};
1244template <
int nLayers>
1248 mIsZeroField = std::abs(mBz) < 0.01;
1249 mTimeFrame->setBz(bz);
1252template <
int nLayers>
1258template <
int nLayers>
1261#if defined(OPTIMISATION_OUTPUT) || defined(CA_DEBUG)
1262 mTaskArena = std::make_shared<tbb::task_arena>(1);
1264 if (arena ==
nullptr) {
1265 mTaskArena = std::make_shared<tbb::task_arena>(std::abs(
n));
1266 LOGP(info,
"Setting tracker with {} threads.",
n);
1269 LOGP(info,
"Attaching tracker to calling thread's arena");