ATLAS Offline Software
TruthPreselectionTool.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3 */
4 
5 // ISF_Algs includes
7 #include "AtlasHepMC/HeavyIon.h"
8 
10 // Public methods:
12 
13 // Constructors
15 ISF::TruthPreselectionTool::TruthPreselectionTool( const std::string& t, const std::string& n, const IInterface* p ) :
16  base_class( t, n, p )
17 {
18 }
19 
20 // Athena Algorithm's Hooks
23 {
24  ATH_MSG_VERBOSE ( "Initializing TruthPreselectionTool Algorithm" );
25 
26  if (!m_genParticleFilters.empty()) ATH_CHECK(m_genParticleFilters.retrieve());
27  ATH_CHECK(m_quasiStableFilter.retrieve());
28 
29  // intialziation successful
30  return StatusCode::SUCCESS;
31 }
32 
34 #ifdef HEPMC3
35 bool ISF::TruthPreselectionTool::passesFilters(HepMC::ConstGenParticlePtr& part, const ToolHandleArray<IGenParticleFilter>& filters) const
36 #else
37 bool ISF::TruthPreselectionTool::passesFilters(HepMC::ConstGenParticlePtr part, const ToolHandleArray<IGenParticleFilter>& filters) const
38 #endif
39 {
40  // TODO: implement this as a std::find_if with a lambda function
41  for ( const auto& filter : filters ) {
42  // determine if the particle passes current filter
43 #ifdef HEPMC3
44  bool passFilter = filter->pass(part);
45 #else
46  bool passFilter = filter->pass(*part);
47 #endif
48  ATH_MSG_VERBOSE("Filter '" << filter.typeAndName() << "' returned: "
49  << (passFilter ? "true, will keep particle."
50  : "false, will remove particle."));
51 
52  if (!passFilter) return false;
53  }
54 
55  return true;
56 }
57 
58 #ifdef HEPMC3
60 #else
62 #endif
63 {
64  bool b_sim = false;
65 #ifdef HEPMC3
66  if (m_quasiStableFilter->pass(part)) {
67  b_sim = passesFilters(part, m_genParticleFilters);
68  }
69 #else
70  if (m_quasiStableFilter->pass(*part)) {
71  b_sim = passesFilters(part, m_genParticleFilters);
72  }
73 #endif
74  return b_sim;
75 }
76 
77 #ifdef HEPMC3
79 #else
81 #endif
82 {
83  // TODO: investigate making this more efficient
84 #ifdef HEPMC3
85  // Recursively loop over ancestral particles looking for a quasi-stable particle
86  if (!part->production_vertex() || part->production_vertex()->particles_in().empty()) { return false; }
87  for ( auto ancestor: part->production_vertex()->particles_in() ) {
88  // Check ancestor particle for Attribute
89  if ( ancestor->attribute<HepMC3::IntAttribute>("ShadowParticleId") ) { return true; }
90 #else
91  if (!part->production_vertex() || part->production_vertex()->particles_in_size()==0) { return false; }
92  // Recursively loop over ancestral particles looking for a quasi-stable particle
93  auto firstParent = part->production_vertex()->particles_begin(HepMC::parents);
94  auto lastParent = part->production_vertex()->particles_end(HepMC::parents);
95  for (auto pitr = firstParent; pitr != lastParent; ++pitr ) {
96  HepMC::ConstGenParticlePtr ancestor = *pitr;
97  if (identifiedQuasiStableParticleForSim(ancestor)) { return true; }
98 #endif
99  if (hasQuasiStableAncestorParticle(ancestor)) { return true; }
100  }
101  return false;
102 }
103 
104 #ifdef HEPMC3
106 {
107  // All outgoing particles have already been removed.
108  if ( vtx->particles_out().empty() ) { return true; }
109  return false;
110 }
111 #else
113 {
114  // Recursively loop over ancestral particles looking for a quasi-stable particle
115  auto firstParent = vtx->particles_in_const_begin();
116  auto lastParent = vtx->particles_in_const_end();
117  for (auto pitr = firstParent; pitr != lastParent; ++pitr ) {
118  HepMC::ConstGenParticlePtr ancestor = *pitr;
119  if (identifiedQuasiStableParticleForSim(ancestor)) { return true; }
120  if (hasQuasiStableAncestorParticle(ancestor)) { return true; }
121  }
122  return false;
123 }
124 #endif
125 
126 std::unique_ptr<HepMC::GenEvent> ISF::TruthPreselectionTool::filterGenEvent(const HepMC::GenEvent& inputEvent) const {
127 #ifdef HEPMC3
128  std::unique_ptr<HepMC::GenEvent> outputEvent = std::make_unique<HepMC::GenEvent>(inputEvent);
131  if (inputEvent.run_info()) {
132  outputEvent->set_run_info(std::make_shared<HepMC3::GenRunInfo>(*(inputEvent.run_info().get())));
133  }
134  if (inputEvent.heavy_ion()) {
135  outputEvent->set_heavy_ion(std::make_shared<HepMC::GenHeavyIon>(*(inputEvent.heavy_ion())));
136  }
137  HepMC::fillBarcodesAttribute(outputEvent.get());
138 
139  // First loop: flag the particles which should be passed to simulation
140  for (auto& particle: outputEvent->particles()) {
142  if (passesFilters(cparticle, m_genParticleFilters)) {
143  // Particle to be simulated
144  const int shadowId = particle->id();
145  // Version 1 Use the Id
146  particle->add_attribute("ShadowParticleId",
147  std::make_shared<HepMC3::IntAttribute>(shadowId));
148  // Version 2 Directly save the ConstGenParticlePtr - needs to link to a version of the GenEvent after zero-lifetime positioner as been applied.
149  // HepMC::ConstGenParticlePtr& shadow = inputEvent.particles().at(shadowId);
150  // particle->add_attribute("ShadowParticle",
151  // std::make_shared<HepMC::ShadowParticle>(particle));
152  }
153  }
154  // Second loop(s): flag particles (and vertices) to be removed (i.e. those
155  // with ancestor particle flagged to be passed to simulation).
156  for (;;) {
157  std::vector<HepMC::GenParticlePtr> p_to_remove;
158  std::vector<HepMC::GenVertexPtr> v_to_remove;
159  for (auto& particle: outputEvent->particles()) {
161  if (hasQuasiStableAncestorParticle(cparticle)) {
162  p_to_remove.push_back(particle);
163  }
164  }
165  for (auto& particle: p_to_remove) outputEvent->remove_particle(particle);
166  for (auto& vertex: outputEvent->vertices()) {
168  if (isPostQuasiStableParticleVertex(cvertex)) {
169  v_to_remove.push_back(vertex);
170  }
171  }
172  for (auto& vertex: v_to_remove) outputEvent->remove_vertex(vertex);
173  if (p_to_remove.empty() && v_to_remove.empty()) break;
174  }
175 #else
176 
177  std::unique_ptr<HepMC::GenEvent> outputEvent = std::make_unique<HepMC::GenEvent>(inputEvent.signal_process_id(),
178  inputEvent.event_number());
179 
180  outputEvent->set_mpi ( inputEvent.mpi() );
181  outputEvent->set_event_scale ( inputEvent.event_scale() );
182  outputEvent->set_alphaQCD ( inputEvent.alphaQCD() );
183  outputEvent->set_alphaQED ( inputEvent.alphaQED() );
184  if ( inputEvent.cross_section() ) {
185  outputEvent->set_cross_section ( *inputEvent.cross_section());
186  }
187  if (inputEvent.heavy_ion()) {
188  outputEvent->set_heavy_ion(*(inputEvent.heavy_ion()));
189  }
190  if (inputEvent.pdf_info()) {
191  outputEvent->set_pdf_info(*(inputEvent.pdf_info()));
192  }
193  outputEvent->define_units( inputEvent.momentum_unit(), inputEvent.length_unit() );
194 
195  // 1. create a NEW copy of all vertices from inputEvent
196  // taking care to map new vertices onto the vertices being copied
197  // and add these new vertices to this event.
198  // We do not use GenVertex::operator= because that would copy
199  // the attached particles as well.
200  std::map<const HepMC::GenVertex*,HepMC::GenVertex*> inputEvtVtxToOutputEvtVtx;
201  HepMC::GenEvent::vertex_const_iterator currentVertexIter(inputEvent.vertices_begin());
202  const HepMC::GenEvent::vertex_const_iterator endOfCurrentListOfVertices(inputEvent.vertices_end());
203  ATH_MSG_VERBOSE( "Starting a vertex loop ... " );
204  for (; currentVertexIter != endOfCurrentListOfVertices; ++currentVertexIter) {
205  const HepMC::GenVertex *pCurrentVertex(*currentVertexIter);
206  if (isPostQuasiStableParticleVertex(pCurrentVertex)) {
207  continue; // skip vertices created by the simulation
208  }
209  std::unique_ptr<HepMC::GenVertex> copyOfGenVertex =std::make_unique<HepMC::GenVertex>(pCurrentVertex->position(), pCurrentVertex->id(), pCurrentVertex->weights() );
210  copyOfGenVertex->suggest_barcode( HepMC::barcode(pCurrentVertex) );
211  inputEvtVtxToOutputEvtVtx[pCurrentVertex] = copyOfGenVertex.get();
212  outputEvent->add_vertex( copyOfGenVertex.release() );
213  } //vertex loop
214 
215  // 2. copy the signal process vertex info.
216  if ( inputEvent.signal_process_vertex() ) {
217  outputEvent->set_signal_process_vertex( inputEvtVtxToOutputEvtVtx[inputEvent.signal_process_vertex()] );
218  }
219  else {
220  outputEvent->set_signal_process_vertex( nullptr );
221  }
222  //
223  // 3. create a NEW copy of all particles from inputEvent
224  // taking care to attach them to the appropriate vertex
227  for ( HepMC::GenEvent::particle_const_iterator particleIter = inputEvent.particles_begin();
228  particleIter != inputEvent.particles_end(); ++particleIter ) {
229  const HepMC::GenParticle* currentParticle = *particleIter;
230  if (hasQuasiStableAncestorParticle(currentParticle)) { // TODO Consider making the threshold for this check configurable.
231  continue; // skip particles created by the simulation
232  }
233  std::unique_ptr<HepMC::GenParticle> copyOfGenParticle = std::make_unique<HepMC::GenParticle>(*currentParticle);
234  const bool isBeamParticle1(currentParticle == inputEvent.beam_particles().first);
235  const bool isBeamParticle2(currentParticle == inputEvent.beam_particles().second);
236  // There may (will) be particles which had end vertices added by
237  // the simulation (inputEvent). Those vertices will not be copied
238  // to the outputEvent, so we should not try to use them here.
239  const bool shouldAddProdVertex(currentParticle->production_vertex() && inputEvtVtxToOutputEvtVtx[ currentParticle->production_vertex() ]);
240  const bool shouldAddEndVertex(currentParticle->end_vertex() && inputEvtVtxToOutputEvtVtx[ currentParticle->end_vertex() ]);
241  if ( isBeamParticle1 || isBeamParticle2 || shouldAddProdVertex || shouldAddEndVertex ) {
242  HepMC::GenParticle* particleCopy = copyOfGenParticle.release();
243  if ( isBeamParticle1 ) {
244  beam1 = particleCopy;
245  }
246  if ( isBeamParticle2 ) {
247  beam2 = particleCopy;
248  }
249  if ( shouldAddProdVertex || shouldAddEndVertex ) {
250  if ( shouldAddEndVertex ) {
251  inputEvtVtxToOutputEvtVtx[ currentParticle->end_vertex() ]->
252  add_particle_in(particleCopy);
253  }
254  if ( shouldAddProdVertex ) {
255  inputEvtVtxToOutputEvtVtx[ currentParticle->production_vertex() ]->
256  add_particle_out(particleCopy);
257  }
258  }
259  else {
260  ATH_MSG_WARNING ( "Found GenParticle with no production or end vertex! \n" << *currentParticle);
261  }
262  }
263  }
264  outputEvent->set_beam_particles( beam1, beam2 );
265  //
266  // 4. now that vtx/particles are copied, copy weights and random states
267  outputEvent->set_random_states( inputEvent.random_states() );
268  outputEvent->weights() = inputEvent.weights();
269 #endif
270  return outputEvent;
271 }
LArG4FSStartPointFilter.part
part
Definition: LArG4FSStartPointFilter.py:21
ISF::TruthPreselectionTool::isPostQuasiStableParticleVertex
bool isPostQuasiStableParticleVertex(HepMC::ConstGenVertexPtr vtx) const
Definition: TruthPreselectionTool.cxx:112
Trk::ParticleSwitcher::particle
constexpr ParticleHypothesis particle[PARTICLEHYPOTHESES]
the array of masses
Definition: ParticleHypothesis.h:76
ForwardTracker::beam1
@ beam1
Definition: ForwardTrackerConstants.h:13
ForwardTracker::beam2
@ beam2
Definition: ForwardTrackerConstants.h:13
ISF::TruthPreselectionTool::identifiedQuasiStableParticleForSim
bool identifiedQuasiStableParticleForSim(HepMC::ConstGenParticlePtr part) const
Definition: TruthPreselectionTool.cxx:61
ISF::TruthPreselectionTool::hasQuasiStableAncestorParticle
bool hasQuasiStableAncestorParticle(HepMC::ConstGenParticlePtr part) const
Definition: TruthPreselectionTool.cxx:80
python.DecayParser.parents
parents
print ("==> buf:",buf)
Definition: DecayParser.py:31
HeavyIon.h
read_hist_ntuple.t
t
Definition: read_hist_ntuple.py:5
covarianceTool.passFilter
bool passFilter
Definition: covarianceTool.py:604
ATH_MSG_VERBOSE
#define ATH_MSG_VERBOSE(x)
Definition: AthMsgStreamMacros.h:28
HepMC::fillBarcodesAttribute
void fillBarcodesAttribute(GenEvent *)
Definition: GenEvent.h:626
covarianceTool.filter
filter
Definition: covarianceTool.py:514
python.utils.AtlRunQueryDQUtils.p
p
Definition: AtlRunQueryDQUtils.py:210
ISF::TruthPreselectionTool::filterGenEvent
virtual std::unique_ptr< HepMC::GenEvent > filterGenEvent(const HepMC::GenEvent &inputEvent) const override final
IGenEventFilter interface.
Definition: TruthPreselectionTool.cxx:126
beamspotman.n
n
Definition: beamspotman.py:731
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
TruthPreselectionTool.h
HepMC::barcode
int barcode(const T *p)
Definition: Barcode.h:16
ISF::TruthPreselectionTool::passesFilters
bool passesFilters(HepMC::ConstGenParticlePtr part, const ToolHandleArray< IGenParticleFilter > &filters) const
check if the given particle passes all filters
Definition: TruthPreselectionTool.cxx:37
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
HepMC::ConstGenParticlePtr
const GenParticle * ConstGenParticlePtr
Definition: GenParticle.h:38
ISF::TruthPreselectionTool::initialize
virtual StatusCode initialize() override final
Athena algorithm's interface method initialize()
Definition: TruthPreselectionTool.cxx:22
ISF::TruthPreselectionTool::TruthPreselectionTool
TruthPreselectionTool(const std::string &t, const std::string &n, const IInterface *p)
Constructor with parameters.
Definition: TruthPreselectionTool.cxx:15
Trk::vertex
@ vertex
Definition: MeasurementType.h:21
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
HepMC::ConstGenVertexPtr
const HepMC::GenVertex * ConstGenVertexPtr
Definition: GenVertex.h:60
GenParticle
@ GenParticle
Definition: TruthClasses.h:30