ATLAS Offline Software
Loading...
Searching...
No Matches
SeedAnalysisAlg.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#include "SeedAnalysisAlg.h"
6
9
12
13#include "Acts/Definitions/Units.hpp"
14#include "Acts/MagneticField/MagneticFieldContext.hpp"
17
18namespace ActsTrk {
19
20 SeedAnalysisAlg::SeedAnalysisAlg(const std::string& name, ISvcLocator* pSvcLocator)
21 : AthMonitorAlgorithm(name, pSvcLocator)
22 {}
23
25 ATH_MSG_INFO("Initializing " << name() << " ...");
26
27 ATH_CHECK( m_beamSpotKey.initialize() );
28 ATH_CHECK( m_fieldCondObjInputKey.initialize() );
29
30 ATH_CHECK( m_inputSeedColletionKey.initialize() );
31
32 ATH_CHECK( m_prdTruth.initialize(not m_prdTruth.empty()));
33 ATH_CHECK( m_detEleCollKey.initialize(not m_detEleCollKey.empty()) );
34
35 ATH_CHECK( m_EventInfoKey.initialize() );
36
37 ATH_CHECK( m_paramEstimationTool.retrieve(EnableTool{!m_prdTruth.empty()}) );
38 ATH_CHECK( m_trackingGeometrySvc.retrieve() );
39 ATH_CHECK( m_geometryConvTool.retrieve(EnableTool{!m_prdTruth.empty()}) );
40 ATH_CHECK( m_ctxProvider.initialize() );
41
42 ATH_MSG_DEBUG("Monitoring settings ...");
44
46 }
47
48 StatusCode SeedAnalysisAlg::fillHistograms(const EventContext& ctx) const {
49 ATH_MSG_DEBUG( "Filling Histograms for " << name() << " ... " );
50
51 // CONDS
52 // Read the Beam Spot information
54 ATH_CHECK( beamSpotHandle.isValid() );
55 auto beamSpotData = beamSpotHandle.cptr();
56
57 // Read the b-field information
59 ATH_CHECK( readHandle.isValid() );
60 const AtlasFieldCacheCondObj* fieldCondObj{ *readHandle };
61
62 // Get the magnetic field
63 // Using ACTS classes in order to be sure we are consistent
64 Acts::MagneticFieldContext magFieldContext(fieldCondObj);
65 // Beam Spot Position
66 Acts::Vector2 beamPos( beamSpotData->beamPos()[ Amg::x ] * Acts::UnitConstants::mm,
67 beamSpotData->beamPos()[ Amg::y ] * Acts::UnitConstants::mm );
68
69 // Magnetic Field
70 ATLASMagneticFieldWrapper magneticField;
71 Acts::MagneticFieldProvider::Cache magFieldCache = magneticField.makeCache( magFieldContext );
72 Acts::Vector3 bField = *magneticField.getField( Acts::Vector3(beamPos.x(), beamPos.y(), 0),
73 magFieldCache );
74
75
76 // SEEDS
77 ATH_MSG_DEBUG( "Reading input collection with key " << m_inputSeedColletionKey.key() );
79 ATH_CHECK( handle.isValid() );
80 const ActsTrk::SeedContainer* seed_collection = handle.get();
81 ATH_MSG_DEBUG( "Retrieved " << seed_collection->size() << " input elements from key " << m_inputSeedColletionKey.key() );
82
83 auto monitor_nseed = Monitored::Scalar<int>("Nseed", seed_collection->size());
84 fill(m_monGroupName.value(), monitor_nseed);
85
86 // bottom
87 auto monitor_x1 =
88 Monitored::Collection("x1", *seed_collection,
89 [] (const auto& seed) -> double
90 { return seed.sp()[0]->x(); });
91 auto monitor_y1 =
92 Monitored::Collection("y1", *seed_collection,
93 [] (const auto& seed) -> double
94 { return seed.sp()[0]->y(); });
95 auto monitor_z1 =
96 Monitored::Collection("z1", *seed_collection,
97 [] (const auto& seed) -> double
98 { return seed.sp()[0]->z(); });
99 auto monitor_r1 =
100 Monitored::Collection("r1", *seed_collection,
101 [] (const auto& seed) -> double
102 {
103 const auto* sp = seed.sp()[0];
104 return std::sqrt(sp->x()*sp->x() + sp->y()*sp->y());
105 });
106
107 // middle
108 auto monitor_x2 =
109 Monitored::Collection("x2", *seed_collection,
110 [] (const auto& seed) -> double
111 { return seed.sp()[1]->x(); });
112 auto monitor_y2 =
113 Monitored::Collection("y2", *seed_collection,
114 [] (const auto& seed) -> double
115 { return seed.sp()[1]->y(); });
116 auto monitor_z2 =
117 Monitored::Collection("z2", *seed_collection,
118 [] (const auto& seed) -> double
119 { return seed.sp()[1]->z(); });
120 auto monitor_r2 =
121 Monitored::Collection("r2", *seed_collection,
122 [] (const auto& seed) -> double
123 {
124 const auto* sp = seed.sp()[1];
125 return std::sqrt(sp->x()*sp->x() + sp->y()*sp->y());
126 });
127
128 // top
129 auto monitor_x3 =
130 Monitored::Collection("x3", *seed_collection,
131 [] (const auto& seed) -> double
132 { return seed.sp()[2]->x(); });
133 auto monitor_y3 =
134 Monitored::Collection("y3", *seed_collection,
135 [] (const auto& seed) -> double
136 { return seed.sp()[2]->y(); });
137 auto monitor_z3 =
138 Monitored::Collection("z3", *seed_collection,
139 [] (const auto& seed) -> double
140 { return seed.sp()[2]->z(); });
141 auto monitor_r3 =
142 Monitored::Collection("r3", *seed_collection,
143 [] (const auto& seed) -> double
144 {
145 const auto* sp = seed.sp()[2];
146 return std::sqrt(sp->x()*sp->x() + sp->y()*sp->y());
147 });
148
149 std::vector< std::array<float, 7> > parametersCollection;
150 parametersCollection.reserve(seed_collection->size());
151
152 for (auto seed : *seed_collection) {
153 parametersCollection.push_back( estimateParameters(seed, 300. * bField[2] / 1000.) );
154 }
155
156 auto monitor_param_pt = Monitored::Collection("pt", parametersCollection,
157 [] (const auto& params) -> float
158 { return params[0]; });
159 auto monitor_param_theta = Monitored::Collection("theta", parametersCollection,
160 [] (const auto& params) -> float
161 { return params[1]; });
162 auto monitor_param_eta = Monitored::Collection("eta", parametersCollection,
163 [] (const auto& params) -> float
164 { return params[2]; });
165 auto monitor_param_d0 = Monitored::Collection("d0", parametersCollection,
166 [] (const auto& params) -> float
167 { return params[3]; });
168
169 auto monitor_param_dzdr_b = Monitored::Collection("dzdr_b", parametersCollection,
170 [] (const auto& params) -> float
171 { return params[4]; });
172 auto monitor_param_dzdr_t = Monitored::Collection("dzdr_t", parametersCollection,
173 [] (const auto& params) -> float
174 { return params[5]; });
175
176
177 auto monitor_param_penalty = Monitored::Collection("penalty", parametersCollection,
178 [] (const auto& params) -> float
179 { return params[6]; });
180
181
183 ATH_CHECK(eventInfo.isValid());
184
185 auto monitor_event_number = Monitored::Scalar<long>("event_number", static_cast<long>(eventInfo->eventNumber()));
186 auto monitor_actual_mu = Monitored::Scalar<float>("actual_mu", eventInfo->actualInteractionsPerCrossing());
187
188 std::vector<int> vec_truthBarcode;
189 std::vector<double> vec_truthProb;
190 if (not m_prdTruth.empty())
191 ATH_CHECK( fillTruthHistograms(ctx, *seed_collection, vec_truthBarcode, vec_truthProb) );
192 auto monitor_truth_barcode = Monitored::Collection("truth_barcode", vec_truthBarcode);
193 auto monitor_truth_prob = Monitored::Collection("truth_prob", vec_truthProb);
194
195 fill(m_monGroupName.value(),
196 monitor_x1, monitor_y1, monitor_z1, monitor_r1,
197 monitor_x2, monitor_y2, monitor_z2, monitor_r2,
198 monitor_x3, monitor_y3, monitor_z3, monitor_r3,
199 monitor_param_pt, monitor_param_theta, monitor_param_eta, monitor_param_d0,
200 monitor_param_dzdr_b, monitor_param_dzdr_t,
201 monitor_param_penalty,
202 monitor_event_number, monitor_actual_mu,
203 monitor_truth_barcode, monitor_truth_prob);
204
205 return StatusCode::SUCCESS;
206 }
207
208 StatusCode SeedAnalysisAlg::fillTruthHistograms(const EventContext& ctx,
209 const ActsTrk::SeedContainer& seed_container,
210 std::vector<int>& truthBarCodeVec,
211 std::vector<double>& truthProbVec) const
212 {
213 ATH_MSG_DEBUG( "Filling Truth Histograms for " << name() << " ... " );
214
216 ATH_CHECK(prdTruthHandle.isValid());
217 const PRD_MultiTruthCollection* prdTruth = prdTruthHandle.get();
218
220 ATH_CHECK( detEleHandle.isValid() );
221 const InDetDD::SiDetectorElementCollection& detElements = *detEleHandle.retrieve();
222
223 // Read the b-field information
225 ATH_CHECK( readHandle.isValid() );
226
227 const AtlasFieldCacheCondObj* fieldCondObj{ *readHandle };
228 ATH_CHECK( fieldCondObj != nullptr );
229
230 Acts::MagneticFieldContext magFieldContext(fieldCondObj);
231 const auto & geo_context = m_trackingGeometrySvc->getNominalContext();
232 const Acts::CalibrationContext calContext = m_ctxProvider.getCalibrationContext(ctx);
233
234 // utilities
235 // Used for param estimation
236 auto retrieveSurfaceFunction =
237 [this, &detElements] (const ActsTrk::Seed& seed) -> const Acts::Surface&
238 {
239 const xAOD::SpacePoint* sp = seed.sp().front();
240 const InDetDD::SiDetectorElement* element = detElements.getDetectorElement(
241 sp->elementIdList().front());
242 const Trk::Surface& atlas_surface = element->surface();
243 return *m_geometryConvTool->convertSurfaceToActs(atlas_surface);
244 };
245
246
247 // computation
248 std::vector<bool> vec_pass;
249 vec_pass.reserve(seed_container.size());
250
251 std::vector<double> estimated_pt;
252 std::vector<double> estimated_eta;
253 estimated_pt.reserve(seed_container.size());
254 estimated_eta.reserve(seed_container.size());
255
256 for (auto seed : seed_container) {
257 const auto& [optTrackParams, estimationStatus] =
258 m_paramEstimationTool->estimateTrackParameters(
259 seed,
260 geo_context.context(),
261 magFieldContext,
262 calContext,
263 retrieveSurfaceFunction);
264
265 if ( not optTrackParams.has_value() ) continue;
266
267 const auto & param = optTrackParams.value();
268 estimated_pt.push_back( param.transverseMomentum() );
269 estimated_eta.push_back( -std::log( std::tan(0.5 * param.parameters()[Acts::eBoundTheta]) ) );
270
271 std::map<int, int> truthHits;
272
273 const auto& sps = seed.sp();
274 for (const auto* sp : sps) {
275 int number_of_clusters = m_usePixel ? 1 : 2;
276 for (int cluster_number(0); cluster_number < number_of_clusters; cluster_number++) {
277 const auto& els = sp->measurements();
278 const auto* cluster = els[cluster_number];
279 const xAOD::UncalibMeasType cluster_type = cluster->type();
280 const Identifier id = cluster_type == xAOD::UncalibMeasType::PixelClusterType
281 ? identify(*reinterpret_cast<const xAOD::PixelCluster*>(cluster))
282 : identify(*reinterpret_cast<const xAOD::StripCluster*>(cluster));
283 matchParticleToSeedClusters(prdTruth, id, truthHits);
284 }
285 }
286
287 auto [barcode, prob] = findSeedMajorityTruthParticle(truthHits);
288 truthBarCodeVec.push_back(barcode);
289 truthProbVec.push_back(prob);
290 vec_pass.push_back( barcode != 0 and prob > 0.5 );
291 }
292
293 auto monitor_estimated_pt = Monitored::Collection("estimated_pt", estimated_pt);
294 auto monitor_estimated_eta = Monitored::Collection("estimated_eta", estimated_eta);
295 auto monitor_pass = Monitored::Collection("passed", vec_pass);
296
297 fill(m_monGroupName.value(),
298 monitor_pass,
299 monitor_estimated_pt, monitor_estimated_eta);
300
301 return StatusCode::SUCCESS;
302 }
303
305 {
306 static const SG::ConstAccessor< ElementLink< InDet::PixelClusterCollection > > pixelLinkAcc("pixelClusterLink");
307
308 // TO-DO -- AODs will not have this decoration, we'll need to provide a function for recomputing
309 // the identifier from local position
310 if (not pixelLinkAcc.isAvailable (cluster))
311 return Identifier();
312
313 ElementLink<InDet::PixelClusterCollection> pixelLink = pixelLinkAcc(cluster);
314 return (*pixelLink)->identify();
315 }
316
318 {
319 static const SG::ConstAccessor< ElementLink< InDet::SCT_ClusterCollection > > stripLinkAcc("sctClusterLink");
320
321 // TO-DO -- AODs will not have this decoration, we'll need to provide a function for recomputing
322 // the identifier from local position
323 if (not stripLinkAcc.isAvailable (cluster))
324 return Identifier();
325
326 ElementLink<InDet::SCT_ClusterCollection> stripLink = stripLinkAcc(cluster);
327 return (*stripLink)->identify();
328 }
329
330
332 const Identifier& id,
333 std::map<int, int>& countMap) const {
334 auto n1 = prdTruth->count(id);
335 if (n1 == 0) {
336 int bc = 0;
337 auto nBC = countMap.count(bc);
338 if (nBC == 0) {
339 countMap[bc] = 1;
340 } else {
341 countMap[bc] += 1;
342 }
343 } else {
344 using iprdt = PRD_MultiTruthCollection::const_iterator;
345 std::pair<iprdt, iprdt> range = prdTruth->equal_range(id);
346 for (iprdt itr = range.first; itr != range.second; ++itr) {
347 auto bc = itr->second.barcode();
348 auto nBC = countMap.count(bc);
349 if (nBC == 0) {
350 countMap[bc] = 1;
351 } else {
352 countMap[bc] += 1;
353 }
354 }
355 }
356 }
357
358
359
360 std::pair<int, double> SeedAnalysisAlg::findSeedMajorityTruthParticle(const std::map<int, int>& countMap) const {
361 int bestCount = 0;
362 int bestBarcode = std::numeric_limits<int>::min();
363
364 for (auto const& [barcode, count] : countMap) {
365 if (count > bestCount) {
366 bestCount = count;
367 bestBarcode = barcode;
368 }
369 }
370
371 // 3 spacepoints per seed, 1 (2) clusters per spacepoint for pixel (strip)
372 double nTotal = m_usePixel ? 3. : 6.;
373 double prob = bestCount / nTotal;
374
375 return std::make_pair(bestBarcode, prob);
376 }
377
378 std::array<float, 7> SeedAnalysisAlg::estimateParameters(const ActsTrk::Seed& seed,
379 float pTPerHelixRadius) const
380 {
381 auto extractCoordinates =
382 [] (const xAOD::SpacePoint* sp) -> std::array<float,4>
383 {
384 std::array<float, 4> coordinates {static_cast<float>(sp->x()),
385 static_cast<float>(sp->y()),
386 static_cast<float>(sp->z()),
387 static_cast<float>(std::sqrt(sp->x()*sp->x() + sp->y()*sp->y()))};
388 return coordinates;
389 };
390
391 auto extractQuantities =
392 [] (const std::array<float, 4>& sp,
393 const std::array<float, 4>& spM,
394 bool isBottom) -> std::array<float, 5>
395 {
396 auto& [xM, yM, zM, rM] = spM;
397 auto& [xO, yO, zO, rO] = sp;
398
399 float cosPhiM = xM / rM;
400 float sinPhiM = yM / rM;
401 float deltaX = xO - xM;
402 float deltaY = yO - yM;
403 float deltaZ = zO - zM;
404 float x = deltaX * cosPhiM + deltaY * sinPhiM;
405 float y = deltaY * cosPhiM - deltaX * sinPhiM;
406 float iDeltaR2 = 1.f / (deltaX * deltaX + deltaY * deltaY);
407 float iDeltaR = std::sqrt(iDeltaR2);
408 int bottomFactor = int(not isBottom) - int(isBottom);
409 float cot_theta = deltaZ * iDeltaR * bottomFactor;
410
411 // cotTheta, Zo, iDeltaR, U, V
412 std::array<float, 5> params =
413 {
414 cot_theta,
415 zM - rM * cot_theta,
416 iDeltaR,
417 x * iDeltaR2,
418 y * iDeltaR2
419 };
420
421 return params;
422 };
423
424 const auto& sps = seed.sp();
425 const auto* bottom = sps[0];
426 const auto* medium = sps[1];
427 const auto* top = sps[2];
428
429 auto coo_b = extractCoordinates(bottom);
430 auto coo_m = extractCoordinates(medium);
431 auto coo_t = extractCoordinates(top);
432
433 // Compute the variables we need
434 auto [cotThetaB, Zob, iDeltaRB, Ub, Vb] = extractQuantities(coo_b, coo_m, true);
435 auto [cotThetaT, Zot, iDeltaRT, Ut, Vt] = extractQuantities(coo_t, coo_m, false);
436
437 float squarediDeltaR2B = iDeltaRB*iDeltaRB;
438 float squarediDeltaR2T = iDeltaRB*iDeltaRT;
439 float squarediDeltaR = std::min(squarediDeltaR2B, squarediDeltaR2T);
440
441 auto& [xB, yB, zB, rB] = coo_b;
442 auto& [xM, yM, zM, rM] = coo_m;
443 auto& [xT, yT, zT, rT] = coo_t;
444
445 float ax = xM / rM;
446 float ay = yM/ rM;
447
448 float dxb = xM - xB;
449 float dyb = yM - yB;
450 float dzb = zM - zB;
451 float xb = dxb * ax + dyb *ay;
452 float yb = dyb * ax - dxb * ay;
453 float dxyb = xb * xb + yb * yb;
454 float dxt = xT - xM;
455 float dyt = yT - yM;
456 float dzt = zT - zM;
457 float xt = dxt * ax + dyt *ay;
458 float yt = dyt * ax - dxt * ay;
459 float dxyt = xt * xt + yt * yt;
460
461 float tzb = dzb * std::sqrt( 1.f/dxyb );
462 float tzt = dzt * std::sqrt( 1.f/dxyt );
463
464 float sTzb2 = std::sqrt(1.f + tzb*tzb);
465
466 float dU = Ut - Ub;
467 if (dU == 0.) {
468 return {-1, -1, -1, -1, -1, -1, -1};
469 }
470
471 float A = (Vt - Vb) / dU;
472 float S2 = 1.f + A * A;
473 float B = Vb - A * Ub;
474 float B2 = B * B;
475 if (B2 == 0) B2 = 1e-8;
476
477 // dzdr
478 float dzdr_b = (zM - zB) / (rM - rB);
479 float dzdr_t = (zT - zM) / (rT - rM);
480
481 // eta
482 float cotThetaAvg2 = cotThetaB * cotThetaT;
483 if (cotThetaAvg2 <= 0) {
484 return {-1, -1, -1, -1, -1, -1, -1};
485 }
486 float theta = std::atan(1.f / std::sqrt(cotThetaAvg2));
487 float eta = -std::log(std::tan(0.5f * theta));
488
489 // pt
490 float pt = pTPerHelixRadius * std::sqrt(S2 / B2) / 2.f;
491
492 // d0
493 float d0 = std::abs((A - B * rM) * rM);
494
495 // curvature
496 // not used in current version of the code. We may want to use it later
497 // float curvature = B / std::sqrt(S2);
498 float penalty = std::abs((tzb - tzt) / (squarediDeltaR * sTzb2));
499
500 return {pt, theta, eta, d0, dzdr_b, dzdr_t, penalty};
501 }
502
503}
Scalar eta() const
pseudorapidity method
Scalar theta() const
theta method
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_DEBUG(x,...)
#define ATH_MSG_INFO(x,...)
bool isBottom(const T &p)
Definition AtlasPID.h:188
Helper class to provide constant type-safe access to aux data.
static Double_t sp
This is an Identifier helper class for the Pixel subdetector.
struct TBPatternUnitContext S2
#define y
#define xt
#define yt
#define x
Acts::Result< Acts::Vector3 > getField(const Acts::Vector3 &position, Acts::MagneticFieldProvider::Cache &gcache) const override
MagneticFieldProvider::Cache makeCache(const Acts::MagneticFieldContext &mctx) const override
virtual StatusCode fillHistograms(const EventContext &ctx) const override
adds event to the monitoring histograms
std::pair< int, double > findSeedMajorityTruthParticle(const std::map< int, int > &countMap) const
SeedAnalysisAlg(const std::string &name, ISvcLocator *pSvcLocator)
Gaudi::Property< bool > m_usePixel
StatusCode fillTruthHistograms(const EventContext &ctx, const ActsTrk::SeedContainer &seed_container, std::vector< int > &, std::vector< double > &) const
ToolHandle< ActsTrk::ITrackParamsEstimationTool > m_paramEstimationTool
const Identifier identify(const xAOD::PixelCluster &) const
void matchParticleToSeedClusters(const PRD_MultiTruthCollection *prdTruth, const Identifier &id, std::map< int, int > &countMap) const
std::array< float, 7 > estimateParameters(const ActsTrk::Seed &seed, float pTPerHelixRadius) const
SG::ReadHandleKey< PRD_MultiTruthCollection > m_prdTruth
virtual StatusCode initialize() override
initialize
ServiceHandle< ActsTrk::ITrackingGeometrySvc > m_trackingGeometrySvc
Gaudi::Property< std::string > m_monGroupName
PublicToolHandle< IGeometryRealmConvTool > m_geometryConvTool
SG::ReadCondHandleKey< AtlasFieldCacheCondObj > m_fieldCondObjInputKey
SG::ReadHandleKey< ActsTrk::SeedContainer > m_inputSeedColletionKey
ContextUtility m_ctxProvider
Auxiliary class to access the calibration context.
SG::ReadCondHandleKey< InDet::BeamSpotData > m_beamSpotKey
SG::ReadCondHandleKey< InDetDD::SiDetectorElementCollection > m_detEleCollKey
virtual StatusCode initialize() override
initialize
AthMonitorAlgorithm(const std::string &name, ISvcLocator *pSvcLocator)
Constructor.
SG::ReadHandleKey< xAOD::EventInfo > m_EventInfoKey
Key for retrieving EventInfo from StoreGate.
Class to hold the SiDetectorElement objects to be put in the detector store.
const SiDetectorElement * getDetectorElement(const IdentifierHash &hash) const
Class to hold geometrical description of a silicon detector element.
Trk::Surface & surface()
Element Surface.
Declare a monitored scalar variable.
A PRD is mapped onto all contributing particles.
Helper class to provide constant type-safe access to aux data.
bool isAvailable(const ELT &e) const
Test to see if this variable exists in the store.
const_pointer_type retrieve()
const_pointer_type cptr()
virtual bool isValid() override final
Can the handle be successfully dereferenced?
const_pointer_type get() const
Dereference the pointer, but don't cache anything.
Abstract Base Class for tracking surfaces.
Definition Surface.h:79
void fill(const ToolHandle< GenericMonitoringTool > &groupHandle, std::vector< std::reference_wrapper< Monitored::IMonitoredVariable > > &&variables) const
Fills a vector of variables to a group by reference.
int count(std::string s, const std::string &regx)
count how many occurances of a regx are in a string
Definition hcg.cxx:148
The AlignStoreProviderAlg loads the rigid alignment corrections and pipes them through the readout ge...
ValuesCollection< T > Collection(std::string name, const T &collection)
Declare a monitored (double-convertible) collection.
SG::ReadCondHandle< T > makeHandle(const SG::ReadCondHandleKey< T > &key, const EventContext &ctx=Gaudi::Hive::currentContext())
StripCluster_v1 StripCluster
Define the version of the strip cluster class.
PixelCluster_v1 PixelCluster
Define the version of the pixel cluster class.
UncalibMeasType
Define the type of the uncalibrated measurement.
hold the test vectors and ease the comparison
std::size_t size() const noexcept