180 mTaskArena->execute([&] {
181 tbb::parallel_for(0, mTimeFrame->getNrof(1), [&](
const short pivotRofId) {
182 bool skip = skipROF(iteration, pivotRofId);
183 const auto& rofRange01 = mTimeFrame->getROFOverlapTableView().getOverlap(1, 0, pivotRofId);
184 for (auto targetRofId = rofRange01.getFirstEntry(); targetRofId < rofRange01.getEntriesBound(); ++targetRofId) {
185 const auto timeErr = mTimeFrame->getROFOverlapTableView().getTimeStamp(0, targetRofId, 1, pivotRofId);
186 trackleterKernelHost<TrackletMode::Layer0Layer1, true>(
187 !skip ? mTimeFrame->getClustersOnLayer(targetRofId, 0) : gsl::span<Cluster>(),
188 !skip ? mTimeFrame->getClustersOnLayer(pivotRofId, 1) : gsl::span<Cluster>(),
189 mTimeFrame->getUsedClustersROF(targetRofId, 0),
190 mTimeFrame->getIndexTable(targetRofId, 0).data(),
191 mVrtParams[iteration].phiCut,
192 mTimeFrame->getTracklets()[0],
193 mTimeFrame->getNTrackletsCluster(pivotRofId, 0),
199 mVrtParams[iteration].maxTrackletsPerCluster);
201 const auto& rofRange12 = mTimeFrame->getROFOverlapTableView().getOverlap(1, 2, pivotRofId);
202 for (
auto targetRofId = rofRange12.getFirstEntry(); targetRofId < rofRange12.getEntriesBound(); ++targetRofId) {
203 const auto timeErr = mTimeFrame->getROFOverlapTableView().getTimeStamp(2, targetRofId, 1, pivotRofId);
204 trackleterKernelHost<TrackletMode::Layer1Layer2, true>(
205 !skip ? mTimeFrame->getClustersOnLayer(targetRofId, 2) : gsl::span<Cluster>(),
206 !skip ? mTimeFrame->getClustersOnLayer(pivotRofId, 1) : gsl::span<Cluster>(),
207 mTimeFrame->getUsedClustersROF(targetRofId, 2),
208 mTimeFrame->getIndexTable(targetRofId, 2).data(),
209 mVrtParams[iteration].phiCut,
210 mTimeFrame->getTracklets()[1],
211 mTimeFrame->getNTrackletsCluster(pivotRofId, 1),
217 mVrtParams[iteration].maxTrackletsPerCluster);
219 mTimeFrame->getNTrackletsROF(pivotRofId, 0) = std::accumulate(mTimeFrame->getNTrackletsCluster(pivotRofId, 0).begin(), mTimeFrame->getNTrackletsCluster(pivotRofId, 0).end(), 0);
220 mTimeFrame->getNTrackletsROF(pivotRofId, 1) = std::accumulate(mTimeFrame->getNTrackletsCluster(pivotRofId, 1).begin(), mTimeFrame->getNTrackletsCluster(pivotRofId, 1).end(), 0);
223 mTimeFrame->computeTrackletsPerROFScans();
224 if (
auto tot0 = mTimeFrame->getTotalTrackletsTF(0), tot1 = mTimeFrame->getTotalTrackletsTF(1);
225 tot0 == 0 || tot1 == 0) {
228 mTimeFrame->getTracklets()[0].resize(tot0);
229 mTimeFrame->getTracklets()[1].resize(tot1);
232 tbb::parallel_for(0, mTimeFrame->getNrof(1), [&](
const short pivotRofId) {
233 bool skip = skipROF(iteration, pivotRofId);
234 const int globalOffsetPivot = mTimeFrame->getSortedStartIndex(pivotRofId, 1);
235 const auto& rofRange01 = mTimeFrame->getROFOverlapTableView().getOverlap(1, 0, pivotRofId);
236 for (auto targetRofId = rofRange01.getFirstEntry(); targetRofId < rofRange01.getEntriesBound(); ++targetRofId) {
237 const auto timeErr = mTimeFrame->getROFOverlapTableView().getTimeStamp(0, targetRofId, 1, pivotRofId);
238 trackleterKernelHost<TrackletMode::Layer0Layer1, false>(
239 !skip ? mTimeFrame->getClustersOnLayer(targetRofId, 0) : gsl::span<Cluster>(),
240 !skip ? mTimeFrame->getClustersOnLayer(pivotRofId, 1) : gsl::span<Cluster>(),
241 mTimeFrame->getUsedClustersROF(targetRofId, 0),
242 mTimeFrame->getIndexTable(targetRofId, 0).data(),
243 mVrtParams[iteration].phiCut,
244 mTimeFrame->getTracklets()[0],
245 mTimeFrame->getNTrackletsCluster(pivotRofId, 0),
248 mTimeFrame->getExclusiveNTrackletsCluster(pivotRofId, 0),
249 mTimeFrame->getSortedStartIndex(targetRofId, 0),
251 mVrtParams[iteration].maxTrackletsPerCluster);
253 const auto& rofRange12 = mTimeFrame->getROFOverlapTableView().getOverlap(1, 2, pivotRofId);
254 for (
auto targetRofId = rofRange12.getFirstEntry(); targetRofId < rofRange12.getEntriesBound(); ++targetRofId) {
255 const auto timeErr = mTimeFrame->getROFOverlapTableView().getTimeStamp(2, targetRofId, 1, pivotRofId);
256 trackleterKernelHost<TrackletMode::Layer1Layer2, false>(
257 !skip ? mTimeFrame->getClustersOnLayer(targetRofId, 2) : gsl::span<Cluster>(),
258 !skip ? mTimeFrame->getClustersOnLayer(pivotRofId, 1) : gsl::span<Cluster>(),
259 mTimeFrame->getUsedClustersROF(targetRofId, 2),
260 mTimeFrame->getIndexTable(targetRofId, 2).data(),
261 mVrtParams[iteration].phiCut,
262 mTimeFrame->getTracklets()[1],
263 mTimeFrame->getNTrackletsCluster(pivotRofId, 1),
266 mTimeFrame->getExclusiveNTrackletsCluster(pivotRofId, 1),
267 mTimeFrame->getSortedStartIndex(targetRofId, 2),
269 mVrtParams[iteration].maxTrackletsPerCluster);
275 if (mTimeFrame->hasMCinformation()) {
276 for (
const auto& trk : mTimeFrame->getTracklets()[0]) {
278 int sortedId0{trk.firstClusterIndex};
279 int sortedId1{trk.secondClusterIndex};
280 for (
const auto& lab0 : mTimeFrame->getClusterLabels(0, mTimeFrame->
getClusters()[0][sortedId0].clusterId)) {
281 for (
const auto& lab1 : mTimeFrame->getClusterLabels(1, mTimeFrame->
getClusters()[1][sortedId1].clusterId)) {
282 if (lab0 == lab1 && lab0.isValid()) {
287 if (
label.isValid()) {
291 mTimeFrame->getTrackletsLabel(0).emplace_back(
label);
299 mTaskArena->execute([&] {
300 tbb::combinable<int> totalLines{0};
302 tbb::blocked_range<short>(0, (
short)mTimeFrame->getNrof(1)),
303 [&](
const tbb::blocked_range<short>& Rofs) {
304 for (short pivotRofId = Rofs.begin(); pivotRofId < Rofs.end(); ++pivotRofId) {
305 if (mTimeFrame->getFoundTracklets(pivotRofId, 0).empty() || skipROF(iteration, pivotRofId)) {
308 mTimeFrame->getLines(pivotRofId).reserve(std::min(mTimeFrame->getFoundTracklets(pivotRofId, 0).size(), mTimeFrame->getNTrackletsCluster(pivotRofId, 0).size() * constants::MaxSelectedTrackletsPerCluster));
309 bounded_vector<uint8_t> usedTracklets(mTimeFrame->getFoundTracklets(pivotRofId, 0).size(), 0, mMemoryPool.get());
310 trackletSelectionKernelHost(
311 mTimeFrame->getClusters()[0].data(),
312 mTimeFrame->getClusters()[1].data(),
313 mTimeFrame->getUsedClusters(0),
314 mTimeFrame->getUsedClusters(2),
315 mTimeFrame->getFoundTracklets(pivotRofId, 0),
316 mTimeFrame->getFoundTracklets(pivotRofId, 1),
318 mTimeFrame->getNTrackletsCluster(pivotRofId, 0),
319 mTimeFrame->getNTrackletsCluster(pivotRofId, 1),
320 mTimeFrame->getLines(pivotRofId),
321 mTimeFrame->getLabelsFoundTracklets(pivotRofId, 0),
322 mTimeFrame->getLinesLabel(pivotRofId),
323 static_cast<int>(mTimeFrame->getClustersOnLayer(pivotRofId, 1).size()),
324 mVrtParams[iteration].tanLambdaCut,
325 mVrtParams[iteration].phiCut,
326 constants::MaxSelectedTrackletsPerCluster);
327 totalLines.local() += mTimeFrame->getLines(pivotRofId).size();
330 mTimeFrame->setNLinesTotal(totalLines.combine(std::plus<int>()));
340 const int nRofs = mTimeFrame->getNrof(1);
341 std::vector<std::vector<Vertex>> rofVertices(nRofs);
342 std::vector<std::vector<VertexLabel>> rofLabels(nRofs);
343 const float pairCut2 = mVrtParams[iteration].pairCut * mVrtParams[iteration].pairCut;
344 const float duplicateZCut = mVrtParams[iteration].duplicateZCut > 0.f ? mVrtParams[iteration].duplicateZCut : std::max(4.f * mVrtParams[iteration].pairCut, 0.5f * mVrtParams[iteration].clusterCut);
345 const float duplicateDistance2Cut = mVrtParams[iteration].duplicateDistance2Cut > 0.f ? mVrtParams[iteration].duplicateDistance2Cut : std::max(16.f * pairCut2, 0.0625f * mVrtParams[iteration].clusterCut * mVrtParams[iteration].clusterCut);
347 settings.
beamX = mTimeFrame->getBeamX();
348 settings.
beamY = mTimeFrame->getBeamY();
349 settings.
pairCut = mVrtParams[iteration].pairCut;
351 settings.
clusterCut = mVrtParams[iteration].clusterCut;
352 settings.
coarseZWindow = mVrtParams[iteration].coarseZWindow;
353 settings.
seedDedupZCut = mVrtParams[iteration].seedDedupZCut;
358 settings.
maxZ = mVrtParams[iteration].maxZPositionAllowed;
363 const auto processROF = [&](
const int rofId) {
364 if (skipROF(iteration, rofId)) {
367 auto& lines = mTimeFrame->getLines(rofId);
368 auto clusters = line_vertexer::buildClusters(std::span<const Line>{lines.data(), lines.size()}, settings);
370 auto clusterBeamDistance2 = [&](
const ClusterLines& cluster) {
371 return (mTimeFrame->getBeamX() - cluster.getVertex()[0]) * (mTimeFrame->getBeamX() - cluster.getVertex()[0]) +
372 (mTimeFrame->getBeamY() - cluster.getVertex()[1]) * (mTimeFrame->getBeamY() - cluster.getVertex()[1]);
375 if (lhs.getSize() != rhs.getSize()) {
376 return lhs.getSize() > rhs.getSize();
378 if (o2::gpu::GPUCommonMath::Abs(lhs.getAvgDistance2() - rhs.getAvgDistance2()) > constants::Tolerance) {
379 return lhs.getAvgDistance2() < rhs.getAvgDistance2();
381 const auto lhsBeam = clusterBeamDistance2(lhs);
382 const auto rhsBeam = clusterBeamDistance2(rhs);
383 if (o2::gpu::GPUCommonMath::Abs(lhsBeam - rhsBeam) > constants::Tolerance) {
384 return lhsBeam < rhsBeam;
386 return lhs.getVertex()[2] < rhs.getVertex()[2];
391 float minClusterZ = std::numeric_limits<float>::max();
392 for (
const auto& cluster :
clusters) {
393 minClusterZ = std::min(minClusterZ, cluster.getVertex()[2]);
396 deduplicated.reserve(
clusters.size());
397 std::unordered_map<int, std::vector<int>> keptByZBin;
399 bool duplicate =
false;
400 const auto candidateZ = candidate.getVertex()[2];
401 const auto zBin =
static_cast<int>(std::floor((candidateZ - minClusterZ) / settings.
duplicateZCut));
402 for (
int neighborBin = zBin - 1; neighborBin <= zBin + 1 && !duplicate; ++neighborBin) {
403 const auto found = keptByZBin.find(neighborBin);
404 if (found == keptByZBin.end()) {
407 for (
const auto ownerId : found->second) {
408 const auto& owner = deduplicated[ownerId];
409 if (!candidate.getTimeStamp().isCompatible(owner.getTimeStamp())) {
412 if (o2::gpu::GPUCommonMath::Abs(candidate.getVertex()[2] - owner.getVertex()[2]) >= settings.
duplicateZCut) {
415 const auto dx = candidate.getVertex()[0] - owner.getVertex()[0];
416 const auto dy = candidate.getVertex()[1] - owner.getVertex()[1];
417 const auto dz = candidate.getVertex()[2] - owner.getVertex()[2];
418 const auto distance2 = math_utils::SqSum(dx, dy, dz);
429 const auto ownerId =
static_cast<int>(deduplicated.size());
430 keptByZBin[zBin].push_back(ownerId);
431 deduplicated.push_back(std::move(candidate));
438 std::vector<int> candidateIndices;
440 for (
int iCluster{0}; iCluster <
nClusters; ++iCluster) {
441 const bool zCompatible = o2::gpu::GPUCommonMath::Abs(
clusters[iCluster].getVertex()[2]) < mVrtParams[iteration].maxZPositionAllowed;
444 candidateIndices.push_back(iCluster);
448 if (candidateIndices.empty()) {
454 auto lhsIt = lhs.getLabels().begin();
455 auto rhsIt = rhs.getLabels().begin();
456 while (lhsIt != lhs.getLabels().end() && rhsIt != rhs.getLabels().end()) {
457 if (*lhsIt == *rhsIt) {
461 }
else if (*lhsIt < *rhsIt) {
470 float minCandidateZ = std::numeric_limits<float>::max();
471 for (
const auto clusterId : candidateIndices) {
472 minCandidateZ = std::min(minCandidateZ,
clusters[clusterId].getVertex()[2]);
474 std::unordered_map<int, std::vector<int>> selectedByZBin;
475 std::vector<int> selectedIndices;
476 selectedIndices.reserve(candidateIndices.size());
477 for (
const auto clusterId : candidateIndices) {
478 const auto& candidate =
clusters[clusterId];
479 const auto candidateZ = candidate.getVertex()[2];
480 const auto zBin =
static_cast<int>((candidateZ - minCandidateZ) / settings.
finalSelectionZCut);
481 bool suppressed =
false;
482 for (
int neighborBin = zBin - 1; neighborBin <= zBin + 1 && !suppressed; ++neighborBin) {
483 const auto found = selectedByZBin.find(neighborBin);
484 if (found == selectedByZBin.end()) {
487 for (
const auto selectedId : found->second) {
488 const auto& selected =
clusters[selectedId];
489 if (!candidate.getTimeStamp().isCompatible(selected.getTimeStamp())) {
492 const auto zDelta = o2::gpu::GPUCommonMath::Abs(candidateZ - selected.getVertex()[2]);
493 const auto sharedLabels = countSharedLabels(candidate, selected);
494 const auto minSize = std::min(candidate.getSize(), selected.getSize());
495 const bool overlapDuplicate = sharedLabels > 0 && sharedLabels * 4 >=
minSize;
497 const bool clearlyBetterMultiplicity = selected.getSize() >= candidate.getSize() + 3;
498 const bool clearlyBetterQuality = selected.getSize() > candidate.getSize() &&
499 selected.getAvgDistance2() + constants::Tolerance < 0.8f * candidate.getAvgDistance2();
500 const bool weakCandidate = clearlyBetterMultiplicity || clearlyBetterQuality;
501 if (overlapDuplicate || (strongZDuplicate && weakCandidate)) {
510 selectedByZBin[zBin].push_back(clusterId);
511 selectedIndices.push_back(clusterId);
515 std::vector<int> sortedIndices(selectedIndices.size());
516 std::iota(sortedIndices.begin(), sortedIndices.end(), 0);
517 std::sort(sortedIndices.begin(), sortedIndices.end(), [&selectedIndices, &
clusters](
int i,
int j) {
518 return clusters[selectedIndices[i]].getSize() > clusters[selectedIndices[j]].getSize();
520 for (
const auto sortedId : sortedIndices) {
521 const auto& cluster =
clusters[selectedIndices[sortedId]];
522 const auto beamDistance2 = clusterBeamDistance2(cluster);
523 if (!(beamDistance2 < mVrtParams[iteration].NSigmaCut)) {
526 if (cluster.getSize() < mVrtParams[iteration].clusterContributorsCut) {
529 if (!rofVertices[rofId].
empty() && cluster.getSize() < mVrtParams[iteration].suppressLowMultDebris) {
535 (ushort)cluster.getSize(),
536 cluster.getAvgDistance2()};
537 if (mVrtParams[iteration].PassFlags[IterationStep::MarkVerticesAsUPC]) {
538 vertex.setFlags(Vertex::UPCMode);
540 vertex.setTimeStamp(cluster.getTimeStamp());
541 rofVertices[rofId].push_back(
vertex);
542 if (mTimeFrame->hasMCinformation()) {
543 auto& lineLabels = mTimeFrame->getLinesLabel(rofId);
545 for (
auto&
index : cluster.getLabels()) {
548 const auto mainLabel = computeMain(
labels);
549 rofLabels[rofId].push_back(mainLabel);
554 if (mTaskArena->max_concurrency() <= 1) {
555 for (
int rofId{0}; rofId < nRofs; ++rofId) {
559 mTaskArena->execute([&] {
560 tbb::parallel_for(0, nRofs, [&](
const int rofId) {
566 for (
int rofId{0}; rofId < nRofs; ++rofId) {
567 for (
auto&
vertex : rofVertices[rofId]) {
568 mTimeFrame->addPrimaryVertex(
vertex);
570 if (mTimeFrame->hasMCinformation()) {
571 for (
auto&
label : rofLabels[rofId]) {
572 mTimeFrame->addPrimaryVertexLabel(
label);