182 mTaskArena->execute([&] {
183 tbb::parallel_for(0, mTimeFrame->getNrof(1), [&](
const short pivotRofId) {
184 bool skip = skipROF(iteration, pivotRofId);
185 const auto& rofRange01 = mTimeFrame->getROFOverlapTableView().getOverlap(1, 0, pivotRofId);
186 for (auto targetRofId = rofRange01.getFirstEntry(); targetRofId < rofRange01.getEntriesBound(); ++targetRofId) {
187 const auto timeErr = mTimeFrame->getROFOverlapTableView().getTimeStamp(0, targetRofId, 1, pivotRofId);
188 trackleterKernelHost<TrackletMode::Layer0Layer1, true>(
189 !skip ? mTimeFrame->getClustersOnLayer(targetRofId, 0) : gsl::span<Cluster>(),
190 !skip ? mTimeFrame->getClustersOnLayer(pivotRofId, 1) : gsl::span<Cluster>(),
191 mTimeFrame->getUsedClustersROF(targetRofId, 0),
192 mTimeFrame->getIndexTable(targetRofId, 0).data(),
193 mVrtParams[iteration].phiCut,
194 mTimeFrame->getTracklets()[0],
195 mTimeFrame->getNTrackletsCluster(pivotRofId, 0),
201 mVrtParams[iteration].maxTrackletsPerCluster);
203 const auto& rofRange12 = mTimeFrame->getROFOverlapTableView().getOverlap(1, 2, pivotRofId);
204 for (
auto targetRofId = rofRange12.getFirstEntry(); targetRofId < rofRange12.getEntriesBound(); ++targetRofId) {
205 const auto timeErr = mTimeFrame->getROFOverlapTableView().getTimeStamp(2, targetRofId, 1, pivotRofId);
206 trackleterKernelHost<TrackletMode::Layer1Layer2, true>(
207 !skip ? mTimeFrame->getClustersOnLayer(targetRofId, 2) : gsl::span<Cluster>(),
208 !skip ? mTimeFrame->getClustersOnLayer(pivotRofId, 1) : gsl::span<Cluster>(),
209 mTimeFrame->getUsedClustersROF(targetRofId, 2),
210 mTimeFrame->getIndexTable(targetRofId, 2).data(),
211 mVrtParams[iteration].phiCut,
212 mTimeFrame->getTracklets()[1],
213 mTimeFrame->getNTrackletsCluster(pivotRofId, 1),
219 mVrtParams[iteration].maxTrackletsPerCluster);
221 mTimeFrame->getNTrackletsROF(pivotRofId, 0) = std::accumulate(mTimeFrame->getNTrackletsCluster(pivotRofId, 0).begin(), mTimeFrame->getNTrackletsCluster(pivotRofId, 0).end(), 0);
222 mTimeFrame->getNTrackletsROF(pivotRofId, 1) = std::accumulate(mTimeFrame->getNTrackletsCluster(pivotRofId, 1).begin(), mTimeFrame->getNTrackletsCluster(pivotRofId, 1).end(), 0);
225 mTimeFrame->computeTrackletsPerROFScans();
226 if (
auto tot0 = mTimeFrame->getTotalTrackletsTF(0), tot1 = mTimeFrame->getTotalTrackletsTF(1);
227 tot0 == 0 || tot1 == 0) {
230 mTimeFrame->getTracklets()[0].resize(tot0);
231 mTimeFrame->getTracklets()[1].resize(tot1);
234 tbb::parallel_for(0, mTimeFrame->getNrof(1), [&](
const short pivotRofId) {
235 bool skip = skipROF(iteration, pivotRofId);
236 const int globalOffsetPivot = mTimeFrame->getSortedStartIndex(pivotRofId, 1);
237 const auto& rofRange01 = mTimeFrame->getROFOverlapTableView().getOverlap(1, 0, pivotRofId);
238 for (auto targetRofId = rofRange01.getFirstEntry(); targetRofId < rofRange01.getEntriesBound(); ++targetRofId) {
239 const auto timeErr = mTimeFrame->getROFOverlapTableView().getTimeStamp(0, targetRofId, 1, pivotRofId);
240 trackleterKernelHost<TrackletMode::Layer0Layer1, false>(
241 !skip ? mTimeFrame->getClustersOnLayer(targetRofId, 0) : gsl::span<Cluster>(),
242 !skip ? mTimeFrame->getClustersOnLayer(pivotRofId, 1) : gsl::span<Cluster>(),
243 mTimeFrame->getUsedClustersROF(targetRofId, 0),
244 mTimeFrame->getIndexTable(targetRofId, 0).data(),
245 mVrtParams[iteration].phiCut,
246 mTimeFrame->getTracklets()[0],
247 mTimeFrame->getNTrackletsCluster(pivotRofId, 0),
250 mTimeFrame->getExclusiveNTrackletsCluster(pivotRofId, 0),
251 mTimeFrame->getSortedStartIndex(targetRofId, 0),
253 mVrtParams[iteration].maxTrackletsPerCluster);
255 const auto& rofRange12 = mTimeFrame->getROFOverlapTableView().getOverlap(1, 2, pivotRofId);
256 for (
auto targetRofId = rofRange12.getFirstEntry(); targetRofId < rofRange12.getEntriesBound(); ++targetRofId) {
257 const auto timeErr = mTimeFrame->getROFOverlapTableView().getTimeStamp(2, targetRofId, 1, pivotRofId);
258 trackleterKernelHost<TrackletMode::Layer1Layer2, false>(
259 !skip ? mTimeFrame->getClustersOnLayer(targetRofId, 2) : gsl::span<Cluster>(),
260 !skip ? mTimeFrame->getClustersOnLayer(pivotRofId, 1) : gsl::span<Cluster>(),
261 mTimeFrame->getUsedClustersROF(targetRofId, 2),
262 mTimeFrame->getIndexTable(targetRofId, 2).data(),
263 mVrtParams[iteration].phiCut,
264 mTimeFrame->getTracklets()[1],
265 mTimeFrame->getNTrackletsCluster(pivotRofId, 1),
268 mTimeFrame->getExclusiveNTrackletsCluster(pivotRofId, 1),
269 mTimeFrame->getSortedStartIndex(targetRofId, 2),
271 mVrtParams[iteration].maxTrackletsPerCluster);
277 if (mTimeFrame->hasMCinformation()) {
278 for (
const auto& trk : mTimeFrame->getTracklets()[0]) {
280 int sortedId0{trk.firstClusterIndex};
281 int sortedId1{trk.secondClusterIndex};
282 for (
const auto& lab0 : mTimeFrame->getClusterLabels(0, mTimeFrame->
getClusters()[0][sortedId0].clusterId)) {
283 for (
const auto& lab1 : mTimeFrame->getClusterLabels(1, mTimeFrame->
getClusters()[1][sortedId1].clusterId)) {
284 if (lab0 == lab1 && lab0.isValid()) {
289 if (
label.isValid()) {
293 mTimeFrame->getTrackletsLabel(0).emplace_back(
label);
301 mTaskArena->execute([&] {
302 tbb::combinable<int> totalLines{0};
304 tbb::blocked_range<short>(0, (
short)mTimeFrame->getNrof(1)),
305 [&](
const tbb::blocked_range<short>& Rofs) {
306 for (short pivotRofId = Rofs.begin(); pivotRofId < Rofs.end(); ++pivotRofId) {
307 if (mTimeFrame->getFoundTracklets(pivotRofId, 0).empty() || skipROF(iteration, pivotRofId)) {
310 mTimeFrame->getLines(pivotRofId).reserve(std::min(mTimeFrame->getFoundTracklets(pivotRofId, 0).size(), mTimeFrame->getNTrackletsCluster(pivotRofId, 0).size() * constants::MaxSelectedTrackletsPerCluster));
311 bounded_vector<uint8_t> usedTracklets(mTimeFrame->getFoundTracklets(pivotRofId, 0).size(), 0, mMemoryPool.get());
312 trackletSelectionKernelHost(
313 mTimeFrame->getClusters()[0].data(),
314 mTimeFrame->getClusters()[1].data(),
315 mTimeFrame->getUsedClusters(0),
316 mTimeFrame->getUsedClusters(2),
317 mTimeFrame->getFoundTracklets(pivotRofId, 0),
318 mTimeFrame->getFoundTracklets(pivotRofId, 1),
320 mTimeFrame->getNTrackletsCluster(pivotRofId, 0),
321 mTimeFrame->getNTrackletsCluster(pivotRofId, 1),
322 mTimeFrame->getLines(pivotRofId),
323 mTimeFrame->getLabelsFoundTracklets(pivotRofId, 0),
324 mTimeFrame->getLinesLabel(pivotRofId),
325 static_cast<int>(mTimeFrame->getClustersOnLayer(pivotRofId, 1).size()),
326 mVrtParams[iteration].tanLambdaCut,
327 mVrtParams[iteration].phiCut,
328 constants::MaxSelectedTrackletsPerCluster);
329 totalLines.local() += mTimeFrame->getLines(pivotRofId).size();
332 mTimeFrame->setNLinesTotal(totalLines.combine(std::plus<int>()));
336 deepVectorClear(mTimeFrame->getTracklets());
342 const int nRofs = mTimeFrame->getNrof(1);
343 std::vector<std::vector<Vertex>> rofVertices(nRofs);
344 std::vector<std::vector<VertexLabel>> rofLabels(nRofs);
345 const float pairCut2 = mVrtParams[iteration].pairCut * mVrtParams[iteration].pairCut;
346 const float duplicateZCut = mVrtParams[iteration].duplicateZCut > 0.f ? mVrtParams[iteration].duplicateZCut : std::max(4.f * mVrtParams[iteration].pairCut, 0.5f * mVrtParams[iteration].clusterCut);
347 const float duplicateDistance2Cut = mVrtParams[iteration].duplicateDistance2Cut > 0.f ? mVrtParams[iteration].duplicateDistance2Cut : std::max(16.f * pairCut2, 0.0625f * mVrtParams[iteration].clusterCut * mVrtParams[iteration].clusterCut);
349 settings.
beamX = mTimeFrame->getBeamX();
350 settings.
beamY = mTimeFrame->getBeamY();
351 settings.
pairCut = mVrtParams[iteration].pairCut;
353 settings.
clusterCut = mVrtParams[iteration].clusterCut;
354 settings.
coarseZWindow = mVrtParams[iteration].coarseZWindow;
355 settings.
seedDedupZCut = mVrtParams[iteration].seedDedupZCut;
360 settings.
maxZ = mVrtParams[iteration].maxZPositionAllowed;
365 const auto processROF = [&](
const int rofId) {
366 if (skipROF(iteration, rofId)) {
369 auto& lines = mTimeFrame->getLines(rofId);
370 auto clusters = line_vertexer::buildClusters(std::span<const Line>{lines.data(), lines.size()}, settings);
371 deepVectorClear(lines);
372 auto clusterBeamDistance2 = [&](
const ClusterLines& cluster) {
373 return (mTimeFrame->getBeamX() - cluster.getVertex()[0]) * (mTimeFrame->getBeamX() - cluster.getVertex()[0]) +
374 (mTimeFrame->getBeamY() - cluster.getVertex()[1]) * (mTimeFrame->getBeamY() - cluster.getVertex()[1]);
377 if (lhs.getSize() != rhs.getSize()) {
378 return lhs.getSize() > rhs.getSize();
380 if (o2::gpu::GPUCommonMath::Abs(lhs.getAvgDistance2() - rhs.getAvgDistance2()) > constants::Tolerance) {
381 return lhs.getAvgDistance2() < rhs.getAvgDistance2();
383 const auto lhsBeam = clusterBeamDistance2(lhs);
384 const auto rhsBeam = clusterBeamDistance2(rhs);
385 if (o2::gpu::GPUCommonMath::Abs(lhsBeam - rhsBeam) > constants::Tolerance) {
386 return lhsBeam < rhsBeam;
388 return lhs.getVertex()[2] < rhs.getVertex()[2];
393 float minClusterZ = std::numeric_limits<float>::max();
394 for (
const auto& cluster :
clusters) {
395 minClusterZ = std::min(minClusterZ, cluster.getVertex()[2]);
397 bounded_vector<ClusterLines> deduplicated(mMemoryPool.get());
398 deduplicated.reserve(
clusters.size());
399 std::unordered_map<int, std::vector<int>> keptByZBin;
401 bool duplicate =
false;
402 const auto candidateZ = candidate.getVertex()[2];
403 const auto zBin =
static_cast<int>(std::floor((candidateZ - minClusterZ) / settings.
duplicateZCut));
404 for (
int neighborBin = zBin - 1; neighborBin <= zBin + 1 && !duplicate; ++neighborBin) {
405 const auto found = keptByZBin.find(neighborBin);
406 if (found == keptByZBin.end()) {
409 for (
const auto ownerId : found->second) {
410 const auto& owner = deduplicated[ownerId];
411 if (!candidate.getTimeStamp().isCompatible(owner.getTimeStamp())) {
414 if (o2::gpu::GPUCommonMath::Abs(candidate.getVertex()[2] - owner.getVertex()[2]) >= settings.
duplicateZCut) {
417 const auto dx = candidate.getVertex()[0] - owner.getVertex()[0];
418 const auto dy = candidate.getVertex()[1] - owner.getVertex()[1];
419 const auto dz = candidate.getVertex()[2] - owner.getVertex()[2];
420 const auto distance2 = math_utils::SqSum(dx, dy, dz);
431 const auto ownerId =
static_cast<int>(deduplicated.size());
432 keptByZBin[zBin].push_back(ownerId);
433 deduplicated.push_back(std::move(candidate));
440 std::vector<int> candidateIndices;
442 for (
int iCluster{0}; iCluster <
nClusters; ++iCluster) {
443 const bool zCompatible = o2::gpu::GPUCommonMath::Abs(
clusters[iCluster].getVertex()[2]) < mVrtParams[iteration].maxZPositionAllowed;
446 candidateIndices.push_back(iCluster);
450 if (candidateIndices.empty()) {
456 auto lhsIt = lhs.getLabels().begin();
457 auto rhsIt = rhs.getLabels().begin();
458 while (lhsIt != lhs.getLabels().end() && rhsIt != rhs.getLabels().end()) {
459 if (*lhsIt == *rhsIt) {
463 }
else if (*lhsIt < *rhsIt) {
472 float minCandidateZ = std::numeric_limits<float>::max();
473 for (
const auto clusterId : candidateIndices) {
474 minCandidateZ = std::min(minCandidateZ,
clusters[clusterId].getVertex()[2]);
476 std::unordered_map<int, std::vector<int>> selectedByZBin;
477 std::vector<int> selectedIndices;
478 selectedIndices.reserve(candidateIndices.size());
479 for (
const auto clusterId : candidateIndices) {
480 const auto& candidate =
clusters[clusterId];
481 const auto candidateZ = candidate.getVertex()[2];
482 const auto zBin =
static_cast<int>((candidateZ - minCandidateZ) / settings.
finalSelectionZCut);
483 bool suppressed =
false;
484 for (
int neighborBin = zBin - 1; neighborBin <= zBin + 1 && !suppressed; ++neighborBin) {
485 const auto found = selectedByZBin.find(neighborBin);
486 if (found == selectedByZBin.end()) {
489 for (
const auto selectedId : found->second) {
490 const auto& selected =
clusters[selectedId];
491 if (!candidate.getTimeStamp().isCompatible(selected.getTimeStamp())) {
494 const auto zDelta = o2::gpu::GPUCommonMath::Abs(candidateZ - selected.getVertex()[2]);
495 const auto sharedLabels = countSharedLabels(candidate, selected);
496 const auto minSize = std::min(candidate.getSize(), selected.getSize());
497 const bool overlapDuplicate = sharedLabels > 0 && sharedLabels * 4 >=
minSize;
499 const bool clearlyBetterMultiplicity = selected.getSize() >= candidate.getSize() + 3;
500 const bool clearlyBetterQuality = selected.getSize() > candidate.getSize() &&
501 selected.getAvgDistance2() + constants::Tolerance < 0.8f * candidate.getAvgDistance2();
502 const bool weakCandidate = clearlyBetterMultiplicity || clearlyBetterQuality;
503 if (overlapDuplicate || (strongZDuplicate && weakCandidate)) {
512 selectedByZBin[zBin].push_back(clusterId);
513 selectedIndices.push_back(clusterId);
517 std::vector<int> sortedIndices(selectedIndices.size());
518 std::iota(sortedIndices.begin(), sortedIndices.end(), 0);
519 std::sort(sortedIndices.begin(), sortedIndices.end(), [&selectedIndices, &
clusters](
int i,
int j) {
520 return clusters[selectedIndices[i]].getSize() > clusters[selectedIndices[j]].getSize();
522 for (
const auto sortedId : sortedIndices) {
523 const auto& cluster =
clusters[selectedIndices[sortedId]];
524 const auto beamDistance2 = clusterBeamDistance2(cluster);
525 if (!(beamDistance2 < mVrtParams[iteration].NSigmaCut)) {
528 if (cluster.getSize() < mVrtParams[iteration].clusterContributorsCut) {
531 if (!rofVertices[rofId].
empty() && cluster.getSize() < mVrtParams[iteration].suppressLowMultDebris) {
537 (ushort)cluster.getSize(),
538 cluster.getAvgDistance2()};
539 if (mVrtParams[iteration].PassFlags[IterationStep::MarkVerticesAsUPC]) {
540 vertex.setFlags(Vertex::UPCMode);
542 vertex.setTimeStamp(cluster.getTimeStamp());
543 rofVertices[rofId].push_back(
vertex);
544 if (mTimeFrame->hasMCinformation()) {
545 auto& lineLabels = mTimeFrame->getLinesLabel(rofId);
546 bounded_vector<o2::MCCompLabel>
labels(mMemoryPool.get());
547 for (
auto&
index : cluster.getLabels()) {
550 const auto mainLabel = computeMain(
labels);
551 rofLabels[rofId].push_back(mainLabel);
556 if (mTaskArena->max_concurrency() <= 1) {
557 for (
int rofId{0}; rofId < nRofs; ++rofId) {
561 mTaskArena->execute([&] {
562 tbb::parallel_for(0, nRofs, [&](
const int rofId) {
568 for (
int rofId{0}; rofId < nRofs; ++rofId) {
569 for (
auto&
vertex : rofVertices[rofId]) {
570 mTimeFrame->addPrimaryVertex(
vertex);
572 if (mTimeFrame->hasMCinformation()) {
573 for (
auto&
label : rofLabels[rofId]) {
574 mTimeFrame->addPrimaryVertexLabel(
label);