ATLAS Offline Software
TruthDressingTool.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3 */
4 
6 // TruthDressingTool.cxx
7 // Author: Kevin Finelli (kevin.finelli@cern.ch)
8 // Create dressed (i.e. including FSR photons) 4-vectors of truth objects
9 
17 
19 #include "TruthUtils/AtlasPID.h"
20 
21 #include "fastjet/PseudoJet.hh"
22 #include "fastjet/ClusterSequence.hh"
23 #include <vector>
24 #include <string>
25 #include <algorithm>
26 #include <memory>
27 namespace {
28  static const SG::ConstAccessor<unsigned int> acc_origin("Classification");
29 }
30 
31 // Athena initialize
33 {
34  // Initialise handle keys
37 
48 
50 
51  // ensure we are not mixing truth taus with other truth particles
52  if (m_listOfPIDs.size() > 1) {
53  if (std::find(m_listOfPIDs.begin(), m_listOfPIDs.end(), MC::TAU) != m_listOfPIDs.end()) {
54  ATH_MSG_ERROR("Truth taus must be dressed separately from other truth particles");
55  return StatusCode::FAILURE;
56  }
57  }
58 
59  return StatusCode::SUCCESS;
60 }
61 
62 // Function to do dressing, implements interface in IAugmentationTool
64 {
65  // Get the event context
66 
67  // Retrieve the truth collections
68  SG::ReadHandle<xAOD::TruthParticleContainer> truthParticles(m_particlesKey,ctx);
69  if (!truthParticles.isValid()) {
70  ATH_MSG_ERROR("Couldn't retrieve TruthParticle collection with name " << m_particlesKey);
71  return StatusCode::FAILURE;
72  }
73 
74  SG::ReadHandle<xAOD::TruthParticleContainer> dressTruthParticles(m_dressParticlesKey,ctx);
75  if (!dressTruthParticles.isValid()) {
76  ATH_MSG_ERROR("Couldn't retrieve TruthParticle collection with name " << m_dressParticlesKey);
77  return StatusCode::FAILURE;
78  }
79 
80  // Decorators
81  SG::WriteDecorHandle< xAOD::TruthParticleContainer,float > decorator_e(m_decorator_eKey, ctx);
82  SG::WriteDecorHandle< xAOD::TruthParticleContainer,float > decorator_pt(m_decorator_ptKey, ctx);
83  SG::WriteDecorHandle< xAOD::TruthParticleContainer,float > decorator_eta(m_decorator_etaKey, ctx);
84  SG::WriteDecorHandle< xAOD::TruthParticleContainer,float > decorator_phi(m_decorator_phiKey, ctx);
85  // for truth taus, use 'vis' in the decoration name to avoid prompt/visible tau momentum ambiguity
86  // use (pt,eta,phi,m) for taus, for consistency with other TauAnalysisTools decorations
87  SG::WriteDecorHandle< xAOD::TruthParticleContainer,float > decorator_pt_vis(m_decorator_pt_visKey, ctx);
88  SG::WriteDecorHandle< xAOD::TruthParticleContainer,float > decorator_eta_vis(m_decorator_eta_visKey, ctx);
89  SG::WriteDecorHandle< xAOD::TruthParticleContainer,float > decorator_phi_vis(m_decorator_phi_visKey, ctx);
90  SG::WriteDecorHandle< xAOD::TruthParticleContainer,float > decorator_m_vis(m_decorator_m_visKey, ctx);
91  SG::WriteDecorHandle< xAOD::TruthParticleContainer,int > decorator_nphoton(m_decorator_nphotonKey, ctx);
92  SG::WriteDecorHandle< xAOD::TruthParticleContainer,char > dressDec(m_decorationKey, ctx);
93  // If we want to decorate, then we need to decorate everything with false to begin with
94  if (m_decoratePhotons){
95  for (const auto * particle : *truthParticles){
96  dressDec(*particle) = 0;
97  }
98  } // We are using the decoration
99 
100  // accessors for truth tau visible momentum
101  static const SG::ConstAccessor<double> pt_visAcc("pt_vis");
102  static const SG::ConstAccessor<double> eta_visAcc("eta_vis");
103  static const SG::ConstAccessor<double> phi_visAcc("phi_vis");
104  static const SG::ConstAccessor<double> mvisAcc("m_vis");
105 
106  //get struct of helper functions
108 
109  std::vector<const xAOD::TruthParticle*> listOfParticlesToDress;
110  std::vector<xAOD::TruthParticle::FourMom_t> listOfDressedP4;
111  std::vector<xAOD::TruthParticle::FourMom_t> listOfBareP4;
112 
113  if (m_listOfPIDs.size()==1 && std::abs(m_listOfPIDs[0])==MC::TAU) {
114  // when dressing truth taus, it is assumed that the truth tau container has been built beforehand and is used as input
115  for (auto *pItr : *dressTruthParticles) {
116  if (!pItr->isTau()) {
117  ATH_MSG_ERROR("Input particles should be truth taus.");
118  return StatusCode::FAILURE;
119  }
120  if (!pt_visAcc.isAvailable(*pItr) || !eta_visAcc.isAvailable(*pItr) || !phi_visAcc.isAvailable(*pItr) || !mvisAcc.isAvailable(*pItr)) {
121  ATH_MSG_ERROR("Visible momentum not available for truth taus, cannot perform dressing!");
122  return StatusCode::FAILURE;
123  }
124 
125  listOfParticlesToDress.push_back(pItr);
126 
127  // we dresss the visible 4-momentum
129  bare_part.SetPtEtaPhiM(pt_visAcc(*pItr), eta_visAcc(*pItr), phi_visAcc(*pItr), mvisAcc(*pItr));
130  listOfDressedP4.push_back(bare_part);
131  }
132  // in the cone-based approach, make a copy of bare P4 to avoid recomputing it
133  if (!m_useAntiKt) {
134  listOfBareP4 = listOfDressedP4;
135  }
136  }
137  else {
138  // non-prompt particles are still included here to ensure all particles
139  // will get the decoration; however further down only the prompt particles
140  // are actually dressed depending on the value of m_useLeptonsFromHadrons
141  decayHelper.constructListOfFinalParticles(dressTruthParticles.ptr(), listOfParticlesToDress, m_listOfPIDs, true);
142 
143  for (const auto* part : listOfParticlesToDress) {
144  listOfDressedP4.push_back(part->p4());
145  }
146  }
147 
148  std::vector<int> dressedParticlesNPhot(listOfParticlesToDress.size(), 0);
149 
150  //fill the photon list
151  std::vector<const xAOD::TruthParticle*> photonsFSRList;
152  std::vector<int> photonPID{22};
153  const bool pass = decayHelper.constructListOfFinalParticles(truthParticles.ptr(), photonsFSRList,
154  photonPID, m_usePhotonsFromHadrons);
155  if (!pass) {
156  ATH_MSG_WARNING("Cannot construct the list of final state particles "<<m_truthClassKey.fullKey());
157  }
158 
159  // Do dR-based photon dressing (default)
160  if (!m_useAntiKt){
161  //loop over photons, uniquely associate each to nearest bare particle
162  for (const auto* phot : photonsFSRList) {
163  double dRmin = m_coneSize;
164  int idx = -1;
165 
166  for (size_t i = 0; i < listOfParticlesToDress.size(); ++i) {
167  if (!m_useLeptonsFromHadrons) {
168  if (!acc_origin.isAvailable(*listOfParticlesToDress[i])) {
169  ATH_MSG_WARNING("MCTruthClassifier "<<m_truthClassKey.fullKey() <<" not available, cannot apply notFromHadron veto!");
170  }
171  unsigned int result = acc_origin(*listOfParticlesToDress[i]);
172  const bool isPrompt = MCTruthPartClassifier::isPrompt(result, true);
173  if (!isPrompt) continue;
174  }
176  if (listOfParticlesToDress[i]->isTau()) {
177  bare_part = listOfBareP4[i];
178  }
179  else {
180  bare_part = listOfParticlesToDress[i]->p4();
181  }
182 
183  double dR = bare_part.DeltaR(phot->p4());
184  if (dR < dRmin) {
185  dRmin = dR;
186  idx = i;
187  }
188  }
189 
190  if(idx > -1) {
191  listOfDressedP4[idx] += phot->p4();
192  dressedParticlesNPhot[idx]++;
193  if (m_decoratePhotons){
194  dressDec(*phot) = 1;
195  }
196  }
197  }
198 
199  //loop over particles and add decorations
200  for (size_t i = 0; i < listOfParticlesToDress.size(); ++i) {
201  const xAOD::TruthParticle* part = listOfParticlesToDress[i];
202  const xAOD::TruthParticle::FourMom_t& dressedVec = listOfDressedP4[i];
203 
204  if(part->isTau()) {
205  decorator_pt_vis(*part) = dressedVec.Pt();
206  decorator_eta_vis(*part) = dressedVec.Eta();
207  decorator_phi_vis(*part) = dressedVec.Phi();
208  decorator_m_vis(*part) = dressedVec.M();
209  }
210  else {
211  decorator_e(*part) = dressedVec.E();
212  decorator_pt(*part) = dressedVec.Pt();
213  decorator_eta(*part) = dressedVec.Eta();
214  decorator_phi(*part) = dressedVec.Phi();
215  }
216  decorator_nphoton(*part) = dressedParticlesNPhot[i];
217  }
218  } // end of the dR matching part
219 
220  //build the anti-kt jet list
221  if (m_useAntiKt) {
222  std::vector<fastjet::PseudoJet> sorted_jets;
223  std::vector<fastjet::PseudoJet> fj_particles;
224  for (const auto* part : listOfParticlesToDress) {
225  if(part->isTau()) {
226  const xAOD::TruthParticle::FourMom_t& tauvis = listOfDressedP4[part->index()];
227  fj_particles.emplace_back(tauvis.Px(), tauvis.Py(), tauvis.Pz(), tauvis.E());
228  }
229  else {
230  fj_particles.emplace_back(part->px(), part->py(), part->pz(), part->e());
231  }
232 
233  fj_particles.back().set_user_index(HepMC::uniqueID(part));
234  }
235  for (const auto* part : photonsFSRList) {
236  fj_particles.emplace_back(part->px(), part->py(), part->pz(), part->e());
237  fj_particles.back().set_user_index(HepMC::uniqueID(part));
238  }
239 
240  //run the clustering
241  fastjet::JetAlgorithm alg=fastjet::antikt_algorithm;
242  const fastjet::JetDefinition jet_def(alg, m_coneSize);
243  fastjet::ClusterSequence cseq(fj_particles, jet_def);
244  sorted_jets = sorted_by_pt(cseq.inclusive_jets(0));
245  //associate clustered jets back to bare particles
246  std::vector<int> photon_uniqueIDs(50);
247  photon_uniqueIDs.clear();
248  for (const auto* part : listOfParticlesToDress) {
249  //loop over fastjet pseudojets and associate one with this particle
250  bool found=false;
251  auto pjItr=sorted_jets.begin();
252  while(!found && pjItr!=sorted_jets.end()) {
253  std::vector<fastjet::PseudoJet> constituents = pjItr->constituents();
254  for(const auto& constit : constituents) {
255  if (HepMC::uniqueID(part)==constit.user_index()) {
256 
257  // shall we count the number of photons among the pseudojet constituents
258  // to decorate leptons with the number of dressing photons found by the anti-kt algorithm?
259 
260  if(part->isTau()) {
261  decorator_pt_vis(*part) = pjItr->pt();
262  decorator_eta_vis(*part) = pjItr->pseudorapidity();
263  decorator_phi_vis(*part) = pjItr->phi_std(); //returns phi in [-pi,pi]
264  decorator_m_vis(*part) = pjItr->m();
265  }
266  else {
267  decorator_e(*part) = pjItr->e();
268  decorator_pt(*part) = pjItr->pt();
269  decorator_eta(*part) = pjItr->pseudorapidity();
270  decorator_phi(*part) = pjItr->phi_std(); //returns phi in [-pi,pi]
271  }
272  found=true;
273  break;
274  } // Found the matching unique ID
275  } // Loop over the jet constituents
276  if (found){
277  for(const auto& constit : constituents) {
278  photon_uniqueIDs.push_back(constit.user_index());
279  } // Loop over the constituents
280  } // Found one of the key leptons in this jet
281  ++pjItr;
282  }
283  if (!found) {
284  if(part->isTau()) {
285  decorator_pt_vis(*part) = 0.;
286  decorator_eta_vis(*part) = 0.;
287  decorator_phi_vis(*part) = 0.;
288  decorator_m_vis(*part) = 0.;
289  }
290  else {
291  decorator_e(*part) = 0;
292  decorator_pt(*part) = 0;
293  decorator_eta(*part) = 0;
294  decorator_phi(*part) = 0;
295  }
296  ATH_MSG_WARNING("Bare particle not found in constituents ");
297  }
298  }
299  // Check if we wanted to decorate photons used for dressing
300  if (m_decoratePhotons){
301  //loop over photons, uniquely associate each to nearest bare particle
302  for (const auto* phot : photonsFSRList ) {
303  bool found = std::find(photon_uniqueIDs.begin(), photon_uniqueIDs.end(), HepMC::uniqueID(phot)) != photon_uniqueIDs.end();
304  if (found) {
305  dressDec(*phot) = 1;
306  }
307  } // End of loop over photons
308  } // End of decoration of photons used in dressing
309  } // End of anti-kT dressing
310 
311  return StatusCode::SUCCESS;
312 }
LArG4FSStartPointFilter.part
part
Definition: LArG4FSStartPointFilter.py:21
DerivationFramework::TruthDressingTool::m_particlesKey
SG::ReadHandleKey< xAOD::TruthParticleContainer > m_particlesKey
ReadHandleKey input collection key.
Definition: TruthDressingTool.h:33
Trk::ParticleSwitcher::particle
constexpr ParticleHypothesis particle[PARTICLEHYPOTHESES]
the array of masses
Definition: ParticleHypothesis.h:79
get_generator_info.result
result
Definition: get_generator_info.py:21
find
std::string find(const std::string &s)
return a remapped string
Definition: hcg.cxx:138
SG::ReadHandle< xAOD::TruthParticleContainer >
DerivationFramework::TruthDressingTool::m_listOfPIDs
Gaudi::Property< std::vector< int > > m_listOfPIDs
Parameter: List of pdgIDs of particles to dress.
Definition: TruthDressingTool.h:73
DerivationFramework::TruthDressingTool::m_decorator_nphotonKey
SG::WriteDecorHandleKey< xAOD::TruthParticleContainer > m_decorator_nphotonKey
Definition: TruthDressingTool.h:58
DerivationFramework::TruthDressingTool::m_dressParticlesKey
SG::ReadHandleKey< xAOD::TruthParticleContainer > m_dressParticlesKey
ReadHandleKey for particles to be dressed.
Definition: TruthDressingTool.h:39
SG::ConstAccessor< unsigned int >
MCTruthClassifier.h
DerivationFramework::DecayGraphHelper::constructListOfFinalParticles
bool constructListOfFinalParticles(const xAOD::TruthParticleContainer *allParticles, std::vector< const xAOD::TruthParticle * > &selectedlist, const std::vector< int > &pdgId, bool allowFromHadron=false, bool chargedOnly=false) const
Definition: DecayGraphHelper.h:218
DerivationFramework::TruthDressingTool::addBranches
virtual StatusCode addBranches(const EventContext &ctx) const override final
Definition: TruthDressingTool.cxx:63
DecorKeyHelpers.h
Some common helper functions used by decoration handles.
DerivationFramework::TruthDressingTool::m_decorator_m_visKey
SG::WriteDecorHandleKey< xAOD::TruthParticleContainer > m_decorator_m_visKey
Definition: TruthDressingTool.h:56
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: AthMsgStreamMacros.h:33
DerivationFramework::TruthDressingTool::m_decorator_phi_visKey
SG::WriteDecorHandleKey< xAOD::TruthParticleContainer > m_decorator_phi_visKey
Definition: TruthDressingTool.h:54
jet::ClusterSequence
fastjet::ClusterSequence ClusterSequence
Definition: ClusterSequence.h:21
lumiFormat.i
int i
Definition: lumiFormat.py:85
SG::ReadDecorHandleKey::initialize
StatusCode initialize(bool used=true)
If this object is used as a property, then this should be called during the initialize phase.
DerivationFramework::TruthDressingTool::m_decorator_phiKey
SG::WriteDecorHandleKey< xAOD::TruthParticleContainer > m_decorator_phiKey
Definition: TruthDressingTool.h:48
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
xAOD::TruthParticle_v1
Class describing a truth particle in the MC record.
Definition: TruthParticle_v1.h:37
SG::WriteDecorHandle
Handle class for adding a decoration to an object.
Definition: StoreGate/StoreGate/WriteDecorHandle.h:100
WriteDecorHandle.h
Handle class for adding a decoration to an object.
HepMC::uniqueID
int uniqueID(const T &p)
Definition: MagicNumbers.h:117
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
DerivationFramework::TruthDressingTool::m_truthClassKey
SG::ReadDecorHandleKey< xAOD::TruthParticleContainer > m_truthClassKey
To ensure that the algorithm is scheduled after the truth classifier.
Definition: TruthDressingTool.h:60
SG::VarHandleKey::initialize
StatusCode initialize(bool used=true)
If this object is used as a property, then this should be called during the initialize phase.
Definition: AthToolSupport/AsgDataHandles/Root/VarHandleKey.cxx:103
TruthDressingTool.h
SG::ReadHandle::isValid
virtual bool isValid() override final
Can the handle be successfully dereferenced?
isTau
bool isTau(const T &p)
Definition: AtlasPID.h:208
DerivationFramework::TruthDressingTool::initialize
virtual StatusCode initialize() override final
Definition: TruthDressingTool.cxx:32
DerivationFramework::TruthDressingTool::m_decorator_eta_visKey
SG::WriteDecorHandleKey< xAOD::TruthParticleContainer > m_decorator_eta_visKey
Definition: TruthDressingTool.h:52
MagicNumbers.h
DerivationFramework::TruthDressingTool::m_decorator_etaKey
SG::WriteDecorHandleKey< xAOD::TruthParticleContainer > m_decorator_etaKey
Definition: TruthDressingTool.h:46
DerivationFramework::DecayGraphHelper
Definition: DecayGraphHelper.h:26
RegSelToolConfig.alg
alg
Definition: RegSelToolConfig.py:332
checkTriggerxAOD.found
found
Definition: checkTriggerxAOD.py:328
xAOD::JetAlgorithmType::antikt_algorithm
@ antikt_algorithm
Definition: JetContainerInfo.h:33
SG::ReadHandle::ptr
const_pointer_type ptr()
Dereference the pointer.
DerivationFramework::TruthDressingTool::m_decorationKey
SG::WriteDecorHandleKey< xAOD::TruthParticleContainer > m_decorationKey
WriteDecorHandleKeys for decorations for particlesKey.
Definition: TruthDressingTool.h:36
DerivationFramework::TruthDressingTool::m_decorator_ptKey
SG::WriteDecorHandleKey< xAOD::TruthParticleContainer > m_decorator_ptKey
Definition: TruthDressingTool.h:44
DerivationFramework::TruthDressingTool::m_decorator_eKey
SG::WriteDecorHandleKey< xAOD::TruthParticleContainer > m_decorator_eKey
Definition: TruthDressingTool.h:42
SG::WriteDecorHandleKey::initialize
StatusCode initialize(bool used=true)
If this object is used as a property, then this should be called during the initialize phase.
MCTruthPartClassifier::isPrompt
int isPrompt(const unsigned int classify, bool allow_prompt_tau_decays=true)
Definition: TruthClassifiers.h:180
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
LArNewCalib_DelayDump_OFC_Cali.idx
idx
Definition: LArNewCalib_DelayDump_OFC_Cali.py:69
DerivationFramework::TruthDressingTool::m_decorator_pt_visKey
SG::WriteDecorHandleKey< xAOD::TruthParticleContainer > m_decorator_pt_visKey
Definition: TruthDressingTool.h:50
ReadDecorHandle.h
Handle class for reading a decoration on an object.
SG::ConstAccessor::isAvailable
bool isAvailable(const ELT &e) const
Test to see if this variable exists in the store.
ConstAccessor.h
Helper class to provide constant type-safe access to aux data.
TruthEventContainer.h
SG::AllowEmpty
@ AllowEmpty
Definition: StoreGate/StoreGate/VarHandleKey.h:27
AtlasPID.h
xAOD::TruthParticle_v1::FourMom_t
IParticle::FourMom_t FourMom_t
Definition of the 4-momentum type.
Definition: TruthParticle_v1.h:142