1+ #if !defined(__CLING__ ) || defined(__ROOTCLING__ )
12#include "FairGenerator.h"
23#include "FairPrimaryGenerator.h"
34#include "Generators/GeneratorPythia8.h"
4-
55#include "Pythia8/Pythia.h"
6-
7- #include <fastjet/PseudoJet.hh>
8- #include <fastjet/JetDefinition.hh>
9- #include <fastjet/ClusterSequence.hh>
10-
6+ #include "TDatabasePDG.h"
7+ #include "TMath.h"
8+ #include "TParticlePDG.h"
9+ #include "TRandom3.h"
10+ #include "TSystem.h"
11+ #include "TVector2.h"
12+ #include "fairlogger/Logger.h"
1113#include <cmath>
12- #include <vector >
14+ #include <fstream >
1315#include <string>
14- #include <algorithm>
15-
16+ #include <vector>
1617using namespace Pythia8 ;
17- using namespace fastjet ;
18+ #endif
1819
19- /// Pythia8 event generator for pp collisions
20- /// Selection of events with Xi or Omega inside jets with pt > 10 GeV
21- /// Jets built from physical primaries OR HF decay products
20+ /// Event generator using Pythia ropes for Ξ and Ω production in jets.
21+ /// Jets are defined as particles within a cone around the highest-pT particle
22+ /// (approximate jet axis) and include charged final-state particles that are
23+ /// either physical primaries or from heavy-flavor decays.
24+ /// Jets must be fully within the acceptance and have pT > 10 GeV.
25+ /// One event of interest is generated after 4 minimum-bias events.
2226
23- class GeneratorPythia8StrangeInJet : public o2 ::eventgen ::GeneratorPythia8 {
27+ class GeneratorPythia8StrangenessInJet : public o2 ::eventgen ::GeneratorPythia8 {
2428public :
2529 /// Constructor
26- GeneratorPythia8StrangeInJet (double ptJetThreshold = 10.0 ,
27- double jetR = 0.4 ,
28- int gapSize = 4 )
30+ GeneratorPythia8StrangenessInJet (double ptJetMin = 10.0 , double Rjet = 0.4 , int gapSize = 4 )
2931 : o2 ::eventgen ::GeneratorPythia8 (),
30- mPtJetThreshold ( ptJetThreshold ),
31- mJetR ( jetR ),
32+ mptJetMin ( ptJetMin ),
33+ mRjet ( Rjet ),
3234 mGapSize (gapSize )
3335 {
3436 fmt ::printf (
35- ">> Pythia8 generator: Xi/Omega inside jets with ptJet > %.1f GeV, R = %.1f, gap = %d\n" ,
36- ptJetThreshold , jetR , gapSize );
37+ ">> Pythia8 generator: Xi/Omega inside jets with pt_{jet} > %.1f GeV, R_{jet} = %.1f, gap = %d\n" ,
38+ ptJetMin , Rjet , gapSize );
3739 }
38-
39- ~GeneratorPythia8StrangeInJet () = default ;
40+ /// Destructor
41+ ~GeneratorPythia8StrangenessInJet () = default ;
4042
4143 bool Init () override {
4244 addSubGenerator (0 , "Pythia8 events with Xi/Omega inside jets" );
4345 return o2 ::eventgen ::GeneratorPythia8 ::Init ();
4446 }
4547
4648protected :
47- /// Check if particle is physical primary OR from HF decay
48- bool isPhysicalPrimaryOrFromHF (const Pythia8 ::Particle & p ,
49- const Pythia8 ::Event & event )
49+ /// Check if particle is physical primary or from HF decay
50+ bool isPhysicalPrimaryOrFromHF (const Pythia8 ::Particle & p , const Pythia8 ::Event & event )
5051 {
52+ // Select only final-state particles
5153 if (!p .isFinal ()) {
5254 return false;
5355 }
5456
55- const int absPdg = std ::abs (p .id ());
56-
5757 // Particle species selection
58- const bool isAcceptedSpecies = (absPdg == 211 || absPdg == 321 || absPdg == 2212 || absPdg == 1000010020 || absPdg == 11 || absPdg == 13 );
59-
60- if (!isAcceptedSpecies ) {
58+ const int absPdg = std ::abs (p .id ());
59+ if (absPdg != 211 && absPdg != 321 && absPdg != 2212 && absPdg != 1000010020 && absPdg != 11 && absPdg != 13 )
6160 return false;
62- }
6361
6462 // Walk up ancestry
65- int motherIdx = p .mother1 ();
63+ int motherId = p .mother1 ();
6664
67- while (motherIdx > 0 ) {
68- const auto& mother = event [motherIdx ];
65+ while (motherId > 0 ) {
66+
67+ // Get mother
68+ const auto& mother = event [motherId ];
6969 const int absMotherPdg = std ::abs (mother .id ());
7070
71- // Charm or beauty hadron → accept ( HF decay)
71+ // Check if particle is from HF decay
7272 if ((absMotherPdg / 100 == 4 ) || (absMotherPdg / 100 == 5 ) || (absMotherPdg / 1000 == 4 ) || (absMotherPdg / 1000 == 5 )) {
7373 return true;
7474 }
7575
76- // Weakly decaying hadron → reject ( non-physical primary)
76+ // Reject non-physical primary hadrons
7777 if (mother .isHadron () && mother .tau0 () > 1.0 ) {
7878 return false;
7979 }
80- motherIdx = mother .mother1 ();
80+ motherId = mother .mother1 ();
8181 }
8282 return true;
8383 }
8484
85+ // Compute delta phi
86+ double getDeltaPhi (double a1 , double a2 )
87+ {
88+ double deltaPhi {0.0 };
89+ double phi1 = TVector2 ::Phi_0_2pi (a1 );
90+ double phi2 = TVector2 ::Phi_0_2pi (a2 );
91+ double diff = std ::fabs (phi1 - phi2 );
92+
93+ if (diff <= M_PI )
94+ deltaPhi = diff ;
95+ if (diff > M_PI )
96+ deltaPhi = 2.0 * M_PI - diff ;
97+
98+ return deltaPhi ;
99+ }
100+
85101 bool generateEvent () override {
86- fmt ::printf (">> Generating event %lu \n" , mGeneratedEvents );
102+ fmt ::printf (">> Generating event %d \n" , mGeneratedEvents );
87103
88104 bool genOk = false;
89105 int localCounter {0 };
106+ constexpr int kMaxTries {100000 };
90107
91108 // Accept mGapSize events unconditionally, then one triggered event
92109 if (mGeneratedEvents % (mGapSize + 1 ) < mGapSize ) {
93110 genOk = GeneratorPythia8 ::generateEvent ();
94111 fmt ::printf (">> Gap-trigger accepted event (no strangeness check)\n" );
95112 } else {
96- while (!genOk ) {
113+ while (!genOk && localCounter < kMaxTries ) {
97114 if (GeneratorPythia8 ::generateEvent ()) {
98115 genOk = selectEvent (mPythia .event );
99116 }
100117 localCounter ++ ;
101118 }
102- fmt ::printf (">> Event accepted after %d iterations (Xi/Omega in jet)\n" ,
103- localCounter );
119+ if (!genOk ) {
120+ fmt ::printf ("Failed to generate triggered event after %d tries\n" ,kMaxTries );
121+ return false;
122+ }
123+ fmt ::printf (">> Event accepted after %d iterations (Xi/Omega in jet)\n" , localCounter );
104124 }
105125
106126 notifySubGenerator (0 );
@@ -109,56 +129,54 @@ protected:
109129 }
110130
111131 bool selectEvent (Pythia8 ::Event & event ) {
112- const std ::vector < int > pdgXiOmega = {3312 , -3312 , 3334 , -3334 };
113- const double mpi = 0.1395704 ;
114132
115- std ::vector < fastjet ::PseudoJet > fjParticles ;
133+ double etaJet {-999.0 }, phiJet {-999.0 }, ptMax {0.0 };
134+ std ::vector < int > particleID ;
135+ bool containsXiOrOmega {false};
116136
117- for (int i = 0 ; i < event .size (); ++ i ) {
137+ for (int i = 0 ; i < event .size (); i ++ ) {
118138 const auto& p = event [i ];
139+ if (std ::abs (p .id ()) == 3312 || std ::abs (p .id ()) == 3334 )
140+ containsXiOrOmega = true;
119141
120- // --- Jet input selection ---
121- if (!p .isFinal ()) continue ;
122- if (!p .isCharged ()) continue ;
142+ if (std ::abs (p .eta ()) > 0.8 || p .pT () < 0.1 ) continue ;
123143 if (!isPhysicalPrimaryOrFromHF (p , event )) continue ;
124- if ( std :: abs ( p . eta ()) > 0.8 ) continue ;
144+ particleID . emplace_back ( i ) ;
125145
126- double pt = std ::sqrt (p .px () * p .px () + p .py () * p .py ());
127- if (pt < 0.1 ) continue ;
128-
129- double energy = std ::sqrt (p .p () * p .p () + mpi * mpi );
130-
131- fastjet ::PseudoJet pj (p .px (), p .py (), p .pz (), energy );
132- pj .set_user_index (i ); // map back to Pythia index
133- fjParticles .push_back (pj );
146+ if (p .pT () > ptMax ) {
147+ ptMax = p .pT ();
148+ etaJet = p .eta ();
149+ phiJet = p .phi ();
150+ }
134151 }
152+ if (ptMax == 0.0 )
153+ return false;
154+ if (std ::abs (etaJet ) + Rjet > 0.8 )
155+ return false;
156+ if (!containsXiOrOmega )
157+ return false;
135158
136- if (fjParticles .empty ()) return false;
137-
138- fastjet ::JetDefinition jetDef (fastjet ::antikt_algorithm , mJetR );
139- fastjet ::ClusterSequence cs (fjParticles , jetDef );
140- auto jets = fastjet ::sorted_by_pt (cs .inclusive_jets (mPtJetThreshold ));
141-
142- for (const auto& jet : jets ) {
143- for (const auto& c : jet .constituents ()) {
144- int idx = c .user_index ();
145- int pdg = event [idx ].id ();
159+ double ptJet {0.0 };
160+ for (int i = 0 ; i < particleID .size () ; i ++ ) {
161+ int id = particleID [i ];
162+ const auto& p = event [id ];
146163
147- if (std ::find (pdgXiOmega .begin (), pdgXiOmega .end (), pdg ) != pdgXiOmega .end ()) {
148- fmt ::printf (
149- ">> Accepted jet: pt = %.2f, eta = %.2f, phi = %.2f, contains PDG %d\n" ,
150- jet .pt (), jet .eta (), jet .phi (), pdg );
151- return true;
152- }
164+ double deltaEta = std ::abs (p .eta () - etaJet );
165+ double deltaPhi = getDeltaPhi (p .phi (),phiJet );
166+ double deltaR = std ::sqrt (deltaEta * deltaEta + deltaPhi * deltaPhi );
167+ if (deltaR < Rjet ) {
168+ ptJet += p .pT ();
153169 }
154170 }
171+ if (ptJet < ptJetMin )
172+ return false;
155173
156- return false ;
174+ return true ;
157175 }
158176
159177private :
160- double mPtJetThreshold {10.0 };
161- double mJetR {0.4 };
178+ double mptJetMin {10.0 };
179+ double mRjet {0.4 };
162180 int mGapSize {4 };
163181 uint64_t mGeneratedEvents {0 };
164182};
0 commit comments