169 mTaskArena->execute([&] {
170 tbb::parallel_for(0, mTimeFrame->getNrof(1), [&](
const short pivotRofId) {
171 bool skip = skipROF(iteration, pivotRofId);
172 const auto& rofRange01 = mTimeFrame->getROFOverlapTableView().getOverlap(1, 0, pivotRofId);
173 for (auto targetRofId = rofRange01.getFirstEntry(); targetRofId < rofRange01.getEntriesBound(); ++targetRofId) {
174 const auto timeErr = mTimeFrame->getROFOverlapTableView().getTimeStamp(0, targetRofId, 1, pivotRofId);
175 trackleterKernelHost<TrackletMode::Layer0Layer1, true>(
176 !skip ? mTimeFrame->getClustersOnLayer(targetRofId, 0) : gsl::span<Cluster>(),
177 !skip ? mTimeFrame->getClustersOnLayer(pivotRofId, 1) : gsl::span<Cluster>(),
178 mTimeFrame->getUsedClustersROF(targetRofId, 0),
179 mTimeFrame->getIndexTable(targetRofId, 0).data(),
180 mVrtParams[iteration].phiCut,
181 mTimeFrame->getTracklets()[0],
182 mTimeFrame->getNTrackletsCluster(pivotRofId, 0),
188 mVrtParams[iteration].maxTrackletsPerCluster);
190 const auto& rofRange12 = mTimeFrame->getROFOverlapTableView().getOverlap(1, 2, pivotRofId);
191 for (
auto targetRofId = rofRange12.getFirstEntry(); targetRofId < rofRange12.getEntriesBound(); ++targetRofId) {
192 const auto timeErr = mTimeFrame->getROFOverlapTableView().getTimeStamp(2, targetRofId, 1, pivotRofId);
193 trackleterKernelHost<TrackletMode::Layer1Layer2, true>(
194 !skip ? mTimeFrame->getClustersOnLayer(targetRofId, 2) : gsl::span<Cluster>(),
195 !skip ? mTimeFrame->getClustersOnLayer(pivotRofId, 1) : gsl::span<Cluster>(),
196 mTimeFrame->getUsedClustersROF(targetRofId, 2),
197 mTimeFrame->getIndexTable(targetRofId, 2).data(),
198 mVrtParams[iteration].phiCut,
199 mTimeFrame->getTracklets()[1],
200 mTimeFrame->getNTrackletsCluster(pivotRofId, 1),
206 mVrtParams[iteration].maxTrackletsPerCluster);
208 mTimeFrame->getNTrackletsROF(pivotRofId, 0) = std::accumulate(mTimeFrame->getNTrackletsCluster(pivotRofId, 0).begin(), mTimeFrame->getNTrackletsCluster(pivotRofId, 0).end(), 0);
209 mTimeFrame->getNTrackletsROF(pivotRofId, 1) = std::accumulate(mTimeFrame->getNTrackletsCluster(pivotRofId, 1).begin(), mTimeFrame->getNTrackletsCluster(pivotRofId, 1).end(), 0);
212 mTimeFrame->computeTrackletsPerROFScans();
213 if (
auto tot0 = mTimeFrame->getTotalTrackletsTF(0), tot1 = mTimeFrame->getTotalTrackletsTF(1);
214 tot0 == 0 || tot1 == 0) {
217 mTimeFrame->getTracklets()[0].resize(tot0);
218 mTimeFrame->getTracklets()[1].resize(tot1);
221 tbb::parallel_for(0, mTimeFrame->getNrof(1), [&](
const short pivotRofId) {
222 bool skip = skipROF(iteration, pivotRofId);
223 const int globalOffsetPivot = mTimeFrame->getSortedStartIndex(pivotRofId, 1);
224 const auto& rofRange01 = mTimeFrame->getROFOverlapTableView().getOverlap(1, 0, pivotRofId);
225 for (auto targetRofId = rofRange01.getFirstEntry(); targetRofId < rofRange01.getEntriesBound(); ++targetRofId) {
226 const auto timeErr = mTimeFrame->getROFOverlapTableView().getTimeStamp(0, targetRofId, 1, pivotRofId);
227 trackleterKernelHost<TrackletMode::Layer0Layer1, false>(
228 !skip ? mTimeFrame->getClustersOnLayer(targetRofId, 0) : gsl::span<Cluster>(),
229 !skip ? mTimeFrame->getClustersOnLayer(pivotRofId, 1) : gsl::span<Cluster>(),
230 mTimeFrame->getUsedClustersROF(targetRofId, 0),
231 mTimeFrame->getIndexTable(targetRofId, 0).data(),
232 mVrtParams[iteration].phiCut,
233 mTimeFrame->getTracklets()[0],
234 mTimeFrame->getNTrackletsCluster(pivotRofId, 0),
237 mTimeFrame->getExclusiveNTrackletsCluster(pivotRofId, 0),
238 mTimeFrame->getSortedStartIndex(targetRofId, 0),
240 mVrtParams[iteration].maxTrackletsPerCluster);
242 const auto& rofRange12 = mTimeFrame->getROFOverlapTableView().getOverlap(1, 2, pivotRofId);
243 for (
auto targetRofId = rofRange12.getFirstEntry(); targetRofId < rofRange12.getEntriesBound(); ++targetRofId) {
244 const auto timeErr = mTimeFrame->getROFOverlapTableView().getTimeStamp(2, targetRofId, 1, pivotRofId);
245 trackleterKernelHost<TrackletMode::Layer1Layer2, false>(
246 !skip ? mTimeFrame->getClustersOnLayer(targetRofId, 2) : gsl::span<Cluster>(),
247 !skip ? mTimeFrame->getClustersOnLayer(pivotRofId, 1) : gsl::span<Cluster>(),
248 mTimeFrame->getUsedClustersROF(targetRofId, 2),
249 mTimeFrame->getIndexTable(targetRofId, 2).data(),
250 mVrtParams[iteration].phiCut,
251 mTimeFrame->getTracklets()[1],
252 mTimeFrame->getNTrackletsCluster(pivotRofId, 1),
255 mTimeFrame->getExclusiveNTrackletsCluster(pivotRofId, 1),
256 mTimeFrame->getSortedStartIndex(targetRofId, 2),
258 mVrtParams[iteration].maxTrackletsPerCluster);
264 if (mTimeFrame->hasMCinformation()) {
265 for (
const auto& trk : mTimeFrame->getTracklets()[0]) {
267 if (!trk.isEmpty()) {
268 int sortedId0{trk.firstClusterIndex};
269 int sortedId1{trk.secondClusterIndex};
270 for (
const auto& lab0 : mTimeFrame->getClusterLabels(0, mTimeFrame->
getClusters()[0][sortedId0].clusterId)) {
271 for (
const auto& lab1 : mTimeFrame->getClusterLabels(1, mTimeFrame->
getClusters()[1][sortedId1].clusterId)) {
272 if (lab0 == lab1 && lab0.isValid()) {
277 if (
label.isValid()) {
282 mTimeFrame->getTrackletsLabel(0).emplace_back(
label);
290 mTaskArena->execute([&] {
291 tbb::combinable<int> totalLines{0};
293 tbb::blocked_range<short>(0, (
short)mTimeFrame->getNrof(1)),
294 [&](
const tbb::blocked_range<short>& Rofs) {
295 for (short pivotRofId = Rofs.begin(); pivotRofId < Rofs.end(); ++pivotRofId) {
296 if (mTimeFrame->getFoundTracklets(pivotRofId, 0).empty() || skipROF(iteration, pivotRofId)) {
299 mTimeFrame->getLines(pivotRofId).reserve(mTimeFrame->getNTrackletsCluster(pivotRofId, 0).size());
300 bounded_vector<bool> usedTracklets(mTimeFrame->getFoundTracklets(pivotRofId, 0).size(), false, mMemoryPool.get());
301 trackletSelectionKernelHost(
302 mTimeFrame->getClusters()[0].data(),
303 mTimeFrame->getClusters()[1].data(),
304 mTimeFrame->getUsedClusters(0),
305 mTimeFrame->getUsedClusters(2),
306 mTimeFrame->getFoundTracklets(pivotRofId, 0),
307 mTimeFrame->getFoundTracklets(pivotRofId, 1),
309 mTimeFrame->getNTrackletsCluster(pivotRofId, 0),
310 mTimeFrame->getNTrackletsCluster(pivotRofId, 1),
311 mTimeFrame->getLines(pivotRofId),
312 mTimeFrame->getLabelsFoundTracklets(pivotRofId, 0),
313 mTimeFrame->getLinesLabel(pivotRofId),
314 static_cast<int>(mTimeFrame->getClustersOnLayer(pivotRofId, 1).size()),
315 mVrtParams[iteration].tanLambdaCut,
316 mVrtParams[iteration].phiCut);
317 totalLines.local() += mTimeFrame->getLines(pivotRofId).size();
320 mTimeFrame->setNLinesTotal(totalLines.combine(std::plus<int>()));
330 const int nRofs = mTimeFrame->getNrof(1);
331 std::vector<std::vector<Vertex>> rofVertices(nRofs);
332 std::vector<std::vector<VertexLabel>> rofLabels(nRofs);
333 const float pairCut2 = mVrtParams[iteration].pairCut * mVrtParams[iteration].pairCut;
334 const float duplicateZCut = mVrtParams[iteration].duplicateZCut > 0.f ? mVrtParams[iteration].duplicateZCut : std::max(4.f * mVrtParams[iteration].pairCut, 0.5f * mVrtParams[iteration].clusterCut);
335 const float duplicateDistance2Cut = mVrtParams[iteration].duplicateDistance2Cut > 0.f ? mVrtParams[iteration].duplicateDistance2Cut : std::max(16.f * pairCut2, 0.0625f * mVrtParams[iteration].clusterCut * mVrtParams[iteration].clusterCut);
337 settings.
beamX = mTimeFrame->getBeamX();
338 settings.
beamY = mTimeFrame->getBeamY();
339 settings.
pairCut = mVrtParams[iteration].pairCut;
341 settings.
clusterCut = mVrtParams[iteration].clusterCut;
342 settings.
coarseZWindow = mVrtParams[iteration].coarseZWindow;
343 settings.
seedDedupZCut = mVrtParams[iteration].seedDedupZCut;
348 settings.
maxZ = mVrtParams[iteration].maxZPositionAllowed;
353 const auto processROF = [&](
const int rofId) {
354 if (skipROF(iteration, rofId)) {
357 auto& lines = mTimeFrame->getLines(rofId);
358 auto clusters = line_vertexer::buildClusters(std::span<const Line>{lines.data(), lines.size()}, settings);
360 auto clusterBeamDistance2 = [&](
const ClusterLines& cluster) {
361 return (mTimeFrame->getBeamX() - cluster.getVertex()[0]) * (mTimeFrame->getBeamX() - cluster.getVertex()[0]) +
362 (mTimeFrame->getBeamY() - cluster.getVertex()[1]) * (mTimeFrame->getBeamY() - cluster.getVertex()[1]);
365 if (lhs.getSize() != rhs.getSize()) {
366 return lhs.getSize() > rhs.getSize();
368 if (o2::gpu::GPUCommonMath::Abs(lhs.getAvgDistance2() - rhs.getAvgDistance2()) > constants::Tolerance) {
369 return lhs.getAvgDistance2() < rhs.getAvgDistance2();
371 const auto lhsBeam = clusterBeamDistance2(lhs);
372 const auto rhsBeam = clusterBeamDistance2(rhs);
373 if (o2::gpu::GPUCommonMath::Abs(lhsBeam - rhsBeam) > constants::Tolerance) {
374 return lhsBeam < rhsBeam;
376 return lhs.getVertex()[2] < rhs.getVertex()[2];
381 float minClusterZ = std::numeric_limits<float>::max();
382 for (
const auto& cluster :
clusters) {
383 minClusterZ = std::min(minClusterZ, cluster.getVertex()[2]);
386 deduplicated.reserve(
clusters.size());
387 std::unordered_map<int, std::vector<int>> keptByZBin;
389 bool duplicate =
false;
390 const auto candidateZ = candidate.getVertex()[2];
391 const auto zBin =
static_cast<int>(std::floor((candidateZ - minClusterZ) / settings.
duplicateZCut));
392 for (
int neighborBin = zBin - 1; neighborBin <= zBin + 1 && !duplicate; ++neighborBin) {
393 const auto found = keptByZBin.find(neighborBin);
394 if (found == keptByZBin.end()) {
397 for (
const auto ownerId : found->second) {
398 const auto& owner = deduplicated[ownerId];
399 if (!candidate.getTimeStamp().isCompatible(owner.getTimeStamp())) {
402 if (o2::gpu::GPUCommonMath::Abs(candidate.getVertex()[2] - owner.getVertex()[2]) >= settings.
duplicateZCut) {
405 const auto dx = candidate.getVertex()[0] - owner.getVertex()[0];
406 const auto dy = candidate.getVertex()[1] - owner.getVertex()[1];
407 const auto dz = candidate.getVertex()[2] - owner.getVertex()[2];
408 const auto distance2 = math_utils::SqSum(dx, dy, dz);
419 const auto ownerId =
static_cast<int>(deduplicated.size());
420 keptByZBin[zBin].push_back(ownerId);
421 deduplicated.push_back(std::move(candidate));
428 std::vector<int> candidateIndices;
430 for (
int iCluster{0}; iCluster <
nClusters; ++iCluster) {
431 const bool zCompatible = o2::gpu::GPUCommonMath::Abs(
clusters[iCluster].getVertex()[2]) < mVrtParams[iteration].maxZPositionAllowed;
434 candidateIndices.push_back(iCluster);
438 if (candidateIndices.empty()) {
444 auto lhsIt = lhs.getLabels().begin();
445 auto rhsIt = rhs.getLabels().begin();
446 while (lhsIt != lhs.getLabels().end() && rhsIt != rhs.getLabels().end()) {
447 if (*lhsIt == *rhsIt) {
451 }
else if (*lhsIt < *rhsIt) {
460 float minCandidateZ = std::numeric_limits<float>::max();
461 for (
const auto clusterId : candidateIndices) {
462 minCandidateZ = std::min(minCandidateZ,
clusters[clusterId].getVertex()[2]);
464 std::unordered_map<int, std::vector<int>> selectedByZBin;
465 std::vector<int> selectedIndices;
466 selectedIndices.reserve(candidateIndices.size());
467 for (
const auto clusterId : candidateIndices) {
468 const auto& candidate =
clusters[clusterId];
469 const auto candidateZ = candidate.getVertex()[2];
470 const auto zBin =
static_cast<int>((candidateZ - minCandidateZ) / settings.
finalSelectionZCut);
471 bool suppressed =
false;
472 for (
int neighborBin = zBin - 1; neighborBin <= zBin + 1 && !suppressed; ++neighborBin) {
473 const auto found = selectedByZBin.find(neighborBin);
474 if (found == selectedByZBin.end()) {
477 for (
const auto selectedId : found->second) {
478 const auto& selected =
clusters[selectedId];
479 if (!candidate.getTimeStamp().isCompatible(selected.getTimeStamp())) {
482 const auto zDelta = o2::gpu::GPUCommonMath::Abs(candidateZ - selected.getVertex()[2]);
483 const auto sharedLabels = countSharedLabels(candidate, selected);
484 const auto minSize = std::min(candidate.getSize(), selected.getSize());
485 const bool overlapDuplicate = sharedLabels > 0 && sharedLabels * 4 >=
minSize;
487 const bool clearlyBetterMultiplicity = selected.getSize() >= candidate.getSize() + 3;
488 const bool clearlyBetterQuality = selected.getSize() > candidate.getSize() &&
489 selected.getAvgDistance2() + constants::Tolerance < 0.8f * candidate.getAvgDistance2();
490 const bool weakCandidate = clearlyBetterMultiplicity || clearlyBetterQuality;
491 if (overlapDuplicate || (strongZDuplicate && weakCandidate)) {
500 selectedByZBin[zBin].push_back(clusterId);
501 selectedIndices.push_back(clusterId);
505 std::vector<int> sortedIndices(selectedIndices.size());
506 std::iota(sortedIndices.begin(), sortedIndices.end(), 0);
507 std::sort(sortedIndices.begin(), sortedIndices.end(), [&selectedIndices, &
clusters](
int i,
int j) {
508 return clusters[selectedIndices[i]].getSize() > clusters[selectedIndices[j]].getSize();
510 for (
const auto sortedId : sortedIndices) {
511 const auto& cluster =
clusters[selectedIndices[sortedId]];
512 const auto beamDistance2 = clusterBeamDistance2(cluster);
513 if (!(beamDistance2 < mVrtParams[iteration].NSigmaCut)) {
516 if (cluster.getSize() < mVrtParams[iteration].clusterContributorsCut) {
519 if (!rofVertices[rofId].
empty() && cluster.getSize() < mVrtParams[iteration].suppressLowMultDebris) {
525 (ushort)cluster.getSize(),
526 cluster.getAvgDistance2()};
528 vertex.setFlags(Vertex::UPCMode);
530 vertex.setTimeStamp(cluster.getTimeStamp());
531 rofVertices[rofId].push_back(
vertex);
532 if (mTimeFrame->hasMCinformation()) {
533 auto& lineLabels = mTimeFrame->getLinesLabel(rofId);
535 for (
auto&
index : cluster.getLabels()) {
538 const auto mainLabel = computeMain(
labels);
539 rofLabels[rofId].push_back(mainLabel);
544 if (mTaskArena->max_concurrency() <= 1) {
545 for (
int rofId{0}; rofId < nRofs; ++rofId) {
549 mTaskArena->execute([&] {
550 tbb::parallel_for(0, nRofs, [&](
const int rofId) {
556 for (
int rofId{0}; rofId < nRofs; ++rofId) {
557 for (
auto&
vertex : rofVertices[rofId]) {
558 mTimeFrame->addPrimaryVertex(
vertex);
560 if (mTimeFrame->hasMCinformation()) {
561 for (
auto&
label : rofLabels[rofId]) {
562 mTimeFrame->addPrimaryVertexLabel(
label);