ATLAS Offline Software
Loading...
Searching...
No Matches
InDetSecVtxTruthMatchTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3*/
6
11
12using namespace InDetSecVtxTruthMatchUtils;
13
15
17 ATH_MSG_INFO("Initializing InDetSecVtxTruthMatchTool");
18
19 // Retrieve the TrackTruthOriginTool
21
22 return StatusCode::SUCCESS;
23}
24
25namespace {
26//Helper methods for this file only
27
28//In the vector of match info, find the element corresponding to link and return its index; create a new one if necessary
29size_t indexOfMatchInfo( std::vector<VertexTruthMatchInfo> & matches, const ElementLink<xAOD::TruthVertexContainer> & link ) {
30 for ( size_t i = 0; i < matches.size(); ++i ) {
31 if ( link.key() == std::get<0>(matches[i]).key() && link.index() == std::get<0>(matches[i]).index() )
32 return i;
33 }
34 // This is the first time we've seen this truth vertex, so make a new entry
35 matches.emplace_back( link, 0., 0. );
36 return matches.size() - 1;
37}
38
39}
40
41StatusCode InDetSecVtxTruthMatchTool::matchVertices( std::vector<const xAOD::Vertex*> recoVerticesToMatch,
42 std::vector<const xAOD::TruthVertex*> truthVerticesToMatch,
43 const xAOD::TrackParticleContainer* trackParticles) {
44
45 ATH_MSG_DEBUG("Start vertex matching");
46
47 //setup decorators for truth matching info
48 static const xAOD::Vertex::Decorator<std::vector<VertexTruthMatchInfo> > matchInfoDecor("truthVertexMatchingInfos");
49 static const xAOD::Vertex::Decorator<int> recoMatchTypeDecor("vertexMatchType");
50 static const xAOD::Vertex::Decorator<std::vector<ElementLink<xAOD::VertexContainer> > > splitPartnerDecor("splitPartners");
51 //optional for SM origin matching
52 static const xAOD::Vertex::Decorator<int> smOriginDecor("vertexMatchOriginType");
53
54 const xAOD::Vertex::Decorator<float> fakeScoreDecor("fakeScore");
55 const xAOD::Vertex::Decorator<float> otherScoreDecor("otherScore");
56
57 //setup accessors
58 // can switch to built in method in xAOD::Vertex once don't have to deal with changing names anymore
60 xAOD::Vertex::ConstAccessor<std::vector<float> > weightAcc("trackWeights");
62 xAOD::TrackParticle::ConstAccessor<float> trk_truthProbAcc("truthMatchProbability");
63
64 ATH_MSG_DEBUG("Starting Loop on Vertices");
65
66 //=============================================================================
67 //First loop over vertices: get tracks, then TruthParticles, and store relative
68 //weights from each TruthVertex
69 //=============================================================================
70 for ( const xAOD::Vertex* vtx : recoVerticesToMatch ) {
71
72 //create the vector we will add as matching info decoration later
73 std::vector<VertexTruthMatchInfo> matchinfo;
74
75 const xAOD::Vertex::TrackParticleLinks_t& trackParticles = trkAcc( *vtx );
76 size_t ntracks = trackParticles.size();
77 const std::vector<float> & trkWeights = weightAcc( *vtx );
78
79 xAOD::Vertex::TrackParticleLinks_t trkMuSATrkParts; // For MuSA mode, we will populate this with MuSA track particles
80
81 // Create a local variable for track particles to use in the rest of the function
82 const xAOD::Vertex::TrackParticleLinks_t& trkParts = m_doMuSA ? trkMuSATrkParts : trackParticles;
83
84 if ( m_doMuSA ) {
85 // MuSA also creates new "MuSA Track" collection which does not have truth particle links
86 // instead, we need to get the associated MS TrackParticle from the "MuSATrk_MSTPLink" decorations on the MuSA Track
87 // and then get the truth particle link from there
88 const SG::AuxElement::Accessor<ElementLink<xAOD::TrackParticleContainer>> acc_MSTPLink("MuSATrk_MSTPLink");
89 // populate the MuSA track particle vector
90 trkMuSATrkParts.reserve(ntracks);
91 for (const auto& trkLink : trackParticles) {
92 if (!trkLink.isValid()) continue;
93 const xAOD::TrackParticle& trackParticle = **trkLink;
94 if (acc_MSTPLink.isAvailable(trackParticle)) {
95 const ElementLink<xAOD::TrackParticleContainer>& trkMuSATrkLink = acc_MSTPLink(trackParticle);
96 if (trkMuSATrkLink.isValid()) {
97 trkMuSATrkParts.push_back(trkMuSATrkLink);
98 } else {
99 ATH_MSG_WARNING("MS track particle link is not valid");
100 }
101 } else {
102 ATH_MSG_WARNING("MuSATrk_MSTPLink decoration is not available on track particle");
103 }
104 }
105 }
106
107 //if don't have track particles
108 if ((!trkAcc.isAvailable(*vtx) || !weightAcc.isAvailable(*vtx)) && !m_doMuSA) {
109 ATH_MSG_WARNING("trackParticles or trackWeights not available, vertex is missing info");
110 continue;
111 }
112 if ( trkWeights.size() != ntracks ) {
113 ATH_MSG_WARNING("Vertex without same number of tracks and trackWeights, vertex is missing info");
114 continue;
115 }
116
117 ATH_MSG_DEBUG("Matching new vertex at (" << vtx->x() << ", " << vtx->y() << ", " << vtx->z() << ")" << " with " << ntracks << " tracks, at index: " << vtx->index());
118
119 float totalWeight = 0.;
120 float totalPt = 0;
121 float otherPt = 0;
122 float fakePt = 0;
123
124 // Add for SM origin tracking
125 int combinedSMOrigin = 0;
126
127 //loop over the tracks in the vertex
128 for ( size_t t = 0; t < ntracks; ++t ) {
129
130 ATH_MSG_DEBUG("Checking track number " << t);
131
132 // First check if the original track particle link is valid
133 if (!trackParticles[t].isValid()) {
134 ATH_MSG_DEBUG("Original track " << t << " is bad!");
135 continue;
136 }
137
138 // Then check if we have a valid track after potential MuSA processing
139 if (t >= trkParts.size() || !trkParts[t].isValid()) {
140 ATH_MSG_DEBUG("Track " << t << " is invalid or out of bounds in trkParts!");
141 continue;
142 }
143 const xAOD::TrackParticle trk = **trkParts[t];
144
145 // Add to total weight
146 if (m_doMuSA) {
147 totalWeight += 1.0; // Add dummy weight of 1 for each track with MuSA
148 } else {
149 totalWeight += trkWeights[t];
150 }
151
152 // Safely get the track pt
153 float trkPt = 0;
154 try {
155 trkPt = trk.pt();
156 totalPt += trkPt;
157 } catch (const std::exception& e) {
158 ATH_MSG_WARNING("Exception when accessing track pt: " << e.what());
159 continue;
160 }
161
162 // get the linked truth particle
163 if (!trk_truthPartAcc.isAvailable(trk)) {
164 ATH_MSG_DEBUG("The truth particle link decoration isn't available.");
165 continue;
166 }
167 const ElementLink<xAOD::TruthParticleContainer> & truthPartLink = trk_truthPartAcc(trk);
168 float prob = 0.0;
169 if (m_doMuSA) {
170 // For MuSA mode, assign a dummy probability of 1.0
171 prob = 1.0;
172 ATH_MSG_DEBUG("MuSA mode: using dummy truth prob of 1.0");
173 } else {
174 // For regular mode, use the decoration
175 prob = trk_truthProbAcc(trk);
176 ATH_MSG_DEBUG("Truth prob: " << prob);
177 }
178
179 // check the truth particle origin
180 if (truthPartLink.isValid() && prob > m_trkMatchProb) {
181 const xAOD::TruthParticle & truthPart = **truthPartLink;
182
183 const int ancestorVertexUniqueID = checkProduction(truthPart, truthVerticesToMatch);
184 // optional SM origin classification
185 if (m_doSMOrigin) {
186 const int smOrigin = checkSMProduction(truthPart);
187 combinedSMOrigin |= smOrigin;
188
189 // Check if this track is from LLP signal
190 if (ancestorVertexUniqueID != HepMC::INVALID_VERTEX_ID) {
191 combinedSMOrigin |= (0x1 << InDetSecVtxTruthMatchUtils::Signal);
192 }
193 }
194
195 //check if the truth particle is "good"
196 if (ancestorVertexUniqueID != HepMC::INVALID_VERTEX_ID) {
197 //track in vertex is linked to LLP descendant
198 //create link to truth vertex and add to matchInfo
199 auto it = std::find_if(truthVerticesToMatch.begin(), truthVerticesToMatch.end(),
200 [&](const auto& ele){ return HepMC::uniqueID(ele) == ancestorVertexUniqueID;} );
201
202 if (it == truthVerticesToMatch.end()) {
203 ATH_MSG_WARNING("Truth vertex with unique ID " << ancestorVertexUniqueID << " not found!");
204 } else {
206 elLink.setElement(*it);
207 elLink.setStorableObject(*dynamic_cast<const xAOD::TruthVertexContainer*>((*it)->container()));
208 size_t matchIdx = indexOfMatchInfo(matchinfo, elLink);
209
210 if (m_doMuSA) {
211 std::get<1>(matchinfo[matchIdx]) += 1.0; // Add dummy weight of 1 for MuSA
212 } else {
213 std::get<1>(matchinfo[matchIdx]) += trkWeights[t];
214 }
215 std::get<2>(matchinfo[matchIdx]) += trk.pt();
216 }
217 } else {
218 //truth particle failed cuts
219 ATH_MSG_DEBUG("Truth particle not from LLP decay.");
220 otherPt += trk.pt();
221 }
222 } else {
223 //not valid or low matching probability
224 ATH_MSG_DEBUG("Invalid or low prob truth link!");
225 fakePt += trk.pt();
226 // Mark as fake for SM origin tracking
227 if (m_doSMOrigin) {
228 combinedSMOrigin |= (0x1 << InDetSecVtxTruthMatchUtils::FakeOrigin);
229 }
230 }
231 }//end loop over tracks in vertex
232
233 // normalize by total weight and pT
234 std::for_each( matchinfo.begin(), matchinfo.end(), [&](VertexTruthMatchInfo& link)
235 {
236 std::get<1>(link) /= totalWeight;
237 std::get<2>(link) /= totalPt;
238 });
239
240 float fakeScore = fakePt/totalPt;
241 float otherScore = otherPt/totalPt;
242
243 matchInfoDecor ( *vtx ) = matchinfo;
244 fakeScoreDecor ( *vtx ) = fakeScore;
245 otherScoreDecor( *vtx ) = otherScore;
246
247 // Decorate with SM origin if enabled
248 if (m_doSMOrigin) {
249 smOriginDecor( *vtx ) = combinedSMOrigin;
250 }
251 }
252
253 //After first loop, all vertices have been decorated with their vector of match info (link to TruthVertex paired with weight)
254 //now we want to use that information from the whole collection to assign types
255 //keep track of whether a type is assigned
256 //useful since looking for splits involves a double loop, and then setting types ahead in the collection
257 std::vector<bool> assignedType( recoVerticesToMatch.size(), false );
258 static const xAOD::TruthVertex::Decorator<bool> isMatched("matchedToRecoVertex");
259 static const xAOD::TruthVertex::Decorator<bool> isSplit("vertexSplit");
260
261 for ( size_t i = 0; i < recoVerticesToMatch.size(); ++i ) {
262
263 int recoVertexMatchType = 0;
264
265 if ( assignedType[i] ) {
266 ATH_MSG_DEBUG("Vertex already defined as split.");
267 continue; // make sure we don't reclassify vertices already found in the split loop below
268 }
269
270 std::vector<VertexTruthMatchInfo> & info = matchInfoDecor( *recoVerticesToMatch[i] );
271 float fakeScore = fakeScoreDecor( *recoVerticesToMatch[i] );
272
273 if(fakeScore > m_vxMatchWeight) {
274 ATH_MSG_DEBUG("Vertex is fake.");
275 recoVertexMatchType = recoVertexMatchType | (0x1 << InDetSecVtxTruthMatchUtils::Fake);
276 } else if (info.size() == 1) {
277 if(std::get<2>(info[0]) > m_vxMatchWeight ) { // one truth matched vertex, sufficient weight
278 ATH_MSG_DEBUG("One true decay vertices matched with sufficient weight. Vertex is matched.");
279 recoVertexMatchType = recoVertexMatchType | (0x1 << InDetSecVtxTruthMatchUtils::Matched);
280 isMatched(**std::get<0>(info[0])) = true;
281 }
282 else {
283 ATH_MSG_DEBUG("One true decay vertices matched with insufficient weight. Vertex is other.");
284 recoVertexMatchType = recoVertexMatchType | (0x1 << InDetSecVtxTruthMatchUtils::Other);
285 }
286 } else if (info.size() >= 2 ) { // more than one true deacy vertices matched
287 ATH_MSG_DEBUG("Multiple true decay vertices matched. Vertex is merged.");
288 recoVertexMatchType = recoVertexMatchType | (0x1 << InDetSecVtxTruthMatchUtils::Merged);
289 std::for_each( info.begin(), info.end(), [](VertexTruthMatchInfo& link)
290 {
291 isMatched(**std::get<0>(link)) = true;
292 });
293 } else { // zero truth matched vertices, but not fake
294 ATH_MSG_DEBUG("Vertex is neither fake nor LLP. Marking as OTHER.");
295 recoVertexMatchType = recoVertexMatchType | (0x1 << InDetSecVtxTruthMatchUtils::Other);
296 }
297
298 recoMatchTypeDecor(*recoVerticesToMatch[i]) = recoVertexMatchType;
299
300 //check for splitting
301 if ( InDetSecVtxTruthMatchUtils::isMatched(recoMatchTypeDecor(*recoVerticesToMatch[i])) ||
302 InDetSecVtxTruthMatchUtils::isMerged(recoMatchTypeDecor(*recoVerticesToMatch[i])) ) {
303 std::vector<size_t> foundSplits;
304 for ( size_t j = i + 1; j < recoVerticesToMatch.size(); ++j ) {
305 std::vector<VertexTruthMatchInfo> & info2 = matchInfoDecor( *recoVerticesToMatch[j] );
306 //check second vertex is not dummy or fake, and that it has same elementlink as first vertex
307 //equality test is in code but doesnt seem to work for ElementLinks that I have?
308 //so i am just checking that the contianer key hash and the index are the same
309 if (recoMatchTypeDecor( *recoVerticesToMatch[j] ) & (0x1 << InDetSecVtxTruthMatchUtils::Fake)) continue;
310 if (!info2.empty() && std::get<0>(info2[0]).isValid() && std::get<0>(info[0]).key() == std::get<0>(info2[0]).key() && std::get<0>(info[0]).index() == std::get<0>(info2[0]).index() ) {
311 //add split links; first between first one found and newest one
313 splitLink_ij.setElement( recoVerticesToMatch[j] );
314 splitLink_ij.setStorableObject( *dynamic_cast<const xAOD::VertexContainer*>(recoVerticesToMatch[j]->container()));
315 splitPartnerDecor( *recoVerticesToMatch[i] ).emplace_back(splitLink_ij);
316
318 splitLink_ji.setElement( recoVerticesToMatch[i] );
319 splitLink_ji.setStorableObject( *dynamic_cast<const xAOD::VertexContainer*>(recoVerticesToMatch[i]->container()));
320 splitPartnerDecor( *recoVerticesToMatch[j] ).emplace_back(splitLink_ji);
321
322 //then between any others we found along the way
323 for ( auto k : foundSplits ) { //k is a size_t in the vector of splits
325 splitLink_kj.setElement( recoVerticesToMatch[j] );
326 splitLink_kj.setStorableObject( *dynamic_cast<const xAOD::VertexContainer*>(recoVerticesToMatch[j]->container()));
327 splitPartnerDecor( *recoVerticesToMatch[k] ).emplace_back(splitLink_kj);
328
330 splitLink_jk.setElement( recoVerticesToMatch[k] );
331 splitLink_jk.setStorableObject( *dynamic_cast<const xAOD::VertexContainer*>(recoVerticesToMatch[k]->container()));
332 splitPartnerDecor( *recoVerticesToMatch[j] ).emplace_back(splitLink_jk);
333 }
334 //then keep track that we found this one
335 foundSplits.push_back(j);
336 recoMatchTypeDecor( *recoVerticesToMatch[i] ) = recoMatchTypeDecor( *recoVerticesToMatch[i] ) | (0x1 << InDetSecVtxTruthMatchUtils::Split);
337 recoMatchTypeDecor( *recoVerticesToMatch[j] ) = recoMatchTypeDecor( *recoVerticesToMatch[j] ) | (0x1 << InDetSecVtxTruthMatchUtils::Split);
338 isSplit(**std::get<0>(info[0])) = true;
339 assignedType[j] = true;
340 } //if the two vertices match to same TruthVertex
341 }//inner loop over vertices
342 } //if matched or merged
343
344 } //outer loop
345
346 // now label truth vertices
347
348 ATH_MSG_DEBUG("Labeling truth vertices");
349
350 static const xAOD::TruthVertex::Decorator<int> truthMatchTypeDecor("truthVertexMatchType");
351
352 for(const xAOD::TruthVertex* truthVtx : truthVerticesToMatch) {
353
354 std::vector<const xAOD::TruthParticle*> reconstructibleParticles;
355 int counter = 0;
356 countReconstructibleDescendentParticles( *truthVtx, reconstructibleParticles, counter );
357
358 // hacky solution for keeping track of particles in the vertex
359 std::vector<int> particleInfo = {0,0,0};
360 std::vector<int> vertexInfo = {0,0,0};
361
362 for(size_t n = 0; n < reconstructibleParticles.size(); n++){
363 ATH_MSG_DEBUG("Checking daughter no. " << n);
364 const xAOD::TruthParticle* outPart = reconstructibleParticles.at(n);
365
366 if (trackParticles){
367 particleInfo = checkParticle(*outPart, trackParticles);
368
369 for(size_t h = 0; h < particleInfo.size(); h++){
370 vertexInfo.at(h) += particleInfo.at(h);
371 }
372 }
373 }
374
375 int truthMatchType = 0;
376 if( vertexInfo.at(0) > 1 &&
377 ((m_doMuSA && truthVtx->perp() < 8000 && std::abs(truthVtx->z()) < 10000) ||
378 (!m_doMuSA && truthVtx->perp() < 320 && std::abs(truthVtx->z()) < 1500))){
379 ATH_MSG_DEBUG("Vertex is reconstructable and in " << (m_doMuSA ? "Muon Spectrometer" : "Inner Det") << " region");
380 truthMatchType = truthMatchType | (0x1 << InDetSecVtxTruthMatchUtils::Reconstructable);
381 }
382 if( InDetSecVtxTruthMatchUtils::isReconstructable(truthMatchType) and vertexInfo.at(1) > 1){
383 ATH_MSG_DEBUG("Vertex has at least two tracks");
384 truthMatchType = truthMatchType | (0x1 << InDetSecVtxTruthMatchUtils::Accepted);
385 }
386 if(InDetSecVtxTruthMatchUtils::isAccepted(truthMatchType) and vertexInfo.at(2) > 1){
387 ATH_MSG_DEBUG("Vertex is has at least two tracks passing track selection: " << vertexInfo.at(2));
388 truthMatchType = truthMatchType | (0x1 << InDetSecVtxTruthMatchUtils::Seeded);
389 }
390 if(InDetSecVtxTruthMatchUtils::isSeeded(truthMatchType) and isMatched(*truthVtx)){
391 ATH_MSG_DEBUG("Vertex is matched to a reconstructed secVtx");
392 truthMatchType = truthMatchType | (0x1 << InDetSecVtxTruthMatchUtils::Reconstructed);
393 }
394 if(InDetSecVtxTruthMatchUtils::isSeeded(truthMatchType) and isSplit(*truthVtx)){
395 ATH_MSG_DEBUG("Vertex is matched to multiple secVtx");
396 truthMatchType = truthMatchType | (0x1 << InDetSecVtxTruthMatchUtils::ReconstructedSplit);
397 }
398 truthMatchTypeDecor(*truthVtx) = truthMatchType;
399 }
400 ATH_MSG_DEBUG("Done labeling truth vertices");
401
402 return StatusCode::SUCCESS;
403
404}
405
406std::vector<int> InDetSecVtxTruthMatchTool::checkParticle(const xAOD::TruthParticle &truthPart, const xAOD::TrackParticleContainer* trkCont) const {
407
410 xAOD::TrackParticle::ConstAccessor<float> trk_truthProbAcc("truthMatchProbability");
411
412 if(truthPart.pt() < m_trkPtCut){
413 ATH_MSG_DEBUG("Insufficient pt to reconstruct the particle");
414 return {0,0,0};
415 }
416 else{
417
418 for(const xAOD::TrackParticle* trkPart : *trkCont){
419 // Handle differently for MuSA vs standard mode
420 if (m_doMuSA) {
421 if (!trk_truthPartAcc.isAvailable(*trkPart)) {
422 ATH_MSG_DEBUG("Truth link not available on MS track");
423 continue;
424 }
425 const ElementLink<xAOD::TruthParticleContainer>& truthLink = trk_truthPartAcc(*trkPart);
426 if (!truthLink.isValid()) {
427 ATH_MSG_DEBUG("Truth link on MS track not valid");
428 continue;
429 }
430 const xAOD::TruthParticle& linkedTruth = **truthLink;
431 if (HepMC::is_same_particle(linkedTruth, truthPart)) {
432 // We found a match between truth particle and MS track!
433 // no selected decoration so need to implement manually -- MSTP must be |eta| < 2.5
434 // ideally we would want to check if the MSTP is also an SA muon but this is more complicated given we need the muon container
435 if (std::abs(trkPart->eta()) < 2.5) {
436 ATH_MSG_DEBUG("Particle has a track that passes track selection.");
437 return {1,1,1};
438 } else {
439 ATH_MSG_DEBUG("Particle has a track, but did not pass track selection.");
440 return {1,1,0};
441 }
442 }
443 }
444
445 // Standard mode - check truth matching
446 if (!trk_truthPartAcc.isAvailable(*trkPart)) {
447 ATH_MSG_DEBUG("truthParticleLink not available on track");
448 continue;
449 }
450
451 const ElementLink<xAOD::TruthParticleContainer> & truthPartLink = trk_truthPartAcc(*trkPart);
452
453 // Check if truth match probability is available
454 float matchProb = 0.0;
455 if (trk_truthProbAcc.isAvailable(*trkPart)) {
456 matchProb = trk_truthProbAcc(*trkPart);
457 } else {
458 ATH_MSG_DEBUG("truthMatchProbability not available on track");
459 continue;
460 }
461
462 if(truthPartLink.isValid() && matchProb > m_trkMatchProb) {
463 const xAOD::TruthParticle& tmpPart = **truthPartLink;
464 if( HepMC::is_same_particle(tmpPart,truthPart) ) {
465 if(trackPass.isAvailable( *trkPart )) {
466 if(trackPass( *trkPart )) {
467 ATH_MSG_DEBUG("Particle has a track that passes track selection.");
468 return {1,1,1};
469 } else {
470 ATH_MSG_DEBUG("Particle has a track, but did not pass track selection.");
471 return {1,1,0};
472 }
473 } else {
474 ATH_MSG_DEBUG("Track selection decoration not available, calling the track selected");
475 return {1,1,1};
476 }
477 }
478 }
479 }
480 ATH_MSG_DEBUG("Particle has enough pt.");
481 return {1,0,0};
482
483 }
484 return {0,0,0};
485}
486
487// check if truth particle originated from decay of particle in the pdgIdList
488int InDetSecVtxTruthMatchTool::checkProduction( const xAOD::TruthParticle & truthPart, std::vector<const xAOD::TruthVertex*> truthVerticesToMatch ) const {
489
490 if (truthPart.nParents() == 0){
491 ATH_MSG_DEBUG("Particle has no parents (end of loop)");
493 }
494 else{
495 const xAOD::TruthParticle * parent = truthPart.parent(0);
496 if(not parent) {
497 ATH_MSG_DEBUG("Particle parent is null");
499 }
500 ATH_MSG_DEBUG("Parent ID: " << parent->pdgId());
501
502 const xAOD::TruthVertex* parentVertex = parent->decayVtx();
503 if(std::find(truthVerticesToMatch.begin(), truthVerticesToMatch.end(), parentVertex) != truthVerticesToMatch.end()) {
504 ATH_MSG_DEBUG("Found LLP decay.");
505 return HepMC::uniqueID(parentVertex);
506 }
507 // recurse on parent
508 return checkProduction(*parent, truthVerticesToMatch);
509 }
511}
512
513// secvtx origin has extra categories compared to original track origin, so need to map them to our enum
514int mapTrkOriginToSecVtxOrigin(int trkOriginBits) {
515 int myBits = 0;
516 if (trkOriginBits & (1 << InDet::TrkOrigin::BHadronDecay))
518 if (trkOriginBits & (1 << InDet::TrkOrigin::DHadronDecay))
520 if (trkOriginBits & (1 << InDet::TrkOrigin::TauDecay))
522 if (trkOriginBits & (1 << InDet::TrkOrigin::GammaConversion))
524 if (trkOriginBits & (1 << InDet::TrkOrigin::StrangeMesonDecay))
526 if (trkOriginBits & (1 << InDet::TrkOrigin::KshortDecay))
528 if (trkOriginBits & (1 << InDet::TrkOrigin::StrangeBaryonDecay))
530 if (trkOriginBits & (1 << InDet::TrkOrigin::LambdaDecay))
532 if (trkOriginBits & (1 << InDet::TrkOrigin::OtherDecay))
534 if (trkOriginBits & (1 << InDet::TrkOrigin::HadronicInteraction))
536 if (trkOriginBits & (1 << InDet::TrkOrigin::OtherSecondary))
538 if (trkOriginBits & (1 << InDet::TrkOrigin::Fragmentation))
540 if (trkOriginBits & (1 << InDet::TrkOrigin::OtherOrigin))
542 return myBits;
543}
544
546 if (m_trackTruthOriginTool.isSet()) {
547 int trkOriginBits = m_trackTruthOriginTool->getTruthOrigin(&truthPart);
548 return mapTrkOriginToSecVtxOrigin(trkOriginBits);
549 }
550 ATH_MSG_WARNING("TrackTruthOriginTool not set, returning 0 for origin");
551 return 0;
552}
553
555 std::vector<const xAOD::TruthParticle*>& set, int counter) const {
556
557 counter++;
558
559 for (size_t itrk = 0; itrk < signalTruthVertex.nOutgoingParticles(); itrk++) {
560 const auto* particle = signalTruthVertex.outgoingParticle(itrk);
561 if (!particle) continue;
562
563 // Recursively add descendents
564 if (particle->hasDecayVtx()) {
565
566 TVector3 decayPos(particle->decayVtx()->x(), particle->decayVtx()->y(), particle->decayVtx()->z());
567 TVector3 prodPos(particle->prodVtx()->x(), particle->prodVtx()->y(), particle->prodVtx()->z());
568
569 // Inner detector criteria
570 auto isInsideID = [](TVector3& v) { return (v.Perp() < 300. && std::abs(v.z()) < 1500.); };
571 auto isOutsideID = [](TVector3& v) { return (v.Perp() > 563. || std::abs(v.z()) > 2720.); };
572
573 // Muon Spectrometer criteria
574 auto isOutsideID_MuSA = [](TVector3& v) { return (v.Perp() > 563. || std::abs(v.z()) > 2720.); };
575 auto isInsideMS_MuSA = [](TVector3& v) { return (v.Perp() < 8000. && std::abs(v.z()) < 10000.); };
576
577 const auto distance = (decayPos - prodPos).Mag();
578
579 if (counter > 100) {
580 ATH_MSG_WARNING("Vetoing particle that may be added recursively infinitely (potential loop in generator record");
581 break;
582 }
583
584 // consider track reconstructible if it travels at least 10mm
585 if (distance < 10.0) {
586 countReconstructibleDescendentParticles(*particle->decayVtx(), set, counter);
587 } else if (m_doMuSA) {
588 // MuSA: particle originates outside ID and ends in MS
589 if (isOutsideID_MuSA(prodPos) && isInsideMS_MuSA(decayPos) && (particle->isCharged() || particle->isMuon())) {
590 set.push_back(particle);
591 }
592 } else {
593 // Regular tracking: particle originates inside ID and ends outside ID
594 if (isInsideID(prodPos) && isOutsideID(decayPos) && particle->isCharged()) {
595 set.push_back(particle);
596 } else if (particle->isElectron() || particle->isMuon()) {
597 set.push_back(particle);
598 }
599 }
600 } else {
601 if (!(particle->isCharged())) continue;
602 // For particles without decay vertex, include them if they're charged
603 set.push_back(particle);
604 }
605 }
606}
607
608bool InDetSecVtxTruthMatchTool::isFrom(const xAOD::TruthParticle& truth, int flav) const {
609 if (m_trackTruthOriginTool.isSet()) {
610 return m_trackTruthOriginTool->isFrom(&truth, flav);
611 }
612 ATH_MSG_WARNING("TrackTruthOriginTool not set, returning false for isFrom");
613 return false;
614}
615
616
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_INFO(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
bool isValid(const T &p)
Av: we implement here an ATLAS-sepcific convention: all particles which are 99xxxxx are fine.
Definition AtlasPID.h:878
ATLAS-specific HepMC functions.
int mapTrkOriginToSecVtxOrigin(int trkOriginBits)
ToolHandle< InDet::IInDetTrackTruthOriginTool > m_trackTruthOriginTool
std::vector< int > checkParticle(const xAOD::TruthParticle &part, const xAOD::TrackParticleContainer *tkCont) const
Gaudi::Property< std::string > m_selectedTrackFlag
void countReconstructibleDescendentParticles(const xAOD::TruthVertex &signalTruthVertex, std::vector< const xAOD::TruthParticle * > &set, int counter) const
virtual StatusCode initialize() override final
Dummy implementation of the initialisation function.
virtual StatusCode matchVertices(std::vector< const xAOD::Vertex * > recoVerticesToMatch, std::vector< const xAOD::TruthVertex * > truthVerticesToMatch, const xAOD::TrackParticleContainer *trackParticles) override
Gaudi::Property< bool > m_doSMOrigin
InDetSecVtxTruthMatchTool(const std::string &name)
int checkProduction(const xAOD::TruthParticle &truthPart, std::vector< const xAOD::TruthVertex * > truthVerticesToMatch) const
int checkSMProduction(const xAOD::TruthParticle &truthPart) const
Gaudi::Property< float > m_trkPtCut
Gaudi::Property< float > m_vxMatchWeight
Gaudi::Property< float > m_trkMatchProb
bool isFrom(const xAOD::TruthParticle &truth, int flav) const
SG::Accessor< T, ALLOC > Accessor
Definition AuxElement.h:572
bool isAvailable(const ELT &e) const
Test to see if this variable exists in the store.
SG::Decorator< T, ALLOC > Decorator
class to provide type-safe access to aux data.
Definition AuxElement.h:135
SG::ConstAccessor< T, ALLOC > ConstAccessor
Helper class to provide type-safe access to aux data.
Definition AuxElement.h:131
AsgTool(const std::string &name)
Constructor specifying the tool instance's name.
Definition AsgTool.cxx:58
STL class.
virtual double pt() const override final
The transverse momentum ( ) of the particle.
const TruthParticle_v1 * parent(size_t i) const
Retrieve the i-th mother (TruthParticle) of this TruthParticle.
virtual double pt() const override final
The transverse momentum ( ) of the particle.
size_t nParents() const
Number of parents of this particle.
const TruthParticle_v1 * outgoingParticle(size_t index) const
Get one of the outgoing particles.
size_t nOutgoingParticles() const
Get the number of outgoing particles.
std::vector< ElementLink< xAOD::TrackParticleContainer > > TrackParticleLinks_t
Type for the associated track particles.
Definition Vertex_v1.h:128
int uniqueID(const T &p)
bool is_same_particle(const T1 &p1, const T2 &p2)
Method to establish if two particles in the GenEvent actually represent the same particle.
constexpr int INVALID_VERTEX_ID
std::tuple< ElementLink< xAOD::TruthVertexContainer >, float, float > VertexTruthMatchInfo
TruthVertex_v1 TruthVertex
Typedef to implementation.
Definition TruthVertex.h:15
TrackParticle_v1 TrackParticle
Reference the current persistent version:
TruthVertexContainer_v1 TruthVertexContainer
Declare the latest version of the truth vertex container.
VertexContainer_v1 VertexContainer
Definition of the current "Vertex container version".
Vertex_v1 Vertex
Define the latest version of the vertex class.
TruthParticle_v1 TruthParticle
Typedef to implementation.
TrackParticleContainer_v1 TrackParticleContainer
Definition of the current "TrackParticle container version".