AV: In case we have 3 particles, we try to add a vertex that correspond to 1->2 and 1->1 splitting. AV: we can try to do that for 4 particles as well.
Remove loops inside decay chains AV: Please note that this approach would distort some branching ratios. If some particle would have decay products with bad PDG ids, after the operation below the visible branching ratio of these decays would be zero.
Check that all particles coming into the decay vertex of bad particle cam from the same production vertex.
98 {
100
101 HepMC::GenEvent*
evt =
const_cast<HepMC::GenEvent*
>(*ievt);
103
104 if (!
m_looper.loop_particles().empty() || !
m_looper.loop_vertices().empty()) {
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();
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" );
125#endif
126
128 for (auto ip: *evt) {
129
130 if (!ip) continue;
132 if (newpid ==
m_pidmap.end())
continue;
133 ip->set_pdg_id(newpid->second);
134
137 }
138 }
139
140#ifdef HEPMC3
142
143 auto cycles = std::make_shared<HepMC3::IntAttribute>(1);
144 evt->add_attribute(
"cycles",cycles);
145 }
146#endif
147
148#ifdef HEPMC3
149
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
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
167 std::vector<HepMC::GenParticlePtr> beams_t;
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
183
184
186 double units_problem = -1.;
187
188 if (beams_t.size() > 0 ){
190 if (
p->momentum().pz() > 1e9) units_problem =
p->momentum().pz();
191 }
192
193 } else {
195 if (p &&
p->momentum().pz() > 1e9) units_problem =
p->momentum().pz();
196 }
197 }
198 if (units_problem>0){
199 ATH_MSG_INFO(
"Apparent units problem; beam particles have z-momentum " << units_problem <<
" in MeV. Will divide by 1000.");
201 }
202 }
203
204
205 std::vector<HepMC::GenParticlePtr> semi_disconnected, decay_loop_particles;
206 for (
auto ip :
evt->particles()) {
207
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
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);
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 }
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.");
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
302 std::vector<HepMC::GenParticlePtr> toremove;
303 for (
auto ip:
evt->particles()) {
304
305 if (!ip) continue;
307
308 bool bad_particle = false;
309
311 bad_particle = true;
315 }
316
318 bad_particle = true;
322 }
323
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();
327 bad_particle = true;
331 }
332
333 if (bad_particle) toremove.push_back(std::move(ip));
334 }
335
336
337 const int num_particles_orig =
evt->particles().size();
338
339
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) {
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
366 ATH_MSG_INFO(
"Particles filtered: " << num_particles_orig <<
" -> " << num_particles_filt);
367 }
368 #else
369
370
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
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
390 std::vector<HepMC::GenParticlePtr> semi_disconnected, decay_loop_particles;
391 for (auto ip : *evt) {
392
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
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.");
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 }
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
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
489 if (*ip == NULL) continue;
491
492
493 bool bad_particle = false;
494
495
497 bad_particle = true;
500 if (
msgLvl( MSG::DEBUG ) ) (*ip)->print();
501 }
502
503
505 bad_particle = true;
508 if (
msgLvl( MSG::DEBUG ) ) (*ip)->print();
509 }
510
511
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();
515 bad_particle = true;
518 if (
msgLvl( MSG::DEBUG ) ) (*ip)->print();
519 }
520
521
522 if (bad_particle) toremove.push_back(*ip);
523 }
524
525
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
537 if (!toremove.empty()) {
538 ATH_MSG_DEBUG(
"Cleaning event record of " << toremove.size() <<
" bad particles");
539
540 int signal_vertex_bc =
evt->signal_process_vertex() ?
evt->signal_process_vertex()->barcode() : 0;
541
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) {
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
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
576 ATH_MSG_INFO(
"Particles filtered: " << num_particles_orig <<
" -> " << num_particles_filt);
577
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 }
588 return StatusCode::SUCCESS;
589}
#define ATH_MSG_WARNING(x)
static void reduce(HepMC::GenEvent *ge, HepMC::GenParticle *gp)
Remove an unwanted particle from the event, collapsing the graph structure consistently.
bool msgLvl(const MSG::Level lvl) const
DataModel_detail::const_iterator< DataVector > const_iterator
bool isPID0(const HepMC::ConstGenParticlePtr &p) const
bool isNonTransportableInDecayChain(const HepMC::ConstGenParticlePtr &p) const
std::map< int, int > m_replacedpid_counts
map of counters of replacements.
MC::Loops< HepMC::GenEvent, HepMC::ConstGenParticlePtr, HepMC::ConstGenVertexPtr > m_looper
member to detect loops
bool isSimpleLoop(const HepMC::ConstGenParticlePtr &p) const
void line(std::ostream &os, const GenEvent &e)
void set_signal_process_vertex(GenEvent *e, T v)
GenVertexPtr newGenVertexPtr(const HepMC::FourVector &pos=HepMC::FourVector(0.0, 0.0, 0.0, 0.0), const int i=0)
GenParticle * GenParticlePtr
GenVertex * signal_process_vertex(const GenEvent *e)
const HepMC::GenVertex * ConstGenVertexPtr
void MeVToGeV(HepMC::GenEvent *evt)