ATLAS Offline Software
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 
12 using namespace InDetSecVtxTruthMatchUtils;
13 
15 
17  ATH_MSG_INFO("Initializing InDetSecVtxTruthMatchTool");
18 
19  // Retrieve the TrackTruthOriginTool
21 
22  return StatusCode::SUCCESS;
23 }
24 
25 namespace {
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
29 size_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 
41 StatusCode 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 
406 std::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
488 int 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
514 int 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))
521  myBits |= (1 << InDetSecVtxTruthMatchUtils::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) {
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 
608 bool 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 
InDet::TrkOrigin::StrangeMesonDecay
@ StrangeMesonDecay
Definition: InDetTrackTruthOriginDefs.h:23
xAOD::TruthVertex_v1::nOutgoingParticles
size_t nOutgoingParticles() const
Get the number of outgoing particles.
xAOD::TrackParticle_v1::pt
virtual double pt() const override final
The transverse momentum ( ) of the particle.
Definition: TrackParticle_v1.cxx:74
AllowedVariables::e
e
Definition: AsgElectronSelectorTool.cxx:37
plotBeamSpotCompare.x1
x1
Definition: plotBeamSpotCompare.py:215
InDetSecVtxTruthMatchTool::m_selectedTrackFlag
Gaudi::Property< std::string > m_selectedTrackFlag
Definition: InDetSecVtxTruthMatchTool.h:148
InDetSecVtxTruthMatchUtils::ReconstructedSplit
@ ReconstructedSplit
Definition: InDetSecVtxTruthMatchTool.h:72
InDetSecVtxTruthMatchUtils::OtherSecondary
@ OtherSecondary
Definition: InDetSecVtxTruthMatchTool.h:57
Trk::ParticleSwitcher::particle
constexpr ParticleHypothesis particle[PARTICLEHYPOTHESES]
the array of masses
Definition: ParticleHypothesis.h:79
InDetSecVtxTruthMatchTool::m_doSMOrigin
Gaudi::Property< bool > m_doSMOrigin
Definition: InDetSecVtxTruthMatchTool.h:150
ATH_MSG_INFO
#define ATH_MSG_INFO(x)
Definition: AthMsgStreamMacros.h:31
find
std::string find(const std::string &s)
return a remapped string
Definition: hcg.cxx:135
InDetSecVtxTruthMatchUtils::HadronicInteraction
@ HadronicInteraction
Definition: InDetSecVtxTruthMatchTool.h:56
SG::Accessor
Helper class to provide type-safe access to aux data.
Definition: Control/AthContainers/AthContainers/Accessor.h:68
InDetSecVtxTruthMatchTool::initialize
virtual StatusCode initialize() override final
Dummy implementation of the initialisation function.
Definition: InDetSecVtxTruthMatchTool.cxx:16
InDetSecVtxTruthMatchUtils::isReconstructable
bool isReconstructable(int matchInfo)
Definition: InDetSecVtxTruthMatchTool.h:96
InDetSecVtxTruthMatchUtils::Signal
@ Signal
Definition: InDetSecVtxTruthMatchTool.h:62
InDet::TrkOrigin::TauDecay
@ TauDecay
Definition: InDetTrackTruthOriginDefs.h:26
skel.it
it
Definition: skel.GENtoEVGEN.py:407
asg
Definition: DataHandleTestTool.h:28
InDetSecVtxTruthMatchTool::countReconstructibleDescendentParticles
void countReconstructibleDescendentParticles(const xAOD::TruthVertex &signalTruthVertex, std::vector< const xAOD::TruthParticle * > &set, int counter) const
Definition: InDetSecVtxTruthMatchTool.cxx:554
InDetSecVtxTruthMatchUtils::isMerged
bool isMerged(int matchInfo)
Definition: InDetSecVtxTruthMatchTool.h:79
InDet::TrkOrigin::KshortDecay
@ KshortDecay
Definition: InDetTrackTruthOriginDefs.h:22
InDet::TrkOrigin::DHadronDecay
@ DHadronDecay
Definition: InDetTrackTruthOriginDefs.h:33
InDetSecVtxTruthMatchUtils::isMatched
bool isMatched(int matchInfo)
Definition: InDetSecVtxTruthMatchTool.h:75
SG::ConstAccessor
Helper class to provide constant type-safe access to aux data.
Definition: ConstAccessor.h:55
InDetSecVtxTruthMatchUtils::isSplit
bool isSplit(int matchInfo)
Definition: InDetSecVtxTruthMatchTool.h:83
read_hist_ntuple.t
t
Definition: read_hist_ntuple.py:5
isValid
bool isValid(const T &p)
Av: we implement here an ATLAS-sepcific convention: all particles which are 99xxxxx are fine.
Definition: AtlasPID.h:872
mapTrkOriginToSecVtxOrigin
int mapTrkOriginToSecVtxOrigin(int trkOriginBits)
Definition: InDetSecVtxTruthMatchTool.cxx:514
covarianceTool.prob
prob
Definition: covarianceTool.py:678
InDetSecVtxTruthMatchUtils::Fake
@ Fake
Definition: InDetSecVtxTruthMatchTool.h:37
HepMC::is_same_particle
bool is_same_particle(const T1 &p1, const T2 &p2)
Method to establish if two particles in the GenEvent actually represent the same particle.
Definition: MagicNumbers.h:366
InDetSecVtxTruthMatchTool::checkProduction
int checkProduction(const xAOD::TruthParticle &truthPart, std::vector< const xAOD::TruthVertex * > truthVerticesToMatch) const
Definition: InDetSecVtxTruthMatchTool.cxx:488
InDetSecVtxTruthMatchUtils::Split
@ Split
Definition: InDetSecVtxTruthMatchTool.h:36
InDet::TrkOrigin::OtherOrigin
@ OtherOrigin
Definition: InDetTrackTruthOriginDefs.h:37
InDetSecVtxTruthMatchTool::m_doMuSA
Gaudi::Property< bool > m_doMuSA
Definition: InDetSecVtxTruthMatchTool.h:149
InDetSecVtxTruthMatchTool::matchVertices
virtual StatusCode matchVertices(std::vector< const xAOD::Vertex * > recoVerticesToMatch, std::vector< const xAOD::TruthVertex * > truthVerticesToMatch, const xAOD::TrackParticleContainer *trackParticles) override
Definition: InDetSecVtxTruthMatchTool.cxx:41
InDetSecVtxTruthMatchUtils::Other
@ Other
Definition: InDetSecVtxTruthMatchTool.h:38
InDetSecVtxTruthMatchTool.h
xAOD::TruthParticle_v1::nParents
size_t nParents() const
Number of parents of this particle.
Definition: TruthParticle_v1.cxx:117
SG::Decorator
Helper class to provide type-safe access to aux data.
Definition: Decorator.h:59
lumiFormat.i
int i
Definition: lumiFormat.py:85
InDetSecVtxTruthMatchTool::m_vxMatchWeight
Gaudi::Property< float > m_vxMatchWeight
Definition: InDetSecVtxTruthMatchTool.h:146
InDetSecVtxTruthMatchUtils::BHadronDecay
@ BHadronDecay
Definition: InDetSecVtxTruthMatchTool.h:58
InDetSecVtxTruthMatchUtils::isAccepted
bool isAccepted(int matchInfo)
Definition: InDetSecVtxTruthMatchTool.h:100
h
beamspotman.n
n
Definition: beamspotman.py:727
InDet::TrkOrigin::BHadronDecay
@ BHadronDecay
Definition: InDetTrackTruthOriginDefs.h:32
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
InDetSecVtxTruthMatchUtils::Fragmentation
@ Fragmentation
Definition: InDetSecVtxTruthMatchTool.h:60
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
xAOD::TruthParticle_v1
Class describing a truth particle in the MC record.
Definition: TruthParticle_v1.h:37
InDet::TrkOrigin::StrangeBaryonDecay
@ StrangeBaryonDecay
Definition: InDetTrackTruthOriginDefs.h:25
InDetSecVtxTruthMatchUtils::Reconstructable
@ Reconstructable
Definition: InDetSecVtxTruthMatchTool.h:68
InDetSecVtxTruthMatchTool::m_trkMatchProb
Gaudi::Property< float > m_trkMatchProb
Definition: InDetSecVtxTruthMatchTool.h:145
InDetSecVtxTruthMatchUtils::LambdaDecay
@ LambdaDecay
Definition: InDetSecVtxTruthMatchTool.h:51
calibdata.exception
exception
Definition: calibdata.py:495
HepMC::uniqueID
int uniqueID(const T &p)
Definition: MagicNumbers.h:116
test_pyathena.parent
parent
Definition: test_pyathena.py:15
InDetSecVtxTruthMatchTool::m_trackTruthOriginTool
ToolHandle< InDet::IInDetTrackTruthOriginTool > m_trackTruthOriginTool
Definition: InDetSecVtxTruthMatchTool.h:152
InDetSecVtxTruthMatchUtils::StrangeMesonDecay
@ StrangeMesonDecay
Definition: InDetSecVtxTruthMatchTool.h:50
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
InDet::TrkOrigin::GammaConversion
@ GammaConversion
Definition: InDetTrackTruthOriginDefs.h:27
xAOD::Vertex_v1::TrackParticleLinks_t
std::vector< ElementLink< xAOD::TrackParticleContainer > > TrackParticleLinks_t
Type for the associated track particles.
Definition: Vertex_v1.h:128
InDet::TrkOrigin::LambdaDecay
@ LambdaDecay
Definition: InDetTrackTruthOriginDefs.h:24
InDet::TrkOrigin::OtherDecay
@ OtherDecay
Definition: InDetTrackTruthOriginDefs.h:28
DataVector
Derived DataVector<T>.
Definition: DataVector.h:794
CxxUtils::set
constexpr std::enable_if_t< is_bitmask_v< E >, E & > set(E &lhs, E rhs)
Convenience function to set bits in a class enum bitmask.
Definition: bitmask.h:232
InDetSecVtxTruthMatchUtils::OtherDecay
@ OtherDecay
Definition: InDetSecVtxTruthMatchTool.h:55
HepMC::INVALID_VERTEX_ID
constexpr int INVALID_VERTEX_ID
Definition: MagicNumbers.h:58
xAOD::TruthVertex_v1
Class describing a truth vertex in the MC record.
Definition: TruthVertex_v1.h:37
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:240
MagicNumbers.h
InDetSecVtxTruthMatchUtils::KshortDecay
@ KshortDecay
Definition: InDetSecVtxTruthMatchTool.h:49
InDet::TrkOrigin::Fragmentation
@ Fragmentation
Definition: InDetTrackTruthOriginDefs.h:35
InDetTrackTruthOriginDefs.h
python.PyAthena.v
v
Definition: PyAthena.py:154
InDetSecVtxTruthMatchUtils::Reconstructed
@ Reconstructed
Definition: InDetSecVtxTruthMatchTool.h:71
InDetSecVtxTruthMatchUtils::Seeded
@ Seeded
Definition: InDetSecVtxTruthMatchTool.h:70
InDetSecVtxTruthMatchUtils::OtherOrigin
@ OtherOrigin
Definition: InDetSecVtxTruthMatchTool.h:61
InDet::TrkOrigin::OtherSecondary
@ OtherSecondary
Definition: InDetTrackTruthOriginDefs.h:30
xAOD::Vertex_v1
Class describing a Vertex.
Definition: Vertex_v1.h:42
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
InDetSecVtxTruthMatchUtils::GammaConversion
@ GammaConversion
Definition: InDetSecVtxTruthMatchTool.h:54
InDetSecVtxTruthMatchUtils::Merged
@ Merged
Definition: InDetSecVtxTruthMatchTool.h:35
InDetSecVtxTruthMatchUtils::VertexTruthMatchInfo
std::tuple< ElementLink< xAOD::TruthVertexContainer >, float, float > VertexTruthMatchInfo
Definition: InDetSecVtxTruthMatchTool.h:30
InDetSecVtxTruthMatchUtils::Matched
@ Matched
Definition: InDetSecVtxTruthMatchTool.h:34
xAOD::TruthParticle_v1::parent
const TruthParticle_v1 * parent(size_t i) const
Retrieve the i-th mother (TruthParticle) of this TruthParticle.
Definition: TruthParticle_v1.cxx:126
InDetSecVtxTruthMatchTool::checkParticle
std::vector< int > checkParticle(const xAOD::TruthParticle &part, const xAOD::TrackParticleContainer *tkCont) const
Definition: InDetSecVtxTruthMatchTool.cxx:406
InDetSecVtxTruthMatchTool::InDetSecVtxTruthMatchTool
InDetSecVtxTruthMatchTool(const std::string &name)
Definition: InDetSecVtxTruthMatchTool.cxx:14
InDet::TrkOrigin::HadronicInteraction
@ HadronicInteraction
Definition: InDetTrackTruthOriginDefs.h:29
xAOD::TruthParticle_v1::pt
virtual double pt() const override final
The transverse momentum ( ) of the particle.
Definition: TruthParticle_v1.cxx:161
InDetSecVtxTruthMatchTool::isFrom
bool isFrom(const xAOD::TruthParticle &truth, int flav) const
Definition: InDetSecVtxTruthMatchTool.cxx:608
SG::ConstAccessor< T, AuxAllocator_t< T > >::isAvailable
bool isAvailable(const ELT &e) const
Test to see if this variable exists in the store.
InDetSecVtxTruthMatchUtils::StrangeBaryonDecay
@ StrangeBaryonDecay
Definition: InDetSecVtxTruthMatchTool.h:52
InDetSecVtxTruthMatchUtils::TauDecay
@ TauDecay
Definition: InDetSecVtxTruthMatchTool.h:53
xAOD::TrackParticle_v1
Class describing a TrackParticle.
Definition: TrackParticle_v1.h:43
InDetSecVtxTruthMatchUtils::FakeOrigin
@ FakeOrigin
Definition: InDetSecVtxTruthMatchTool.h:47
TruthEventContainer.h
InDetSecVtxTruthMatchUtils::isSeeded
bool isSeeded(int matchInfo)
Definition: InDetSecVtxTruthMatchTool.h:104
test_pyathena.counter
counter
Definition: test_pyathena.py:15
Amg::distance
float distance(const Amg::Vector3D &p1, const Amg::Vector3D &p2)
calculates the distance between two point in 3D space
Definition: GeoPrimitivesHelpers.h:54
python.ParticleTypeUtil.info
def info
Definition: ParticleTypeUtil.py:87
xAOD::TruthVertex_v1::outgoingParticle
const TruthParticle_v1 * outgoingParticle(size_t index) const
Get one of the outgoing particles.
Definition: TruthVertex_v1.cxx:120
InDetSecVtxTruthMatchUtils::Accepted
@ Accepted
Definition: InDetSecVtxTruthMatchTool.h:69
InDetSecVtxTruthMatchTool::checkSMProduction
int checkSMProduction(const xAOD::TruthParticle &truthPart) const
Definition: InDetSecVtxTruthMatchTool.cxx:545
TrackParticleContainer.h
HepMCHelpers.h
InDetSecVtxTruthMatchUtils
Definition: InDetSecVtxTruthMatchTool.h:25
fitman.k
k
Definition: fitman.py:528
InDetSecVtxTruthMatchTool::m_trkPtCut
Gaudi::Property< float > m_trkPtCut
Definition: InDetSecVtxTruthMatchTool.h:147
InDetSecVtxTruthMatchUtils::DHadronDecay
@ DHadronDecay
Definition: InDetSecVtxTruthMatchTool.h:59