183 mTaskArena->execute([&] {
184 tbb::parallel_for(0, mTimeFrame->getNrof(1), [&](
const short pivotRofId) {
185 bool skip = skipROF(iteration, pivotRofId);
186 const auto& rofRange01 = mTimeFrame->getROFOverlapTableView().getOverlap(1, 0, pivotRofId);
187 for (auto targetRofId = rofRange01.getFirstEntry(); targetRofId < rofRange01.getEntriesBound(); ++targetRofId) {
188 const auto timeErr = mTimeFrame->getROFOverlapTableView().getTimeStamp(0, targetRofId, 1, pivotRofId);
189 trackleterKernelHost<TrackletMode::Layer0Layer1, true>(
190 !skip ? mTimeFrame->getClustersOnLayer(targetRofId, 0) : gsl::span<Cluster>(),
191 !skip ? mTimeFrame->getClustersOnLayer(pivotRofId, 1) : gsl::span<Cluster>(),
192 mTimeFrame->getUsedClustersROF(targetRofId, 0),
193 mTimeFrame->getIndexTable(targetRofId, 0).data(),
194 mVrtParams[iteration].phiCut,
195 mTimeFrame->getTracklets()[0],
196 mTimeFrame->getNTrackletsCluster(pivotRofId, 0),
202 mVrtParams[iteration].maxTrackletsPerCluster);
204 const auto& rofRange12 = mTimeFrame->getROFOverlapTableView().getOverlap(1, 2, pivotRofId);
205 for (
auto targetRofId = rofRange12.getFirstEntry(); targetRofId < rofRange12.getEntriesBound(); ++targetRofId) {
206 const auto timeErr = mTimeFrame->getROFOverlapTableView().getTimeStamp(2, targetRofId, 1, pivotRofId);
207 trackleterKernelHost<TrackletMode::Layer1Layer2, true>(
208 !skip ? mTimeFrame->getClustersOnLayer(targetRofId, 2) : gsl::span<Cluster>(),
209 !skip ? mTimeFrame->getClustersOnLayer(pivotRofId, 1) : gsl::span<Cluster>(),
210 mTimeFrame->getUsedClustersROF(targetRofId, 2),
211 mTimeFrame->getIndexTable(targetRofId, 2).data(),
212 mVrtParams[iteration].phiCut,
213 mTimeFrame->getTracklets()[1],
214 mTimeFrame->getNTrackletsCluster(pivotRofId, 1),
220 mVrtParams[iteration].maxTrackletsPerCluster);
222 mTimeFrame->getNTrackletsROF(pivotRofId, 0) = std::accumulate(mTimeFrame->getNTrackletsCluster(pivotRofId, 0).begin(), mTimeFrame->getNTrackletsCluster(pivotRofId, 0).end(), 0);
223 mTimeFrame->getNTrackletsROF(pivotRofId, 1) = std::accumulate(mTimeFrame->getNTrackletsCluster(pivotRofId, 1).begin(), mTimeFrame->getNTrackletsCluster(pivotRofId, 1).end(), 0);
226 mTimeFrame->computeTrackletsPerROFScans();
227 if (
auto tot0 = mTimeFrame->getTotalTrackletsTF(0), tot1 = mTimeFrame->getTotalTrackletsTF(1);
228 tot0 == 0 || tot1 == 0) {
231 mTimeFrame->getTracklets()[0].resize(tot0);
232 mTimeFrame->getTracklets()[1].resize(tot1);
235 tbb::parallel_for(0, mTimeFrame->getNrof(1), [&](
const short pivotRofId) {
236 bool skip = skipROF(iteration, pivotRofId);
237 const int globalOffsetPivot = mTimeFrame->getSortedStartIndex(pivotRofId, 1);
238 const auto& rofRange01 = mTimeFrame->getROFOverlapTableView().getOverlap(1, 0, pivotRofId);
239 for (auto targetRofId = rofRange01.getFirstEntry(); targetRofId < rofRange01.getEntriesBound(); ++targetRofId) {
240 const auto timeErr = mTimeFrame->getROFOverlapTableView().getTimeStamp(0, targetRofId, 1, pivotRofId);
241 trackleterKernelHost<TrackletMode::Layer0Layer1, false>(
242 !skip ? mTimeFrame->getClustersOnLayer(targetRofId, 0) : gsl::span<Cluster>(),
243 !skip ? mTimeFrame->getClustersOnLayer(pivotRofId, 1) : gsl::span<Cluster>(),
244 mTimeFrame->getUsedClustersROF(targetRofId, 0),
245 mTimeFrame->getIndexTable(targetRofId, 0).data(),
246 mVrtParams[iteration].phiCut,
247 mTimeFrame->getTracklets()[0],
248 mTimeFrame->getNTrackletsCluster(pivotRofId, 0),
251 mTimeFrame->getExclusiveNTrackletsCluster(pivotRofId, 0),
252 mTimeFrame->getSortedStartIndex(targetRofId, 0),
254 mVrtParams[iteration].maxTrackletsPerCluster);
256 const auto& rofRange12 = mTimeFrame->getROFOverlapTableView().getOverlap(1, 2, pivotRofId);
257 for (
auto targetRofId = rofRange12.getFirstEntry(); targetRofId < rofRange12.getEntriesBound(); ++targetRofId) {
258 const auto timeErr = mTimeFrame->getROFOverlapTableView().getTimeStamp(2, targetRofId, 1, pivotRofId);
259 trackleterKernelHost<TrackletMode::Layer1Layer2, false>(
260 !skip ? mTimeFrame->getClustersOnLayer(targetRofId, 2) : gsl::span<Cluster>(),
261 !skip ? mTimeFrame->getClustersOnLayer(pivotRofId, 1) : gsl::span<Cluster>(),
262 mTimeFrame->getUsedClustersROF(targetRofId, 2),
263 mTimeFrame->getIndexTable(targetRofId, 2).data(),
264 mVrtParams[iteration].phiCut,
265 mTimeFrame->getTracklets()[1],
266 mTimeFrame->getNTrackletsCluster(pivotRofId, 1),
269 mTimeFrame->getExclusiveNTrackletsCluster(pivotRofId, 1),
270 mTimeFrame->getSortedStartIndex(targetRofId, 2),
272 mVrtParams[iteration].maxTrackletsPerCluster);
278 if (mTimeFrame->hasMCinformation()) {
279 for (
const auto& trk : mTimeFrame->getTracklets()[0]) {
281 int sortedId0{trk.firstClusterIndex};
282 int sortedId1{trk.secondClusterIndex};
283 for (
const auto& lab0 : mTimeFrame->getClusterLabels(0, mTimeFrame->
getClusters()[0][sortedId0].clusterId)) {
284 for (
const auto& lab1 : mTimeFrame->getClusterLabels(1, mTimeFrame->
getClusters()[1][sortedId1].clusterId)) {
285 if (lab0 == lab1 && lab0.isValid()) {
290 if (
label.isValid()) {
294 mTimeFrame->getTrackletsLabel(0).emplace_back(
label);
302 mTaskArena->execute([&] {
303 tbb::combinable<int> totalLines{0};
305 tbb::blocked_range<short>(0, (
short)mTimeFrame->getNrof(1)),
306 [&](
const tbb::blocked_range<short>& Rofs) {
307 for (short pivotRofId = Rofs.begin(); pivotRofId < Rofs.end(); ++pivotRofId) {
308 if (mTimeFrame->getFoundTracklets(pivotRofId, 0).empty() || skipROF(iteration, pivotRofId)) {
311 mTimeFrame->getLines(pivotRofId).reserve(std::min(mTimeFrame->getFoundTracklets(pivotRofId, 0).size(), mTimeFrame->getNTrackletsCluster(pivotRofId, 0).size() * constants::MaxSelectedTrackletsPerCluster));
312 bounded_vector<uint8_t> usedTracklets(mTimeFrame->getFoundTracklets(pivotRofId, 0).size(), 0, mMemoryPool.get());
313 trackletSelectionKernelHost(
314 mTimeFrame->getClusters()[0].data(),
315 mTimeFrame->getClusters()[1].data(),
316 mTimeFrame->getUsedClusters(0),
317 mTimeFrame->getUsedClusters(2),
318 mTimeFrame->getFoundTracklets(pivotRofId, 0),
319 mTimeFrame->getFoundTracklets(pivotRofId, 1),
321 mTimeFrame->getNTrackletsCluster(pivotRofId, 0),
322 mTimeFrame->getNTrackletsCluster(pivotRofId, 1),
323 mTimeFrame->getLines(pivotRofId),
324 mTimeFrame->getLabelsFoundTracklets(pivotRofId, 0),
325 mTimeFrame->getLinesLabel(pivotRofId),
326 static_cast<int>(mTimeFrame->getClustersOnLayer(pivotRofId, 1).size()),
327 mVrtParams[iteration].tanLambdaCut,
328 mVrtParams[iteration].phiCut,
329 constants::MaxSelectedTrackletsPerCluster);
330 totalLines.local() += mTimeFrame->getLines(pivotRofId).size();
333 mTimeFrame->setNLinesTotal(totalLines.combine(std::plus<int>()));
337 deepVectorClear(mTimeFrame->getTracklets());
343 const int nRofs = mTimeFrame->getNrof(1);
344 std::vector<std::vector<Vertex>> rofVertices(nRofs);
345 std::vector<std::vector<VertexLabel>> rofLabels(nRofs);
346 const float pairCut2 = mVrtParams[iteration].pairCut * mVrtParams[iteration].pairCut;
347 const float duplicateZCut = mVrtParams[iteration].duplicateZCut > 0.f ? mVrtParams[iteration].duplicateZCut : std::max(4.f * mVrtParams[iteration].pairCut, 0.5f * mVrtParams[iteration].clusterCut);
348 const float duplicateDistance2Cut = mVrtParams[iteration].duplicateDistance2Cut > 0.f ? mVrtParams[iteration].duplicateDistance2Cut : std::max(16.f * pairCut2, 0.0625f * mVrtParams[iteration].clusterCut * mVrtParams[iteration].clusterCut);
350 settings.
beamX = mTimeFrame->getBeamX();
351 settings.
beamY = mTimeFrame->getBeamY();
352 settings.
pairCut = mVrtParams[iteration].pairCut;
354 settings.
clusterCut = mVrtParams[iteration].clusterCut;
355 settings.
coarseZWindow = mVrtParams[iteration].coarseZWindow;
356 settings.
seedDedupZCut = mVrtParams[iteration].seedDedupZCut;
361 settings.
maxZ = mVrtParams[iteration].maxZPositionAllowed;
366 const auto processROF = [&](
const int rofId) {
367 if (skipROF(iteration, rofId)) {
370 auto& lines = mTimeFrame->getLines(rofId);
371 auto clusters = line_vertexer::buildClusters(std::span<const Line>{lines.data(), lines.size()}, settings);
372 deepVectorClear(lines);
374 return (mTimeFrame->getBeamX() - cluster.getVertex()[0]) * (mTimeFrame->getBeamX() - cluster.getVertex()[0]) +
375 (mTimeFrame->getBeamY() - cluster.getVertex()[1]) * (mTimeFrame->getBeamY() - cluster.getVertex()[1]);
378 if (lhs.getSize() != rhs.getSize()) {
379 return lhs.getSize() > rhs.getSize();
381 if (o2::gpu::GPUCommonMath::Abs(lhs.getAvgDistance2() - rhs.getAvgDistance2()) > constants::Tolerance) {
382 return lhs.getAvgDistance2() < rhs.getAvgDistance2();
384 const auto lhsBeam = clusterBeamDistance2(lhs);
385 const auto rhsBeam = clusterBeamDistance2(rhs);
386 if (o2::gpu::GPUCommonMath::Abs(lhsBeam - rhsBeam) > constants::Tolerance) {
387 return lhsBeam < rhsBeam;
389 return lhs.getVertex()[2] < rhs.getVertex()[2];
394 float minClusterZ = std::numeric_limits<float>::max();
395 for (
const auto& cluster :
clusters) {
396 minClusterZ = std::min(minClusterZ, cluster.getVertex()[2]);
398 bounded_vector<line_vertexer::ClusterWithLines> deduplicated(mMemoryPool.get());
399 deduplicated.reserve(
clusters.size());
400 std::unordered_map<int, std::vector<int>> keptByZBin;
402 bool duplicate =
false;
403 const auto candidateZ = candidate.getVertex()[2];
404 const auto zBin =
static_cast<int>(std::floor((candidateZ - minClusterZ) / settings.
duplicateZCut));
405 for (
int neighborBin = zBin - 1; neighborBin <= zBin + 1 && !duplicate; ++neighborBin) {
406 const auto found = keptByZBin.find(neighborBin);
407 if (found == keptByZBin.end()) {
410 for (
const auto ownerId : found->second) {
411 const auto& owner = deduplicated[ownerId];
412 if (!candidate.getTimeStamp().isCompatible(owner.getTimeStamp())) {
415 if (o2::gpu::GPUCommonMath::Abs(candidate.getVertex()[2] - owner.getVertex()[2]) >= settings.
duplicateZCut) {
418 const auto dx = candidate.getVertex()[0] - owner.getVertex()[0];
419 const auto dy = candidate.getVertex()[1] - owner.getVertex()[1];
420 const auto dz = candidate.getVertex()[2] - owner.getVertex()[2];
421 const auto distance2 = math_utils::SqSum(dx, dy, dz);
432 const auto ownerId =
static_cast<int>(deduplicated.size());
433 keptByZBin[zBin].push_back(ownerId);
434 deduplicated.push_back(std::move(candidate));
441 std::vector<int> candidateIndices;
443 for (
int iCluster{0}; iCluster <
nClusters; ++iCluster) {
444 const bool zCompatible = o2::gpu::GPUCommonMath::Abs(
clusters[iCluster].getVertex()[2]) < mVrtParams[iteration].maxZPositionAllowed;
447 candidateIndices.push_back(iCluster);
451 if (candidateIndices.empty()) {
457 auto lhsIt = lhs.getLabels().begin();
458 auto rhsIt = rhs.getLabels().begin();
459 while (lhsIt != lhs.getLabels().end() && rhsIt != rhs.getLabels().end()) {
460 if (*lhsIt == *rhsIt) {
464 }
else if (*lhsIt < *rhsIt) {
473 float minCandidateZ = std::numeric_limits<float>::max();
474 for (
const auto clusterId : candidateIndices) {
475 minCandidateZ = std::min(minCandidateZ,
clusters[clusterId].getVertex()[2]);
477 std::unordered_map<int, std::vector<int>> selectedByZBin;
478 std::vector<int> selectedIndices;
479 selectedIndices.reserve(candidateIndices.size());
480 for (
const auto clusterId : candidateIndices) {
481 const auto& candidate =
clusters[clusterId];
482 const auto candidateZ = candidate.getVertex()[2];
483 const auto zBin =
static_cast<int>((candidateZ - minCandidateZ) / settings.
finalSelectionZCut);
484 bool suppressed =
false;
485 for (
int neighborBin = zBin - 1; neighborBin <= zBin + 1 && !suppressed; ++neighborBin) {
486 const auto found = selectedByZBin.find(neighborBin);
487 if (found == selectedByZBin.end()) {
490 for (
const auto selectedId : found->second) {
491 const auto& selected =
clusters[selectedId];
492 if (!candidate.getTimeStamp().isCompatible(selected.getTimeStamp())) {
495 const auto zDelta = o2::gpu::GPUCommonMath::Abs(candidateZ - selected.getVertex()[2]);
496 const auto sharedLabels = countSharedLabels(candidate, selected);
497 const auto minSize = std::min(candidate.getSize(), selected.getSize());
498 const bool overlapDuplicate = sharedLabels > 0 && sharedLabels * 4 >=
minSize;
500 const bool clearlyBetterMultiplicity = selected.getSize() >= candidate.getSize() + 3;
501 const bool clearlyBetterQuality = selected.getSize() > candidate.getSize() &&
502 selected.getAvgDistance2() + constants::Tolerance < 0.8f * candidate.getAvgDistance2();
503 const bool weakCandidate = clearlyBetterMultiplicity || clearlyBetterQuality;
504 if (overlapDuplicate || (strongZDuplicate && weakCandidate)) {
513 selectedByZBin[zBin].push_back(clusterId);
514 selectedIndices.push_back(clusterId);
518 std::vector<int> sortedIndices(selectedIndices.size());
519 std::iota(sortedIndices.begin(), sortedIndices.end(), 0);
520 std::sort(sortedIndices.begin(), sortedIndices.end(), [&selectedIndices, &
clusters](
int i,
int j) {
521 return clusters[selectedIndices[i]].getSize() > clusters[selectedIndices[j]].getSize();
523 for (
const auto sortedId : sortedIndices) {
524 const auto& cluster =
clusters[selectedIndices[sortedId]];
525 const auto beamDistance2 = clusterBeamDistance2(cluster);
526 if (!(beamDistance2 < mVrtParams[iteration].NSigmaCut)) {
529 if (cluster.getSize() < mVrtParams[iteration].clusterContributorsCut) {
532 if (!rofVertices[rofId].
empty() && cluster.getSize() < mVrtParams[iteration].suppressLowMultDebris) {
538 (ushort)cluster.getSize(),
539 cluster.getAvgDistance2()};
540 if (mVrtParams[iteration].PassFlags[IterationStep::MarkVerticesAsUPC]) {
541 vertex.setFlags(Vertex::UPCMode);
543 vertex.setTimeStamp(cluster.getTimeStamp());
544 rofVertices[rofId].push_back(
vertex);
545 if (mTimeFrame->hasMCinformation()) {
546 auto& lineLabels = mTimeFrame->getLinesLabel(rofId);
547 bounded_vector<o2::MCCompLabel>
labels(mMemoryPool.get());
548 for (
auto&
index : cluster.getLabels()) {
552 rofLabels[rofId].push_back(mainLabel);
557 if (mTaskArena->max_concurrency() <= 1) {
558 for (
int rofId{0}; rofId < nRofs; ++rofId) {
562 mTaskArena->execute([&] {
563 tbb::parallel_for(0, nRofs, [&](
const int rofId) {
569 for (
int rofId{0}; rofId < nRofs; ++rofId) {
570 for (
auto&
vertex : rofVertices[rofId]) {
571 mTimeFrame->addPrimaryVertex(
vertex);
573 if (mTimeFrame->hasMCinformation()) {
574 for (
auto&
label : rofLabels[rofId]) {
575 mTimeFrame->addPrimaryVertexLabel(
label);