66#include "Pythia8/Pythia.h"
77#include "TRandom3.h"
88#include "TMath.h"
9- // #include "TF1.h"
109#include "TParticle.h"
1110#include "TSystem.h"
1211#if __has_include ("SimulationDataFormat/MCGenStatus.h" )
1918#endif
2019#include <cmath>
2120#include <string>
21+ #include <vector>
2222#endif
2323
24- // Double_t FuncLavy(Double_t *x, Double_t *par)
25- // {
26-
27- // Double_t p = (par[0] - 1) * (par[0] - 2) * par[1] * x[0] / (((pow((1 + (((sqrt((par[2] * par[2]) + (x[0] * x[0]))) - par[2]) / (par[0] * par[3]))), par[0]) * (par[0] * par[3] * ((par[0] * par[3]) + (par[2] * (par[0] - 2)))))));
28- // return (p);
29- // }
30-
3124class GeneratorPhiResonance : public o2 ::eventgen ::GeneratorPythia8
3225{
3326public :
@@ -38,21 +31,30 @@ public:
3831 int signalInterval = 3 )
3932 : GeneratorPythia8 (), mResoPDG (resoPDG ), mPtMin (ptMin ), mPtMaxPhiPhi (ptMax ), mYMin (yMin ), mYMax (yMax ), mSignalInterval (signalInterval )
4033 {
41- // 1. Initialize Gun Pythia object & define custom resonance
42- // # id::all = name antiName spinType chargeType colType m0 mWidth mMin mMax tau0
34+
35+ // 1. Define Custom Signal Resonance (PDG: 999999) decay into standard Phis (333 333)
4336 std ::string createReso = std ::to_string (mResoPDG ) + ":new = f2_Custom void 5 0 0 2.714 0.012 2.05 3.50 0.0" ;
44- mPythiaGun .readString (createReso );
45- mPythiaGun .readString (std ::to_string (mResoPDG ) + ":mayDecay = on" );
46- // id:addChannel = onMode bRatio meMode product1 product2, (onMode = 1: allow decay, bRatio = branching ratio, meMode = matrix element mode where 0 is isotropic decay)
47- std ::string addDecay = std ::to_string (mResoPDG ) + ":addChannel = 1 1.0 0 333 333" ;
48- mPythiaGun .readString (addDecay );
37+ std ::string resoMayDecay = std ::to_string (mResoPDG ) + ":mayDecay = on" ;
38+ std ::string addResoDecay = std ::to_string (mResoPDG ) + ":addChannel = 1 1.0 0 333 333" ;
39+
40+ // Helper lambda to load custom particle definitions across ALL Pythia engines
41+ auto applyCustomParticles = [& ](Pythia8 ::Pythia & pythiaInst )
42+ {
43+ pythiaInst .readString (createReso );
44+ pythiaInst .readString (resoMayDecay );
45+ pythiaInst .readString (addResoDecay );
46+ };
47+
48+ // 1: Apply particle definitions to mPythia, mPythiaGun, and pythiaObjectMinimumBias
49+ applyCustomParticles (mPythia );
50+ applyCustomParticles (mPythiaGun );
4951
5052 mPythiaGun .readString ("ProcessLevel:all off" );
5153 mPythiaGun .readString ("Random:setSeed = on" );
5254 mPythiaGun .readString ("Random:seed = " + std ::to_string (1 + gRandom -> Integer (900000000 )));
5355 mPythiaGun .init ();
5456
55- // 2 . Initialize Minimum Bias Pythia Engine
57+ // 3 . Initialize Minimum Bias Pythia Engine
5658 if (pythiaCfgMb .empty ())
5759 {
5860 auto & param = o2 ::eventgen ::GeneratorPythia8Param ::Instance ();
@@ -67,25 +69,8 @@ public:
6769 pythiaObjectMinimumBias .readString ("Random:setSeed = on" );
6870 pythiaObjectMinimumBias .readString ("Random:seed = " + std ::to_string (1 + gRandom -> Integer (900000000 )));
6971
70- // Add custom particle definition to MB instance so particle table matches
71- pythiaObjectMinimumBias .readString (createReso );
72- pythiaObjectMinimumBias .readString (std ::to_string (mResoPDG ) + ":mayDecay = on" );
73- pythiaObjectMinimumBias .readString (addDecay );
74-
72+ applyCustomParticles (pythiaObjectMinimumBias );
7573 pythiaObjectMinimumBias .init ();
76-
77- // // Thermal pT distribution for phi-phi resonance
78- // mThermal = new TF1("mThermal", "x*sqrt(x*x+[0]*[0])*exp(-sqrt(x*x+[0]*[0])/[1])", mPtMin, mPtMaxPhiPhi);
79-
80- // // Lévy-Tsallis pT distribution for direct phi
81- // mLevyTsallis = new TF1("mLevyTsallis", FuncLavy, mPtMin, 100.0, 4);
82-
83- // mLevyTsallis->SetParameters(
84- // 7.60279, // n
85- // 0.0374237, // dN/dy
86- // 1.01946, // mass
87- // 0.338379 // T
88- // );
8974 }
9075
9176 Bool_t generateEvent () override
@@ -99,69 +84,77 @@ public:
9984 mbOK = pythiaObjectMinimumBias .next ();
10085 }
10186
102- // Copy MB event into mPythia
103- mPythia . event = pythiaObjectMinimumBias . event ;
87+ // 2: Copy MB event using exact pointer binding from generator_pythia8_LF_rapidity_width.C
88+ copyMinimumBiasEventForInjection () ;
10489
10590 // 2. Clear Gun event container
10691 mPythiaGun .event .reset ();
10792
10893 // 3. Inject Signal Gun Particles into mPythiaGun
10994 if (mEventCounter % mSignalInterval == 0 )
11095 {
111- // Theramal distribution
96+ // Resonant signal -> Decays into 333 333 (Standard Phis)
11297 injectParticle (mResoPDG , 1 , true);
11398 }
11499 else
115100 {
116- // From published
101+ // Directly injected uncorrelated Phi
117102 injectParticle (333 , 2 , false);
118103 }
119104
120105 // 4. Force Decay of injected particles using Pythia's Decayer
121- for (int i = 1 ; i < mPythiaGun .event .size (); ++ i )
122- {
123- if (mPythiaGun .event [i ].status () > 0 )
124- { // Active injected particles
125- mPythiaGun .particleData .mayDecay (mPythiaGun .event [i ].id (), true);
126- mPythiaGun .moreDecays ();
127- }
128- }
106+ mPythiaGun .moreDecays ();
107+ mPythiaGun .next ();
129108
130- // 5. Merge mPythiaGun event into mPythia.event
109+ // 3: Index Mapping during Event Merging
131110 int offset = mPythia .event .size ();
111+ std ::vector < int > indexMap (mPythiaGun .event .size (), 0 );
132112
133113 for (int i = 1 ; i < mPythiaGun .event .size (); ++ i )
134- { // Skip system particle 0
114+ {
115+ indexMap [i ] = mPythia .event .size ();
135116 Pythia8 ::Particle p = mPythiaGun .event [i ];
117+ mPythia .event .append (p );
118+ }
119+
120+ // Re-link mother and daughter index relationships accurately
121+ for (int i = 1 ; i < mPythiaGun .event .size (); ++ i )
122+ {
123+ int newIdx = indexMap [i ];
124+ Pythia8 ::Particle & p = mPythia .event [newIdx ];
136125
137- // Adjust history indices accurately
138- int mother1 = (p .mother1 () > 0 ) ? p .mother1 () + offset - 1 : p .mother1 ();
139- int mother2 = (p .mother2 () > 0 ) ? p .mother2 () + offset - 1 : p .mother2 ();
140- int daughter1 = (p .daughter1 () > 0 ) ? p .daughter1 () + offset - 1 : p .daughter1 ();
141- int daughter2 = (p .daughter2 () > 0 ) ? p .daughter2 () + offset - 1 : p .daughter2 ();
126+ int m1 = p .mother1 ();
127+ int m2 = p .mother2 ();
128+ int d1 = p .daughter1 ();
129+ int d2 = p .daughter2 ();
142130
143- p .mothers (mother1 , mother2 );
144- p . daughters ( daughter1 , daughter2 );
131+ p .mothers (( m1 > 0 && m1 < ( int ) indexMap . size ()) ? indexMap [ m1 ] : 0 ,
132+ ( m2 > 0 && m2 < ( int ) indexMap . size ()) ? indexMap [ m2 ] : 0 );
145133
146- mPythia .event .append (p );
134+ p .daughters ((d1 > 0 && d1 < (int )indexMap .size ()) ? indexMap [d1 ] : 0 ,
135+ (d2 > 0 && d2 < (int )indexMap .size ()) ? indexMap [d2 ] : 0 );
147136 }
148137
149- // 6. CRITICAL : Restore Pythia particleData pointers for O2 exporter
138+ // 4 : Restore Pythia particleData pointers for O2 exporter
150139 mPythia .event .restorePtrs ();
151140
152- // 7. Invoke base generator hooks to sync O2 event record
153- // return GeneratorPythia8::generateEvent();
154- return true; // Skip base generator processing to avoid overwriting injected particles
141+ return true;
155142 }
156143
157144private :
145+ void copyMinimumBiasEventForInjection ()
146+ {
147+ mPythia .event = pythiaObjectMinimumBias .event ;
148+ mPythia .event .init ("Minimum-bias event with injected particles" , & mPythia .particleData );
149+ mPythia .event .restorePtrs ();
150+ }
151+
158152 void injectParticle (int pdg , int nParticles , bool thermalPt )
159153 {
160154 const double phiMass = 1.019461 ;
161155
162156 for (int i = 0 ; i < nParticles ; ++ i )
163157 {
164- // const double pt = gRandom->Uniform(mPtMin, mPtMaxPhiPhi);
165158 const double y = gRandom -> Uniform (mYMin , mYMax );
166159 const double phi = gRandom -> Uniform (0 , TMath ::TwoPi ());
167160
@@ -179,22 +172,13 @@ private:
179172 }
180173
181174 double pt ;
182-
183175 if (thermalPt )
184176 {
185- // const double T = 0.160;
186-
187- // mThermal->SetParameter(0, mass);
188- // mThermal->SetParameter(1, T);
189-
190- // pt = mThermal->GetRandom();
191-
192- pt = gRandom -> Uniform (mPtMin , mPtMaxPhiPhi ); // Falling back to flat pT due to low statistics in high pT
177+ pt = gRandom -> Uniform (mPtMin , mPtMaxPhiPhi );
193178 }
194179 else
195180 {
196- // pt = mLevyTsallis->GetRandom();
197- pt = gRandom -> Uniform (mPtMin , 100.0 ); // Falling back to flat pT due to low statistics in high pT
181+ pt = gRandom -> Uniform (mPtMin , 100.0 );
198182 }
199183
200184 const double px = pt * std ::cos (phi );
@@ -215,6 +199,7 @@ private:
215199 particle .yProd (0. );
216200 particle .zProd (0. );
217201
202+ mPythiaGun .particleData .mayDecay (pdg , true);
218203 mPythiaGun .event .append (particle );
219204 }
220205 }
@@ -226,9 +211,6 @@ private:
226211
227212 Pythia8 ::Pythia mPythiaGun ;
228213 Pythia8 ::Pythia pythiaObjectMinimumBias ;
229-
230- // TF1 *mThermal;
231- // TF1 *mLevyTsallis;
232214};
233215
234216/// Entry point for o2-sim
0 commit comments