Project
Loading...
Searching...
No Matches
TrackParametrization.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 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
16
20#include <MathUtils/Cartesian.h>
21#include <GPUCommonLogger.h>
22
23#ifndef GPUCA_GPUCODE_DEVICE
24#include <iostream>
25#endif
26
27#ifndef GPUCA_ALIGPUCODE
28#include <fmt/printf.h>
29#endif
30
31using namespace o2::gpu;
32using namespace o2::track;
33
34//______________________________________________________________
35template <typename value_T>
36GPUd() TrackParametrization<value_T>::TrackParametrization(const dim3_t& xyz, const dim3_t& pxpypz, int charge, bool sectorAlpha, const PID pid)
37 : mX{0.f}, mAlpha{0.f}, mP{0.f}
38{
39 // construct track param from kinematics
40
41 // Alpha of the frame is defined as:
42 // sectorAlpha == false : -> angle of pt direction
43 // sectorAlpha == true : -> angle of the sector from X,Y coordinate for r>1
44 // angle of pt direction for r==0
45 //
46 //
47 constexpr value_t kSafe = 1e-5;
48 value_t radPos2 = xyz[0] * xyz[0] + xyz[1] * xyz[1];
49 value_t alp = 0;
50 if (sectorAlpha || radPos2 < 1) {
51 alp = gpu::CAMath::ATan2(pxpypz[1], pxpypz[0]);
52 } else {
53 alp = gpu::CAMath::ATan2(xyz[1], xyz[0]);
54 }
55 if (sectorAlpha) {
56 alp = math_utils::detail::angle2Alpha<value_t>(alp);
57 }
58 //
59 value_t sn, cs;
60 math_utils::detail::sincos(alp, sn, cs);
61 // protection against cosp<0
62 if (cs * pxpypz[0] + sn * pxpypz[1] < 0) {
63 LOG(debug) << "alpha from phiPos() will invalidate this track parameters, overriding to alpha from phi()";
64 alp = gpu::CAMath::ATan2(pxpypz[1], pxpypz[0]);
65 if (sectorAlpha) {
66 alp = math_utils::detail::angle2Alpha<value_t>(alp);
67 }
68 math_utils::detail::sincos(alp, sn, cs);
69 }
70
71 // protection: avoid alpha being too close to 0 or +-pi/2
72 if (gpu::CAMath::Abs(sn) < 2 * kSafe) {
73 if (alp > 0) {
74 alp += alp < constants::math::PIHalf ? 2 * kSafe : -2 * kSafe;
75 } else {
76 alp += alp > -constants::math::PIHalf ? -2 * kSafe : 2 * kSafe;
77 }
78 math_utils::detail::sincos(alp, sn, cs);
79 } else if (gpu::CAMath::Abs(cs) < 2 * kSafe) {
80 if (alp > 0) {
81 alp += alp > constants::math::PIHalf ? 2 * kSafe : -2 * kSafe;
82 } else {
83 alp += alp > -constants::math::PIHalf ? 2 * kSafe : -2 * kSafe;
84 }
85 math_utils::detail::sincos(alp, sn, cs);
86 }
87 // get the vertex of origin and the momentum
88 dim3_t ver{xyz[0], xyz[1], xyz[2]};
89 dim3_t mom{pxpypz[0], pxpypz[1], pxpypz[2]};
90 //
91 // Rotate to the local coordinate system
92 math_utils::detail::rotateZ<value_t>(ver, -alp);
93 math_utils::detail::rotateZ<value_t>(mom, -alp);
94 //
95 value_t ptI = 1.f / gpu::CAMath::Sqrt(mom[0] * mom[0] + mom[1] * mom[1]);
96 mX = ver[0];
97 mAlpha = alp;
98 mP[kY] = ver[1];
99 mP[kZ] = ver[2];
100 mP[kSnp] = mom[1] * ptI;
101 mP[kTgl] = mom[2] * ptI;
102 mAbsCharge = gpu::CAMath::Abs(charge);
103 mP[kQ2Pt] = charge ? ptI * charge : ptI;
104 mPID = pid;
105 //
106 if (gpu::CAMath::Abs(1 - getSnp()) < kSafe) {
107 mP[kSnp] = 1.f - kSafe; // Protection
108 } else if (gpu::CAMath::Abs(-1 - getSnp()) < kSafe) {
109 mP[kSnp] = -1.f + kSafe; // Protection
110 }
111 //
112}
113
114//_______________________________________________________
115template <typename value_T>
116GPUd() bool TrackParametrization<value_T>::getPxPyPzGlo(dim3_t& pxyz) const
117{
118 // track momentum
119 if (gpu::CAMath::Abs(getQ2Pt()) < constants::math::Almost0 || gpu::CAMath::Abs(getSnp()) > constants::math::Almost1) {
120 return false;
121 }
122 value_t cs, sn, pt = getPt();
123 value_t r = gpu::CAMath::Sqrt((1.f - getSnp()) * (1.f + getSnp()));
124 math_utils::detail::sincos(getAlpha(), sn, cs);
125 pxyz[0] = pt * (r * cs - getSnp() * sn);
126 pxyz[1] = pt * (getSnp() * cs + r * sn);
127 pxyz[2] = pt * getTgl();
128 return true;
129}
130
131//____________________________________________________
132template <typename value_T>
133GPUd() bool TrackParametrization<value_T>::getPosDirGlo(std::array<value_t, 9>& posdirp) const
134{
135 // fill vector with lab x,y,z,px/p,py/p,pz/p,p,sinAlpha,cosAlpha
136 value_t ptI = getPtInv();
137 value_t snp = getSnp();
138 if (gpu::CAMath::Abs(snp) > constants::math::Almost1) {
139 return false;
140 }
141 value_t &sn = posdirp[7], &cs = posdirp[8];
142 value_t csp = gpu::CAMath::Sqrt((1.f - snp) * (1.f + snp));
143 value_t cstht = gpu::CAMath::Sqrt(1.f + getTgl() * getTgl());
144 value_t csthti = 1.f / cstht;
145 math_utils::detail::sincos(getAlpha(), sn, cs);
146 posdirp[0] = getX() * cs - getY() * sn;
147 posdirp[1] = getX() * sn + getY() * cs;
148 posdirp[2] = getZ();
149 posdirp[3] = (csp * cs - snp * sn) * csthti; // px/p
150 posdirp[4] = (snp * cs + csp * sn) * csthti; // py/p
151 posdirp[5] = getTgl() * csthti; // pz/p
152 posdirp[6] = cstht / ptI; // p
153 return true;
154}
155
156//______________________________________________________________
157template <typename value_T>
158GPUd() bool TrackParametrization<value_T>::rotateParam(value_t alpha)
159{
160 // rotate to alpha frame
161 if (gpu::CAMath::Abs(getSnp()) > constants::math::Almost1) {
162 LOGP(debug, "Precondition is not satisfied: |sin(phi)|>1 ! {:f}", getSnp());
163 return false;
164 }
165 //
166 math_utils::detail::bringToPMPi<value_t>(alpha);
167 //
168 value_t ca = 0, sa = 0;
169 math_utils::detail::sincos(alpha - getAlpha(), sa, ca);
170 value_t snp = getSnp(), csp = gpu::CAMath::Sqrt((1.f - snp) * (1.f + snp)); // Improve precision
171 // RS: check if rotation does no invalidate track model (cos(local_phi)>=0, i.e. particle
172 // direction in local frame is along the X axis
173 if ((csp * ca + snp * sa) < 0) {
174 // LOGF(warning,"Rotation failed: local cos(phi) would become {:.2f}", csp * ca + snp * sa);
175 return false;
176 }
177 //
178 value_t tmp = snp * ca - csp * sa;
179 if (gpu::CAMath::Abs(tmp) > constants::math::Almost1) {
180 LOGP(debug, "Rotation failed: new snp {:.2f}", tmp);
181 return false;
182 }
183 value_t xold = getX(), yold = getY();
184 mAlpha = alpha;
185 mX = xold * ca + yold * sa;
186 mP[kY] = -xold * sa + yold * ca;
187 mP[kSnp] = tmp;
188 return true;
189}
190
191//______________________________________________________________
192template <typename value_T>
193GPUd() bool TrackParametrization<value_T>::rotateParam(value_t& alpha, value_t& ca, value_t& sa)
194{
195 // rotate to alpha frame
196 if (gpu::CAMath::Abs(getSnp()) > constants::math::Almost1) {
197 LOGP(debug, "Precondition is not satisfied: |sin(phi)|>1 ! {:f}", getSnp());
198 return false;
199 }
200 //
201 math_utils::detail::bringToPMPi<value_t>(alpha);
202 math_utils::detail::sincos(alpha - getAlpha(), sa, ca);
203 value_t snp = getSnp(), csp = gpu::CAMath::Sqrt((1.f - snp) * (1.f + snp)); // Improve precision
204 // RS: check if rotation does no invalidate track model (cos(local_phi)>=0, i.e. particle direction in local frame is along the X axis
205 if ((csp * ca + snp * sa) < 0) {
206 // LOGF(warning,"Rotation failed: local cos(phi) would become {:.2f}", csp * ca + snp * sa);
207 return false;
208 }
209 //
210 value_t tmp = snp * ca - csp * sa;
211 if (gpu::CAMath::Abs(tmp) > constants::math::Almost1) {
212 LOGP(debug, "Rotation failed: new snp {:.2f}", tmp);
213 return false;
214 }
215 value_t xold = getX(), yold = getY();
216 mAlpha = alpha;
217 mX = xold * ca + yold * sa;
218 mP[kY] = -xold * sa + yold * ca;
219 mP[kSnp] = tmp;
220 return true;
221}
222
223//____________________________________________________________
224template <typename value_T>
225GPUd() bool TrackParametrization<value_T>::propagateParamTo(value_t xk, const dim3_t& b)
226{
227 //----------------------------------------------------------------
228 // Extrapolate this track params (w/o cov matrix) to the plane X=xk in the field b[].
229 //
230 // X [cm] is in the "tracking coordinate system" of this track.
231 // b[]={Bx,By,Bz} [kG] is in the Global coordidate system.
232 //----------------------------------------------------------------
233 value_t dx = xk - getX();
234 if (gpu::CAMath::Abs(dx) < constants::math::Almost0) {
235 return true;
236 }
237 // Do not propagate tracks outside the ALICE detector
238 if (gpu::CAMath::Abs(dx) > 1e5 || gpu::CAMath::Abs(getY()) > 1e5 || gpu::CAMath::Abs(getZ()) > 1e5) {
239 LOG(warning) << "Anomalous track, traget X:" << xk;
240 return false;
241 }
242 value_t crv = getCurvature(b[2]);
243 if (crv == 0.) {
244 return propagateParamTo(xk, 0.); // for the straight-line propagation use 1D field method
245 }
246
247 value_t x2r = crv * dx;
248 value_t f1 = getSnp(), f2 = f1 + x2r;
249 if (gpu::CAMath::Abs(f1) > constants::math::Almost1 || gpu::CAMath::Abs(f2) > constants::math::Almost1) {
250 return false;
251 }
252 value_t r1 = gpu::CAMath::Sqrt((1.f - f1) * (1.f + f1));
253 if (gpu::CAMath::Abs(r1) < constants::math::Almost0) {
254 return false;
255 }
256 value_t r2 = gpu::CAMath::Sqrt((1.f - f2) * (1.f + f2));
257 if (gpu::CAMath::Abs(r2) < constants::math::Almost0) {
258 return false;
259 }
260 value_t dy2dx = (f1 + f2) / (r1 + r2);
261 value_t step = (gpu::CAMath::Abs(x2r) < 0.05f) ? dx * gpu::CAMath::Abs(r2 + f2 * dy2dx) // chord
262 : 2.f * CAMath::ASin(0.5f * dx * gpu::CAMath::Sqrt(1.f + dy2dx * dy2dx) * crv) / crv; // arc
263 step *= gpu::CAMath::Sqrt(1.f + getTgl() * getTgl());
264 //
265 // get the track x,y,z,px/p,py/p,pz/p,p,sinAlpha,cosAlpha in the Global System
266 std::array<value_t, 9> vecLab{0.f};
267 if (!getPosDirGlo(vecLab)) {
268 return false;
269 }
270
271 // rotate to the system where Bx=By=0.
272 value_t bxy2 = b[0] * b[0] + b[1] * b[1];
273 value_t bt = gpu::CAMath::Sqrt(bxy2);
274 value_t cosphi = 1.f, sinphi = 0.f;
275 if (bt > constants::math::Almost0) {
276 cosphi = b[0] / bt;
277 sinphi = b[1] / bt;
278 }
279 value_t bb = gpu::CAMath::Sqrt(bxy2 + b[2] * b[2]);
280 value_t costet = 1.f, sintet = 0.f;
281 if (bb > constants::math::Almost0) {
282 costet = b[2] / bb;
283 sintet = bt / bb;
284 }
285 std::array<value_t, 7> vect{costet * cosphi * vecLab[0] + costet * sinphi * vecLab[1] - sintet * vecLab[2],
286 -sinphi * vecLab[0] + cosphi * vecLab[1],
287 sintet * cosphi * vecLab[0] + sintet * sinphi * vecLab[1] + costet * vecLab[2],
288 costet * cosphi * vecLab[3] + costet * sinphi * vecLab[4] - sintet * vecLab[5],
289 -sinphi * vecLab[3] + cosphi * vecLab[4],
290 sintet * cosphi * vecLab[3] + sintet * sinphi * vecLab[4] + costet * vecLab[5],
291 vecLab[6]};
292
293 // Do the helix step
294 value_t q = getCharge();
295 g3helx3(q * bb, step, vect);
296
297 // rotate back to the Global System
298 vecLab[0] = cosphi * costet * vect[0] - sinphi * vect[1] + cosphi * sintet * vect[2];
299 vecLab[1] = sinphi * costet * vect[0] + cosphi * vect[1] + sinphi * sintet * vect[2];
300 vecLab[2] = -sintet * vect[0] + costet * vect[2];
301
302 vecLab[3] = cosphi * costet * vect[3] - sinphi * vect[4] + cosphi * sintet * vect[5];
303 vecLab[4] = sinphi * costet * vect[3] + cosphi * vect[4] + sinphi * sintet * vect[5];
304 vecLab[5] = -sintet * vect[3] + costet * vect[5];
305
306 // rotate back to the Tracking System
307 value_t sinalp = -vecLab[7], cosalp = vecLab[8];
308 value_t t = cosalp * vecLab[0] - sinalp * vecLab[1];
309 vecLab[1] = sinalp * vecLab[0] + cosalp * vecLab[1];
310 vecLab[0] = t;
311 t = cosalp * vecLab[3] - sinalp * vecLab[4];
312 vecLab[4] = sinalp * vecLab[3] + cosalp * vecLab[4];
313 vecLab[3] = t;
314
315 // Do the final correcting step to the target plane (linear approximation)
316 value_t x = vecLab[0], y = vecLab[1], z = vecLab[2];
317 if (gpu::CAMath::Abs(dx) > constants::math::Almost0) {
318 if (gpu::CAMath::Abs(vecLab[3]) < constants::math::Almost0) {
319 return false;
320 }
321 dx = xk - vecLab[0];
322 x += dx;
323 y += vecLab[4] / vecLab[3] * dx;
324 z += vecLab[5] / vecLab[3] * dx;
325 }
326
327 // Calculate the track parameters
328 t = 1.f / gpu::CAMath::Sqrt(vecLab[3] * vecLab[3] + vecLab[4] * vecLab[4]);
329 mX = xk;
330 mP[kY] = y;
331 mP[kZ] = z;
332 mP[kSnp] = vecLab[4] * t;
333 mP[kTgl] = vecLab[5] * t;
334 mP[kQ2Pt] = q * t / vecLab[6];
335
336 return true;
337}
338
339//____________________________________________________________
340template <typename value_T>
341GPUd() bool TrackParametrization<value_T>::propagateParamTo(value_t xk, value_t b)
342{
343 //----------------------------------------------------------------
344 // propagate this track to the plane X=xk (cm) in the field "b" (kG)
345 // Only parameters are propagated, not the matrix. To be used for small
346 // distances only (<mm, i.e. misalignment)
347 //----------------------------------------------------------------
348 value_t dx = xk - getX();
349 if (gpu::CAMath::Abs(dx) < constants::math::Almost0) {
350 return true;
351 }
352 value_t crv = (gpu::CAMath::Abs(b) < constants::math::Almost0) ? 0.f : getCurvature(b);
353 value_t x2r = crv * dx;
354 value_t f1 = getSnp(), f2 = f1 + x2r;
355 if ((gpu::CAMath::Abs(f1) > constants::math::Almost1) || (gpu::CAMath::Abs(f2) > constants::math::Almost1)) {
356 return false;
357 }
358 value_t r1 = gpu::CAMath::Sqrt((1.f - f1) * (1.f + f1));
359 if (gpu::CAMath::Abs(r1) < constants::math::Almost0) {
360 return false;
361 }
362 value_t r2 = gpu::CAMath::Sqrt((1.f - f2) * (1.f + f2));
363 if (gpu::CAMath::Abs(r2) < constants::math::Almost0) {
364 return false;
365 }
366 double dy2dx = (f1 + f2) / (r1 + r2);
367 bool arcz = gpu::CAMath::Abs(x2r) > 0.05f;
368 if (arcz) {
369 // for small dx/R the linear apporximation of the arc by the segment is OK,
370 // but at large dx/R the error is very large and leads to incorrect Z propagation
371 // angle traversed delta = 2*asin(dist_start_end / R / 2), hence the arc is: R*deltaPhi
372 // The dist_start_end is obtained from sqrt(dx^2+dy^2) = x/(r1+r2)*sqrt(2+f1*f2+r1*r2)
373 // double chord = dx*TMath::Sqrt(1+dy2dx*dy2dx); // distance from old position to new one
374 // double rot = 2*TMath::ASin(0.5*chord*crv); // angular difference seen from the circle center
375 // track1 += rot/crv*track3;
376 //
377 auto arg = r1 * f2 - r2 * f1;
378 if (gpu::CAMath::Abs(arg) > constants::math::Almost1) {
379 return false;
380 }
381 value_t rot = CAMath::ASin(arg); // more economic version from Yura.
382 if (f1 * f1 + f2 * f2 > 1.f && f1 * f2 < 0.f) { // special cases of large rotations or large abs angles
383 if (f2 > 0.f) {
384 rot = constants::math::PI - rot; //
385 } else {
386 rot = -constants::math::PI - rot;
387 }
388 }
389 mP[kZ] += getTgl() / crv * rot;
390 } else {
391 mP[kZ] += dx * (r2 + f2 * dy2dx) * getTgl();
392 }
393 mX = xk;
394 mP[kY] += dx * dy2dx;
395 mP[kSnp] += x2r;
396 return true;
397}
398
399//_______________________________________________________________________
400template <typename value_T>
401GPUd() bool TrackParametrization<value_T>::propagateParamToDCA(const math_utils::Point3D<value_t>& vtx, value_t b, dim2_t* dca, value_t maxD)
402{
403 // propagate track to DCA to the vertex
404 value_t sn, cs, alp = getAlpha();
405 math_utils::detail::sincos(alp, sn, cs);
406 value_t x = getX(), y = getY(), snp = getSnp(), csp = gpu::CAMath::Sqrt((1.f - snp) * (1.f + snp));
407 value_t xv = vtx.X() * cs + vtx.Y() * sn, yv = -vtx.X() * sn + vtx.Y() * cs, zv = vtx.Z();
408 x -= xv;
409 y -= yv;
410 // Estimate the impact parameter neglecting the track curvature
411 value_t d = gpu::CAMath::Abs(x * snp - y * csp);
412 if (d > maxD) {
413 if (dca) { // provide default DCA for failed propag
414 (*dca)[0] = o2::track::DefaultDCA;
415 (*dca)[1] = o2::track::DefaultDCA;
416 }
417 return false;
418 }
419 value_t crv = getCurvature(b);
420 value_t tgfv = -(crv * x - snp) / (crv * y + csp);
421 sn = tgfv / gpu::CAMath::Sqrt(1.f + tgfv * tgfv);
422 cs = gpu::CAMath::Sqrt((1.f - sn) * (1.f + sn));
423 cs = (gpu::CAMath::Abs(tgfv) > constants::math::Almost0) ? sn / tgfv : constants::math::Almost1;
424
425 x = xv * cs + yv * sn;
426 yv = -xv * sn + yv * cs;
427 xv = x;
428
429 auto tmpT(*this); // operate on the copy to recover after the failure
430 alp += gpu::CAMath::ASin(sn);
431 if (!tmpT.rotateParam(alp) || !tmpT.propagateParamTo(xv, b)) {
432#ifndef GPUCA_ALIGPUCODE
433 LOG(debug) << "failed to propagate to alpha=" << alp << " X=" << xv << " for vertex "
434 << vtx.X() << ' ' << vtx.Y() << ' ' << vtx.Z() << " | Track is: " << tmpT.asString();
435#else
436 LOG(debug) << "failed to propagate to alpha=" << alp << " X=" << xv << " for vertex " << vtx.X() << ' ' << vtx.Y() << ' ' << vtx.Z();
437#endif
438 if (dca) { // provide default DCA for failed propag
439 (*dca)[0] = o2::track::DefaultDCA;
440 (*dca)[1] = o2::track::DefaultDCA;
441 }
442 return false;
443 }
444 *this = tmpT;
445 if (dca) {
446 (*dca)[0] = getY() - yv;
447 (*dca)[1] = getZ() - zv;
448 }
449 return true;
450}
451
452//____________________________________________________________
453template <typename value_T>
454GPUd() bool TrackParametrization<value_T>::getYZAt(value_t xk, value_t b, value_t& y, value_t& z) const
455{
456 //----------------------------------------------------------------
457 // estimate Y,Z in tracking frame at given X
458 //----------------------------------------------------------------
459 value_t dx = xk - getX();
460 y = mP[kY];
461 z = mP[kZ];
462 if (gpu::CAMath::Abs(dx) < constants::math::Almost0) {
463 return true;
464 }
465 value_t crv = getCurvature(b);
466 value_t x2r = crv * dx;
467 value_t f1 = getSnp(), f2 = f1 + x2r;
468 if ((gpu::CAMath::Abs(f1) > constants::math::Almost1) || (gpu::CAMath::Abs(f2) > constants::math::Almost1)) {
469 return false;
470 }
471 value_t r1 = gpu::CAMath::Sqrt((1.f - f1) * (1.f + f1));
472 if (gpu::CAMath::Abs(r1) < constants::math::Almost0) {
473 return false;
474 }
475 value_t r2 = gpu::CAMath::Sqrt((1.f - f2) * (1.f + f2));
476 if (gpu::CAMath::Abs(r2) < constants::math::Almost0) {
477 return false;
478 }
479 double dy2dx = (f1 + f2) / (r1 + r2);
480 y += dx * dy2dx;
481 if (gpu::CAMath::Abs(x2r) < 0.05f) {
482 z += dx * (r2 + f2 * dy2dx) * getTgl();
483 } else {
484 // for small dx/R the linear apporximation of the arc by the segment is OK,
485 // but at large dx/R the error is very large and leads to incorrect Z propagation
486 // angle traversed delta = 2*asin(dist_start_end / R / 2), hence the arc is: R*deltaPhi
487 // The dist_start_end is obtained from sqrt(dx^2+dy^2) = x/(r1+r2)*sqrt(2+f1*f2+r1*r2)
488 // double chord = dx*TMath::Sqrt(1+dy2dx*dy2dx); // distance from old position to new one
489 // double rot = 2*TMath::ASin(0.5*chord*crv); // angular difference seen from the circle center
490 // track1 += rot/crv*track3;
491 //
492 value_t rot = CAMath::ASin(r1 * f2 - r2 * f1); // more economic version from Yura.
493 if (f1 * f1 + f2 * f2 > 1.f && f1 * f2 < 0.f) { // special cases of large rotations or large abs angles
494 if (f2 > 0.f) {
495 rot = constants::math::PI - rot; //
496 } else {
497 rot = -constants::math::PI - rot;
498 }
499 }
500 z += getTgl() / crv * rot;
501 }
502 return true;
503}
504
505//______________________________________________________________
506template <typename value_T>
507GPUd() void TrackParametrization<value_T>::invertParam()
508{
509 // Transform this track to the local coord. system rotated by 180 deg.
510 mX = -mX;
511 mAlpha += constants::math::PI;
512 math_utils::detail::bringToPMPi<value_t>(mAlpha);
513 //
514 mP[0] = -mP[0];
515 mP[3] = -mP[3];
516 mP[4] = -mP[4];
517 //
518}
519
520//______________________________________________________________
521template <typename value_T>
522GPUd() typename TrackParametrization<value_T>::value_t TrackParametrization<value_T>::getZAt(value_t xk, value_t b) const
523{
525 value_t y, z;
526 return getYZAt(xk, b, y, z) ? z : -9999.f;
527}
528
529//______________________________________________________________
530template <typename value_T>
531GPUd() typename TrackParametrization<value_T>::value_t TrackParametrization<value_T>::getYAt(value_t xk, value_t b) const
532{
534 value_t y, z;
535 return getYZAt(xk, b, y, z) ? y : -9999.f;
536}
537
538//______________________________________________________________
539template <typename value_T>
540GPUd() typename TrackParametrization<value_T>::value_t TrackParametrization<value_T>::getSnpAt(value_t xk, value_t b) const
541{
543 value_t dx = xk - getX();
544 if (gpu::CAMath::Abs(dx) < constants::math::Almost0) {
545 return getSnp();
546 }
547 value_t crv = (gpu::CAMath::Abs(b) < constants::math::Almost0) ? 0.f : getCurvature(b);
548 value_t x2r = crv * dx;
549 return mP[kSnp] + x2r;
550}
551
552//______________________________________________________________
553template <typename value_T>
554GPUd() typename TrackParametrization<value_T>::value_t TrackParametrization<value_T>::getPhiAt(value_t xk, value_t b) const
555{
557 value_t dx = xk - getX();
558 if (gpu::CAMath::Abs(dx) < constants::math::Almost0) {
559 return getPhi();
560 }
561 value_t crv = (gpu::CAMath::Abs(b) < constants::math::Almost0) ? 0.f : getCurvature(b);
562 value_t x2r = crv * dx;
563 value_t snp = mP[kSnp] + x2r;
564 value_t phi = 999.;
565 if (gpu::CAMath::Abs(snp) < constants::math::Almost1) {
566 phi = gpu::CAMath::ASin(snp) + getAlpha();
567 math_utils::detail::bringTo02Pi<value_t>(phi);
568 }
569 return phi;
570}
571
572//______________________________________________________________
573template <typename value_T>
574GPUd() typename TrackParametrization<value_T>::value_t TrackParametrization<value_T>::getPhiPosAt(value_t xk, value_t b) const
575{
577 value_t phi = 999.;
578 auto y = getYAt(xk, b);
579 if (y > -9998.) {
580 phi = gpu::CAMath::ATan2(y, xk) + getAlpha();
581 math_utils::detail::bringTo02Pi<value_t>(phi);
582 }
583 return phi;
584}
585
586//______________________________________________________________
587template <typename value_T>
588GPUd() typename TrackParametrization<value_T>::value_t TrackParametrization<value_T>::getSnpAt(value_t alpha, value_t xk, value_t b) const
589{
591 math_utils::detail::bringToPMPi<value_t>(alpha);
592 value_t ca = 0, sa = 0;
593 math_utils::detail::sincos(alpha - getAlpha(), sa, ca);
594 value_t snp = getSnp(), csp = gpu::CAMath::Sqrt((1.f - snp) * (1.f + snp)); // Improve precision
595 // RS: check if rotation does no invalidate track model (cos(local_phi)>=0, i.e. particle direction in local frame is along the X axis
596 if ((csp * ca + snp * sa) < 0.) {
597 // LOGF(warning,"Rotation failed: local cos(phi) would become {:.2f}", csp * ca + snp * sa);
598 return -999;
599 }
600 value_t tmp = snp * ca - csp * sa;
601 if (gpu::CAMath::Abs(tmp) > constants::math::Almost1) {
602 LOGP(debug, "Rotation failed: new snp {:.2f}", tmp);
603 return -999;
604 }
605 value_t xrot = getX() * ca + getY() * sa;
606 value_t dx = xk - xrot;
607 value_t crv = (gpu::CAMath::Abs(b) < constants::math::Almost0) ? 0.f : getCurvature(b);
608 value_t x2r = crv * dx;
609 return tmp + x2r;
610}
611
612#ifndef GPUCA_ALIGPUCODE
613//_____________________________________________________________
614template <typename value_T>
616{
617 // print parameters as string
618 return fmt::format("X:{:+.4e} Alp:{:+.3e} Par: {:+.4e} {:+.4e} {:+.4e} {:+.4e} {:+.4e} |Q|:{:d} {:s}",
619 getX(), getAlpha(), getY(), getZ(), getSnp(), getTgl(), getQ2Pt(), getAbsCharge(), getPID().getName());
620}
621
622//_____________________________________________________________
623template <typename value_T>
625{
626 auto _X = getX();
627 auto _Alpha = getAlpha();
628 auto _Y = getY();
629 auto _Z = getZ();
630 auto _Snp = getSnp();
631 auto _Tgl = getTgl();
632 float _Q2Pt = getQ2Pt();
633 float _AbsCharge = getAbsCharge();
634 // print parameters as string
635 return fmt::format("X:{:x} Alp:{:x} Par: {:x} {:x} {:x} {:x} {:x} |Q|:{:x} {:s}\n",
636 reinterpret_cast<const unsigned int&>(_X),
637 reinterpret_cast<const unsigned int&>(_Alpha),
638 reinterpret_cast<const unsigned int&>(_Y),
639 reinterpret_cast<const unsigned int&>(_Z),
640 reinterpret_cast<const unsigned int&>(_Snp),
641 reinterpret_cast<const unsigned int&>(_Tgl),
642 reinterpret_cast<const unsigned int&>(_Q2Pt),
643 reinterpret_cast<const unsigned int&>(_AbsCharge),
644 getPID().getName());
645}
646#endif
647
648//______________________________________________________________
649template <typename value_T>
650GPUd() void TrackParametrization<value_T>::printParam() const
651{
652 // print parameters
653#ifndef GPUCA_ALIGPUCODE
654 printf("%s\n", asString().c_str());
655#elif !defined(GPUCA_GPUCODE_DEVICE) || (!defined(__OPENCL__) && defined(GPUCA_GPU_DEBUG_PRINT))
656 printf("X:%+.4e Alp:%+.3e Par: %+.4e %+.4e %+.4e %+.4e %+.4e |Q|:%d %s\n",
657 getX(), getAlpha(), getY(), getZ(), getSnp(), getTgl(), getQ2Pt(), getAbsCharge(), getPID().getName());
658#endif
659}
660
661//______________________________________________________________
662template <typename value_T>
663GPUd() void TrackParametrization<value_T>::printParamHexadecimal()
664{
665 // print parameters
666#ifndef GPUCA_ALIGPUCODE
667 printf("%s\n", asStringHexadecimal().c_str());
668#elif !defined(GPUCA_GPUCODE_DEVICE) || (!defined(__OPENCL__) && defined(GPUCA_GPU_DEBUG_PRINT))
669 printf("X:%x Alp:%x Par: %x %x %x %x %x |Q|:%x %s\n",
670 gpu::CAMath::Float2UIntReint(getX()),
671 gpu::CAMath::Float2UIntReint(getAlpha()),
672 gpu::CAMath::Float2UIntReint(getY()),
673 gpu::CAMath::Float2UIntReint(getZ()),
674 gpu::CAMath::Float2UIntReint(getSnp()),
675 gpu::CAMath::Float2UIntReint(getTgl()),
676 gpu::CAMath::Float2UIntReint(getQ2Pt()),
677 gpu::CAMath::Float2UIntReint(getAbsCharge()),
678 getPID().getName());
679#endif
680}
681
682//______________________________________________________________
683template <typename value_T>
684GPUd() bool TrackParametrization<value_T>::getXatLabR(value_t r, value_t& x, value_t bz, track::DirType dir) const
685{
686 // Get local X of the track position estimated at the radius lab radius r.
687 // The track curvature is accounted exactly
688 //
689 // The flag "dir" can be used to remove the ambiguity of which intersection to take (out of 2 possible)
690 // DirAuto (==0) - take the intersection closest to the current track position
691 // DirOutward (==1) - go along the track (increasing mX)
692 // DirInward (==-1) - go backward (decreasing mX)
693 //
694 const double fy = mP[0], sn = mP[2];
695 const value_t kEps = 1.e-6;
696 //
697 if (gpu::CAMath::Abs(getSnp()) > constants::math::Almost1) {
698 return false;
699 }
700 auto crv = getCurvature(bz);
701 while (gpu::CAMath::Abs(crv) > constants::math::Almost0) { // helix ?
702 // get center of the track circle
704 getCircleParamsLoc(bz, circle);
705 if (circle.rC == 0.) {
706 crv = 0.;
707 break;
708 }
709 value_t r0 = gpu::CAMath::Sqrt(circle.getCenterD2());
710 if (r0 <= constants::math::Almost0) {
711 return false; // the track is concentric to circle
712 }
713 double tR2r0 = 1., g = 0., tmp = 0.;
714 if (gpu::CAMath::Abs(circle.rC - r0) > kEps) {
715 tR2r0 = circle.rC / r0;
716 g = 0.5f * (r * r / (r0 * circle.rC) - tR2r0 - 1.f / tR2r0);
717 tmp = 1.f + g * tR2r0;
718 } else {
719 tR2r0 = 1.0;
720 g = 0.5 * r * r / (r0 * circle.rC) - 1.;
721 tmp = 0.5 * r * r / (r0 * r0);
722 }
723 auto det = (1. - g) * (1. + g);
724 if (det < 0.) {
725 return false; // does not reach raduis r
726 }
727 det = gpu::CAMath::Sqrt(det);
728 //
729 // the intersection happens in 2 points: {circle.xC+tR*C,circle.yC+tR*S}
730 // with C=f*c0+-|s0|*det and S=f*s0-+c0 sign(s0)*det
731 // where s0 and c0 make direction for the circle center (=circle.xC/r0 and circle.yC/r0)
732 //
733 x = circle.xC * tmp;
734 auto y = circle.yC * tmp;
735 if (gpu::CAMath::Abs(circle.yC) > constants::math::Almost0) { // when circle.yC==0 the x,y is unique
736 auto dfx = tR2r0 * gpu::CAMath::Abs(circle.yC) * det;
737 auto dfy = tR2r0 * circle.xC * (circle.yC > 0. ? det : -det);
738 if (dir == DirAuto) { // chose the one which corresponds to smallest step
739 auto delta = (x - mX) * dfx - (y - fy) * dfy; // the choice of + in C will lead to smaller step if delta<0
740 x += delta < 0. ? dfx : -dfx;
741 } else if (dir == DirOutward) { // along track direction: x must be > mX
742 x -= dfx; // try the smallest step (dfx is positive)
743 auto dfeps = mX - x; // handle special case of very small step
744 if (dfeps < -kEps) {
745 return true;
746 }
747 if (gpu::CAMath::Abs(dfeps) < kEps && gpu::CAMath::Abs(mX * mX + fy * fy - r * r) < kEps) { // are we already in right r?
748 x = mX;
749 return true;
750 }
751 x += dfx + dfx;
752 auto dxm = x - mX;
753 if (dxm > 0.) {
754 return true;
755 } else if (dxm < -kEps) {
756 return false;
757 }
758 x = mX; // don't move
759 } else { // backward: x must be < mX
760 x += dfx; // try the smallest step (dfx is positive)
761 auto dfeps = x - mX; // handle special case of very small step
762 if (dfeps < -kEps) {
763 return true;
764 }
765 if (gpu::CAMath::Abs(dfeps) < kEps && gpu::CAMath::Abs(mX * mX + fy * fy - r * r) < kEps) { // are we already in right r?
766 x = mX;
767 return true;
768 }
769 x -= dfx + dfx;
770 auto dxm = x - mX;
771 if (dxm < 0.) {
772 return true;
773 }
774 if (dxm > kEps) {
775 return false;
776 }
777 x = mX; // don't move
778 }
779 } else { // special case: track touching the circle just in 1 point
780 if ((dir == DirOutward && x < mX) || (dir == DirInward && x > mX)) {
781 return false;
782 }
783 }
784 return true;
785 }
786 // this is a straight track
787 if (gpu::CAMath::Abs(sn) >= constants::math::Almost1) { // || to Y axis
788 double det = (r - mX) * (r + mX);
789 if (det < 0.f) {
790 return false; // does not reach raduis r
791 }
792 x = mX;
793 if (dir == DirAuto) {
794 return true;
795 }
796 det = gpu::CAMath::Sqrt(det);
797 if (dir == DirOutward) { // along the track direction
798 if (sn > 0.) {
799 if (fy > det) {
800 return false; // track is along Y axis and above the circle
801 }
802 } else {
803 if (fy < -det) {
804 return false; // track is against Y axis amd belo the circle
805 }
806 }
807 } else if (dir == DirInward) { // against track direction
808 if (sn > 0.) {
809 if (fy < -det) {
810 return false; // track is along Y axis
811 }
812 } else if (fy > det) {
813 return false; // track is against Y axis
814 }
815 }
816 } else if (gpu::CAMath::Abs(sn) <= constants::math::Almost0) { // || to X axis
817 double det = (r - fy) * (r + fy);
818 if (det < 0.) {
819 return false; // does not reach raduis r
820 }
821 det = gpu::CAMath::Sqrt(det);
822 if (dir == DirAuto) {
823 x = mX > 0. ? det : -det; // choose the solution requiring the smalest step
824 return true;
825 } else if (dir == DirOutward) { // along the track direction
826 if (mX > det) {
827 return false; // current point is in on the right from the circle
828 } else {
829 x = (mX < -det) ? -det : det; // on the left : within the circle
830 }
831 } else { // against the track direction
832 if (mX < -det) {
833 return false;
834 } else {
835 x = mX > det ? det : -det;
836 }
837 }
838 } else { // general case of straight line
839 auto cs = gpu::CAMath::Sqrt((1. - sn) * (1. + sn));
840 auto xsyc = mX * sn - fy * cs;
841 auto det = (r - xsyc) * (r + xsyc);
842 if (det < 0.) {
843 return false; // does not reach raduis r
844 }
845 det = gpu::CAMath::Sqrt(det);
846 auto xcys = mX * cs + fy * sn;
847 auto t = -xcys;
848 if (dir == DirAuto) {
849 t += t > 0. ? -det : det; // chose the solution requiring the smalest step
850 } else if (dir > 0) { // go in increasing mX direction. ( t+-det > 0)
851 if (t >= -det) {
852 t += det; // take minimal step giving t>0
853 } else {
854 return false; // both solutions have negative t
855 }
856 } else { // go in decreasing mX direction. (t+-det < 0)
857 if (t < det) {
858 t -= det; // take minimal step giving t<0
859 } else {
860 return false; // both solutions have positive t
861 }
862 }
863 x = mX + cs * t;
864 }
865 //
866 return true;
867}
868
869//______________________________________________
870template <typename value_T>
871GPUd() bool TrackParametrization<value_T>::correctForELoss(value_t xrho, bool anglecorr)
872{
873 //------------------------------------------------------------------
874 // This function corrects the track parameters for the energy loss in crossed material.
875 // "xrho" - is the product length*density (g/cm^2).
876 // It should be passed as negative when propagating tracks
877 // from the intreaction point to the outside of the central barrel.
878 // "dedx" - mean enery loss (GeV/(g/cm^2), if <=kCalcdEdxAuto : calculate on the fly
879 // "anglecorr" - switch for the angular correction
880 //------------------------------------------------------------------
881 constexpr value_t kMinP = 0.01f; // kill below this momentum
882
883 auto m = getPID().getMass();
884 if (m > 0 && xrho != 0.f) {
885 // Apply angle correction, if requested
886 if (anglecorr) {
887 value_t csp2 = (1.f - getSnp()) * (1.f + getSnp()); // cos(phi)^2
888 value_t cst2I = (1.f + getTgl() * getTgl()); // 1/cos(lambda)^2
889 value_t angle = gpu::CAMath::Sqrt(cst2I / (csp2));
890 xrho *= angle;
891 }
892 int charge2 = getAbsCharge() * getAbsCharge();
893 value_t p = getP(), p0 = p, p2 = p * p, e2 = p2 + getPID().getMass2(), massInv = 1. / m, bg = p * massInv;
894 value_t e = gpu::CAMath::Sqrt(e2), ekin = e - m, dedx = getdEdxBBOpt(bg);
895#ifdef _BB_NONCONST_CORR_
896 value_t dedxDer = 0., dedx1 = dedx;
897#endif
898 if (charge2 != 1) {
899 dedx *= charge2;
900 }
901 value_t dE = dedx * xrho;
902 int na = 1 + int(gpu::CAMath::Abs(dE) / ekin * ELoss2EKinThreshInv);
903 if (na > MaxELossIter) {
904 na = MaxELossIter;
905 }
906 if (na > 1) {
907 dE /= na;
908 xrho /= na;
909#ifdef _BB_NONCONST_CORR_
910 dedxDer = getBetheBlochSolidDerivativeApprox(dedx1, bg); // require correction for non-constantness of dedx vs betagamma
911 if (charge2 != 1) {
912 dedxDer *= charge2;
913 }
914#endif
915 }
916 while (na--) {
917#ifdef _BB_NONCONST_CORR_
918 if (dedxDer != 0.) { // correction for non-constantness of dedx vs beta*gamma (in linear approximation): for a single step dE -> dE * [(exp(dedxDer) - 1)/dedxDer]
919 if (xrho < 0) {
920 dedxDer = -dedxDer; // E.loss ( -> positive derivative)
921 }
922 auto corrC = (gpu::CAMath::Exp(dedxDer) - 1.) / dedxDer;
923 dE *= corrC;
924 }
925#endif
926 e += dE;
927 if (e > m) { // stopped
928 p = gpu::CAMath::Sqrt(e * e - getPID().getMass2());
929 } else {
930 return false;
931 }
932 if (na) {
933 bg = p * massInv;
934 dedx = getdEdxBBOpt(bg);
935#ifdef _BB_NONCONST_CORR_
936 dedxDer = getBetheBlochSolidDerivativeApprox(dedx, bg);
937#endif
938 if (charge2 != 1) {
939 dedx *= charge2;
940#ifdef _BB_NONCONST_CORR_
941 dedxDer *= charge2;
942#endif
943 }
944 dE = dedx * xrho;
945 }
946 }
947
948 if (p < kMinP) {
949 return false;
950 }
951 setQ2Pt(getQ2Pt() * p0 / p);
952 }
953
954 return true;
955}
956
957//______________________________________________
958template <typename value_T>
959GPUd() typename o2::track::TrackParametrization<value_T>::yzerr_t TrackParametrization<value_T>::getVertexInTrackFrame(const o2::dataformats::VertexBase& v) const
960{
961 // rotate vertex to track frame and return parameters used by getPredictedChi2 and update of TrackParametrizationWithError
962 value_t sn, cs;
963 math_utils::detail::sincos(-mAlpha, sn, cs); // use -alpha since we rotate from lab to tracking frame
964 value_t sn2 = sn * sn, cs2 = cs * cs, sncs = sn * cs;
965 value_t dsxysncs = 2. * v.getSigmaXY() * sncs;
966 return {{/*v.getX()*cs-v.getY()*sn,*/ v.getX() * sn + v.getY() * cs, v.getZ()},
967 {v.getSigmaX2() * sn2 + dsxysncs + v.getSigmaY2() * cs2, (sn + cs) * v.getSigmaYZ(), v.getSigmaZ2()}};
968}
969
970//______________________________________________
971template <typename value_T>
972GPUd() typename TrackParametrization<value_T>::value_t TrackParametrization<value_T>::getDCAYtoMV(value_t b, value_t xmv, value_t ymv, value_t zmv) const
973{
974 auto ttmp = *this;
975 dim2_t dca;
976 return ttmp.propagateParamToDCA({xmv, ymv, zmv}, b, &dca) ? dca[0] : -9999.;
977}
978
979//______________________________________________
980template <typename value_T>
981GPUd() typename TrackParametrization<value_T>::value_t TrackParametrization<value_T>::getDCAZtoMV(value_t b, value_t xmv, value_t ymv, value_t zmv) const
982{
983 auto ttmp = *this;
984 dim2_t dca;
985 return ttmp.propagateParamToDCA({xmv, ymv, zmv}, b, &dca) ? dca[1] : -9999.;
986}
987
988namespace o2::track
989{
990#if !defined(GPUCA_GPUCODE) || defined(GPUCA_GPUCODE_DEVICE) // FIXME: DR: WORKAROUND to avoid CUDA bug creating host symbols for device code.
991template class TrackParametrization<float>;
992#endif
993#ifndef GPUCA_GPUCODE
994template class TrackParametrization<double>;
995#endif
996} // namespace o2::track
std::string getName(const TDataMember *dm, int index, int size)
std::string asString(TDataMember const &dm, char *pointer)
std::ostringstream debug
int16_t charge
Definition RawEventData.h:5
const int16_t bb
constexpr int p2()
uint16_t pid
Definition RawData.h:2
std::string asString() const
GLfloat GLfloat GLfloat alpha
Definition glcorearb.h:279
GLint GLenum GLint x
Definition glcorearb.h:403
const GLfloat * m
Definition glcorearb.h:4066
const GLdouble * v
Definition glcorearb.h:832
GLenum array
Definition glcorearb.h:4274
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
GLint y
Definition glcorearb.h:270
typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode)
GLboolean GLboolean g
Definition glcorearb.h:1233
GLfloat angle
Definition glcorearb.h:4071
GLboolean r
Definition glcorearb.h:1233
GLdouble GLdouble GLdouble z
Definition glcorearb.h:843
typename trackParam_t::dim3_t dim3_t
Definition utils.h:32
typename trackParam_t::dim2_t dim2_t
Definition utils.h:31
typename trackParam_t::value_t value_t
Definition utils.h:30
constexpr float Almost1
std::array< int, 24 > p0
double * getX(double *xyDxy, int N)
double * getY(double *xyDxy, int N)
value_T bg
Definition TrackUtils.h:194
value_T step
Definition TrackUtils.h:42
value_T f1
Definition TrackUtils.h:91
const value_T x
Definition TrackUtils.h:136
value_T std::array< value_T, 7 > & vect
Definition TrackUtils.h:42
GPUd() value_T BetheBlochSolid(value_T bg
Definition TrackUtils.h:150
value_T f2
Definition TrackUtils.h:92
constexpr float DefaultDCA
constexpr int MaxELossIter
constexpr float ELoss2EKinThreshInv
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
Defining DataPointCompositeObject explicitly as copiable.
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"