Project
Loading...
Searching...
No Matches
TrackHelpers.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.
15
16#ifndef O2_ITS_TRACKING_TRACKHELPERS_H_
17#define O2_ITS_TRACKING_TRACKHELPERS_H_
18
21#include "ITStracking/Cell.h"
22#include "ITStracking/Cluster.h"
29
31{
32
33GPUhdi() bool isBetter(const int nClustersA, const float chi2A, const int nClustersB, const float chi2B)
34{
35 return (nClustersA > nClustersB) || (nClustersA == nClustersB && chi2A < chi2B);
36}
37
38GPUhdi() bool isBetter(const auto& a, const auto& b)
39{
40 return isBetter(a.getNumberOfClusters(), a.getChi2(), b.getNumberOfClusters(), b.getChi2());
41}
42
43template <int NLayers>
45 float maxQ2Pt;
46 float maxChi2;
51
54 {
55 }
56
57 static GPUhdi() int getEffectiveTrackLength(LayerMask hitLayerMask, LayerMask excludedLayerMask)
58 {
59 if (hitLayerMask.empty()) {
60 return 0;
61 }
62 return hitLayerMask.length() - (LayerMask::span(hitLayerMask.first(), hitLayerMask.last()) & excludedLayerMask).count();
63 }
64
65 static GPUhdi() LayerMask getEffectiveHoleMask(LayerMask hitLayerMask, LayerMask excludedLayerMask)
66 {
67 return hitLayerMask.holeMask() & ~excludedLayerMask;
68 }
69
70 GPUhd() bool operator()(const TrackSeed<NLayers>& seed) const
71 {
72 const auto hitLayerMask = seed.getHitLayerMask();
73 return !(seed.getQ2Pt() > maxQ2Pt || seed.getChi2() > maxChi2) &&
74 getEffectiveTrackLength(hitLayerMask, nonSeedingLayerMask) >= minTrackLength &&
75 getEffectiveHoleMask(hitLayerMask, nonSeedingLayerMask).isAllowedHoleMask(maxHoles, holeLayerMask);
76 }
77};
78
79// Find the populated interior layer closest to the radial midpoint.
80// If no layer can be found, return constants::UnusedIndex.
81// Should minimize the sagitta bias.
82template <int NLayers>
83GPUdi() int selectReseedMidLayer(int minLayer, int maxLayer, const float* layerRadii, const TrackSeed<NLayers>& seed)
84{
86 float distanceToMidR = layerRadii[NLayers - 1]; // midpoint cannot be last layer
87 const float midR = 0.5f * (layerRadii[maxLayer] + layerRadii[minLayer]);
88 for (int iLayer = minLayer + 1; iLayer < maxLayer; ++iLayer) {
89 if (seed.getCluster(iLayer) != constants::UnusedIndex) {
90 const float distance = o2::gpu::CAMath::Abs(midR - layerRadii[iLayer]);
91 if (distance < distanceToMidR) { // keep the smaller-radius layer on ties
92 midLayer = iLayer;
94 }
95 }
96 }
97 return midLayer;
98}
99
101{
102 track.resetCovariance();
104}
105
106GPUdi() o2::track::TrackParCov buildTrackSeed(const Cluster& cluster1,
107 const Cluster& cluster2,
108 const TrackingFrameInfo& tf3,
109 const float bz,
110 const bool reverse = false)
111{
113 o2::gpu::CAMath::SinCos(tf3.alphaTrackingFrame, sa, ca);
114 const float sign = reverse ? -1.f : 1.f;
115 const float x1 = (cluster1.xCoordinate * ca) + (cluster1.yCoordinate * sa);
116 const float y1 = (-cluster1.xCoordinate * sa) + (cluster1.yCoordinate * ca);
117 const float x2 = (cluster2.xCoordinate * ca) + (cluster2.yCoordinate * sa);
118 const float y2 = (-cluster2.xCoordinate * sa) + (cluster2.yCoordinate * ca);
119 const float x3 = tf3.xTrackingFrame;
120 const float y3 = tf3.positionTrackingFrame[0];
121 if (o2::gpu::CAMath::Abs(bz) < 0.01f) { // zero field
122 const float dx = x3 - x1;
123 const float dy = y3 - y1;
124 snp = sign * dy / o2::gpu::CAMath::Hypot(dx, dy);
125 q2pt = 1.f / o2::track::kMostProbablePt;
126 q2pt2 = 1.f;
127 } else {
128 const float crv = math_utils::computeCurvature(x3, y3, x2, y2, x1, y1);
129 snp = sign * crv * (x3 - math_utils::computeCurvatureCentreX(x3, y3, x2, y2, x1, y1));
130 q2pt = sign * crv / (bz * o2::constants::math::B2C);
131 q2pt2 = crv * crv;
132 }
133 const float tgl = -0.5f * sign * (math_utils::computeTanDipAngle(x1, y1, x2, y2, cluster1.zCoordinate, cluster2.zCoordinate) + math_utils::computeTanDipAngle(x2, y2, x3, y3, cluster2.zCoordinate, tf3.positionTrackingFrame[1]));
134 const float sg2q2pt = o2::track::kC1Pt2max * o2::gpu::CAMath::Clamp(q2pt2, 0.0005f, 1.0f);
135 return {x3, tf3.alphaTrackingFrame, {y3, tf3.positionTrackingFrame[1], snp, tgl, q2pt}, {tf3.covarianceTrackingFrame[0], tf3.covarianceTrackingFrame[1], tf3.covarianceTrackingFrame[2], 0.f, 0.f, o2::track::kCSnp2max, 0.f, 0.f, 0.f, o2::track::kCTgl2max, 0.f, 0.f, 0.f, 0.f, sg2q2pt}};
136}
137
138template <int NLayers>
139GPUdi() TrackITSInternal<NLayers> seedTrackForRefit(const TrackSeed<NLayers>& seed,
142 const float* layerRadii,
143 const float bz,
145{
148 int lrMin = NLayers;
149 int lrMax = 0;
150 for (int iL{0}; iL < NLayers; ++iL) {
151 const int idx = seed.getCluster(iL);
152 temporaryTrack.setClusterIndex(iL, idx);
153 if (idx != constants::UnusedIndex) {
154 lrMin = o2::gpu::CAMath::Min(lrMin, iL);
155 lrMax = o2::gpu::CAMath::Max(lrMax, iL);
156 }
157 }
158
159 const int ncl = temporaryTrack.getNClusters();
160 if (ncl < reseedIfShorter && ncl > 2) {
161 const int lrMid = selectReseedMidLayer<NLayers>(lrMin, lrMax, layerRadii, seed);
162 if (lrMid != constants::UnusedIndex) {
163 const auto& cluster0TF = foundTrackingFrameInfo[lrMin][seed.getCluster(lrMin)];
164 const auto& cluster1GL = unsortedClusters[lrMid][seed.getCluster(lrMid)];
165 const auto& cluster2GL = unsortedClusters[lrMax][seed.getCluster(lrMax)];
166 temporaryTrack.paramIn = buildTrackSeed(cluster2GL, cluster1GL, cluster0TF, bz, true);
167 }
168 }
169
172}
173
174// Inputs shared by fit/refit calls within a tracking pass.
175template <int NLayers>
177 const TrackingFrameInfo* const* tfInfos{nullptr};
178 const float* layerxX0{nullptr};
179 int nLayers{0};
180 float bz{0.f};
182 float maxChi2NDF{0.f};
184 o2::base::PropagatorF::MatCorrType matCorrType{o2::base::PropagatorF::MatCorrType::USEMatCorrNONE};
185 bool shiftRefToCluster{false};
186 bool repeatRefitOut{false};
187};
188
189template <int NLayers>
190GPUdi() bool fitTrack(TrackITSInternal<NLayers>& trk,
192 int start,
193 int end,
194 int step,
196 int nCl,
197 const TrackFitContext<NLayers>& ctx,
198 o2::track::TrackPar* linRef = nullptr)
199{
200 for (int iLayer{start}; iLayer != end; iLayer += step) {
201 const int clsIdx = trk.getClusterIndex(iLayer);
202 if (clsIdx == constants::UnusedIndex) {
203 continue;
204 }
205
206 const TrackingFrameInfo& trackingHit = ctx.tfInfos[iLayer][clsIdx];
207 if (linRef) {
208 if (!param.o2::track::TrackParCovF::rotate(trackingHit.alphaTrackingFrame, *linRef, ctx.bz)) {
209 return false;
210 }
211 if (!ctx.propagator->propagateToX(param, *linRef, trackingHit.xTrackingFrame, ctx.bz,
214 ctx.matCorrType)) {
215 return false;
216 }
217 if (ctx.matCorrType == o2::base::PropagatorF::MatCorrType::USEMatCorrNONE) {
218 if (!param.correctForMaterial(*linRef, ctx.layerxX0[iLayer], ctx.layerxX0[iLayer] * constants::Radl * constants::Rho, true)) {
219 continue;
220 }
221 }
222 } else {
223 if (!param.o2::track::TrackParCovF::rotate(trackingHit.alphaTrackingFrame)) {
224 return false;
225 }
226 if (!ctx.propagator->propagateToX(param, trackingHit.xTrackingFrame, ctx.bz,
229 ctx.matCorrType)) {
230 return false;
231 }
232 if (ctx.matCorrType == o2::base::PropagatorF::MatCorrType::USEMatCorrNONE) {
233 if (!param.correctForMaterial(ctx.layerxX0[iLayer], ctx.layerxX0[iLayer] * constants::Radl * constants::Rho, true)) {
234 continue;
235 }
236 }
237 }
238
239 const auto predChi2{param.getPredictedChi2Quiet(trackingHit.positionTrackingFrame, trackingHit.covarianceTrackingFrame)};
240 if ((nCl >= 3 && predChi2 > ctx.maxChi2ClusterAttachment) || predChi2 < 0.f) {
241 return false;
242 }
243 trk.setChi2(trk.getChi2() + predChi2);
244 if (!param.o2::track::TrackParCov::update(trackingHit.positionTrackingFrame, trackingHit.covarianceTrackingFrame)) {
245 return false;
246 }
247 if (linRef && ctx.shiftRefToCluster) {
248 linRef->setY(trackingHit.positionTrackingFrame[0]);
249 linRef->setZ(trackingHit.positionTrackingFrame[1]);
250 }
251 nCl++;
252 }
253
254 return o2::gpu::CAMath::Abs(param.getQ2Pt()) < maxQoverPt && trk.getChi2() < ctx.maxChi2NDF * (float)((nCl * 2) - 5);
255}
256
257template <int NLayers>
258GPUdi() bool refitTrack(TrackITSInternal<NLayers>& track,
259 const TrackFitContext<NLayers>& ctx,
260 const float minPt = -1.f)
261{
262 o2::track::TrackPar linRef{track.paramIn};
263 resetTrackCovariance(track.paramIn);
264 track.setChi2(0);
265 bool fitSuccess = fitTrack(track, track.paramIn, 0, ctx.nLayers, 1,
266 o2::constants::math::VeryBig, 0, ctx, &linRef);
267 if (!fitSuccess) {
268 return false;
269 }
270
271 track.paramOut = track.paramIn;
272 linRef = track.paramOut;
273 resetTrackCovariance(track.paramIn);
274 track.setChi2(0);
275 fitSuccess = fitTrack(track, track.paramIn, ctx.nLayers - 1, -1, -1,
276 50.f, 0, ctx, &linRef);
277 if (!fitSuccess) {
278 return false;
279 }
280 if (minPt > 0.f && track.getPt() < minPt) {
281 return false;
282 }
283 if (ctx.repeatRefitOut) { // repeat outward refit seeding and linearizing with the stable inward fit result
284 o2::track::TrackParCov saveInw{track.paramIn};
285 linRef = saveInw; // use refitted track as lin.reference
286 float saveChi2 = track.getChi2();
287 track.paramOut = saveInw;
289 track.setChi2(0);
290 fitSuccess = fitTrack(track, track.paramOut, 0, ctx.nLayers, 1,
291 o2::constants::math::VeryBig, 0, ctx, &linRef);
292 if (!fitSuccess) {
293 return false;
294 }
295 track.paramIn = saveInw;
296 track.setChi2(saveChi2);
297 }
298 return true;
299}
300
301template <int NLayers>
302GPUdi() bool refitTrackSeed(const TrackSeed<NLayers>& trackSeed,
303 TrackITSInternal<NLayers>& temporaryTrack,
304 const TrackFitContext<NLayers>& ctx,
305 const Cluster* const* clusters,
306 const float* layerRadii,
307 const float* minPt,
308 const int reseedIfShorter)
309{
310 temporaryTrack = seedTrackForRefit(trackSeed,
311 ctx.tfInfos,
312 clusters,
314 ctx.bz,
316 return refitTrack(temporaryTrack, ctx, minPt[NLayers - temporaryTrack.getNClusters()]);
317}
318
319} // namespace o2::its::track
320
321#endif
Base track model for the Barrel, params only, w/o covariance.
useful math constants
o2::track::TrackParCov TrackParCov
Definition Recon.h:39
std::array< int, 64 > reverse(std::array< int, 64 > a)
Definition of the ITS track.
HMPID cluster implementation.
Definition Cluster.h:27
GLint GLsizei count
Definition glcorearb.h:399
GLuint GLfloat GLfloat GLfloat GLfloat y1
Definition glcorearb.h:5034
GLuint GLuint end
Definition glcorearb.h:469
GLuint GLfloat GLfloat GLfloat x1
Definition glcorearb.h:5034
GLdouble f
Definition glcorearb.h:310
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
GLsizei GLsizei GLfloat distance
Definition glcorearb.h:5506
typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode)
GLuint start
Definition glcorearb.h:469
GLenum GLfloat param
Definition glcorearb.h:271
GLboolean GLboolean GLboolean GLboolean a
Definition glcorearb.h:1233
constexpr float B2C
constexpr float VeryBig
constexpr int UnusedIndex
Definition Constants.h:32
constexpr float Radl
Definition Constants.h:34
constexpr float Rho
Definition Constants.h:35
constexpr float UnsetValue
Definition Constants.h:33
o2::track::TrackParCov int int int float maxQoverPt
const TrackingFrameInfo *const * foundTrackingFrameInfo
resetTrackCovariance(temporaryTrack.paramIn)
const TrackingFrameInfo *const const Cluster *const * unsortedClusters
int const float * layerRadii
return temporaryTrack
GPUhdi() bool isBetter(const int nClustersA
int const float const TrackSeed< NLayers > & seed
const float const int nClustersB
o2::track::TrackParCov int int int float int const TrackFitContext< NLayers > & ctx
o2::track::TrackParCov int int end
o2::track::TrackParCov int int int step
const float chi2A
const TrackingFrameInfo *const const Cluster *const const float const float const int reseedIfShorter
const float const int const float chi2B
const float midR
o2::track::TrackParCov int int int float int nCl
const TrackingFrameInfo *const const Cluster *const const float const float bz
GPUdi() int selectReseedMidLayer(int minLayer
const bool const int TrackITSInternal< NLayers > & track
constexpr float kCTgl2max
TrackParCovF TrackParCov
Definition Track.h:33
constexpr float kCSnp2max
constexpr float kMostProbablePt
constexpr float kC1Pt2max
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
o2::track::TrackParCov paramIn
std::array< float, 2 > positionTrackingFrame
Definition Cluster.h:66
std::array< float, 3 > covarianceTrackingFrame
Definition Cluster.h:67
o2::base::PropagatorF::MatCorrType matCorrType
const TrackingFrameInfo *const * tfInfos
const o2::base::Propagator * propagator
GPUhd() TrackSeedSelector(float maxQ2Pt
std::vector< Cluster > clusters