Project
Loading...
Searching...
No Matches
TrackFollower.h
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.
11
14
15#ifndef TRACKINGITSU_INCLUDE_TRACKFOLLOWER_H_
16#define TRACKINGITSU_INCLUDE_TRACKFOLLOWER_H_
17
18#include <cstdint>
19
20#include "GPUCommonDef.h"
21#include "GPUCommonMath.h"
23
24#include "ITStracking/Cluster.h"
31
32namespace o2::its
33{
34
35template <int NLayers>
36GPUhdi() void keepTrackExtensionHypothesis(const TrackExtensionHypothesis<NLayers>& hypo,
39 const int maxHypotheses)
40{
43 return;
44 }
45
46 int worst{0};
47 for (int i{1}; i < nKeptHypotheses; ++i) {
48 if (track::isBetter(keptHypotheses[worst].nClusters, keptHypotheses[worst].chi2, keptHypotheses[i].nClusters, keptHypotheses[i].chi2)) {
49 worst = i;
50 }
51 }
52 if (track::isBetter(hypo.nClusters, hypo.chi2, keptHypotheses[worst].nClusters, keptHypotheses[worst].chi2)) {
53 keptHypotheses[worst] = hypo;
54 }
55}
56
57template <int NLayers>
58GPUhdi() void updateTrackFromExtensionHypothesis(const TrackExtensionHypothesis<NLayers>& hypo,
59 const bool outward,
60 const int nLayers,
61 TrackITSInternal<NLayers>& track)
62{
63 if (outward) {
64 track.paramOut = hypo.param;
65 } else {
66 track.paramIn = hypo.param;
67 }
68 track.time = hypo.time;
69 track.setChi2(hypo.chi2);
70 for (int iLayer{0}; iLayer < nLayers; ++iLayer) {
71 if (track.getClusterIndex(iLayer) == constants::UnusedIndex && hypo.clusters[iLayer] != constants::UnusedIndex) {
72 track.setClusterIndex(iLayer, hypo.clusters[iLayer]);
73 }
74 }
75}
76
77// Search-specific inputs for track extension: cluster/ROF/index tables, layer
78// radii, and phi/z search cuts. Kept separate from the fit context so that
79// refit-only callers don't have to carry these fields.
80template <int NLayers>
85 const Cluster* const* clusters{nullptr};
86 const unsigned char* const* usedClusters{nullptr};
87 const int* const* clustersIndexTables{nullptr};
88 const int* const* ROFClusters{nullptr};
89 const float* layerRadii{nullptr};
90 int phiBins{0};
92 float nSigmaCutPhi{0.f};
93 float nSigmaCutZ{0.f};
94};
95
96template <int NLayers>
98 GPUdi() TrackExtensionBestTrial(uint32_t backupPattern, const track::TrackFitContext<NLayers>& fit)
99 : backupPattern{backupPattern}, fit{fit}
100 {
101 }
102
103 GPUdi() void update(TrackITSInternal<NLayers>& trial, TrackITSInternal<NLayers>& best, uint32_t& bestDiff) const
104 {
105 const auto diff = (trial.getPattern() & ~backupPattern) & TrackITS::getLayerPatternMask<NLayers>();
106 if (!diff || !track::refitTrack(trial, fit)) {
107 return;
108 }
109 if (track::isBetter(trial, best)) {
110 best = trial;
111 bestDiff = diff;
112 }
113 }
114
115 uint32_t backupPattern{0};
116 const track::TrackFitContext<NLayers>& fit;
117};
118
119template <int NLayers, typename FollowDirection, typename BestTrial>
120GPUdi() void followTrackExtensionBranches(const TrackITSInternal<NLayers>& backup,
121 const bool extendTop,
122 const bool extendBot,
123 const int nLayers,
124 FollowDirection& followDirection,
125 BestTrial& bestTrial,
127 uint32_t& bestDiff)
128{
129 const uint32_t lastLayer = static_cast<uint32_t>(nLayers - 1);
132 bool hasTopResult{false};
133 bool hasBotResult{false};
134
135 if (extendTop && backup.getLastClusterLayer() != lastLayer) {
136 auto candidate = backup;
137 if (followDirection(candidate, true)) {
138 topResult = candidate;
139 hasTopResult = true;
140 bestTrial.update(candidate, best, bestDiff);
141 }
142 }
143 if (extendBot && backup.getFirstClusterLayer() != 0) {
144 auto candidate = backup;
145 if (followDirection(candidate, false)) {
146 botResult = candidate;
147 hasBotResult = true;
148 bestTrial.update(candidate, best, bestDiff);
149 }
150 }
152 if (hasTopResult && topResult.getFirstClusterLayer() != 0) {
153 auto candidate = topResult;
154 if (followDirection(candidate, false)) {
155 bestTrial.update(candidate, best, bestDiff);
156 }
157 }
158 if (hasBotResult && botResult.getLastClusterLayer() != lastLayer) {
159 auto candidate = botResult;
160 if (followDirection(candidate, true)) {
161 bestTrial.update(candidate, best, bestDiff);
162 }
163 }
164 }
165}
166
167template <int NLayers>
168GPUhdi() bool followTrackExtensionDirection(const TrackExtensionHypothesis<NLayers>& startHypothesis,
169 const track::TrackFitContext<NLayers>& fit,
170 const TrackFollowContext<NLayers>& ctx,
171 const bool outward,
175{
176 const auto& utils = *ctx.utils;
177 const int step = outward ? 1 : -1;
178 const int end = outward ? fit.nLayers - 1 : 0;
179 const int maxHypotheses = o2::gpu::CAMath::Max(ctx.maxHypotheses, 1);
180 int nActive{1};
181 int nNext{0};
182 activeHypotheses[0] = startHypothesis;
183
184 const int tableSize = utils.getNphiBins() * utils.getNzBins() + 1;
185 for (int iLayer = activeHypotheses[0].edgeLayer + step; nActive > 0; iLayer += step) {
186 if ((step > 0 && iLayer > end) || (step < 0 && iLayer < end)) {
187 break;
188 }
189 nNext = 0;
190 for (int iHypo{0}; iHypo < nActive; ++iHypo) {
191 auto hypo = activeHypotheses[iHypo];
192 const float r = ctx.layerRadii[iLayer];
193 float x{-999.f};
194 if (!hypo.param.getXatLabR(r, x, fit.bz, o2::track::DirAuto) || x <= 0.f) {
195 continue;
196 }
197
198 if (!fit.propagator->propagateToX(hypo.param, x, fit.bz, o2::base::PropagatorF::MAX_SIN_PHI,
199 o2::base::PropagatorF::MAX_STEP, fit.matCorrType)) {
200 continue;
201 }
202 if (fit.matCorrType == o2::base::PropagatorF::MatCorrType::USEMatCorrNONE &&
203 !hypo.param.correctForMaterial(fit.layerxX0[iLayer], fit.layerxX0[iLayer] * constants::Radl * constants::Rho, true)) {
204 continue;
205 }
206
207 const float ePhi{o2::gpu::CAMath::Sqrt(hypo.param.getSigmaSnp2() / hypo.param.getCsp2())};
208 const float eZ{o2::gpu::CAMath::Sqrt(hypo.param.getSigmaZ2())};
209 const int4 selectedBins = getBinsRect(iLayer, hypo.param.getPhi(), hypo.param.getZ(), ctx.nSigmaCutZ * eZ, ctx.nSigmaCutPhi * ePhi, utils);
210 if (selectedBins.x < 0) {
211 continue;
212 }
213
214 int phiBinsNum = selectedBins.w - selectedBins.y + 1;
215 if (phiBinsNum < 0) {
216 phiBinsNum += ctx.phiBins;
217 }
218
219 const auto rofRange = ctx.rofOverlaps.getLayer(iLayer).getROFRange(hypo.time);
220 for (int rof = rofRange.getFirstEntry(); rof < rofRange.getEntriesBound(); ++rof) {
221 if (!ctx.rofMask.isROFEnabled(iLayer, rof)) {
222 continue;
223 }
224 const int rofStart = ctx.ROFClusters[iLayer][rof];
225 const int nLayerClusters = ctx.ROFClusters[iLayer][rof + 1] - rofStart;
226 if (nLayerClusters <= 0) {
227 continue;
228 }
229 const Cluster* layerClusters = ctx.clusters[iLayer] + rofStart;
230 const int* indexTable = ctx.clustersIndexTables[iLayer] + rof * tableSize;
231 const int zBinRange = selectedBins.z - selectedBins.x + 1;
232 for (int iPhiCount = 0; iPhiCount < phiBinsNum; ++iPhiCount) {
233 const int iPhiBin = (selectedBins.y + iPhiCount) % ctx.phiBins;
234 const int firstBinIndex = utils.getBinIndex(selectedBins.x, iPhiBin);
235 const int maxBinIndex = firstBinIndex + zBinRange;
236 const int firstRowClusterIndex = indexTable[firstBinIndex];
237 const int maxRowClusterIndex = indexTable[maxBinIndex];
238 for (int iNextCluster{firstRowClusterIndex}; iNextCluster < maxRowClusterIndex; ++iNextCluster) {
239 if (iNextCluster >= nLayerClusters) {
240 break;
241 }
242 const Cluster& nextCluster = layerClusters[iNextCluster];
243 if (ctx.usedClusters[iLayer][nextCluster.clusterId]) {
244 continue;
245 }
246
247 const TrackingFrameInfo& trackingHit = fit.tfInfos[iLayer][nextCluster.clusterId];
248 auto updated = hypo;
249 if (!updated.param.rotate(trackingHit.alphaTrackingFrame) ||
250 !fit.propagator->propagateToX(updated.param, trackingHit.xTrackingFrame, fit.bz,
253 fit.matCorrType)) {
254 continue;
255 }
256
257 const auto predChi2 = updated.param.getPredictedChi2Quiet(trackingHit.positionTrackingFrame, trackingHit.covarianceTrackingFrame);
258 if (predChi2 < 0.f || predChi2 > fit.maxChi2ClusterAttachment) {
259 continue;
260 }
261 if (!updated.param.o2::track::TrackParCov::update(trackingHit.positionTrackingFrame, trackingHit.covarianceTrackingFrame)) {
262 continue;
263 }
264 updated.chi2 += predChi2;
265 updated.clusters[iLayer] = nextCluster.clusterId;
266 ++updated.nClusters;
267 updated.edgeLayer = iLayer;
268 updated.time += ctx.rofOverlaps.getLayer(iLayer).getROFTimeBounds(rof, true);
269 keepTrackExtensionHypothesis(updated, nextHypotheses, nNext, maxHypotheses);
270 }
271 }
272 }
273 keepTrackExtensionHypothesis(hypo, nextHypotheses, nNext, maxHypotheses);
274 }
275 if (nNext == 0) {
276 break;
277 }
278 for (int iHypo{0}; iHypo < nNext; ++iHypo) {
279 activeHypotheses[iHypo] = nextHypotheses[iHypo];
280 }
281 nActive = nNext;
282 }
283
285 for (int iHypo{0}; iHypo < nActive; ++iHypo) {
286 const auto& hypo = activeHypotheses[iHypo];
287 if (hypo.nClusters == startHypothesis.nClusters) {
288 continue;
289 }
290 const float maxChi2 = fit.maxChi2NDF * static_cast<float>(hypo.nClusters * 2 - 5);
291 if (hypo.chi2 >= maxChi2) {
292 continue;
293 }
294 if (!bestHypo || track::isBetter(hypo.nClusters, hypo.chi2, bestHypo->nClusters, bestHypo->chi2)) {
295 bestHypo = &hypo;
296 }
297 }
298 if (!bestHypo) {
299 return false;
300 }
301
303 return true;
304}
305
306} // namespace o2::its
307
308#endif // TRACKINGITSU_INCLUDE_TRACKFOLLOWER_H_
int32_t i
#define GPUdi()
Shared host/device helpers for ITS tracker trait implementations.
int nClusters
static constexpr float MAX_SIN_PHI
Definition Propagator.h:72
static constexpr float MAX_STEP
Definition Propagator.h:73
GLint GLenum GLint x
Definition glcorearb.h:403
GLuint GLuint end
Definition glcorearb.h:469
typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode)
GLboolean r
Definition glcorearb.h:1233
constexpr int UnusedIndex
Definition Constants.h:32
constexpr float Radl
Definition Constants.h:34
constexpr float Rho
Definition Constants.h:35
const bool const bool const int FollowDirection BestTrial TrackITSInternal< NLayers > uint32_t & bestDiff
const int step
TrackExtensionHypothesis< NLayers > * keptHypotheses
const bool const int nLayers
const bool outward
const bool const bool const int FollowDirection BestTrial TrackITSInternal< NLayers > & best
GPUhdi() int IndexTableUtils< nLayers >
TrackExtensionHypothesis< NLayers > int const int maxHypotheses
const bool const int TrackITSInternal< NLayers > & track
const bool const bool extendBot
const track::TrackFitContext< NLayers > const TrackFollowContext< NLayers > const bool TrackExtensionHypothesis< NLayers > TrackExtensionHypothesis< NLayers > TrackExtensionHypothesis< NLayers > & bestHypothesis
const bool extendTop
return getBinsRect(layerIndex, currentCluster.phi, zMean, zDelta, maxdeltaphi, utils)
const TrackExtensionHypothesis< NLayers > * bestHypo
const bool const bool const int FollowDirection BestTrial & bestTrial
TrackITSInternal< NLayers > topResult
const int tableSize
const track::TrackFitContext< NLayers > const TrackFollowContext< NLayers > & ctx
bool hasBotResult
const track::TrackFitContext< NLayers > const TrackFollowContext< NLayers > const bool TrackExtensionHypothesis< NLayers > * activeHypotheses
bool hasTopResult
const track::TrackFitContext< NLayers > & fit
TrackITSInternal< NLayers > botResult
const track::TrackFitContext< NLayers > const TrackFollowContext< NLayers > const bool TrackExtensionHypothesis< NLayers > TrackExtensionHypothesis< NLayers > * nextHypotheses
TrackExtensionHypothesis< NLayers > int & nKeptHypotheses
const bool const bool const int FollowDirection & followDirection
Common utility functions.
int32_t y
int32_t z
int32_t x
int32_t w
GPUdi() TrackExtensionBestTrial(uint32_t backupPattern
const track::TrackFitContext< NLayers > & fit
const unsigned char *const * usedClusters
const Cluster *const * clusters
const int *const * ROFClusters
const int *const * clustersIndexTables
ROFMaskTable< NLayers >::View rofMask
ROFOverlapTable< NLayers >::View rofOverlaps
std::array< float, 2 > positionTrackingFrame
Definition Cluster.h:66
std::array< float, 3 > covarianceTrackingFrame
Definition Cluster.h:67