48 const auto topology = mTimeFrame->getTrackingTopologyView();
49 for (
int transitionId = 0; transitionId < topology.nTransitions; ++transitionId) {
50 mTimeFrame->getTracklets()[transitionId].clear();
51 mTimeFrame->getTrackletsLabel(transitionId).clear();
52 std::fill(mTimeFrame->getTrackletsLookupTable()[transitionId].begin(), mTimeFrame->getTrackletsLookupTable()[transitionId].end(), 0);
55 const Vertex diamondVert(mTrkParams[iteration].Diamond, mTrkParams[iteration].DiamondCov, 1, 1.f);
56 gsl::span<const Vertex> diamondSpan(&diamondVert, 1);
58 mTaskArena->execute([&] {
59 auto forTracklets = [&](
auto Tag,
int transitionId,
int pivotROF,
int base,
int&
offset) ->
int {
60 const auto& transition = topology.getTransition(transitionId);
61 if (!mTimeFrame->getROFMaskView().isROFEnabled(transition.fromLayer, pivotROF)) {
64 gsl::span<const Vertex> primaryVertices = mTrkParams[iteration].UseDiamond ? diamondSpan : mTimeFrame->getPrimaryVertices(transition.fromLayer, pivotROF);
65 if (primaryVertices.empty()) {
68 const int startVtx = iVertex >= 0 ? iVertex : 0;
69 const int endVtx = iVertex >= 0 ? o2::gpu::CAMath::Min(iVertex + 1,
int(primaryVertices.size())) :
int(primaryVertices.size());
70 if (endVtx <= startVtx || (iVertex + 1) > primaryVertices.size()) {
74 const auto& rofOverlap = mTimeFrame->getROFOverlapTableView().getOverlap(transition.fromLayer, transition.toLayer, pivotROF);
75 if (!rofOverlap.getEntries()) {
80 auto&
tracklets = mTimeFrame->getTracklets()[transitionId];
81 auto layer0 = mTimeFrame->getClustersOnLayer(pivotROF, transition.fromLayer);
86 const float meanDeltaR = mTrkParams[iteration].LayerRadii[transition.toLayer] - mTrkParams[iteration].LayerRadii[transition.fromLayer];
87 const float phiCut = mTimeFrame->getTransitionPhiCut(transitionId);
88 const float msAngle = mTimeFrame->getTransitionMSAngle(transitionId);
90 for (
int iCluster = 0; iCluster <
int(layer0.size()); ++iCluster) {
91 const Cluster& currentCluster = layer0[iCluster];
92 const int currentSortedIndex = mTimeFrame->getSortedIndex(pivotROF, transition.fromLayer, iCluster);
93 if (mTimeFrame->isClusterUsed(transition.fromLayer, currentCluster.
clusterId)) {
96 const float inverseR0 = 1.f / currentCluster.
radius;
98 for (
int iV = startVtx; iV < endVtx; ++iV) {
99 const auto& pv = primaryVertices[iV];
100 if (!mTimeFrame->getROFVertexLookupTableView().isVertexCompatible(transition.fromLayer, pivotROF, pv)) {
106 const float resolution = o2::gpu::CAMath::Sqrt(math_utils::Sq(mTimeFrame->getPositionResolution(transition.fromLayer)) + math_utils::Sq(mTrkParams[iteration].PVres) /
float(pv.getNContributors()));
107 const float tanLambda = (currentCluster.
zCoordinate - pv.getZ()) * inverseR0;
108 const float zAtRmin = tanLambda * (mTimeFrame->getMinR(transition.toLayer) - currentCluster.
radius) + currentCluster.
zCoordinate;
109 const float zAtRmax = tanLambda * (mTimeFrame->getMaxR(transition.toLayer) - currentCluster.
radius) + currentCluster.
zCoordinate;
111 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));
112 const auto bins = o2::its::getBinsRect(currentCluster, transition.toLayer, zAtRmin, zAtRmax,
113 sigmaZ * mTrkParams[iteration].NSigmaCut, phiCut,
114 mTimeFrame->getIndexTableUtils());
118 int phiBinsNum =
bins.w -
bins.y + 1;
119 if (phiBinsNum < 0) {
120 phiBinsNum += mTrkParams[iteration].PhiBins;
123 for (
int targetROF = rofOverlap.getFirstEntry(); targetROF < rofOverlap.getEntriesBound(); ++targetROF) {
124 if (!mTimeFrame->getROFMaskView().isROFEnabled(transition.toLayer, targetROF)) {
127 auto layer1 = mTimeFrame->getClustersOnLayer(targetROF, transition.toLayer);
128 if (layer1.empty()) {
131 const auto ts = mTimeFrame->getROFOverlapTableView().getTimeStamp(transition.fromLayer, pivotROF, transition.toLayer, targetROF);
132 if (!ts.isCompatible(pv.getTimeStamp())) {
135 const auto& targetIndexTable = mTimeFrame->getIndexTable(targetROF, transition.toLayer);
136 const int zBinRange = (
bins.z -
bins.x) + 1;
137 for (
int iPhi = 0; iPhi < phiBinsNum; ++iPhi) {
138 const int iPhiBin = (
bins.y + iPhi) % mTrkParams[iteration].PhiBins;
139 const int firstBinIdx = mTimeFrame->getIndexTableUtils().getBinIndex(
bins.x, iPhiBin);
140 const int maxBinIdx = firstBinIdx + zBinRange;
141 const int firstRow = targetIndexTable[firstBinIdx];
142 const int lastRow = targetIndexTable[maxBinIdx];
143 for (
int iNext = firstRow; iNext <
lastRow; ++iNext) {
144 if (iNext >=
int(layer1.size())) {
147 const Cluster& nextCluster = layer1[iNext];
148 if (mTimeFrame->isClusterUsed(transition.toLayer, nextCluster.
clusterId)) {
153 if (deltaZ / sigmaZ < mTrkParams[iteration].NSigmaCut &&
154 math_utils::isPhiDifferenceBelow(currentCluster.
phi, nextCluster.
phi, phiCut)) {
157 if constexpr (
decltype(Tag)
::value == PassMode::OnePass::value) {
158 tracklets.emplace_back(currentSortedIndex, mTimeFrame->getSortedIndex(targetROF, transition.toLayer, iNext), tanL, phi, ts);
159 }
else if constexpr (
decltype(Tag)
::value == PassMode::TwoPassCount::value) {
161 }
else if constexpr (
decltype(Tag)
::value == PassMode::TwoPassInsert::value) {
162 const int idx = base +
offset++;
163 tracklets[idx] =
Tracklet(currentSortedIndex, mTimeFrame->getSortedIndex(targetROF, transition.toLayer, iNext), tanL, phi, ts);
175 if (mTaskArena->max_concurrency() <= 1) {
176 for (
int transitionId{0}; transitionId < topology.nTransitions; ++transitionId) {
177 const int fromLayer = topology.getTransition(transitionId).fromLayer;
178 const int startROF = 0, endROF = mTimeFrame->getROFOverlapTableView().getLayer(fromLayer).mNROFsTF;
179 for (
int pivotROF{startROF}; pivotROF < endROF; ++pivotROF) {
184 tbb::parallel_for(0,
static_cast<int>(topology.nTransitions), [&](
const int transitionId) {
185 const int fromLayer = topology.getTransition(transitionId).fromLayer;
186 const int startROF = 0, endROF = mTimeFrame->getROFOverlapTableView().getLayer(fromLayer).mNROFsTF;
187 bounded_vector<int> perROFCount((endROF - startROF) + 1, mMemoryPool.get());
188 tbb::parallel_for(startROF, endROF, [&](const int pivotROF) {
189 perROFCount[pivotROF - startROF] = forTracklets(PassMode::TwoPassCount{}, transitionId, pivotROF, 0, dummy);
191 std::exclusive_scan(perROFCount.begin(), perROFCount.end(), perROFCount.begin(), 0);
192 const int nTracklets = perROFCount.back();
193 mTimeFrame->getTracklets()[transitionId].resize(nTracklets);
194 if (nTracklets == 0) {
197 tbb::parallel_for(startROF, endROF, [&](
const int pivotROF) {
198 int baseIdx = perROFCount[pivotROF - startROF];
199 if (baseIdx == perROFCount[pivotROF + 1 - startROF]) {
208 tbb::parallel_for(0,
static_cast<int>(topology.nTransitions), [&](
const int transitionId) {
211 auto& trkl{mTimeFrame->getTracklets()[transitionId]};
212 std::sort(trkl.begin(), trkl.end());
213 trkl.erase(std::unique(trkl.begin(), trkl.end()), trkl.end());
214 trkl.shrink_to_fit();
215 auto& lut{mTimeFrame->getTrackletsLookupTable()[transitionId]};
217 for (
const auto& tkl : trkl) {
218 lut[tkl.firstClusterIndex + 1]++;
220 std::inclusive_scan(lut.begin(), lut.end(), lut.begin());
225 if (mTimeFrame->hasMCinformation() && mTrkParams[iteration].CreateArtefactLabels) {
226 tbb::parallel_for(0,
static_cast<int>(topology.nTransitions), [&](
const int transitionId) {
227 const auto& transition = topology.getTransition(transitionId);
228 for (auto& trk : mTimeFrame->getTracklets()[transitionId]) {
230 int currentId{mTimeFrame->getClusters()[transition.fromLayer][trk.firstClusterIndex].clusterId};
231 int nextId{mTimeFrame->getClusters()[transition.toLayer][trk.secondClusterIndex].clusterId};
232 for (const auto& lab1 : mTimeFrame->getClusterLabels(transition.fromLayer, currentId)) {
233 for (const auto& lab2 : mTimeFrame->getClusterLabels(transition.toLayer, nextId)) {
234 if (lab1 == lab2 && lab1.isValid()) {
239 if (label.isValid()) {
243 mTimeFrame->getTrackletsLabel(transitionId).emplace_back(label);
253 const auto topology = mTimeFrame->getTrackingTopologyView();
254 for (
int cellTopologyId = 0; cellTopologyId < topology.nCells; ++cellTopologyId) {
257 if (mTimeFrame->hasMCinformation() && mTrkParams[iteration].CreateArtefactLabels) {
262 mTaskArena->execute([&] {
264 const auto& cellTopology = topology.getCell(cellTopologyId);
265 const auto& firstTransition = topology.getTransition(cellTopology.firstTransition);
266 const auto& secondTransition = topology.getTransition(cellTopology.secondTransition);
267 const Tracklet& currentTracklet{mTimeFrame->getTracklets()[cellTopology.firstTransition][iTracklet]};
269 const int nextLayerFirstTrackletIndex{mTimeFrame->getTrackletsLookupTable()[cellTopology.secondTransition][nextLayerClusterIndex]};
270 const int nextLayerLastTrackletIndex{mTimeFrame->getTrackletsLookupTable()[cellTopology.secondTransition][nextLayerClusterIndex + 1]};
272 for (
int iNextTracklet{nextLayerFirstTrackletIndex}; iNextTracklet < nextLayerLastTrackletIndex; ++iNextTracklet) {
273 const Tracklet& nextTracklet{mTimeFrame->getTracklets()[cellTopology.secondTransition][iNextTracklet]};
274 if (nextTracklet.firstClusterIndex != nextLayerClusterIndex) {
277 if (!currentTracklet.getTimeStamp().isCompatible(nextTracklet.getTimeStamp())) {
281 const float deltaTanLambdaSigma = std::abs(currentTracklet.tanLambda - nextTracklet.tanLambda) / mTrkParams[iteration].CellDeltaTanLambdaSigma;
282 if (deltaTanLambdaSigma < mTrkParams[iteration].NSigmaCut) {
286 mTimeFrame->getClusters()[firstTransition.fromLayer][currentTracklet.firstClusterIndex].clusterId,
287 mTimeFrame->getClusters()[firstTransition.toLayer][nextTracklet.firstClusterIndex].clusterId,
288 mTimeFrame->getClusters()[secondTransition.toLayer][nextTracklet.secondClusterIndex].clusterId};
289 const int hitLayers[3]{firstTransition.fromLayer, firstTransition.toLayer, secondTransition.toLayer};
290 const auto& cluster1_glo = mTimeFrame->getUnsortedClusters()[firstTransition.fromLayer][clusId[0]];
291 const auto& cluster2_glo = mTimeFrame->getUnsortedClusters()[firstTransition.toLayer][clusId[1]];
292 const auto& cluster3_tf = mTimeFrame->getTrackingFrameInfoOnLayer(secondTransition.toLayer)[clusId[2]];
293 auto track{o2::its::track::buildTrackSeed(cluster1_glo, cluster2_glo, cluster3_tf, mBz)};
297 for (
int iC{2}; iC--;) {
298 const int hitLayer = hitLayers[iC];
299 const TrackingFrameInfo& trackingHit = mTimeFrame->getTrackingFrameInfoOnLayer(hitLayer)[clusId[iC]];
309 if (!track.correctForMaterial(mTrkParams[iteration].LayerxX0[hitLayer], mTrkParams[iteration].LayerxX0[hitLayer] * constants::Radl * constants::Rho,
true)) {
314 if (!iC && predChi2 > mTrkParams[iteration].MaxChi2ClusterAttachment) {
326 TimeEstBC ts = currentTracklet.getTimeStamp();
327 ts += nextTracklet.getTimeStamp();
328 if constexpr (
decltype(Tag)
::value == PassMode::OnePass::value) {
329 layerCells.emplace_back(cellTopology.hitLayerMask, clusId[0], clusId[1], clusId[2], iTracklet, iNextTracklet, track, chi2, ts);
331 }
else if constexpr (
decltype(Tag)
::value == PassMode::TwoPassCount::value) {
333 }
else if constexpr (
decltype(Tag)
::value == PassMode::TwoPassInsert::value) {
334 layerCells[
offset++] =
CellSeed(cellTopology.hitLayerMask, clusId[0], clusId[1], clusId[2], iTracklet, iNextTracklet, track, chi2, ts);
337 static_assert(
false,
"Unknown mode!");
345 for (
int cellTopologyId = 0; cellTopologyId < topology.nCells; ++cellTopologyId) {
346 const auto& cellTopology = topology.getCell(cellTopologyId);
347 if (mTimeFrame->getTracklets()[cellTopology.firstTransition].empty() ||
348 mTimeFrame->getTracklets()[cellTopology.secondTransition].empty()) {
352 auto& layerCells = mTimeFrame->getCells()[cellTopologyId];
353 const int currentLayerTrackletsNum{
static_cast<int>(mTimeFrame->getTracklets()[cellTopology.firstTransition].size())};
355 if (mTaskArena->max_concurrency() <= 1) {
356 for (
int iTracklet{0}; iTracklet < currentLayerTrackletsNum; ++iTracklet) {
357 perTrackletCount[iTracklet] = forTrackletCells(
PassMode::OnePass{}, cellTopologyId, layerCells, iTracklet);
359 std::exclusive_scan(perTrackletCount.begin(), perTrackletCount.end(), perTrackletCount.begin(), 0);
361 tbb::parallel_for(0, currentLayerTrackletsNum, [&](
const int iTracklet) {
362 perTrackletCount[iTracklet] = forTrackletCells(
PassMode::TwoPassCount{}, cellTopologyId, layerCells, iTracklet);
365 std::exclusive_scan(perTrackletCount.begin(), perTrackletCount.end(), perTrackletCount.begin(), 0);
366 auto totalCells{perTrackletCount.back()};
367 if (totalCells == 0) {
368 auto& lut = mTimeFrame->getCellsLookupTable()[cellTopologyId];
369 lut.resize(currentLayerTrackletsNum + 1);
370 std::fill(lut.begin(), lut.end(), 0);
373 layerCells.resize(totalCells);
375 tbb::parallel_for(0, currentLayerTrackletsNum, [&](
const int iTracklet) {
376 int offset = perTrackletCount[iTracklet];
377 if (
offset == perTrackletCount[iTracklet + 1]) {
384 auto& lut = mTimeFrame->getCellsLookupTable()[cellTopologyId];
385 lut.resize(currentLayerTrackletsNum + 1);
386 std::copy_n(perTrackletCount.begin(), currentLayerTrackletsNum + 1, lut.begin());
388 if (mTimeFrame->hasMCinformation() && mTrkParams[iteration].CreateArtefactLabels) {
389 auto&
labels = mTimeFrame->getCellsLabel(cellTopologyId);
390 labels.reserve(layerCells.size());
391 for (
const auto& cell : layerCells) {
392 MCCompLabel currentLab{mTimeFrame->getTrackletsLabel(cellTopology.firstTransition)[cell.getFirstTrackletIndex()]};
393 MCCompLabel nextLab{mTimeFrame->getTrackletsLabel(cellTopology.secondTransition)[cell.getSecondTrackletIndex()]};
400 for (
int transitionId = 0; transitionId < topology.nTransitions; ++transitionId) {
409 const auto topology = mTimeFrame->getTrackingTopologyView();
410 mTaskArena->execute([&] {
411 std::vector<bounded_vector<CellNeighbour>> cellsNeighboursByTarget;
412 cellsNeighboursByTarget.reserve(topology.nCells);
413 for (
int cellTopologyId{0}; cellTopologyId < topology.nCells; ++cellTopologyId) {
415 deepVectorClear(mTimeFrame->getCellsNeighboursTopology()[cellTopologyId]);
417 cellsNeighboursByTarget.emplace_back(mMemoryPool.get());
420 for (
int outerLayer{0}; outerLayer < NLayers; ++outerLayer) {
421 for (
int cellTopologyId{0}; cellTopologyId < topology.nCells; ++cellTopologyId) {
422 const auto& cellTopology = topology.getCell(cellTopologyId);
423 if (cellTopology.hitLayerMask.last() != outerLayer ||
424 mTimeFrame->getCells()[cellTopologyId].empty()) {
427 const auto successors = topology.getCellsStartingWithTransition(cellTopology.secondTransition);
428 if (!successors.getEntries()) {
432 tbb::enumerable_thread_specific<bounded_vector<CellNeighbour>> sourceNeighbours([&]() {
return bounded_vector<CellNeighbour>{mMemoryPool.get()}; });
433 tbb::parallel_for(0,
static_cast<int>(mTimeFrame->getCells()[cellTopologyId].size()), [&](
const int iCell) {
434 auto& localNeighbours = sourceNeighbours.local();
435 const auto& currentCellSeed{mTimeFrame->getCells()[cellTopologyId][iCell]};
436 const int nextLayerTrackletIndex{currentCellSeed.getSecondTrackletIndex()};
437 for (
int iSuccessor{0}; iSuccessor < successors.getEntries(); ++iSuccessor) {
438 const int nextCellTopologyId = topology.cellsByFirstTransition[successors.getFirstEntry() + iSuccessor];
439 if (mTimeFrame->getCells()[nextCellTopologyId].empty() ||
440 mTimeFrame->getCellsLookupTable()[nextCellTopologyId].empty()) {
443 const auto& nextCellLUT = mTimeFrame->getCellsLookupTable()[nextCellTopologyId];
444 if (nextLayerTrackletIndex + 1 >=
static_cast<int>(nextCellLUT.size())) {
447 const int nextLayerFirstCellIndex{nextCellLUT[nextLayerTrackletIndex]};
448 const int nextLayerLastCellIndex{nextCellLUT[nextLayerTrackletIndex + 1]};
449 for (
int iNextCell{nextLayerFirstCellIndex}; iNextCell < nextLayerLastCellIndex; ++iNextCell) {
450 const auto& nextCellSeedRef{mTimeFrame->getCells()[nextCellTopologyId][iNextCell]};
451 if (nextCellSeedRef.getFirstTrackletIndex() != nextLayerTrackletIndex || !currentCellSeed.getTimeStamp().isCompatible(nextCellSeedRef.getTimeStamp())) {
455 auto nextCellSeed{mTimeFrame->getCells()[nextCellTopologyId][iNextCell]};
456 if (!nextCellSeed.rotate(currentCellSeed.getAlpha()) ||
457 !nextCellSeed.propagateTo(currentCellSeed.getX(), getBz())) {
461 float chi2 = currentCellSeed.getPredictedChi2(nextCellSeed);
462 if (chi2 > mTrkParams[iteration].MaxChi2ClusterAttachment) {
466 const int nextLevel = currentCellSeed.getLevel() + 1;
467 localNeighbours.emplace_back(cellTopologyId, iCell, nextCellTopologyId, iNextCell, nextLevel);
473 for (
const auto& localNeighbours : sourceNeighbours) {
474 for (
const auto& neigh : localNeighbours) {
475 ++
count[neigh.nextCellTopology];
478 for (
size_t i{0};
i < topology.nCells; ++
i) {
479 cellsNeighboursByTarget[
i].reserve(
count[
i]);
481 for (
const auto& localNeighbours : sourceNeighbours) {
482 for (
const auto& neigh : localNeighbours) {
483 cellsNeighboursByTarget[neigh.nextCellTopology].emplace_back(neigh);
484 if (neigh.level > mTimeFrame->getCells()[neigh.nextCellTopology][neigh.nextCell].getLevel()) {
485 mTimeFrame->getCells()[neigh.nextCellTopology][neigh.nextCell].setLevel(neigh.level);
492 for (
int cellTopologyId{0}; cellTopologyId < topology.nCells; ++cellTopologyId) {
493 auto& cellsNeighbours = cellsNeighboursByTarget[cellTopologyId];
494 if (cellsNeighbours.empty()) {
498 std::sort(cellsNeighbours.begin(), cellsNeighbours.end(), [](
const auto&
a,
const auto&
b) {
499 return a.nextCell < b.nextCell;
502 auto& cellsNeighbourLUT = mTimeFrame->getCellsNeighboursLUT()[cellTopologyId];
503 cellsNeighbourLUT.assign(mTimeFrame->getCells()[cellTopologyId].size(), 0);
504 for (
const auto& neigh : cellsNeighbours) {
505 ++cellsNeighbourLUT[neigh.nextCell];
507 std::inclusive_scan(cellsNeighbourLUT.begin(), cellsNeighbourLUT.end(), cellsNeighbourLUT.begin());
509 mTimeFrame->getCellsNeighbours()[cellTopologyId].reserve(cellsNeighbours.size());
510 mTimeFrame->getCellsNeighboursTopology()[cellTopologyId].reserve(cellsNeighbours.size());
511 std::ranges::transform(cellsNeighbours, std::back_inserter(mTimeFrame->getCellsNeighbours()[cellTopologyId]), [](
const auto& neigh) { return neigh.cell; });
512 std::ranges::transform(cellsNeighbours, std::back_inserter(mTimeFrame->getCellsNeighboursTopology()[cellTopologyId]), [](
const auto& neigh) { return neigh.cellTopology; });
516 for (
auto& cellLUT : mTimeFrame->getCellsLookupTable()) {
528 mTaskArena->execute([&] {
529 auto forCellNeighbours = [&](
auto Tag,
int iCell,
int offset = 0) ->
int {
530 const auto& currentCell{currentCellSeed[iCell]};
531 const int cellTopologyId = currentCellTopologyId.empty() ? defaultCellTopologyId : currentCellTopologyId[iCell];
533 if constexpr (
decltype(Tag)
::value != PassMode::TwoPassInsert::value) {
534 if (currentCell.getLevel() != iLevel) {
537 if (currentCellId.empty()) {
539 const int clusterIndex = currentCell.getCluster(
layer);
540 if (clusterIndex != constants::UnusedIndex && mTimeFrame->isClusterUsed(
layer, clusterIndex)) {
547 const int cellId = currentCellId.empty() ? iCell : currentCellId[iCell];
548 if (cellTopologyId < 0 || mTimeFrame->getCellsNeighboursLUT()[cellTopologyId].empty()) {
551 const int startNeighbourId{cellId ? mTimeFrame->getCellsNeighboursLUT()[cellTopologyId][cellId - 1] : 0};
552 const int endNeighbourId{mTimeFrame->getCellsNeighboursLUT()[cellTopologyId][cellId]};
554 for (
int iNeighbourCell{startNeighbourId}; iNeighbourCell < endNeighbourId; ++iNeighbourCell) {
555 const int neighbourCellTopologyId = mTimeFrame->getCellsNeighboursTopology()[cellTopologyId][iNeighbourCell];
556 const int neighbourCellId = mTimeFrame->getCellsNeighbours()[cellTopologyId][iNeighbourCell];
557 const auto& neighbourCell = mTimeFrame->getCells()[neighbourCellTopologyId][neighbourCellId];
558 if (neighbourCell.getSecondTrackletIndex() != currentCell.getFirstTrackletIndex()) {
561 if (!currentCell.getTimeStamp().isCompatible(neighbourCell.getTimeStamp())) {
564 if (currentCell.getLevel() - 1 != neighbourCell.getLevel()) {
567 const int neighbourLayer = neighbourCell.getInnerLayer();
568 const int neighbourCluster = neighbourCell.getFirstClusterIndex();
569 if (mTimeFrame->isClusterUsed(neighbourLayer, neighbourCluster)) {
575 seed.getTimeStamp() = currentCell.getTimeStamp();
576 seed.getTimeStamp() += neighbourCell.getTimeStamp();
577 const auto& trHit = mTimeFrame->getTrackingFrameInfoOnLayer(neighbourLayer)[neighbourCluster];
579 if (!seed.rotate(trHit.alphaTrackingFrame)) {
587 if (mTrkParams[iteration].CorrType == o2::base::PropagatorF::MatCorrType::USEMatCorrNONE) {
588 if (!seed.correctForMaterial(mTrkParams[iteration].LayerxX0[neighbourLayer], mTrkParams[iteration].LayerxX0[neighbourLayer] * constants::Radl * constants::Rho,
true)) {
593 auto predChi2{seed.getPredictedChi2Quiet(trHit.positionTrackingFrame, trHit.covarianceTrackingFrame)};
594 if ((predChi2 > mTrkParams[iteration].MaxChi2ClusterAttachment) || predChi2 < 0.f) {
597 seed.setChi2(seed.getChi2() + predChi2);
598 if (!seed.o2::track::TrackParCov::update(trHit.positionTrackingFrame, trHit.covarianceTrackingFrame)) {
602 if constexpr (
decltype(Tag)
::value != PassMode::TwoPassCount::value) {
603 seed.getClusters()[neighbourLayer] = neighbourCluster;
604 auto mask = seed.getHitLayerMask();
605 mask.set(neighbourLayer);
606 seed.setHitLayerMask(
mask);
607 seed.setLevel(neighbourCell.getLevel());
608 seed.setFirstTrackletIndex(neighbourCell.getFirstTrackletIndex());
609 seed.setSecondTrackletIndex(neighbourCell.getSecondTrackletIndex());
612 if constexpr (
decltype(Tag)
::value == PassMode::OnePass::value) {
613 updatedCellSeeds.push_back(seed);
614 updatedCellsIds.push_back(neighbourCellId);
615 updatedCellsTopologyIds.push_back(neighbourCellTopologyId);
616 }
else if constexpr (
decltype(Tag)
::value == PassMode::TwoPassCount::value) {
618 }
else if constexpr (
decltype(Tag)
::value == PassMode::TwoPassInsert::value) {
619 updatedCellSeeds[
offset] = seed;
620 updatedCellsIds[
offset] = neighbourCellId;
621 updatedCellsTopologyIds[
offset++] = neighbourCellTopologyId;
623 static_assert(
false,
"Unknown mode!");
629 const int nCells =
static_cast<int>(currentCellSeed.size());
630 if (mTaskArena->max_concurrency() <= 1) {
631 for (
int iCell{0}; iCell < nCells; ++iCell) {
636 tbb::parallel_for(0, nCells, [&](
const int iCell) {
640 std::exclusive_scan(perCellCount.begin(), perCellCount.end(), perCellCount.begin(), 0);
641 auto totalNeighbours{perCellCount.back()};
642 if (totalNeighbours == 0) {
645 updatedCellSeeds.resize(totalNeighbours);
646 updatedCellsIds.resize(totalNeighbours);
647 updatedCellsTopologyIds.resize(totalNeighbours);
649 tbb::parallel_for(0, nCells, [&](
const int iCell) {
650 int offset = perCellCount[iCell];
651 if (
offset == perCellCount[iCell + 1]) {
664 firstClusters.resize(mTrkParams[iteration].NLayers);
667 const Cluster* unsortedClusters[NLayers]{};
668 for (
int iLayer = 0; iLayer < NLayers; ++iLayer) {
669 tfInfos[iLayer] = mTimeFrame->getTrackingFrameInfoOnLayer(iLayer).data();
670 unsortedClusters[iLayer] = mTimeFrame->getUnsortedClusters()[iLayer].data();
672 const auto topology = mTimeFrame->getTrackingTopologyView();
673 for (
int startLevel{mTrkParams[iteration].CellsPerRoad()}; startLevel >= mTrkParams[iteration].CellMinimumLevel(); --startLevel) {
675 auto seedFilter = [&](
const auto& seed) {
676 return seed.getHitLayerMask().isAllowed(mTrkParams[iteration].MaxHoles, mTrkParams[iteration].HoleLayerMask) &&
677 seed.getHitLayerMask().length() >= mTrkParams[iteration].MinTrackLength &&
678 seed.getQ2Pt() <= 1.e3 && seed.getChi2() <= mTrkParams[iteration].MaxChi2NDF * ((startLevel + 2) * 2 - 5);
682 for (
int startCellTopologyId{0}; startCellTopologyId < topology.nCells; ++startCellTopologyId) {
683 const int startLayer = topology.getCell(startCellTopologyId).hitLayerMask.last();
684 if (!(mTrkParams[iteration].StartLayerMask.has(startLayer)) || mTimeFrame->getCells()[startCellTopologyId].empty()) {
689 bounded_vector<int> lastCellTopologyId(mMemoryPool.get()), updatedCellTopologyId(mMemoryPool.get());
692 processNeighbours(iteration, startCellTopologyId, startLevel, mTimeFrame->getCells()[startCellTopologyId], lastCellId, lastCellTopologyId, updatedCellSeed, updatedCellId, updatedCellTopologyId);
694 int level = startLevel;
695 while (
level > 2 && !updatedCellSeed.empty()) {
696 lastCellSeed.swap(updatedCellSeed);
697 lastCellId.swap(updatedCellId);
698 lastCellTopologyId.swap(updatedCellTopologyId);
702 processNeighbours(iteration, constants::UnusedIndex, --
level, lastCellSeed, lastCellId, lastCellTopologyId, updatedCellSeed, updatedCellId, updatedCellTopologyId);
708 if (!updatedCellSeed.empty()) {
709 trackSeeds.reserve(trackSeeds.size() + std::count_if(updatedCellSeed.begin(), updatedCellSeed.end(), seedFilter));
710 std::copy_if(updatedCellSeed.begin(), updatedCellSeed.end(), std::back_inserter(trackSeeds), seedFilter);
714 if (trackSeeds.empty()) {
719 mTaskArena->execute([&] {
720 auto forSeed = [&](
auto Tag,
int iSeed,
int offset = 0) {
722 bool refitSuccess = track::refitTrack<NLayers>(trackSeeds[iSeed],
724 mTrkParams[iteration].MaxChi2ClusterAttachment,
725 mTrkParams[iteration].MaxChi2NDF,
729 mTrkParams[iteration].LayerxX0.data(),
730 mTrkParams[iteration].LayerRadii.data(),
731 mTrkParams[iteration].MinPt.data(),
733 mTrkParams[iteration].CorrType,
734 mTrkParams[iteration].ReseedIfShorter,
735 mTrkParams[iteration].ShiftRefToCluster,
736 mTrkParams[iteration].RepeatRefitOut);
739 if constexpr (
decltype(Tag)
::value == PassMode::OnePass::value) {
740 tracks.push_back(temporaryTrack);
741 }
else if constexpr (
decltype(Tag)
::value == PassMode::TwoPassCount::value) {
743 }
else if constexpr (
decltype(Tag)
::value == PassMode::TwoPassInsert::value) {
744 tracks[
offset] = temporaryTrack;
746 static_assert(
false,
"Unknown mode!");
753 const int nSeeds =
static_cast<int>(trackSeeds.size());
754 if (mTaskArena->max_concurrency() <= 1) {
755 for (
int iSeed{0}; iSeed < nSeeds; ++iSeed) {
761 tbb::parallel_for(0, nSeeds, [&](
const int iSeed) {
765 std::exclusive_scan(perSeedCount.begin(), perSeedCount.end(), perSeedCount.begin(), 0);
766 auto totalTracks{perSeedCount.back()};
767 if (totalTracks == 0) {
770 tracks.resize(totalTracks);
772 tbb::parallel_for(0, nSeeds, [&](
const int iSeed) {
773 if (perSeedCount[iSeed] == perSeedCount[iSeed + 1]) {
783 std::sort(tracks.begin(), tracks.end(), [](
const auto&
a,
const auto&
b) {
784 return track::isBetter(a, b);
787 acceptTracks(iteration, tracks, firstClusters);
789 markTracks(iteration);
795 auto& trks = mTimeFrame->getTracks();
796 trks.reserve(trks.size() + tracks.size());
797 const float smallestROFHalf = mTimeFrame->getROFOverlapTableView().getClockLayer().mROFLength * 0.5f;
798 for (
auto& track : tracks) {
800 bool isFirstShared{
false};
801 int firstLayer{-1}, firstCluster{-1};
802 for (
int iLayer{0}; iLayer < mTrkParams[iteration].NLayers; ++iLayer) {
803 if (track.getClusterIndex(iLayer) == constants::UnusedIndex) {
806 bool isShared = mTimeFrame->isClusterUsed(iLayer, track.getClusterIndex(iLayer));
807 nShared +=
int(isShared);
808 if (firstLayer < 0) {
809 firstCluster = track.getClusterIndex(iLayer);
810 isFirstShared = isShared && mTrkParams[iteration].AllowSharingFirstCluster && std::find(firstClusters[iLayer].begin(), firstClusters[iLayer].
end(), firstCluster) != firstClusters[iLayer].end();
816 if (nShared -
int(isFirstShared && mTrkParams[iteration].AllowSharingFirstCluster) > mTrkParams[iteration].SharedMaxClusters) {
820 bool firstCls{
true}, nominalCompatible{
true};
822 for (
int iLayer{0}; iLayer < mTrkParams[iteration].NLayers; ++iLayer) {
823 if (track.getClusterIndex(iLayer) == constants::UnusedIndex) {
826 mTimeFrame->markUsedCluster(iLayer, track.getClusterIndex(iLayer));
827 int currentROF = mTimeFrame->getClusterROF(iLayer, track.getClusterIndex(iLayer));
828 const auto nominalROFTS = mTimeFrame->getROFOverlapTableView().getLayer(iLayer).getROFTimeBounds(currentROF);
829 const auto expandedROFTS = mTimeFrame->getROFOverlapTableView().getLayer(iLayer).getROFTimeBounds(currentROF,
true);
832 nominalTS = nominalROFTS;
833 expandedTS = expandedROFTS;
835 if (nominalCompatible) {
836 if (nominalTS.isCompatible(nominalROFTS)) {
837 nominalTS += nominalROFTS;
839 nominalCompatible =
false;
842 if (!expandedTS.isCompatible(expandedROFTS)) {
843 LOGP(fatal,
"TS {}+/-{} are incompatible with {}+/-{}, this should not happen!", expandedROFTS.getTimeStamp(), expandedROFTS.getTimeStampError(), expandedTS.getTimeStamp(), expandedTS.getTimeStampError());
845 expandedTS += expandedROFTS;
848 track.getTimeStamp() = (nominalCompatible ? nominalTS : expandedTS).makeSymmetrical();
851 if (track.getTimeStamp().getTimeStampError() > smallestROFHalf) {
852 track.getTimeStamp().setTimeStampError(smallestROFHalf);
854 track.setUserField(0);
855 track.getParamOut().setUserField(0);
856 trks.emplace_back(track);
858 if (mTrkParams[iteration].AllowSharingFirstCluster) {
859 firstClusters[firstLayer].push_back(firstCluster);
867 if (mTrkParams[iteration].AllowSharingFirstCluster) {
869 auto& tracks = mTimeFrame->getTracks();
872 std::iota(fclusSort.begin(), fclusSort.end(), 0);
873 std::sort(fclusSort.begin(), fclusSort.end(), [&tracks](
int a,
int b) {
874 return tracks[a].getFirstLayerClusterIndex() < tracks[b].getFirstLayerClusterIndex();
878 const auto t1FirstLayer{
t1.getFirstClusterLayer()}, t2FirstLayer{t2.getFirstClusterLayer()};
879 if (t1FirstLayer != t2FirstLayer) {
882 if (mTimeFrame->getClusterROF(t1FirstLayer,
t1.getClusterIndex(t1FirstLayer)) != mTimeFrame->getClusterROF(t2FirstLayer, t2.getClusterIndex(t2FirstLayer))) {
885 if (!math_utils::isPhiDifferenceBelow(
t1.getPhi(), t2.getPhi(), mTrkParams[iteration].SharedClusterMaxDeltaPhi)) {
888 if (std::abs(
t1.getEta() - t2.getEta()) > mTrkParams[iteration].SharedClusterMaxDeltaEta) {
891 if (mTrkParams[iteration].SharedClusterOppositeSign &&
t1.getSign() == t2.getSign()) {
897 for (
int i{0}; i < static_cast<int>(fclusSort.size()); ++
i) {
898 auto& track = tracks[fclusSort[
i]];
899 for (
int j{
i + 1}; j < static_cast<int>(fclusSort.size()) && tracks[fclusSort[
j]].getFirstLayerClusterIndex() == track.getFirstLayerClusterIndex(); ++
j) {
900 auto& track2 = tracks[fclusSort[
j]];
901 if (areTracksSelected(track, track2)) {
902 track.setSharedClusters();
903 track2.setSharedClusters();