From c06479cb7266facd84bb3323d72548fd3d9dff8b Mon Sep 17 00:00:00 2001
From: Petr Balek <petr.balek@cern.ch>
Date: Wed, 12 Feb 2025 17:25:56 +0100
Subject: [PATCH 1/2] purge unstable particles from Hijing

---
 .../python/GENtoEVGEN_Skeleton.py             |  3 +-
 .../share/skel.GENtoEVGEN.py                  |  4 +++
 .../EvgenProdTools/EvgenProdTools/FixHepMC.h  |  2 ++
 .../python/EvgenProdToolsConfig.py            |  2 ++
 Generators/EvgenProdTools/src/FixHepMC.cxx    | 36 +++++++++++++++++++
 Generators/Hijing_i/src/Hijing.cxx            | 20 -----------
 6 files changed, 46 insertions(+), 21 deletions(-)

diff --git a/Generators/EvgenJobTransforms/python/GENtoEVGEN_Skeleton.py b/Generators/EvgenJobTransforms/python/GENtoEVGEN_Skeleton.py
index 3ae10202c2de..21e6ce0c2bca 100644
--- a/Generators/EvgenJobTransforms/python/GENtoEVGEN_Skeleton.py
+++ b/Generators/EvgenJobTransforms/python/GENtoEVGEN_Skeleton.py
@@ -239,7 +239,8 @@ def fromRunArgs(runArgs):
     
     # Fix non-standard event features
     from EvgenProdTools.EvgenProdToolsConfig import FixHepMCCfg
-    cfg.merge(FixHepMCCfg(flags))
+    cfg.merge(FixHepMCCfg(flags, 
+                          PurgeUnstableWithoutEndVtx = "Hijing" in sample.generators))
 
     ## Sanity check the event record (not appropriate for all generators)
     from GeneratorConfig.GenConfigHelpers import gens_testhepmc
diff --git a/Generators/EvgenJobTransforms/share/skel.GENtoEVGEN.py b/Generators/EvgenJobTransforms/share/skel.GENtoEVGEN.py
index c36845e63a50..e51307d748ab 100644
--- a/Generators/EvgenJobTransforms/share/skel.GENtoEVGEN.py
+++ b/Generators/EvgenJobTransforms/share/skel.GENtoEVGEN.py
@@ -501,6 +501,10 @@ else:
 # Propagate DSID and seed to the generators
    include("EvgenJobTransforms/Generate_dsid_ranseed.py")
 
+## Purge unstable particle w/o end vertex occasionally produced by Hijing
+if 'Hijing' in evgenConfig.generators:
+    fixSeq.FixHepMC.PurgeUnstableWithoutEndVtx = True
+
 ## Propagate debug output level requirement to generators
 if (hasattr( runArgs, "VERBOSE") and runArgs.VERBOSE ) or (hasattr( runArgs, "loglevel") and runArgs.loglevel == "DEBUG") or (hasattr( runArgs, "loglevel") and runArgs.loglevel == "VERBOSE"):
    include("EvgenJobTransforms/Generate_debug_level.py")
diff --git a/Generators/EvgenProdTools/EvgenProdTools/FixHepMC.h b/Generators/EvgenProdTools/EvgenProdTools/FixHepMC.h
index 92cba96c3a92..0e4e94819cc1 100644
--- a/Generators/EvgenProdTools/EvgenProdTools/FixHepMC.h
+++ b/Generators/EvgenProdTools/EvgenProdTools/FixHepMC.h
@@ -51,6 +51,7 @@ private:
   bool m_killLoops;   // Kill loops?
   bool m_killPDG0;    // Kill PDG0 particles?
   bool m_cleanDecays; // Clean decays?
+  bool m_purgeUnstableWithoutEndVtx; // Remove unstable particles without decay vertex?
   //@}
 
   /// @name Cleaned-particle counters
@@ -58,6 +59,7 @@ private:
   long m_loopKilled;
   long m_pdg0Killed;
   long m_decayCleaned;
+  long m_unstablePurged;
   long m_totalSeen;
   long m_replacedPIDs;
   //@}
