ATLAS Offline Software
Loading...
Searching...
No Matches
dRMatchingTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3*/
4
5#include "dRMatchingTool.h"
7
8// InDetPhysValMonitoring include(s)
9#include "../src/TrackTruthSelectionTool.h" /* to perform dynamic_cast */
10
11namespace { // Placing utility functions in anonymous namespace.
12// Utility definitions.
13
14// Accessor utility function, for getting the best available value of pT.
15 template<class U>
16 float
17 pt(const U* p) {
18 return p->pt();
19 }
20
21// Accessor utility function, for getting the best available value of phi.
22// Need to explicitly state that 'isAvailable' and 'auxdata' are templated
23// functions.
24 template<class U>
25 float
26 phi(const U* p) {
27 static const SG::ConstAccessor<float> phiAcc("phi");
28 return(phiAcc.isAvailable(*p) ? phiAcc(*p) : p->phi());
29 }
30
31// Accessor utility function, for getting the best available value of eta.
32// Need to explicitly state that 'isAvailable' and 'auxdata' are templated
33// functions.
34 template<class U>
35 float
36 eta(const U* p) {
37 static const SG::ConstAccessor<float> etaAcc("eta");
38 return(etaAcc.isAvailable(*p) ? etaAcc(*p) : p->eta());
39 }
40
41// Function to compute dPhi-separation using best available parameter values.
42 template<class U, class V>
43 float
44 comp_deltaPhi(const U* p1, const V* p2) {
45 // Ensures that $\Delta\phi \in [-pi, pi)$, and takes absolute value.
46 float dphi = phi(p1) - phi(p2);
47
48 while (dphi >= M_PI) {
49 dphi -= 2.*M_PI;
50 }
51 while (dphi < -M_PI) {
52 dphi += 2.*M_PI;
53 }
54 return std::fabs(dphi);
55 }
56
57// Function to compute dEta-separation using best available parameter values.
58 template<class U, class V>
59 float
60 comp_deltaEta(const U* p1, const V* p2) {
61 return eta(p1) - eta(p2);
62 }
63
64// Function to compute dR-separation using best available parameter values.
65 template<class U, class V>
66 float
67 comp_deltaR(const U* p1, const V* p2) {
68 return sqrt(pow(comp_deltaPhi(p1, p2), 2.) + pow(comp_deltaEta(p1, p2), 2.));
69 }
70
71// Function for sorting vector of xAOD particles by increasing pT.
72 template<class U>
73 bool
74 sort_pt(const U* p1, const U* p2) {
75 return pt(p1) < pt(p2);
76 }
77
78// Function for sorting vector of xAOD particles by increasing eta.
79 template<class U>
80 bool
81 sort_eta(const U* p1, const U* p2) {
82 return eta(p1) < eta(p2);
83 }
84
85// Function for sorting vector of xAOD particles by increasing phi.
86 template<class U>
87 bool
88 sort_phi(const U* p1, const U* p2) {
89 return phi(p1) < phi(p2);
90 }
91} // namespace
92
93
94dRMatchingTool::dRMatchingTool(const std::string& name) :
95 asg::AsgTool(name) {
96 declareInterface<IAsgSelectionTool>(this);
97}
98
100
101StatusCode
103 if (asg::AsgTool::initialize().isFailure()) {
104 return StatusCode::FAILURE;
105 }
106
107 ATH_MSG_INFO("Initializing " << name() << "...");
108
109 // Clear cuts container.
110 m_cuts.clear();
111
112 // Define cut names and descriptions.
113 if (m_dRmax > -1) {
114 m_cuts.emplace_back("dRmax", "Cut on maximal dR between track and truth particle.");
115 }
116 if (m_pTResMax > -1) {
117 m_cuts.emplace_back("pTResMax",
118 "Cut on maximal, relativ pT difference between track and truth particle.");
119 }
120
121 // Add cuts to the AcceptOmfp.
122 for (const auto& cut : m_cuts) {
123 if (m_accept.addCut(cut.first, cut.second) < 0) {
124 ATH_MSG_ERROR("Failed to add cut " << cut.first << " because the AcceptInfo object is full.");
125 return StatusCode::FAILURE;
126 }
127 }
128
129 // Initialise counters.
130 m_numPassedCuts.resize(m_accept.getNCuts(), 0);
131
137 if (m_accept.getNCuts() == 0) {
138 m_accept.addCut("nop", "Forcing to have length 1.");
139 }
140
141 return StatusCode::SUCCESS;
142}
143
144const asg::AcceptInfo&
146 return m_accept;
147}
148
151
153 "accept(...) function called without needed Truth- or TrackParticleContainer. Please use one of the dRMatchingTool-specific accept methods.");
154
155 return asg::AcceptData (&m_accept);
156}
157
158template<class T, class U>
159void
161 std::vector< const U* >& vec_pt,
162 std::vector< const U* >& vec_eta,
163 std::vector< const U* >& vec_phi,
164 bool (* selectionTool)(const U*)) const {
165 // Look all particles in container.
166 for (const U* p : *container) {
167 // Ignore particles not passing the selection, if applicable.
168 if (selectionTool and !(*selectionTool)(p)) {
169 continue;
170 }
171
172 // Append passing particles to cached vectors.
173 vec_pt.push_back(p);
174 vec_eta.push_back(p);
175 vec_phi.push_back(p);
176 }
177
178 // Sort vectors.
179 std::sort(vec_pt.begin(), vec_pt.end(), sort_pt <U>);
180 std::sort(vec_eta.begin(), vec_eta.end(), sort_eta<U>);
181 std::sort(vec_phi.begin(), vec_phi.end(), sort_phi<U>);
182}
183
184void
186 CacheEntry* ent,
187 bool (* trackSelectionTool)(const xAOD::TrackParticle*)) const {
188 // Check whether to cache.
189 if (*trackParticles == ent->m_baseTrackContainer) {
190 return;
191 }
192
193 // Clear existing cache.
195
196 // Cache track particles.
198 xAOD::TrackParticle>(trackParticles,
202 trackSelectionTool);
203
204 // Store copy of base track container.
205 ent->m_baseTrackContainer = *trackParticles;
206}
207
208void
210 CacheEntry* ent,
211 bool (* truthSelectionTool)(const xAOD::TruthParticle*)) const {
212 // Check whether to cache.
213 if (*truthParticles == ent->m_baseTruthContainer) {
214 return;
215 }
216
217 // Clear existing cache.
219
220 // Cache truth particles.
222 xAOD::TruthParticle>(truthParticles,
226 truthSelectionTool);
227
228 // Store copy of base truth container.
229 ent->m_baseTruthContainer = *truthParticles;
230}
231
232template<class U, class V>
233bool
235 std::vector< const V* >& vec_pt,
236 std::vector< const V* >& vec_eta,
237 std::vector< const V* >& vec_phi,
238 float& dRmin) const {
239 // (Re-)set variables.
240 dRmin = 9999.;
241
242 // Perform search in cached vectors.
243 auto it_pt_lower = m_pTResMax < 0 ? vec_pt.begin() :
244 std::lower_bound(vec_pt.begin(), vec_pt.end(),
245 pt(p) * (1. - m_pTResMax),
246 [](const V* o, const float& val) -> bool {
247 return pt(o) < val;
248 });
249
250 auto it_pt_upper = m_pTResMax < 0 ? vec_pt.end() :
251 std::upper_bound(vec_pt.begin(), vec_pt.end(),
252 pt(p) * (1. + m_pTResMax),
253 [](const float& val, const V* o) -> bool {
254 return val < pt(o);
255 });
256
257 auto it_eta_lower = m_dRmax < 0 ? vec_eta.begin() :
258 std::lower_bound(vec_eta.begin(), vec_eta.end(),
259 eta(p) - m_dRmax,
260 [](const V* o, const float& val) -> bool {
261 return eta(o) < val;
262 });
263
264 auto it_eta_upper = m_dRmax < 0 ? vec_eta.end() :
265 std::upper_bound(vec_eta.begin(), vec_eta.end(),
266 eta(p) + m_dRmax,
267 [](const float& val, const V* o) -> bool {
268 return val < eta(o);
269 });
270
271 // Dealing with cyclic nature of phi: Determining whether phi range wraps
272 // around +-pi.
273 bool wrapLow = phi(p) - m_dRmax < -M_PI;
274 bool wrapHigh = phi(p) + m_dRmax > M_PI;
275 bool wrap = wrapLow or wrapHigh;
276
277 auto it_phi_lower = m_dRmax < 0 ? vec_phi.begin() :
278 std::lower_bound(vec_phi.begin(), vec_phi.end(),
279 phi(p) - m_dRmax + (wrapLow ? 2.*M_PI : 0),
280 [](const V* o, const float& val) -> bool {
281 return phi(o) < val;
282 });
283
284 auto it_phi_upper = m_dRmax < 0 ? vec_phi.end() :
285 std::upper_bound(vec_phi.begin(), vec_phi.end(),
286 phi(p) + m_dRmax + (wrapHigh ? -2.*M_PI : 0),
287 [](const float& val, const V* o) -> bool {
288 return val < phi(o);
289 });
290
291 // Break early if no truth particles passed selection.
292 if (m_pTResMax > 0 and it_pt_upper < it_pt_lower) {
293 return false;
294 } else if (m_dRmax > 0 and it_eta_upper < it_eta_lower) {
295 return false;
296 } else if (m_dRmax > 0 and((!wrap and it_phi_upper < it_phi_lower)or
297 (wrap and it_phi_upper > it_phi_lower))) {
298 return false;
299 }
300
301 // Initialise base set.
302 std::vector< const V* > set(vec_pt);
303
304 // -- Sort, pointer-based; necessary for set_intersection.
305 std::sort(set.begin(), set.end());
306
307 // Compute subset of selected truth particles.
308 std::vector< const V* > subset_pt(it_pt_lower, it_pt_upper);
309 std::vector< const V* > subset_eta(it_eta_lower, it_eta_upper);
310 std::vector< const V* > subset_phi;
311 if (!wrap) {
312 subset_phi = std::vector< const V* >(it_phi_lower, it_phi_upper);
313 } else {
314 subset_phi = std::vector< const V* >(vec_phi.begin(), it_phi_upper);
315 subset_phi.insert(subset_phi.end(), it_phi_lower, vec_phi.end());
316 }
317
318 // Add subsets according to specified cut values.
319 std::vector< std::vector< const V* > > subsets;
320 if (m_pTResMax > 0) {
321 subsets.push_back(subset_pt);
322 }
323 if (m_dRmax > 0) {
324 subsets.push_back(subset_eta);
325 subsets.push_back(subset_phi);
326 }
327
328 // Compute successive intersections between base set and subset.
329 for (std::vector< const V* > subset : subsets) {
330 // -- Sort, pointer-based; necessary for set::set_intersection.
331 std::sort(subset.begin(), subset.end());
332
333 // -- Set intersection.
334 std::vector< const V* > intersection;
335 std::set_intersection(set.begin(), set.end(),
336 subset.begin(), subset.end(),
337 std::back_inserter(intersection));
338
339 // -- Break early if intersection is empty.
340 if (intersection.size() == 0) {
341 return false;
342 }
343
345 }
346
347 // If only pT-matching, we're done.
348 if (m_dRmax < 0) {
349 return set.size() > 0;
350 }
351
352 // Otherwise, compute dR for all remaining particles.
353 bool passes = false;
354 for (const V* other : set) {
355 float dR = comp_deltaR(p, other);
356 dRmin = (dR < dRmin ? dR : dRmin);
357 passes |= dRmin < m_dRmax;
358 }
359
360 return passes;
361}
362
365 const xAOD::TruthParticleContainer* truthParticles,
366 bool (* truthSelectionTool)(const xAOD::TruthParticle*)) const {
367 asg::AcceptData acceptData (&m_accept);
368
369 std::lock_guard<std::mutex> lock{m_mutex}; // To guard m_numPassedCuts and m_cache
370 const EventContext& ctx{Gaudi::Hive::currentContext()};
371 CacheEntry* ent{m_cache.get(ctx)};
372 ent->check(ctx.evt());
373
374 // Determine whether to cache current truth particle container
375 checkCacheTruthParticles(truthParticles, ent, truthSelectionTool);
376
377 bool passes = sortedMatch<xAOD::TrackParticle,
378 xAOD::TruthParticle>(track,
382 ent->m_dRmin);
383
384 // Set cut values.
385 if (m_dRmax > -1) {
386 acceptData.setCutResult("dRmax", passes);
387 }
388 if (m_pTResMax > -1) {
389 acceptData.setCutResult("pTResMax", passes);
390 }
391
392 // Book keep cuts
393 for (const auto& cut : m_cuts) {
394 unsigned int pos = acceptData.getCutPosition(cut.first);
395 if (acceptData.getCutResult(pos)) {
396 m_numPassedCuts[pos]++;
397 }
398 }
399
401 if (acceptData) {
402 m_numPassed++;
403 }
404
405 return acceptData;
406}
407
410 const xAOD::TrackParticleContainer* trackParticles,
411 bool (* trackSelectionTool)(const xAOD::TrackParticle*)) const {
412 asg::AcceptData acceptData (&m_accept);
413
414 std::lock_guard<std::mutex> lock{m_mutex}; // To guard m_numPassedCuts and m_cache
415 const EventContext& ctx{Gaudi::Hive::currentContext()};
416 CacheEntry* ent{m_cache.get(ctx)};
417 ent->check(ctx.evt());
418
419 // Determine whether to cache current track particle container
420 checkCacheTrackParticles(trackParticles, ent, trackSelectionTool);
421
422 bool passes = sortedMatch<xAOD::TruthParticle,
423 xAOD::TrackParticle>(truth,
427 ent->m_dRmin);
428
429 // Set cut values.
430 if (m_dRmax > -1) {
431 acceptData.setCutResult("dRmax", passes);
432 }
433 if (m_pTResMax > -1) {
434 acceptData.setCutResult("pTResMax", passes);
435 }
436
437 // Book keep cuts
438 for (const auto& cut : m_cuts) {
439 unsigned int pos = acceptData.getCutPosition(cut.first);
440 if (acceptData.getCutResult(pos)) {
441 m_numPassedCuts[pos]++;
442 }
443 }
444
446 if (acceptData) {
447 m_numPassed++;
448 }
449
450 return acceptData;
451}
452
455 const xAOD::TruthParticleContainer* truthParticles,
456 bool (* truthSelectionTool)(const xAOD::TruthParticle*)) const {
457 asg::AcceptData acceptData (&m_accept);
458
459 std::lock_guard<std::mutex> lock{m_mutex}; // To guard m_numPassedCuts and m_cache
460 const EventContext& ctx{Gaudi::Hive::currentContext()};
461 CacheEntry* ent{m_cache.get(ctx)};
462 ent->check(ctx.evt());
463
464 ent->m_dRmin = 9999.;
465
466 // Define variables.
467 const unsigned int Ncuts(m_cuts.size());
468 bool passes(false), passesThis(false);
469
470 // Loop all truth particles.
471 for (const xAOD::TruthParticle* truth : *truthParticles) {
472 // Ignore all truth particles failing the selection.
473 if (truthSelectionTool and !(*truthSelectionTool)(truth)) {
474 continue;
475 }
476
477 // Compute cut variable values.
478 float dR = comp_deltaR(p, truth);
479 float pTRes = std::fabs(pt(truth) / pt(p) - 1.);
480
481 // Initialise cut monitoring objects.
482 std::vector<bool> vecPassesThis(Ncuts, false);
483
484 // Check whether each individual cut passed.
485 unsigned int icut = 0;
486 if (m_dRmax > -1) {
487 vecPassesThis[icut++] = dR < m_dRmax;
488 }
489 if (m_pTResMax > -1) {
490 vecPassesThis[icut++] = pTRes < m_pTResMax;
491 }
492
493 // Check whether all cuts passed.
494 passesThis = std::all_of(vecPassesThis.begin(),
495 vecPassesThis.end(),
496 [](const bool& v) {
497 return v;
498 });
499 passes |= passesThis;
500
501 // If the current truth particle was matched, check minimal dR.
502 if (passesThis) {
503 ent->m_dRmin = (dR < ent->m_dRmin ? dR : ent->m_dRmin);
504 }
505 }
506
507 // Set cut values.
508 if (m_dRmax > -1) {
509 acceptData.setCutResult("dRmax", passes);
510 }
511 if (m_pTResMax > -1) {
512 acceptData.setCutResult("pTResMax", passes);
513 }
514
515 // Book keep cuts
516 for (const auto& cut : m_cuts) {
517 unsigned int pos = acceptData.getCutPosition(cut.first);
518 if (acceptData.getCutResult(pos)) {
519 m_numPassedCuts[pos]++;
520 }
521 }
522
524 if (acceptData) {
525 m_numPassed++;
526 }
527
528 return acceptData;
529}
530
533 const xAOD::TrackParticleContainer* trackParticles,
534 bool (* trackSelectionTool)(const xAOD::TrackParticle*)) const {
535 // Reset the results.
536 asg::AcceptData acceptData (&m_accept);
537
538 std::lock_guard<std::mutex> lock{m_mutex}; // To guard m_numPassedCuts and m_cache
539 const EventContext& ctx{Gaudi::Hive::currentContext()};
540 CacheEntry* ent{m_cache.get(ctx)};
541 ent->check(ctx.evt());
542
543 ent->m_dRmin = 9999.;
544
545 // Define variables.
546 const unsigned int Ncuts(m_cuts.size());
547 bool passes(false), passesThis(false);
548
549 // Loop all track particles.
550 for (const xAOD::TrackParticle* track : *trackParticles) {
551 // Ignore all tracks failing the selection.
552 if (trackSelectionTool and !(*trackSelectionTool)(track)) {
553 continue;
554 }
555
556 // Compute cut variable values.
557 float dR = comp_deltaR(p, track);
558 float pTRes = std::fabs(pt(track) / pt(p) - 1.);
559
560 // Initialise cut monitoring objects.
561 std::vector<bool> vecPassesThis(Ncuts, false);
562
563 // Check whether each individual cut passed.
564 unsigned int icut = 0;
565 if (m_dRmax > -1) {
566 vecPassesThis[icut++] = dR < m_dRmax;
567 }
568 if (m_pTResMax > -1) {
569 vecPassesThis[icut++] = pTRes < m_pTResMax;
570 }
571
572 // Check whether all cuts passed.
573 passesThis = std::all_of(vecPassesThis.begin(),
574 vecPassesThis.end(),
575 [](const bool& v) {
576 return v;
577 });
578 passes |= passesThis;
579
580 // If the current track particle was matched, check minimal dR.
581 if (passesThis) {
582 ent->m_dRmin = (dR < ent->m_dRmin ? dR : ent->m_dRmin);
583 }
584 }
585
586 // Set cut values.
587 if (m_dRmax > -1) {
588 acceptData.setCutResult("dRmax", passes);
589 }
590 if (m_pTResMax > -1) {
591 acceptData.setCutResult("pTResMax", passes);
592 }
593
594 // Book keep cuts
595 for (const auto& cut : m_cuts) {
596 unsigned int pos = acceptData.getCutPosition(cut.first);
597 if (acceptData.getCutResult(pos)) {
598 m_numPassedCuts[pos]++;
599 }
600 }
601
603 if (acceptData) {
604 m_numPassed++;
605 }
606
607 return acceptData;
608}
609
610StatusCode
612 ATH_MSG_INFO("Finalizing " << name() << "...");
613
614 if (m_numProcessed == 0) {
615 ATH_MSG_INFO("No tracks processed in selection tool.");
616 return StatusCode::SUCCESS;
617 }
618 ATH_MSG_INFO(m_numPassed << " / " << m_numProcessed << " = "
619 << m_numPassed * 100. / m_numProcessed
620 << "% passed all cuts.");
621 for (const auto& cut : m_cuts) {
622 ULong64_t numPassed = m_numPassedCuts.at(m_accept.getCutPosition(cut.first));
623 ATH_MSG_INFO(numPassed << " = " << numPassed * 100. / m_numProcessed
624 << "% passed " << cut.first << " cut.");
625 }
626
627 return StatusCode::SUCCESS;
628}
629
630float
632 std::lock_guard<std::mutex> lock{m_mutex}; // To guard m_cache
633 const EventContext& ctx{Gaudi::Hive::currentContext()};
634 CacheEntry* ent{m_cache.get(ctx)};
635 ent->check(ctx.evt());
636
637 return ent->m_dRmin;
638}
#define M_PI
Scalar eta() const
pseudorapidity method
Scalar phi() const
phi method
#define ATH_MSG_ERROR(x)
#define ATH_MSG_INFO(x)
Helper class to provide constant type-safe access to aux data.
const size_t Ncuts
constexpr int pow(int base, int exp) noexcept
Helper class to provide constant type-safe access to aux data.
void setCutResult(const std::string &cutName, bool cutResult)
Set the result of a cut, based on the cut name (safer)
Definition AcceptData.h:134
unsigned int getCutPosition(const std::string &cutName) const
Get the bit position of a cut.
Definition AcceptData.h:71
bool getCutResult(const std::string &cutName) const
Get the result of a cut, based on the cut name (safer)
Definition AcceptData.h:98
AsgTool(const std::string &name)
Constructor specifying the tool instance's name.
Definition AsgTool.cxx:58
virtual StatusCode initialize()
Dummy implementation of the initialisation function.
Definition AsgTool.h:133
dRMatchingTool(const std::string &name)
Constructor(s).
virtual StatusCode finalize() override
FloatProperty m_dRmax
Cut vales.
std::atomic< ULong64_t > m_numProcessed
virtual const asg::AcceptInfo & getAcceptInfo() const override
Declare the interface ID for this pure-virtual interface class to the Athena framework.
void checkCacheTruthParticles(const xAOD::TruthParticleContainer *truthParticles, CacheEntry *ent, bool(*truthSelectionTool)(const xAOD::TruthParticle *)=nullptr) const
virtual asg::AcceptData accept(const xAOD::IParticle *p) const override
The main accept method: the actual cuts are applied here.
std::atomic< ULong64_t > m_numPassed
void clearTrackParticles(CacheEntry *ent) const
bool sortedMatch(const U *p, std::vector< const V * > &vec_pt, std::vector< const V * > &vec_eta, std::vector< const V * > &vec_phi, float &dRmin) const
std::vector< std::pair< std::string, std::string > > m_cuts
virtual StatusCode initialize() override
SelectionTool method(s).
std::mutex m_mutex
virtual asg::AcceptData acceptLegacy(const xAOD::TrackParticle *p, const xAOD::TruthParticleContainer *truthParticles, bool(*truthSelectionTool)(const xAOD::TruthParticle *)=nullptr) const
dR-matching specific method(s).
float dRmin() const
void checkCacheTrackParticles(const xAOD::TrackParticleContainer *trackParticles, CacheEntry *ent, bool(*trackSelectionTool)(const xAOD::TrackParticle *)=nullptr) const
Internal method(s).
virtual ~dRMatchingTool()
Destructor.
void clearTruthParticles(CacheEntry *ent) const
asg::AcceptInfo m_accept
Data member(s).
FloatProperty m_pTResMax
void sortVectors(const T *container, std::vector< const U * > &vec_pt, std::vector< const U * > &vec_eta, std::vector< const U * > &vec_phi, bool(*selectionTool)(const U *)) const
STL class.
Class providing the definition of the 4-vector interface.
std::vector< std::string > intersection(std::vector< std::string > &v1, std::vector< std::string > &v2)
Tool to perform dR-based matching of tracks and truth particles.
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
TrackParticle_v1 TrackParticle
Reference the current persistent version:
TruthParticle_v1 TruthParticle
Typedef to implementation.
TrackParticleContainer_v1 TrackParticleContainer
Definition of the current "TrackParticle container version".
TruthParticleContainer_v1 TruthParticleContainer
Declare the latest version of the truth particle container.
std::vector< const xAOD::TrackParticle * > m_trackParticlesSortedPt
std::vector< const xAOD::TrackParticle * > m_trackParticlesSortedEta
xAOD::TruthParticleContainer m_baseTruthContainer
std::vector< const xAOD::TruthParticle * > m_truthParticlesSortedEta
void check(EventContext::ContextEvt_t evt)
std::vector< const xAOD::TrackParticle * > m_trackParticlesSortedPhi
std::vector< const xAOD::TruthParticle * > m_truthParticlesSortedPt
std::vector< const xAOD::TruthParticle * > m_truthParticlesSortedPhi
xAOD::TrackParticleContainer m_baseTrackContainer