54 const auto topology = mTimeFrame->getTrackingTopologyView();
55 for (
int linkId = 0; linkId < topology.nLinks; ++linkId) {
56 mTimeFrame->getTracklets()[linkId].clear();
57 mTimeFrame->getTrackletsLabel(linkId).clear();
58 std::fill(mTimeFrame->getTrackletsLookupTable()[linkId].begin(), mTimeFrame->getTrackletsLookupTable()[linkId].end(), 0);
61 const Vertex diamondVert(mTrkParams[iteration].Diamond, mTrkParams[iteration].DiamondCov, 1, 1.f);
62 gsl::span<const Vertex> diamondSpan(&diamondVert, 1);
64 mTaskArena->execute([&] {
65 auto forTracklets = [&](
auto Tag,
int linkId,
int pivotROF,
int base,
int&
offset) ->
int {
66 const auto&
link = topology.getLink(linkId);
67 if (!mTimeFrame->getROFMaskView().isROFEnabled(
link.fromLayer, pivotROF)) {
70 gsl::span<const Vertex> primaryVertices = mTrkParams[iteration].UseDiamond ? diamondSpan : mTimeFrame->getPrimaryVertices(
link.fromLayer, pivotROF);
71 if (primaryVertices.empty()) {
74 const int startVtx = iVertex >= 0 ? iVertex : 0;
75 const int endVtx = iVertex >= 0 ? o2::gpu::CAMath::Min(iVertex + 1,
int(primaryVertices.size())) :
int(primaryVertices.size());
76 if (endVtx <= startVtx || (iVertex + 1) > primaryVertices.size()) {
80 const auto& rofOverlap = mTimeFrame->getROFOverlapTableView().getOverlap(
link.fromLayer,
link.toLayer, pivotROF);
81 if (!rofOverlap.getEntries()) {
86 auto&
tracklets = mTimeFrame->getTracklets()[linkId];
87 auto layer0 = mTimeFrame->getClustersOnLayer(pivotROF,
link.fromLayer);
92 const float meanDeltaR = mTrkParams[iteration].LayerRadii[
link.toLayer] - mTrkParams[iteration].LayerRadii[
link.fromLayer];
93 const float phiCut = mTimeFrame->getLinkPhiCut(linkId);
94 const float msAngle = mTimeFrame->getLinkMSAngle(linkId);
96 for (
int iCluster = 0; iCluster <
int(layer0.size()); ++iCluster) {
97 const Cluster& currentCluster = layer0[iCluster];
98 const int currentSortedIndex = mTimeFrame->getSortedIndex(pivotROF,
link.fromLayer, iCluster);
99 if (mTimeFrame->isClusterUsed(
link.fromLayer, currentCluster.
clusterId)) {
102 const float inverseR0 = 1.f / currentCluster.
radius;
104 for (
int iV = startVtx; iV < endVtx; ++iV) {
105 const auto& pv = primaryVertices[iV];
106 if (!mTimeFrame->getROFVertexLookupTableView().isVertexCompatible(
link.fromLayer, pivotROF, pv)) {
112 const float resolution = o2::gpu::CAMath::Sqrt(math_utils::Sq(mTimeFrame->getPositionResolution(
link.fromLayer)) + math_utils::Sq(mTrkParams[iteration].PVres) /
float(pv.getNContributors()));
113 const float tanLambda = (currentCluster.
zCoordinate - pv.getZ()) * inverseR0;
114 const float zAtRmin = tanLambda * (mTimeFrame->getMinR(
link.toLayer) - currentCluster.
radius) + currentCluster.
zCoordinate;
115 const float zAtRmax = tanLambda * (mTimeFrame->getMaxR(
link.toLayer) - currentCluster.
radius) + currentCluster.
zCoordinate;
117 const float sigmaZ = o2::gpu::CAMath::Sqrt((math_utils::Sq(resolution) * math_utils::Sq(tanLambda) * ((math_utils::Sq(inverseR0) + sqInvDeltaZ0) * math_utils::Sq(meanDeltaR) + 1.f)) + math_utils::Sq(meanDeltaR * msAngle));
119 sigmaZ * mTrkParams[iteration].NSigmaCut, phiCut,
120 mTimeFrame->getIndexTableUtils());
124 int phiBinsNum =
bins.w -
bins.y + 1;
125 if (phiBinsNum < 0) {
126 phiBinsNum += mTrkParams[iteration].PhiBins;
129 for (
int targetROF = rofOverlap.getFirstEntry(); targetROF < rofOverlap.getEntriesBound(); ++targetROF) {
130 if (!mTimeFrame->getROFMaskView().isROFEnabled(
link.toLayer, targetROF)) {
133 auto layer1 = mTimeFrame->getClustersOnLayer(targetROF,
link.toLayer);
134 if (layer1.empty()) {
137 const auto ts = mTimeFrame->getROFOverlapTableView().getTimeStamp(
link.fromLayer, pivotROF,
link.toLayer, targetROF);
138 if (!ts.isCompatible(pv.getTimeStamp())) {
141 const auto& targetIndexTable = mTimeFrame->getIndexTable(targetROF,
link.toLayer);
142 const int zBinRange = (
bins.z -
bins.x) + 1;
143 for (
int iPhi = 0; iPhi < phiBinsNum; ++iPhi) {
144 const int iPhiBin = (
bins.y + iPhi) % mTrkParams[iteration].PhiBins;
145 const int firstBinIdx = mTimeFrame->getIndexTableUtils().getBinIndex(
bins.x, iPhiBin);
146 const int maxBinIdx = firstBinIdx + zBinRange;
147 const int firstRow = targetIndexTable[firstBinIdx];
148 const int lastRow = targetIndexTable[maxBinIdx];
149 for (
int iNext = firstRow; iNext <
lastRow; ++iNext) {
150 if (iNext >=
int(layer1.size())) {
153 const Cluster& nextCluster = layer1[iNext];
154 if (mTimeFrame->isClusterUsed(
link.toLayer, nextCluster.
clusterId)) {
159 if (deltaZ / sigmaZ < mTrkParams[iteration].NSigmaCut &&
160 math_utils::isPhiDifferenceBelow(currentCluster.
phi, nextCluster.
phi, phiCut)) {
163 if constexpr (
decltype(Tag)
::value == PassMode::OnePass::value) {
164 tracklets.emplace_back(currentSortedIndex, mTimeFrame->getSortedIndex(targetROF,
link.toLayer, iNext), tanL, phi, ts);
165 }
else if constexpr (
decltype(Tag)
::value == PassMode::TwoPassCount::value) {
167 }
else if constexpr (
decltype(Tag)
::value == PassMode::TwoPassInsert::value) {
168 const int idx = base +
offset++;
169 tracklets[idx] =
Tracklet(currentSortedIndex, mTimeFrame->getSortedIndex(targetROF,
link.toLayer, iNext), tanL, phi, ts);
181 if (mTaskArena->max_concurrency() <= 1) {
182 for (
int linkId{0}; linkId < topology.nLinks; ++linkId) {
183 const int fromLayer = topology.getLink(linkId).fromLayer;
184 const int startROF = 0, endROF = mTimeFrame->getROFOverlapTableView().getLayer(fromLayer).mNROFsTF;
185 for (
int pivotROF{startROF}; pivotROF < endROF; ++pivotROF) {
190 tbb::parallel_for(0,
static_cast<int>(topology.nLinks), [&](
const int linkId) {
191 const int fromLayer = topology.getLink(linkId).fromLayer;
192 const int startROF = 0, endROF = mTimeFrame->getROFOverlapTableView().getLayer(fromLayer).mNROFsTF;
193 bounded_vector<int> perROFCount((endROF - startROF) + 1, mMemoryPool.get());
194 tbb::parallel_for(startROF, endROF, [&](const int pivotROF) {
195 perROFCount[pivotROF - startROF] = forTracklets(PassMode::TwoPassCount{}, linkId, pivotROF, 0, dummy);
197 std::exclusive_scan(perROFCount.begin(), perROFCount.end(), perROFCount.begin(), 0);
198 const int nTracklets = perROFCount.back();
199 mTimeFrame->getTracklets()[linkId].resize(nTracklets);
200 if (nTracklets == 0) {
203 tbb::parallel_for(startROF, endROF, [&](
const int pivotROF) {
204 int baseIdx = perROFCount[pivotROF - startROF];
205 if (baseIdx == perROFCount[pivotROF + 1 - startROF]) {
214 tbb::parallel_for(0,
static_cast<int>(topology.nLinks), [&](
const int linkId) {
217 auto& trkl{mTimeFrame->getTracklets()[linkId]};
218 std::sort(trkl.begin(), trkl.end());
219 trkl.erase(std::unique(trkl.begin(), trkl.end()), trkl.end());
220 trkl.shrink_to_fit();
221 auto& lut{mTimeFrame->getTrackletsLookupTable()[linkId]};
223 for (
const auto& tkl : trkl) {
224 lut[tkl.firstClusterIndex + 1]++;
226 std::inclusive_scan(lut.begin(), lut.end(), lut.begin());
231 if (mTimeFrame->hasMCinformation() && mTrkParams[iteration].CreateArtefactLabels) {
232 tbb::parallel_for(0,
static_cast<int>(topology.nLinks), [&](
const int linkId) {
233 const auto& link = topology.getLink(linkId);
234 for (auto& trk : mTimeFrame->getTracklets()[linkId]) {
236 int currentId{mTimeFrame->getClusters()[link.fromLayer][trk.firstClusterIndex].clusterId};
237 int nextId{mTimeFrame->getClusters()[link.toLayer][trk.secondClusterIndex].clusterId};
238 for (const auto& lab1 : mTimeFrame->getClusterLabels(link.fromLayer, currentId)) {
239 for (const auto& lab2 : mTimeFrame->getClusterLabels(link.toLayer, nextId)) {
240 if (lab1 == lab2 && lab1.isValid()) {
245 if (label.isValid()) {
249 mTimeFrame->getTrackletsLabel(linkId).emplace_back(label);
259 const auto topology = mTimeFrame->getTrackingTopologyView();
260 for (
int cellTopologyId = 0; cellTopologyId < topology.nCells; ++cellTopologyId) {
263 if (mTimeFrame->hasMCinformation() && mTrkParams[iteration].CreateArtefactLabels) {
268 mTaskArena->execute([&] {
270 const auto& cellTopology = topology.getCell(cellTopologyId);
271 const auto& firstLink = topology.getLink(cellTopology.firstLink);
272 const auto& secondLink = topology.getLink(cellTopology.secondLink);
273 const Tracklet& currentTracklet{mTimeFrame->getTracklets()[cellTopology.firstLink][iTracklet]};
275 const int nextLayerFirstTrackletIndex{mTimeFrame->getTrackletsLookupTable()[cellTopology.secondLink][nextLayerClusterIndex]};
276 const int nextLayerLastTrackletIndex{mTimeFrame->getTrackletsLookupTable()[cellTopology.secondLink][nextLayerClusterIndex + 1]};
278 for (
int iNextTracklet{nextLayerFirstTrackletIndex}; iNextTracklet < nextLayerLastTrackletIndex; ++iNextTracklet) {
279 const Tracklet& nextTracklet{mTimeFrame->getTracklets()[cellTopology.secondLink][iNextTracklet]};
280 if (nextTracklet.firstClusterIndex != nextLayerClusterIndex) {
283 if (!currentTracklet.getTimeStamp().isCompatible(nextTracklet.getTimeStamp())) {
287 const float deltaTanLambdaSigma = std::abs(currentTracklet.tanLambda - nextTracklet.tanLambda) / mTrkParams[iteration].CellDeltaTanLambdaSigma;
288 if (deltaTanLambdaSigma < mTrkParams[iteration].NSigmaCut) {
292 mTimeFrame->getClusters()[firstLink.fromLayer][currentTracklet.firstClusterIndex].clusterId,
293 mTimeFrame->getClusters()[firstLink.toLayer][nextTracklet.firstClusterIndex].clusterId,
294 mTimeFrame->getClusters()[secondLink.toLayer][nextTracklet.secondClusterIndex].clusterId};
295 const int hitLayers[3]{firstLink.fromLayer, firstLink.toLayer, secondLink.toLayer};
296 const auto& cluster1_glo = mTimeFrame->getUnsortedClusters()[firstLink.fromLayer][clusId[0]];
297 const auto& cluster2_glo = mTimeFrame->getUnsortedClusters()[firstLink.toLayer][clusId[1]];
298 const auto& cluster3_tf = mTimeFrame->getTrackingFrameInfoOnLayer(secondLink.toLayer)[clusId[2]];
299 auto track{o2::its::track::buildTrackSeed(cluster1_glo, cluster2_glo, cluster3_tf, mBz)};
303 for (
int iC{2}; iC--;) {
304 const int hitLayer = hitLayers[iC];
305 const TrackingFrameInfo& trackingHit = mTimeFrame->getTrackingFrameInfoOnLayer(hitLayer)[clusId[iC]];
315 if (!
track.correctForMaterial(mTrkParams[iteration].LayerxX0[hitLayer], mTrkParams[iteration].LayerxX0[hitLayer] * constants::Radl * constants::Rho,
true)) {
320 if (!iC && predChi2 > mTrkParams[iteration].MaxChi2ClusterAttachment) {
332 TimeEstBC ts = currentTracklet.getTimeStamp();
333 ts += nextTracklet.getTimeStamp();
334 if constexpr (
decltype(Tag)
::value == PassMode::OnePass::value) {
335 layerCells.emplace_back(cellTopology.hitLayerMask, clusId[0], clusId[1], clusId[2], iTracklet, iNextTracklet,
track, chi2, ts);
337 }
else if constexpr (
decltype(Tag)
::value == PassMode::TwoPassCount::value) {
339 }
else if constexpr (
decltype(Tag)
::value == PassMode::TwoPassInsert::value) {
340 layerCells[
offset++] =
CellSeed(cellTopology.hitLayerMask, clusId[0], clusId[1], clusId[2], iTracklet, iNextTracklet,
track, chi2, ts);
343 static_assert(
false,
"Unknown mode!");
351 for (
int cellTopologyId = 0; cellTopologyId < topology.nCells; ++cellTopologyId) {
352 const auto& cellTopology = topology.getCell(cellTopologyId);
353 if (mTimeFrame->getTracklets()[cellTopology.firstLink].empty() ||
354 mTimeFrame->getTracklets()[cellTopology.secondLink].empty()) {
358 auto& layerCells = mTimeFrame->getCells()[cellTopologyId];
359 const int currentLayerTrackletsNum{
static_cast<int>(mTimeFrame->getTracklets()[cellTopology.firstLink].size())};
361 if (mTaskArena->max_concurrency() <= 1) {
362 for (
int iTracklet{0}; iTracklet < currentLayerTrackletsNum; ++iTracklet) {
363 perTrackletCount[iTracklet] = forTrackletCells(
PassMode::OnePass{}, cellTopologyId, layerCells, iTracklet);
365 std::exclusive_scan(perTrackletCount.begin(), perTrackletCount.end(), perTrackletCount.begin(), 0);
367 tbb::parallel_for(0, currentLayerTrackletsNum, [&](
const int iTracklet) {
368 perTrackletCount[iTracklet] = forTrackletCells(
PassMode::TwoPassCount{}, cellTopologyId, layerCells, iTracklet);
371 std::exclusive_scan(perTrackletCount.begin(), perTrackletCount.end(), perTrackletCount.begin(), 0);
372 auto totalCells{perTrackletCount.back()};
373 if (totalCells == 0) {
374 auto& lut = mTimeFrame->getCellsLookupTable()[cellTopologyId];
375 lut.resize(currentLayerTrackletsNum + 1);
376 std::fill(lut.begin(), lut.end(), 0);
379 layerCells.resize(totalCells);
381 tbb::parallel_for(0, currentLayerTrackletsNum, [&](
const int iTracklet) {
382 int offset = perTrackletCount[iTracklet];
383 if (
offset == perTrackletCount[iTracklet + 1]) {
390 auto& lut = mTimeFrame->getCellsLookupTable()[cellTopologyId];
391 lut.resize(currentLayerTrackletsNum + 1);
392 std::copy_n(perTrackletCount.begin(), currentLayerTrackletsNum + 1, lut.begin());
394 if (mTimeFrame->hasMCinformation() && mTrkParams[iteration].CreateArtefactLabels) {
395 auto&
labels = mTimeFrame->getCellsLabel(cellTopologyId);
396 labels.reserve(layerCells.size());
397 for (
const auto& cell : layerCells) {
398 MCCompLabel currentLab{mTimeFrame->getTrackletsLabel(cellTopology.firstLink)[cell.getFirstTrackletIndex()]};
399 MCCompLabel nextLab{mTimeFrame->getTrackletsLabel(cellTopology.secondLink)[cell.getSecondTrackletIndex()]};
406 for (
int linkId = 0; linkId < topology.nLinks; ++linkId) {
415 const auto topology = mTimeFrame->getTrackingTopologyView();
416 mTaskArena->execute([&] {
417 std::vector<bounded_vector<CellNeighbour>> cellsNeighboursByTarget;
418 cellsNeighboursByTarget.reserve(topology.nCells);
419 for (
int cellTopologyId{0}; cellTopologyId < topology.nCells; ++cellTopologyId) {
421 deepVectorClear(mTimeFrame->getCellsNeighboursTopology()[cellTopologyId]);
423 cellsNeighboursByTarget.emplace_back(mMemoryPool.get());
426 for (
int outerLayer{0}; outerLayer < NLayers; ++outerLayer) {
427 for (
int cellTopologyId{0}; cellTopologyId < topology.nCells; ++cellTopologyId) {
428 const auto& cellTopology = topology.getCell(cellTopologyId);
429 if (cellTopology.hitLayerMask.last() != outerLayer ||
430 mTimeFrame->getCells()[cellTopologyId].empty()) {
433 const auto successors = topology.getCellsStartingWithLink(cellTopology.secondLink);
434 if (!successors.getEntries()) {
438 tbb::enumerable_thread_specific<bounded_vector<CellNeighbour>> sourceNeighbours([&]() {
return bounded_vector<CellNeighbour>{mMemoryPool.get()}; });
439 tbb::parallel_for(0,
static_cast<int>(mTimeFrame->getCells()[cellTopologyId].size()), [&](
const int iCell) {
440 auto& localNeighbours = sourceNeighbours.local();
441 const auto& currentCellSeed{mTimeFrame->getCells()[cellTopologyId][iCell]};
442 const int nextLayerTrackletIndex{currentCellSeed.getSecondTrackletIndex()};
443 for (
int iSuccessor{0}; iSuccessor < successors.getEntries(); ++iSuccessor) {
444 const int nextCellTopologyId = topology.cellsByFirstLink[successors.getFirstEntry() + iSuccessor];
445 if (mTimeFrame->getCells()[nextCellTopologyId].empty() ||
446 mTimeFrame->getCellsLookupTable()[nextCellTopologyId].empty()) {
449 const auto& nextCellLUT = mTimeFrame->getCellsLookupTable()[nextCellTopologyId];
450 if (nextLayerTrackletIndex + 1 >=
static_cast<int>(nextCellLUT.size())) {
453 const int nextLayerFirstCellIndex{nextCellLUT[nextLayerTrackletIndex]};
454 const int nextLayerLastCellIndex{nextCellLUT[nextLayerTrackletIndex + 1]};
455 for (
int iNextCell{nextLayerFirstCellIndex}; iNextCell < nextLayerLastCellIndex; ++iNextCell) {
456 const auto& nextCellSeedRef{mTimeFrame->getCells()[nextCellTopologyId][iNextCell]};
457 if (nextCellSeedRef.getFirstTrackletIndex() != nextLayerTrackletIndex || !currentCellSeed.getTimeStamp().isCompatible(nextCellSeedRef.getTimeStamp())) {
461 auto nextCellSeed{mTimeFrame->getCells()[nextCellTopologyId][iNextCell]};
462 if (!nextCellSeed.rotate(currentCellSeed.getAlpha()) ||
463 !nextCellSeed.propagateTo(currentCellSeed.getX(), getBz())) {
467 float chi2 = currentCellSeed.getPredictedChi2(nextCellSeed);
468 if (chi2 > mTrkParams[iteration].MaxChi2ClusterAttachment) {
472 const int nextLevel = currentCellSeed.getLevel() + 1;
473 localNeighbours.emplace_back(cellTopologyId, iCell, nextCellTopologyId, iNextCell, nextLevel);
479 for (
const auto& localNeighbours : sourceNeighbours) {
480 for (
const auto& neigh : localNeighbours) {
481 ++
count[neigh.nextCellTopology];
484 for (
size_t i{0};
i < topology.nCells; ++
i) {
485 cellsNeighboursByTarget[
i].reserve(
count[
i]);
487 for (
const auto& localNeighbours : sourceNeighbours) {
488 for (
const auto& neigh : localNeighbours) {
489 cellsNeighboursByTarget[neigh.nextCellTopology].emplace_back(neigh);
490 if (neigh.level > mTimeFrame->getCells()[neigh.nextCellTopology][neigh.nextCell].getLevel()) {
491 mTimeFrame->getCells()[neigh.nextCellTopology][neigh.nextCell].setLevel(neigh.level);
498 for (
int cellTopologyId{0}; cellTopologyId < topology.nCells; ++cellTopologyId) {
499 auto& cellsNeighbours = cellsNeighboursByTarget[cellTopologyId];
500 if (cellsNeighbours.empty()) {
504 std::sort(cellsNeighbours.begin(), cellsNeighbours.end(), [](
const auto&
a,
const auto&
b) {
505 return a.nextCell < b.nextCell;
508 auto& cellsNeighbourLUT = mTimeFrame->getCellsNeighboursLUT()[cellTopologyId];
509 cellsNeighbourLUT.assign(mTimeFrame->getCells()[cellTopologyId].size(), 0);
510 for (
const auto& neigh : cellsNeighbours) {
511 ++cellsNeighbourLUT[neigh.nextCell];
513 std::inclusive_scan(cellsNeighbourLUT.begin(), cellsNeighbourLUT.end(), cellsNeighbourLUT.begin());
515 mTimeFrame->getCellsNeighbours()[cellTopologyId].reserve(cellsNeighbours.size());
516 mTimeFrame->getCellsNeighboursTopology()[cellTopologyId].reserve(cellsNeighbours.size());
517 std::ranges::transform(cellsNeighbours, std::back_inserter(mTimeFrame->getCellsNeighbours()[cellTopologyId]), [](
const auto& neigh) { return neigh.cell; });
518 std::ranges::transform(cellsNeighbours, std::back_inserter(mTimeFrame->getCellsNeighboursTopology()[cellTopologyId]), [](
const auto& neigh) { return neigh.cellTopology; });
522 for (
auto& cellLUT : mTimeFrame->getCellsLookupTable()) {
534 mTaskArena->execute([&] {
535 auto forCellNeighbours = [&](
auto Tag,
int iCell,
int offset = 0) ->
int {
536 const auto& currentCell{currentCellSeed[iCell]};
537 const int cellTopologyId = currentCellTopologyId.empty() ? defaultCellTopologyId : currentCellTopologyId[iCell];
539 if constexpr (
decltype(Tag)
::value != PassMode::TwoPassInsert::value) {
540 if (currentCell.getLevel() != iLevel) {
543 if (currentCellId.empty()) {
545 const int clusterIndex = currentCell.getCluster(
layer);
546 if (clusterIndex != constants::UnusedIndex && mTimeFrame->isClusterUsed(
layer, clusterIndex)) {
553 const int cellId = currentCellId.empty() ? iCell : currentCellId[iCell];
554 if (cellTopologyId < 0 || mTimeFrame->getCellsNeighboursLUT()[cellTopologyId].empty()) {
557 const int startNeighbourId{cellId ? mTimeFrame->getCellsNeighboursLUT()[cellTopologyId][cellId - 1] : 0};
558 const int endNeighbourId{mTimeFrame->getCellsNeighboursLUT()[cellTopologyId][cellId]};
560 for (
int iNeighbourCell{startNeighbourId}; iNeighbourCell < endNeighbourId; ++iNeighbourCell) {
561 const int neighbourCellTopologyId = mTimeFrame->getCellsNeighboursTopology()[cellTopologyId][iNeighbourCell];
562 const int neighbourCellId = mTimeFrame->getCellsNeighbours()[cellTopologyId][iNeighbourCell];
563 const auto& neighbourCell = mTimeFrame->getCells()[neighbourCellTopologyId][neighbourCellId];
564 if (neighbourCell.getSecondTrackletIndex() != currentCell.getFirstTrackletIndex()) {
567 if (!currentCell.getTimeStamp().isCompatible(neighbourCell.getTimeStamp())) {
570 if (currentCell.getLevel() - 1 != neighbourCell.getLevel()) {
573 const int neighbourLayer = neighbourCell.getInnerLayer();
574 const int neighbourCluster = neighbourCell.getFirstClusterIndex();
575 if (mTimeFrame->isClusterUsed(neighbourLayer, neighbourCluster)) {
581 seed.getTimeStamp() = currentCell.getTimeStamp();
582 seed.getTimeStamp() += neighbourCell.getTimeStamp();
583 const auto& trHit = mTimeFrame->getTrackingFrameInfoOnLayer(neighbourLayer)[neighbourCluster];
585 if (!seed.rotate(trHit.alphaTrackingFrame)) {
593 if (mTrkParams[iteration].CorrType == o2::base::PropagatorF::MatCorrType::USEMatCorrNONE) {
594 if (!seed.correctForMaterial(mTrkParams[iteration].LayerxX0[neighbourLayer], mTrkParams[iteration].LayerxX0[neighbourLayer] * constants::Radl * constants::Rho,
true)) {
599 auto predChi2{seed.getPredictedChi2Quiet(trHit.positionTrackingFrame, trHit.covarianceTrackingFrame)};
600 if ((predChi2 > mTrkParams[iteration].MaxChi2ClusterAttachment) || predChi2 < 0.f) {
603 seed.setChi2(seed.getChi2() + predChi2);
604 if (!seed.o2::track::TrackParCov::update(trHit.positionTrackingFrame, trHit.covarianceTrackingFrame)) {
608 if constexpr (
decltype(Tag)
::value != PassMode::TwoPassCount::value) {
609 seed.getClusters()[neighbourLayer] = neighbourCluster;
610 auto mask = seed.getHitLayerMask();
611 mask.set(neighbourLayer);
612 seed.setHitLayerMask(
mask);
613 seed.setLevel(neighbourCell.getLevel());
614 seed.setFirstTrackletIndex(neighbourCell.getFirstTrackletIndex());
615 seed.setSecondTrackletIndex(neighbourCell.getSecondTrackletIndex());
618 if constexpr (
decltype(Tag)
::value == PassMode::OnePass::value) {
619 updatedCellSeeds.push_back(seed);
620 updatedCellsIds.push_back(neighbourCellId);
621 updatedCellsTopologyIds.push_back(neighbourCellTopologyId);
622 }
else if constexpr (
decltype(Tag)
::value == PassMode::TwoPassCount::value) {
624 }
else if constexpr (
decltype(Tag)
::value == PassMode::TwoPassInsert::value) {
625 updatedCellSeeds[
offset] = seed;
626 updatedCellsIds[
offset] = neighbourCellId;
627 updatedCellsTopologyIds[
offset++] = neighbourCellTopologyId;
629 static_assert(
false,
"Unknown mode!");
635 const int nCells =
static_cast<int>(currentCellSeed.size());
636 if (mTaskArena->max_concurrency() <= 1) {
637 for (
int iCell{0}; iCell < nCells; ++iCell) {
642 tbb::parallel_for(0, nCells, [&](
const int iCell) {
646 std::exclusive_scan(perCellCount.begin(), perCellCount.end(), perCellCount.begin(), 0);
647 auto totalNeighbours{perCellCount.back()};
648 if (totalNeighbours == 0) {
651 updatedCellSeeds.resize(totalNeighbours);
652 updatedCellsIds.resize(totalNeighbours);
653 updatedCellsTopologyIds.resize(totalNeighbours);
655 tbb::parallel_for(0, nCells, [&](
const int iCell) {
656 int offset = perCellCount[iCell];
657 if (
offset == perCellCount[iCell + 1]) {
671 const Cluster*
const* unsortedClusters,
674 const auto& trkParams = mTrkParams[iteration];
676 tfInfos, trkParams.LayerxX0.data(), trkParams.NLayers, mBz,
677 trkParams.MaxChi2ClusterAttachment, trkParams.MaxChi2NDF,
678 propagator, trkParams.CorrType, trkParams.ShiftRefToCluster, trkParams.RepeatRefitOut};
680 if (!track::refitTrackSeed<NLayers>(seed,
684 trkParams.LayerRadii.data(),
685 trkParams.MinPt.data(),
686 trkParams.ReseedIfShorter)) {
690 const bool extendTop = trkParams.PassFlags[IterationStep::TrackFollowerTop];
691 const bool extendBot = trkParams.PassFlags[IterationStep::TrackFollowerBot];
693 track = makeTrackITSExt(internalTrack);
697 const int maxHypotheses = std::max(1, trkParams.TrackFollowerMaxHypotheses);
699 if (
static_cast<int>(scratch.activeHypotheses.size()) <
maxHypotheses) {
702 if (
static_cast<int>(scratch.nextHypotheses.size()) <
maxHypotheses) {
706 const Cluster* clustersPtrs[NLayers]{};
707 const unsigned char* usedClustersPtrs[NLayers]{};
708 const int* clustersIndexTablesPtrs[NLayers]{};
709 const int* rofClustersPtrs[NLayers]{};
710 for (
int iLayer{0}; iLayer < NLayers; ++iLayer) {
711 clustersPtrs[iLayer] = mTimeFrame->getClusters()[iLayer].data();
712 usedClustersPtrs[iLayer] = mTimeFrame->getUsedClusters(iLayer).data();
713 clustersIndexTablesPtrs[iLayer] = mTimeFrame->getIndexTable(0, iLayer).data();
714 rofClustersPtrs[iLayer] = mTimeFrame->getROFrameClusters(iLayer).data();
717 &mTimeFrame->getIndexTableUtils(),
718 mTimeFrame->getROFMaskView(),
719 mTimeFrame->getROFOverlapTableView(),
720 clustersPtrs, usedClustersPtrs, clustersIndexTablesPtrs, rofClustersPtrs,
721 trkParams.LayerRadii.data(), trkParams.PhiBins,
maxHypotheses,
722 trkParams.TrackFollowerNSigmaCutPhi, trkParams.TrackFollowerNSigmaCutZ};
724 const auto backup = internalTrack;
725 auto best = internalTrack;
730 if (!followTrackExtensionDirection<NLayers>(startHypothesis, fitCtx, followCtx,
outward,
731 scratch.activeHypotheses.data(),
732 scratch.nextHypotheses.data(),
753 firstClusters.resize(mTrkParams[iteration].NLayers);
756 const Cluster* unsortedClusters[NLayers]{};
757 for (
int iLayer = 0; iLayer < NLayers; ++iLayer) {
758 tfInfos[iLayer] = mTimeFrame->getTrackingFrameInfoOnLayer(iLayer).data();
759 unsortedClusters[iLayer] = mTimeFrame->getUnsortedClusters()[iLayer].data();
761 const auto topology = mTimeFrame->getTrackingTopologyView();
762 for (
int startLevel{mTrkParams[iteration].CellsPerRoad()}; startLevel >= mTrkParams[iteration].CellMinimumLevel(); --startLevel) {
764 auto seedFilter = [&](
const auto& seed) {
765 return seed.getHitLayerMask().isAllowed(mTrkParams[iteration].MaxHoles, mTrkParams[iteration].HoleLayerMask) &&
766 seed.getHitLayerMask().length() >= mTrkParams[iteration].MinTrackLength &&
767 seed.getQ2Pt() <= 1.e3 && seed.getChi2() <= mTrkParams[iteration].MaxChi2NDF * ((startLevel + 2) * 2 - 5);
771 for (
int startCellTopologyId{0}; startCellTopologyId < topology.nCells; ++startCellTopologyId) {
772 const int startLayer = topology.getCell(startCellTopologyId).hitLayerMask.last();
773 if (!(mTrkParams[iteration].StartLayerMask.has(startLayer)) || mTimeFrame->getCells()[startCellTopologyId].empty()) {
778 bounded_vector<int> lastCellTopologyId(mMemoryPool.get()), updatedCellTopologyId(mMemoryPool.get());
781 processNeighbours(iteration, startCellTopologyId, startLevel, mTimeFrame->getCells()[startCellTopologyId], lastCellId, lastCellTopologyId, updatedCellSeed, updatedCellId, updatedCellTopologyId);
783 int level = startLevel;
784 while (
level > 2 && !updatedCellSeed.empty()) {
785 lastCellSeed.swap(updatedCellSeed);
786 lastCellId.swap(updatedCellId);
787 lastCellTopologyId.swap(updatedCellTopologyId);
791 processNeighbours(iteration, constants::UnusedIndex, --
level, lastCellSeed, lastCellId, lastCellTopologyId, updatedCellSeed, updatedCellId, updatedCellTopologyId);
797 if (!updatedCellSeed.empty()) {
798 trackSeeds.reserve(trackSeeds.size() + std::count_if(updatedCellSeed.begin(), updatedCellSeed.end(), seedFilter));
799 std::copy_if(updatedCellSeed.begin(), updatedCellSeed.end(), std::back_inserter(trackSeeds), seedFilter);
803 if (trackSeeds.empty()) {
808 mTaskArena->execute([&] {
809 const int nSeeds =
static_cast<int>(trackSeeds.size());
810 const int nWorkers = std::min(
static_cast<int>(mTaskArena->max_concurrency()), nSeeds);
811 const int chunkSize = std::min(nSeeds, std::clamp(nSeeds / (16 * nWorkers), 256, 4096));
812 std::atomic<int> nextSeed{0};
813 std::mutex tracksMutex;
814 tbb::parallel_for(0, nWorkers, [&](
const int) {
816 localTracks.reserve(chunkSize);
818 const int firstSeed = nextSeed.fetch_add(chunkSize, std::memory_order_relaxed);
819 if (firstSeed >= nSeeds) {
822 const int lastSeed = std::min(firstSeed + chunkSize, nSeeds);
823 for (
int iSeed{firstSeed}; iSeed < lastSeed; ++iSeed) {
825 if (finaliseTrackSeed(trackSeeds[iSeed], temporaryTrack, iteration, tfInfos, unsortedClusters, propagator)) {
826 localTracks.push_back(temporaryTrack);
829 if (!localTracks.empty()) {
830 std::lock_guard lock{tracksMutex};
831 tracks.insert(tracks.end(), std::make_move_iterator(localTracks.begin()), std::make_move_iterator(localTracks.end()));
841 std::sort(tracks.begin(), tracks.end(), [](
const auto&
a,
const auto&
b) {
842 return track::isBetter(a, b);
845 acceptTracks(iteration, tracks, firstClusters);
847 markTracks(iteration);
855 auto& trks = mTimeFrame->getTracks();
856 trks.reserve(trks.size() + tracks.size());
857 const float smallestROFHalf = mTimeFrame->getROFOverlapTableView().getClockLayer().mROFLength * 0.5f;
858 for (
auto&
track : tracks) {
860 bool isFirstShared{
false};
861 int firstLayer{-1}, firstCluster{-1};
862 for (
int iLayer{0}; iLayer < mTrkParams[iteration].NLayers; ++iLayer) {
863 if (
track.getClusterIndex(iLayer) == constants::UnusedIndex) {
866 bool isShared = mTimeFrame->isClusterUsed(iLayer,
track.getClusterIndex(iLayer));
867 nShared +=
int(isShared);
868 if (firstLayer < 0) {
869 firstCluster =
track.getClusterIndex(iLayer);
870 isFirstShared = isShared && mTrkParams[iteration].AllowSharingFirstCluster && std::find(firstClusters[iLayer].begin(), firstClusters[iLayer].
end(), firstCluster) != firstClusters[iLayer].end();
876 if (nShared -
int(isFirstShared && mTrkParams[iteration].AllowSharingFirstCluster) > mTrkParams[iteration].SharedMaxClusters) {
880 bool firstCls{
true}, nominalCompatible{
true};
882 for (
int iLayer{0}; iLayer < mTrkParams[iteration].NLayers; ++iLayer) {
883 if (
track.getClusterIndex(iLayer) == constants::UnusedIndex) {
886 mTimeFrame->markUsedCluster(iLayer,
track.getClusterIndex(iLayer));
887 int currentROF = mTimeFrame->getClusterROF(iLayer,
track.getClusterIndex(iLayer));
888 const auto nominalROFTS = mTimeFrame->getROFOverlapTableView().getLayer(iLayer).getROFTimeBounds(currentROF);
889 const auto expandedROFTS = mTimeFrame->getROFOverlapTableView().getLayer(iLayer).getROFTimeBounds(currentROF,
true);
892 nominalTS = nominalROFTS;
893 expandedTS = expandedROFTS;
895 if (nominalCompatible) {
896 if (nominalTS.isCompatible(nominalROFTS)) {
897 nominalTS += nominalROFTS;
899 nominalCompatible =
false;
902 if (!expandedTS.isCompatible(expandedROFTS)) {
903 LOGP(fatal,
"TS {}+/-{} are incompatible with {}+/-{}, this should not happen!", expandedROFTS.getTimeStamp(), expandedROFTS.getTimeStampError(), expandedTS.getTimeStamp(), expandedTS.getTimeStampError());
905 expandedTS += expandedROFTS;
908 track.getTimeStamp() = (nominalCompatible ? nominalTS : expandedTS).makeSymmetrical();
911 if (
track.getTimeStamp().getTimeStampError() > smallestROFHalf) {
912 track.getTimeStamp().setTimeStampError(smallestROFHalf);
914 const auto diff =
track.getExtendedLayerPattern<NLayers>();
916 size_t nExtendedClusters = 0;
917 for (
int iLayer{0}; iLayer < mTrkParams[iteration].NLayers; ++iLayer) {
918 nExtendedClusters +=
static_cast<bool>(diff & (0x1u << iLayer));
920 mTimeFrame->addTrackExtensionCounters(1, nExtendedClusters);
922 track.clearExtendedLayerPattern();
923 trks.emplace_back(
track);
925 if (mTrkParams[iteration].AllowSharingFirstCluster) {
926 firstClusters[firstLayer].push_back(firstCluster);
934 if (mTrkParams[iteration].AllowSharingFirstCluster) {
936 auto& tracks = mTimeFrame->getTracks();
939 std::iota(fclusSort.begin(), fclusSort.end(), 0);
940 std::sort(fclusSort.begin(), fclusSort.end(), [&tracks](
int a,
int b) {
941 return tracks[a].getFirstLayerClusterIndex() < tracks[b].getFirstLayerClusterIndex();
945 const auto t1FirstLayer{
t1.getFirstClusterLayer()}, t2FirstLayer{t2.getFirstClusterLayer()};
946 if (t1FirstLayer != t2FirstLayer) {
949 if (mTimeFrame->getClusterROF(t1FirstLayer,
t1.getClusterIndex(t1FirstLayer)) != mTimeFrame->getClusterROF(t2FirstLayer, t2.getClusterIndex(t2FirstLayer))) {
952 if (!math_utils::isPhiDifferenceBelow(
t1.getPhi(), t2.getPhi(), mTrkParams[iteration].SharedClusterMaxDeltaPhi)) {
955 if (std::abs(
t1.getEta() - t2.getEta()) > mTrkParams[iteration].SharedClusterMaxDeltaEta) {
958 if (mTrkParams[iteration].SharedClusterOppositeSign &&
t1.getSign() == t2.getSign()) {
964 for (
int i{0}; i < static_cast<int>(fclusSort.size()); ++
i) {
965 auto&
track = tracks[fclusSort[
i]];
966 for (
int j{
i + 1}; j < static_cast<int>(fclusSort.size()) && tracks[fclusSort[
j]].getFirstLayerClusterIndex() ==
track.getFirstLayerClusterIndex(); ++
j) {
967 auto& track2 = tracks[fclusSort[
j]];
968 if (areTracksSelected(
track, track2)) {
969 track.setSharedClusters();
970 track2.setSharedClusters();