Project
Loading...
Searching...
No Matches
VertexerTraits.cxx
Go to the documentation of this file.
1// Copyright 2019-2026 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
12
13#include <algorithm>
14#include <memory>
15#include <ranges>
16#include <span>
17#include <unordered_map>
18
19#include <oneapi/tbb/blocked_range.h>
20#include <oneapi/tbb/parallel_for.h>
21#include <oneapi/tbb/combinable.h>
22
34
35namespace o2::its
36{
38
39namespace
40{
41
42template <TrackletMode Mode, bool EvalRun, int NLayers>
43void trackleterKernelHost(
44 const gsl::span<const Cluster>& clustersNextLayer, // 0 2
45 const gsl::span<const Cluster>& clustersCurrentLayer, // 1 1
46 const gsl::span<uint8_t>& usedClustersNextLayer, // 0 2
47 const int* indexTableNext,
48 const float phiCut,
49 bounded_vector<Tracklet>& tracklets,
50 gsl::span<int> foundTracklets,
51 const IndexTableUtils<NLayers>& utils,
52 const TimeEstBC& timErr,
53 gsl::span<int> rofFoundTrackletsOffsets,
54 const int globalOffsetNextLayer,
55 const int globalOffsetCurrentLayer,
56 const int maxTrackletsPerCluster)
57{
58 const int PhiBins{utils.getNphiBins()};
59 const int ZBins{utils.getNzBins()};
60 // loop on layer1 clusters
61 for (int iCurrentLayerClusterIndex = 0; iCurrentLayerClusterIndex < clustersCurrentLayer.size(); ++iCurrentLayerClusterIndex) {
62 int storedTracklets{0};
63 const Cluster& currentCluster{clustersCurrentLayer[iCurrentLayerClusterIndex]};
64 const int4 selectedBinsRect{o2::its::getBinsRect(currentCluster, (int)Mode + 1, 0.f, 0.f, 100.f, phiCut / 2, utils)};
65 if (selectedBinsRect.x >= 0) {
66 int phiBinsNum{selectedBinsRect.w - selectedBinsRect.y + 1};
67 if (phiBinsNum < 0) {
68 phiBinsNum += PhiBins;
69 }
70 // loop on phi bins next layer
71 for (int iPhiBin{selectedBinsRect.y}, iPhiCount{0}; iPhiCount < phiBinsNum && storedTracklets < maxTrackletsPerCluster; iPhiBin = ++iPhiBin == PhiBins ? 0 : iPhiBin, iPhiCount++) {
72 const int firstBinIndex{utils.getBinIndex(selectedBinsRect.x, iPhiBin)};
73 const int firstRowClusterIndex{indexTableNext[firstBinIndex]};
74 const int maxRowClusterIndex{indexTableNext[firstBinIndex + ZBins]};
75 // loop on clusters next layer
76 for (int iNextLayerClusterIndex{firstRowClusterIndex}; iNextLayerClusterIndex < maxRowClusterIndex && iNextLayerClusterIndex < static_cast<int>(clustersNextLayer.size()) && storedTracklets < maxTrackletsPerCluster; ++iNextLayerClusterIndex) {
77 if (usedClustersNextLayer[iNextLayerClusterIndex]) {
78 continue;
79 }
80 const Cluster& nextCluster{clustersNextLayer[iNextLayerClusterIndex]};
81 if (math_utils::isPhiDifferenceBelow(currentCluster.phi, nextCluster.phi, phiCut)) {
82 if (storedTracklets < maxTrackletsPerCluster) {
83 if constexpr (!EvalRun) {
84 if constexpr (Mode == TrackletMode::Layer0Layer1) {
85 tracklets[rofFoundTrackletsOffsets[iCurrentLayerClusterIndex] + storedTracklets] = Tracklet{globalOffsetNextLayer + iNextLayerClusterIndex, globalOffsetCurrentLayer + iCurrentLayerClusterIndex, nextCluster, currentCluster, timErr};
86 } else {
87 tracklets[rofFoundTrackletsOffsets[iCurrentLayerClusterIndex] + storedTracklets] = Tracklet{globalOffsetCurrentLayer + iCurrentLayerClusterIndex, globalOffsetNextLayer + iNextLayerClusterIndex, currentCluster, nextCluster, timErr};
88 }
89 }
90 ++storedTracklets;
91 }
92 }
93 }
94 }
95 }
96 if constexpr (EvalRun) {
97 foundTracklets[iCurrentLayerClusterIndex] += storedTracklets;
98 } else {
99 rofFoundTrackletsOffsets[iCurrentLayerClusterIndex] += storedTracklets;
100 }
101 }
102}
103
104void trackletSelectionKernelHost(
105 const Cluster* clusters0, // global layer 0 clusters
106 const Cluster* clusters1, // global layer 1 clusters
107 gsl::span<unsigned char> usedClusters0, // global layer 0 used clusters
108 gsl::span<unsigned char> usedClusters2, // global layer 2 used clusters
109 const gsl::span<const Tracklet>& tracklets01,
110 const gsl::span<const Tracklet>& tracklets12,
111 bounded_vector<uint8_t>& usedTracklets,
112 const gsl::span<int> foundTracklets01,
113 const gsl::span<int> foundTracklets12,
114 bounded_vector<Line>& lines,
115 const gsl::span<const o2::MCCompLabel>& trackletLabels,
116 bounded_vector<o2::MCCompLabel>& linesLabels,
117 const int nLayer1Clusters,
118 const float tanLambdaCut,
119 const float phiCut,
120 const int maxTracklets)
121{
122 int offset01{0}, offset12{0};
123 for (int iCurrentLayerClusterIndex{0}; iCurrentLayerClusterIndex < nLayer1Clusters; ++iCurrentLayerClusterIndex) {
124 int validTracklets{0};
125 const int endTracklet01 = offset01 + foundTracklets01[iCurrentLayerClusterIndex];
126 const int endTracklet12 = offset12 + foundTracklets12[iCurrentLayerClusterIndex];
127 for (int iTracklet12{offset12}; iTracklet12 < endTracklet12 && validTracklets != maxTracklets; ++iTracklet12) {
128 const auto& tracklet12{tracklets12[iTracklet12]};
129 for (int iTracklet01{offset01}; iTracklet01 < endTracklet01 && validTracklets != maxTracklets; ++iTracklet01) {
130 if (usedTracklets[iTracklet01]) {
131 continue;
132 }
133
134 const auto& tracklet01{tracklets01[iTracklet01]};
135 if (!tracklet01.getTimeStamp().isCompatible(tracklet12.getTimeStamp())) {
136 continue;
137 }
138
139 const float deltaTanLambda{o2::gpu::GPUCommonMath::Abs(tracklet01.tanLambda - tracklet12.tanLambda)};
140 if (deltaTanLambda >= tanLambdaCut) {
141 continue;
142 }
143 if (math_utils::isPhiDifferenceBelow(tracklet01.phi, tracklet12.phi, phiCut) && validTracklets != maxTracklets) {
144 usedClusters0[tracklet01.firstClusterIndex] = 1;
145 usedClusters2[tracklet12.secondClusterIndex] = 1;
146 usedTracklets[iTracklet01] = true;
147 lines.emplace_back(tracklet01, clusters0, clusters1);
148 if (!trackletLabels.empty()) {
149 linesLabels.emplace_back(trackletLabels[iTracklet01]);
150 }
151 ++validTracklets;
152 }
153 }
154 }
155 offset01 += foundTracklets01[iCurrentLayerClusterIndex];
156 offset12 += foundTracklets12[iCurrentLayerClusterIndex];
157 }
158}
159} // namespace
160
161template <int NLayers>
163{
164 mTaskArena->execute([&] { mTimeFrame->initialise(trackingParams, 3); });
165}
166
167template <int NLayers>
168void VertexerTraits<NLayers>::updateVertexingParameters(const std::vector<VertexingParameters>& vrtPar)
169{
170 mVrtParams = vrtPar;
171 mIndexTableUtils.setTrackingParameters(vrtPar[0]);
172 for (auto& par : mVrtParams) {
173 par.phiSpan = static_cast<int>(std::ceil(mIndexTableUtils.getNphiBins() * par.phiCut / o2::constants::math::TwoPI));
174 par.zSpan = static_cast<int>(std::ceil(par.zCut * mIndexTableUtils.getInverseZCoordinate(0)));
175 }
176}
177
178// Main functions
179template <int NLayers>
181{
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>(), // Clusters to be matched with the next layer in target rof
190 !skip ? mTimeFrame->getClustersOnLayer(pivotRofId, 1) : gsl::span<Cluster>(), // Clusters to be matched with the current layer in pivot rof
191 mTimeFrame->getUsedClustersROF(targetRofId, 0), // Span of the used clusters in the target rof
192 mTimeFrame->getIndexTable(targetRofId, 0).data(), // Index table to access the data on the next layer in target rof
193 mVrtParams[iteration].phiCut,
194 mTimeFrame->getTracklets()[0], // Flat tracklet buffer
195 mTimeFrame->getNTrackletsCluster(pivotRofId, 0), // Span of the number of tracklets per each cluster in pivot rof
196 mIndexTableUtils,
197 timeErr,
198 gsl::span<int>(), // Offset in the tracklet buffer
199 0,
200 0,
201 mVrtParams[iteration].maxTrackletsPerCluster);
202 }
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), // Span of the number of tracklets per each cluster in pivot rof
214 mIndexTableUtils,
215 timeErr,
216 gsl::span<int>(), // Offset in the tracklet buffer
217 0,
218 0,
219 mVrtParams[iteration].maxTrackletsPerCluster);
220 }
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);
223 });
224
225 mTimeFrame->computeTrackletsPerROFScans();
226 if (auto tot0 = mTimeFrame->getTotalTrackletsTF(0), tot1 = mTimeFrame->getTotalTrackletsTF(1);
227 tot0 == 0 || tot1 == 0) {
228 return;
229 } else {
230 mTimeFrame->getTracklets()[0].resize(tot0);
231 mTimeFrame->getTracklets()[1].resize(tot1);
232 }
233
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),
248 mIndexTableUtils,
249 timeErr,
250 mTimeFrame->getExclusiveNTrackletsCluster(pivotRofId, 0),
251 mTimeFrame->getSortedStartIndex(targetRofId, 0),
252 globalOffsetPivot,
253 mVrtParams[iteration].maxTrackletsPerCluster);
254 }
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),
266 mIndexTableUtils,
267 timeErr,
268 mTimeFrame->getExclusiveNTrackletsCluster(pivotRofId, 1),
269 mTimeFrame->getSortedStartIndex(targetRofId, 2),
270 globalOffsetPivot,
271 mVrtParams[iteration].maxTrackletsPerCluster);
272 }
273 });
274 });
275
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()) {
285 label = lab0;
286 break;
287 }
288 }
289 if (label.isValid()) {
290 break;
291 }
292 }
293 mTimeFrame->getTrackletsLabel(0).emplace_back(label);
294 }
295 }
296}
297
298template <int NLayers>
300{
301 mTaskArena->execute([&] {
302 tbb::combinable<int> totalLines{0};
303 tbb::parallel_for(
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)) {
308 continue;
309 }
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),
319 usedTracklets,
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();
330 }
331 });
332 mTimeFrame->setNLinesTotal(totalLines.combine(std::plus<int>()));
333 });
334
335 // from here on we do not use tracklets anymore, so let's free them
336 deepVectorClear(mTimeFrame->getTracklets());
337}
338
339template <int NLayers>
341{
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;
352 settings.pairCut2 = pairCut2;
353 settings.clusterCut = mVrtParams[iteration].clusterCut;
354 settings.coarseZWindow = mVrtParams[iteration].coarseZWindow;
355 settings.seedDedupZCut = mVrtParams[iteration].seedDedupZCut;
356 settings.refitDedupZCut = mVrtParams[iteration].refitDedupZCut;
357 settings.duplicateZCut = duplicateZCut;
358 settings.duplicateDistance2Cut = duplicateDistance2Cut;
359 settings.finalSelectionZCut = mVrtParams[iteration].finalSelectionZCut;
360 settings.maxZ = mVrtParams[iteration].maxZPositionAllowed;
361 settings.seedMemberRadiusTime = mVrtParams[iteration].seedMemberRadiusTime;
362 settings.seedMemberRadiusZ = mVrtParams[iteration].seedMemberRadiusZ;
363 settings.memoryPool = mMemoryPool;
364
365 const auto processROF = [&](const int rofId) {
366 if (skipROF(iteration, rofId)) {
367 return;
368 }
369 auto& lines = mTimeFrame->getLines(rofId);
370 auto clusters = line_vertexer::buildClusters(std::span<const Line>{lines.data(), lines.size()}, settings);
371 deepVectorClear(lines); // not needed after
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]);
375 };
376 auto clusterBetter = [&](const ClusterLines& lhs, const ClusterLines& rhs) {
377 if (lhs.getSize() != rhs.getSize()) {
378 return lhs.getSize() > rhs.getSize();
379 }
380 if (o2::gpu::GPUCommonMath::Abs(lhs.getAvgDistance2() - rhs.getAvgDistance2()) > constants::Tolerance) {
381 return lhs.getAvgDistance2() < rhs.getAvgDistance2();
382 }
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;
387 }
388 return lhs.getVertex()[2] < rhs.getVertex()[2];
389 };
390
391 // Cluster deduplication by local non-maximum suppression in time/space
392 std::sort(clusters.begin(), clusters.end(), clusterBetter);
393 float minClusterZ = std::numeric_limits<float>::max();
394 for (const auto& cluster : clusters) {
395 minClusterZ = std::min(minClusterZ, cluster.getVertex()[2]);
396 }
397 bounded_vector<ClusterLines> deduplicated(mMemoryPool.get());
398 deduplicated.reserve(clusters.size());
399 std::unordered_map<int, std::vector<int>> keptByZBin;
400 for (auto& candidate : clusters) {
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()) {
407 continue;
408 }
409 for (const auto ownerId : found->second) {
410 const auto& owner = deduplicated[ownerId];
411 if (!candidate.getTimeStamp().isCompatible(owner.getTimeStamp())) {
412 continue;
413 }
414 if (o2::gpu::GPUCommonMath::Abs(candidate.getVertex()[2] - owner.getVertex()[2]) >= settings.duplicateZCut) {
415 continue;
416 }
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);
421 if (distance2 < settings.duplicateDistance2Cut) {
422 duplicate = true;
423 break;
424 }
425 }
426 }
427 if (duplicate) {
428 continue;
429 }
430
431 const auto ownerId = static_cast<int>(deduplicated.size());
432 keptByZBin[zBin].push_back(ownerId);
433 deduplicated.push_back(std::move(candidate));
434 }
435 clusters = std::move(deduplicated);
436 int nClusters = static_cast<int>(clusters.size());
437
438 // Vertex filtering with score-based local NMS
439 std::sort(clusters.begin(), clusters.end(), clusterBetter);
440 std::vector<int> candidateIndices;
441 candidateIndices.reserve(nClusters);
442 for (int iCluster{0}; iCluster < nClusters; ++iCluster) {
443 const bool zCompatible = o2::gpu::GPUCommonMath::Abs(clusters[iCluster].getVertex()[2]) < mVrtParams[iteration].maxZPositionAllowed;
444
445 if (zCompatible) {
446 candidateIndices.push_back(iCluster);
447 }
448 }
449
450 if (candidateIndices.empty()) {
451 return;
452 }
453
454 auto countSharedLabels = [](const ClusterLines& lhs, const ClusterLines& rhs) {
455 size_t shared = 0;
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) {
460 ++shared;
461 ++lhsIt;
462 ++rhsIt;
463 } else if (*lhsIt < *rhsIt) {
464 ++lhsIt;
465 } else {
466 ++rhsIt;
467 }
468 }
469 return shared;
470 };
471
472 float minCandidateZ = std::numeric_limits<float>::max();
473 for (const auto clusterId : candidateIndices) {
474 minCandidateZ = std::min(minCandidateZ, clusters[clusterId].getVertex()[2]);
475 }
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()) {
487 continue;
488 }
489 for (const auto selectedId : found->second) {
490 const auto& selected = clusters[selectedId];
491 if (!candidate.getTimeStamp().isCompatible(selected.getTimeStamp())) {
492 continue;
493 }
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;
498 const bool strongZDuplicate = zDelta < settings.finalSelectionZCut;
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)) {
504 suppressed = true;
505 break;
506 }
507 }
508 }
509 if (suppressed) {
510 continue;
511 }
512 selectedByZBin[zBin].push_back(clusterId);
513 selectedIndices.push_back(clusterId);
514 }
515
516 // sort vertices by their multiplicity to opt. suppress lower mult. debris
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();
521 });
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)) {
526 continue;
527 }
528 if (cluster.getSize() < mVrtParams[iteration].clusterContributorsCut) {
529 continue;
530 }
531 if (!rofVertices[rofId].empty() && cluster.getSize() < mVrtParams[iteration].suppressLowMultDebris) {
532 continue;
533 }
534
535 Vertex vertex{cluster.getVertex().data(),
536 cluster.getRMS2(),
537 (ushort)cluster.getSize(),
538 cluster.getAvgDistance2()};
539 if (mVrtParams[iteration].PassFlags[IterationStep::MarkVerticesAsUPC]) {
540 vertex.setFlags(Vertex::UPCMode);
541 }
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()) {
548 labels.push_back(lineLabels[index]);
549 }
550 const auto mainLabel = computeMain(labels);
551 rofLabels[rofId].push_back(mainLabel);
552 }
553 }
554 };
555
556 if (mTaskArena->max_concurrency() <= 1) {
557 for (int rofId{0}; rofId < nRofs; ++rofId) {
558 processROF(rofId);
559 }
560 } else {
561 mTaskArena->execute([&] {
562 tbb::parallel_for(0, nRofs, [&](const int rofId) {
563 processROF(rofId);
564 });
565 });
566 }
567 // add vertices, these anyways get sorted afterward
568 for (int rofId{0}; rofId < nRofs; ++rofId) {
569 for (auto& vertex : rofVertices[rofId]) {
570 mTimeFrame->addPrimaryVertex(vertex);
571 }
572 if (mTimeFrame->hasMCinformation()) {
573 for (auto& label : rofLabels[rofId]) {
574 mTimeFrame->addPrimaryVertexLabel(label);
575 }
576 }
577 }
578}
579
580template <int NLayers>
582{
583 LOGP(info, "Using truth seeds as vertices; will skip computations");
584 const auto dc = o2::steer::DigitizationContext::loadFromFile("collisioncontext.root");
585 const auto irs = dc->getEventRecords();
587 int64_t roFrameLengthInBC = o2::itsmft::DPLAlpideParam<o2::detectors::DetID::ITS>::Instance().getROFLengthInBC(1);
589 const int iSrc = 0; // take only events from collision generator
590 auto eveId2colId = dc->getCollisionIndicesForSource(iSrc);
591 for (int iEve{0}; iEve < mcReader.getNEvents(iSrc); ++iEve) {
592 const auto& ir = irs[eveId2colId[iEve]];
593 if (!ir.isDummy()) { // do we need this, is this for diffractive events?
594 const auto& eve = mcReader.getMCEventHeader(iSrc, iEve);
595 auto bc = (ir - raw::HBFUtils::Instance().getFirstSampledTFIR()).toLong() - roFrameBiasInBC;
596 if (bc < 0) { // event happened before TF
597 continue;
598 }
599 Vertex vert;
600 vert.getTimeStamp().setTimeStamp(bc);
601 vert.getTimeStamp().setTimeStampError(roFrameLengthInBC / 2);
602 // set minimum to 1 sometimes for diffractive events there is nothing acceptance
603 vert.setNContributors(std::max(1L, std::ranges::count_if(mcReader.getTracks(iSrc, iEve), [](const auto& trk) {
604 if (!trk.isPrimary() || trk.GetPt() < 0.05 || std::abs(trk.GetEta()) > 1.1) {
605 return false;
606 }
607 const auto* p = o2::O2DatabasePDG::Instance()->GetParticle(trk.GetPdgCode());
608 return (!p) ? false : p->Charge() != 0;
609 })));
610 vert.setXYZ((float)eve.GetX(), (float)eve.GetY(), (float)eve.GetZ());
611 vert.setChi2(1); // not used as constraint
612 constexpr float cov = 25e-4;
613 vert.setSigmaX(cov);
614 vert.setSigmaY(cov);
615 vert.setSigmaZ(cov);
616 mTimeFrame->addPrimaryVertex(vert);
617 o2::MCCompLabel mcLbl(o2::MCCompLabel::maxTrackID(), iEve, iSrc, false);
618 VertexLabel lbl(mcLbl, 1.0);
619 mTimeFrame->addPrimaryVertexLabel(lbl);
620 }
621 mcReader.releaseTracksForSourceAndEvent(iSrc, iEve);
622 }
623 LOGP(info, "Imposed {} pv collisions from mc-truth", mTimeFrame->getPrimaryVertices().size());
624}
625
626template <int NLayers>
627void VertexerTraits<NLayers>::setNThreads(int n, std::shared_ptr<tbb::task_arena>& arena)
628{
629 if (arena == nullptr) {
630 mTaskArena = std::make_shared<tbb::task_arena>(std::abs(n));
631 LOGP(info, "Setting seeding vertexer with {} threads.", n);
632 } else {
633 mTaskArena = arena;
634 }
635}
636
637template <int NLayers>
638bool VertexerTraits<NLayers>::skipROF(int iteration, int rof) const
639{
640 return mVrtParams[iteration].PassFlags[IterationStep::SkipROFsAboveThreshold] &&
641 (int)mTimeFrame->getROFVertexLookupTableView().getVertices(1, rof).getEntries() > mVrtParams[iteration].vertPerRofThreshold;
642}
643
644template class VertexerTraits<7>;
645} // namespace o2::its
std::vector< std::string > labels
size_t minSize
uint64_t vertex
Definition RawEventData.h:9
uint64_t bc
Definition RawEventData.h:5
int32_t i
Mode
Definition Utils.h:89
uint32_t j
Definition RawData.h:0
Class to compute the primary vertex in ITS from tracklets.
int nClusters
static constexpr int maxTrackID()
static TDatabasePDG * Instance()
HMPID cluster implementation.
Definition Cluster.h:27
virtual void initialise(const TrackingParameters &trackingParams)
virtual void updateVertexingParameters(const std::vector< VertexingParameters > &vrtPar)
virtual void computeTracklets(const int iteration)
static DigitizationContext * loadFromFile(std::string_view filename="")
size_t getNEvents(int source) const
Get number of events.
o2::dataformats::MCEventHeader const & getMCEventHeader(int source, int event) const
retrieves the MCEventHeader for a given eventID and sourceID
void releaseTracksForSourceAndEvent(int source, int event)
API to ask releasing tracks (freeing memory) for source + event.
std::vector< MCTrack > const & getTracks(int source, int event) const
variant returning all tracks for source and event at once
GLdouble n
Definition glcorearb.h:1982
GLuint index
Definition glcorearb.h:781
GLuint GLsizei const GLchar * label
Definition glcorearb.h:2519
constexpr float TwoPI
std::pair< o2::MCCompLabel, float > VertexLabel
Definition Vertex.h:27
const float zDelta
return getBinsRect(layerIndex, currentCluster.phi, zMean, zDelta, maxdeltaphi, utils)
void deepVectorClear(std::vector< T > &vec)
std::vector< Cluster > getClusters(int event)
Common utility functions.
void empty(int)
int32_t w
std::shared_ptr< BoundedMemoryResource > memoryPool
o2::InteractionRecord ir(0, 0)
std::vector< Cluster > clusters
std::vector< Tracklet64 > tracklets