ATLAS Offline Software
Loading...
Searching...
No Matches
GbtsSeedingTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
5#if defined(FLATTEN) && defined(__GNUC__)
6// Avoid warning in dbg build
7#pragma GCC optimize "-fno-var-tracking-assignments"
8#endif
9
10#include "src/GbtsSeedingTool.h"
11
13
14#include <algorithm>
15#include <fstream>
16#include <memory>
17#include <unordered_map>
18#include <utility>
19
20namespace ActsTrk {
21
23 const std::string& name,
24 const IInterface* parent)
25 : base_class(type, name, parent)
26 {}
27
29 ATH_CHECK(m_layerTool.retrieve());
30 ATH_MSG_DEBUG("Initializing " << name() << "...");
31
32 // Make the logger And Propagate to ACTS routines
33 m_logger = makeActsAthenaLogger(this, "Acts");
34
35 // etaMin,etaMax,zMin,zMax
36 m_internalRoi.emplace(-4.5, 4.5, m_minZ0.value(), m_maxZ0.value());
37
40
41 // The layer tool builds the GBTS layers, in dense layer index order, and
42 // knows which layer each module hash belongs to and what it is made of.
43 const std::vector<Acts::Experimental::GbtsLayerDescription>& layers =
44 m_layerTool->layerDescriptions();
45
46 m_pixelHashToLayer = &m_layerTool->pixelLayers();
47 m_stripHashToLayer = &m_layerTool->stripLayers();
48
50 ATH_MSG_ERROR("Neither pixel nor strip layers are enabled, there is "
51 "nothing to seed on.");
52 return StatusCode::FAILURE;
53 }
54
55 std::vector<Acts::Experimental::GbtsLayerConnection> connections;
56 float etaBinWidth = 0.0f;
57 ATH_CHECK(m_layerTool->readConnections(layers, connections, etaBinWidth, m_connectorInputFile.value(), m_usePixelLayers, m_useStripLayers));
58
59 // option that allows for adding custom eta binning (default is at 0.2)
60 if (m_etaBinWidthOverride.value() != 0.0f) {
61 etaBinWidth = m_etaBinWidthOverride.value();
62 }
63
64 // the cluster width cuts are the only user of the tau lookup table
65 if (m_finderCfg.useClusterWidthCuts) {
67 }
68
69 // create geoemtry object that holds allowed pairing of allowed eta regions in each layer
70 // holds all geometry information (m_layergeomtry and connection table)
71 auto gbtsGeo = std::make_shared<Acts::Experimental::GbtsGeometry>(
72 layers, connections, etaBinWidth, Acts::Experimental::GbtsZ0Range{}, logger());
73
74 m_finder = Acts::Experimental::GraphBasedTrackSeeder(
75 Acts::Experimental::GraphBasedTrackSeeder::DerivedConfig(m_finderCfg),
76 gbtsGeo, logger().cloneWithSuffix("gbtsFinder"));
77
78 m_graphBuilder.emplace(m_graphCfg, gbtsGeo,
79 logger().cloneWithSuffix("gbtsGraphBuilder"));
80
81 m_filter = Acts::Experimental::GbtsTrackingFilter(m_filterCfg, gbtsGeo);
82
83 return StatusCode::SUCCESS;
84 }
85
88 const EventContext& ctx,
89 const std::vector<const xAOD::SpacePointContainer*>& spacePointCollections,
90 const Eigen::Vector3f& beamSpotPos, float bFieldInZ,
91 ActsTrk::SeedContainer& seedContainer) const
92 {
93 // to avoid compile issues with unused veriables
94 (void) ctx;
95
96 const Acts::Experimental::GraphBasedTrackSeeder::Options options{
97 .bFieldInZ = bFieldInZ};
98
99
100 std::vector<const xAOD::SpacePoint*> tmpSpacePoints;
101
102 // add spacepoint pointers to singel container, this makes indexing them easier
103 for (const xAOD::SpacePointContainer* spacePoints : spacePointCollections) {
104 for (const xAOD::SpacePoint* sp : *spacePoints) {
105 tmpSpacePoints.emplace_back(sp);
106 }
107 }
108
109
110 // create the node storage and fill it from the xAOD space points
111 Acts::Experimental::GbtsNodeStorage nodeStorage = m_finder->makeNodeStorage();
112
113 // node positions are relative to the beam spot in x and y if the correction is on
114 const float offsetX = m_beamSpotCorrection ? beamSpotPos[0] : 0.0f;
115 const float offsetY = m_beamSpotCorrection ? beamSpotPos[1] : 0.0f;
116
117 std::size_t nPixelNodes = 0;
118 std::size_t nStripNodes = 0;
119
120 // space points GBTS has no layer for, counted rather than reported per
121 // space point: the loop runs over the whole event
122 std::size_t nUnmappedHashes = 0;
123 std::size_t nUngroupedModules = 0;
124
125 // add spacepoints to node storage
126 for(std::size_t idx = 0; idx < tmpSpacePoints.size(); ++idx){
127 // obtain module hash for spacepoint
128 const xAOD::SpacePoint* sp = tmpSpacePoints[idx];
129 const std::vector<xAOD::DetectorIDHashType>& elementlist = sp->elementIdList();
130
131 // a strip space point is made of one cluster on each side of a stereo pair
132 const bool isPixel(elementlist.size() == 1);
133
134 if (isPixel ? !m_usePixelLayers : !m_useStripLayers) {
135 continue;
136 }
137
138 const std::vector<short>& hashToLayer =
140 const auto hash = static_cast<std::size_t>(elementlist[0]);
141 if (hash >= hashToLayer.size()) [[unlikely]] {
142 ++nUnmappedHashes;
143 continue;
144 }
145
146 const short layer = hashToLayer[hash];
147 if (layer == IGbtsLayerTool::kNoLayer) {
148 // a wafer GBTS does not group into any of its layers
149 ++nUngroupedModules;
150 continue;
151 }
152
153 float clusterWidth = 0.0f;
154 float localPositionY = 0.0f;
155 if (m_finderCfg.useClusterWidthCuts && isPixel) {
156 assert(dynamic_cast<const xAOD::PixelCluster*>(sp->measurements().front())!=nullptr);
157 const xAOD::PixelCluster* pCL = static_cast<const xAOD::PixelCluster*>(sp->measurements().front());
158 clusterWidth = pCL->widthInEta();
159 localPositionY = pCL->localPosition<2>().y();
160 }
161
162 // the stereo pair of a strip space point, for the strip calibration in GBTS
163 Acts::OuterStripSpacePointCalibrationDetails stripDetails{};
164 const Acts::OuterStripSpacePointCalibrationDetails* strip = nullptr;
165 if (!isPixel) {
166 // topStripCenter is global, the node frame shifts only x and y
167 Eigen::Map<Eigen::Vector3f>(stripDetails.outerCenter.data()) =
168 sp->topStripCenter() - Eigen::Vector3f(offsetX, offsetY, 0.0f);
169 Eigen::Map<Eigen::Vector3f>(stripDetails.innerToOuterSeparation.data()) =
170 sp->stripCenterDistance();
171 Eigen::Map<Eigen::Vector3f>(stripDetails.outerHalfVector.data()) =
172 sp->topHalfStripLength() * sp->topStripDirection();
173 Eigen::Map<Eigen::Vector3f>(stripDetails.innerHalfVector.data()) =
174 sp->bottomHalfStripLength() * sp->bottomStripDirection();
175 strip = &stripDetails;
176 }
177
178 const float x = static_cast<float>(sp->x()) - offsetX;
179 const float y = static_cast<float>(sp->y()) - offsetY;
180 const std::optional<std::uint32_t> bin = nodeStorage.insert(
181 static_cast<Acts::SpacePointIndex>(idx), x, y,
182 static_cast<float>(sp->z()), std::hypot(x, y), std::atan2(y, x),
183 static_cast<Acts::Experimental::GbtsLayerIndex>(layer), clusterWidth,
184 localPositionY, strip);
185
186 if (bin.has_value()) {
187 ++(isPixel ? nPixelNodes : nStripNodes);
188 }
189 }
190
191 ATH_MSG_DEBUG("Inserted " << nPixelNodes << " pixel and " << nStripNodes
192 << " strip nodes; the graph "
193 << (nodeStorage.hasStrips() ? "carries" : "does not carry")
194 << " stereo pairs");
195
196 if (nUnmappedHashes != 0) [[unlikely]] {
197 ATH_MSG_WARNING(nUnmappedHashes << " space points sit on a wafer hash "
198 "outside the GBTS layer map and were dropped");
199 }
200 if (nUngroupedModules != 0) {
201 ATH_MSG_DEBUG(nUngroupedModules << " space points sit on a wafer GBTS "
202 "does not group into a layer");
203 }
204
205 // order the nodes and build the derived per-node data
206 nodeStorage.finalize();
207
208 ATH_MSG_VERBOSE("Spacepoints successfully added to node storage");
209
210 Acts::SeedContainer seeds;
211 m_finder->createSeeds(nodeStorage, m_internalRoi.value(), *m_graphBuilder,
212 *m_filter, options, seeds);
213
214 // add seeds to the output container
215 seedContainer.reserve(seedContainer.size() + seeds.size(), 7.0f);
216 for (auto seed : seeds) {
217 seedContainer.push_back(
218 seed.asConst(),
219 [&](const Acts::SpacePointIndex spIndex) {
220 return tmpSpacePoints[spIndex];
221 });
222 }
223
224 ATH_MSG_VERBOSE("Number of seeds created is " << seedContainer.size());
225 return StatusCode::SUCCESS;
226 }
227
229 Acts::Experimental::GbtsTauLookupTable& tauLookupTable) const
230 {
231 std::ifstream lutStream(m_lutFile.value());
232 if (!lutStream.is_open()) {
233 ATH_MSG_ERROR("Cannot open the GBTS tau lookup table " << m_lutFile.value());
234 return StatusCode::FAILURE;
235 }
236
237 tauLookupTable.clear();
238
239 // the width is dropped: a row is located by index, one row per
240 // tauLutBinWidth of cluster width, never searched
241 float clusterWidth = 0.0f;
242 Acts::Experimental::GbtsTauBounds bounds;
243 while (lutStream >> clusterWidth >> bounds.minTau >> bounds.maxTau >>
244 bounds.minTauNearEdge >> bounds.maxTauNearEdge) {
245 tauLookupTable.push_back(bounds);
246 }
247
248 if (!lutStream.eof()) {
249 // ended on a parse error, not on a clean end of file
250 ATH_MSG_ERROR("Malformed GBTS tau lookup table " << m_lutFile.value());
251 return StatusCode::FAILURE;
252 }
253 if (tauLookupTable.empty()) {
254 ATH_MSG_ERROR("The GBTS tau lookup table " << m_lutFile.value() << " is empty");
255 return StatusCode::FAILURE;
256 }
257
258 ATH_MSG_DEBUG("Read " << tauLookupTable.size() << " rows of the GBTS tau lookup table "
259 << m_lutFile.value());
260
261 return StatusCode::SUCCESS;
262 }
263
265 m_finderCfg.useClusterWidthCuts = m_useML;
266 m_graphCfg.matchBeforeCreate = m_matchBeforeCreate;
267 m_graphCfg.minPt = m_minPt;
268 m_finderCfg.nMaxPhiSlice = m_nMaxPhiSlice;
269 m_graphCfg.useEtaBinning = m_useEtaBinning;
270 m_graphCfg.doubletFilterRZ = m_doubletFilterRZ;
271 m_graphCfg.minDeltaRadius = m_minDeltaRadius;
272 m_graphCfg.maxEdgesPerSP = m_maxEdgesPerSP;
273 m_graphCfg.tauRatioCut = m_tauRatioCut;
274 m_graphCfg.tauRatioPrecut = m_tauRatioPrecut;
275 m_finderCfg.edgeMaskMinEta = m_edgeMaskMinEta;
276 m_finderCfg.hitShareThreshold = m_hitShareThreshold;
277 m_finderCfg.maxEndcapClusterWidth = m_maxEndcapClusterwidth;
278 m_graphCfg.d0Max = m_d0Max;
279
280 //use roi for pixel and given value for strip
281 m_graphCfg.maxZ0 = m_maxZ0.value();
282 m_graphCfg.minZ0 = m_minZ0.value();
283
284 m_graphCfg.validateTriplets = m_validateTriplets;
285 m_graphCfg.useAdaptiveCuts = m_useAdaptiveCuts;
286 m_graphCfg.tauRatioCorr = m_tauRatioCorr;
287 m_finderCfg.addTriplets = m_addTriplets;
288 m_finderCfg.maxAbsEtaAddTriplets = m_maxEtaAddTriplets;
289 m_graphCfg.cutDPhiMax = m_cutDPhiMax;
290 m_graphCfg.cutDCurvMax = m_cutDCurvMax;
291 m_graphCfg.maxOuterRadius = m_maxOuterRadius;
292
293 // The seeder no longer recognises an LRT mode, so spell out what it used
294 // to imply: a triplet with no confirmation.
295 if (m_LRTmode) {
296 m_finderCfg.minSeedLevel = 2;
297 }
298
299 m_filterCfg.sigmaMS = m_sigmaMS;
300 m_filterCfg.radLen = m_radLen;
301 m_filterCfg.sigmaX = m_sigmaX;
302 m_filterCfg.sigmaY = m_sigmaY;
303 m_filterCfg.weightX = m_weightX;
304 m_filterCfg.weightY = m_weightY;
305 m_filterCfg.maxDChi2X = m_maxDChi2X;
306 m_filterCfg.maxDChi2Y = m_maxDChi2Y;
307 m_filterCfg.addHit = m_addHit;
308 m_filterCfg.maxCurvature = m_maxCurvature;
310
311 return StatusCode::SUCCESS;
312 }
313
314 // called in initialise, used to make sure all config settings look sensible
316 ATH_MSG_DEBUG("===== GBTS finder config =====");
317 ATH_MSG_DEBUG( "beamSpotCorrection: " << m_beamSpotCorrection.value());
318 ATH_MSG_DEBUG( "connectorInputFile: " << m_connectorInputFile.value());
319 ATH_MSG_DEBUG( "lutInputFile: " << m_lutFile.value());
320 ATH_MSG_DEBUG( "LRTmode: " << m_LRTmode.value());
321 ATH_MSG_DEBUG( "useStripConnections: " << m_stripConnections.value());
322 ATH_MSG_DEBUG( "useClusterWidthCuts: " << m_finderCfg.useClusterWidthCuts);
323 ATH_MSG_DEBUG( "matchBeforeCreate: " << m_graphCfg.matchBeforeCreate);
324 ATH_MSG_DEBUG( "minSeedLevel: " << static_cast<unsigned>(m_finderCfg.minSeedLevel));
325 ATH_MSG_DEBUG( "tauRatioPrecut: " << m_graphCfg.tauRatioPrecut);
326 ATH_MSG_DEBUG( "tauRatioCut: " << m_graphCfg.tauRatioCut);
327 ATH_MSG_DEBUG( "tauRatioCorr: " << m_graphCfg.tauRatioCorr);
328 ATH_MSG_DEBUG( "etaBinWidthOverride: " << m_etaBinWidthOverride.value());
329 ATH_MSG_DEBUG( "nMaxPhiSlice: " << m_finderCfg.nMaxPhiSlice);
330 ATH_MSG_DEBUG( "minPt: " << m_graphCfg.minPt);
331 ATH_MSG_DEBUG( "useEtaBinning: " << m_graphCfg.useEtaBinning);
332 ATH_MSG_DEBUG( "doubletFilterRZ: " << m_graphCfg.doubletFilterRZ);
333 ATH_MSG_DEBUG( "maxEdgesPerSP: " << m_graphCfg.maxEdgesPerSP);
334 ATH_MSG_DEBUG( "minDeltaRadius: " << m_graphCfg.minDeltaRadius);
335 ATH_MSG_DEBUG( "edgeMaskMinEta: " << m_finderCfg.edgeMaskMinEta);
336 ATH_MSG_DEBUG( "hitShareThreshold: " << m_finderCfg.hitShareThreshold);
337 ATH_MSG_DEBUG( "maxEndcapClusterWidth: " << m_finderCfg.maxEndcapClusterWidth);
338 ATH_MSG_DEBUG( "d0Max: " << m_graphCfg.d0Max);
339 ATH_MSG_DEBUG("maxZ0: " << m_graphCfg.maxZ0);
340 ATH_MSG_DEBUG("minZ0: " << m_graphCfg.minZ0);
341 ATH_MSG_DEBUG( "validateTriplets: " << m_graphCfg.validateTriplets);
342 ATH_MSG_DEBUG( "useAdaptiveCuts: " << m_graphCfg.useAdaptiveCuts);
343 ATH_MSG_DEBUG( "addTriplets: " << m_finderCfg.addTriplets);
344 ATH_MSG_DEBUG( "maxEtaAddTriplets: " << m_finderCfg.maxAbsEtaAddTriplets);
345 ATH_MSG_DEBUG("cutDphiMax: " << m_graphCfg.cutDPhiMax);
346 ATH_MSG_DEBUG("cutDCurvMax: " << m_graphCfg.cutDCurvMax);
347 ATH_MSG_DEBUG("maxOuterRadius: " << m_graphCfg.maxOuterRadius);
348
349 ATH_MSG_DEBUG("===== GBTS filter config =====");
350 ATH_MSG_DEBUG( "sigmaMS: " << m_filterCfg.sigmaMS);
351 ATH_MSG_DEBUG( "radLen: " << m_filterCfg.radLen);
352 ATH_MSG_DEBUG( "sigmaX: " << m_filterCfg.sigmaX);
353 ATH_MSG_DEBUG( "sigmaY: " << m_filterCfg.sigmaY);
354 ATH_MSG_DEBUG( "weightX: " << m_filterCfg.weightX);
355 ATH_MSG_DEBUG( "weightY: " << m_filterCfg.weightY);
356 ATH_MSG_DEBUG( "maxDChi2X: " << m_filterCfg.maxDChi2X);
357 ATH_MSG_DEBUG( "maxDChi2Y: " << m_filterCfg.maxDChi2Y);
358 ATH_MSG_DEBUG( "addHit: " << m_filterCfg.addHit);
359 ATH_MSG_DEBUG( "maxCurvature: " << m_filterCfg.maxCurvature);
360 ATH_MSG_DEBUG( "filterMaxZ0: " << m_filterCfg.maxZ0);
361}
362
363} // namespace ActsTrk
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_DEBUG(x,...)
#define ATH_MSG_ERROR(x,...)
#define ATH_MSG_WARNING(x,...)
#define ATH_MSG_VERBOSE(x,...)
static Double_t sp
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
#define y
#define x
Gaudi::Property< bool > m_doubletFilterRZ
Gaudi::Property< float > m_maxZ0
Gaudi::Property< float > m_maxEtaAddTriplets
Gaudi::Property< float > m_filterMaxZ0
Gaudi::Property< float > m_minPt
Gaudi::Property< bool > m_useAdaptiveCuts
Gaudi::Property< bool > m_usePixelLayers
Which technologies this instance seeds on.
Gaudi::Property< float > m_maxDChi2X
Acts::Experimental::GbtsGraphBuilder::Config m_graphCfg
steering for doublet graph building
Gaudi::Property< float > m_weightX
std::optional< Acts::Experimental::GbtsGraphBuilder > m_graphBuilder
the doublet graph builder
Gaudi::Property< float > m_sigmaMS
virtual StatusCode initialize() override
Gaudi::Property< float > m_cutDPhiMax
Gaudi::Property< bool > m_validateTriplets
Gaudi::Property< float > m_sigmaY
Gaudi::Property< float > m_maxEdgesPerSP
Gaudi::Property< bool > m_LRTmode
StatusCode readTauLookupTable(Acts::Experimental::GbtsTauLookupTable &tauLookupTable) const
Reads the tau lookup table the cluster width cuts need: per line a cluster width, the bulk tau bounds...
std::optional< Acts::Experimental::GbtsRoiDescriptor > m_internalRoi
region of interest for pixel seeding
Gaudi::Property< float > m_edgeMaskMinEta
Gaudi::Property< float > m_addHit
std::unique_ptr< const Acts::Logger > m_logger
logging instance
Gaudi::Property< bool > m_stripConnections
StatusCode createSeeds(const EventContext &ctx, const std::vector< const xAOD::SpacePointContainer * > &spacePointCollections, const Eigen::Vector3f &beamSpotPos, float bFieldInZ, ActsTrk::SeedContainer &seedContainer) const override
Gaudi::Property< float > m_nMaxPhiSlice
Gaudi::Property< float > m_maxCurvature
Gaudi::Property< bool > m_useStripLayers
Gaudi::Property< float > m_maxOuterRadius
Gaudi::Property< float > m_etaBinWidthOverride
Gaudi::Property< float > m_minZ0
const Acts::Logger & logger() const
Private access to the logger.
Acts::Experimental::GbtsTrackingFilter::Config m_filterCfg
steering for track filter
void printGbtsConfig() const
prints all current config settings used either with default settings or properties changed by the gau...
Gaudi::Property< float > m_maxDChi2Y
Gaudi::Property< std::string > m_connectorInputFile
Acts::Experimental::GraphBasedTrackSeeder::Config m_finderCfg
steering for seeding algorithm
Gaudi::Property< float > m_cutDCurvMax
Gaudi::Property< bool > m_useML
Gaudi::Property< float > m_minDeltaRadius
std::optional< Acts::Experimental::GbtsTrackingFilter > m_filter
the seed filter
Gaudi::Property< float > m_tauRatioPrecut
Gaudi::Property< bool > m_useEtaBinning
Gaudi::Property< bool > m_matchBeforeCreate
std::optional< Acts::Experimental::GraphBasedTrackSeeder > m_finder
the actual seed fining algorithm
StatusCode prepareConfiguration()
sets configs based on gaudi properties defined below
ToolHandle< IGbtsLayerTool > m_layerTool
Builds the GBTS layers out of the ITk readout geometry.
Gaudi::Property< float > m_maxEndcapClusterwidth
Gaudi::Property< float > m_tauRatioCorr
Gaudi::Property< float > m_hitShareThreshold
Gaudi::Property< float > m_sigmaX
Gaudi::Property< bool > m_beamSpotCorrection
const std::vector< short > * m_stripHashToLayer
Wafer hash to dense GBTS layer index, one map per technology.
Gaudi::Property< float > m_weightY
Gaudi::Property< float > m_tauRatioCut
Gaudi::Property< float > m_d0Max
Gaudi::Property< bool > m_addTriplets
Gaudi::Property< std::string > m_lutFile
const std::vector< short > * m_pixelHashToLayer
GbtsSeedingTool(const std::string &type, const std::string &name, const IInterface *parent)
Gaudi::Property< float > m_radLen
static constexpr short kNoLayer
Value stored in the hash maps for a module GBTS does not use.
float widthInEta() const
Returns the width of the cluster in phi (x) and eta (y) directions, respectively.
ConstVectorMap< N > localPosition() const
Returns the local position of the measurement.
#define ATH_FLATTEN
The AlignStoreProviderAlg loads the rigid alignment corrections and pipes them through the readout ge...
SpacePointContainer_v1 SpacePointContainer
Define the version of the space point container.
PixelCluster_v1 PixelCluster
Define the version of the pixel cluster class.
#define unlikely(x)
Seed push_back(SpacePointRange spacePoints, float quality, float vertexZ)
void reserve(std::size_t size, float averageSpacePoints=3) noexcept
std::size_t size() const noexcept