Project
Loading...
Searching...
No Matches
TrackGeometry.h
Go to the documentation of this file.
1// Copyright 2026-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
12#ifndef ALICEO2_TRACKTOOLS_TRACKGEOMETRY_H_
13#define ALICEO2_TRACKTOOLS_TRACKGEOMETRY_H_
14
71#include <algorithm>
72#include <array>
73#include <cmath>
74#include <cstdint>
75#include <limits>
76#include <cstddef>
77#include <vector>
78#include <utility>
79
81#include "MathUtils/Utils.h"
83#include "TPCBase/Mapper.h"
85
87{
88
91 OK = 0,
92 InvalidInput = 1,
97};
98
104 float gx = std::numeric_limits<float>::quiet_NaN();
105 float gy = std::numeric_limits<float>::quiet_NaN();
106 float gz = std::numeric_limits<float>::quiet_NaN();
107 float px = std::numeric_limits<float>::quiet_NaN();
108 float py = std::numeric_limits<float>::quiet_NaN();
109 float pz = std::numeric_limits<float>::quiet_NaN();
111
112 bool valid() const { return status == TrackParametersStatus::OK; }
113};
114
117{
118 return state.valid() ? std::atan2(state.gy, state.gx) : std::numeric_limits<float>::quiet_NaN();
119}
120
123{
124 return state.valid() ? std::atan2(state.py, state.px) : std::numeric_limits<float>::quiet_NaN();
125}
126
129{
130 if (!state.valid()) {
131 return std::numeric_limits<float>::quiet_NaN();
132 }
133 const float pt = std::hypot(state.px, state.py);
134 return pt > 0.f ? state.pz / pt : std::numeric_limits<float>::quiet_NaN();
135}
136
146inline float dSector(float phi, int nSectors = 18, float sectorPhaseRad = 0.f)
147{
148 if (!std::isfinite(phi) || !std::isfinite(sectorPhaseRad) || nSectors <= 0) {
149 return std::numeric_limits<float>::quiet_NaN();
150 }
151 const float x = 0.5f * nSectors * (phi - sectorPhaseRad) / o2::constants::math::PI;
152 const float phase = x - std::floor(x);
153 return phase < 1.f ? phase : 0.f;
154}
155
157inline float stateDSector(const TrackParametersAtRadius& state, int nSectors = 18, float sectorPhaseRad = 0.f)
158{
159 return dSector(statePhiPos(state), nSectors, sectorPhaseRad);
160}
161
171inline o2::track::TrackPar makeTrackParFromPrimaryApproximation(float phi, float tgl, float qpt,
172 float vx = 0.f, float vy = 0.f, float vz = 0.f)
173{
174 const float pt = 1.f / std::abs(qpt);
175 const int charge = qpt >= 0.f ? 1 : -1;
176 o2::track::TrackPar::dim3_t xyz{{vx, vy, vz}};
177 o2::track::TrackPar::dim3_t pxyz{{pt * std::cos(phi), pt * std::sin(phi), pt * tgl}};
178 return o2::track::TrackPar(xyz, pxyz, charge, false);
179}
180
182inline o2::track::TrackPar makePrimaryTrackPar(float phi, float tgl, float qpt, float vz = 0.f)
183{
184 return makeTrackParFromPrimaryApproximation(phi, tgl, qpt, 0.f, 0.f, vz);
185}
186
191{
192 track.getXYZGlo(xyz);
193 if (!track.getPxPyPzGlo(pxyz)) {
194 return false;
195 }
196 for (int i = 0; i < 3; ++i) {
197 if (!std::isfinite(xyz[i]) || !std::isfinite(pxyz[i])) {
198 return false;
199 }
200 }
201 return true;
202}
203
205inline bool directionMatches(o2::track::DirType dir, float drds)
206{
207 constexpr float eps = 1.e-6f;
209 return drds >= -eps;
210 }
212 return drds <= eps;
213 }
214 return true;
215}
216
231{
233 if (!(radius > 0.f) || !std::isfinite(radius) || !std::isfinite(bzKG) || !track.isValid()) {
235 return out;
236 }
237
238 o2::track::TrackPar::dim3_t xyz{}, pxyz{};
239 if (!extractGlobalState(track, xyz, pxyz)) {
241 return out;
242 }
243
244 // Use double precision for the analytic construction even though TrackPar and
245 // the public result are float-based. For high-pT tracks the circle centre is
246 // O(1/curvature) away while the requested detector radius is O(10^2 cm).
247 // Performing the circle/circle intersection in float loses several microrad
248 // through cancellation. K0 is therefore the numerical oracle for the final
249 // float state, while H keeps the fast analytic transport.
250 const double x0 = static_cast<double>(xyz[0]);
251 const double y0 = static_cast<double>(xyz[1]);
252 const double z0 = static_cast<double>(xyz[2]);
253 const double px0 = static_cast<double>(pxyz[0]);
254 const double py0 = static_cast<double>(pxyz[1]);
255 const double pz0 = static_cast<double>(pxyz[2]);
256 const double targetR = static_cast<double>(radius);
257 const double pt = std::hypot(px0, py0);
258 if (!(pt > 0.) || !std::isfinite(pt)) {
260 return out;
261 }
262
263 const double phi0 = std::atan2(py0, px0);
264 const double tgl = pz0 / pt;
265 const double curv = static_cast<double>(track.getQ2Pt()) *
266 static_cast<double>(bzKG) *
267 static_cast<double>(o2::constants::math::B2C);
268 constexpr double eps = 1.e-10;
269 constexpr double curvEps = 1.e-12;
270 const double twoPi = 2.0 * static_cast<double>(o2::constants::math::PI);
271
272 bool foundAny = false;
273 bool foundDirection = false;
274 double bestSxy = std::numeric_limits<double>::infinity();
275 double bestX = 0., bestY = 0., bestPhiMom = 0.;
276
277 auto directionMatchesD = [&](double drds) {
278 constexpr double dirEps = 1.e-10;
280 return drds >= -dirEps;
281 }
283 return drds <= dirEps;
284 }
285 return true;
286 };
287
288 auto consider = [&](double x, double y, double phiMom, double sxy) {
289 if (!std::isfinite(sxy) || sxy < -eps) {
290 return;
291 }
292 foundAny = true;
293 sxy = std::max(0.0, sxy);
294 const double drds = (x * std::cos(phiMom) + y * std::sin(phiMom)) / targetR;
295 if (!directionMatchesD(drds)) {
296 return;
297 }
298 foundDirection = true;
299 if (sxy < bestSxy) {
300 bestSxy = sxy;
301 bestX = x;
302 bestY = y;
303 bestPhiMom = phiMom;
304 }
305 };
306
307 if (std::abs(curv) < curvEps) {
308 const double ux = px0 / pt, uy = py0 / pt;
309 const double b = x0 * ux + y0 * uy;
310 const double c = x0 * x0 + y0 * y0 - targetR * targetR;
311 double disc = b * b - c;
312 if (disc < -eps) {
314 return out;
315 }
316 disc = std::max(0.0, disc);
317 const double root = std::sqrt(disc);
318 for (const double sxy : {-b - root, -b + root}) {
319 consider(x0 + sxy * ux, y0 + sxy * uy, phi0, sxy);
320 }
321 } else {
322 const double xc = x0 - std::sin(phi0) / curv;
323 const double yc = y0 + std::cos(phi0) / curv;
324 const double rho = 1.0 / std::abs(curv);
325 const double d = std::hypot(xc, yc);
326 if (!(d > eps) || d > targetR + rho + eps || d < std::abs(targetR - rho) - eps) {
328 return out;
329 }
330
331 const double a = (targetR * targetR - rho * rho + d * d) / (2.0 * d);
332 double h2 = targetR * targetR - a * a;
333 if (h2 < -eps) {
335 return out;
336 }
337 h2 = std::max(0.0, h2);
338 const double h = std::sqrt(h2);
339 const double bx = a * xc / d, by = a * yc / d;
340 const double ox = -yc * h / d, oy = xc * h / d;
341
342 const std::array<std::array<double, 2>, 2> intersections{{{{bx + ox, by + oy}},
343 {{bx - ox, by - oy}}}};
344 for (const auto& xy : intersections) {
345 const double x = xy[0], y = xy[1];
346 double sinPhi = curv * (x - xc);
347 double cosPhi = -curv * (y - yc);
348 const double norm = std::hypot(sinPhi, cosPhi);
349 if (!(norm > 0.) || !std::isfinite(norm)) {
350 continue;
351 }
352 sinPhi /= norm;
353 cosPhi /= norm;
354 const double phiMom = std::atan2(sinPhi, cosPhi);
355 double delta = phiMom - phi0;
356 if (curv > 0.) {
357 while (delta < -eps) {
358 delta += twoPi;
359 }
360 } else {
361 while (delta > eps) {
362 delta -= twoPi;
363 }
364 }
365 consider(x, y, phiMom, delta / curv);
366 }
367 }
368
369 if (!foundDirection || !std::isfinite(bestSxy)) {
371 return out;
372 }
373
374 out.gx = static_cast<float>(bestX);
375 out.gy = static_cast<float>(bestY);
376 out.gz = static_cast<float>(z0 + bestSxy * tgl);
377 out.px = static_cast<float>(pt * std::cos(bestPhiMom));
378 out.py = static_cast<float>(pt * std::sin(bestPhiMom));
379 out.pz = static_cast<float>(pz0);
381 return out;
382}
383
399{
401 if (!(radius > 0.f) || !std::isfinite(radius) || !std::isfinite(bzKG) || !track.isValid()) {
403 return out;
404 }
405
406 float xAtR = 0.f;
407 if (!track.getXatLabR(radius, xAtR, bzKG, dir)) {
409 return out;
410 }
411
412 auto propagated = track;
413 if (!propagated.propagateParamTo(xAtR, bzKG)) {
415 return out;
416 }
417
418 o2::track::TrackPar::dim3_t xyz{}, pxyz{};
419 if (!extractGlobalState(propagated, xyz, pxyz)) {
421 return out;
422 }
423
424 // A successful internal TrackPar update is not sufficient: the returned
425 // global state must actually lie on the requested cylinder (Architect A5).
426 constexpr float radiusToleranceCm = 2.e-3f;
427 const float resultRadius = std::hypot(xyz[0], xyz[1]);
428 if (!std::isfinite(resultRadius) || std::abs(resultRadius - radius) > radiusToleranceCm) {
430 return out;
431 }
432
433 out.gx = xyz[0];
434 out.gy = xyz[1];
435 out.gz = xyz[2];
436 out.px = pxyz[0];
437 out.py = pxyz[1];
438 out.pz = pxyz[2];
440 return out;
441}
442
444inline float phiAtRadius(const o2::track::TrackPar& track, float radius, float bzKG,
446{
447 return statePhiPos(getParametersAtRadiusK0(track, radius, bzKG, dir));
448}
449
451inline float dSectorAtRadius(const o2::track::TrackPar& track, float radius, float bzKG, int nSectors = 18,
452 o2::track::DirType dir = o2::track::DirType::DirOutward, float sectorPhaseRad = 0.f)
453{
454 return stateDSector(getParametersAtRadiusK0(track, radius, bzKG, dir), nSectors, sectorPhaseRad);
455}
456
458inline float primaryPhiAtRadius(float phi, float tgl, float qpt, float radius, float bzKG, float vz = 0.f)
459{
460 if (!std::isfinite(phi) || !std::isfinite(tgl) || !std::isfinite(qpt) || std::abs(qpt) < 1.e-12f) {
461 return std::numeric_limits<float>::quiet_NaN();
462 }
463 return phiAtRadius(makePrimaryTrackPar(phi, tgl, qpt, vz), radius, bzKG, o2::track::DirType::DirOutward);
464}
465
467inline float primaryDSectorAtRadius(float phi, float tgl, float qpt, float radius, float bzKG,
468 int nSectors = 18, float vz = 0.f, float sectorPhaseRad = 0.f)
469{
470 const float phiR = primaryPhiAtRadius(phi, tgl, qpt, radius, bzKG, vz);
471 return dSector(phiR, nSectors, sectorPhaseRad);
472}
473
480 std::vector<float> gx, gy, gz, px, py, pz;
481 std::vector<float> phiPos, phiMom, tgl, dSector;
482 std::vector<int32_t> status;
483
484 void resize(std::size_t n)
485 {
486 gx.resize(n);
487 gy.resize(n);
488 gz.resize(n);
489 px.resize(n);
490 py.resize(n);
491 pz.resize(n);
492 phiPos.resize(n);
493 phiMom.resize(n);
494 tgl.resize(n);
495 dSector.resize(n);
496 status.resize(n);
497 }
498
499 void set(std::size_t i, const TrackParametersAtRadius& state, int nSectors, float sectorPhaseRad)
500 {
501 gx[i] = state.gx;
502 gy[i] = state.gy;
503 gz[i] = state.gz;
504 px[i] = state.px;
505 py[i] = state.py;
506 pz[i] = state.pz;
509 tgl[i] = stateTgl(state);
510 dSector[i] = stateDSector(state, nSectors, sectorPhaseRad);
511 status[i] = static_cast<int32_t>(state.status);
512 }
513};
514
515template <typename Evaluator>
517 const float* phi, const float* tgl, const float* qpt,
518 const float* vx, const float* vy, const float* vz,
519 std::size_t n, float radius, float bzKG, int nSectors, float sectorPhaseRad, Evaluator&& evaluate)
520{
522 out.resize(n);
523 for (std::size_t i = 0; i < n; ++i) {
524 if (!phi || !tgl || !qpt || !std::isfinite(qpt[i]) || std::abs(qpt[i]) < 1.e-12f) {
527 out.set(i, invalid, nSectors, sectorPhaseRad);
528 continue;
529 }
530 const auto track = makeTrackParFromPrimaryApproximation(phi[i], tgl[i], qpt[i],
531 vx ? vx[i] : 0.f,
532 vy ? vy[i] : 0.f,
533 vz ? vz[i] : 0.f);
534 out.set(i, evaluate(track, radius, bzKG), nSectors, sectorPhaseRad);
535 }
536 return out;
537}
538
541 const float* phi, const float* tgl, const float* qpt,
542 const float* vx, const float* vy, const float* vz,
543 std::size_t n, float radius, float bzKG, int nSectors = 18, float sectorPhaseRad = 0.f)
544{
546 phi, tgl, qpt, vx, vy, vz, n, radius, bzKG, nSectors, sectorPhaseRad,
547 [](const o2::track::TrackPar& track, float r, float bz) {
549 });
550}
551
554 const float* phi, const float* tgl, const float* qpt,
555 const float* vx, const float* vy, const float* vz,
556 std::size_t n, float radius, float bzKG, int nSectors = 18, float sectorPhaseRad = 0.f)
557{
559 phi, tgl, qpt, vx, vy, vz, n, radius, bzKG, nSectors, sectorPhaseRad,
560 [](const o2::track::TrackPar& track, float r, float bz) {
562 });
563}
564
567 float snp, float tgl, float qpt, int absCharge = 1)
568{
569 o2::track::TrackPar::params_t par{{y, z, snp, tgl, qpt}};
570 return o2::track::TrackPar(x, alpha, par, std::max(1, std::abs(absCharge)));
571}
572
573template <typename Evaluator>
575 const float* x, const float* alpha, const float* y, const float* z,
576 const float* snp, const float* tgl, const float* qpt,
577 std::size_t n, float radius, float bzKG, int nSectors, float sectorPhaseRad, Evaluator&& evaluate)
578{
580 out.resize(n);
581 for (std::size_t i = 0; i < n; ++i) {
582 if (!x || !alpha || !y || !z || !snp || !tgl || !qpt) {
585 out.set(i, invalid, nSectors, sectorPhaseRad);
586 continue;
587 }
588 const auto track = makeTrackParFromLocalParameters(x[i], alpha[i], y[i], z[i], snp[i], tgl[i], qpt[i]);
589 out.set(i, evaluate(track, radius, bzKG), nSectors, sectorPhaseRad);
590 }
591 return out;
592}
593
596 const float* x, const float* alpha, const float* y, const float* z,
597 const float* snp, const float* tgl, const float* qpt,
598 std::size_t n, float radius, float bzKG, int nSectors = 18, float sectorPhaseRad = 0.f)
599{
601 x, alpha, y, z, snp, tgl, qpt, n, radius, bzKG, nSectors, sectorPhaseRad,
602 [](const o2::track::TrackPar& track, float r, float bz) {
604 });
605}
606
609 const float* x, const float* alpha, const float* y, const float* z,
610 const float* snp, const float* tgl, const float* qpt,
611 std::size_t n, float radius, float bzKG, int nSectors = 18, float sectorPhaseRad = 0.f)
612{
614 x, alpha, y, z, snp, tgl, qpt, n, radius, bzKG, nSectors, sectorPhaseRad,
615 [](const o2::track::TrackPar& track, float r, float bz) {
617 });
618}
619
621inline std::vector<float> primaryPhiAtRadiusBatch(const float* phi, const float* tgl, const float* qpt, const float* vz,
622 std::size_t n, float radius, float bzKG)
623{
624 auto batch = primaryTrackParametersAtRadiusK0Batch(phi, tgl, qpt, nullptr, nullptr, vz, n, radius, bzKG);
625 return std::move(batch.phiPos);
626}
627
628inline std::vector<float> primaryDSectorAtRadiusBatch(const float* phi, const float* tgl, const float* qpt, const float* vz,
629 std::size_t n, float radius, float bzKG, int nSectors = 18,
630 float sectorPhaseRad = 0.f)
631{
632 auto batch = primaryTrackParametersAtRadiusK0Batch(phi, tgl, qpt, nullptr, nullptr, vz, n, radius, bzKG,
633 nSectors, sectorPhaseRad);
634 return std::move(batch.dSector);
635}
636
639 std::vector<float> phi;
640 std::vector<float> dSector;
641};
642
644 const float* phi, const float* tgl, const float* qpt, const float* vz,
645 std::size_t n, float radius, float bzKG, int nSectors = 18, float sectorPhaseRad = 0.f)
646{
647 auto batch = primaryTrackParametersAtRadiusK0Batch(phi, tgl, qpt, nullptr, nullptr, vz, n, radius, bzKG,
648 nSectors, sectorPhaseRad);
649 return {std::move(batch.phiPos), std::move(batch.dSector)};
650}
651
652} // namespace o2::recohelpers
653
655{
656
664
667 OK = 0,
668 InvalidInput = 1,
669 NoRowsCrossed = 2,
672};
673
679 float phi = 0.f; // momentum azimuth at the primary vertex [rad]
680 float tgl = 0.f; // tan(lambda)
681 float qpt = 0.f; // signed q/pT [(GeV/c)^-1]
682 float vz = 0.f; // primary vertex z [cm]
683 float bzKG = std::numeric_limits<float>::quiet_NaN(); // signed O2 field convention [kG]; must be supplied
684};
685
710 float guardLowerCm = 0.f; // active-side exclusion adjacent to negative local-y edge
711 float guardUpperCm = 0.f; // active-side exclusion adjacent to positive local-y edge
712 float zMaxCm = 250.f; // symmetric TPC longitudinal acceptance |z| <= zMaxCm
713 float maxSnp = 0.9f; // radial-frame |sin(phiMom-phiPos)| < maxSnp; not O2 TrackPar::getSnp()
714};
715
728 float lengthCrossedCm = 0.f;
729 float lengthDeadCm = 0.f;
730 float lengthExcludedCm = 0.f;
731 float lengthAvailableCm = 0.f;
732 float maxRadiusCm = std::numeric_limits<float>::quiet_NaN(); // last accepted row radius [cm], not turning radius
733
738
739 std::array<uint32_t, 5> crossedMask{};
740 std::array<uint32_t, 5> deadMask{};
741 std::array<uint32_t, 5> excludedMask{};
742 std::array<uint32_t, 5> availableMask{};
743
744 int16_t firstDeadRow = -1;
745 int16_t lastDeadRow = -1;
747};
748
754 std::vector<float> lengthCrossedCm;
755 std::vector<float> lengthDeadCm;
756 std::vector<float> lengthExcludedCm;
757 std::vector<float> lengthAvailableCm;
758 std::vector<float> maxRadiusCm;
759
760 std::vector<int16_t> nRowsCrossed;
761 std::vector<int16_t> nRowsDead;
762 std::vector<int16_t> nRowsExcluded;
763 std::vector<int16_t> nRowsAvailable;
764
765 std::vector<int32_t> status;
766
767 void resize(std::size_t n)
768 {
769 lengthCrossedCm.resize(n);
770 lengthDeadCm.resize(n);
771 lengthExcludedCm.resize(n);
772 lengthAvailableCm.resize(n);
773 maxRadiusCm.resize(n);
774 nRowsCrossed.resize(n);
775 nRowsDead.resize(n);
776 nRowsExcluded.resize(n);
777 nRowsAvailable.resize(n);
778 status.resize(n);
779 }
780
781 void set(std::size_t i, const TPCSectorEdgeResult& r)
782 {
783 lengthCrossedCm[i] = r.lengthCrossedCm;
784 lengthDeadCm[i] = r.lengthDeadCm;
785 lengthExcludedCm[i] = r.lengthExcludedCm;
786 lengthAvailableCm[i] = r.lengthAvailableCm;
787 maxRadiusCm[i] = r.maxRadiusCm;
788 nRowsCrossed[i] = static_cast<int16_t>(r.nRowsCrossed);
789 nRowsDead[i] = static_cast<int16_t>(r.nRowsDead);
790 nRowsExcluded[i] = static_cast<int16_t>(r.nRowsExcluded);
791 nRowsAvailable[i] = static_cast<int16_t>(r.nRowsAvailable);
792 status[i] = static_cast<int32_t>(r.status);
793 }
794};
795
798 float x = 0.f;
799 float y = 0.f;
800 float z = 0.f;
801 float phiPos = 0.f;
802 float phiMom = 0.f;
803 float dsDr = 0.f;
804 bool valid = false;
805};
806
810inline void appendTrajectoryState(std::vector<o2::recohelpers::TrackParametersAtRadius>& trajectory,
811 const TrajectoryPoint& p, float qpt, float tgl)
812{
813 const float pt = 1.f / std::abs(qpt);
814 trajectory.push_back({p.x, p.y, p.z, pt * std::cos(p.phiMom), pt * std::sin(p.phiMom),
816}
817
819inline void setMaskBit(std::array<uint32_t, 5>& mask, int row)
820{
821 mask[row >> 5] |= uint32_t(1) << (row & 31);
822}
823
825inline int regionForRow(const o2::tpc::Mapper& mapper, int row)
826{
827 for (int i = 0; i < mapper.getNumberOfPadRegions(); ++i) {
828 const auto& r = mapper.getPadRegionInfo(i);
829 const int first = r.getGlobalRowOffset(), last = first + r.getNumberOfPadRows();
830 if (row >= first && row < last) {
831 return i;
832 }
833 }
834 return -1;
835}
836
838inline float rowRadius(const o2::tpc::Mapper& mapper, int row)
839{
840 const int ireg = regionForRow(mapper, row);
841 if (ireg < 0) {
842 return std::numeric_limits<float>::quiet_NaN();
843 }
844 const auto& r = mapper.getPadRegionInfo(ireg);
845 return r.getRadiusFirstRow() + (row - r.getGlobalRowOffset()) * r.getPadHeight();
846}
847
849inline float rowLengthRadial(const o2::tpc::Mapper& mapper, int row)
850{
851 const int ireg = regionForRow(mapper, row);
852 return ireg < 0 ? 0.f : mapper.getPadRegionInfo(ireg).getPadHeight();
853}
854
856inline float rowActiveHalfWidth(const o2::tpc::Mapper& mapper, int row)
857{
858 const int ireg = regionForRow(mapper, row);
859 if (ireg < 0) {
860 return 0.f;
861 }
862 const auto& r = mapper.getPadRegionInfo(ireg);
863 return 0.5f * mapper.getNumberOfPadsInRowSector(row) * r.getPadWidth();
864}
865
872{
873 if (!p.valid || !std::isfinite(p.x) || !std::isfinite(p.y) || !std::isfinite(p.phiMom)) {
874 return std::numeric_limits<float>::quiet_NaN();
875 }
876 return std::sin(p.phiMom - std::atan2(p.y, p.x));
877}
878
880inline float trajectoryLocalSnp(const TrajectoryPoint& p) { return trajectoryRadialSnp(p); }
881
884{
885 const float snp = trajectoryRadialSnp(p);
886 return p.valid && std::isfinite(p.z) && std::abs(p.z) <= cfg.zMaxCm &&
887 std::isfinite(snp) && std::abs(snp) < cfg.maxSnp;
888}
889
891inline bool reachedMaxSnp(const TrajectoryPoint& p, const TPCSectorEdgeConfig& cfg)
892{
893 const float snp = trajectoryRadialSnp(p);
894 return std::isfinite(snp) && std::abs(snp) >= cfg.maxSnp;
895}
896
900inline bool trackOutwardReference(const o2::track::TrackPar& track, float& radius)
901{
902 o2::track::TrackPar::dim3_t xyz{}, pxyz{};
903 if (!track.isValid() || !o2::recohelpers::extractGlobalState(track, xyz, pxyz)) {
904 return false;
905 }
906 radius = std::hypot(xyz[0], xyz[1]);
907 if (!std::isfinite(radius) || !std::isfinite(track.getQ2Pt()) ||
908 std::abs(track.getQ2Pt()) < 1.e-12f) {
909 return false;
910 }
911 // Negative radial motion at the supplied reference is not the first outward branch.
912 return radius < 1.e-5f || xyz[0] * pxyz[0] + xyz[1] * pxyz[1] >= 0.f;
913}
914
916inline TrajectoryPoint helixAtRadius(const o2::track::TrackPar& track, float radius, float bzKG)
917{
919 if (!track.isValid() || !std::isfinite(bzKG) || !(radius > 0.f)) {
920 return p;
921 }
924 if (!state.valid()) {
925 return p;
926 }
927 p.x = state.gx;
928 p.y = state.gy;
929 p.z = state.gz;
932 const float c = std::abs(std::cos(p.phiMom - p.phiPos));
933 const float tgl = o2::recohelpers::stateTgl(state);
934 p.dsDr = std::sqrt(1.f + tgl * tgl) / std::max(c, 1.e-6f);
935 p.valid = std::isfinite(p.dsDr);
936 return p;
937}
938
941{
942 if (!std::isfinite(seed.phi) || !std::isfinite(seed.tgl) || !std::isfinite(seed.qpt) ||
943 !std::isfinite(seed.bzKG) || std::abs(seed.qpt) < 1.e-12f) {
944 return {};
945 }
947 seed.phi, seed.tgl, seed.qpt, 0.f, 0.f, seed.vz),
948 radius, seed.bzKG);
949}
950
959inline void accumulateRow(const o2::tpc::Mapper& mapper, int row, const TrajectoryPoint& p, float rowLength,
961{
962 if (!rowWithinAcceptance(p, cfg) || !std::isfinite(rowLength) || rowLength <= 0.f) {
963 return;
964 }
965
966 const float phi = std::atan2(p.y, p.x);
967 const int sector = o2::math_utils::angle2Sector(phi);
969 const float localY = -p.x * std::sin(alpha) + p.y * std::cos(alpha);
970 const float halfWidth = rowActiveHalfWidth(mapper, row);
971 const float edgeDistance = halfWidth - std::abs(localY);
972 const float guard = localY < 0.f ? cfg.guardLowerCm : cfg.guardUpperCm;
973
974 ++out.nRowsCrossed;
975 out.maxRadiusCm = rowRadius(mapper, row);
976 out.lengthCrossedCm += rowLength;
978
979 if (edgeDistance < 0.f) {
980 ++out.nRowsDead;
981 out.lengthDeadCm += rowLength;
982 setMaskBit(out.deadMask, row);
983 if (out.firstDeadRow < 0) {
984 out.firstDeadRow = row;
985 }
986 out.lastDeadRow = row;
987 } else if (edgeDistance < guard) {
988 ++out.nRowsExcluded;
989 out.lengthExcludedCm += rowLength;
991 } else {
992 ++out.nRowsAvailable;
993 out.lengthAvailableCm += rowLength;
995 }
996}
997
1004 std::vector<o2::recohelpers::TrackParametersAtRadius>* trajectory = nullptr)
1005{
1006 TPCSectorEdgeResult out;
1007 if (trajectory) {
1008 trajectory->clear();
1009 }
1010 float startRadius = 0.f;
1011 if (!std::isfinite(bzKG) || !trackOutwardReference(track, startRadius)) {
1013 return out;
1014 }
1015 const auto& mapper = o2::tpc::Mapper::instance();
1016
1017 for (int row = 0; row < mapper.getNumberOfRows(); ++row) {
1018 const float r = rowRadius(mapper, row);
1019 if (r + 1.e-4f < startRadius) {
1020 if (trajectory) {
1021 trajectory->emplace_back(); // Preserve trajectory[row] indexing for skipped rows.
1022 }
1023 continue; // A full track can start inside the TPC; do not count earlier rows.
1024 }
1025 const auto p = helixAtRadius(track, r, bzKG);
1026 if (!p.valid) {
1027 break; // a larger radius cannot re-enter the first outward primary-helix branch
1028 }
1029 if (trajectory) {
1030 appendTrajectoryState(*trajectory, p, track.getQ2Pt(), track.getTgl());
1031 }
1032 if (reachedMaxSnp(p, cfg)) {
1033 break;
1034 }
1035 accumulateRow(mapper, row, p, rowLengthRadial(mapper, row) * p.dsDr, cfg, out);
1036 }
1037
1038 if (!out.nRowsCrossed) {
1040 }
1041 return out;
1042}
1043
1046 std::vector<o2::recohelpers::TrackParametersAtRadius>* trajectory = nullptr)
1047{
1048 if (!std::isfinite(seed.phi) || !std::isfinite(seed.tgl) || !std::isfinite(seed.qpt) ||
1049 !std::isfinite(seed.bzKG) || std::abs(seed.qpt) < 1.e-12f) {
1050 TPCSectorEdgeResult r;
1052 return r;
1053 }
1055 seed.phi, seed.tgl, seed.qpt, 0.f, 0.f, seed.vz),
1056 seed.bzKG, cfg, trajectory);
1057}
1058
1065inline bool plausibleFirstOutwardStep(float dr, float ds, float tgl, float maxSnp)
1066{
1067 if (!(dr > 0.f) || !(ds > 0.f) || !std::isfinite(ds) || !std::isfinite(tgl) ||
1068 !(maxSnp > 0.f && maxSnp < 1.f)) {
1069 return false;
1070 }
1071 const float minRadialCos = std::sqrt(1.f - maxSnp * maxSnp);
1072 return ds <= 10.f * dr * std::sqrt(1.f + tgl * tgl) / minRadialCos;
1073}
1074
1087 const TPCSectorEdgeConfig& cfg = {},
1088 std::vector<o2::recohelpers::TrackParametersAtRadius>* trajectory = nullptr)
1089{
1090 TPCSectorEdgeResult out;
1091 if (trajectory) {
1092 trajectory->clear();
1093 }
1094 const auto& mapper = o2::tpc::Mapper::instance();
1095 auto* prop = o2::base::Propagator::Instance();
1096 if (!prop->hasMagFieldSet()) {
1098 return out;
1099 }
1100 float startRadius = 0.f;
1101 if (!std::isfinite(bzKG) || !trackOutwardReference(inputTrack, startRadius) ||
1102 !std::isfinite(cfg.maxSnp) || !(cfg.maxSnp > 0.f && cfg.maxSnp < 1.f)) {
1103 out.status = SectorEdgeStatus::InvalidInput;
1104 return out;
1105 }
1106
1107 int firstRow = 0;
1108 while (firstRow < mapper.getNumberOfRows() &&
1109 rowRadius(mapper, firstRow) + 1.e-4f < startRadius) {
1110 ++firstRow;
1111 }
1112 if (firstRow == mapper.getNumberOfRows()) {
1114 return out;
1115 }
1116 const float r0 = rowRadius(mapper, firstRow);
1117 if (trajectory) {
1118 trajectory->resize(firstRow); // Keep diagnostic trace indexed by global TPC row.
1119 }
1120 // Preserve the reviewed K first-row seeding convention, but use the complete
1121 // original track rather than reconstructing a primary vertex. K field-map
1122 // transport from the original reference remains a separate physics-validation item.
1123 const auto p0 = helixAtRadius(inputTrack, r0, bzKG);
1124 if (!p0.valid) {
1126 return out;
1127 }
1128
1129 const float qpt = inputTrack.getQ2Pt();
1130 const float pt = 1.f / std::abs(qpt);
1131 const int charge = qpt >= 0.f ? 1 : -1;
1132 o2::track::TrackPar::dim3_t xyz{{p0.x, p0.y, p0.z}};
1133 o2::track::TrackPar::dim3_t pxyz{{pt * std::cos(p0.phiMom), pt * std::sin(p0.phiMom), pt * inputTrack.getTgl()}};
1134 o2::track::TrackPar track(xyz, pxyz, charge, true);
1136 path.clear();
1137 path.setTimeNotNeeded();
1138 float previousPathCm = 0.f;
1139 float previousRadiusCm = r0;
1140
1141 for (int row = firstRow; row < mapper.getNumberOfRows(); ++row) {
1142 const float radius = rowRadius(mapper, row);
1143 if (row > firstRow) {
1144 // Record accumulated transported path length. A later outward *orbit* can have positive dr/ds
1145 // and lie on the requested cylinder; radialCos > 0 alone would accept that wrong branch.
1146 // With radial |snp| < maxSnp, a first-branch step should be short relative to its radial
1147 // increment. This deliberately generous guard only rejects gross discontinuities; numerical
1148 // H/K row-mask agreement is checked separately by the physics oracle.
1149 if (!prop->propagateToR(track, radius, false, o2::base::Propagator::MAX_SIN_PHI,
1150 o2::base::Propagator::MAX_STEP,
1151 o2::base::Propagator::MatCorrType::USEMatCorrNONE, &path)) {
1153 return out;
1154 }
1155 const float deltaPathCm = path.getL() - previousPathCm;
1156 const float deltaRadiusCm = radius - previousRadiusCm;
1157 if (!plausibleFirstOutwardStep(deltaRadiusCm, deltaPathCm, track.getTgl(), cfg.maxSnp)) {
1159 return out;
1160 }
1161 previousPathCm = path.getL();
1162 previousRadiusCm = radius;
1163 }
1164
1165 const auto xyzg = track.getXYZGlo();
1166 TrajectoryPoint p;
1167 p.x = xyzg.X();
1168 p.y = xyzg.Y();
1169 p.z = xyzg.Z();
1170 p.phiPos = track.getPhiPos();
1171 p.phiMom = track.getPhi();
1172 const float dphi = p.phiMom - p.phiPos;
1173 const float radialCos = std::cos(dphi);
1174 // propagateToR() may return a state on a different branch or slightly off the target cylinder.
1175 // Neither may contribute a crossed row. The radial-frame snp limit is checked independently below.
1176 constexpr float radiusToleranceCm = 2.e-3f;
1177 const float actualRadius = std::hypot(p.x, p.y);
1178 if (!std::isfinite(actualRadius) || std::abs(actualRadius - radius) > radiusToleranceCm ||
1179 !std::isfinite(radialCos)) {
1181 return out;
1182 }
1183 if (radialCos <= 0.f) {
1184 break; // reached the transverse turning point or a returning arc
1185 }
1186 p.dsDr = std::sqrt(1.f + track.getTgl() * track.getTgl()) / radialCos;
1187 p.valid = true;
1188 if (trajectory) {
1189 appendTrajectoryState(*trajectory, p, track.getQ2Pt(), track.getTgl());
1190 }
1191 if (reachedMaxSnp(p, cfg)) {
1192 break;
1193 }
1194 accumulateRow(mapper, row, p, rowLengthRadial(mapper, row) * p.dsDr, cfg, out);
1195 }
1196
1197 if (!out.nRowsCrossed && out.status == SectorEdgeStatus::OK) {
1199 }
1200 return out;
1201}
1202
1205 const TPCSectorEdgeConfig& cfg = {},
1206 std::vector<o2::recohelpers::TrackParametersAtRadius>* trajectory = nullptr)
1207{
1208 if (!std::isfinite(seed.phi) || !std::isfinite(seed.tgl) || !std::isfinite(seed.qpt) ||
1209 !std::isfinite(seed.bzKG) || std::abs(seed.qpt) < 1.e-12f) {
1210 TPCSectorEdgeResult r;
1212 return r;
1213 }
1215 seed.phi, seed.tgl, seed.qpt, 0.f, 0.f, seed.vz),
1216 seed.bzKG, cfg, trajectory);
1217}
1218
1227 std::vector<o2::recohelpers::TrackParametersAtRadius>* trajectory = nullptr)
1228{
1229 TPCSectorEdgeResult out;
1230 if (trajectory) {
1231 trajectory->clear();
1232 }
1233 float startRadius = 0.f;
1234 if (!std::isfinite(bzKG) || !trackOutwardReference(track, startRadius)) {
1236 return out;
1237 }
1238 const auto& mapper = o2::tpc::Mapper::instance();
1239
1240 int first = 0;
1241 while (first < mapper.getNumberOfRows()) {
1242 const float h = rowLengthRadial(mapper, first);
1243 int last = first;
1244 while (last + 1 < mapper.getNumberOfRows() && std::abs(rowLengthRadial(mapper, last + 1) - h) < 1.e-6f) {
1245 ++last;
1246 }
1247
1248 if (rowRadius(mapper, first) + 1.e-4f < startRadius) {
1249 if (trajectory) {
1250 trajectory->emplace_back(); // Preserve global row indexing.
1251 }
1252 ++first; // Ignore rows inside the complete track's reference radius.
1253 continue;
1254 }
1255 const float r0 = rowRadius(mapper, first);
1256 const auto p0 = helixAtRadius(track, r0, bzKG);
1257 if (!p0.valid || reachedMaxSnp(p0, cfg)) {
1258 break;
1259 }
1260
1261 // The frozen Linear contract keeps a reachable partial stack. If the nominal
1262 // outer endpoint is unreachable or already beyond maxSnp, walk inward to the
1263 // last reachable row below maxSnp and use that row as the interpolation endpoint.
1264 int endpoint = last;
1265 auto p1 = helixAtRadius(track, rowRadius(mapper, endpoint), bzKG);
1266 bool stopAfterStack = false;
1267 while (endpoint > first && (!p1.valid || reachedMaxSnp(p1, cfg))) {
1268 --endpoint;
1269 p1 = helixAtRadius(track, rowRadius(mapper, endpoint), bzKG);
1270 stopAfterStack = true;
1271 }
1272 if (!p1.valid || reachedMaxSnp(p1, cfg)) {
1273 break;
1274 }
1275 stopAfterStack = stopAfterStack || endpoint < last;
1276
1277 const float r1 = rowRadius(mapper, endpoint);
1278 float dphi = p1.phiPos - p0.phiPos;
1279 o2::math_utils::detail::bringToPMPi(dphi);
1280 const float dr = std::max(r1 - r0, 1.e-6f);
1281 const float dphiDr = dphi / dr, dzDr = (p1.z - p0.z) / dr;
1282
1283 for (int row = first; row <= endpoint; ++row) {
1284 const float r = rowRadius(mapper, row), f = (r - r0) / dr;
1285 const float phi = p0.phiPos + f * dphi;
1286 TrajectoryPoint p;
1287 p.x = r * std::cos(phi);
1288 p.y = r * std::sin(phi);
1289 p.z = p0.z + f * (p1.z - p0.z);
1290 p.phiPos = phi;
1291 p.phiMom = phi + std::atan(r * dphiDr);
1292 p.dsDr = std::sqrt(1.f + (r * dphiDr) * (r * dphiDr) + dzDr * dzDr);
1293 // When the limit leaves a single reachable row, finite-difference derivatives are undefined.
1294 // Reuse the actual helix tangent and path length at that row rather than setting the slopes to zero.
1295 if (endpoint == first) {
1296 p.phiMom = p0.phiMom;
1297 p.dsDr = p0.dsDr;
1298 }
1299 p.valid = true;
1300 if (trajectory) {
1301 appendTrajectoryState(*trajectory, p, track.getQ2Pt(), track.getTgl());
1302 }
1303 if (reachedMaxSnp(p, cfg)) {
1304 stopAfterStack = true;
1305 break;
1306 }
1307 accumulateRow(mapper, row, p, rowLengthRadial(mapper, row) * p.dsDr, cfg, out);
1308 }
1309
1310 if (stopAfterStack) {
1311 break;
1312 }
1313 first = last + 1;
1314 }
1315
1316 if (!out.nRowsCrossed) {
1318 }
1319 return out;
1320}
1321
1324 std::vector<o2::recohelpers::TrackParametersAtRadius>* trajectory = nullptr)
1325{
1326 if (!std::isfinite(seed.phi) || !std::isfinite(seed.tgl) || !std::isfinite(seed.qpt) ||
1327 !std::isfinite(seed.bzKG) || std::abs(seed.qpt) < 1.e-12f) {
1328 TPCSectorEdgeResult r;
1330 return r;
1331 }
1333 seed.phi, seed.tgl, seed.qpt, 0.f, 0.f, seed.vz),
1334 seed.bzKG, cfg, trajectory);
1335}
1336
1337template <typename Evaluator>
1338inline TPCSectorEdgeBatchResult sectorEdgeBatch(const float* phi, const float* tgl, const float* qpt, const float* vz,
1339 std::size_t n, float bzKG, const TPCSectorEdgeConfig& cfg, Evaluator&& evaluate)
1340{
1342 out.resize(n);
1343
1344 if (!phi || !tgl || !qpt) {
1345 for (std::size_t i = 0; i < n; ++i) {
1348 out.set(i, r);
1349 }
1350 return out;
1351 }
1352
1353 for (std::size_t i = 0; i < n; ++i) {
1355 seed.phi = phi[i];
1356 seed.tgl = tgl[i];
1357 seed.qpt = qpt[i];
1358 seed.vz = vz ? vz[i] : 0.f;
1359 seed.bzKG = bzKG;
1360 out.set(i, evaluate(seed, cfg));
1361 }
1362 return out;
1363}
1364
1366inline TPCSectorEdgeBatchResult sectorEdgeHelixRowsBatch(const float* phi, const float* tgl, const float* qpt, const float* vz,
1367 std::size_t n, float bzKG, const TPCSectorEdgeConfig& cfg = {})
1368{
1369 return sectorEdgeBatch(phi, tgl, qpt, vz, n, bzKG, cfg,
1370 [](const TPCPrimaryTrackSeed& seed, const TPCSectorEdgeConfig& c) { return sectorEdgeHelixRows(seed, c); });
1371}
1372
1374inline TPCSectorEdgeBatchResult sectorEdgeStackLinearBatch(const float* phi, const float* tgl, const float* qpt, const float* vz,
1375 std::size_t n, float bzKG, const TPCSectorEdgeConfig& cfg = {})
1376{
1377 return sectorEdgeBatch(phi, tgl, qpt, vz, n, bzKG, cfg,
1378 [](const TPCPrimaryTrackSeed& seed, const TPCSectorEdgeConfig& c) { return sectorEdgeStackLinear(seed, c); });
1379}
1380
1382inline TPCSectorEdgeBatchResult sectorEdgeO2PropagatorRowsBatch(const float* phi, const float* tgl, const float* qpt, const float* vz,
1383 std::size_t n, float bzKG, const TPCSectorEdgeConfig& cfg = {})
1384{
1385 return sectorEdgeBatch(phi, tgl, qpt, vz, n, bzKG, cfg,
1386 [](const TPCPrimaryTrackSeed& seed, const TPCSectorEdgeConfig& c) {
1387 return sectorEdgeO2PropagatorRows(seed, c);
1388 });
1389}
1390
1396template <typename Evaluator>
1398 const float* x, const float* alpha, const float* y, const float* z,
1399 const float* snp, const float* tgl, const float* qpt,
1400 std::size_t n, float bzKG, const TPCSectorEdgeConfig& cfg, Evaluator&& evaluate)
1401{
1403 out.resize(n);
1404 for (std::size_t i = 0; i < n; ++i) {
1405 if (!x || !alpha || !y || !z || !snp || !tgl || !qpt ||
1406 !std::isfinite(x[i]) || !std::isfinite(alpha[i]) || !std::isfinite(y[i]) ||
1407 !std::isfinite(z[i]) || !std::isfinite(snp[i]) || !std::isfinite(tgl[i]) ||
1408 !std::isfinite(qpt[i]) || std::abs(qpt[i]) < 1.e-12f || std::abs(snp[i]) >= 1.f) {
1411 out.set(i, r);
1412 continue;
1413 }
1415 x[i], alpha[i], y[i], z[i], snp[i], tgl[i], qpt[i]);
1416 out.set(i, evaluate(track, bzKG, cfg));
1417 }
1418 return out;
1419}
1420
1422 const float* x, const float* alpha, const float* y, const float* z,
1423 const float* snp, const float* tgl, const float* qpt,
1424 std::size_t n, float bzKG, const TPCSectorEdgeConfig& cfg = {})
1425{
1426 return localSectorEdgeBatch(x, alpha, y, z, snp, tgl, qpt, n, bzKG, cfg,
1427 [](const o2::track::TrackPar& t, float bz, const TPCSectorEdgeConfig& c) {
1428 return sectorEdgeHelixRows(t, bz, c);
1429 });
1430}
1431
1433 const float* x, const float* alpha, const float* y, const float* z,
1434 const float* snp, const float* tgl, const float* qpt,
1435 std::size_t n, float bzKG, const TPCSectorEdgeConfig& cfg = {})
1436{
1437 return localSectorEdgeBatch(x, alpha, y, z, snp, tgl, qpt, n, bzKG, cfg,
1438 [](const o2::track::TrackPar& t, float bz, const TPCSectorEdgeConfig& c) {
1439 return sectorEdgeStackLinear(t, bz, c);
1440 });
1441}
1442
1444 const float* x, const float* alpha, const float* y, const float* z,
1445 const float* snp, const float* tgl, const float* qpt,
1446 std::size_t n, float bzKG, const TPCSectorEdgeConfig& cfg = {})
1447{
1448 return localSectorEdgeBatch(x, alpha, y, z, snp, tgl, qpt, n, bzKG, cfg,
1449 [](const o2::track::TrackPar& t, float bz, const TPCSectorEdgeConfig& c) {
1450 return sectorEdgeO2PropagatorRows(t, bz, c);
1451 });
1452}
1453
1455
1456} // namespace o2::tpc::recohelpers
1457
1458#endif // ALICEO2_TRACKTOOLS_TRACKGEOMETRY_H_
General auxilliary methods.
Base track model for the Barrel, params only, w/o covariance.
int16_t charge
Definition RawEventData.h:5
uint64_t phase
Definition RawEventData.h:7
unsigned short int uint16_t
unsigned int uint32_t
int32_t i
configStandalone Light OpenGL display display_light Apply smoothing to points Enable Z buffer Highlight links Highlight seeds Highlight sector tracks Highlight final tracks Show individual sector
Timeframe settings Average distance in cm of events merged into Randomize distance around average distance of merged events Simulate correct bunch interactions instead of placing only the average number of events A value[n] sets TFlen for[n] collisions in Number of bunches per trainsort Number of bunch trains Instantaneous interaction rate Do not simulate border Total number of collisions to be placed in the interior of all time Do not select random but walk over array of events in stride steps h Event generator settings h configStandalone Use CPU for GPU Force usage of the specified GPU device no CPU fallback Continue processing after an error First event to Number of events to Number of iterations to Number of iterations to Number of initial iterations excluded from const char Directory with events to Events directory is and not inside events d
configStandalone Reconstruction rec_tpc multiplier for the combined cluster track error during track following area in cm for the search of for z only used if decrease removal by when above this local occupancy rowx Shift of TPC revert cluster flag edge bit distance to edge exceeds this ZOffset for secondary multiple of radius max P of electron K BB bands crossing max P of electron p BB bands crossing max P of electron d BB bands crossing max P of electron t BB bands crossing min accepted dEdxMaxTPC of the track Additive extra cluster error for Y2 if edge flag set Additive extra cluster error for Y2 if single set Additive extra cluster error for Y2 if or single set Additive extra cluster error for Z2 if or single set Extra errors to add to track when crossing depending on addErrorsCECrossing Inner portion of y range in sector that is not used in searching for extrapolated track candidates factor2YS for track merging factor2K for track merging Margin in cm of Y position when rejecting edge clusters based on uncorrected track Y Max fraction of shared clusters for tracklet Except pad from cluster finding if total number of charges in a fragment is above this Except pad from cluster finding if number of consecutive charges in a fragment is above this Threshold where a timebin is considered disabling the noisy pad check for that pad Treat signal above this minimum as saturated Smoothing factor for the exponential Highly Ionising Particle tail filter Number of timebins to use for the averaging Add additional custom track errors when crossing relative as fraction of Do N fit passes in final fit of< 0:reject at max -n hits") AddOptionRTC(rejectIFCLowRadiusCluster, uint8_t, 1, "", 0, "Reject clusters that get the IFC mask error during refit") AddOptionRTC(dEdxTruncLow, uint8_t, 2, "", 0, "Low truncation threshold, fraction of 128") AddOptionRTC(dEdxTruncHigh, uint8_t, 77, "", 0, "High truncation threshold, fraction of 128") AddOptionRTC(extrapolationTracking, int8_t, 1, "", 0, "Enable Extrapolation Tracking(prolong tracks to adjacent sectors to find short segments)") AddOptionRTC(disableRefitAttachment, uint8_t, 0, "", 0, "Bitmask to disable certain attachment steps during refit(1:attachment, 2:propagation, 4:loop following, 8:mirroring)") AddOptionRTC(rejectionStrategy, uint8_t, o2::gpu::GPUSettings::RejectionStrategyA, "", 0, "Enable rejection of TPC clusters for compression(0=no, 1=strategy A, 2=strategy B)") AddOptionRTC(mergeLoopersAfterburner, uint8_t, 1, "", 0, "Run afterburner for additional looper merging") AddOptionRTC(compressionTypeMask, uint8_t, o2::gpu::GPUSettings::CompressionFull, "", 0, "TPC Compression mode bits(1=truncate charge/width LSB, 2=differences, 4=track-model)") AddOptionRTC(compressionSortOrder, uint8_t, o2::gpu::GPUSettings::SortTime, "", 0, "Sort order of TPC compression(0=time, 1=pad, 2=Z-time-pad, 3=Z-pad-time, 4=no sorting(use incoming order))") AddOptionRTC(sigBitsCharge, uint8_t, 4, "", 0, "Number of significant bits for TPC cluster charge in compression mode 1") AddOptionRTC(sigBitsWidth, uint8_t, 3, "", 0, "Number of significant bits for TPC cluster width in compression mode 1") AddOptionRTC(dropLoopers, uint8_t, 0, "", 0, "Drop looping tracks starting from second loop") AddOptionRTC(mergerInterpolateErrors, uint8_t, 1, "", 0, "Use interpolation instead of extrapolation for chi2 based cluster rejection") AddOptionRTC(mergerInterpolateRejectAlsoOnCurrentPosition, uint8_t, 1, "", 0, "When using mergerInterpolateErrors, reject based on chi2 twice computed with interpolated and current track position starting from NDF > mergerNonInterpolateRejectMinNDF Merge tracks accross the central electrode Enable PID response Add sub threshold clusters in TPC dEdx computation OR mask of TPC flags that will reject the cluster in alternative dEdx Reject edge clusters based on uncorrected track Y during track fit Increase decrease removal by when on this number of pads from the edge h configStandalone Reconstruction rec_trd Max chi2 for TRD tracklets to be matched to a track Chi2 cut for strict matching mode Number of sigmas for ITS TPC track time error estimate Addition to search road around track prolongation along Y in cm Optimal tracklet rphi resolution in maximum chi2 per attached tracklet for TRD tracks take into account the full likelihood of the slope including exponential tails Tracks with less attached tracklets are discarded after the tracking Post trigger Pile up integration time in BCs fits all iterations but the last one in projections Use material lookup table for TPC refit Apply workarounds to avoid cyclic merge should not be needed tpc dyn configStandalone Processing proc_rtc Replace constant variables static by constexpr expressions Compile RTC in deterministic with NO_FAST_MATH flags and GPUCA_DETERMINISTIC_MODE define Use RTC to optimize GPU code h configStandalone Processing proc_rtctech Use a file lock to serialize access to the cache folder int32_t
constexpr int p1()
constexpr to accelerate the coordinates changing
SurfaceTrackState state
useful math constants
uint8_t endpoint
Definition RawData.h:0
uint32_t c
Definition RawData.h:2
double radius
Class for time synchronization of RawReader instances.
GPUd() value_type estimateLTFast(o2 static GPUd() float estimateLTIncrement(const o2 PropagatorImpl * Instance(bool uninitialized=false)
Definition Propagator.h:180
int getNumberOfPadsInRowSector(int row) const
Definition Mapper.h:340
static Mapper & instance(const std::string mappingDir="")
Definition Mapper.h:44
const PadRegionInfo & getPadRegionInfo(const unsigned char region) const
Definition Mapper.h:385
int getNumberOfPadRegions() const
Definition Mapper.h:387
float getPadHeight() const
std::array< value_t, kNParams > params_t
GLdouble n
Definition glcorearb.h:1982
GLfloat GLfloat GLfloat alpha
Definition glcorearb.h:279
GLint GLenum GLint x
Definition glcorearb.h:403
GLint first
Definition glcorearb.h:399
GLdouble f
Definition glcorearb.h:310
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
GLint y
Definition glcorearb.h:270
GLuint GLfloat x0
Definition glcorearb.h:5034
GLsizei const GLchar *const * path
Definition glcorearb.h:3591
GLboolean r
Definition glcorearb.h:1233
GLboolean GLboolean GLboolean GLboolean a
Definition glcorearb.h:1233
GLint GLuint mask
Definition glcorearb.h:291
GLuint GLfloat GLfloat y0
Definition glcorearb.h:5034
GLdouble GLdouble GLdouble z
Definition glcorearb.h:843
const bool const int TrackITSInternal< NLayers > & track
int angle2Sector(float phi)
Definition Utils.h:183
float sector2Angle(int sect)
Definition Utils.h:193
std::array< int, 24 > p0
TrackParametersAtRadiusBatchResult localTrackParametersAtRadiusK0Batch(const float *x, const float *alpha, const float *y, const float *z, const float *snp, const float *tgl, const float *qpt, std::size_t n, float radius, float bzKG, int nSectors=18, float sectorPhaseRad=0.f)
Batch K0 transport for tracks supplied in local O2 parameterization.
float stateTgl(const TrackParametersAtRadius &state)
tan(lambda)=pz/pT of the propagated state, or NaN for an invalid state.
float phiAtRadius(const o2::track::TrackPar &track, float radius, float bzKG, o2::track::DirType dir=o2::track::DirType::DirOutward)
Backward-compatible scalar wrapper returning only the propagated position azimuth using K0.
TrackParametersAtRadiusBatchResult primaryTrackParametersAtRadiusBatch(const float *phi, const float *tgl, const float *qpt, const float *vx, const float *vy, const float *vz, std::size_t n, float radius, float bzKG, int nSectors, float sectorPhaseRad, Evaluator &&evaluate)
TrackParametersAtRadius getParametersAtRadiusK0(const o2::track::TrackPar &track, float radius, float bzKG, o2::track::DirType dir=o2::track::DirType::DirOutward)
K0 transport: O2 TrackPar propagation to a cylindrical radius in Bz, without material correction.
TrackParametersAtRadiusBatchResult localTrackParametersAtRadiusBatch(const float *x, const float *alpha, const float *y, const float *z, const float *snp, const float *tgl, const float *qpt, std::size_t n, float radius, float bzKG, int nSectors, float sectorPhaseRad, Evaluator &&evaluate)
bool extractGlobalState(const o2::track::TrackPar &track, o2::track::TrackPar::dim3_t &xyz, o2::track::TrackPar::dim3_t &pxyz)
Extract finite global position and momentum from an O2 TrackPar.
float primaryDSectorAtRadius(float phi, float tgl, float qpt, float radius, float bzKG, int nSectors=18, float vz=0.f, float sectorPhaseRad=0.f)
Fractional sector coordinate at radius for the reduced primary-like parameterization,...
float statePhiMom(const TrackParametersAtRadius &state)
Global azimuth of the propagated momentum, atan2(py,px), or NaN for an invalid state.
TrackParametersStatus
Status returned by the cylindrical-radius track-parameter evaluators.
float stateDSector(const TrackParametersAtRadius &state, int nSectors=18, float sectorPhaseRad=0.f)
dSector() evaluated from the propagated global position azimuth.
TrackParametersAtRadius getParametersAtRadiusH(const o2::track::TrackPar &track, float radius, float bzKG, o2::track::DirType dir=o2::track::DirType::DirOutward)
H transport: analytic helix intersection with a cylindrical radius in uniform Bz.
float statePhiPos(const TrackParametersAtRadius &state)
Global azimuth of the propagated position, atan2(y,x), or NaN for an invalid state.
std::vector< float > primaryDSectorAtRadiusBatch(const float *phi, const float *tgl, const float *qpt, const float *vz, std::size_t n, float radius, float bzKG, int nSectors=18, float sectorPhaseRad=0.f)
TrackParametersAtRadiusBatchResult primaryTrackParametersAtRadiusK0Batch(const float *phi, const float *tgl, const float *qpt, const float *vx, const float *vy, const float *vz, std::size_t n, float radius, float bzKG, int nSectors=18, float sectorPhaseRad=0.f)
Batch K0 transport for reduced primary-like inputs.
o2::track::TrackPar makeTrackParFromPrimaryApproximation(float phi, float tgl, float qpt, float vx=0.f, float vy=0.f, float vz=0.f)
Build an O2 TrackPar from a reduced primary-like state.
std::vector< float > primaryPhiAtRadiusBatch(const float *phi, const float *tgl, const float *qpt, const float *vz, std::size_t n, float radius, float bzKG)
Backward-compatible batch wrappers retained for existing commissioning notebooks/tests.
TrackParametersAtRadiusBatchResult primaryTrackParametersAtRadiusHBatch(const float *phi, const float *tgl, const float *qpt, const float *vx, const float *vy, const float *vz, std::size_t n, float radius, float bzKG, int nSectors=18, float sectorPhaseRad=0.f)
Batch H transport for reduced primary-like inputs.
o2::track::TrackPar makeTrackParFromLocalParameters(float x, float alpha, float y, float z, float snp, float tgl, float qpt, int absCharge=1)
Build an O2 TrackPar from the standard local O2 track parameterization.
TrackParametersAtRadiusBatchResult localTrackParametersAtRadiusHBatch(const float *x, const float *alpha, const float *y, const float *z, const float *snp, const float *tgl, const float *qpt, std::size_t n, float radius, float bzKG, int nSectors=18, float sectorPhaseRad=0.f)
Batch H transport for tracks supplied in local O2 parameterization.
float dSector(float phi, int nSectors=18, float sectorPhaseRad=0.f)
Fractional azimuthal position inside a periodic sector pattern.
bool directionMatches(o2::track::DirType dir, float drds)
Check whether the radial derivative is compatible with the requested propagation direction.
o2::track::TrackPar makePrimaryTrackPar(float phi, float tgl, float qpt, float vz=0.f)
Backward-compatible reduced-primary constructor used by existing commissioning code.
float primaryPhiAtRadius(float phi, float tgl, float qpt, float radius, float bzKG, float vz=0.f)
Position azimuth at radius for the reduced primary-like parameterization, evaluated with K0.
PrimaryTrackGeometryBatchResult primaryTrackGeometryAtRadiusBatch(const float *phi, const float *tgl, const float *qpt, const float *vz, std::size_t n, float radius, float bzKG, int nSectors=18, float sectorPhaseRad=0.f)
float dSectorAtRadius(const o2::track::TrackPar &track, float radius, float bzKG, int nSectors=18, o2::track::DirType dir=o2::track::DirType::DirOutward, float sectorPhaseRad=0.f)
Backward-compatible scalar wrapper returning only the propagated fractional sector coordinate using K...
TPCSectorEdgeResult sectorEdgeO2PropagatorRows(const o2::track::TrackPar &inputTrack, float bzKG, const TPCSectorEdgeConfig &cfg={}, std::vector< o2::recohelpers::TrackParametersAtRadius > *trajectory=nullptr)
K row evaluator: O2 Propagator traversal of TPC row radii without material correction.
float trajectoryRadialSnp(const TrajectoryPoint &p)
Radial-frame sin(phiMom-phiPos); independent of the O2 TrackPar alpha rotation.
TPCSectorEdgeBatchResult sectorEdgeStackLinearBatch(const float *phi, const float *tgl, const float *qpt, const float *vz, std::size_t n, float bzKG, const TPCSectorEdgeConfig &cfg={})
Batch wrapper for the stack-linear L TPC row evaluator.
TPCSectorEdgeBatchResult localSectorEdgeO2PropagatorRowsBatch(const float *x, const float *alpha, const float *y, const float *z, const float *snp, const float *tgl, const float *qpt, std::size_t n, float bzKG, const TPCSectorEdgeConfig &cfg={})
TPCSectorEdgeBatchResult sectorEdgeBatch(const float *phi, const float *tgl, const float *qpt, const float *vz, std::size_t n, float bzKG, const TPCSectorEdgeConfig &cfg, Evaluator &&evaluate)
TPCSectorEdgeResult sectorEdgeHelixRows(const o2::track::TrackPar &track, float bzKG, const TPCSectorEdgeConfig &cfg={}, std::vector< o2::recohelpers::TrackParametersAtRadius > *trajectory=nullptr)
H row evaluator: analytic helix sampled at the current Mapper row radii.
bool rowWithinAcceptance(const TrajectoryPoint &p, const TPCSectorEdgeConfig &cfg)
True when a valid row-centre trajectory point satisfies the configured z and snp acceptance.
void setMaskBit(std::array< uint32_t, 5 > &mask, int row)
Set one of the 152 TPC row bits in the five-word row mask.
float trajectoryLocalSnp(const TrajectoryPoint &p)
Backward-compatible internal spelling; use trajectoryRadialSnp for new code.
TPCSectorEdgeBatchResult localSectorEdgeStackLinearBatch(const float *x, const float *alpha, const float *y, const float *z, const float *snp, const float *tgl, const float *qpt, std::size_t n, float bzKG, const TPCSectorEdgeConfig &cfg={})
bool plausibleFirstOutwardStep(float dr, float ds, float tgl, float maxSnp)
Conservative path-continuity guard against a later outward orbit.
TPCSectorEdgeBatchResult sectorEdgeO2PropagatorRowsBatch(const float *phi, const float *tgl, const float *qpt, const float *vz, std::size_t n, float bzKG, const TPCSectorEdgeConfig &cfg={})
Batch wrapper for the O2 Propagator K TPC row evaluator, without material correction.
TPCSectorEdgeResult sectorEdgeStackLinear(const o2::track::TrackPar &track, float bzKG, const TPCSectorEdgeConfig &cfg={}, std::vector< o2::recohelpers::TrackParametersAtRadius > *trajectory=nullptr)
L row evaluator: stack-local linear approximation to the analytic helix.
float rowLengthRadial(const o2::tpc::Mapper &mapper, int row)
Radial row thickness, taken from the Mapper pad height [cm].
SectorEdgeStatus
Status returned by the TPC row/sector-edge evaluators.
float rowActiveHalfWidth(const o2::tpc::Mapper &mapper, int row)
Active half-width of one TPC row in local-y from Mapper pad count and pad width [cm].
TPCSectorEdgeBatchResult localSectorEdgeBatch(const float *x, const float *alpha, const float *y, const float *z, const float *snp, const float *tgl, const float *qpt, std::size_t n, float bzKG, const TPCSectorEdgeConfig &cfg, Evaluator &&evaluate)
Evaluate row acceptance for a batch of complete O2 local 5D track states. Input arrays are x,...
bool reachedMaxSnp(const TrajectoryPoint &p, const TPCSectorEdgeConfig &cfg)
True when the radial-frame inclination reaches the configured stopping boundary.
TPCSectorEdgeBatchResult sectorEdgeHelixRowsBatch(const float *phi, const float *tgl, const float *qpt, const float *vz, std::size_t n, float bzKG, const TPCSectorEdgeConfig &cfg={})
Batch wrapper for the analytic H TPC row evaluator.
TrajectoryPoint primaryHelixAtRadius(const TPCPrimaryTrackSeed &seed, float radius)
Legacy reduced-primary adapter to the same complete-track H implementation.
bool trackOutwardReference(const o2::track::TrackPar &track, float &radius)
Validate the complete input state and report its global reference radius. An outward-only row query d...
TrajectoryPoint helixAtRadius(const o2::track::TrackPar &track, float radius, float bzKG)
One TPC row trajectory sample from a complete O2 local five-parameter track.
TPCSectorEdgeBatchResult localSectorEdgeHelixRowsBatch(const float *x, const float *alpha, const float *y, const float *z, const float *snp, const float *tgl, const float *qpt, std::size_t n, float bzKG, const TPCSectorEdgeConfig &cfg={})
void appendTrajectoryState(std::vector< o2::recohelpers::TrackParametersAtRadius > &trajectory, const TrajectoryPoint &p, float qpt, float tgl)
Debug-only row state; trajectory[row] is the state at that sampled TPC row. Append even the first sta...
float rowRadius(const o2::tpc::Mapper &mapper, int row)
Current sampled TPC row radius [cm]; F6 physical pad-centre correction remains pending.
int regionForRow(const o2::tpc::Mapper &mapper, int row)
Return the Mapper pad-region index containing a global TPC row, or -1 if none.
void accumulateRow(const o2::tpc::Mapper &mapper, int row, const TrajectoryPoint &p, float rowLength, const TPCSectorEdgeConfig &cfg, TPCSectorEdgeResult &out)
Apply acceptance and classify one crossed row as Dead, Excluded, or Available.
TrackParF TrackPar
Definition Track.h:29
Legacy compact batch result containing only position azimuth and fractional sector coordinate.
Structure-of-arrays result for batch cylindrical-radius propagation.
void set(std::size_t i, const TrackParametersAtRadius &state, int nSectors, float sectorPhaseRad)
Global track state evaluated at a requested cylindrical radius.
Reduced primary-track seed used by the TPC row evaluators.
Structure-of-arrays batch result for the TPC row/sector-edge evaluators.
void set(std::size_t i, const TPCSectorEdgeResult &r)
Configuration for TPC row acceptance and sector-edge classification.
Result of one TPC row/sector-edge evaluation.
std::array< uint32_t, 5 > availableMask
Internal global trajectory sample at one TPC row-centre radius.
o2::mch::DsIndex ds
std::vector< int > row