|
| 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 | + |
| 12 | +/// |
| 13 | +/// \file TrackerACTS.h |
| 14 | +/// \brief TRK tracker using ACTS seeding algorithm |
| 15 | +/// \author Nicolò Jacazio, Università del Piemonte Orientale (IT) |
| 16 | +/// \since 2026-04-01 |
| 17 | +/// |
| 18 | + |
| 19 | +#ifndef ALICE3_INCLUDE_TRACKERACTS_H_ |
| 20 | +#define ALICE3_INCLUDE_TRACKERACTS_H_ |
| 21 | + |
| 22 | +#include "Acts/Definitions/Units.hpp" |
| 23 | +#include "Framework/Logger.h" |
| 24 | + |
| 25 | +#include "ITStracking/TimeFrame.h" |
| 26 | +#include "TH2F.h" |
| 27 | + |
| 28 | +namespace o2::trk |
| 29 | +{ |
| 30 | + |
| 31 | +/// Configuration for the ACTS-based tracker |
| 32 | +struct TrackerACTSConfig { |
| 33 | + // Seeding parameters |
| 34 | + float minPt = 0.4f * Acts::UnitConstants::GeV; ///< Minimum pT for seeds |
| 35 | + float maxImpactParameter = 10.f * Acts::UnitConstants::mm; ///< Maximum impact parameter |
| 36 | + float cotThetaMax = std::sinh(4.0f); ///< Maximum cot(theta), corresponds to eta ~4 |
| 37 | + |
| 38 | + // Delta R cuts for doublet/triplet formation |
| 39 | + float deltaRMinBottom = 5.f * Acts::UnitConstants::mm; ///< Min deltaR for bottom-middle |
| 40 | + float deltaRMaxBottom = 200.f * Acts::UnitConstants::mm; ///< Max deltaR for bottom-middle |
| 41 | + float deltaRMinTop = 5.f * Acts::UnitConstants::mm; ///< Min deltaR for middle-top |
| 42 | + float deltaRMaxTop = 200.f * Acts::UnitConstants::mm; ///< Max deltaR for middle-top |
| 43 | + |
| 44 | + // Z cuts |
| 45 | + float zMin = -3000.f * Acts::UnitConstants::mm; |
| 46 | + float zMax = 3000.f * Acts::UnitConstants::mm; |
| 47 | + |
| 48 | + // Collision region |
| 49 | + float collisionRegionMin = -150.f * Acts::UnitConstants::mm; |
| 50 | + float collisionRegionMax = 150.f * Acts::UnitConstants::mm; |
| 51 | + |
| 52 | + // Quality cuts |
| 53 | + float maxSeedsPerMiddleSP = 2; |
| 54 | + float deltaPhiMax = 0.1f; ///< Maximum phi difference for doublets |
| 55 | +}; |
| 56 | + |
| 57 | +/// Space point representation for tracking |
| 58 | +struct SpacePoint { |
| 59 | + float x{0.f}; |
| 60 | + float y{0.f}; |
| 61 | + float z{0.f}; |
| 62 | + int layer{-1}; |
| 63 | + int clusterId{-1}; |
| 64 | + int rof{-1}; |
| 65 | + |
| 66 | + // Derived quantities |
| 67 | + float r() const { return std::hypot(x, y); } |
| 68 | + float radius() const { return r(); } // required by Acts::CylindricalGridElement concept |
| 69 | + float phi() const { return std::atan2(y, x); } |
| 70 | + |
| 71 | + // Variance estimates (can be refined based on cluster properties) |
| 72 | + float varianceR{0.01f}; // ~100 um resolution squared |
| 73 | + float varianceZ{0.01f}; |
| 74 | +}; |
| 75 | + |
| 76 | +/// Seed (triplet of space points) |
| 77 | +struct SeedACTS { |
| 78 | + const SpacePoint* bottom{nullptr}; |
| 79 | + const SpacePoint* middle{nullptr}; |
| 80 | + const SpacePoint* top{nullptr}; |
| 81 | + float quality{0.f}; |
| 82 | +}; |
| 83 | + |
| 84 | +/// TRK Tracker using ACTS algorithms for seeding and track finding |
| 85 | +template <int nLayers> |
| 86 | +class TrackerACTS |
| 87 | +{ |
| 88 | + public: |
| 89 | + TrackerACTS(); |
| 90 | + ~TrackerACTS() |
| 91 | + { |
| 92 | + if (mHistSpacePoints) { |
| 93 | + mHistSpacePoints->SaveAs("/tmp/mHistSpacePoints.C"); |
| 94 | + delete mHistSpacePoints; |
| 95 | + mHistSpacePoints = nullptr; |
| 96 | + } |
| 97 | + } |
| 98 | + |
| 99 | + /// Adopt a TimeFrame for processing |
| 100 | + void adoptTimeFrame(o2::its::TimeFrame<nLayers>& tf); |
| 101 | + |
| 102 | + /// Main tracking entry point: convert clusters to tracks |
| 103 | + void clustersToTracks(); |
| 104 | + |
| 105 | + /// Configuration |
| 106 | + void setConfig(const TrackerACTSConfig& cfg) { mConfig = cfg; } |
| 107 | + TrackerACTSConfig& getConfig() { return mConfig; } |
| 108 | + const TrackerACTSConfig& getConfig() const { return mConfig; } |
| 109 | + |
| 110 | + /// Set the magnetic field strength |
| 111 | + void setBz(float bz) { mBz = bz; } |
| 112 | + |
| 113 | + /// Get the magnetic field strength |
| 114 | + float getBz() const { return mBz; } |
| 115 | + |
| 116 | + /// Print tracking summary |
| 117 | + void printSummary() const; |
| 118 | + |
| 119 | + private: |
| 120 | + TH2F* mHistSpacePoints = nullptr; |
| 121 | + |
| 122 | + /// Build space points from clusters in the TimeFrame |
| 123 | + void buildSpacePoints(int rof); |
| 124 | + |
| 125 | + /// Create seeds (triplets) from space points using ACTS SeedFinder |
| 126 | + void createSeeds(); |
| 127 | + |
| 128 | + /// Estimate track parameters from a seed using ACTS |
| 129 | + bool estimateTrackParams(const SeedACTS& seed, o2::its::TrackITSExt& track) const; |
| 130 | + |
| 131 | + /// Run track finding from seeds |
| 132 | + void findTracks(); |
| 133 | + |
| 134 | + /// Assign MC labels to tracks |
| 135 | + void computeTracksMClabels(); |
| 136 | + |
| 137 | + /// Helper: time a task |
| 138 | + template <typename Func> |
| 139 | + float evaluateTask(Func&& task, std::string_view taskName); |
| 140 | + |
| 141 | + // Configuration |
| 142 | + TrackerACTSConfig mConfig; |
| 143 | + |
| 144 | + // TimeFrame data |
| 145 | + o2::its::TimeFrame<nLayers>* mTimeFrame = nullptr; |
| 146 | + |
| 147 | + // Space points built from clusters |
| 148 | + std::vector<SpacePoint> mSpacePoints; |
| 149 | + std::vector<std::vector<const SpacePoint*>> mSpacePointsPerLayer; |
| 150 | + |
| 151 | + // Seeds |
| 152 | + std::vector<SeedACTS> mSeeds; |
| 153 | + |
| 154 | + // Tracking state |
| 155 | + float mBz{0.5f}; ///< Magnetic field in Tesla |
| 156 | + unsigned int mTimeFrameCounter{0}; |
| 157 | + double mTotalTime{0.}; |
| 158 | + |
| 159 | + // Tracking states for logging |
| 160 | + enum State { |
| 161 | + SpacePointBuilding = 0, |
| 162 | + Seeding, |
| 163 | + TrackFinding, |
| 164 | + NStates, |
| 165 | + }; |
| 166 | + State mCurState{SpacePointBuilding}; |
| 167 | + static constexpr std::array<const char*, NStates> StateNames{ |
| 168 | + "Space point building", |
| 169 | + "ACTS seeding", |
| 170 | + "Track finding"}; |
| 171 | +}; |
| 172 | + |
| 173 | +template <int nLayers> |
| 174 | +template <typename Func> |
| 175 | +float TrackerACTS<nLayers>::evaluateTask(Func&& task, std::string_view taskName) |
| 176 | +{ |
| 177 | + LOG(debug) << " + Starting " << taskName; |
| 178 | + const auto start = std::chrono::high_resolution_clock::now(); |
| 179 | + task(); |
| 180 | + const auto end = std::chrono::high_resolution_clock::now(); |
| 181 | + std::chrono::duration<double, std::milli> diff{end - start}; |
| 182 | + |
| 183 | + LOG(debug) << " - " << taskName << " completed in: " << std::fixed << std::setprecision(2) << diff.count() << " ms"; |
| 184 | + return static_cast<float>(diff.count()); |
| 185 | +} |
| 186 | + |
| 187 | +} // namespace o2::trk |
| 188 | + |
| 189 | +#endif /* ALICE3_INCLUDE_TRACKERACTS_H_ */ |
0 commit comments