ATLAS Offline Software
TruthBornLeptonCollectionMaker.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3 */
4 
6 // TruthBornLeptonCollectionMaker.cxx
7 // Makes a special collection of Born leptons
8 
9 // R/W/D handles
10 #include "StoreGate/ReadHandle.h"
11 #include "StoreGate/WriteHandle.h"
13 // My own header file
15 // EDM includes for the particles we need
18 // To look up which generator is being used
19 #include "StoreGate/StoreGateSvc.h"
22 // STL includes
23 #include <string>
25 
26 // Constructor
28  const std::string& n,
29  const IInterface* p)
30  : AthAlgTool(t,n,p)
31  , m_metaStore( "MetaDataStore", n )
32 {
33  declareInterface<DerivationFramework::IAugmentationTool>(this);
34  declareProperty( "MetaDataStore", m_metaStore );
35 }
36 
37 // Destructor
39 }
40 
41 // Athena initialize and finalize
43 {
44  ATH_MSG_VERBOSE("initialize() ...");
45 
46  // Input truth particles
47  ATH_CHECK( m_particlesKey.initialize() );
48  ATH_MSG_INFO("Using " << m_particlesKey.key() << " as the input truth container key");
49 
50  // Output truth particles
51  if (m_collectionName.empty()) {
52  ATH_MSG_FATAL("No key provided for the new truth particle collection");
53  return StatusCode::FAILURE;
54  } else {ATH_MSG_INFO("New truth particle collection key: " << m_collectionName.key() );}
55  ATH_CHECK( m_collectionName.initialize());
56 
57  // Decoration keys
58  m_originDecoratorKey = m_collectionName.key() + ".classifierParticleOrigin";
59  ATH_CHECK(m_originDecoratorKey.initialize());
60  m_typeDecoratorKey = m_collectionName.key() + ".classifierParticleType";
61  ATH_CHECK(m_typeDecoratorKey.initialize());
62  m_outcomeDecoratorKey = m_collectionName.key() + ".classifierParticleOutCome";
63  ATH_CHECK(m_outcomeDecoratorKey.initialize());
64  m_classificationDecoratorKey = m_collectionName.key() + ".Classification";
65  ATH_CHECK(m_classificationDecoratorKey.initialize());
66 
67  // TODO: needs to be made MT-friendly
68  ATH_CHECK( m_metaStore.retrieve() );
69 
70  return StatusCode::SUCCESS;
71 }
72 
73 // Selection and collection creation
75 {
76  // Event context
77  const EventContext& ctx = Gaudi::Hive::currentContext();
78 
79  // Set up for some metadata handling
80  static const bool is_sherpa = [this]() {
81  bool is_sherpa = false;
82  // TODO: needs to be made MT-friendly
83  if (m_metaStore->contains<xAOD::TruthMetaDataContainer>("TruthMetaData")){
84  // Note that I'd like to get this out of metadata in general, but it seems that the
85  // metadata isn't fully available in initialize, and since this is a const function
86  // I can only do the retrieve every event, rather than lazy-initializing, since this
87  // metadata ought not change during a run
88  const xAOD::TruthMetaDataContainer* truthMetaData(nullptr);
89  // Shamelessly stolen from the file meta data tool
90 
91  if (m_metaStore->retrieve(truthMetaData).isSuccess() && !truthMetaData->empty()){
92  // Let's just be super sure...
93  const std::string gens = truthMetaData->at(0)->generators();
94  is_sherpa = (gens.find("sherpa")==std::string::npos &&
95  gens.find("Sherpa")==std::string::npos &&
96  gens.find("SHERPA")==std::string::npos) ? false : true;
97  } // Seems to be the only sure way...
98  else {
99  ATH_MSG_WARNING("Found xAODTruthMetaDataContainer empty! Configuring to be NOT Sherpa.");
100  }
101  ATH_MSG_INFO("From metadata configured: Sherpa? " << is_sherpa);
102  }
103  else {
104  ATH_MSG_WARNING("Could not find metadata container in storegate; assuming NOT Sherpa");
105  }
106  return is_sherpa;
107  }();
108 
109  // Retrieve truth collections
110  SG::ReadHandle<xAOD::TruthParticleContainer> truthParticles(m_particlesKey,ctx);
111  if (!truthParticles.isValid()) {
112  ATH_MSG_ERROR("Couldn't retrieve TruthParticle collection with name " << m_particlesKey);
113  return StatusCode::FAILURE;
114  }
115 
116  // Create the new particle containers and WriteHandles
117  SG::WriteHandle<xAOD::TruthParticleContainer> newParticlesWriteHandle(m_collectionName, ctx);
118  ATH_CHECK(newParticlesWriteHandle.record(std::make_unique<xAOD::TruthParticleContainer>(),
119  std::make_unique<xAOD::TruthParticleAuxContainer>()));
120  ATH_MSG_DEBUG( "Recorded new TruthParticleContainer with key: " << (m_collectionName.key()));
121 
122  // Set up decorators
123  SG::WriteDecorHandle<xAOD::TruthParticleContainer, unsigned int > originDecorator(m_originDecoratorKey, ctx);
124  SG::WriteDecorHandle<xAOD::TruthParticleContainer, unsigned int > typeDecorator(m_typeDecoratorKey, ctx);
125  SG::WriteDecorHandle<xAOD::TruthParticleContainer, unsigned int > outcomeDecorator(m_outcomeDecoratorKey, ctx);
126  SG::WriteDecorHandle<xAOD::TruthParticleContainer, unsigned int > classificationDecorator(m_classificationDecoratorKey, ctx);
127 
128  static const SG::ConstAccessor<unsigned int> classifierParticleTypeAcc("classifierParticleType");
129  static const SG::ConstAccessor<unsigned int> classifierParticleOriginAcc("classifierParticleOrigin");
130  static const SG::ConstAccessor<unsigned int> classifierParticleOutComeAcc("classifierParticleOutCome");
131  static const SG::ConstAccessor<unsigned int> ClassificationAcc("Classification");
132 
133  // add relevant particles to new collection
134  int sherpLepParentUniqueID = HepMC::UNDEFINED_ID;
135  for (unsigned int i=0; i<truthParticles->size(); ++i) {
136  // Grab the particle
137  const xAOD::TruthParticle* theParticle = (*truthParticles)[i];
138  if (!theParticle) continue; // Protection against null pointers
139  if (!theParticle->isLepton()) continue; // Only include leptons!
140 
141  if (is_sherpa > 0) {
142  // For Sherpa, skip is not status 11
143  if (theParticle->status() != 11) continue;
144  // Sherpa may have two sets of status == 11 leptons. Here we take the first set.
145  // To do so, we check the first status == 11 leptons,
146  // check that it has a child a parent barecode corresponding the the lepton's uniqueID
147  // If so, then save this parent uniqueID and skip all status 11 leptons with this parent uniqueID.
148 
149  if (sherpLepParentUniqueID == HepMC::UNDEFINED_ID) {
150  // Do test on first status 11 lepton
151  const xAOD::TruthParticle* thePartchild = theParticle->child();
152  if (thePartchild) {
153  int cparentUniqueID = (thePartchild->parent()) ? HepMC::uniqueID(thePartchild->parent()) : HepMC::UNDEFINED_ID;
154  if (cparentUniqueID == HepMC::uniqueID(theParticle)) {
155  sherpLepParentUniqueID = cparentUniqueID;
156  }
157  }
158  }
159  int puniqueID = (theParticle->parent()) ? HepMC::uniqueID(theParticle->parent()) : HepMC::UNDEFINED_ID;
160  if (sherpLepParentUniqueID > 0 && sherpLepParentUniqueID == puniqueID) continue;
161  } else if (is_sherpa == 0) {
162  // Some generators, look for leptons coming from vertices with other leptons
163  bool has_status_n3=false, has_status_3=false, has_V=false;
164  if (!MC::isPhysical(theParticle)){
165  // Look for other leptons in the production vertex... carefully
166  if (theParticle->hasProdVtx()){
167  const xAOD::TruthVertex * prod = theParticle->prodVtx();
168  for (size_t p=0;p<prod->nOutgoingParticles();++p){
169  if (prod->outgoingParticle(p) &&
170  prod->outgoingParticle(p)->isLepton()){
171  has_status_n3 = has_status_n3 || MC::isPhysical(prod->outgoingParticle(p));
172  has_status_3 = has_status_3 || MC::isPhysical(prod->outgoingParticle(p));
173  }
174  } // Loop over particles from the same production vertex
175  for (size_t p=0;p<prod->nIncomingParticles();++p){
176  // See if there was a boson going *into* the vertex
177  if (prod->incomingParticle(p) &&
178  (prod->incomingParticle(p)->isZ() || prod->incomingParticle(p)->isW() || prod->incomingParticle(p)->isHiggs()) ){
179  has_V=true;
180  break;
181  } // Found a vector boson
182  } // Loop over particles going into the same production vertex
183  } // Doesn't have a production vertex
184  }
185 
186  // Now we have all the information for the special case of V->l(born) l(bare) l(born) l(bare)
187  if ( !(has_status_3 && has_status_n3 && has_V && !MC::isPhysical(theParticle)) &&
188  theParticle->status()!=23){
189  // If not a special case, deal with the standard: has a boson parent, is a lepton, and has a descendent that is a bare lepton
190  if (!theParticle->parent()) continue;
191  if (!theParticle->parent()->isZ() && !theParticle->parent()->isW() && !theParticle->parent()->isHiggs()) continue;
192  if (!hasBareDescendent( theParticle ) ) continue;
193  }
194  } // End of treatment for generators that are not Sherpa
195 
196  // Add this particle to the new collection
197  xAOD::TruthParticle* xTruthParticle = new xAOD::TruthParticle();
198  newParticlesWriteHandle->push_back( xTruthParticle );
199  // Fill with numerical content
200  *xTruthParticle=*theParticle;
201  // Copy over the decorations if they are available
202  typeDecorator(*xTruthParticle) = classifierParticleTypeAcc.withDefault(*theParticle, 0);
203  originDecorator(*xTruthParticle) = classifierParticleOriginAcc.withDefault(*theParticle, 0);
204  outcomeDecorator(*xTruthParticle) = classifierParticleOutComeAcc.withDefault(*theParticle, 0);
205  classificationDecorator(*xTruthParticle) = ClassificationAcc.withDefault(*theParticle, 0);
206  } // Loop over alll particles
207 
208  return StatusCode::SUCCESS;
209 }
210 
211 // Find out if a particle has a bare descendent
213 {
214  // Null pointer check
215  if (!p) return false;
216  // If we hit a bare descendent, then we're a winnner
217  if (p->isLepton() && MC::isStable(p) ) return true;
218  // Otherwise look through all the children
219  for (size_t c=0;c<p->nChildren();++c){
220  if (!p->child(c)) continue; // Null pointer protection
221  if (p->pdgId()!=p->child(c)->pdgId()) continue; // Different particle child
222  if (hasBareDescendent( p->child(c) )) return true;
223  }
224  // No luck -- this branch is a dead end
225  return false;
226 }
227 
xAOD::TruthVertex_v1::nOutgoingParticles
size_t nOutgoingParticles() const
Get the number of outgoing particles.
xAOD::TruthParticle_v1::parent
const TruthParticle_v1 * parent(size_t i=0) const
Retrieve the i-th mother (TruthParticle) of this TruthParticle.
Definition: TruthParticle_v1.cxx:131
ATH_MSG_FATAL
#define ATH_MSG_FATAL(x)
Definition: AthMsgStreamMacros.h:34
python.PerfMonSerializer.p
def p
Definition: PerfMonSerializer.py:743
ATH_MSG_INFO
#define ATH_MSG_INFO(x)
Definition: AthMsgStreamMacros.h:31
SG::ReadHandle
Definition: StoreGate/StoreGate/ReadHandle.h:70
AthCommonDataStore< AthCommonMsg< AlgTool > >::declareProperty
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T > &t)
Definition: AthCommonDataStore.h:145
TruthParticleContainer.h
DerivationFramework::TruthBornLeptonCollectionMaker::TruthBornLeptonCollectionMaker
TruthBornLeptonCollectionMaker(const std::string &t, const std::string &n, const IInterface *p)
Definition: TruthBornLeptonCollectionMaker.cxx:27
DerivationFramework::TruthBornLeptonCollectionMaker::addBranches
virtual StatusCode addBranches() const
Pass the thinning service
Definition: TruthBornLeptonCollectionMaker.cxx:74
xAOD::TruthParticle_v1::isW
bool isW() const
Check if this particle is a W boson.
SG::ConstAccessor< unsigned int >
read_hist_ntuple.t
t
Definition: read_hist_ntuple.py:5
ATH_MSG_VERBOSE
#define ATH_MSG_VERBOSE(x)
Definition: AthMsgStreamMacros.h:28
TruthParticleAuxContainer.h
xAOD::TruthParticle_v1::isZ
bool isZ() const
Check if this particle is a Z boson.
MC::isPhysical
bool isPhysical(const T &p)
Definition: HepMCHelpers.h:32
WriteHandle.h
Handle class for recording to StoreGate.
xAOD::TruthParticle_v1::isLepton
bool isLepton() const
Whether the particle is a lepton.
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: AthMsgStreamMacros.h:33
lumiFormat.i
int i
Definition: lumiFormat.py:92
beamspotman.n
n
Definition: beamspotman.py:731
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
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:41
SG::WriteDecorHandle
Handle class for adding a decoration to an object.
Definition: StoreGate/StoreGate/WriteDecorHandle.h:99
WriteDecorHandle.h
Handle class for adding a decoration to an object.
DerivationFramework::TruthBornLeptonCollectionMaker::initialize
StatusCode initialize()
Definition: TruthBornLeptonCollectionMaker.cxx:42
xAOD::TruthParticle
TruthParticle_v1 TruthParticle
Typedef to implementation.
Definition: Event/xAOD/xAODTruth/xAODTruth/TruthParticle.h:15
xAOD::TruthParticle_v1::hasProdVtx
bool hasProdVtx() const
Check for a production vertex on this particle.
Definition: TruthParticle_v1.cxx:74
HepMC::uniqueID
int uniqueID(const T &p)
Definition: MagicNumbers.h:113
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
xAOD::TruthVertex_v1::incomingParticle
const TruthParticle_v1 * incomingParticle(size_t index) const
Get one of the incoming particles.
Definition: TruthVertex_v1.cxx:71
DataVector
Derived DataVector<T>.
Definition: DataVector.h:581
SG::ReadHandle::isValid
virtual bool isValid() override final
Can the handle be successfully dereferenced?
HepMC::UNDEFINED_ID
constexpr int UNDEFINED_ID
Definition: MagicNumbers.h:55
xAOD::TruthParticle_v1::prodVtx
const TruthVertex_v1 * prodVtx() const
The production vertex of this particle.
Definition: TruthParticle_v1.cxx:80
xAOD::TruthVertex_v1
Class describing a truth vertex in the MC record.
Definition: TruthVertex_v1.h:41
DataVector::push_back
value_type push_back(value_type pElem)
Add an element to the end of the collection.
TruthBornLeptonCollectionMaker.h
SG::WriteHandle
Definition: StoreGate/StoreGate/WriteHandle.h:76
xAOD::TruthParticle_v1::status
int status() const
Status code.
MC::isStable
bool isStable(const T &p)
Definition: HepMCHelpers.h:30
SG::WriteHandle::record
StatusCode record(std::unique_ptr< T > data)
Record a const object to the store.
xAOD::TruthParticle_v1::isHiggs
bool isHiggs() const
Check if this particle is a Higgs boson.
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
xAOD::TruthVertex_v1::nIncomingParticles
size_t nIncomingParticles() const
Get the number of incoming particles.
Definition: TruthVertex_v1.cxx:49
xAOD::TruthParticle_v1::child
const TruthParticle_v1 * child(size_t i=0) const
Retrieve the i-th mother (TruthParticle) of this TruthParticle.
Definition: TruthParticle_v1.cxx:149
DerivationFramework::TruthBornLeptonCollectionMaker::hasBareDescendent
bool hasBareDescendent(const xAOD::TruthParticle *p) const
Helper function for finding bare descendents of born leptons.
Definition: TruthBornLeptonCollectionMaker.cxx:212
DerivationFramework::TruthBornLeptonCollectionMaker::m_metaStore
ServiceHandle< StoreGateSvc > m_metaStore
Handle on the metadata store for init.
Definition: TruthBornLeptonCollectionMaker.h:55
DataVector::at
const T * at(size_type n) const
Access an element, as an rvalue.
ConstAccessor.h
Helper class to provide constant type-safe access to aux data.
ReadHandle.h
Handle class for reading from StoreGate.
DerivationFramework::TruthBornLeptonCollectionMaker::~TruthBornLeptonCollectionMaker
~TruthBornLeptonCollectionMaker()
Definition: TruthBornLeptonCollectionMaker.cxx:38
AthAlgTool
Definition: AthAlgTool.h:26
TruthMetaDataContainer.h
StoreGateSvc.h
python.compressB64.c
def c
Definition: compressB64.py:93
DataVector::size
size_type size() const noexcept
Returns the number of elements in the collection.
xAOD::TruthVertex_v1::outgoingParticle
const TruthParticle_v1 * outgoingParticle(size_t index) const
Get one of the outgoing particles.
Definition: TruthVertex_v1.cxx:121
DataVector::empty
bool empty() const noexcept
Returns true if the collection is empty.
HepMCHelpers.h
SG::ConstAccessor::withDefault
const_reference_type withDefault(const ELT &e, const T &deflt) const
Fetch the variable for one element, as a const reference, with a default.