diff --git a/Generators/EvgenProdTools/python/EvgenProdToolsConfig.py b/Generators/EvgenProdTools/python/EvgenProdToolsConfig.py
index f2573a92f3a2..df0d2b3d107c 100644
--- a/Generators/EvgenProdTools/python/EvgenProdToolsConfig.py
+++ b/Generators/EvgenProdTools/python/EvgenProdToolsConfig.py
@@ -17,6 +17,8 @@ def TestHepMCCfg(flags, name="TestHepMC", streamName="TestHepMCname", fileName="
 
 
 def FixHepMCCfg(flags, name="FixHepMC", **kwargs):
+    kwargs.setdefault("PurgeUnstableWithoutEndVtx", False)
+
     acc = ComponentAccumulator(EvgenSequenceFactory(EvgenSequence.Fix))
     acc.addEventAlgo(CompFactory.FixHepMC(name, **kwargs))
     return acc
diff --git a/Generators/EvgenProdTools/src/FixHepMC.cxx b/Generators/EvgenProdTools/src/FixHepMC.cxx
index 98733132d072..dbe9f195490e 100644
--- a/Generators/EvgenProdTools/src/FixHepMC.cxx
+++ b/Generators/EvgenProdTools/src/FixHepMC.cxx
@@ -16,12 +16,14 @@ FixHepMC::FixHepMC(const std::string& name, ISvcLocator* pSvcLocator)
   , m_loopKilled(0)
   , m_pdg0Killed(0)
   , m_decayCleaned(0)
+  , m_unstablePurged(0)
   , m_totalSeen(0)
   , m_replacedPIDs(0)
 {
   declareProperty("KillLoops", m_killLoops = true, "Remove particles in loops?");
   declareProperty("KillPDG0", m_killPDG0 = true, "Remove particles with PDG ID 0?");
   declareProperty("CleanDecays", m_cleanDecays = true, "Clean decay chains from non-propagating particles?");
+  declareProperty("PurgeUnstableWithoutEndVtx", m_purgeUnstableWithoutEndVtx = false, "Remove unstable particles without decay vertex?");
   declareProperty("PIDmap", m_pidmap = std::map<int,int>(), "Map of PDG IDs to replace");
 }
 #ifndef HEPMC3
@@ -271,6 +273,24 @@ StatusCode FixHepMC::execute() {
     // Properties before cleaning
     const int num_particles_orig = evt->particles().size();
     for (auto part: toremove) evt->remove_particle(part);
+
+    if(m_purgeUnstableWithoutEndVtx) {
+      int purged=0;
+      do {
+        purged=0;
+        const std::vector <HepMC::GenParticlePtr> allParticles=evt->particles();
+        for(auto p : allParticles) {
+          HepMC::ConstGenVertexPtr end_v=p->end_vertex();
+          if(p->status() == 2 && !end_v) {
+            evt->remove_particle(p);
+            ++purged;
+            ++m_unstablePurged;
+          } 
+        }
+      }
+      while (purged>0);
+    }
+
     const int num_particles_filt = evt->particles().size();
      // Write out the change in the number of particles
     ATH_MSG_INFO("Particles filtered: " << num_particles_orig << " -> " << num_particles_filt);
@@ -453,6 +473,21 @@ StatusCode FixHepMC::execute() {
       evt->set_signal_process_vertex (nullptr);
     }
 
+    if(m_purgeUnstableWithoutEndVtx) {
+      int purged=0;
+      do {
+        for (HepMC::GenParticle* p : *evt) {
+          HepMC::ConstGenVertexPtr end_v = p->end_vertex();
+          if (p->status() == 2 && !end_v) {
+            delete p->production_vertex()->remove_particle(p);
+            ++purged;
+            ++m_unstablePurged;
+          }
+        }
+      }
+      while (purged>0);
+    }
+
     // Properties after cleaning
     const int num_particles_filt = evt->particles_size();
     int num_orphan_vtxs_filt = 0;
@@ -484,6 +519,7 @@ StatusCode FixHepMC::finalize() {
   if (m_killLoops  ) ATH_MSG_INFO( "Removed " <<   m_loopKilled << " of " << m_totalSeen << " particles because of loops." );
   if (m_killPDG0   ) ATH_MSG_INFO( "Removed " <<   m_pdg0Killed << " of " << m_totalSeen << " particles because of PDG ID 0." );
   if (m_cleanDecays) ATH_MSG_INFO( "Removed " << m_decayCleaned << " of " << m_totalSeen << " particles while cleaning decay chains." );
+  if(m_purgeUnstableWithoutEndVtx) ATH_MSG_INFO( "Removed " << m_unstablePurged << " of " << m_totalSeen << " unstable particles because they had no decay vertex." );
   if (!m_pidmap.empty()) ATH_MSG_INFO( "Replaced " << m_replacedPIDs << "PIDs of particles." );
   return StatusCode::SUCCESS;
 }
diff --git a/Generators/Hijing_i/src/Hijing.cxx b/Generators/Hijing_i/src/Hijing.cxx
index 79a78619ec54..9c70daf5fa80 100644
--- a/Generators/Hijing_i/src/Hijing.cxx
+++ b/Generators/Hijing_i/src/Hijing.cxx
@@ -737,26 +737,6 @@ Hijing::fillEvt(HepMC::GenEvent* evt)
     }
     //BPK-<
 
-    //ARA -- ATLHI-483, clean up unstable particles with no decay vertex
-#ifdef HEPMC3
-    if(m_keepAllDecayVertices)
-    {
-      const std::vector <HepMC::GenParticlePtr> allParticles=evt->particles();
-      for(auto p : allParticles)
-      {
-        HepMC::ConstGenVertexPtr end_v=p->end_vertex();
-        if(p->status() == 2 && !end_v) evt->remove_particle(p);
-      }
-    }
-#else
-    if(m_keepAllDecayVertices)  
-    {
-      for (HepMC::GenParticle* p : *evt) {
-        HepMC::ConstGenVertexPtr end_v = p->end_vertex();
-        if (p->status() == 2 && !end_v) delete p->production_vertex()->remove_particle(p);
-      }
-    }
-#endif
     return StatusCode::SUCCESS;
 }
 
