ATLAS Offline Software
Loading...
Searching...
No Matches
FixHepMC.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
5#ifndef XAOD_ANALYSIS
6
10#include "AtlasHepMC/GenEvent.h"
11#include <vector>
12
13
14FixHepMC::FixHepMC(const std::string& name, ISvcLocator* pSvcLocator)
15 : GenBase(name, pSvcLocator)
16 , m_loopKilled(0)
17 , m_pdg0Killed(0)
20 , m_totalSeen(0)
22{
23 declareProperty("KillLoops", m_killLoops = true, "Remove particles in loops?");
24 declareProperty("KillPDG0", m_killPDG0 = true, "Remove particles with PDG ID 0?");
25 declareProperty("CleanDecays", m_cleanDecays = true, "Clean decay chains from non-propagating particles?");
26 declareProperty("PurgeUnstableWithoutEndVtx", m_purgeUnstableWithoutEndVtx = false, "Remove unstable particles without decay vertex?");
27 declareProperty("IgnoreSemiDisconnected", m_ignoreSemiDisconnected = false, "Ignore semi-disconnected particles (normal in Sherpa)");
28 declareProperty("PIDmap", m_pidmap = std::map<int,int>(), "Map of PDG IDs to replace");
29 declareProperty("forced_momentum", m_forced_momentum = "MEV", "Forced momentum unit");
30 declareProperty("forced_length", m_forced_length = "MM", "Forced length unit");
31 declareProperty("ApplyUnitsFix", m_unitsFix = true, "Attempt to identify momentum units problems and fix them");
32 declareProperty("SetHasCycles", m_setHasCycles = false, "Inform HEPMC3 that this event has cycles (loops)");
33}
34#ifndef HEPMC3
35//---->//This is copied from MCUtils
37
38
40static inline void reduce(HepMC::GenEvent* ge, HepMC::GenParticle* gp) {
41 // Do nothing if for some reason this particle is not actually in this event
42 if (gp->parent_event() != ge) return;
43
44 // Get start and end vertices
45 HepMC::GenVertex* vstart = gp->production_vertex();
46 HepMC::GenVertex* vend = gp->end_vertex();
47
48 // Disconnect the unwanted particle from its vertices and delete it
49 if (vstart != nullptr) vstart->remove_particle(gp);
50 if (vend != nullptr) vend->remove_particle(gp);
51 delete gp;
52
53 // If start/end vertices are valid and distinct, and this was the only particle that
54 // connected them, then reassign the end vertex decay products to the start vertex
55 // and rewrite the vertex position as most appropriate.
58 if (vstart != nullptr && vend != nullptr && vend != vstart) {
59 bool is_only_link = true;
60 for (auto pchild=vstart->particles_out_const_begin();pchild!=vstart->particles_out_const_end();++pchild) {
61 if ((*pchild)->end_vertex() == vend) is_only_link = false;
62 }
63 if (is_only_link) {
64 if (vend->position() != HepMC::FourVector())
65 vstart->set_position(vend->position()); //< @todo Always use end position if defined... ok?
66 while (vend->particles_out_size() > 0) {
67 vstart->add_particle_out(*vend->particles_out_const_begin());
68 }
69 while (vend->particles_in_size() > 0) {
70 vstart->add_particle_in(*vend->particles_in_const_begin());
71 }
72 }
73 }
74
75 // Sweep up any vertices orphaned by the particle removal
80 std::vector<HepMC::GenVertex*> orphaned_vtxs;
81 for (HepMC::GenEvent::vertex_const_iterator vi = ge->vertices_begin(); vi != ge->vertices_end(); ++vi) {
82 if ((*vi)->particles_in_size() == 0 && (*vi)->particles_out_size() == 0) orphaned_vtxs.push_back(*vi);
83 }
84 for (HepMC::GenVertex* gv : orphaned_vtxs) delete gv;
85 }
86
88 inline void reduce(HepMC::GenEvent* ge, std::vector<HepMC::GenParticlePtr> toremove) {
89 while (toremove.size()) {
90 auto gp = toremove.back();
91 toremove.pop_back();
92 reduce(ge, gp);
93 }
94 }
95//<----//This is copied from MCUtils
96#endif
97
98StatusCode FixHepMC::execute() {
99 for (McEventCollection::const_iterator ievt = events()->begin(); ievt != events()->end(); ++ievt) {
100 // FIXME: const_cast
101 HepMC::GenEvent* evt = const_cast<HepMC::GenEvent*>(*ievt);
102 m_looper.findLoops(evt,true);
103 /* AV: To understand why some algorithms fail one would have to request debug explicitly, but that is the reviwers consensus.*/
104 if (!m_looper.loop_particles().empty() || !m_looper.loop_vertices().empty()) {
105 ATH_MSG_DEBUG("Found " << m_looper.loop_vertices().size() << " vertices in loops");
106 ATH_MSG_DEBUG("Found " << m_looper.loop_particles().size() << " particles in loops");
107 ATH_MSG_DEBUG("Please use MC::Loops::findLoops for this event to obtain all particles and vertices in the loops");
108 }
109#ifdef HEPMC3
110 auto old_momentum = evt->momentum_unit();
111 auto old_length = evt->length_unit();
112 evt->set_units(
113 m_forced_momentum != "" ? HepMC3::Units::momentum_unit(m_forced_momentum): old_momentum,
114 m_forced_length != "" ? HepMC3::Units::length_unit(m_forced_length): old_length);
115 if ( m_forced_momentum != "" && m_forced_momentum != HepMC3::Units::name(old_momentum) ) ATH_MSG_WARNING("Updated momentum units " << HepMC3::Units::name(old_momentum) << "->" << m_forced_momentum);
116 if ( m_forced_length != "" && m_forced_length != HepMC3::Units::name(old_length) ) ATH_MSG_WARNING("Updated length units " << HepMC3::Units::name(old_length) << "->" << m_forced_length);
117#else
118 std::string old_momentum = (evt->momentum_unit() == HepMC::Units::MomentumUnit::MEV ? "MEV" : "GEV" );
119 std::string old_length = (evt->length_unit() == HepMC::Units::LengthUnit::MM ? "MM" : "CM" );
120 evt->define_units(
121 m_forced_momentum != "" ? m_forced_momentum: old_momentum,
122 m_forced_length != "" ? m_forced_length: old_length);
123 if ( m_forced_momentum != "" && m_forced_momentum != old_momentum ) ATH_MSG_WARNING("Updated momentum units " << old_momentum << "->" << m_forced_momentum);
124 if ( m_forced_length != "" && m_forced_length != old_length ) ATH_MSG_WARNING("Updated length units " << old_length << "->" << m_forced_length);
125#endif
126
127 if (!m_pidmap.empty()) {
128 for (auto ip: *evt) {
129 // Skip this particle if (somehow) its pointer is null
130 if (!ip) continue;
131 auto newpid = m_pidmap.find(ip->pdg_id());
132 if (newpid == m_pidmap.end()) continue;
133 ip->set_pdg_id(newpid->second);
134 // Increment the counter for replaced PDG IDs
136 m_replacedpid_counts[ip->pdg_id()]++;
137 }
138 }
139
140#ifdef HEPMC3
141 if (m_setHasCycles){
142 // If asked, tag the event as having cycles and alert the user that this problem exists
143 auto cycles = std::make_shared<HepMC3::IntAttribute>(1);
144 evt->add_attribute("cycles",cycles);
145 }
146#endif
147
148#ifdef HEPMC3
149 // Add a unit entry to the event weight vector if it's currently empty
150 if (evt->weights().empty()) {
151 ATH_MSG_DEBUG("Adding a unit weight to empty event weight vector");
152 evt->weights().push_back(1);
153 }
154 // Set a (0,0,0) vertex to be the signal vertex if not already set
156 const HepMC::FourVector nullpos;
157 for (auto iv: evt->vertices()) {
158 if (iv->position() == nullpos) {
159 ATH_MSG_DEBUG("Setting representative event position vertex");
161 break;
162 }
163 }
164 }
165
166 // Catch cases with more than 2 beam particles (16.11.2021)
167 std::vector<HepMC::GenParticlePtr> beams_t;
168 for (const HepMC::GenParticlePtr& p : evt->beams()) {
169 if (p->status() == 4) beams_t.push_back(p);
170 }
171 if (beams_t.size() > 2) {
172 ATH_MSG_INFO("Invalid number of beam particles " << beams_t.size() << ". Will try to fix.");
173 std::vector<HepMC::GenParticlePtr> bparttoremove;
174 for (const auto& bpart : beams_t) {
175 if (bpart->id() == 0 && bpart->production_vertex()) bparttoremove.push_back(bpart);
176 }
177 for (auto bpart: bparttoremove) {
178 bpart->production_vertex()->remove_particle_out(bpart);
179 }
180 }
181
182 // Some generators / samples have a mis-match between the units they report and the units used for momentum, usually because we have applied
183 // a correction to the momentum without also correcting the units. Here we're going to check for states that look particularly suspicious
184 // and apply a correction if required. We will try to identify those issues based on the beam particles.
185 if (m_unitsFix){ // Only if requested - allow folks to disable this if they know what they're doing
186 double units_problem = -1.;
187 // If we have beam particles, let's use them - it's much faster!
188 if (beams_t.size() > 0 ){
189 for (const HepMC::GenParticlePtr& p : beams_t){
190 if (p->momentum().pz() > 1e9) units_problem = p->momentum().pz();
191 }
192 // if we didn't have beam particles, we'll go through some of the main record
193 } else {
194 for (const HepMC::GenParticlePtr& p : evt->particles()) {
195 if (p && p->momentum().pz() > 1e9) units_problem = p->momentum().pz();
196 }
197 }
198 if (units_problem>0){ // No particles should have momenta above 1 PeV; this must be a units issue
199 ATH_MSG_INFO("Apparent units problem; beam particles have z-momentum " << units_problem << " in MeV. Will divide by 1000.");
200 MC::MeVToGeV(evt); //Only scales momenta and masses
201 }
202 }
203
204 // Some heuristics to catch problematic cases
205 std::vector<HepMC::GenParticlePtr> semi_disconnected, decay_loop_particles;
206 for (auto ip : evt->particles()) {
207 // Skip this particle if (somehow) its pointer is null
208 if (!ip) continue;
209 bool particle_to_fix = false;
210 int abspid = std::abs(ip->pdg_id());
211 auto vProd = ip->production_vertex();
212 auto vEnd = ip->end_vertex();
214 if ( (!vProd || vProd->id() == 0) && vEnd && ip->status() != 4) {
215 particle_to_fix = true;
216 ATH_MSG_DEBUG("Found particle " << ip->pdg_id() << " without production vertex! HepMC status = " << ip->status());
217 }
219 if (vProd && !vEnd && ip->status() != 1) {
220 particle_to_fix = true;
221 ATH_MSG_DEBUG("Found particle " << ip->pdg_id() << " without decay vertex! HepMC status = " << ip->status());
222 }
223 if (particle_to_fix) semi_disconnected.push_back(ip);
224 // Case 3: keep track of loop particles inside decay chains (seen in H7+EvtGen)
225 if (abspid == 43 || abspid == 44 || abspid == 30353 || abspid == 30343) {
226 decay_loop_particles.push_back(std::move(ip));
227 }
228 }
229
233
238 if ( !m_ignoreSemiDisconnected && (semi_disconnected.size() == 4 || semi_disconnected.size() == 3 || semi_disconnected.size() == 2)) {
239 size_t no_endv = 0;
240 size_t no_prov = 0;
241 HepMC::FourVector sum(0,0,0,0);
242 std::set<HepMC::GenVertexPtr> standalone;
243 for (const auto& part : semi_disconnected) {
244 if (!part->production_vertex() || !part->production_vertex()->id()) {
245 no_prov++; sum += part->momentum();
246 }
247 if (!part->end_vertex()) {
248 no_endv++; sum -= part->momentum();
249 }
250 if (part->production_vertex()) standalone.insert(part->production_vertex());
251 if (part->end_vertex()) standalone.insert(part->end_vertex());
252 }
253 ATH_MSG_INFO("Heuristics: found " << semi_disconnected.size() << " semi-disconnected particles. Momentum sum is " << sum << " Standalone vertices " << standalone.size());
254 bool standalonevertex = (standalone.size() == 1 && (*standalone.begin())->particles_in().size() + (*standalone.begin())->particles_out().size() == semi_disconnected.size());
256 if (! standalonevertex && no_endv && no_prov && ( no_endv + no_prov == semi_disconnected.size() )) {
257 if (std::abs(sum.px()) < 1e-2 && std::abs(sum.py()) < 1e-2 && std::abs(sum.pz()) < 1e-2 ) {
258 ATH_MSG_INFO("Try " << no_endv << "->" << no_prov << " splitting/merging.");
259 auto v = HepMC::newGenVertexPtr();
260 for (auto part : semi_disconnected) {
261 if (!part->production_vertex() || part->production_vertex()->id() == 0) v->add_particle_out(std::move(part));
262 }
263 for (auto part : semi_disconnected) {
264 if (!part->end_vertex()) v->add_particle_in(std::move(part));
265 }
266 evt->add_vertex(std::move(v));
267 }
268 }
269 }
270
275 for (auto part: decay_loop_particles) {
277 auto vend = part->end_vertex();
278 auto vprod = part->production_vertex();
279 if (!vprod || !vend) continue;
280 bool loop_in_decay = true;
283 auto sisters = vend->particles_in();
284 for (auto sister: sisters) {
285 if (vprod != sister->production_vertex()) loop_in_decay = false;
286 }
287 if (!loop_in_decay) continue;
288
290 auto daughters = vend->particles_out();
291 for (auto p : daughters) vprod->add_particle_out(std::move(p));
292 for (auto sister : sisters) {
293 vprod->remove_particle_out(sister);
294 vend->remove_particle_in(sister);
295 evt->remove_particle(std::move(sister));
296 }
297 evt->remove_vertex(std::move(vend));
298
299 }
300
301 // Event particle content cleaning -- remove "bad" structures
302 std::vector<HepMC::GenParticlePtr> toremove;
303 for (auto ip: evt->particles()) {
304 // Skip this particle if (somehow) its pointer is null
305 if (!ip) continue;
306 m_totalSeen += 1;
307 // Flag to declare if a particle should be removed
308 bool bad_particle = false;
309 // Check for loops
310 if ( m_killLoops && isSimpleLoop(ip) ) {
311 bad_particle = true;
312 m_loopKilled += 1;
313 ATH_MSG_DEBUG( "Found a looper : " );
314 if ( msgLvl( MSG::DEBUG ) ) HepMC::Print::line(ip);
315 }
316 // Check on PDG ID 0
317 if ( m_killPDG0 && isPID0(ip) ) {
318 bad_particle = true;
319 m_pdg0Killed += 1;
320 ATH_MSG_DEBUG( "Found PDG ID 0 : " );
321 if ( msgLvl( MSG::DEBUG ) )HepMC::Print::line(ip);
322 }
323 // Clean decays
324 int abs_pdg_id = std::abs(ip->pdg_id());
325 bool is_decayed_weak_boson = ( abs_pdg_id == 23 || abs_pdg_id == 24 || abs_pdg_id == 25 ) && ip->end_vertex();
326 if ( m_cleanDecays && isNonTransportableInDecayChain(ip) && !is_decayed_weak_boson ) {
327 bad_particle = true;
328 m_decayCleaned += 1;
329 ATH_MSG_DEBUG( "Found a bad particle in a decay chain : " );
330 if ( msgLvl( MSG::DEBUG ) ) HepMC::Print::line(ip);
331 }
332 // Only add to the toremove vector once, even if multiple tests match
333 if (bad_particle) toremove.push_back(std::move(ip));
334 }
335
336 // Properties before cleaning
337 const int num_particles_orig = evt->particles().size();
338
339 // Do the cleaning
340 if (!toremove.empty()) {
341 ATH_MSG_DEBUG("Cleaning event record of " << toremove.size() << " bad particles");
342 for (auto part: toremove) evt->remove_particle(std::move(part));
343 }
344
346 int purged=0;
347 do {
348 purged=0;
349 const std::vector <HepMC::GenParticlePtr> allParticles=evt->particles();
350 for(auto p : allParticles) {
351 HepMC::ConstGenVertexPtr end_v=p->end_vertex();
352 if(p->status() == 2 && !end_v) {
353 evt->remove_particle(std::move(p));
354 ++purged;
356 }
357 }
358 }
359 while (purged>0);
360 }
361
362 const int num_particles_filt = evt->particles().size();
363
364 if(num_particles_orig!=num_particles_filt) {
365 // Write out the change in the number of particles
366 ATH_MSG_INFO("Particles filtered: " << num_particles_orig << " -> " << num_particles_filt);
367 }
368 #else
369
370 // Add a unit entry to the event weight vector if it's currently empty
371 if (evt->weights().empty()) {
372 ATH_MSG_DEBUG("Adding a unit weight to empty event weight vector");
373 evt->weights().push_back(1);
374 }
375
376 // Set a (0,0,0) vertex to be the signal vertex if not already set
377 if (evt->signal_process_vertex() == NULL) {
378 const HepMC::FourVector nullpos;
379 for (HepMC::GenEvent::vertex_const_iterator iv = evt->vertices_begin(); iv != evt->vertices_end(); ++iv) {
380 if ((*iv)->position() == nullpos) {
381 ATH_MSG_DEBUG("Setting representative event position vertex");
382 evt->set_signal_process_vertex(const_cast<HepMC::GenVertex*>(*iv));
383 break;
384 }
385 }
386 }
387
388
389 // Some heuristics to catch problematic cases
390 std::vector<HepMC::GenParticlePtr> semi_disconnected, decay_loop_particles;
391 for (auto ip : *evt) {
392 // Skip this particle if (somehow) its pointer is null
393 if (!ip) continue;
394 bool particle_to_fix = false;
395 int abspid = std::abs(ip->pdg_id());
396 auto vProd = ip->production_vertex();
397 auto vEnd = ip->end_vertex();
399 if ( (!vProd || vProd->id() == 0) && vEnd && ip->status() != 4) {
400 particle_to_fix = true;
401 ATH_MSG_DEBUG("Found particle " << ip->pdg_id() << " without production vertex! HepMC status = " << ip->status());
402 }
404 if (vProd && !vEnd && ip->status() != 1) {
405 particle_to_fix = true;
406 ATH_MSG_DEBUG("Found particle " << ip->pdg_id() << " without decay vertex! HepMC status = " << ip->status());
407 }
408 if (particle_to_fix) semi_disconnected.push_back(ip);
409 // Case 3: keep track of loop particles inside decay chains (seen in H7+EvtGen)
410 if (abspid == 43 || abspid == 44 || abspid == 30353 || abspid == 30343) {
411 decay_loop_particles.push_back(ip);
412 }
413 }
414
417 if (semi_disconnected.size() == 4 ||semi_disconnected.size() == 3 || semi_disconnected.size() == 2) {
418 size_t no_endv = 0;
419 size_t no_prov = 0;
420 double vsum[4] = {0,0,0,0};
421 for (auto part : semi_disconnected) {
422 if (!part->production_vertex() ) {
423 no_prov++;
424 vsum[0] += part->momentum().px();
425 vsum[1] += part->momentum().py();
426 vsum[2] += part->momentum().pz();
427 vsum[3] += part->momentum().e();
428 }
429 if (!part->end_vertex()) {
430 no_endv++;
431 vsum[0] -= part->momentum().px();
432 vsum[1] -= part->momentum().py();
433 vsum[2] -= part->momentum().pz();
434 vsum[3] -= part->momentum().e();
435 }
436 }
437 HepMC::FourVector sum(vsum[0],vsum[1],vsum[2],vsum[3]);
438 ATH_MSG_INFO("Heuristics: found " << semi_disconnected.size() << " semi-disconnected particles. Momentum sum is " << vsum[0] << " " << vsum[1] << " " << vsum[2] << " " << vsum[3]);
440 if (no_endv && no_prov && ( no_endv + no_prov == semi_disconnected.size() )) {
441 if (std::abs(sum.px()) < 1e-2 && std::abs(sum.py()) < 1e-2 && std::abs(sum.pz()) < 1e-2 ) {
442 ATH_MSG_INFO("Try " << no_endv << "->" << no_prov << " splitting/merging.");
443 auto v = HepMC::newGenVertexPtr();
444 for (auto part : semi_disconnected) {
445 if (!part->production_vertex()) v->add_particle_out(part);
446 }
447 for (auto part : semi_disconnected) {
448 if (!part->end_vertex()) v->add_particle_in(part);
449 }
450 evt->add_vertex(v);
451 }
452 }
453 }
454
459 for (auto part: decay_loop_particles) {
461 auto vend = part->end_vertex();
462 auto vprod = part->production_vertex();
463 if (!vend || !vprod) continue;
464 bool loop_in_decay = true;
466 std::vector<HepMC::GenParticlePtr> sisters;
467 for (auto p = vend->particles_begin(HepMC::parents); p!= vend->particles_end(HepMC::parents); ++p) sisters.push_back(*p);
468 for (auto sister : sisters) {
469 if (vprod != sister->production_vertex()) loop_in_decay = false;
470 }
471 if (!loop_in_decay) continue;
472
473 std::vector<HepMC::GenParticlePtr> daughters;
474 for (auto p = vend->particles_begin(HepMC::children); p!= vend->particles_end(HepMC::children); ++p) daughters.push_back(*p);
475 for (auto p : daughters) vprod->add_particle_out(p);
476 for (auto sister : sisters) {
477 vprod->remove_particle(sister);
478 vend->remove_particle(sister);
479 }
480 evt->remove_vertex(vend);
481
482 }
483
484
485 // Event particle content cleaning -- remove "bad" structures
486 std::vector<HepMC::GenParticlePtr> toremove; toremove.reserve(10);
487 for (HepMC::GenEvent::particle_const_iterator ip = evt->particles_begin(); ip != evt->particles_end(); ++ip) {
488 // Skip this particle if (somehow) its pointer is null
489 if (*ip == NULL) continue;
490 m_totalSeen += 1;
491
492 // Flag to declare if a particle should be removed
493 bool bad_particle = false;
494
495 // Check for loops
496 if ( m_killLoops && isSimpleLoop(*ip) ) {
497 bad_particle = true;
498 m_loopKilled += 1;
499 ATH_MSG_DEBUG( "Found a looper : " );
500 if ( msgLvl( MSG::DEBUG ) ) (*ip)->print();
501 }
502
503 // Check on PDG ID 0
504 if ( m_killPDG0 && isPID0(*ip) ) {
505 bad_particle = true;
506 m_pdg0Killed += 1;
507 ATH_MSG_DEBUG( "Found PDG ID 0 : " );
508 if ( msgLvl( MSG::DEBUG ) ) (*ip)->print();
509 }
510
511 // Clean decays
512 int abs_pdg_id = std::abs((*ip)->pdg_id());
513 bool is_decayed_weak_boson = ( abs_pdg_id == 23 || abs_pdg_id == 24 || abs_pdg_id == 25 ) && (*ip)->end_vertex();
514 if ( m_cleanDecays && isNonTransportableInDecayChain(*ip) && !is_decayed_weak_boson ) {
515 bad_particle = true;
516 m_decayCleaned += 1;
517 ATH_MSG_DEBUG( "Found a bad particle in a decay chain : " );
518 if ( msgLvl( MSG::DEBUG ) ) (*ip)->print();
519 }
520
521 // Only add to the toremove vector once, even if multiple tests match
522 if (bad_particle) toremove.push_back(*ip);
523 }
524
525 // Properties before cleaning
526 const int num_particles_orig = evt->particles_size();
527 int num_orphan_vtxs_orig = 0;
528 int num_noparent_vtxs_orig = 0;
529 int num_nochild_vtxs_orig = 0;
530 for (auto v = evt->vertices_begin(); v != evt->vertices_end(); ++v) {
531 if ((*v)->particles_in_size()==0&&(*v)->particles_out_size()==0) num_orphan_vtxs_orig++;
532 if ((*v)->particles_in_size()==0) num_noparent_vtxs_orig++;
533 if ((*v)->particles_out_size()==0) num_nochild_vtxs_orig++;
534 }
535
536 // Do the cleaning
537 if (!toremove.empty()) {
538 ATH_MSG_DEBUG("Cleaning event record of " << toremove.size() << " bad particles");
539 // Clean!
540 int signal_vertex_bc = evt->signal_process_vertex() ? evt->signal_process_vertex()->barcode() : 0;
541 //This is the only place where reduce is used.
542 reduce(evt , toremove);
543 if (evt->barcode_to_vertex (signal_vertex_bc) == nullptr) {
544 evt->set_signal_process_vertex (nullptr);
545 }
546 }
547
549 int purged=0;
550 do {
551 for (HepMC::GenParticle* p : *evt) {
552 HepMC::ConstGenVertexPtr end_v = p->end_vertex();
553 if (p->status() == 2 && !end_v) {
554 delete p->production_vertex()->remove_particle(p);
555 ++purged;
557 }
558 }
559 }
560 while (purged>0);
561 }
562
563 // Properties after cleaning
564 const int num_particles_filt = evt->particles_size();
565 if(num_particles_orig!=num_particles_filt) {
566 int num_orphan_vtxs_filt = 0;
567 int num_noparent_vtxs_filt = 0;
568 int num_nochild_vtxs_filt = 0;
569 for (auto v = evt->vertices_begin(); v != evt->vertices_end(); ++v) {
570 if ((*v)->particles_in_size()==0&&(*v)->particles_out_size()==0) num_orphan_vtxs_filt++;
571 if ((*v)->particles_in_size()==0) num_noparent_vtxs_filt++;
572 if ((*v)->particles_out_size()==0) num_nochild_vtxs_filt++;
573 }
574
575 // Write out the change in the number of particles
576 ATH_MSG_INFO("Particles filtered: " << num_particles_orig << " -> " << num_particles_filt);
577 // Warn if the numbers of "strange" vertices have changed
578 if (num_orphan_vtxs_filt != num_orphan_vtxs_orig)
579 ATH_MSG_WARNING("Change in orphaned vertices: " << num_orphan_vtxs_orig << " -> " << num_orphan_vtxs_filt);
580 if (num_noparent_vtxs_filt != num_noparent_vtxs_orig)
581 ATH_MSG_WARNING("Change in no-parent vertices: " << num_noparent_vtxs_orig << " -> " << num_noparent_vtxs_filt);
582 if (num_nochild_vtxs_filt != num_nochild_vtxs_orig)
583 ATH_MSG_WARNING("Change in no-parent vertices: " << num_nochild_vtxs_orig << " -> " << num_nochild_vtxs_filt);
584 }
585#endif
586
587 } // End of the loop over events in the MC event collection
588 return StatusCode::SUCCESS;
589}
590
591
592StatusCode FixHepMC::finalize() {
593 if (m_killLoops ) ATH_MSG_INFO( "Removed " << m_loopKilled << " of " << m_totalSeen << " particles because of loops." );
594 if (m_killPDG0 ) ATH_MSG_INFO( "Removed " << m_pdg0Killed << " of " << m_totalSeen << " particles because of PDG ID 0." );
595 if (m_cleanDecays) ATH_MSG_INFO( "Removed " << m_decayCleaned << " of " << m_totalSeen << " particles while cleaning decay chains." );
596 if(m_purgeUnstableWithoutEndVtx) ATH_MSG_INFO( "Removed " << m_unstablePurged << " of " << m_totalSeen << " unstable particles because they had no decay vertex." );
597 if (!m_pidmap.empty()) {
598 ATH_MSG_INFO( "Replaced " << m_replacedPIDs << " PIDs of particles." );
599 for (const auto& p: m_replacedpid_counts) ATH_MSG_INFO( "Replaced " << p.first << " PIDs " << p.second << "times." );
600 }
601 return StatusCode::SUCCESS;
602}
603
604
606
607
608// Identify PDG ID = 0 particles, usually from HEPEVT padding
610 return p->pdg_id() == 0;
611}
612
613// Identify the particles from
614bool FixHepMC::fromDecay(const HepMC::ConstGenParticlePtr& p, std::shared_ptr<std::set<int> >& storage) const {
615 if (!p) return false;
616 auto v=p->production_vertex();
617 if (!v) return false;
618#ifdef HEPMC3
619 for ( const auto& anc: v->particles_in()) {
620 if (MC::isDecayed(anc) && (MC::isTau(anc->pdg_id()) || MC::isHadron(anc->pdg_id()))) return true;
621 }
622 if (storage->find(p->id()) != storage->end()) return false;
623 storage->insert(p->id());
624 for ( const auto& anc: v->particles_in()) {
625 if (fromDecay(anc, storage)) return true;
626 }
627#else
628 for (auto anc=v->particles_in_const_begin(); anc != v->particles_in_const_end(); ++anc) {
629 if (MC::isDecayed((*anc)) && (MC::isTau((*anc)->pdg_id()) || MC::isHadron((*anc)->pdg_id()))) return true;
630 }
631 if (storage->find(p->barcode()) != storage->end()) return false;
632 storage->insert(p->barcode());
633 for (auto anc=v->particles_in_const_begin(); anc != v->particles_in_const_end(); ++anc){
634 if (fromDecay(*anc, storage)) return true;
635 }
636#endif
637 return false;
638}
639
640// Identify non-transportable stuff _after_ hadronisation
642 auto storage = std::make_shared<std::set<int>>();
643 return !MC::isTransportable(p->pdg_id()) && fromDecay(p, storage);
644}
645
646// Identify internal "loop" particles
648 return (p->production_vertex() == p->end_vertex() && p->end_vertex() != nullptr);
649}
650
652
653#endif
654
#define ATH_MSG_INFO(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
static void reduce(HepMC::GenEvent *ge, HepMC::GenParticle *gp)
Remove an unwanted particle from the event, collapsing the graph structure consistently.
Definition FixHepMC.cxx:40
ATLAS-specific HepMC functions.
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)
bool msgLvl(const MSG::Level lvl) const
DataModel_detail::const_iterator< DataVector > const_iterator
Definition DataVector.h:838
bool isPID0(const HepMC::ConstGenParticlePtr &p) const
Definition FixHepMC.cxx:609
StatusCode execute()
Definition FixHepMC.cxx:98
bool m_setHasCycles
Definition FixHepMC.h:59
FixHepMC(const std::string &name, ISvcLocator *pSvcLocator)
Definition FixHepMC.cxx:14
bool m_purgeUnstableWithoutEndVtx
Definition FixHepMC.h:54
long m_replacedPIDs
Definition FixHepMC.h:69
bool m_killPDG0
Definition FixHepMC.h:52
bool isNonTransportableInDecayChain(const HepMC::ConstGenParticlePtr &p) const
Definition FixHepMC.cxx:641
std::string m_forced_momentum
Definition FixHepMC.h:56
bool m_unitsFix
Definition FixHepMC.h:58
bool fromDecay(const HepMC::ConstGenParticlePtr &p, std::shared_ptr< std::set< int > > &storage) const
Definition FixHepMC.cxx:614
long m_totalSeen
Definition FixHepMC.h:68
StatusCode finalize()
Definition FixHepMC.cxx:592
long m_pdg0Killed
Definition FixHepMC.h:65
long m_decayCleaned
Definition FixHepMC.h:66
bool m_ignoreSemiDisconnected
Definition FixHepMC.h:55
bool m_cleanDecays
Definition FixHepMC.h:53
bool m_killLoops
Definition FixHepMC.h:51
long m_unstablePurged
Definition FixHepMC.h:67
std::map< int, int > m_replacedpid_counts
map of counters of replacements.
Definition FixHepMC.h:73
long m_loopKilled
Definition FixHepMC.h:64
std::map< int, int > m_pidmap
map of pids to change.
Definition FixHepMC.h:72
MC::Loops< HepMC::GenEvent, HepMC::ConstGenParticlePtr, HepMC::ConstGenVertexPtr > m_looper
member to detect loops
Definition FixHepMC.h:76
bool isSimpleLoop(const HepMC::ConstGenParticlePtr &p) const
Definition FixHepMC.cxx:647
std::string m_forced_length
Definition FixHepMC.h:57
GenBase(const std::string &name, ISvcLocator *pSvcLocator)
Constructor.
Definition GenBase.cxx:11
void line(std::ostream &os, const GenEvent &e)
Definition GenEvent.h:696
void set_signal_process_vertex(GenEvent *e, T v)
Definition GenEvent.h:670
GenVertexPtr newGenVertexPtr(const HepMC::FourVector &pos=HepMC::FourVector(0.0, 0.0, 0.0, 0.0), const int i=0)
Definition GenVertex.h:64
GenParticle * GenParticlePtr
Definition GenParticle.h:37
const GenParticle * ConstGenParticlePtr
Definition GenParticle.h:38
GenVertex * signal_process_vertex(const GenEvent *e)
Definition GenEvent.h:645
const HepMC::GenVertex * ConstGenVertexPtr
Definition GenVertex.h:60
void MeVToGeV(HepMC::GenEvent *evt)
bool isTransportable(const T &p)
bool isDecayed(const T &p)
Identify if the particle decayed.
bool isHadron(const T &p)
bool isTau(const T &p)