@@ -21,15 +21,18 @@ using namespace fastjet;
2121
2222/// Pythia8 event generator for pp collisions
2323/// Selection of events with Xi or Omega inside jets with pt > 10 GeV
24+ /// Jets built from physical primaries OR HF decay products
2425
2526class GeneratorPythia8StrangeInJet : public o2 ::eventgen ::GeneratorPythia8 {
2627public :
2728 /// Constructor
28- GeneratorPythia8StrangeInJet (double ptJetThreshold = 10.0 , double jetR = 0.4 , int gapSize = 4 )
29+ GeneratorPythia8StrangeInJet (double ptJetThreshold = 10.0 ,
30+ double jetR = 0.4 ,
31+ int gapSize = 4 )
2932 : o2 ::eventgen ::GeneratorPythia8 (),
30- mPtJetThreshold (ptJetThreshold ),
31- mJetR (jetR ),
32- mGapSize (gapSize )
33+ mPtJetThreshold (ptJetThreshold ),
34+ mJetR (jetR ),
35+ mGapSize (gapSize )
3336 {
3437 fmt ::printf (
3538 ">> Pythia8 generator: Xi/Omega inside jets with ptJet > %.1f GeV, R = %.1f, gap = %d\n" ,
@@ -44,6 +47,42 @@ public:
4447 }
4548
4649protected :
50+ /// Check if particle is physical primary OR from HF decay
51+ bool isPhysicalPrimaryOrFromHF (const Pythia8 ::Particle & p ,
52+ const Pythia8 ::Event & event )
53+ {
54+ // Must be final
55+ if (!p .isFinal ()) {
56+ return false;
57+ }
58+
59+ // Physical primary: no real mother (or beam)
60+ if (p .mother1 () <= 0 ) {
61+ return true;
62+ }
63+
64+ // Walk up ancestry to identify charm or beauty
65+ int motherIdx = p .mother1 ();
66+ while (motherIdx > 0 ) {
67+ const auto& mother = event [motherIdx ];
68+ int absPdg = std ::abs (mother .id ());
69+
70+ // Charm or beauty hadrons
71+ if ((absPdg / 100 == 4 ) || (absPdg / 100 == 5 ) ||
72+ (absPdg / 1000 == 4 ) || (absPdg / 1000 == 5 )) {
73+ return true;
74+ }
75+
76+ // Stop at beam
77+ if (mother .mother1 () <= 0 ) {
78+ break ;
79+ }
80+ motherIdx = mother .mother1 ();
81+ }
82+
83+ return false;
84+ }
85+
4786 bool generateEvent () override {
4887 fmt ::printf (">> Generating event %lu\n" , mGeneratedEvents );
4988
@@ -72,19 +111,25 @@ protected:
72111
73112 bool selectEvent (Pythia8 ::Event & event ) {
74113 const std ::vector < int > pdgXiOmega = {3312 , -3312 , 3334 , -3334 };
114+ const double mpi = 0.1395704 ;
75115
76116 std ::vector < PseudoJet > fjParticles ;
77117
78118 for (int i = 0 ; i < event .size (); ++ i ) {
79- const auto & p = event [i ];
119+ const auto& p = event [i ];
80120
81121 // --- Jet input selection ---
82122 if (!p .isFinal ()) continue ;
83- if (!p .isPrimary ()) continue ;
84123 if (!p .isCharged ()) continue ;
124+ if (!isPhysicalPrimaryOrFromHF (p , event )) continue ;
85125 if (std ::abs (p .eta ()) > 0.8 ) continue ;
86126
87- PseudoJet pj (p .px (), p .py (), p .pz (), p .e ());
127+ double pt = std ::sqrt (p .px () * p .px () + p .py () * p .py ());
128+ if (pt < 0.1 ) continue ;
129+
130+ double energy = std ::sqrt (p .p () * p .p () + mpi * mpi );
131+
132+ PseudoJet pj (p .px (), p .py (), p .pz (), energy );
88133 pj .set_user_index (i ); // map back to Pythia index
89134 fjParticles .push_back (pj );
90135 }
@@ -95,10 +140,11 @@ protected:
95140 ClusterSequence cs (fjParticles , jetDef );
96141 auto jets = sorted_by_pt (cs .inclusive_jets (mPtJetThreshold ));
97142
98- for (const auto & jet : jets ) {
99- for (const auto & c : jet .constituents ()) {
143+ for (const auto& jet : jets ) {
144+ for (const auto& c : jet .constituents ()) {
100145 int idx = c .user_index ();
101146 int pdg = event [idx ].id ();
147+
102148 if (std ::find (pdgXiOmega .begin (), pdgXiOmega .end (), pdg ) != pdgXiOmega .end ()) {
103149 fmt ::printf (
104150 ">> Accepted jet: pt = %.2f, eta = %.2f, phi = %.2f, contains PDG %d\n" ,
@@ -107,6 +153,7 @@ protected:
107153 }
108154 }
109155 }
156+
110157 return false;
111158 }
112159
@@ -116,3 +163,4 @@ private:
116163 int mGapSize {4 };
117164 uint64_t mGeneratedEvents {0 };
118165};
166+
0 commit comments