From f151a42c1ec2b887540b6113734724abe2d86ac1 Mon Sep 17 00:00:00 2001 From: sawan Date: Fri, 2 Oct 2026 22:46:44 +0530 Subject: [PATCH 1/2] Added twoPhi trigger MC and renamed codes based on convention --- .../ini/GeneratorLF_doublephi_trigger.ini | 10 ++ .../PWGLF/ini/GeneratorLF_phiphiInvMass.ini | 4 +- .../ini/tests/GeneratorLF_doublephi_trigger.C | 76 ++++++++ .../ini/tests/GeneratorLF_phiphiInvMass.C | 28 +-- ...LF_phiphi.C => generator_pythia8_phiphi.C} | 62 ++----- .../generator_pythia8_twophi_trigger.C | 169 ++++++++++++++++++ 6 files changed, 277 insertions(+), 72 deletions(-) create mode 100644 MC/config/PWGLF/ini/GeneratorLF_doublephi_trigger.ini create mode 100644 MC/config/PWGLF/ini/tests/GeneratorLF_doublephi_trigger.C rename MC/config/PWGLF/pythia8/{GeneratorLF_phiphi.C => generator_pythia8_phiphi.C} (71%) create mode 100644 MC/config/PWGLF/pythia8/generator_pythia8_twophi_trigger.C diff --git a/MC/config/PWGLF/ini/GeneratorLF_doublephi_trigger.ini b/MC/config/PWGLF/ini/GeneratorLF_doublephi_trigger.ini new file mode 100644 index 000000000..6f1dcd71a --- /dev/null +++ b/MC/config/PWGLF/ini/GeneratorLF_doublephi_trigger.ini @@ -0,0 +1,10 @@ +[GeneratorExternal] +fileName=${O2DPG_MC_CONFIG_ROOT}/MC/config/PWGLF/pythia8/generator_pythia8_twophi_trigger.C +funcName=generateDoublePhi(0, 0.0, 100.0, 0.8) + +[GeneratorPythia8] +config=${O2DPG_MC_CONFIG_ROOT}/MC/config/PWGLF/pythia8/generator/pythia8_inel_136tev.cfg + +[DecayerPythia8] +config[0]=${O2DPG_MC_CONFIG_ROOT}/MC/config/common/pythia8/decayer/base.cfg +config[1]=${O2DPG_MC_CONFIG_ROOT}/MC/config/PWGLF/pythia8/generator/resonances.cfg diff --git a/MC/config/PWGLF/ini/GeneratorLF_phiphiInvMass.ini b/MC/config/PWGLF/ini/GeneratorLF_phiphiInvMass.ini index d9ad4041c..e74204392 100644 --- a/MC/config/PWGLF/ini/GeneratorLF_phiphiInvMass.ini +++ b/MC/config/PWGLF/ini/GeneratorLF_phiphiInvMass.ini @@ -1,6 +1,6 @@ [GeneratorExternal] -fileName=${O2DPG_MC_CONFIG_ROOT}/MC/config/PWGLF/pythia8/GeneratorLF_phiphi.C -funcName=generatePhiResonanceGun(999999, 888888, 0.0, 50.0, 100.0, -1.0, 1.0, "${O2DPG_MC_CONFIG_ROOT}/MC/config/PWGLF/pythia8/generator/pythia8_inel_136tev.cfg", 3) +fileName=${O2DPG_MC_CONFIG_ROOT}/MC/config/PWGLF/pythia8/generator_pythia8_phiphi.C +funcName=generatePhiResonanceGun(999999, 0.0, 50.0, -1.0, 1.0, "${O2DPG_MC_CONFIG_ROOT}/MC/config/PWGLF/pythia8/generator/pythia8_inel_136tev.cfg", 0) [GeneratorPythia8] config=${O2DPG_MC_CONFIG_ROOT}/MC/config/PWGLF/pythia8/generator/pythia8_inel_136tev.cfg diff --git a/MC/config/PWGLF/ini/tests/GeneratorLF_doublephi_trigger.C b/MC/config/PWGLF/ini/tests/GeneratorLF_doublephi_trigger.C new file mode 100644 index 000000000..58767f843 --- /dev/null +++ b/MC/config/PWGLF/ini/tests/GeneratorLF_doublephi_trigger.C @@ -0,0 +1,76 @@ +int External() +{ + const std::string path{"o2sim_Kine.root"}; + + 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); + + // Counters + int nMBPhi = 0; + int nKPlusFromMBPhi = 0; + int nKMinusFromMBPhi = 0; + int numberOfEventsProcessed = 0; + + for (Long64_t i = 0; i < tree->GetEntries(); ++i) + { + tree->GetEntry(i); + ++numberOfEventsProcessed; + + for (size_t idx = 0; idx < tracks->size(); ++idx) + { + const auto &track = tracks->at(idx); + const auto pdg = track.GetPdgCode(); + + if (pdg == 333) + { + ++nMBPhi; + + if (track.getFirstDaughterTrackId() >= 0) + { + for (int j = track.getFirstDaughterTrackId(); j <= track.getLastDaughterTrackId(); ++j) + { + auto dauPdg = tracks->at(j).GetPdgCode(); + if (dauPdg == 321) + { + ++nKPlusFromMBPhi; + } + if (dauPdg == -321) + { + ++nKMinusFromMBPhi; + } + } + } + } + } + } + + // --------------------------- Output --------------------------- + std::cout << "=================================================\n"; + std::cout << "Total Events: " << tree->GetEntries() << "\n\n"; + std::cout << "Total events processed: " << numberOfEventsProcessed << "\n"; + std::cout << "Total Minimum Bias Phi (333): " << nMBPhi << "\n"; + std::cout << " -> Decayed to K+: " << nKPlusFromMBPhi << "\n"; + std::cout << " -> Decayed to K-: " << nKMinusFromMBPhi << "\n"; + std::cout << "=================================================\n"; + + return 0; +} + +void GeneratorLF_doublephi_trigger() +{ + External(); +} diff --git a/MC/config/PWGLF/ini/tests/GeneratorLF_phiphiInvMass.C b/MC/config/PWGLF/ini/tests/GeneratorLF_phiphiInvMass.C index 4f08d32f8..f86d9e588 100644 --- a/MC/config/PWGLF/ini/tests/GeneratorLF_phiphiInvMass.C +++ b/MC/config/PWGLF/ini/tests/GeneratorLF_phiphiInvMass.C @@ -28,11 +28,8 @@ int External() int nKPlusFromResonancePhi = 0; int nKMinusFromResonancePhi = 0; - int nDirectInjectedPhi = 0; int nMBPhi = 0; - int nKPlusFromDirectPhi = 0; - int nKMinusFromDirectPhi = 0; int nKPlusFromMBPhi = 0; int nKMinusFromMBPhi = 0; @@ -86,24 +83,6 @@ int External() } } - else if (pdg == 888888) - { - ++nDirectInjectedPhi; - hasInjection = true; - - if (track.getFirstDaughterTrackId() >= 0) - { - for (int j = track.getFirstDaughterTrackId(); j <= track.getLastDaughterTrackId(); ++j) - { - auto dauPdg = tracks->at(j).GetPdgCode(); - if (dauPdg == 321) - ++nKPlusFromDirectPhi; - if (dauPdg == -321) - ++nKMinusFromDirectPhi; - } - } - } - // 2. Process Phi (333) Mesons else if (pdg == 333) { @@ -149,12 +128,7 @@ int External() std::cout << " -> Decayed to K+: " << nKPlusFromResonancePhi << "\n"; std::cout << " -> Decayed to K-: " << nKMinusFromResonancePhi << "\n\n"; - std::cout << "--- 2. DIRECTLY INJECTED PHI (333) ---\n"; - std::cout << "Total Directly Injected Phi (333): " << nDirectInjectedPhi << "\n"; - std::cout << " -> Decayed to K+: " << nKPlusFromDirectPhi << "\n"; - std::cout << " -> Decayed to K-: " << nKMinusFromDirectPhi << "\n\n"; - - std::cout << "--- 3. MINIMUM BIAS PHI (333) ---\n"; + std::cout << "--- 2. MINIMUM BIAS PHI (333) ---\n"; std::cout << "Total Minimum Bias Phi (333): " << nMBPhi << "\n"; std::cout << " -> Decayed to K+: " << nKPlusFromMBPhi << "\n"; std::cout << " -> Decayed to K-: " << nKMinusFromMBPhi << "\n"; diff --git a/MC/config/PWGLF/pythia8/GeneratorLF_phiphi.C b/MC/config/PWGLF/pythia8/generator_pythia8_phiphi.C similarity index 71% rename from MC/config/PWGLF/pythia8/GeneratorLF_phiphi.C rename to MC/config/PWGLF/pythia8/generator_pythia8_phiphi.C index 8537ebd3a..605f8b303 100644 --- a/MC/config/PWGLF/pythia8/GeneratorLF_phiphi.C +++ b/MC/config/PWGLF/pythia8/generator_pythia8_phiphi.C @@ -25,19 +25,14 @@ class GeneratorPhiResonance : public o2::eventgen::GeneratorPythia8 { public: GeneratorPhiResonance(int resoPDG = 999999, - int customPhiPDG = 888888, - float ptMin = 0.0, float ptMax = 50.0, float ptMaxPhi = 100.0, + float ptMin = 0.0, float ptMax = 50.0, float yMin = -1.0, float yMax = 1.0, std::string pythiaCfgMb = "${O2DPG_MC_CONFIG_ROOT}/MC/config/PWGLF/pythia8/generator/pythia8_inel_136tev.cfg", - int signalInterval = 3) - : GeneratorPythia8(), mResoPDG(resoPDG), mCustomPhiPDG(customPhiPDG), mPtMin(ptMin), mPtMaxPhiPhi(ptMax), mPtMaxPhi(ptMaxPhi), mYMin(yMin), mYMax(yMax), mSignalInterval(signalInterval) + int signalInterval = 0) + : GeneratorPythia8(), mResoPDG(resoPDG), mPtMin(ptMin), mPtMaxPhiPhi(ptMax), mYMin(yMin), mYMax(yMax), mSignalInterval(signalInterval) { - // 1. Define Custom Directly Injected Phi (PDG: 888888) with mass, width, and decay to kaons - std::string createCustomPhi = std::to_string(mCustomPhiPDG) + ":new = custom_phi custom_phi 3 0 0 1.019461 0.004249 0.980 1.100 0.0"; - std::string customPhiMayDecay = std::to_string(mCustomPhiPDG) + ":mayDecay = on"; - std::string addPhiDecayKPlusKMinus = std::to_string(mCustomPhiPDG) + ":addChannel = 1 0.492 0 321 -321"; - // 2. Define Custom Signal Resonance (PDG: 999999) decay into standard Phis (333 333) + // 1. Define Custom Signal Resonance (PDG: 999999) decay into standard Phis (333 333) std::string createReso = std::to_string(mResoPDG) + ":new = f2_Custom void 5 0 0 2.714 0.012 2.05 3.50 0.0"; std::string resoMayDecay = std::to_string(mResoPDG) + ":mayDecay = on"; std::string addResoDecay = std::to_string(mResoPDG) + ":addChannel = 1 1.0 0 333 333"; @@ -45,12 +40,11 @@ public: // Helper lambda to load custom particle definitions across ALL Pythia engines auto applyCustomParticles = [&](Pythia8::Pythia &pythiaInst) { - pythiaInst.readString(createCustomPhi); - pythiaInst.readString(customPhiMayDecay); - pythiaInst.readString(addPhiDecayKPlusKMinus); pythiaInst.readString(createReso); pythiaInst.readString(resoMayDecay); pythiaInst.readString(addResoDecay); + pythiaInst.readString("333:mayDecay = on"); + pythiaInst.readString("333:oneChannel = 1 1.0 0 321 -321"); }; // 1: Apply particle definitions to mPythia, mPythiaGun, and pythiaObjectMinimumBias @@ -99,15 +93,10 @@ public: mPythiaGun.event.reset(); // 3. Inject Signal Gun Particles into mPythiaGun - if (mEventCounter % mSignalInterval == 0) + if (mSignalInterval > 0 && mEventCounter % mSignalInterval == 0) { - // Resonant signal -> Decays into 333 333 (Standard Phis) - injectParticle(mResoPDG, 1, true); - } - else - { - // Directly injected uncorrelated Phi -> Uses Custom PDG 888888 - injectParticle(mCustomPhiPDG, 2, false); + // Resonant signal -> Decays into 333 333 + injectParticle(mResoPDG, 1); } // 4. Force Decay of injected particles using Pythia's Decayer @@ -157,7 +146,7 @@ private: mPythia.event.restorePtrs(); } - void injectParticle(int pdg, int nParticles, bool thermalPt) + void injectParticle(int pdg, int nParticles) { const double phiMass = 1.019461; @@ -167,27 +156,15 @@ private: const double phi = gRandom->Uniform(0, TMath::TwoPi()); double mass = 0.0; - if (pdg == mResoPDG) - { - do - { - mass = gRandom->BreitWigner(2.714, 0.012); - } while (mass <= 2.0 * phiMass || mass < 2.05 || mass > 3.50); - } - else + + do { - mass = mPythiaGun.particleData.mSel(333); // Use standard phi mass for directly injected custom phi - } + mass = gRandom->BreitWigner(2.714, 0.012); + } while (mass <= 2.0 * phiMass || mass < 2.05 || mass > 3.50); double pt; - if (thermalPt) - { - pt = gRandom->Uniform(mPtMin, mPtMaxPhiPhi); - } - else - { - pt = gRandom->Uniform(mPtMin, mPtMaxPhi); - } + + pt = gRandom->Uniform(mPtMin, mPtMaxPhiPhi); const double px = pt * std::cos(phi); const double py = pt * std::sin(phi); @@ -214,16 +191,15 @@ private: int mEventCounter = 0; int mResoPDG; - int mCustomPhiPDG; int mSignalInterval; - float mPtMin, mPtMaxPhiPhi, mPtMaxPhi, mYMin, mYMax; + float mPtMin, mPtMaxPhiPhi, mYMin, mYMax; Pythia8::Pythia mPythiaGun; Pythia8::Pythia pythiaObjectMinimumBias; }; /// Entry point for o2-sim -FairGenerator *generatePhiResonanceGun(int resoPDG = 999999, int customPhiPDG = 888888, float ptMin = 0.0, float ptMax = 50.0, float ptMaxPhi = 100.0, float yMin = -1.0, float yMax = 1.0, std::string pythiaCfgMb = "", int signalInterval = 3) +FairGenerator *generatePhiResonanceGun(int resoPDG = 999999, float ptMin = 0.0, float ptMax = 50.0, float yMin = -1.0, float yMax = 1.0, std::string pythiaCfgMb = "", int signalInterval = 0) { - return new GeneratorPhiResonance(resoPDG, customPhiPDG, ptMin, ptMax, ptMaxPhi, yMin, yMax, pythiaCfgMb, signalInterval); + return new GeneratorPhiResonance(resoPDG, ptMin, ptMax, yMin, yMax, pythiaCfgMb, signalInterval); } \ No newline at end of file diff --git a/MC/config/PWGLF/pythia8/generator_pythia8_twophi_trigger.C b/MC/config/PWGLF/pythia8/generator_pythia8_twophi_trigger.C new file mode 100644 index 000000000..da20738e1 --- /dev/null +++ b/MC/config/PWGLF/pythia8/generator_pythia8_twophi_trigger.C @@ -0,0 +1,169 @@ +#if !defined(__CLING__) || defined(__ROOTCLING__) +#include "FairGenerator.h" +#include "FairPrimaryGenerator.h" +#include "Generators/GeneratorPythia8.h" +#include "Pythia8/Pythia.h" +#include "TDatabasePDG.h" +#include "TMath.h" +#include "TParticlePDG.h" +#include "TRandom3.h" +#include "TSystem.h" +#include "TVector2.h" +#include "fairlogger/Logger.h" +#include +#include +#include +#include +using namespace Pythia8; +#endif + +/// Event generator using Pythia ropes (Adapted from task generator_pythia8_doubleLambdas.C) +/// Triggers events containing at least two generated phi(1020) mesons. + +class GeneratorPythia8DoublePhi : public o2::eventgen::GeneratorPythia8 +{ +public: + /// Constructor + GeneratorPythia8DoublePhi(int gapSize = 0, double minPt = 0.0, double maxPt = 100.0, double maxEta = 0.8) + : o2::eventgen::GeneratorPythia8(), + mGapSize(gapSize), + mMinPt(minPt), + mMaxPt(maxPt), + mMaxEta(maxEta) + { + fmt::printf(">> Pythia8 generator: two phi(1020) mesons, gap = %d, minPtPhi = %f, maxPtPhi = %f, |etaPhi| < %f\n", gapSize, minPt, maxPt, maxEta); + } + /// Destructor + ~GeneratorPythia8DoublePhi() = default; + + bool Init() override + { + addSubGenerator(0, "Pythia8 events with two phi(1020) mesons"); + return o2::eventgen::GeneratorPythia8::Init(); + } + +protected: + bool isPhiFromHFDecay(const Pythia8::Particle &p, const Pythia8::Event &event) + { + + // Walk up ancestry + int motherId = p.mother1(); + + while (motherId > 0) + { + // Get mother + const auto &mother = event[motherId]; + const int absMotherPdg = std::abs(mother.id()); + + // Check if particle is from HF decay + if (((absMotherPdg / 100) % 10 == 4) || + ((absMotherPdg / 100) % 10 == 5) || + ((absMotherPdg / 1000) % 10 == 4) || + ((absMotherPdg / 1000) % 10 == 5)) + { + return true; + } + + motherId = mother.mother1(); + } + return false; + } + + bool generateEvent() override + { + fmt::printf(">> Generating event %d\n", mGeneratedEvents); + + bool genOk = false; + int localCounter{0}; + constexpr int kMaxTries{100000}; + + // If mGapSize <= 0, filter ALL events to contain two phis. + // Otherwise, generate mGapSize gap events before 1 triggered event. + if (mGapSize > 0 && (mGeneratedEvents % (mGapSize + 1) < mGapSize)) + { + genOk = GeneratorPythia8::generateEvent(); + fmt::printf(">> Gap-event (no phi check)\n"); + } + else + { + while (!genOk && localCounter < kMaxTries) + { + if (GeneratorPythia8::generateEvent()) + { + genOk = selectEvent(mPythia.event); + } + localCounter++; + } + if (!genOk) + { + fmt::printf("Failed to generate triggered event after %d tries\n", kMaxTries); + return false; + } + fmt::printf(">> Triggered event: event accepted after %d iterations (double phi(1020))\n", localCounter); + } + + notifySubGenerator(0); + mGeneratedEvents++; + return true; + } + + bool selectEvent(Pythia8::Event &event) + { + int nPhi{0}; + + for (int i = 0; i < event.size(); i++) + { + const auto &p = event[i]; + + if (std::abs(p.id()) != 333) + continue; + + if (p.pT() < mMinPt || p.pT() > mMaxPt) + continue; + + if (std::abs(p.eta()) > mMaxEta) + continue; + + if (isPhiFromHFDecay(p, event)) + continue; + + // // Avoid double-counting copy/history entries: + // // Ensure this is the physical produced phi (e.g. check if its daughter is a copy of itself) + // int d1 = p.daughter1(); + // int d2 = p.daughter2(); + // if (d1 > 0 && d1 == d2 && std::abs(event[d1].id()) == 333) + // { + // // p decayed into another copy of phi, so skip this intermediate entry + // continue; + // } + + nPhi++; + } + if (nPhi < 2) + return false; + + return true; + } + +private: + int mGapSize{0}; + double mMinPt{0.0}; + double mMaxPt{100.0}; + double mMaxEta{0.8}; + uint64_t mGeneratedEvents{0}; +}; + +///___________________________________________________________ +FairGenerator *generateDoublePhi(int gap = 0, double minPt = 0.0, double maxPt = 100.0, double maxEta = 0.8) +{ + auto myGenerator = new GeneratorPythia8DoublePhi(gap, minPt, maxPt, maxEta); + + myGenerator->readString("333:onMode = off"); + myGenerator->readString("333:onIfMatch = 321 -321"); + + auto seed = (gRandom->TRandom::GetSeed() % 900000000); + myGenerator->readString("Random:setSeed on"); + myGenerator->readString("Random:seed " + std::to_string(seed)); + + return myGenerator; +} \ No newline at end of file From f09453b14d971deffaa7ea123e2476f315f7ce90 Mon Sep 17 00:00:00 2001 From: sawan Date: Sat, 3 Oct 2026 11:35:51 +0530 Subject: [PATCH 2/2] commented out recurring print statements and injection logic --- MC/config/PWGLF/pythia8/generator_pythia8_phiphi.C | 5 +++++ MC/config/PWGLF/pythia8/generator_pythia8_twophi_trigger.C | 6 +++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/MC/config/PWGLF/pythia8/generator_pythia8_phiphi.C b/MC/config/PWGLF/pythia8/generator_pythia8_phiphi.C index 605f8b303..46aa5b75d 100644 --- a/MC/config/PWGLF/pythia8/generator_pythia8_phiphi.C +++ b/MC/config/PWGLF/pythia8/generator_pythia8_phiphi.C @@ -98,6 +98,11 @@ public: // Resonant signal -> Decays into 333 333 injectParticle(mResoPDG, 1); } + else if (mSignalInterval <= 0) + { + // Continuous signal -> Decays into 333 333 + injectParticle(mResoPDG, 1); + } // 4. Force Decay of injected particles using Pythia's Decayer mPythiaGun.moreDecays(); diff --git a/MC/config/PWGLF/pythia8/generator_pythia8_twophi_trigger.C b/MC/config/PWGLF/pythia8/generator_pythia8_twophi_trigger.C index da20738e1..8de46d445 100644 --- a/MC/config/PWGLF/pythia8/generator_pythia8_twophi_trigger.C +++ b/MC/config/PWGLF/pythia8/generator_pythia8_twophi_trigger.C @@ -71,7 +71,7 @@ protected: bool generateEvent() override { - fmt::printf(">> Generating event %d\n", mGeneratedEvents); + // fmt::printf(">> Generating event %d\n", mGeneratedEvents); bool genOk = false; int localCounter{0}; @@ -82,7 +82,7 @@ protected: if (mGapSize > 0 && (mGeneratedEvents % (mGapSize + 1) < mGapSize)) { genOk = GeneratorPythia8::generateEvent(); - fmt::printf(">> Gap-event (no phi check)\n"); + // fmt::printf(">> Gap-event (no phi check)\n"); } else { @@ -99,7 +99,7 @@ protected: fmt::printf("Failed to generate triggered event after %d tries\n", kMaxTries); return false; } - fmt::printf(">> Triggered event: event accepted after %d iterations (double phi(1020))\n", localCounter); + // fmt::printf(">> Triggered event: event accepted after %d iterations (double phi(1020))\n", localCounter); } notifySubGenerator(0);