From e77f86d9f59054b7be25e09e23cf3937ab350e7a Mon Sep 17 00:00:00 2001 From: ldellost Date: Tue, 6 Oct 2026 12:29:37 +0000 Subject: [PATCH 1/3] Add Lstar gun generator, ini and config --- .../ini/GeneratorLF_Strangeness_ppLStar.ini | 6 + .../generator/pythia8_inel_forceLStar.cfg | 20 ++ .../PWGLF/pythia8/generator_pythia8_Lstar.C | 226 ++++++++++++++++++ 3 files changed, 252 insertions(+) create mode 100644 MC/config/PWGLF/ini/GeneratorLF_Strangeness_ppLStar.ini create mode 100644 MC/config/PWGLF/pythia8/generator/pythia8_inel_forceLStar.cfg create mode 100644 MC/config/PWGLF/pythia8/generator_pythia8_Lstar.C diff --git a/MC/config/PWGLF/ini/GeneratorLF_Strangeness_ppLStar.ini b/MC/config/PWGLF/ini/GeneratorLF_Strangeness_ppLStar.ini new file mode 100644 index 000000000..bd0e804d8 --- /dev/null +++ b/MC/config/PWGLF/ini/GeneratorLF_Strangeness_ppLStar.ini @@ -0,0 +1,6 @@ +[GeneratorExternal] +fileName=${O2DPG_ROOT}/MC/config/PWGLF/pythia8/generator_pythia8_Lstar.C +funcName=generator_Lstar() + +[GeneratorPythia8] +config=${O2DPG_ROOT}/MC/config/PWGLF/pythia8/generator/pythia8_inel_forceLStar.cfg \ No newline at end of file diff --git a/MC/config/PWGLF/pythia8/generator/pythia8_inel_forceLStar.cfg b/MC/config/PWGLF/pythia8/generator/pythia8_inel_forceLStar.cfg new file mode 100644 index 000000000..2230a1537 --- /dev/null +++ b/MC/config/PWGLF/pythia8/generator/pythia8_inel_forceLStar.cfg @@ -0,0 +1,20 @@ +### beams +Beams:idA 2212 # proton +Beams:idB 2212 # proton +Beams:eCM 13600. # GeV + +### processes +SoftQCD:inelastic on # all inelastic processes + +### decays +ParticleDecays:limitTau0 on +ParticleDecays:tau0Max 10. + +### Add Lambda* decay 3124 102134 +# id::all = name antiName spinType chargeType colType m0 mWidth mMin mMax tau0 +3124:all = Lambda1520 Lambda1520bar 4 0 0 1.51950 0.01560 1.47 1.60 0 + +### add Resonance decays absent in PYTHIA8 decay table and set BRs from PDG for other +3124:oneChannel = 1 1.000 0 3122 22 +3124:onMode = off +3124:onIfMatch = 3122 22 \ No newline at end of file diff --git a/MC/config/PWGLF/pythia8/generator_pythia8_Lstar.C b/MC/config/PWGLF/pythia8/generator_pythia8_Lstar.C new file mode 100644 index 000000000..66cb4646b --- /dev/null +++ b/MC/config/PWGLF/pythia8/generator_pythia8_Lstar.C @@ -0,0 +1,226 @@ + +#include "Pythia8/Pythia.h" +#include "Pythia8/HeavyIons.h" +#include "FairGenerator.h" +#include "FairPrimaryGenerator.h" +#include "Generators/GeneratorPythia8.h" +#include "TF1.h" +#include "TRandom3.h" +//#include "TParticlePDG.h" +//#include "TDatabasePDG.h" + +#include +#include + +class GeneratorPythia8ExtraStrangeness : public o2::eventgen::GeneratorPythia8 +{ +public: + /// default constructor + GeneratorPythia8ExtraStrangeness() = default; + + /// Constructor + GeneratorPythia8ExtraStrangeness(int input_pdg) + { + genMinPt=0.0; + genMaxPt=12.0; + genminY=-1.5; + genmaxY=1.5; + genminEta=-1.5; + genmaxEta=1.5; + + pdg=input_pdg; + m = 0; + E=0; + px=0; + py=0; + pz=0; + p=0; + y=0; + eta=0; + xProd=0.; yProd=0.; zProd=0.; + + fLVHelper = std::make_unique(); + + randomizePDGsign = false; + + fSpectra = makeLevySpectrum("fSpectra", genMinPt, genMaxPt, mPythia.particleData.m0(input_pdg), 0.30, 7.); + } + + /// randomize the PDG code sign of core particle + void setRandomizePDGsign() { randomizePDGsign = true; } + + Double_t y2eta(Double_t pt, Double_t mass, Double_t y){ + Double_t mt = TMath::Sqrt(mass * mass + pt * pt); + return TMath::ASinH(mt / pt * TMath::SinH(y)); + } + + + /// set mass + double sampleMass(int input_pdg) + { + auto& pd = mPythia.particleData; + const double mass = pd.mWidth(input_pdg) > 0. ? pd.mSel(input_pdg) : pd.m0(input_pdg); + return mass; + } + + static double myLevyPt(double* pt, double* par) + { + const double lMass = par[0]; + const double ldNdy = par[1]; + const double lTemp = par[2]; + const double lPower = par[3]; + + const double lBigCoef = ((lPower-1)*(lPower-2)) / (lPower*lTemp*(lPower*lTemp+lMass*(lPower-2))); + const double lInPower = 1 + (TMath::Sqrt(pt[0]*pt[0]+lMass*lMass)-lMass) / (lPower*lTemp); + + return ldNdy * pt[0] * lBigCoef * TMath::Power(lInPower, -lPower); + } + + /// build a Levy-Tsallis pT spectrum for a particle of given mass +TF1* makeLevySpectrum(const char* name, double ptMin, double ptMax, double mass, double T, double n, double norm = 1.) + { + TF1* f = new TF1(name, myLevyPt, ptMin, ptMax, 4); + f->SetParNames("mass", "norm", "T", "n"); + f->FixParameter(0, mass); // mass [GeV/c^2] + f->SetParameter(1, norm); // normalization (irrelevant for GetRandom) + f->SetParameter(2, T); // slope parameter [GeV] + f->SetParameter(3, n); // power-law exponent + f->SetNpx(1000); + return f; + } + + /// set 4-momentum + void set4momentum(double input_px, double input_py, double input_pz){ + px = input_px; + py = input_py; + pz = input_pz; + E = sqrt( m*m+px*px+py*py+pz*pz ); + fourMomentum.px(px); + fourMomentum.py(py); + fourMomentum.pz(pz); + fourMomentum.e(E); + p = sqrt( px*px+py*py+pz*pz ); + y = 0.5*log( (E+pz)/(E-pz) ); + eta = 0.5*log( (p+pz)/(p-pz) ); + } + + + //_________________________________________________________________________________ + /// generate uniform eta and uniform momentum + void genSpectraMomentumEta(double minPt, double maxPt, double minY, double maxY){ + // random generator + std::unique_ptr ranGenerator { new TRandom3() }; + ranGenerator->SetSeed(0); + + // generate transverse momentum + //const double gen_pT = ranGenerator->Uniform(minPt, maxPt); + const double gen_pT = fSpectra->GetRandom(minPt,maxPt); + + //Actually could be something else without loss of generality but okay + const double gen_phi = ranGenerator->Uniform(0,2*TMath::Pi()); + + // sample flat in rapidity, calculate eta + Double_t gen_Y=10, gen_eta=10; + + while( gen_eta>genmaxEta || gen_etaUniform(minY,maxY); + gen_eta = y2eta(gen_pT, m, gen_Y); + } + + fLVHelper->SetPtEtaPhiM(gen_pT, gen_eta, gen_phi, m); + set4momentum(fLVHelper->Px(),fLVHelper->Py(),fLVHelper->Pz()); + } + + //__________________________________________________________________ + Pythia8::Particle createParticle(){ + //std::cout << "createParticle() mass " << m << " pdgCode " << pdg << std::endl; + Pythia8::Particle myparticle; + myparticle.id(pdg); + myparticle.status(11); + myparticle.px(px); + myparticle.py(py); + myparticle.pz(pz); + myparticle.e(E); + myparticle.m(m); + myparticle.xProd(xProd); + myparticle.yProd(yProd); + myparticle.zProd(zProd); + + return myparticle; + } + + //__________________________________________________________________ + int randomizeSign() + { + std::unique_ptr gen_random{new TRandom3(0)}; + const float n = gen_random->Uniform(-1, 1); + + return n / abs(n); + } + + //__________________________________________________________________ + Bool_t generateEvent() override { + // Generate PYTHIA event + + mPythia.event.reset(); + + /// go to next Pythia event + Bool_t lPythiaOK = kFALSE; + while (!lPythiaOK){ + lPythiaOK = mPythia.next(); + } + + /// reset event + //mPythia.event.reset(); + + /// create and append the desired particle + m = sampleMass(pdg); + genSpectraMomentumEta(genMinPt, genMaxPt, genminY, genmaxY); + + if (randomizePDGsign) + pdg *= randomizeSign(); + + Pythia8::Particle particle = createParticle(); + mPythia.event.append(particle); + mPythia.moreDecays(); + + return true; + } + +private: + + double genMinPt; /// minimum 3-momentum for generated particles + double genMaxPt; /// maximum 3-momentum for generated particles + double genminY; /// minimum pseudorapidity for generated particles + double genmaxY; /// maximum pseudorapidity for generated particles + double genminEta; + double genmaxEta; + + Pythia8::Vec4 fourMomentum; /// four-momentum (px,py,pz,E) + //std::unique_ptr lutGen; + + double E; /// energy: sqrt( m*m+px*px+py*py+pz*pz ) [GeV/c] + double m; /// particle mass [GeV/c^2] + int pdg; /// particle pdg code + double px; /// x-component momentum [GeV/c] + double py; /// y-component momentum [GeV/c] + double pz; /// z-component momentum [GeV/c] + double p; /// momentum + double y; /// rapidity + double eta; /// pseudorapidity + double xProd; /// x-coordinate position production vertex [cm] + double yProd; /// y-coordinate position production vertex [cm] + double zProd; /// z-coordinate position production vertex [cm] + + bool randomizePDGsign; /// bool to randomize the PDG code of the core particle + + TF1 *fSpectra = nullptr; /// TF1 to store more realistic shape of spectrum + std::unique_ptr fLVHelper; +}; + + FairGenerator *generator_Lstar() + { + auto myGen = new GeneratorPythia8ExtraStrangeness(3124); + myGen->setRandomizePDGsign(); // randomization of PDG switched on + return myGen; + } \ No newline at end of file From 9d182d7ad3956f61cf02189f36a5dd75fa9c60e1 Mon Sep 17 00:00:00 2001 From: ldellost Date: Tue, 6 Oct 2026 13:03:17 +0000 Subject: [PATCH 2/3] add test file --- .../tests/GeneratorLF_Strangeness_ppLStar.C | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 MC/config/PWGLF/ini/tests/GeneratorLF_Strangeness_ppLStar.C diff --git a/MC/config/PWGLF/ini/tests/GeneratorLF_Strangeness_ppLStar.C b/MC/config/PWGLF/ini/tests/GeneratorLF_Strangeness_ppLStar.C new file mode 100644 index 000000000..ef04688a0 --- /dev/null +++ b/MC/config/PWGLF/ini/tests/GeneratorLF_Strangeness_ppLStar.C @@ -0,0 +1,77 @@ +int External() +{ + std::string path{"o2sim_Kine.root"}; + const int pdgMother = 3124; // Lambda(1520)0 (sign randomized by the generator) + + TFile file(path.c_str(), "READ"); + if (file.IsZombie()) { + std::cerr << "Cannot open ROOT file " << path << "\n"; + return 1; + } + auto tree = (TTree *)file.Get("o2sim"); + if (!tree) { + std::cerr << "Cannot find tree o2sim in file " << path << "\n"; + return 1; + } + std::vector *tracks{}; + tree->SetBranchAddress("MCTrack", &tracks); + + const auto nEvents = tree->GetEntries(); + int nMother = 0; + int nNotDecayed = 0; + int nBadDecay = 0; // mothers not decaying exactly to Lambda + gamma + int nEventsWrongCount = 0; // events without exactly one injected mother + + for (int i = 0; i < nEvents; i++) { + tree->GetEntry(i); + int nInEvent = 0; + for (auto &track : *tracks) { + const int pdg = track.GetPdgCode(); + if (std::abs(pdg) != pdgMother) { + continue; + } + nInEvent++; + nMother++; + + if (track.getFirstDaughterTrackId() < 0) { + nNotDecayed++; + continue; + } + const int expectedLambda = (pdg > 0) ? 3122 : -3122; + int nLambda = 0, nGamma = 0, nDau = 0; + for (int j = track.getFirstDaughterTrackId(); j <= track.getLastDaughterTrackId(); ++j) { + const int pdgDau = tracks->at(j).GetPdgCode(); + nDau++; + if (pdgDau == expectedLambda) nLambda++; + if (pdgDau == 22) nGamma++; + } + if (nDau != 2 || nLambda != 1 || nGamma != 1) { + nBadDecay++; + std::cerr << "Unexpected decay of " << pdg << " (" << nDau << " daughters)\n"; + } + } + if (nInEvent != 1) { + nEventsWrongCount++; + } + } + + std::cout << "--------------------------------\n"; + std::cout << "# Events: " << nEvents << "\n"; + std::cout << "# Lambda(1520) + anti: " << nMother << "\n"; + std::cout << "# not decayed: " << nNotDecayed << "\n"; + std::cout << "# unexpected decays: " << nBadDecay << "\n"; + std::cout << "# events with != 1 mother: " << nEventsWrongCount << "\n"; + std::cout << "--------------------------------\n"; + + if (nEventsWrongCount > 0) { + std::cerr << "Each event must contain exactly one injected Lambda(1520)\n"; + return 1; + } + if (nNotDecayed > 0 || nBadDecay > 0) { + std::cerr << "Lambda(1520) must always decay to Lambda + gamma\n"; + return 1; + } + return 0; +} + +void GeneratorLF_Strangeness_ppLStar() { External(); } \ No newline at end of file From 921192484ef50647088094939de325cb886a3d5f Mon Sep 17 00:00:00 2001 From: ldellost Date: Tue, 6 Oct 2026 13:05:35 +0000 Subject: [PATCH 3/3] fix --- MC/config/PWGLF/ini/GeneratorLF_Strangeness_ppLStar.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MC/config/PWGLF/ini/GeneratorLF_Strangeness_ppLStar.ini b/MC/config/PWGLF/ini/GeneratorLF_Strangeness_ppLStar.ini index bd0e804d8..9836791ed 100644 --- a/MC/config/PWGLF/ini/GeneratorLF_Strangeness_ppLStar.ini +++ b/MC/config/PWGLF/ini/GeneratorLF_Strangeness_ppLStar.ini @@ -1,6 +1,6 @@ [GeneratorExternal] -fileName=${O2DPG_ROOT}/MC/config/PWGLF/pythia8/generator_pythia8_Lstar.C +fileName=${O2DPG_MC_CONFIG_ROOT}/MC/config/PWGLF/pythia8/generator_pythia8_Lstar.C funcName=generator_Lstar() [GeneratorPythia8] -config=${O2DPG_ROOT}/MC/config/PWGLF/pythia8/generator/pythia8_inel_forceLStar.cfg \ No newline at end of file +config=${O2DPG_MC_CONFIG_ROOT}/MC/config/PWGLF/pythia8/generator/pythia8_inel_forceLStar.cfg \ No newline at end of file