From 087a8f43c4faceedab70410f07c5eea3e99738ff Mon Sep 17 00:00:00 2001
From: John Chapman <John.Chapman@cern.ch>
Date: Wed, 4 Dec 2024 12:16:22 +0100
Subject: [PATCH 1/6] AtlasPID: Re-order helper function definitions ahead of
 fixing the definition of isValid function

---
 Generators/TruthUtils/TruthUtils/AtlasPID.h | 36 +++++++++++++--------
 1 file changed, 22 insertions(+), 14 deletions(-)

diff --git a/Generators/TruthUtils/TruthUtils/AtlasPID.h b/Generators/TruthUtils/TruthUtils/AtlasPID.h
index 9aaf1cdb2314..591e99b28bd2 100644
--- a/Generators/TruthUtils/TruthUtils/AtlasPID.h
+++ b/Generators/TruthUtils/TruthUtils/AtlasPID.h
@@ -180,18 +180,6 @@ template<> inline bool isNeutrino(const int& p){ auto sp = std::abs(p); return s
 template<class T> inline bool isSMNeutrino(const T& p){return isSMNeutrino(p->pdg_id());}
 template<> inline bool isSMNeutrino(const int& p){ auto sp = std::abs(p); return sp == NU_E || sp == NU_MU || sp == NU_TAU;  }
 
-template<class T> inline bool isGluon(const T& p){return isGluon(p->pdg_id());}
-template<> inline bool isGluon(const int& p){ return p == GLUON; }
-
-template<class T> inline bool isPhoton(const T& p){return isPhoton(p->pdg_id());}
-template<> inline bool isPhoton(const int& p){ return p == PHOTON; }
-
-template<class T> inline bool isZ(const T& p){return isZ(p->pdg_id());}
-template<> inline bool isZ(const int& p){ return p == Z0BOSON; }
-
-template<class T> inline bool isW(const T& p){return isW(p->pdg_id());}
-template<> inline bool isW(const int& p){ return std::abs(p) == WPLUSBOSON; }
-
 /// PDG rule 4
 /// Diquarks have 4-digit numbers with nq1 >= nq2 and nq3 = 0
 /// APID: the diquarks with fourth generation are not diquarks
@@ -312,12 +300,14 @@ template<class T> inline bool isHadron(const T& p){return isHadron(p->pdg_id());
 template<> inline bool isHadron(const DecodedPID& p){ return isMeson(p) || isBaryon(p) || isTetraquark(p) || isPentaquark(p); }
 template<> inline bool isHadron(const int& p){ auto value_digits = DecodedPID(p); return isHadron(value_digits);}
 
+
 /// PDG rule 8:
 /// The pomeron and odderon trajectories and a generic reggeon trajectory
 /// of states in QCD areassigned codes 990, 9990, and 110 respectively
 template<class T> inline bool isTrajectory(const T& p){return isTrajectory(p->pdg_id());}
 template<> inline bool isTrajectory(const int& p){ return std::abs(p) == POMERON || std::abs(p) == ODDERON || std::abs(p) == REGGEON; }
 
+
 /// PDG rule 9:
 /// Two-digit numbers in the range 21–30 are provided for the Standard
 /// Model gauge and Higgs bosons.
@@ -328,15 +318,33 @@ template<class T> inline bool isBoson(const T& p){return isBoson(p->pdg_id());}
 template<> inline bool isBoson(const int& p){ auto sp = std::abs(p); return sp > 20 && sp < 41; }
 template<> inline bool isBoson(const DecodedPID& p){ return isBoson(p.pid()); }
 
+template<class T> inline bool isGluon(const T& p){return isGluon(p->pdg_id());}
+template<> inline bool isGluon(const int& p){ return p == GLUON; }
+
+template<class T> inline bool isPhoton(const T& p){return isPhoton(p->pdg_id());}
+template<> inline bool isPhoton(const int& p){ return p == PHOTON; }
+
+template<class T> inline bool isZ(const T& p){return isZ(p->pdg_id());}
+template<> inline bool isZ(const int& p){ return p == Z0BOSON; }
+
+template<class T> inline bool isW(const T& p){return isW(p->pdg_id());}
+template<> inline bool isW(const int& p){ return std::abs(p) == WPLUSBOSON; }
+
 /// APID: HIGGS boson is only one particle.
 template<class T> inline bool isHiggs(const T& p){return isHiggs(p->pdg_id());}
 template<> inline bool isHiggs(const int& p){ return p == HIGGSBOSON; }
 
-template<class T> inline bool isResonance(const T& p) { return isZ(p) || isW(p) || isHiggs(p) || isTop(p); } // APID: not including t' (pdg_id=8)
-
 template<class T> inline bool isGraviton(const T& p) {return isGraviton(p->pdg_id());}
 template<> inline bool isGraviton(const int& p){ return p == GRAVITON; }
 
+template<class T> inline bool isResonance(const T& p) { return isZ(p) || isW(p) || isHiggs(p) || isTop(p); } // APID: not including t' (pdg_id=8)
+
+/// PDG rule 11c:
+/// “One-of-a-kind” exotic particles are assigned numbers in the range
+/// 41–80. The subrange 61-80 can be used for new heavier fermions in
+/// generic models, where partners to the SM fermions would have codes
+/// offset by 60. If required, however, other assignments could be
+/// made.
 template<class T> inline bool isLeptoQuark(const T& p){return isLeptoQuark(p->pdg_id());}
 template<> inline bool isLeptoQuark(const int& p){ return std::abs(p) == LEPTOQUARK; }
 
-- 
GitLab


From fe4f2b1cbf8d48d3e3ab9e7e0c884cf21a353252 Mon Sep 17 00:00:00 2001
From: John Chapman <John.Chapman@cern.ch>
Date: Fri, 6 Dec 2024 13:49:00 +0100
Subject: [PATCH 2/6] AtlasPID: isBSM reorder checks in terms of most used
 models in ATLAS.

---
 Generators/TruthUtils/TruthUtils/AtlasPID.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Generators/TruthUtils/TruthUtils/AtlasPID.h b/Generators/TruthUtils/TruthUtils/AtlasPID.h
index 591e99b28bd2..88be40fb1914 100644
--- a/Generators/TruthUtils/TruthUtils/AtlasPID.h
+++ b/Generators/TruthUtils/TruthUtils/AtlasPID.h
@@ -594,11 +594,11 @@ template<> inline bool isBSM(const DecodedPID& p){
   if (std::abs(p.pid()) > 39 && std::abs(p.pid()) < 81) return true;
   if (std::abs(p.pid()) > 6 && std::abs(p.pid()) < 9) return true;
   if (isSUSY(p)) return true;
+  if (isGenericMultichargedParticle(p)) return true;
   if (isTechnicolor(p)) return true;
   if (isExcited(p)) return true;
   if (isKK(p)) return true;
   if (isHiddenValley(p)) return true;
-  if (isGenericMultichargedParticle(p)) return true;
   return false;
 }
 template<> inline bool isBSM(const int& p){
-- 
GitLab


From beceb47e7cfbd84b2d9243ffbb2e2b15efd40e19 Mon Sep 17 00:00:00 2001
From: John Chapman <John.Chapman@cern.ch>
Date: Wed, 4 Dec 2024 12:18:12 +0100
Subject: [PATCH 3/6] AtlasPID: redefinition is isHiddenValley

---
 Generators/TruthUtils/TruthUtils/AtlasPID.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/Generators/TruthUtils/TruthUtils/AtlasPID.h b/Generators/TruthUtils/TruthUtils/AtlasPID.h
index 88be40fb1914..1b5731b870b6 100644
--- a/Generators/TruthUtils/TruthUtils/AtlasPID.h
+++ b/Generators/TruthUtils/TruthUtils/AtlasPID.h
@@ -557,7 +557,8 @@ template<> inline bool isDM(const int& p){ auto sp = std::abs(p); return (sp >=
 /// as far as possible. Thus 4900021 is the gauge boson g_v of a confining gauge field, 490000n_{q_v} and 490001n_{l_v} fundamental
 /// constituents charged or not under this, 4900022 is the γ_v of a non-confining field, and 4900n_{q_{v1}}n_{q_{v2}}n_J a Hidden Valley meson.
 template<class T> inline bool isHiddenValley(const T& p){return isHiddenValley(p->pdg_id());}
-template<> inline bool isHiddenValley(const DecodedPID& p){return (p.ndigits() == 7 &&  p(0) == 4 && p(1) == 9 && isValid(p.shift(2)));}
+template<> inline bool isHiddenValley(const DecodedPID& p){ auto pp = (p.ndigits()==7) ? p.shift(2) : DecodedPID(0);  return (p.ndigits() == 7 &&  p(0) == 4 && p(1) == 9 &&
+                                                                                           ( isQuark(pp) || isLepton(pp) || isBoson(pp) || isGlueball(pp) || isDiquark(pp) || isHadron(pp) ) ); }
 template<> inline bool isHiddenValley(const int& p){ auto value_digits = DecodedPID(p); return isHiddenValley(value_digits);}
 
 /// In addition, there is a need to identify ”Q-ball” and similar very exotic (multi-charged) particles which may have large, non-integer charge.
-- 
GitLab


From b47dbe5ea11609f8ac1d2746ff8808c0a18e3583 Mon Sep 17 00:00:00 2001
From: John Chapman <John.Chapman@cern.ch>
Date: Wed, 4 Dec 2024 12:19:54 +0100
Subject: [PATCH 4/6] AtlasPID: redefinition is isTechnicolor

---
 Generators/TruthUtils/TruthUtils/AtlasPID.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/Generators/TruthUtils/TruthUtils/AtlasPID.h b/Generators/TruthUtils/TruthUtils/AtlasPID.h
index 1b5731b870b6..9678e955829c 100644
--- a/Generators/TruthUtils/TruthUtils/AtlasPID.h
+++ b/Generators/TruthUtils/TruthUtils/AtlasPID.h
@@ -454,7 +454,8 @@ template<> inline bool isGaugino(const int& p){ auto value_digits = DecodedPID(p
 /// the quantum numbers are specified by tech, ij, where i and j are 1 or 2. nLis then 2i+j. The coloron
 /// V8, is a heavy gluon color octet and thus is 3100021
 template<class T> inline bool isTechnicolor(const T& p){return isTechnicolor(p->pdg_id());}
-template<> inline bool isTechnicolor(const DecodedPID& p){return (p.ndigits() == 7 &&  p(0) == 3 && (p(1) == 0 || p(0) == 1) && isValid(p.shift(2)) && !isGenSpecific(p.shift(2).pid()));}
+template<> inline bool isTechnicolor(const DecodedPID& p){ auto pp = (p.ndigits()==7) ? p.shift(2) : DecodedPID(0); return (p.ndigits() == 7 &&  p(0) == 3 && (p(1) == 0 || p(0) == 1) &&
+                                                                                           ( isQuark(pp) || isLepton(pp) || isBoson(pp) || isGlueball(pp) || isDiquark(pp) || isHadron(pp) ) ); }
 template<> inline bool isTechnicolor(const int& p){ auto value_digits = DecodedPID(p); return isTechnicolor(value_digits);}
 
 /// PDG rule 11f
-- 
GitLab


From 39b97cde9fc1a7cfe0d60b4019156a4c9658e009 Mon Sep 17 00:00:00 2001
From: John Chapman <John.Chapman@cern.ch>
Date: Fri, 6 Dec 2024 13:48:21 +0100
Subject: [PATCH 5/6] AtlasPID: Redefinition of isExcited helper function

---
 Generators/TruthUtils/TruthUtils/AtlasPID.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Generators/TruthUtils/TruthUtils/AtlasPID.h b/Generators/TruthUtils/TruthUtils/AtlasPID.h
index 9678e955829c..eee68ac64922 100644
--- a/Generators/TruthUtils/TruthUtils/AtlasPID.h
+++ b/Generators/TruthUtils/TruthUtils/AtlasPID.h
@@ -461,7 +461,7 @@ template<> inline bool isTechnicolor(const int& p){ auto value_digits = DecodedP
 /// PDG rule 11f
 /// Excited (composite) quarks and leptons are identified by setting n= 4 and nr= 0
 template<class T> inline bool isExcited(const T& p){return isExcited(p->pdg_id());}
-template<> inline bool isExcited(const DecodedPID& p){return (p.ndigits() == 7 && (p(0) == 4 && p(1) == 0 ) && (isLepton(p.shift(2))||isQuark(p.shift(2))) );}
+template<> inline bool isExcited(const DecodedPID& p){ auto pp = (p.ndigits()==7) ? p.shift(2) : DecodedPID(0); return (p.ndigits() == 7 && (p(0) == 4 && p(1) == 0 ) && (isLepton(pp) || isQuark(pp)) );}
 template<> inline bool isExcited(const int& p){ auto value_digits = DecodedPID(p); return isExcited(value_digits);}
 
 /// PDG rule 11g:
-- 
GitLab


From 36d91e358efc5dcee16264dcb3612158a2d8619b Mon Sep 17 00:00:00 2001
From: John Chapman <John.Chapman@cern.ch>
Date: Wed, 4 Dec 2024 14:02:59 +0100
Subject: [PATCH 6/6] AtlasPID: Expand the definition of isValid to cover all
 known valid pdg_ids

---
 Generators/TruthUtils/TruthUtils/AtlasPID.h | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/Generators/TruthUtils/TruthUtils/AtlasPID.h b/Generators/TruthUtils/TruthUtils/AtlasPID.h
index eee68ac64922..56fbfd2329ba 100644
--- a/Generators/TruthUtils/TruthUtils/AtlasPID.h
+++ b/Generators/TruthUtils/TruthUtils/AtlasPID.h
@@ -348,9 +348,6 @@ template<class T> inline bool isResonance(const T& p) { return isZ(p) || isW(p)
 template<class T> inline bool isLeptoQuark(const T& p){return isLeptoQuark(p->pdg_id());}
 template<> inline bool isLeptoQuark(const int& p){ return std::abs(p) == LEPTOQUARK; }
 
-template<class T> inline bool isValid(const T& p){return isValid(p->pdg_id());}
-template<> inline bool isValid(const DecodedPID& p);
-
 template<class T> inline bool isPythia8Specific(const T& p){return isPythia8Specific(p->pdg_id());}
 template<> inline bool isPythia8Specific(const DecodedPID& p){ return (p.ndigits() == 7 && p(0) == 9 && p(1) == 9);}
 template<> inline bool isPythia8Specific(const int& p){ auto value_digits = DecodedPID(p); return isPythia8Specific(value_digits);}
@@ -617,7 +614,12 @@ template<> inline bool isTransportable(const DecodedPID& p){ return isPhoton(p.p
 template<> inline bool isTransportable(const int& p){ auto value_digits = DecodedPID(p); return isTransportable(value_digits);}
 
 /// Av: we implement here an ATLAS-sepcific convention: all particles which are 99xxxxx are fine.
-template<> inline bool isValid(const DecodedPID& p){ return isHadron(p) || isTrajectory(p.pid()) || isDiquark(p) || isBSM(p) || isNucleus(p) || (std::abs(p.pid()) < 42) || isGenSpecific(p.pid()) || isGeantino(p.pid()) || isPythia8Specific(p) || isGlueball(p); }
+template<class T> inline bool isValid(const T& p){return isValid(p->pdg_id());}
+template<> inline bool isValid(const DecodedPID& p){
+  return p.pid() !=0 && ( isQuark(p) || isLepton(p) || isBoson(p) || isGlueball(p) ||
+                         isTrajectory(p.pid()) || isGenSpecific(p.pid()) || isDiquark(p) ||
+                         isBSM(p) || isHadron(p) || isNucleus(p) || isGeantino(p.pid()) ||
+                         isPythia8Specific(p) ); }
 template<> inline bool isValid(const int& p){ if (!p) return false; if (std::abs(p) < 42) return true;
   if (isGenSpecific(p)) return true;
   auto value_digits = DecodedPID(p); return isValid(value_digits);
-- 
GitLab