-- 
GitLab


From c423acdd19a8a5e7fb1447a3cd6e35f3f32dc258 Mon Sep 17 00:00:00 2001
From: Petr Balek <petr.balek@cern.ch>
Date: Wed, 12 Feb 2025 23:47:01 +0100
Subject: [PATCH 2/2] purge unstable particles from Hijing

---
 .../python/EvgenProdToolsConfig.py            |  2 -
 Generators/EvgenProdTools/src/FixHepMC.cxx    | 75 ++++++++++---------
 2 files changed, 41 insertions(+), 36 deletions(-)

diff --git a/Generators/EvgenProdTools/python/EvgenProdToolsConfig.py b/Generators/EvgenProdTools/python/EvgenProdToolsConfig.py
index df0d2b3d107c..f2573a92f3a2 100644
--- a/Generators/EvgenProdTools/python/EvgenProdToolsConfig.py
+++ b/Generators/EvgenProdTools/python/EvgenProdToolsConfig.py
@@ -17,8 +17,6 @@ def TestHepMCCfg(flags, name="TestHepMC", streamName="TestHepMCname", fileName="
 
 
 def FixHepMCCfg(flags, name="FixHepMC", **kwargs):
-    kwargs.setdefault("PurgeUnstableWithoutEndVtx", False)
-
     acc = ComponentAccumulator(EvgenSequenceFactory(EvgenSequence.Fix))
     acc.addEventAlgo(CompFactory.FixHepMC(name, **kwargs))
     return acc
diff --git a/Generators/EvgenProdTools/src/FixHepMC.cxx b/Generators/EvgenProdTools/src/FixHepMC.cxx
index dbe9f195490e..71aeab7092bc 100644
--- a/Generators/EvgenProdTools/src/FixHepMC.cxx
+++ b/Generators/EvgenProdTools/src/FixHepMC.cxx
@@ -267,12 +267,14 @@ StatusCode FixHepMC::execute() {
       if (bad_particle) toremove.push_back(ip);
     }
 
-    // Escape here if there's nothing more to do, otherwise do the cleaning
-    if (toremove.empty()) continue;
-    ATH_MSG_DEBUG("Cleaning event record of " << toremove.size() << " bad particles");
     // Properties before cleaning
     const int num_particles_orig = evt->particles().size();
-    for (auto part: toremove) evt->remove_particle(part);
+
+    // Do the cleaning
+    if (!toremove.empty()) {
+      ATH_MSG_DEBUG("Cleaning event record of " << toremove.size() << " bad particles");
+      for (auto part: toremove) evt->remove_particle(part);
+    }
 
     if(m_purgeUnstableWithoutEndVtx) {
       int purged=0;
@@ -292,8 +294,11 @@ StatusCode FixHepMC::execute() {
     }
 
     const int num_particles_filt = evt->particles().size();
-     // Write out the change in the number of particles
-    ATH_MSG_INFO("Particles filtered: " << num_particles_orig << " -> " << num_particles_filt);
+
+    if(num_particles_orig!=num_particles_filt) {
+      // Write out the change in the number of particles
+      ATH_MSG_INFO("Particles filtered: " << num_particles_orig << " -> " << num_particles_filt);
+    }
  #else
 
     // Add a unit entry to the event weight vector if it's currently empty
@@ -451,10 +456,6 @@ StatusCode FixHepMC::execute() {
       if (bad_particle) toremove.push_back(*ip);
     }
 
-    // Escape here if there's nothing more to do, otherwise do the cleaning
-    if (toremove.empty()) continue;
-    ATH_MSG_DEBUG("Cleaning event record of " << toremove.size() << " bad particles");
-
     // Properties before cleaning
     const int num_particles_orig = evt->particles_size();
     int num_orphan_vtxs_orig = 0;
@@ -465,12 +466,17 @@ StatusCode FixHepMC::execute() {
       if ((*v)->particles_in_size()==0) num_noparent_vtxs_orig++;
       if ((*v)->particles_out_size()==0) num_nochild_vtxs_orig++;
     }
-    // Clean!
-    int signal_vertex_bc = evt->signal_process_vertex() ? evt->signal_process_vertex()->barcode() : 0;
-    //This is the only place where reduce is used.
-    reduce(evt , toremove);
-    if (evt->barcode_to_vertex (signal_vertex_bc) == nullptr) {
-      evt->set_signal_process_vertex (nullptr);
+
+    // Do the cleaning
+    if (!toremove.empty()) {
+      ATH_MSG_DEBUG("Cleaning event record of " << toremove.size() << " bad particles");
+      // Clean!
+      int signal_vertex_bc = evt->signal_process_vertex() ? evt->signal_process_vertex()->barcode() : 0;
+      //This is the only place where reduce is used.
+      reduce(evt , toremove);
+      if (evt->barcode_to_vertex (signal_vertex_bc) == nullptr) {
+        evt->set_signal_process_vertex (nullptr);
+      }
     }
 
     if(m_purgeUnstableWithoutEndVtx) {
@@ -490,25 +496,26 @@ StatusCode FixHepMC::execute() {
 
     // Properties after cleaning
     const int num_particles_filt = evt->particles_size();
-    int num_orphan_vtxs_filt = 0;
-    int num_noparent_vtxs_filt = 0;
-    int num_nochild_vtxs_filt = 0;
-    for (auto v = evt->vertices_begin(); v != evt->vertices_end(); ++v) {
-      if ((*v)->particles_in_size()==0&&(*v)->particles_out_size()==0) num_orphan_vtxs_filt++;
-      if ((*v)->particles_in_size()==0) num_noparent_vtxs_filt++;
-      if ((*v)->particles_out_size()==0) num_nochild_vtxs_filt++;
+    if(num_particles_orig!=num_particles_filt) {
+      int num_orphan_vtxs_filt = 0;
+      int num_noparent_vtxs_filt = 0;
+      int num_nochild_vtxs_filt = 0;
+      for (auto v = evt->vertices_begin(); v != evt->vertices_end(); ++v) {
+        if ((*v)->particles_in_size()==0&&(*v)->particles_out_size()==0) num_orphan_vtxs_filt++;
+        if ((*v)->particles_in_size()==0) num_noparent_vtxs_filt++;
+        if ((*v)->particles_out_size()==0) num_nochild_vtxs_filt++;
+      }
+
+      // Write out the change in the number of particles
+      ATH_MSG_INFO("Particles filtered: " << num_particles_orig << " -> " << num_particles_filt);
+      // Warn if the numbers of "strange" vertices have changed
+      if (num_orphan_vtxs_filt != num_orphan_vtxs_orig)
+        ATH_MSG_WARNING("Change in orphaned vertices: " << num_orphan_vtxs_orig << " -> " << num_orphan_vtxs_filt);
+      if (num_noparent_vtxs_filt != num_noparent_vtxs_orig)
+        ATH_MSG_WARNING("Change in no-parent vertices: " << num_noparent_vtxs_orig << " -> " << num_noparent_vtxs_filt);
+      if (num_nochild_vtxs_filt != num_nochild_vtxs_orig)
+        ATH_MSG_WARNING("Change in no-parent vertices: " << num_nochild_vtxs_orig << " -> " << num_nochild_vtxs_filt);
     }
-
-    // Write out the change in the number of particles
-    ATH_MSG_INFO("Particles filtered: " << num_particles_orig << " -> " << num_particles_filt);
-    // Warn if the numbers of "strange" vertices have changed
-    if (num_orphan_vtxs_filt != num_orphan_vtxs_orig)
-      ATH_MSG_WARNING("Change in orphaned vertices: " << num_orphan_vtxs_orig << " -> " << num_orphan_vtxs_filt);
-    if (num_noparent_vtxs_filt != num_noparent_vtxs_orig)
-      ATH_MSG_WARNING("Change in no-parent vertices: " << num_noparent_vtxs_orig << " -> " << num_noparent_vtxs_filt);
-    if (num_nochild_vtxs_filt != num_nochild_vtxs_orig)
-      ATH_MSG_WARNING("Change in no-parent vertices: " << num_nochild_vtxs_orig << " -> " << num_nochild_vtxs_filt);
-
 #endif
   }
   return StatusCode::SUCCESS;
-- 
GitLab