82 if (primaryVertices.empty()) {
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 auto it = cellsNeighbours.begin();
605 int current = it->nextCell;
606 int maxLvl = it->level;
608 for (; it != cellsNeighbours.end(); ++it) {
609 if (it->nextCell == current) {
610 maxLvl = std::max(maxLvl, it->level);
612 mTimeFrame->getCells()[iLayer + 1][current].setLevel(maxLvl);
613 current = it->nextCell;
617 mTimeFrame->getCells()[iLayer + 1][current].setLevel(maxLvl);
622template <
int nLayers>
625 CA_DEBUGGER(std::cout <<
"Processing neighbours layer " << iLayer <<
" level " << iLevel <<
", size of the cell seeds: " << currentCellSeed.size() << std::endl);
629 int failed[5]{0, 0, 0, 0, 0}, attempts{0}, failedByMismatch{0};
632 mTaskArena->execute([&] {
633 auto forCellNeighbours = [&](
auto Tag,
int iCell,
int offset = 0) ->
int {
634 const auto& currentCell{currentCellSeed[iCell]};
636 if constexpr (
decltype(Tag)
::value != PassMode::TwoPassInsert::value) {
637 if (currentCell.getLevel() != iLevel) {
640 if (currentCellId.empty() && (mTimeFrame->isClusterUsed(iLayer, currentCell.getFirstClusterIndex()) ||
641 mTimeFrame->isClusterUsed(iLayer + 1, currentCell.getSecondClusterIndex()) ||
642 mTimeFrame->isClusterUsed(iLayer + 2, currentCell.getThirdClusterIndex()))) {
647 const int cellId = currentCellId.empty() ? iCell : currentCellId[iCell];
648 const int startNeighbourId{cellId ? mTimeFrame->getCellsNeighboursLUT()[iLayer - 1][cellId - 1] : 0};
649 const int endNeighbourId{mTimeFrame->getCellsNeighboursLUT()[iLayer - 1][cellId]};
651 for (
int iNeighbourCell{startNeighbourId}; iNeighbourCell < endNeighbourId; ++iNeighbourCell) {
653 const int neighbourCellId = mTimeFrame->getCellsNeighbours()[iLayer - 1][iNeighbourCell];
654 const auto& neighbourCell = mTimeFrame->getCells()[iLayer - 1][neighbourCellId];
655 if (neighbourCell.getSecondTrackletIndex() != currentCell.getFirstTrackletIndex()) {
659 if (mTimeFrame->isClusterUsed(iLayer - 1, neighbourCell.getFirstClusterIndex())) {
662 if (currentCell.getLevel() - 1 != neighbourCell.getLevel()) {
669 const auto& trHit = mTimeFrame->getTrackingFrameInfoOnLayer(iLayer - 1)[neighbourCell.getFirstClusterIndex()];
671 if (!seed.rotate(trHit.alphaTrackingFrame)) {
681 if (mTrkParams[0].CorrType == o2::base::PropagatorF::MatCorrType::USEMatCorrNONE) {
682 if (!seed.correctForMaterial(mTrkParams[0].LayerxX0[iLayer - 1], mTrkParams[0].LayerxX0[iLayer - 1] * constants::Radl * constants::Rho,
true)) {
687 auto predChi2{seed.getPredictedChi2Quiet(trHit.positionTrackingFrame, trHit.covarianceTrackingFrame)};
688 if ((predChi2 > mTrkParams[0].MaxChi2ClusterAttachment) || predChi2 < 0.f) {
692 seed.setChi2(seed.getChi2() + predChi2);
693 if (!seed.o2::track::TrackParCov::update(trHit.positionTrackingFrame, trHit.covarianceTrackingFrame)) {
698 if constexpr (
decltype(Tag)
::value != PassMode::TwoPassCount::value) {
699 seed.getClusters()[iLayer - 1] = neighbourCell.getFirstClusterIndex();
700 seed.setLevel(neighbourCell.getLevel());
701 seed.setFirstTrackletIndex(neighbourCell.getFirstTrackletIndex());
702 seed.setSecondTrackletIndex(neighbourCell.getSecondTrackletIndex());
705 if constexpr (
decltype(Tag)
::value == PassMode::OnePass::value) {
706 updatedCellSeeds.push_back(seed);
707 updatedCellsIds.push_back(neighbourCellId);
708 }
else if constexpr (
decltype(Tag)
::value == PassMode::TwoPassCount::value) {
710 }
else if constexpr (
decltype(Tag)
::value == PassMode::TwoPassInsert::value) {
711 updatedCellSeeds[
offset] = seed;
712 updatedCellsIds[
offset++] = neighbourCellId;
714 static_assert(
false,
"Unknown mode!");
720 const int nCells =
static_cast<int>(currentCellSeed.size());
721 if (mTaskArena->max_concurrency() <= 1) {
722 for (
int iCell{0}; iCell < nCells; ++iCell) {
728 tbb::blocked_range<int>(0, nCells),
729 [&](
const tbb::blocked_range<int>& Cells) {
730 for (
int iCell = Cells.begin(); iCell < Cells.end(); ++iCell) {
735 std::exclusive_scan(perCellCount.begin(), perCellCount.end(), perCellCount.begin(), 0);
736 auto totalNeighbours{perCellCount.back()};
737 if (totalNeighbours == 0) {
740 updatedCellSeeds.resize(totalNeighbours);
741 updatedCellsIds.resize(totalNeighbours);
744 tbb::blocked_range<int>(0, nCells),
745 [&](
const tbb::blocked_range<int>& Cells) {
746 for (
int iCell = Cells.begin(); iCell < Cells.end(); ++iCell) {
747 int offset = perCellCount[iCell];
748 if (
offset == perCellCount[iCell + 1]) {
758 std::cout <<
"\t\t- Found " << updatedCellSeeds.size() <<
" cell seeds out of " << attempts <<
" attempts" << std::endl;
759 std::cout <<
"\t\t\t> " <<
failed[0] <<
" failed because of level" << std::endl;
760 std::cout <<
"\t\t\t> " <<
failed[1] <<
" failed because of rotation" << std::endl;
761 std::cout <<
"\t\t\t> " <<
failed[2] <<
" failed because of propagation" << std::endl;
762 std::cout <<
"\t\t\t> " <<
failed[3] <<
" failed because of chi2 cut" << std::endl;
763 std::cout <<
"\t\t\t> " <<
failed[4] <<
" failed because of update" << std::endl;
764 std::cout <<
"\t\t\t> " << failedByMismatch <<
" failed because of mismatch" << std::endl;
768template <
int nLayers>
771 CA_DEBUGGER(std::cout <<
"Finding roads, iteration " << iteration << std::endl);
773 for (
int startLevel{mTrkParams[iteration].CellsPerRoad()}; startLevel >= mTrkParams[iteration].CellMinimumLevel(); --startLevel) {
774 CA_DEBUGGER(std::cout <<
"\t > Processing level " << startLevel << std::endl);
775 auto seedFilter = [&](
const auto& seed) {
776 return seed.getQ2Pt() <= 1.e3 && seed.getChi2() <= mTrkParams[0].MaxChi2NDF * ((startLevel + 2) * 2 - 5);
779 for (
int startLayer{mTrkParams[iteration].CellsPerRoad() - 1}; startLayer >= startLevel - 1; --startLayer) {
780 if ((mTrkParams[iteration].StartLayerMask & (1 << (startLayer + 2))) == 0) {
783 CA_DEBUGGER(std::cout <<
"\t\t > Starting processing layer " << startLayer << std::endl);
787 processNeighbours(startLayer, startLevel, mTimeFrame->getCells()[startLayer], lastCellId, updatedCellSeed, updatedCellId);
789 int level = startLevel;
790 for (
int iLayer{startLayer - 1}; iLayer > 0 &&
level > 2; --iLayer) {
791 lastCellSeed.swap(updatedCellSeed);
792 lastCellId.swap(updatedCellId);
795 processNeighbours(iLayer, --
level, lastCellSeed, lastCellId, updatedCellSeed, updatedCellId);
800 if (!updatedCellSeed.empty()) {
801 trackSeeds.reserve(trackSeeds.size() + std::count_if(updatedCellSeed.begin(), updatedCellSeed.end(), seedFilter));
802 std::copy_if(updatedCellSeed.begin(), updatedCellSeed.end(), std::back_inserter(trackSeeds), seedFilter);
806 if (trackSeeds.empty()) {
811 mTaskArena->execute([&] {
812 auto forSeed = [&](
auto Tag,
int iSeed,
int offset = 0) {
813 const auto& seed{trackSeeds[iSeed]};
815 temporaryTrack.resetCovariance();
816 temporaryTrack.setChi2(0);
817 for (
int iL{0}; iL < 7; ++iL) {
818 temporaryTrack.setExternalClusterIndex(iL, seed.getCluster(iL), seed.getCluster(iL) != constants::UnusedIndex);
821 bool fitSuccess = fitTrack(temporaryTrack, 0, mTrkParams[0].NLayers, 1, mTrkParams[0].MaxChi2ClusterAttachment, mTrkParams[0].MaxChi2NDF);
826 temporaryTrack.getParamOut() = temporaryTrack.getParamIn();
827 temporaryTrack.resetCovariance();
828 temporaryTrack.setChi2(0);
829 fitSuccess = fitTrack(temporaryTrack, mTrkParams[0].NLayers - 1, -1, -1, mTrkParams[0].MaxChi2ClusterAttachment, mTrkParams[0].MaxChi2NDF, 50.f);
830 if (!fitSuccess || temporaryTrack.getPt() < mTrkParams[iteration].MinPt[mTrkParams[iteration].NLayers - temporaryTrack.getNClusters()]) {
834 if constexpr (
decltype(Tag)
::value == PassMode::OnePass::value) {
835 tracks.push_back(temporaryTrack);
836 }
else if constexpr (
decltype(Tag)
::value == PassMode::TwoPassCount::value) {
838 }
else if constexpr (
decltype(Tag)
::value == PassMode::TwoPassInsert::value) {
839 tracks[
offset] = temporaryTrack;
841 static_assert(
false,
"Unknown mode!");
846 const int nSeeds =
static_cast<int>(trackSeeds.size());
847 if (mTaskArena->max_concurrency() <= 1) {
848 for (
int iSeed{0}; iSeed < nSeeds; ++iSeed) {
854 tbb::blocked_range<int>(0, nSeeds),
855 [&](
const tbb::blocked_range<int>& Seeds) {
856 for (
int iSeed = Seeds.begin(); iSeed < Seeds.end(); ++iSeed) {
861 std::exclusive_scan(perSeedCount.begin(), perSeedCount.end(), perSeedCount.begin(), 0);
862 auto totalTracks{perSeedCount.back()};
863 if (totalTracks == 0) {
866 tracks.resize(totalTracks);
869 tbb::blocked_range<int>(0, nSeeds),
870 [&](
const tbb::blocked_range<int>& Seeds) {
871 for (
int iSeed = Seeds.begin(); iSeed < Seeds.end(); ++iSeed) {
872 if (perSeedCount[iSeed] == perSeedCount[iSeed + 1]) {
881 tbb::parallel_sort(tracks.begin(), tracks.end(), [](
const auto&
a,
const auto&
b) {
882 return a.getChi2() < b.getChi2();
886 for (
auto& track : tracks) {
888 bool isFirstShared{
false};
889 for (
int iLayer{0}; iLayer < mTrkParams[0].NLayers; ++iLayer) {
890 if (track.getClusterIndex(iLayer) == constants::UnusedIndex) {
893 nShared +=
int(mTimeFrame->isClusterUsed(iLayer, track.getClusterIndex(iLayer)));
894 isFirstShared |= !iLayer && mTimeFrame->isClusterUsed(iLayer, track.getClusterIndex(iLayer));
897 if (nShared > mTrkParams[0].ClusterSharing) {
901 std::array<int, 3> rofs{INT_MAX, INT_MAX, INT_MAX};
902 for (
int iLayer{0}; iLayer < mTrkParams[0].NLayers; ++iLayer) {
903 if (track.getClusterIndex(iLayer) == constants::UnusedIndex) {
906 mTimeFrame->markUsedCluster(iLayer, track.getClusterIndex(iLayer));
907 int currentROF = mTimeFrame->getClusterROF(iLayer, track.getClusterIndex(iLayer));
908 for (
int iR{0}; iR < 3; ++iR) {
909 if (rofs[iR] == INT_MAX) {
910 rofs[iR] = currentROF;
912 if (rofs[iR] == currentROF) {
917 if (rofs[2] != INT_MAX) {
920 track.setUserField(0);
921 track.getParamOut().setUserField(0);
922 if (rofs[1] != INT_MAX) {
923 track.setNextROFbit();
925 mTimeFrame->getTracks(o2::gpu::CAMath::Min(rofs[0], rofs[1])).emplace_back(track);
930template <
int nLayers>
933 for (
int rof{0}; rof < mTimeFrame->getNrof(); ++rof) {
934 for (
auto& track : mTimeFrame->getTracks(rof)) {
938 if ((mTrkParams[iteration].UseTrackFollowerMix || mTrkParams[iteration].UseTrackFollowerTop) && track.getLastClusterLayer() != mTrkParams[iteration].NLayers - 1) {
939 success = success || trackFollowing(&track, rof,
true, iteration);
941 if ((mTrkParams[iteration].UseTrackFollowerMix || (mTrkParams[iteration].UseTrackFollowerBot && !success)) && track.getFirstClusterLayer() != 0) {
942 success = success || trackFollowing(&track, rof,
false, iteration);
946 track.resetCovariance();
948 bool fitSuccess = fitTrack(track, 0, mTrkParams[iteration].NLayers, 1, mTrkParams[iteration].MaxChi2ClusterAttachment, mTrkParams[0].MaxChi2NDF);
953 track.getParamOut() = track;
954 track.resetCovariance();
956 fitSuccess = fitTrack(track, mTrkParams[iteration].NLayers - 1, -1, -1, mTrkParams[iteration].MaxChi2ClusterAttachment, mTrkParams[0].MaxChi2NDF, 50.);
961 mTimeFrame->mNExtendedTracks++;
962 mTimeFrame->mNExtendedUsedClusters += track.getNClusters() - backup.getNClusters();
963 auto pattern = track.getPattern();
964 auto diff = (
pattern & ~backup.getPattern()) & 0xff;
968 for (
int iLayer{0}; iLayer < mTrkParams[iteration].NLayers; ++iLayer) {
969 if (track.getClusterIndex(iLayer) == constants::UnusedIndex) {
972 mTimeFrame->markUsedCluster(iLayer, track.getClusterIndex(iLayer));
979template <
int nLayers>
983 mTimeFrame->fillPrimaryVerticesXandAlpha();
985 for (
auto& cell : mTimeFrame->getCells()[0]) {
986 auto& cluster3_glo = mTimeFrame->getClusters()[2][cell.getThirdClusterIndex()];
987 auto& cluster2_glo = mTimeFrame->getClusters()[1][cell.getSecondClusterIndex()];
988 auto& cluster1_glo = mTimeFrame->getClusters()[0][cell.getFirstClusterIndex()];
989 if (mTimeFrame->isClusterUsed(2, cluster1_glo.clusterId) ||
990 mTimeFrame->isClusterUsed(1, cluster2_glo.clusterId) ||
991 mTimeFrame->isClusterUsed(0, cluster3_glo.clusterId)) {
995 std::array<int, 3> rofs{
996 mTimeFrame->getClusterROF(2, cluster3_glo.clusterId),
997 mTimeFrame->getClusterROF(1, cluster2_glo.clusterId),
998 mTimeFrame->getClusterROF(0, cluster1_glo.clusterId)};
999 if (rofs[0] != rofs[1] && rofs[1] != rofs[2] && rofs[0] != rofs[2]) {
1004 if (rofs[1] == rofs[2]) {
1008 auto pvs{mTimeFrame->getPrimaryVertices(rof)};
1009 auto pvsXAlpha{mTimeFrame->getPrimaryVerticesXAlpha(rof)};
1011 const auto& cluster3_tf = mTimeFrame->getTrackingFrameInfoOnLayer(2)[cluster3_glo.clusterId];
1012 TrackITSExt temporaryTrack{buildTrackSeed(cluster1_glo, cluster2_glo, cluster3_tf)};
1013 temporaryTrack.setExternalClusterIndex(0, cluster1_glo.clusterId,
true);
1014 temporaryTrack.setExternalClusterIndex(1, cluster2_glo.clusterId,
true);
1015 temporaryTrack.setExternalClusterIndex(2, cluster3_glo.clusterId,
true);
1018 bool fitSuccess = fitTrack(temporaryTrack, 1, -1, -1);
1024 TrackITSExt bestTrack{temporaryTrack}, backup{temporaryTrack};
1025 float bestChi2{std::numeric_limits<float>::max()};
1026 for (
int iV{0}; iV < (
int)pvs.size(); ++iV) {
1027 temporaryTrack = backup;
1028 if (!temporaryTrack.rotate(pvsXAlpha[iV][1])) {
1031 if (!propagator->propagateTo(temporaryTrack, pvsXAlpha[iV][0],
true)) {
1035 float pvRes{mTrkParams[0].PVres / o2::gpu::CAMath::Sqrt(
float(pvs[iV].getNContributors()))};
1036 const float posVtx[2]{0.f, pvs[iV].getZ()};
1037 const float covVtx[3]{pvRes, 0.f, pvRes};
1038 float chi2 = temporaryTrack.getPredictedChi2Quiet(posVtx, covVtx);
1039 if (chi2 < bestChi2) {
1040 if (!temporaryTrack.track::TrackParCov::update(posVtx, covVtx)) {
1043 bestTrack = temporaryTrack;
1048 bestTrack.resetCovariance();
1049 bestTrack.setChi2(0.f);
1050 fitSuccess = fitTrack(bestTrack, 0, mTrkParams[0].NLayers, 1, mTrkParams[0].MaxChi2ClusterAttachment, mTrkParams[0].MaxChi2NDF);
1054 bestTrack.getParamOut() = bestTrack;
1055 bestTrack.resetCovariance();
1056 bestTrack.setChi2(0.f);
1057 fitSuccess = fitTrack(bestTrack, mTrkParams[0].NLayers - 1, -1, -1, mTrkParams[0].MaxChi2ClusterAttachment, mTrkParams[0].MaxChi2NDF, 50.);
1061 mTimeFrame->markUsedCluster(0, bestTrack.getClusterIndex(0));
1062 mTimeFrame->markUsedCluster(1, bestTrack.getClusterIndex(1));
1063 mTimeFrame->markUsedCluster(2, bestTrack.getClusterIndex(2));
1064 mTimeFrame->getTracks(rof).emplace_back(bestTrack);
1068template <
int nLayers>
1073 for (
int iLayer{
start}; iLayer !=
end; iLayer += step) {
1074 if (track.getClusterIndex(iLayer) == constants::UnusedIndex) {
1077 const TrackingFrameInfo& trackingHit = mTimeFrame->getTrackingFrameInfoOnLayer(iLayer)[track.getClusterIndex(iLayer)];
1079 if (!track.rotate(trackingHit.alphaTrackingFrame)) {
1087 if (mTrkParams[0].CorrType == o2::base::PropagatorF::MatCorrType::USEMatCorrNONE) {
1088 if (!track.correctForMaterial(mTrkParams[0].LayerxX0[iLayer], mTrkParams[0].LayerxX0[iLayer] * constants::Radl * constants::Rho,
true)) {
1093 auto predChi2{track.getPredictedChi2Quiet(trackingHit.positionTrackingFrame, trackingHit.covarianceTrackingFrame)};
1094 if ((nCl >= 3 && predChi2 > chi2clcut) || predChi2 < 0.f) {
1097 track.setChi2(track.getChi2() + predChi2);
1098 if (!track.o2::track::TrackParCov::update(trackingHit.positionTrackingFrame, trackingHit.covarianceTrackingFrame)) {
1103 return std::abs(track.getQ2Pt()) < maxQoverPt && track.getChi2() < chi2ndfcut * (nCl * 2 - 5);
1106template <
int nLayers>
1110 const int step = -1 + outward * 2;
1111 const int end = outward ? mTrkParams[iteration].NLayers - 1 : 0;
1113 for (
size_t iHypo{0}; iHypo < hypotheses.size(); ++iHypo) {
1114 auto hypo{hypotheses[iHypo]};
1115 int iLayer =
static_cast<int>(outward ? hypo.getLastClusterLayer() : hypo.getFirstClusterLayer());
1117 while (iLayer !=
end) {
1119 const float r = mTrkParams[iteration].LayerRadii[iLayer];
1126 auto& hypoParam{outward ? hypo.getParamOut() : hypo.getParamIn()};
1127 if (!propInstance->propagateToX(hypoParam,
x, mTimeFrame->getBz(), PropagatorF::MAX_SIN_PHI,
1128 PropagatorF::MAX_STEP, mTrkParams[iteration].CorrType)) {
1132 if (mTrkParams[iteration].CorrType == PropagatorF::MatCorrType::USEMatCorrNONE) {
1133 if (!hypoParam.correctForMaterial(mTrkParams[iteration].LayerxX0[iLayer], mTrkParams[iteration].LayerxX0[iLayer] * constants::Radl * constants::Rho,
true)) {
1139 const float phi{hypoParam.getPhi()};
1140 const float ePhi{o2::gpu::CAMath::Sqrt(hypoParam.getSigmaSnp2() / hypoParam.getCsp2())};
1141 const float z{hypoParam.getZ()};
1142 const float eZ{o2::gpu::CAMath::Sqrt(hypoParam.getSigmaZ2())};
1143 const int4 selectedBinsRect{getBinsRect(iLayer, phi, mTrkParams[iteration].TrackFollowerNSigmaCutPhi * ePhi,
z, mTrkParams[iteration].TrackFollowerNSigmaCutZ * eZ)};
1144 if (selectedBinsRect.x == 0 && selectedBinsRect.y == 0 && selectedBinsRect.z == 0 && selectedBinsRect.w == 0) {
1148 int phiBinsNum{selectedBinsRect.
w - selectedBinsRect.y + 1};
1150 if (phiBinsNum < 0) {
1151 phiBinsNum += mTrkParams[iteration].PhiBins;
1154 gsl::span<const Cluster> layer1 = mTimeFrame->getClustersOnLayer(rof, iLayer);
1155 if (layer1.empty()) {
1160 for (
int iPhiCount = 0; iPhiCount < phiBinsNum; iPhiCount++) {
1161 int iPhiBin = (selectedBinsRect.y + iPhiCount) % mTrkParams[iteration].PhiBins;
1162 const int firstBinIndex{mTimeFrame->mIndexTableUtils.getBinIndex(selectedBinsRect.x, iPhiBin)};
1163 const int maxBinIndex{firstBinIndex + selectedBinsRect.z - selectedBinsRect.x + 1};
1164 const int firstRowClusterIndex = mTimeFrame->getIndexTable(rof, iLayer)[firstBinIndex];
1165 const int maxRowClusterIndex = mTimeFrame->getIndexTable(rof, iLayer)[maxBinIndex];
1167 for (
int iNextCluster{firstRowClusterIndex}; iNextCluster < maxRowClusterIndex; ++iNextCluster) {
1168 if (iNextCluster >= (
int)layer1.size()) {
1171 const Cluster& nextCluster{layer1[iNextCluster]};
1173 if (mTimeFrame->isClusterUsed(iLayer, nextCluster.clusterId)) {
1177 const TrackingFrameInfo& trackingHit = mTimeFrame->getTrackingFrameInfoOnLayer(iLayer)[nextCluster.clusterId];
1179 auto tbupdated{hypo};
1180 auto& tbuParams = outward ? tbupdated.getParamOut() : tbupdated.getParamIn();
1185 if (!propInstance->propagateToX(tbuParams, trackingHit.
xTrackingFrame, mTimeFrame->getBz(),
1186 PropagatorF::MAX_SIN_PHI, PropagatorF::MAX_STEP, PropagatorF::MatCorrType::USEMatCorrNONE)) {
1191 if (predChi2 >= track->getChi2() * mTrkParams[iteration].NSigmaCut) {
1198 tbupdated.setChi2(tbupdated.getChi2() + predChi2);
1199 tbupdated.setExternalClusterIndex(iLayer, nextCluster.clusterId,
true);
1200 hypotheses.emplace_back(tbupdated);
1207 bool swapped{
false};
1208 for (
auto& hypo : hypotheses) {
1209 if (hypo.isBetter(*bestHypo, track->getChi2() * mTrkParams[iteration].NSigmaCut)) {
1220template <
int nLayers>
1223 float ca{-999.f}, sa{-999.f};
1234 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};
1236 tgp = o2::gpu::CAMath::ATan2(y3 -
y1, x3 -
x1);
1237 snp = tgp / o2::gpu::CAMath::Sqrt(1.f + tgp * tgp);
1239 crv = math_utils::computeCurvature(x3, y3, x2, y2,
x1,
y1);
1240 snp = crv * (
x3 - math_utils::computeCurvatureCentreX(x3, y3, x2, y2,
x1,
y1));
1244 tgl12 = math_utils::computeTanDipAngle(
x1,
y1, x2, y2, z1, z2);
1245 tgl23 = math_utils::computeTanDipAngle(x2, y2, x3, y3, z2, z3);
1246 sg2q2pt =
track::kC1Pt2max * (q2pt2 > 0.0005f ? (q2pt2 < 1.f ? q2pt2 : 1.f) : 0.0005f);
1247 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}};
1250template <
int nLayers>
1254 mIsZeroField = std::abs(mBz) < 0.01;
1255 mTimeFrame->setBz(bz);
1258template <
int nLayers>
1264template <
int nLayers>
1267#if defined(OPTIMISATION_OUTPUT) || defined(CA_DEBUG)
1268 mTaskArena = std::make_shared<tbb::task_arena>(1);
1270 if (arena ==
nullptr) {
1271 mTaskArena = std::make_shared<tbb::task_arena>(std::abs(
n));
1272 LOGP(info,
"Setting tracker with {} threads.",
n);
1275 LOGP(info,
"Attaching tracker to calling thread's arena");