82 const int startVtx = iVertex >= 0 ? iVertex : 0;
83 const int endVtx = iVertex >= 0 ? o2::gpu::CAMath::Min(iVertex + 1,
int(primaryVertices.size())) :
int(primaryVertices.
size());
84 if (endVtx <= startVtx) {
89 auto&
tracklets = mTimeFrame->getTracklets()[iLayer];
90 for (
int targetROF0{minROF}; targetROF0 <= maxROF; ++targetROF0) {
91 if (!mTimeFrame->mMultiplicityCutMask[targetROF0]) {
94 auto layer0 = mTimeFrame->getClustersOnLayer(targetROF0, 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(targetROF0, 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 targetROF1{minROF}; targetROF1 <= maxROF; ++targetROF1) {
132 if (!mTimeFrame->mMultiplicityCutMask[targetROF1] || std::abs(targetROF0 - targetROF1) > mTrkParams[iteration].DeltaROF) {
135 auto layer1 = mTimeFrame->getClustersOnLayer(targetROF1, iLayer + 1);
136 if (layer1.empty()) {
139 for (
int iPhi = 0; iPhi < phiBinsNum; ++iPhi) {
140 int iPhiBin = (
bins.y + iPhi) % mTrkParams[iteration].PhiBins;
141 int firstBinIdx = mTimeFrame->mIndexTableUtils.getBinIndex(
bins.x, iPhiBin);
142 int maxBinIdx = firstBinIdx + (
bins.z -
bins.x) + 1;
143 int firstRow = mTimeFrame->getIndexTable(targetROF1, iLayer + 1)[firstBinIdx];
144 int lastRow = mTimeFrame->getIndexTable(targetROF1, 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) ||
177 float phi = o2::gpu::GPUCommonMath::ATan2(currentCluster.yCoordinate - nextCluster.yCoordinate, currentCluster.xCoordinate - nextCluster.xCoordinate);
178 float tanL = (currentCluster.zCoordinate - nextCluster.zCoordinate) / (currentCluster.radius - nextCluster.radius);
179 if constexpr (
decltype(Tag)
::value == PassMode::OnePass::value) {
180 tracklets.emplace_back(currentSortedIndex, mTimeFrame->getSortedIndex(targetROF1, iLayer + 1, iNext), tanL,
phi, targetROF0, targetROF1);
181 }
else if constexpr (
decltype(Tag)
::value == PassMode::TwoPassCount::value) {
183 }
else if constexpr (
decltype(Tag)
::value == PassMode::TwoPassInsert::value) {
185 tracklets[
idx] = Tracklet(currentSortedIndex, mTimeFrame->getSortedIndex(targetROF1, iLayer + 1, iNext), tanL, phi, targetROF0, targetROF1);
198 if (mTaskArena->max_concurrency() <= 1) {
199 for (
int pivotROF{startROF}; pivotROF < endROF; ++pivotROF) {
200 for (
int iLayer{0}; iLayer < mTrkParams[iteration].TrackletsPerRoad(); ++iLayer) {
205 bounded_vector<bounded_vector<int>> perROFCount(mTrkParams[iteration].
TrackletsPerRoad(), bounded_vector<int>(endROF - startROF + 1, 0, mMemoryPool.get()), mMemoryPool.get());
207 tbb::blocked_range2d<int, int>(0, mTrkParams[iteration].
TrackletsPerRoad(), 1,
208 startROF, endROF, 1),
209 [&](
auto const& Range) {
210 for (
int iLayer{Range.rows().
begin()}; iLayer < Range.rows().
end(); ++iLayer) {
211 for (
int pivotROF = Range.cols().begin(); pivotROF < Range.cols().end(); ++pivotROF) {
212 perROFCount[iLayer][pivotROF - startROF] = forTracklets(
PassMode::TwoPassCount{}, iLayer, pivotROF, 0, dummy);
219 [&](
auto const& Layers) {
220 for (
int iLayer{Layers.begin()}; iLayer < Layers.end(); ++iLayer) {
221 std::exclusive_scan(perROFCount[iLayer].
begin(), perROFCount[iLayer].
end(), perROFCount[iLayer].
begin(), 0);
222 mTimeFrame->getTracklets()[iLayer].resize(perROFCount[iLayer].back());
227 tbb::blocked_range2d<int, int>(0, mTrkParams[iteration].
TrackletsPerRoad(), 1,
228 startROF, endROF, 1),
229 [&](
auto const& Range) {
230 for (
int iLayer{Range.rows().
begin()}; iLayer < Range.rows().
end(); ++iLayer) {
231 if (perROFCount[iLayer].back() == 0) {
234 for (
int pivotROF = Range.cols().begin(); pivotROF < Range.cols().end(); ++pivotROF) {
235 int baseIdx = perROFCount[iLayer][pivotROF - startROF];
236 if (baseIdx == perROFCount[iLayer][pivotROF - startROF + 1]) {
248 [&](
const tbb::blocked_range<int>& Layers) {
249 for (
int iLayer = Layers.begin(); iLayer < Layers.end(); ++iLayer) {
251 auto& trkl{mTimeFrame->getTracklets()[iLayer]};
252 tbb::parallel_sort(trkl.begin(), trkl.end(), [](
const Tracklet&
a,
const Tracklet&
b) ->
bool {
253 return a.firstClusterIndex < b.firstClusterIndex || (a.firstClusterIndex == b.firstClusterIndex && a.secondClusterIndex < b.secondClusterIndex);
256 trkl.erase(std::unique(trkl.begin(), trkl.end(), [](
const Tracklet&
a,
const Tracklet&
b) ->
bool {
257 return a.firstClusterIndex == b.firstClusterIndex && a.secondClusterIndex == b.secondClusterIndex;
260 trkl.shrink_to_fit();
262 auto& lut{mTimeFrame->getTrackletsLookupTable()[iLayer - 1]};
264 for (
const auto& tkl : trkl) {
265 lut[tkl.firstClusterIndex + 1]++;
267 std::inclusive_scan(lut.begin(), lut.end(), lut.begin());
274 if (mTimeFrame->hasMCinformation()) {
277 [&](
const tbb::blocked_range<int>& Layers) {
278 for (
int iLayer = Layers.begin(); iLayer < Layers.end(); ++iLayer) {
279 for (
auto& trk : mTimeFrame->getTracklets()[iLayer]) {
281 int currentId{mTimeFrame->getClusters()[iLayer][trk.firstClusterIndex].clusterId};
282 int nextId{mTimeFrame->getClusters()[iLayer + 1][trk.secondClusterIndex].clusterId};
283 for (
const auto& lab1 : mTimeFrame->getClusterLabels(iLayer, currentId)) {
284 for (
const auto& lab2 : mTimeFrame->getClusterLabels(iLayer + 1, nextId)) {
285 if (lab1 == lab2 && lab1.isValid()) {
290 if (
label.isValid()) {
294 mTimeFrame->getTrackletsLabel(iLayer).emplace_back(
label);
302template <
int nLayers>
305#ifdef OPTIMISATION_OUTPUT
307 std::ofstream off(std::format(
"cells{}.txt", iter++));
310 for (
int iLayer = 0; iLayer < mTrkParams[iteration].CellsPerRoad(); ++iLayer) {
315 if (mTimeFrame->hasMCinformation()) {
320 mTaskArena->execute([&] {
322 const Tracklet& currentTracklet{mTimeFrame->getTracklets()[iLayer][iTracklet]};
324 const int nextLayerFirstTrackletIndex{mTimeFrame->getTrackletsLookupTable()[iLayer][nextLayerClusterIndex]};
325 const int nextLayerLastTrackletIndex{mTimeFrame->getTrackletsLookupTable()[iLayer][nextLayerClusterIndex + 1]};
327 for (
int iNextTracklet{nextLayerFirstTrackletIndex}; iNextTracklet < nextLayerLastTrackletIndex; ++iNextTracklet) {
328 const Tracklet& nextTracklet{mTimeFrame->getTracklets()[iLayer + 1][iNextTracklet]};
329 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++] =
CellSeed(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()) {
462 for (
int iLayer{0}; iLayer < mTrkParams[iteration].CellsPerRoad(); ++iLayer) {
463 for (
const auto& cell : mTimeFrame->getCells()[iLayer]) {
464 MCCompLabel currentLab{mTimeFrame->getTrackletsLabel(iLayer)[cell.getFirstTrackletIndex()]};
465 MCCompLabel nextLab{mTimeFrame->getTrackletsLabel(iLayer + 1)[cell.getSecondTrackletIndex()]};
466 mTimeFrame->getCellsLabel(iLayer).emplace_back(currentLab == nextLab ? currentLab :
MCCompLabel());
472template <
int nLayers>
475#ifdef OPTIMISATION_OUTPUT
476 std::ofstream off(std::format(
"cellneighs{}.txt", iteration));
480 int cell{-1}, nextCell{-1},
level{-1};
483 mTaskArena->execute([&] {
484 for (
int iLayer{0}; iLayer < mTrkParams[iteration].CellsPerRoad() - 1; ++iLayer) {
487 if (mTimeFrame->getCells()[iLayer + 1].empty() ||
488 mTimeFrame->getCellsLookupTable()[iLayer].empty()) {
492 int nCells{
static_cast<int>(mTimeFrame->getCells()[iLayer].size())};
495 auto forCellNeighbour = [&](
auto Tag,
int iCell,
int offset = 0) ->
int {
496 const auto& currentCellSeed{mTimeFrame->getCells()[iLayer][iCell]};
497 const int nextLayerTrackletIndex{currentCellSeed.getSecondTrackletIndex()};
498 const int nextLayerFirstCellIndex{mTimeFrame->getCellsLookupTable()[iLayer][nextLayerTrackletIndex]};
499 const int nextLayerLastCellIndex{mTimeFrame->getCellsLookupTable()[iLayer][nextLayerTrackletIndex + 1]};
500 int foundNextCells{0};
501 for (
int iNextCell{nextLayerFirstCellIndex}; iNextCell < nextLayerLastCellIndex; ++iNextCell) {
502 auto nextCellSeed{mTimeFrame->getCells()[iLayer + 1][iNextCell]};
503 if (nextCellSeed.getFirstTrackletIndex() != nextLayerTrackletIndex) {
507 if (mTrkParams[iteration].DeltaROF) {
508 const auto& trkl00 = mTimeFrame->getTracklets()[iLayer][currentCellSeed.getFirstTrackletIndex()];
509 const auto& trkl01 = mTimeFrame->getTracklets()[iLayer + 1][currentCellSeed.getSecondTrackletIndex()];
510 const auto& trkl10 = mTimeFrame->getTracklets()[iLayer + 1][nextCellSeed.getFirstTrackletIndex()];
511 const auto& trkl11 = mTimeFrame->getTracklets()[iLayer + 2][nextCellSeed.getSecondTrackletIndex()];
512 if ((std::max({trkl00.getMaxRof(), trkl01.getMaxRof(), trkl10.getMaxRof(), trkl11.getMaxRof()}) - std::min({trkl00.getMinRof(), trkl01.getMinRof(), trkl10.getMinRof(), trkl10.getMinRof()})) > mTrkParams[0].DeltaROF) {
517 if (!nextCellSeed.rotate(currentCellSeed.getAlpha()) ||
518 !nextCellSeed.propagateTo(currentCellSeed.getX(), getBz())) {
521 float chi2 = currentCellSeed.getPredictedChi2(nextCellSeed);
523#ifdef OPTIMISATION_OUTPUT
524 bool good{mTimeFrame->getCellsLabel(iLayer)[iCell] == mTimeFrame->getCellsLabel(iLayer + 1)[iNextCell]};
525 off << std::format(
"{}\t{:d}\t{}", iLayer, good, chi2) << std::endl;
528 if (chi2 > mTrkParams[0].MaxChi2ClusterAttachment) {
532 if constexpr (
decltype(Tag)
::value == PassMode::OnePass::value) {
533 cellsNeighbours.emplace_back(iCell, iNextCell, currentCellSeed.getLevel() + 1);
534 }
else if constexpr (
decltype(Tag)
::value == PassMode::TwoPassCount::value) {
536 }
else if constexpr (
decltype(Tag)
::value == PassMode::TwoPassInsert::value) {
537 cellsNeighbours[
offset++] = {iCell, iNextCell, currentCellSeed.getLevel() + 1};
539 static_assert(
false,
"Unknown mode!");
542 return foundNextCells;
545 if (mTaskArena->max_concurrency() <= 1) {
546 for (
int iCell{0}; iCell < nCells; ++iCell) {
552 tbb::blocked_range<int>(0, nCells),
553 [&](
const tbb::blocked_range<int>& Cells) {
554 for (
int iCell = Cells.begin(); iCell < Cells.end(); ++iCell) {
559 std::exclusive_scan(perCellCount.begin(), perCellCount.end(), perCellCount.begin(), 0);
560 int totalCellNeighbours = perCellCount.back();
561 if (totalCellNeighbours == 0) {
565 cellsNeighbours.resize(totalCellNeighbours);
568 tbb::blocked_range<int>(0, nCells),
569 [&](
const tbb::blocked_range<int>& Cells) {
570 for (
int iCell = Cells.begin(); iCell < Cells.end(); ++iCell) {
571 int offset = perCellCount[iCell];
572 if (
offset == perCellCount[iCell + 1]) {
580 if (cellsNeighbours.empty()) {
584 tbb::parallel_sort(cellsNeighbours.begin(), cellsNeighbours.end(), [](
const auto&
a,
const auto&
b) {
585 return a.nextCell < b.nextCell;
588 auto& cellsNeighbourLUT = mTimeFrame->getCellsNeighboursLUT()[iLayer];
589 cellsNeighbourLUT.assign(mTimeFrame->getCells()[iLayer + 1].size(), 0);
590 for (
const auto& neigh : cellsNeighbours) {
591 ++cellsNeighbourLUT[neigh.nextCell];
593 std::inclusive_scan(cellsNeighbourLUT.begin(), cellsNeighbourLUT.end(), cellsNeighbourLUT.begin());
595 mTimeFrame->getCellsNeighbours()[iLayer].reserve(cellsNeighbours.size());
596 std::ranges::transform(cellsNeighbours, std::back_inserter(mTimeFrame->getCellsNeighbours()[iLayer]), [](
const auto& neigh) { return neigh.cell; });
598 auto it = cellsNeighbours.begin();
599 int current = it->nextCell;
600 int maxLvl = it->level;
602 for (; it != cellsNeighbours.end(); ++it) {
603 if (it->nextCell == current) {
604 maxLvl = std::max(maxLvl, it->level);
606 mTimeFrame->getCells()[iLayer + 1][current].setLevel(maxLvl);
607 current = it->nextCell;
611 mTimeFrame->getCells()[iLayer + 1][current].setLevel(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 CellSeed& 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 CellSeed& 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()) {
660 if (mTrkParams[0].DeltaROF) {
661 const auto& trklNeigh = mTimeFrame->getTracklets()[iLayer - 1][neighbourCell.getFirstTrackletIndex()];
662 short minRof{std::numeric_limits<short>::max()}, maxRof{std::numeric_limits<short>::min()};
663 for (
int iLayer{0}; iLayer < mTrkParams[0].NLayers; ++iLayer) {
665 const short clsROF = mTimeFrame->getClusterROF(iLayer, clsId);
666 minRof = std::min(minRof, clsROF);
667 maxRof = std::max(maxRof, clsROF);
670 if ((std::max(trklNeigh.getMaxRof(), maxRof) - std::min(trklNeigh.getMinRof(), minRof)) > mTrkParams[0].DeltaROF) {
677 const auto& trHit = mTimeFrame->getTrackingFrameInfoOnLayer(iLayer - 1)[neighbourCell.getFirstClusterIndex()];
679 if (!seed.rotate(trHit.alphaTrackingFrame)) {
689 if (mTrkParams[0].CorrType == o2::base::PropagatorF::MatCorrType::USEMatCorrNONE) {
690 if (!seed.correctForMaterial(mTrkParams[0].LayerxX0[iLayer - 1], mTrkParams[0].LayerxX0[iLayer - 1] *
constants::Radl *
constants::Rho,
true)) {
695 auto predChi2{seed.getPredictedChi2Quiet(trHit.positionTrackingFrame, trHit.covarianceTrackingFrame)};
696 if ((predChi2 > mTrkParams[0].MaxChi2ClusterAttachment) || predChi2 < 0.f) {
700 seed.setChi2(seed.getChi2() + predChi2);
701 if (!seed.o2::track::TrackParCov::update(trHit.positionTrackingFrame, trHit.covarianceTrackingFrame)) {
706 if constexpr (
decltype(Tag)
::value != PassMode::TwoPassCount::value) {
707 seed.getClusters()[iLayer - 1] = neighbourCell.getFirstClusterIndex();
708 seed.setLevel(neighbourCell.getLevel());
709 seed.setFirstTrackletIndex(neighbourCell.getFirstTrackletIndex());
710 seed.setSecondTrackletIndex(neighbourCell.getSecondTrackletIndex());
713 if constexpr (
decltype(Tag)
::value == PassMode::OnePass::value) {
714 updatedCellSeeds.push_back(seed);
715 updatedCellsIds.push_back(neighbourCellId);
716 }
else if constexpr (
decltype(Tag)
::value == PassMode::TwoPassCount::value) {
718 }
else if constexpr (
decltype(Tag)
::value == PassMode::TwoPassInsert::value) {
719 updatedCellSeeds[
offset] = seed;
720 updatedCellsIds[
offset++] = neighbourCellId;
722 static_assert(
false,
"Unknown mode!");
728 const int nCells =
static_cast<int>(currentCellSeed.size());
729 if (mTaskArena->max_concurrency() <= 1) {
730 for (
int iCell{0}; iCell < nCells; ++iCell) {
736 tbb::blocked_range<int>(0, nCells),
737 [&](
const tbb::blocked_range<int>& Cells) {
738 for (
int iCell = Cells.begin(); iCell < Cells.end(); ++iCell) {
743 std::exclusive_scan(perCellCount.begin(), perCellCount.end(), perCellCount.begin(), 0);
744 auto totalNeighbours{perCellCount.back()};
745 if (totalNeighbours == 0) {
748 updatedCellSeeds.resize(totalNeighbours);
749 updatedCellsIds.resize(totalNeighbours);
752 tbb::blocked_range<int>(0, nCells),
753 [&](
const tbb::blocked_range<int>& Cells) {
754 for (
int iCell = Cells.begin(); iCell < Cells.end(); ++iCell) {
755 int offset = perCellCount[iCell];
756 if (
offset == perCellCount[iCell + 1]) {
766 std::cout <<
"\t\t- Found " << updatedCellSeeds.size() <<
" cell seeds out of " << attempts <<
" attempts" << std::endl;
767 std::cout <<
"\t\t\t> " <<
failed[0] <<
" failed because of level" << std::endl;
768 std::cout <<
"\t\t\t> " <<
failed[1] <<
" failed because of rotation" << std::endl;
769 std::cout <<
"\t\t\t> " <<
failed[2] <<
" failed because of propagation" << std::endl;
770 std::cout <<
"\t\t\t> " <<
failed[3] <<
" failed because of chi2 cut" << std::endl;
771 std::cout <<
"\t\t\t> " <<
failed[4] <<
" failed because of update" << std::endl;
772 std::cout <<
"\t\t\t> " << failedByMismatch <<
" failed because of mismatch" << std::endl;
776template <
int nLayers>
779 CA_DEBUGGER(std::cout <<
"Finding roads, iteration " << iteration << std::endl);
781 for (
int startLevel{mTrkParams[iteration].CellsPerRoad()}; startLevel >= mTrkParams[iteration].CellMinimumLevel(); --startLevel) {
782 CA_DEBUGGER(std::cout <<
"\t > Processing level " << startLevel << std::endl);
783 auto seedFilter = [&](
const CellSeed& seed) {
784 return seed.getQ2Pt() <= 1.e3 && seed.getChi2() <= mTrkParams[0].MaxChi2NDF * ((startLevel + 2) * 2 - 5);
787 for (
int startLayer{mTrkParams[iteration].CellsPerRoad() - 1}; startLayer >= startLevel - 1; --startLayer) {
788 if ((mTrkParams[iteration].StartLayerMask & (1 << (startLayer + 2))) == 0) {
791 CA_DEBUGGER(std::cout <<
"\t\t > Starting processing layer " << startLayer << std::endl);
795 processNeighbours(startLayer, startLevel, mTimeFrame->getCells()[startLayer], lastCellId, updatedCellSeed, updatedCellId);
797 int level = startLevel;
798 for (
int iLayer{startLayer - 1}; iLayer > 0 &&
level > 2; --iLayer) {
799 lastCellSeed.swap(updatedCellSeed);
800 lastCellId.swap(updatedCellId);
803 processNeighbours(iLayer, --
level, lastCellSeed, lastCellId, updatedCellSeed, updatedCellId);
808 if (!updatedCellSeed.empty()) {
809 trackSeeds.reserve(trackSeeds.size() + std::count_if(updatedCellSeed.begin(), updatedCellSeed.end(), seedFilter));
810 std::copy_if(updatedCellSeed.begin(), updatedCellSeed.end(), std::back_inserter(trackSeeds), seedFilter);
814 if (trackSeeds.empty()) {
819 mTaskArena->execute([&] {
820 auto forSeed = [&](
auto Tag,
int iSeed,
int offset = 0) {
821 const CellSeed& seed{trackSeeds[iSeed]};
823 temporaryTrack.resetCovariance();
824 temporaryTrack.setChi2(0);
825 for (
int iL{0}; iL < 7; ++iL) {
826 temporaryTrack.setExternalClusterIndex(iL, seed.getCluster(iL), seed.getCluster(iL) !=
constants::UnusedIndex);
829 bool fitSuccess = fitTrack(temporaryTrack, 0, mTrkParams[0].NLayers, 1, mTrkParams[0].MaxChi2ClusterAttachment, mTrkParams[0].MaxChi2NDF);
834 temporaryTrack.getParamOut() = temporaryTrack.getParamIn();
835 temporaryTrack.resetCovariance();
836 temporaryTrack.setChi2(0);
837 fitSuccess = fitTrack(temporaryTrack, mTrkParams[0].NLayers - 1, -1, -1, mTrkParams[0].MaxChi2ClusterAttachment, mTrkParams[0].MaxChi2NDF, 50.f);
838 if (!fitSuccess || temporaryTrack.getPt() < mTrkParams[iteration].MinPt[mTrkParams[iteration].NLayers - temporaryTrack.getNClusters()]) {
842 if constexpr (
decltype(Tag)
::value == PassMode::OnePass::value) {
843 tracks.push_back(temporaryTrack);
844 }
else if constexpr (
decltype(Tag)
::value == PassMode::TwoPassCount::value) {
846 }
else if constexpr (
decltype(Tag)
::value == PassMode::TwoPassInsert::value) {
847 tracks[
offset] = temporaryTrack;
849 static_assert(
false,
"Unknown mode!");
854 const int nSeeds =
static_cast<int>(trackSeeds.size());
855 if (mTaskArena->max_concurrency() <= 1) {
856 for (
int iSeed{0}; iSeed < nSeeds; ++iSeed) {
862 tbb::blocked_range<int>(0, nSeeds),
863 [&](
const tbb::blocked_range<int>& Seeds) {
864 for (
int iSeed = Seeds.begin(); iSeed < Seeds.end(); ++iSeed) {
869 std::exclusive_scan(perSeedCount.begin(), perSeedCount.end(), perSeedCount.begin(), 0);
870 auto totalTracks{perSeedCount.back()};
871 if (totalTracks == 0) {
874 tracks.resize(totalTracks);
877 tbb::blocked_range<int>(0, nSeeds),
878 [&](
const tbb::blocked_range<int>& Seeds) {
879 for (
int iSeed = Seeds.begin(); iSeed < Seeds.end(); ++iSeed) {
880 if (perSeedCount[iSeed] == perSeedCount[iSeed + 1]) {
889 tbb::parallel_sort(tracks.begin(), tracks.end(), [](
const auto&
a,
const auto&
b) {
890 return a.getChi2() < b.getChi2();
894 for (
auto& track : tracks) {
896 bool isFirstShared{
false};
897 for (
int iLayer{0}; iLayer < mTrkParams[0].NLayers; ++iLayer) {
901 nShared +=
int(mTimeFrame->isClusterUsed(iLayer, track.getClusterIndex(iLayer)));
902 isFirstShared |= !iLayer && mTimeFrame->isClusterUsed(iLayer, track.getClusterIndex(iLayer));
905 if (nShared > mTrkParams[0].ClusterSharing) {
909 std::array<int, 3> rofs{INT_MAX, INT_MAX, INT_MAX};
910 for (
int iLayer{0}; iLayer < mTrkParams[0].NLayers; ++iLayer) {
914 mTimeFrame->markUsedCluster(iLayer, track.getClusterIndex(iLayer));
915 int currentROF = mTimeFrame->getClusterROF(iLayer, track.getClusterIndex(iLayer));
916 for (
int iR{0}; iR < 3; ++iR) {
917 if (rofs[iR] == INT_MAX) {
918 rofs[iR] = currentROF;
920 if (rofs[iR] == currentROF) {
925 if (rofs[2] != INT_MAX) {
928 track.setUserField(0);
929 track.getParamOut().setUserField(0);
930 if (rofs[1] != INT_MAX) {
931 track.setNextROFbit();
933 mTimeFrame->getTracks(o2::gpu::CAMath::Min(rofs[0], rofs[1])).emplace_back(track);
938template <
int nLayers>
941 for (
int rof{0}; rof < mTimeFrame->getNrof(); ++rof) {
942 for (
auto& track : mTimeFrame->getTracks(rof)) {
946 if ((mTrkParams[iteration].UseTrackFollowerMix || mTrkParams[iteration].UseTrackFollowerTop) && track.getLastClusterLayer() != mTrkParams[iteration].NLayers - 1) {
947 success = success || trackFollowing(&track, rof,
true, iteration);
949 if ((mTrkParams[iteration].UseTrackFollowerMix || (mTrkParams[iteration].UseTrackFollowerBot && !success)) && track.getFirstClusterLayer() != 0) {
950 success = success || trackFollowing(&track, rof,
false, iteration);
954 track.resetCovariance();
956 bool fitSuccess = fitTrack(track, 0, mTrkParams[iteration].NLayers, 1, mTrkParams[iteration].MaxChi2ClusterAttachment, mTrkParams[0].MaxChi2NDF);
961 track.getParamOut() = track;
962 track.resetCovariance();
964 fitSuccess = fitTrack(track, mTrkParams[iteration].NLayers - 1, -1, -1, mTrkParams[iteration].MaxChi2ClusterAttachment, mTrkParams[0].MaxChi2NDF, 50.);
969 mTimeFrame->mNExtendedTracks++;
970 mTimeFrame->mNExtendedUsedClusters += track.getNClusters() - backup.getNClusters();
971 auto pattern = track.getPattern();
972 auto diff = (
pattern & ~backup.getPattern()) & 0xff;
976 for (
int iLayer{0}; iLayer < mTrkParams[iteration].NLayers; ++iLayer) {
980 mTimeFrame->markUsedCluster(iLayer, track.getClusterIndex(iLayer));
987template <
int nLayers>
991 mTimeFrame->fillPrimaryVerticesXandAlpha();
993 for (
auto& cell : mTimeFrame->getCells()[0]) {
994 auto& cluster3_glo = mTimeFrame->getClusters()[2][cell.getThirdClusterIndex()];
995 auto& cluster2_glo = mTimeFrame->getClusters()[1][cell.getSecondClusterIndex()];
996 auto& cluster1_glo = mTimeFrame->getClusters()[0][cell.getFirstClusterIndex()];
997 if (mTimeFrame->isClusterUsed(2, cluster1_glo.clusterId) ||
998 mTimeFrame->isClusterUsed(1, cluster2_glo.clusterId) ||
999 mTimeFrame->isClusterUsed(0, cluster3_glo.clusterId)) {
1003 std::array<int, 3> rofs{
1004 mTimeFrame->getClusterROF(2, cluster3_glo.clusterId),
1005 mTimeFrame->getClusterROF(1, cluster2_glo.clusterId),
1006 mTimeFrame->getClusterROF(0, cluster1_glo.clusterId)};
1007 if (rofs[0] != rofs[1] && rofs[1] != rofs[2] && rofs[0] != rofs[2]) {
1012 if (rofs[1] == rofs[2]) {
1016 auto pvs{mTimeFrame->getPrimaryVertices(rof)};
1017 auto pvsXAlpha{mTimeFrame->getPrimaryVerticesXAlpha(rof)};
1019 const auto& cluster3_tf = mTimeFrame->getTrackingFrameInfoOnLayer(2)[cluster3_glo.clusterId];
1020 TrackITSExt temporaryTrack{buildTrackSeed(cluster1_glo, cluster2_glo, cluster3_tf)};
1021 temporaryTrack.setExternalClusterIndex(0, cluster1_glo.clusterId,
true);
1022 temporaryTrack.setExternalClusterIndex(1, cluster2_glo.clusterId,
true);
1023 temporaryTrack.setExternalClusterIndex(2, cluster3_glo.clusterId,
true);
1026 bool fitSuccess = fitTrack(temporaryTrack, 1, -1, -1);
1032 TrackITSExt bestTrack{temporaryTrack}, backup{temporaryTrack};
1033 float bestChi2{std::numeric_limits<float>::max()};
1034 for (
int iV{0}; iV < (
int)pvs.size(); ++iV) {
1035 temporaryTrack = backup;
1036 if (!temporaryTrack.rotate(pvsXAlpha[iV][1])) {
1039 if (!propagator->propagateTo(temporaryTrack, pvsXAlpha[iV][0],
true)) {
1043 float pvRes{mTrkParams[0].PVres / o2::gpu::CAMath::Sqrt(
float(pvs[iV].getNContributors()))};
1044 const float posVtx[2]{0.f, pvs[iV].getZ()};
1045 const float covVtx[3]{pvRes, 0.f, pvRes};
1046 float chi2 = temporaryTrack.getPredictedChi2Quiet(posVtx, covVtx);
1047 if (chi2 < bestChi2) {
1048 if (!temporaryTrack.track::TrackParCov::update(posVtx, covVtx)) {
1051 bestTrack = temporaryTrack;
1056 bestTrack.resetCovariance();
1057 bestTrack.setChi2(0.f);
1058 fitSuccess = fitTrack(bestTrack, 0, mTrkParams[0].NLayers, 1, mTrkParams[0].MaxChi2ClusterAttachment, mTrkParams[0].MaxChi2NDF);
1062 bestTrack.getParamOut() = bestTrack;
1063 bestTrack.resetCovariance();
1064 bestTrack.setChi2(0.f);
1065 fitSuccess = fitTrack(bestTrack, mTrkParams[0].NLayers - 1, -1, -1, mTrkParams[0].MaxChi2ClusterAttachment, mTrkParams[0].MaxChi2NDF, 50.);
1069 mTimeFrame->markUsedCluster(0, bestTrack.getClusterIndex(0));
1070 mTimeFrame->markUsedCluster(1, bestTrack.getClusterIndex(1));
1071 mTimeFrame->markUsedCluster(2, bestTrack.getClusterIndex(2));
1072 mTimeFrame->getTracks(rof).emplace_back(bestTrack);
1076template <
int nLayers>
1081 for (
int iLayer{
start}; iLayer !=
end; iLayer += step) {
1085 const TrackingFrameInfo& trackingHit = mTimeFrame->getTrackingFrameInfoOnLayer(iLayer)[track.getClusterIndex(iLayer)];
1087 if (!track.rotate(trackingHit.alphaTrackingFrame)) {
1095 if (mTrkParams[0].CorrType == o2::base::PropagatorF::MatCorrType::USEMatCorrNONE) {
1101 auto predChi2{track.getPredictedChi2Quiet(trackingHit.positionTrackingFrame, trackingHit.covarianceTrackingFrame)};
1102 if ((nCl >= 3 && predChi2 > chi2clcut) || predChi2 < 0.f) {
1105 track.setChi2(track.getChi2() + predChi2);
1106 if (!track.o2::track::TrackParCov::update(trackingHit.positionTrackingFrame, trackingHit.covarianceTrackingFrame)) {
1111 return std::abs(track.getQ2Pt()) < maxQoverPt && track.getChi2() < chi2ndfcut * (nCl * 2 - 5);
1114template <
int nLayers>
1118 const int step = -1 + outward * 2;
1119 const int end = outward ? mTrkParams[iteration].NLayers - 1 : 0;
1121 for (
size_t iHypo{0}; iHypo < hypotheses.size(); ++iHypo) {
1122 auto hypo{hypotheses[iHypo]};
1123 int iLayer =
static_cast<int>(outward ? hypo.getLastClusterLayer() : hypo.getFirstClusterLayer());
1125 while (iLayer !=
end) {
1127 const float r = mTrkParams[iteration].LayerRadii[iLayer];
1134 auto& hypoParam{outward ? hypo.getParamOut() : hypo.getParamIn()};
1135 if (!propInstance->propagateToX(hypoParam,
x, mTimeFrame->getBz(), PropagatorF::MAX_SIN_PHI,
1136 PropagatorF::MAX_STEP, mTrkParams[iteration].CorrType)) {
1140 if (mTrkParams[iteration].CorrType == PropagatorF::MatCorrType::USEMatCorrNONE) {
1141 if (!hypoParam.correctForMaterial(mTrkParams[iteration].LayerxX0[iLayer], mTrkParams[iteration].LayerxX0[iLayer] *
constants::Radl *
constants::Rho,
true)) {
1147 const float phi{hypoParam.getPhi()};
1148 const float ePhi{o2::gpu::CAMath::Sqrt(hypoParam.getSigmaSnp2() / hypoParam.getCsp2())};
1149 const float z{hypoParam.getZ()};
1150 const float eZ{o2::gpu::CAMath::Sqrt(hypoParam.getSigmaZ2())};
1151 const int4 selectedBinsRect{getBinsRect(iLayer, phi, mTrkParams[iteration].TrackFollowerNSigmaCutPhi * ePhi,
z, mTrkParams[iteration].TrackFollowerNSigmaCutZ * eZ)};
1152 if (selectedBinsRect.x == 0 && selectedBinsRect.y == 0 && selectedBinsRect.z == 0 && selectedBinsRect.w == 0) {
1156 int phiBinsNum{selectedBinsRect.
w - selectedBinsRect.y + 1};
1158 if (phiBinsNum < 0) {
1159 phiBinsNum += mTrkParams[iteration].PhiBins;
1162 gsl::span<const Cluster> layer1 = mTimeFrame->getClustersOnLayer(rof, iLayer);
1163 if (layer1.empty()) {
1168 for (
int iPhiCount = 0; iPhiCount < phiBinsNum; iPhiCount++) {
1169 int iPhiBin = (selectedBinsRect.y + iPhiCount) % mTrkParams[iteration].PhiBins;
1170 const int firstBinIndex{mTimeFrame->mIndexTableUtils.getBinIndex(selectedBinsRect.x, iPhiBin)};
1171 const int maxBinIndex{firstBinIndex + selectedBinsRect.z - selectedBinsRect.x + 1};
1172 const int firstRowClusterIndex = mTimeFrame->getIndexTable(rof, iLayer)[firstBinIndex];
1173 const int maxRowClusterIndex = mTimeFrame->getIndexTable(rof, iLayer)[maxBinIndex];
1175 for (
int iNextCluster{firstRowClusterIndex}; iNextCluster < maxRowClusterIndex; ++iNextCluster) {
1176 if (iNextCluster >= (
int)layer1.size()) {
1179 const Cluster& nextCluster{layer1[iNextCluster]};
1181 if (mTimeFrame->isClusterUsed(iLayer, nextCluster.clusterId)) {
1185 const TrackingFrameInfo& trackingHit = mTimeFrame->getTrackingFrameInfoOnLayer(iLayer)[nextCluster.clusterId];
1187 auto tbupdated{hypo};
1188 auto& tbuParams = outward ? tbupdated.getParamOut() : tbupdated.getParamIn();
1193 if (!propInstance->propagateToX(tbuParams, trackingHit.
xTrackingFrame, mTimeFrame->getBz(),
1194 PropagatorF::MAX_SIN_PHI, PropagatorF::MAX_STEP, PropagatorF::MatCorrType::USEMatCorrNONE)) {
1199 if (predChi2 >= track->getChi2() * mTrkParams[iteration].NSigmaCut) {
1206 tbupdated.setChi2(tbupdated.getChi2() + predChi2);
1207 tbupdated.setExternalClusterIndex(iLayer, nextCluster.clusterId,
true);
1208 hypotheses.emplace_back(tbupdated);
1215 bool swapped{
false};
1216 for (
auto& hypo : hypotheses) {
1217 if (hypo.isBetter(*bestHypo, track->getChi2() * mTrkParams[iteration].NSigmaCut)) {
1228template <
int nLayers>
1231 float ca{-999.f}, sa{-999.f};
1242 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};
1244 tgp = o2::gpu::CAMath::ATan2(y3 -
y1, x3 -
x1);
1245 snp = tgp / o2::gpu::CAMath::Sqrt(1.f + tgp * tgp);
1247 crv = math_utils::computeCurvature(x3, y3, x2, y2,
x1,
y1);
1248 snp = crv * (
x3 - math_utils::computeCurvatureCentreX(x3, y3, x2, y2,
x1,
y1));
1252 tgl12 = math_utils::computeTanDipAngle(
x1,
y1, x2, y2, z1, z2);
1253 tgl23 = math_utils::computeTanDipAngle(x2, y2, x3, y3, z2, z3);
1254 sg2q2pt =
track::kC1Pt2max * (q2pt2 > 0.0005f ? (q2pt2 < 1.f ? q2pt2 : 1.f) : 0.0005f);
1255 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}};
1258template <
int nLayers>
1262 mIsZeroField = std::abs(mBz) < 0.01;
1263 mTimeFrame->setBz(bz);
1266template <
int nLayers>
1272template <
int nLayers>
1275#if defined(OPTIMISATION_OUTPUT) || defined(CA_DEBUG)
1276 mTaskArena = std::make_shared<tbb::task_arena>(1);
1278 if (arena ==
nullptr) {
1279 mTaskArena = std::make_shared<tbb::task_arena>(std::abs(
n));
1280 LOGP(info,
"Setting tracker with {} threads.",
n);
1283 LOGP(info,
"Attaching tracker to calling thread's arena");