40 if (gp->parent_event() != ge)
return;
43 HepMC::GenVertex* vstart = gp->production_vertex();
44 HepMC::GenVertex* vend = gp->end_vertex();
47 if (vstart !=
nullptr) vstart->remove_particle(gp);
48 if (vend !=
nullptr) vend->remove_particle(gp);
56 if (vstart !=
nullptr && vend !=
nullptr && vend != vstart) {
57 bool is_only_link =
true;
58 for (
auto pchild=vstart->particles_out_const_begin();pchild!=vstart->particles_out_const_end();++pchild) {
59 if ((*pchild)->end_vertex() == vend) is_only_link =
false;
62 if (vend->position() != HepMC::FourVector())
63 vstart->set_position(vend->position());
64 while (vend->particles_out_size() > 0) {
65 vstart->add_particle_out(*vend->particles_out_const_begin());
67 while (vend->particles_in_size() > 0) {
68 vstart->add_particle_in(*vend->particles_in_const_begin());
78 std::vector<HepMC::GenVertex*> orphaned_vtxs;
79 for (HepMC::GenEvent::vertex_const_iterator vi = ge->vertices_begin(); vi != ge->vertices_end(); ++vi) {
80 if ((*vi)->particles_in_size() == 0 && (*vi)->particles_out_size() == 0) orphaned_vtxs.push_back(*vi);
82 for (HepMC::GenVertex* gv : orphaned_vtxs)
delete gv;
86 inline void reduce(HepMC::GenEvent* ge, std::vector<HepMC::GenParticlePtr> toremove) {
87 while (toremove.size()) {
88 auto gp = toremove.back();
99 HepMC::GenEvent*
evt =
const_cast<HepMC::GenEvent*
>(*ievt);
105 ATH_MSG_DEBUG(
"Please use MC::Loops::findLoops for this event to obtain all particles and vertices in the loops");
108 auto old_momentum =
evt->momentum_unit();
109 auto old_length =
evt->length_unit();
116 std::string old_momentum = (
evt->momentum_unit() == HepMC::Units::MomentumUnit::MEV ?
"MEV" :
"GEV" );
125 for (
auto ip: *
evt) {
129 if (newpid ==
m_pidmap.end())
continue;
130 ip->set_pdg_id(newpid->second);
138 if (
evt->weights().empty()) {
139 ATH_MSG_DEBUG(
"Adding a unit weight to empty event weight vector");
140 evt->weights().push_back(1);
144 const HepMC::FourVector nullpos;
145 for (
auto iv:
evt->vertices()) {
146 if (iv->position() == nullpos) {
147 ATH_MSG_DEBUG(
"Setting representative event position vertex");
155 std::vector<HepMC::GenParticlePtr> beams_t;
157 if (
p->status() == 4) beams_t.push_back(
p);
159 if (beams_t.size() > 2) {
160 ATH_MSG_INFO(
"Invalid number of beam particles " << beams_t.size() <<
". Will try to fix.");
161 std::vector<HepMC::GenParticlePtr> bparttoremove;
162 for (
const auto& bpart : beams_t) {
163 if (bpart->id() == 0 && bpart->production_vertex()) bparttoremove.push_back(bpart);
165 for (
auto bpart: bparttoremove) {
166 bpart->production_vertex()->remove_particle_out(bpart);
171 std::vector<HepMC::GenParticlePtr> semi_disconnected, decay_loop_particles;
172 for (
auto ip :
evt->particles()) {
175 bool particle_to_fix =
false;
176 int abspid = std::abs(
ip->pdg_id());
177 auto vProd =
ip->production_vertex();
178 auto vEnd =
ip->end_vertex();
180 if ( (!vProd || vProd->id() == 0) && vEnd &&
ip->status() != 4) {
181 particle_to_fix =
true;
182 ATH_MSG_DEBUG(
"Found particle " <<
ip->pdg_id() <<
" without production vertex! HepMC status = " <<
ip->status());
185 if (vProd && !vEnd &&
ip->status() != 1) {
186 particle_to_fix =
true;
187 ATH_MSG_DEBUG(
"Found particle " <<
ip->pdg_id() <<
" without decay vertex! HepMC status = " <<
ip->status());
189 if (particle_to_fix) semi_disconnected.push_back(
ip);
191 if (abspid == 43 || abspid == 44 || abspid == 30353 || abspid == 30343) {
192 decay_loop_particles.push_back(std::move(
ip));
204 if ( !
m_ignoreSemiDisconnected && (semi_disconnected.size() == 4 || semi_disconnected.size() == 3 || semi_disconnected.size() == 2)) {
207 HepMC::FourVector
sum(0,0,0,0);
209 for (
const auto&
part : semi_disconnected) {
210 if (!
part->production_vertex() || !
part->production_vertex()->id()) {
211 no_prov++;
sum +=
part->momentum();
213 if (!
part->end_vertex()) {
214 no_endv++;
sum -=
part->momentum();
219 ATH_MSG_INFO(
"Heuristics: found " << semi_disconnected.size() <<
" semi-disconnected particles. Momentum sum is " <<
sum <<
" Standalone vertices " <<
standalone.size());
220 bool standalonevertex = (
standalone.size() == 1 && (*
standalone.begin())->particles_in().size() + (*
standalone.begin())->particles_out().size() == semi_disconnected.size());
222 if (! standalonevertex && no_endv && no_prov && ( no_endv + no_prov == semi_disconnected.size() )) {
223 if (std::abs(
sum.px()) < 1
e-2 && std::abs(
sum.py()) < 1
e-2 && std::abs(
sum.pz()) < 1
e-2 ) {
224 ATH_MSG_INFO(
"Try " << no_endv <<
"->" << no_prov <<
" splitting/merging.");
226 for (
auto part : semi_disconnected) {
227 if (!
part->production_vertex() ||
part->production_vertex()->id() == 0)
v->add_particle_out(std::move(
part));
229 for (
auto part : semi_disconnected) {
230 if (!
part->end_vertex())
v->add_particle_in(std::move(
part));
232 evt->add_vertex(std::move(
v));
241 for (
auto part: decay_loop_particles) {
243 auto vend =
part->end_vertex();
244 auto vprod =
part->production_vertex();
245 if (!vprod || !vend)
continue;
246 bool loop_in_decay =
true;
249 auto sisters = vend->particles_in();
250 for (
auto sister: sisters) {
251 if (vprod != sister->production_vertex()) loop_in_decay =
false;
253 if (!loop_in_decay)
continue;
256 auto daughters = vend->particles_out();
257 for (
auto p : daughters) vprod->add_particle_out(std::move(
p));
258 for (
auto sister : sisters) {
259 vprod->remove_particle_out(sister);
260 vend->remove_particle_in(sister);
261 evt->remove_particle(std::move(sister));
263 evt->remove_vertex(std::move(vend));
268 std::vector<HepMC::GenParticlePtr> toremove;
269 for (
auto ip:
evt->particles()) {
274 bool bad_particle =
false;
290 int abs_pdg_id = std::abs(
ip->pdg_id());
291 bool is_decayed_weak_boson = ( abs_pdg_id == 23 || abs_pdg_id == 24 || abs_pdg_id == 25 ) &&
ip->end_vertex();
299 if (bad_particle) toremove.push_back(
ip);
303 const int num_particles_orig =
evt->particles().size();
306 if (!toremove.empty()) {
307 ATH_MSG_DEBUG(
"Cleaning event record of " << toremove.size() <<
" bad particles");
308 for (
auto part: toremove)
evt->remove_particle(
part);
315 const std::vector <HepMC::GenParticlePtr> allParticles=
evt->particles();
316 for(
auto p : allParticles) {
318 if(
p->status() == 2 && !end_v) {
319 evt->remove_particle(std::move(
p));
328 const int num_particles_filt =
evt->particles().size();
330 if(num_particles_orig!=num_particles_filt) {
332 ATH_MSG_INFO(
"Particles filtered: " << num_particles_orig <<
" -> " << num_particles_filt);
337 if (
evt->weights().empty()) {
338 ATH_MSG_DEBUG(
"Adding a unit weight to empty event weight vector");
339 evt->weights().push_back(1);
343 if (
evt->signal_process_vertex() == NULL) {
344 const HepMC::FourVector nullpos;
345 for (HepMC::GenEvent::vertex_const_iterator iv =
evt->vertices_begin(); iv !=
evt->vertices_end(); ++iv) {
346 if ((*iv)->position() == nullpos) {
347 ATH_MSG_DEBUG(
"Setting representative event position vertex");
348 evt->set_signal_process_vertex(
const_cast<HepMC::GenVertex*
>(*iv));
356 std::vector<HepMC::GenParticlePtr> semi_disconnected, decay_loop_particles;
357 for (
auto ip : *
evt) {
360 bool particle_to_fix =
false;
361 int abspid = std::abs(
ip->pdg_id());
362 auto vProd =
ip->production_vertex();
363 auto vEnd =
ip->end_vertex();
365 if ( (!vProd || vProd->id() == 0) && vEnd &&
ip->status() != 4) {
366 particle_to_fix =
true;
367 ATH_MSG_DEBUG(
"Found particle " <<
ip->pdg_id() <<
" without production vertex! HepMC status = " <<
ip->status());
370 if (vProd && !vEnd &&
ip->status() != 1) {
371 particle_to_fix =
true;
372 ATH_MSG_DEBUG(
"Found particle " <<
ip->pdg_id() <<
" without decay vertex! HepMC status = " <<
ip->status());
374 if (particle_to_fix) semi_disconnected.push_back(
ip);
376 if (abspid == 43 || abspid == 44 || abspid == 30353 || abspid == 30343) {
377 decay_loop_particles.push_back(
ip);
383 if (semi_disconnected.size() == 4 ||semi_disconnected.size() == 3 || semi_disconnected.size() == 2) {
386 double vsum[4] = {0,0,0,0};
387 for (
auto part : semi_disconnected) {
388 if (!
part->production_vertex() ) {
390 vsum[0] +=
part->momentum().px();
391 vsum[1] +=
part->momentum().py();
392 vsum[2] +=
part->momentum().pz();
393 vsum[3] +=
part->momentum().e();
395 if (!
part->end_vertex()) {
397 vsum[0] -=
part->momentum().px();
398 vsum[1] -=
part->momentum().py();
399 vsum[2] -=
part->momentum().pz();
400 vsum[3] -=
part->momentum().e();
403 HepMC::FourVector
sum(vsum[0],vsum[1],vsum[2],vsum[3]);
404 ATH_MSG_INFO(
"Heuristics: found " << semi_disconnected.size() <<
" semi-disconnected particles. Momentum sum is " << vsum[0] <<
" " << vsum[1] <<
" " << vsum[2] <<
" " << vsum[3]);
406 if (no_endv && no_prov && ( no_endv + no_prov == semi_disconnected.size() )) {
407 if (std::abs(
sum.px()) < 1
e-2 && std::abs(
sum.py()) < 1
e-2 && std::abs(
sum.pz()) < 1
e-2 ) {
408 ATH_MSG_INFO(
"Try " << no_endv <<
"->" << no_prov <<
" splitting/merging.");
410 for (
auto part : semi_disconnected) {
411 if (!
part->production_vertex())
v->add_particle_out(
part);
413 for (
auto part : semi_disconnected) {
414 if (!
part->end_vertex())
v->add_particle_in(
part);
425 for (
auto part: decay_loop_particles) {
427 auto vend =
part->end_vertex();
428 auto vprod =
part->production_vertex();
429 if (!vend || !vprod)
continue;
430 bool loop_in_decay =
true;
432 std::vector<HepMC::GenParticlePtr> sisters;
434 for (
auto sister : sisters) {
435 if (vprod != sister->production_vertex()) loop_in_decay =
false;
437 if (!loop_in_decay)
continue;
439 std::vector<HepMC::GenParticlePtr> daughters;
441 for (
auto p : daughters) vprod->add_particle_out(
p);
442 for (
auto sister : sisters) {
443 vprod->remove_particle(sister);
444 vend->remove_particle(sister);
446 evt->remove_vertex(vend);
452 std::vector<HepMC::GenParticlePtr> toremove; toremove.reserve(10);
453 for (HepMC::GenEvent::particle_const_iterator
ip =
evt->particles_begin();
ip !=
evt->particles_end(); ++
ip) {
455 if (*
ip == NULL)
continue;
459 bool bad_particle =
false;
478 int abs_pdg_id = std::abs((*ip)->pdg_id());
479 bool is_decayed_weak_boson = ( abs_pdg_id == 23 || abs_pdg_id == 24 || abs_pdg_id == 25 ) && (*ip)->end_vertex();
488 if (bad_particle) toremove.push_back(*
ip);
492 const int num_particles_orig =
evt->particles_size();
493 int num_orphan_vtxs_orig = 0;
494 int num_noparent_vtxs_orig = 0;
495 int num_nochild_vtxs_orig = 0;
496 for (
auto v =
evt->vertices_begin();
v !=
evt->vertices_end(); ++
v) {
497 if ((*v)->particles_in_size()==0&&(*v)->particles_out_size()==0) num_orphan_vtxs_orig++;
498 if ((*v)->particles_in_size()==0) num_noparent_vtxs_orig++;
499 if ((*v)->particles_out_size()==0) num_nochild_vtxs_orig++;
503 if (!toremove.empty()) {
504 ATH_MSG_DEBUG(
"Cleaning event record of " << toremove.size() <<
" bad particles");
506 int signal_vertex_bc =
evt->signal_process_vertex() ?
evt->signal_process_vertex()->barcode() : 0;
509 if (
evt->barcode_to_vertex (signal_vertex_bc) ==
nullptr) {
510 evt->set_signal_process_vertex (
nullptr);
519 if (
p->status() == 2 && !end_v) {
520 delete p->production_vertex()->remove_particle(
p);
530 const int num_particles_filt =
evt->particles_size();
531 if(num_particles_orig!=num_particles_filt) {
532 int num_orphan_vtxs_filt = 0;
533 int num_noparent_vtxs_filt = 0;
534 int num_nochild_vtxs_filt = 0;
535 for (
auto v =
evt->vertices_begin();
v !=
evt->vertices_end(); ++
v) {
536 if ((*v)->particles_in_size()==0&&(*v)->particles_out_size()==0) num_orphan_vtxs_filt++;
537 if ((*v)->particles_in_size()==0) num_noparent_vtxs_filt++;
538 if ((*v)->particles_out_size()==0) num_nochild_vtxs_filt++;
542 ATH_MSG_INFO(
"Particles filtered: " << num_particles_orig <<
" -> " << num_particles_filt);
544 if (num_orphan_vtxs_filt != num_orphan_vtxs_orig)
545 ATH_MSG_WARNING(
"Change in orphaned vertices: " << num_orphan_vtxs_orig <<
" -> " << num_orphan_vtxs_filt);
546 if (num_noparent_vtxs_filt != num_noparent_vtxs_orig)
547 ATH_MSG_WARNING(
"Change in no-parent vertices: " << num_noparent_vtxs_orig <<
" -> " << num_noparent_vtxs_filt);
548 if (num_nochild_vtxs_filt != num_nochild_vtxs_orig)
549 ATH_MSG_WARNING(
"Change in no-parent vertices: " << num_nochild_vtxs_orig <<
" -> " << num_nochild_vtxs_filt);
553 return StatusCode::SUCCESS;
566 return StatusCode::SUCCESS;
575 return p->pdg_id() == 0;
580 if (!
p)
return false;
581 auto v=
p->production_vertex();
582 if (!
v)
return false;
584 for (
const auto& anc:
v->particles_in()) {
587 if (storage->find(
p->id()) != storage->end())
return false;
588 storage->insert(
p->id());
589 for (
const auto& anc:
v->particles_in()) {
590 if (
fromDecay(anc, storage))
return true;
593 for (
auto anc=
v->particles_in_const_begin(); anc !=
v->particles_in_const_end(); ++anc) {
596 if (storage->find(
p->barcode()) != storage->end())
return false;
597 storage->insert(
p->barcode());
598 for (
auto anc=
v->particles_in_const_begin(); anc !=
v->particles_in_const_end(); ++anc){
599 if (
fromDecay(*anc, storage))
return true;
607 auto storage = std::make_shared<std::set<int>>();
613 return (
p->production_vertex() ==
p->end_vertex() &&
p->end_vertex() !=
nullptr);