ATLAS Offline Software
Loading...
Searching...
No Matches
TrackFindingGNNAlg.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
6
7// Athena
12
13// ACTS
14#include "Acts/Definitions/Units.hpp"
15#include "Acts/EventData/VectorMultiTrajectory.hpp"
16#include "Acts/EventData/VectorTrackContainer.hpp"
17#include "Acts/Geometry/TrackingGeometry.hpp"
18#include "Acts/Surfaces/Surface.hpp"
19#include "Acts/Utilities/MathHelpers.hpp"
20
21// ActsTrk
25
26// STL
27#include <algorithm>
28#include <cmath>
29#include <optional>
30#include <stdexcept>
31#include <string>
32#include <utility>
33#include <vector>
34#include <boost/container/small_vector.hpp>
35
36using namespace Acts::UnitLiterals;
37
38namespace ActsTrk {
39
40
42 ISvcLocator *pSvcLocator)
43 : AthReentrantAlgorithm(name, pSvcLocator) {}
44
46
47// === initialize ==========================================================
48
50 // Athena tools
51 m_logger = makeActsAthenaLogger(this, "Acts GNN Algorithm");
52 ACTS_DEBUG("TrackFindingGNNAlg::initialize() - begin");
54 ATH_CHECK(m_trackContainerKey.initialize());
55 ATH_CHECK(m_ctxProvider.initialize());
59 ATH_CHECK(m_trackContainerKey.initialize());
60 ATH_CHECK(m_chronoSvc.retrieve());
62 ATH_CHECK(m_fitterTool.retrieve());
63 ATH_CHECK(m_gnnPipelineTool.retrieve());
64
70
71 using TSC = Acts::TrackSelector::Config;
72 m_trackSelectorConfig = Acts::TrackSelector::EtaBinnedConfig(0.0);
73
74 auto commonConfig = [&](TSC &config) {
75 config.requireReferenceSurface = true;
76 config.loc1Min = m_offlineZ0Sel.value() ? -200_mm : -150_mm; // z0 min
77 config.loc1Max = m_offlineZ0Sel.value() ? 200_mm : 150_mm; // z0 max
78 };
79
81 .addCuts(2.0,
82 [&](TSC &config) {
83 commonConfig(config);
84 config.maxHoles = m_relaxCentralHoleSel.value() ? 4 : 2;
85 config.minMeasurements = m_relaxMeasurementSel.value() ? 7 : 9;
86 config.ptMin = 900_MeV;
87 config.loc0Max = 2_mm; // d0 max
88 config.loc0Min = -2_mm; // d0 min
89 })
90 .addCuts(2.6,
91 [&](TSC &config) {
92 commonConfig(config);
93 config.maxHoles = m_relaxCentralHoleSel.value() ? 4 : 2;
94 config.minMeasurements = m_relaxMeasurementSel.value() ? 7 : 8;
95 config.ptMin = 400_MeV;
96 config.loc0Max = 2_mm; // d0 max
97 config.loc0Min = -2_mm; // d0 min
98 })
99 .addCuts([&](TSC &config) {
100 commonConfig(config);
101 config.maxHoles = 2;
102 config.minMeasurements = 7;
103 config.ptMin = 400_MeV;
104 config.loc0Max = 10_mm; // d0 max
105 config.loc0Min = -10_mm; // d0 min
106 });
107
108 ACTS_INFO("Track selector config:\n" << m_trackSelectorConfig);
109
110 ACTS_DEBUG("TrackFindingGNNAlg::initialize() - end");
111 return StatusCode::SUCCESS;
112}
113
114// === execute =============================================================
115
116StatusCode TrackFindingGNNAlg::execute(const EventContext &ctx) const {
117 ACTS_DEBUG("TrackFindingGNNAlg::execute() - begin");
118
119 std::optional<Athena::Chrono> timer;
120 timer.emplace("GNN get spacepoint handles", m_chronoSvc.get());
121
122 const Acts::GeometryContext gctx = m_ctxProvider.getGeometryContext(ctx);
123 const Acts::MagneticFieldContext mctx = m_ctxProvider.getMagneticFieldContext(ctx);
124 const Acts::CalibrationContext cctx = m_ctxProvider.getCalibrationContext(ctx);
125
126 auto detElToGeoIdMap = m_trackingGeometrySvc->surfaceIdMap();
127
128 // Collect the spacepoint containers and hand them to the GNN pipeline
129 auto pixelSPHandle = SG::makeHandle(m_xaodPixelSpacePointContainerKey, ctx);
130 ATH_CHECK(pixelSPHandle.isValid());
131 auto stripSPHandle = SG::makeHandle(m_xaodStripSpacePointContainerKey, ctx);
132 ATH_CHECK(stripSPHandle.isValid());
133 auto stripSPOVHandle =
135 ATH_CHECK(stripSPOVHandle.isValid());
136
137 std::vector<const xAOD::SpacePointContainer*> spacePointCollections{
138 pixelSPHandle.cptr(), stripSPHandle.cptr(), stripSPOVHandle.cptr()};
139
140 timer.reset();
141 timer.emplace("GNN seed building", m_chronoSvc.get());
142
143 ActsTrk::SeedContainer gnnSeeds;
144 ATH_CHECK(m_gnnPipelineTool->buildSeed(spacePointCollections, gnnSeeds));
145
146 ACTS_DEBUG("GNN produced " << gnnSeeds.size() << " seed candidates");
147
148 timer.reset();
149 timer.emplace("GNN parameter estimation + fit", m_chronoSvc.get());
150
151 Acts::VectorTrackContainer trackBackend;
152 Acts::VectorMultiTrajectory trackStateBackend;
153 constexpr std::size_t nTracksExpected = 3000;
154 trackBackend.reserve(nTracksExpected);
155 trackStateBackend.reserve(nTracksExpected * 30);
156 detail::RecoTrackContainer tracks(trackBackend, trackStateBackend);
158
159 // v45: Create SeedContainer to hold seeds (Seeds are now proxy objects)
160 ActsTrk::SeedContainer seedContainer;
161 auto R_of = [](const xAOD::SpacePoint* sp) {
162 return Acts::fastHypot(sp->x(), sp->y(), sp->z());
163 };
164
165 // Loop over GNN seeds, to pick SP used to estimate track parameters.
166 auto spacePointSelector = [&](ActsTrk::SpacePointRange cand)
167 -> std::optional<
168 boost::container::small_vector<const xAOD::SpacePoint*, 3>> {
169 // Select at least 3 SPs with deltaR spacing in cylindrical coordinates
170 boost::container::small_vector<const xAOD::SpacePoint*, 3> picked;
171 if (cand.empty()) {
172 return std::nullopt;
173 }
174 const xAOD::SpacePoint* last = cand.front();
175 picked.push_back(last);
176 for (std::size_t i = 1; i < cand.size() && picked.size() < 3; ++i) {
177 const xAOD::SpacePoint* sp = cand[i];
178 if (std::abs(R_of(sp) - R_of(last)) > m_minDeltaR.value()) {
179 picked.push_back(sp);
180 last = sp;
181 }
182 }
183 if (picked.size() < 3)
184 return std::nullopt;
185 return picked;
186 };
187
188 auto retrieveSurface = [&](const ActsTrk::Seed& seed, bool useTopSp) -> const Acts::Surface& {
189 const xAOD::SpacePoint* sp = useTopSp ? seed.sp().front() : seed.sp().back();
190 auto geoId = ActsTrk::getSurfaceGeometryIdOfMeasurement(*detElToGeoIdMap, *sp->measurements().front());
191 const auto* surface = m_trackingGeometrySvc->trackingGeometry()->findSurface(geoId);
192 if (!surface) {
193 throw std::runtime_error("retrieveSurface: no Acts surface for GeometryIdentifier " + std::to_string(geoId.value()));
194 }
195 return *surface;
196 };
197
198 for (const ActsTrk::Seed gnnSeed : gnnSeeds) {
199 ActsTrk::SpacePointRange cand = gnnSeed.sp();
200 auto pickedOpt = spacePointSelector(cand);
201 if (!pickedOpt.has_value()) continue;
202
203 auto picked = *pickedOpt;
204 std::sort(picked.begin(), picked.end(),
205 [&](const xAOD::SpacePoint* a, const xAOD::SpacePoint* b) {
206 return R_of(a) < R_of(b);
207 });
208 constexpr float quality = 0.f; // quality is not computed in the GNN pipeline
209 constexpr float vertexZ = 0.f; // vertexZ is not computed in the GNN pipeline
210 ActsTrk::Seed seed = seedContainer.push_back(
211 ActsTrk::SpacePointRange(picked.data(), picked.size()), quality, vertexZ);
212
213 const auto& [initialParamsOpt, estimationStatus] = m_paramEstimationTool->estimateTrackParameters(
214 seed, /*useTopSp=*/true, gctx, mctx, cctx, retrieveSurface);
215 if (!initialParamsOpt.has_value()) continue;
216
217 boost::container::small_vector<const xAOD::SpacePoint*, 16> sortedSP;
218 sortedSP.reserve(cand.size());
219 for (const xAOD::SpacePoint* sp : cand)
220 sortedSP.push_back(sp);
221 std::sort(sortedSP.begin(), sortedSP.end(),
222 [&](const xAOD::SpacePoint* a, const xAOD::SpacePoint* b) {
223 return R_of(a) < R_of(b);
224 });
225
226 std::vector<const xAOD::UncalibratedMeasurement*> measList;
227 measList.reserve(sortedSP.size() * 2);
228 for (const xAOD::SpacePoint* sp : sortedSP) {
229 for (const xAOD::UncalibratedMeasurement* m : sp->measurements()) {
230 measList.push_back(m);
231 }
232 }
233
234 auto fitted = m_fitterTool->fit(measList, *initialParamsOpt, gctx, mctx, cctx);
235 if (fitted) {
236 for (auto track : *fitted) {
237 auto newTrack = tracks.makeTrack();
238 newTrack.copyFrom(track);
239 }
240 }
241 }
242
243 ACTS_DEBUG("After track fit: " << tracks.size() << " / " << gnnSeeds.size()
244 << " successfull");
245
246 timer.reset();
247 timer.emplace("Track selection & conversion", m_chronoSvc.get());
248
249 Acts::VectorTrackContainer selTrackBackend;
250 selTrackBackend.reserve(trackBackend.size());
251 detail::RecoTrackContainer selectedTracks(selTrackBackend, trackStateBackend);
253
254 Acts::TrackSelector selector(m_trackSelectorConfig);
255 for (auto track : tracks) {
256 if (selector.isValidTrack(track)) {
257 auto newTrack = selectedTracks.makeTrack();
258
259 // v45: copyFrom now copies everything including tip/stem indices
260 newTrack.copyFrom(track);
261 }
262 }
263
264 ACTS_DEBUG("GNN seeds: " << gnnSeeds.size() << ", fitted: " << tracks.size()
265 << ", selected: " << selectedTracks.size());
266
267 // Write tracks to storage again
268 Acts::ConstVectorTrackContainer constTrackBackend(std::move(selTrackBackend));
269 Acts::ConstVectorMultiTrajectory constTrackStateBackend(std::move(trackStateBackend));
270 std::unique_ptr<ActsTrk::TrackContainer> constTracksContainer
271 = std::make_unique<ActsTrk::TrackContainer>(std::move(constTrackBackend), std::move(constTrackStateBackend) );
272
273 ACTS_DEBUG("Storing track collection with key '" << m_trackContainerKey.key() << "'");
275 ATH_CHECK(trackContainerHandle.record(std::move(constTracksContainer)));
276
277 return StatusCode::SUCCESS;
278}
279} // namespace ActsTrk
#define ATH_CHECK
Evaluate an expression and check for errors.
Exception-safe IChronoSvc caller.
static Double_t sp
static Double_t a
Handle class for reading from StoreGate.
Handle class for recording to StoreGate.
std::unique_ptr< const Acts::Logger > makeActsAthenaLogger(IMessageSvc *svc, const std::string &name, int level, std::optional< std::string > parent_name)
Definition Logger.cxx:64
Gaudi::Property< bool > m_relaxCentralHoleSel
std::unique_ptr< const Acts::Logger > m_logger
logging instance
detail::OnTrackCalibrator< MutableTrackStateBackend > m_uncalibMeasCalibrator
Acts::TrackSelector::EtaBinnedConfig m_trackSelectorConfig
ToolHandle< ITrackParamsEstimationTool > m_paramEstimationTool
virtual StatusCode initialize() override
Gaudi::Property< bool > m_relaxMeasurementSel
SG::ReadHandleKey< xAOD::SpacePointContainer > m_xaodStripSpacePointOverlapContainerKey
Gaudi::Property< bool > m_offlineZ0Sel
virtual StatusCode execute(const EventContext &ctx) const override
SG::ReadHandleKey< xAOD::SpacePointContainer > m_xaodPixelSpacePointContainerKey
TrackFindingGNNAlg(const std::string &name, ISvcLocator *pSvcLocator)
ServiceHandle< ActsTrk::ITrackingGeometrySvc > m_trackingGeometrySvc
SG::WriteHandleKey< TrackContainer > m_trackContainerKey
Gaudi::Property< double > m_minDeltaR
ContextUtility m_ctxProvider
Utility to fetch the geometry, magnetic field and calibration context in the event.
ServiceHandle< IChronoStatSvc > m_chronoSvc
SG::ReadHandleKey< xAOD::SpacePointContainer > m_xaodStripSpacePointContainerKey
detail::xAODUncalibMeasSurfAcc m_uncalibMeasSurfAccessor
ToolHandle< ActsTrk::IGnnPipelineTool > m_gnnPipelineTool
ToolHandle< IFitterTool > m_fitterTool
static OnTrackCalibrator NoCalibration(const ActsTrk::ITrackingGeometrySvc *trackGeoSvc)
Constructs a calibrator which copies the local position & covariance of the ITk measurements onto the...
Helper class to access the Acts::surface associated with an Uncalibrated xAOD measurement.
An algorithm that can be simultaneously executed in multiple threads.
StatusCode record(std::unique_ptr< T > data)
Record a const object to the store.
Acts::TrackContainer< Acts::VectorTrackContainer, Acts::VectorMultiTrajectory > RecoTrackContainer
The AlignStoreProviderAlg loads the rigid alignment corrections and pipes them through the readout ge...
Acts::GeometryIdentifier getSurfaceGeometryIdOfMeasurement(const DetectorElementToActsGeometryIdMap &detector_element_to_geoid, const xAOD::UncalibratedMeasurement &measurement)
SG::ReadCondHandle< T > makeHandle(const SG::ReadCondHandleKey< T > &key, const EventContext &ctx=Gaudi::Hive::currentContext())
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
UncalibratedMeasurement_v1 UncalibratedMeasurement
Define the version of the uncalibrated measurement class.
Seed push_back(SpacePointRange spacePoints, float quality, float vertexZ)
std::size_t size() const noexcept
static void addFitterTypeProperty(track_container_t &tracksContainer)
add fitter column to the track container