diff --git a/MC/config/PWGEM/external/generator/Generator_pythia8_GapTriggered_HFLepton_pp5360.C b/MC/config/PWGEM/external/generator/Generator_pythia8_GapTriggered_HFLepton_pp5360.C new file mode 100644 index 000000000..3daa246ae --- /dev/null +++ b/MC/config/PWGEM/external/generator/Generator_pythia8_GapTriggered_HFLepton_pp5360.C @@ -0,0 +1,224 @@ +#include "Pythia8/Pythia.h" +#include "Pythia8/HeavyIons.h" +#include "FairGenerator.h" +#include "FairPrimaryGenerator.h" +#include "Generators/GeneratorPythia8.h" +#include "TRandom3.h" +#include "TParticlePDG.h" +#include "TDatabasePDG.h" + +#include +#include +//#include // for std::pair + +using namespace Pythia8; + +class GeneratorPythia8GapTriggeredHFLepton : public o2::eventgen::GeneratorPythia8 +{ +public: + /// default constructor + GeneratorPythia8GapTriggeredHFLepton() = default; + + /// constructor + GeneratorPythia8GapTriggeredHFLepton(TString configsignal, int quarkPdg = 4, int lInputTriggerRatio = 5, int lInputExternalID = 0) + { + + lGeneratedEvents = 0; + lInverseTriggerRatio = lInputTriggerRatio; + lExternalID = lInputExternalID; + mQuarkPdg = quarkPdg; + + auto seed = (gRandom->TRandom::GetSeed() % 900000000); + + int offset = (int)(gRandom->Uniform(lInverseTriggerRatio)); // create offset to mitigate edge effects due to small number of events per job + lGeneratedEvents += offset; + + cout << "Initalizing extra PYTHIA object used to generate min-bias events..." << endl; + TString pathconfigMB = gSystem->ExpandPathName("${O2DPG_MC_CONFIG_ROOT}/MC/config/PWGEM/pythia8/generator/pythia8_pp_5360_MB_gapevent.cfg"); + pythiaObjectMinimumBias.readFile(pathconfigMB.Data()); + pythiaObjectMinimumBias.readString("Random:setSeed on"); + pythiaObjectMinimumBias.readString("Random:seed " + std::to_string(seed)); + pythiaObjectMinimumBias.init(); + cout << "Initalization complete" << endl; + cout << "Initalizing extra PYTHIA object used to generate signal events..." << endl; + TString pathconfigSignal = gSystem->ExpandPathName(configsignal.Data()); + pythiaObjectSignal.readFile(pathconfigSignal.Data()); + pythiaObjectSignal.readString("Random:setSeed on"); + pythiaObjectSignal.readString("Random:seed " + std::to_string(seed)); + pythiaObjectSignal.init(); + cout << "Initalization complete" << endl; + // flag the generators using type + // addCocktailConstituent(type, "interesting"); + // addCocktailConstitent(0, "minbias"); + // Add Sub generators + addSubGenerator(0, "default generator"); + addSubGenerator(1, "charm lepton"); + addSubGenerator(2, "beauty forced decay"); + addSubGenerator(3, "beauty no foced decay"); + } + + /// Destructor + ~GeneratorPythia8GapTriggeredHFLepton() = default; + + void addTriggerOnDaughter(int nb, int pdg) + { + mNbDaughter = nb; + mPdgDaughter = pdg; + }; + void setQuarkRapidity(float yMin, float yMax) + { + mQuarkRapidityMin = yMin; + mQuarkRapidityMax = yMax; + }; + void setDaughterRapidity(float yMin, float yMax) + { + mDaughterRapidityMin = yMin; + mDaughterRapidityMax = yMax; + }; + +protected: + //__________________________________________________________________ + Bool_t generateEvent() override + { + /// reset event + mPythia.event.reset(); + + // Simple straightforward check to alternate generators + if (lGeneratedEvents % lInverseTriggerRatio == 0) { + // Generate event of interest + Bool_t lGenerationOK = kFALSE; + while (!lGenerationOK) { + if (pythiaObjectSignal.next()) { + lGenerationOK = selectEvent(pythiaObjectSignal.event); + } + } + mPythia.event = pythiaObjectSignal.event; + notifySubGenerator(lExternalID); + } else { + // Generate minimum-bias event + Bool_t lGenerationOK = kFALSE; + while (!lGenerationOK) { + lGenerationOK = pythiaObjectMinimumBias.next(); + } + mPythia.event = pythiaObjectMinimumBias.event; + notifySubGenerator(0); + } + + lGeneratedEvents++; + // mPythia.next(); + + return true; + } + + bool selectEvent(const Pythia8::Event& event) + { + bool isGoodAtPartonLevel = false, isGoodAtDaughterLevel = (mPdgDaughter != 0) ? false : true; + int nbDaughter = 0; + for (auto iPart{0}; iPart < event.size(); ++iPart) { + // search for Q-Qbar mother with at least one Q in rapidity window + if (!isGoodAtPartonLevel) { + auto daughterList = event[iPart].daughterList(); + bool hasQ = false, hasQbar = false, atSelectedY = false; + for (auto iDau : daughterList) { + if (event[iDau].id() == mQuarkPdg) { + hasQ = true; + } + if (event[iDau].id() == -mQuarkPdg) { + hasQbar = true; + } + if ((std::abs(event[iDau].id()) == mQuarkPdg) && (event[iDau].y() > mQuarkRapidityMin) && (event[iDau].y() < mQuarkRapidityMax)) + atSelectedY = true; + } + if (hasQ && hasQbar && atSelectedY) { + isGoodAtPartonLevel = true; + } + } + // search for mNbDaughter daughters of type mPdgDaughter in rapidity window + if (!isGoodAtDaughterLevel) { + int id = std::abs(event[iPart].id()); + float rap = event[iPart].y(); + if (id == mPdgDaughter) { + int motherindexa = event[iPart].mother1(); + if (motherindexa > 0) { + int idmother = std::abs(event[motherindexa].id()); + if (int(std::abs(idmother) / 100.) == 4 || int(std::abs(idmother) / 1000.) == 4 || int(std::abs(idmother) / 100.) == 5 || int(std::abs(idmother) / 1000.) == 5) { + if (rap > mDaughterRapidityMin && rap < mDaughterRapidityMax) { + nbDaughter++; + if (nbDaughter >= mNbDaughter) isGoodAtDaughterLevel = true; + } + } + } + } + } + // we send the trigger + if (isGoodAtPartonLevel && isGoodAtDaughterLevel) { + return true; + } + } + return false; + }; + +private: + // Interface to override import particles + Pythia8::Event mOutputEvent; + + // Properties of selection + int mQuarkPdg; + float mQuarkRapidityMin; + float mQuarkRapidityMax; + int mPdgDaughter; + int mNbDaughter; + float mDaughterRapidityMin; + float mDaughterRapidityMax; + + // Control gap-triggering + Long64_t lGeneratedEvents; + int lInverseTriggerRatio; + // ID for different generators + int lExternalID; + + // Base event generators + Pythia8::Pythia pythiaObjectMinimumBias; ///Minimum bias collision generator + Pythia8::Pythia pythiaObjectSignal; ///Signal collision generator +}; + +// Predefined generators: + +// Charm-enriched forced decay +FairGenerator* GeneratorPythia8GapTriggeredCharmLepton(int inputTriggerRatio, int inputExternalID, float yMin = -1.5, float yMax = 1.5) +{ + auto myGen = new GeneratorPythia8GapTriggeredHFLepton("${O2DPG_MC_CONFIG_ROOT}/MC/config/PWGEM/pythia8/generator/pythia8_pp_5360_cr2_forceddecayscharm.cfg", 4, inputTriggerRatio, inputExternalID); + auto seed = (gRandom->TRandom::GetSeed() % 900000000); + myGen->readString("Random:setSeed on"); + myGen->readString("Random:seed " + std::to_string(seed)); + myGen->setQuarkRapidity(yMin, yMax); + myGen->addTriggerOnDaughter(2, 11); + myGen->setDaughterRapidity(-1., 1.); + return myGen; +} + +// Beauty-enriched forced decay +FairGenerator* GeneratorPythia8GapTriggeredBeautyForcedDecays(int inputTriggerRatio, int inputExternalID, float yMin = -1.5, float yMax = 1.5) +{ + auto myGen = new GeneratorPythia8GapTriggeredHFLepton("${O2DPG_MC_CONFIG_ROOT}/MC/config/PWGEM/pythia8/generator/pythia8_pp_5360_bbbar_forceddecayscharmbeauty.cfg", 5, inputTriggerRatio, inputExternalID); + auto seed = (gRandom->TRandom::GetSeed() % 900000000); + myGen->readString("Random:setSeed on"); + myGen->readString("Random:seed " + std::to_string(seed)); + myGen->setQuarkRapidity(yMin, yMax); + myGen->addTriggerOnDaughter(2, 11); + myGen->setDaughterRapidity(-1., 1.); + return myGen; +} + +// Beauty-enriched no forced decay +FairGenerator* GeneratorPythia8GapTriggeredBeautyNoForcedDecays(int inputTriggerRatio, int inputExternalID, float yMin = -1.5, float yMax = 1.5) +{ + auto myGen = new GeneratorPythia8GapTriggeredHFLepton("${O2DPG_MC_CONFIG_ROOT}/MC/config/PWGEM/pythia8/generator/pythia8_pp_5360_bbbar.cfg", 5, inputTriggerRatio, inputExternalID); + auto seed = (gRandom->TRandom::GetSeed() % 900000000); + myGen->readString("Random:setSeed on"); + myGen->readString("Random:seed " + std::to_string(seed)); + myGen->setQuarkRapidity(yMin, yMax); + myGen->addTriggerOnDaughter(2, 11); + myGen->setDaughterRapidity(-1., 1.); + return myGen; +} diff --git a/MC/config/PWGEM/ini/GeneratorHFGapTriggered_BeautyForcedDecay_Gap5_pp5360GeV.ini b/MC/config/PWGEM/ini/GeneratorHFGapTriggered_BeautyForcedDecay_Gap5_pp5360GeV.ini new file mode 100644 index 000000000..54de7afa1 --- /dev/null +++ b/MC/config/PWGEM/ini/GeneratorHFGapTriggered_BeautyForcedDecay_Gap5_pp5360GeV.ini @@ -0,0 +1,7 @@ +[GeneratorExternal] +fileName = ${O2DPG_MC_CONFIG_ROOT}/MC/config/PWGEM/external/generator/Generator_pythia8_GapTriggered_HFLepton_pp5360.C +funcName = GeneratorPythia8GapTriggeredBeautyForcedDecays(5,2) + +[GeneratorPythia8] +config = ${O2DPG_MC_CONFIG_ROOT}/MC/config/PWGEM/pythia8/generator/configPythiaEmpty.cfg +includePartonEvent = true diff --git a/MC/config/PWGEM/ini/GeneratorHFGapTriggered_BeautyNoForcedDecay_Gap5_pp5360GeV.ini b/MC/config/PWGEM/ini/GeneratorHFGapTriggered_BeautyNoForcedDecay_Gap5_pp5360GeV.ini new file mode 100644 index 000000000..0cc38a529 --- /dev/null +++ b/MC/config/PWGEM/ini/GeneratorHFGapTriggered_BeautyNoForcedDecay_Gap5_pp5360GeV.ini @@ -0,0 +1,7 @@ +[GeneratorExternal] +fileName = ${O2DPG_MC_CONFIG_ROOT}/MC/config/PWGEM/external/generator/Generator_pythia8_GapTriggered_HFLepton_pp5360.C +funcName = GeneratorPythia8GapTriggeredBeautyNoForcedDecays(5,3) + +[GeneratorPythia8] +config = ${O2DPG_MC_CONFIG_ROOT}/MC/config/PWGEM/pythia8/generator/configPythiaEmpty.cfg +includePartonEvent = true diff --git a/MC/config/PWGEM/ini/GeneratorHFGapTriggered_Charm_Gap5_pp5360GeV.ini b/MC/config/PWGEM/ini/GeneratorHFGapTriggered_Charm_Gap5_pp5360GeV.ini new file mode 100644 index 000000000..e653a993b --- /dev/null +++ b/MC/config/PWGEM/ini/GeneratorHFGapTriggered_Charm_Gap5_pp5360GeV.ini @@ -0,0 +1,7 @@ +[GeneratorExternal] +fileName = ${O2DPG_MC_CONFIG_ROOT}/MC/config/PWGEM/external/generator/Generator_pythia8_GapTriggered_HFLepton_pp5360.C +funcName = GeneratorPythia8GapTriggeredCharmLepton(5,1) + +[GeneratorPythia8] +config = ${O2DPG_MC_CONFIG_ROOT}/MC/config/PWGEM/pythia8/generator/configPythiaEmpty.cfg +includePartonEvent = true diff --git a/MC/config/PWGEM/ini/tests/GeneratorHFGapTriggered_BeautyForcedDecay_Gap5_pp5360GeV.C b/MC/config/PWGEM/ini/tests/GeneratorHFGapTriggered_BeautyForcedDecay_Gap5_pp5360GeV.C new file mode 100644 index 000000000..5bee390cc --- /dev/null +++ b/MC/config/PWGEM/ini/tests/GeneratorHFGapTriggered_BeautyForcedDecay_Gap5_pp5360GeV.C @@ -0,0 +1,118 @@ +int External() +{ + + int checkPdgDecay = -11; + 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; + } + + float ratioTrigger = 1./3; // one event triggered out of 3 + auto tree = (TTree*)file.Get("o2sim"); + std::vector* tracks{}; + tree->SetBranchAddress("MCTrack", &tracks); + + int nLeptonsInAcceptance{}; + int nLeptons{}; + int nAntileptons{}; + int nLeptonsToBeDone{}; + int nAntileptonsToBeDone{}; + int nSignalPairs{}; + int nLeptonPairs{}; + int nLeptonPairsToBeDone{}; + auto nEvents = tree->GetEntries(); + + for (int i = 0; i < nEvents; i++) { + printf("Event %d\n",i); + tree->GetEntry(i); + int nElectrons = 0; + int nPositrons = 0; + int nElectronsToBeDone = 0; + int nPositronsToBeDone = 0; + int nOpenBeautyPos = 0; + int nOpenBeautyNeg = 0; + int nPositronsElectronsInAcceptance = 0; + for (auto& track : *tracks) { + auto pdg = track.GetPdgCode(); + auto y = track.GetRapidity(); + if (pdg == checkPdgDecay) { + int igmother = track.getMotherTrackId(); + if (igmother > 0) { + auto gmTrack = (*tracks)[igmother]; + int gmpdg = gmTrack.GetPdgCode(); + if (int(std::abs(gmpdg)/100.) == 5 || int(std::abs(gmpdg)/1000.) == 5 || int(std::abs(gmpdg)/100.) == 4 || int(std::abs(gmpdg)/1000.) == 4) { + nLeptons++; + nElectrons++; + if (-1 < y && y < 1) nPositronsElectronsInAcceptance++; + if (track.getToBeDone()) { + nLeptonsToBeDone++; + nElectronsToBeDone++; + } + } + } + } else if (pdg == -checkPdgDecay) { + int igmother = track.getMotherTrackId(); + if (igmother > 0) { + auto gmTrack = (*tracks)[igmother]; + int gmpdg = gmTrack.GetPdgCode(); + if (int(TMath::Abs(gmpdg)/100.) == 4 || int(TMath::Abs(gmpdg)/1000.) == 4 || int(std::abs(gmpdg)/100.) == 5 || int(std::abs(gmpdg)/1000.) == 5) { + nAntileptons++; + nPositrons++; + if (-1 < y && y < 1) nPositronsElectronsInAcceptance++; + if (track.getToBeDone()) { + nAntileptonsToBeDone++; + nPositronsToBeDone++; + } + } + } + } else if (pdg == 511 || pdg == 521 || pdg == 531 || pdg == 5122 || pdg == 5132 || pdg == 5232 || pdg == 5332) { + nOpenBeautyPos++; + } else if (pdg == -511 || pdg == -521 || pdg == -531 || pdg == -5122 || pdg == -5132 || pdg == -5232 || pdg == -5332) { + nOpenBeautyNeg++; + } + } + if (nOpenBeautyPos > 0 && nOpenBeautyNeg > 0) { + nSignalPairs++; + } + if (nPositronsElectronsInAcceptance > 1) { + nLeptonsInAcceptance++; + } + if (nElectrons > 0 && nPositrons > 0) { + nLeptonPairs++; + } + if (nElectronsToBeDone > 0 && nPositronsToBeDone > 0) nLeptonPairsToBeDone++; + } + std::cout << "#events: " << nEvents << "\n" + << "#leptons: " << nLeptons << "\n" + << "#antileptons: " << nAntileptons << "\n" + << "#leptons to be done: " << nLeptonsToBeDone << "\n" + << "#antileptons to be done: " << nAntileptonsToBeDone << "\n" + << "#Open-beauty hadron pairs: " << nSignalPairs << "\n" + << "#leptons in acceptance: " << nLeptonsInAcceptance << "\n" + << "#Electron-positron pairs " << nLeptonPairs << "\n" + << "#Electron-positron pairs to be done: " << nLeptonPairsToBeDone << "\n"; + if (nLeptons == 0 && nAntileptons == 0) { + std::cerr << "Number of leptons, number of anti-leptons should all be greater than 1.\n"; + return 1; + } + if (nLeptonPairs != nLeptonPairsToBeDone) { + std::cerr << "The number of electron-positron pairs should be the same as the number of electron-positron pairs which should be transported.\n"; + return 1; + } + if (nLeptons != nLeptonsToBeDone) { + std::cerr << "The number of leptons should be the same as the number of leptons which should be transported.\n"; + return 1; + } + if (nLeptonsInAcceptance == (nEvents/ratioTrigger)) { + std::cerr << "The number of leptons in acceptance should be at least equaled to the number of events.\n"; + return 1; + } + if (nLeptonPairs < nLeptonsInAcceptance) { + std::cerr << "The number of positron-electron pairs should be at least equaled to the number of leptons in acceptance.\n"; + return 1; + } + + return 0; +} diff --git a/MC/config/PWGEM/ini/tests/GeneratorHFGapTriggered_BeautyNoForcedDecay_Gap5_pp5360GeV.C b/MC/config/PWGEM/ini/tests/GeneratorHFGapTriggered_BeautyNoForcedDecay_Gap5_pp5360GeV.C new file mode 100644 index 000000000..10907110b --- /dev/null +++ b/MC/config/PWGEM/ini/tests/GeneratorHFGapTriggered_BeautyNoForcedDecay_Gap5_pp5360GeV.C @@ -0,0 +1,113 @@ +int External() +{ + + int checkPdgDecay = -11; + 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; + } + + float ratioTrigger = 1./3; // one event triggered out of 3 + auto tree = (TTree*)file.Get("o2sim"); + std::vector* tracks{}; + tree->SetBranchAddress("MCTrack", &tracks); + + int nLeptonsInAcceptance{}; + int nLeptons{}; + int nAntileptons{}; + int nLeptonsToBeDone{}; + int nAntileptonsToBeDone{}; + int nSignalPairs{}; + int nLeptonPairs{}; + int nLeptonPairsToBeDone{}; + auto nEvents = tree->GetEntries(); + + for (int i = 0; i < nEvents; i++) { + tree->GetEntry(i); + int nElectrons = 0; + int nPositrons = 0; + int nElectronsToBeDone = 0; + int nPositronsToBeDone = 0; + int nOpenBeautyPos = 0; + int nOpenBeautyNeg = 0; + int nPositronsElectronsInAcceptance = 0; + for (auto& track : *tracks) { + auto pdg = track.GetPdgCode(); + auto y = track.GetRapidity(); + if (pdg == checkPdgDecay) { + int igmother = track.getMotherTrackId(); + if (igmother > 0) { + auto gmTrack = (*tracks)[igmother]; + int gmpdg = gmTrack.GetPdgCode(); + if (int(std::abs(gmpdg)/100.) == 5 || int(std::abs(gmpdg)/1000.) == 5 || int(std::abs(gmpdg)/100.) == 4 || int(std::abs(gmpdg)/1000.) == 4) { + nLeptons++; + nElectrons++; + if (-1 < y && y < 1) nPositronsElectronsInAcceptance++; + if (track.getToBeDone()) { + nLeptonsToBeDone++; + nElectronsToBeDone++; + } + } + } + } else if (pdg == -checkPdgDecay) { + int igmother = track.getMotherTrackId(); + if (igmother > 0) { + auto gmTrack = (*tracks)[igmother]; + int gmpdg = gmTrack.GetPdgCode(); + if (int(TMath::Abs(gmpdg)/100.) == 4 || int(TMath::Abs(gmpdg)/1000.) == 4 || int(std::abs(gmpdg)/100.) == 5 || int(std::abs(gmpdg)/1000.) == 5) { + nAntileptons++; + nPositrons++; + if (-1 < y && y < 1) nPositronsElectronsInAcceptance++; + if (track.getToBeDone()) { + nAntileptonsToBeDone++; + nPositronsToBeDone++; + } + } + } + } else if (pdg == 511 || pdg == 521 || pdg == 531 || pdg == 5122 || pdg == 5132 || pdg == 5232 || pdg == 5332) { + nOpenBeautyPos++; + } else if (pdg == -511 || pdg == -521 || pdg == -531 || pdg == -5122 || pdg == -5132 || pdg == -5232 || pdg == -5332) { + nOpenBeautyNeg++; + } + } + if (nOpenBeautyPos > 0 && nOpenBeautyNeg > 0) { + nSignalPairs++; + } + if (nPositronsElectronsInAcceptance > 1) { + nLeptonsInAcceptance++; + } + if (nElectrons > 0 && nPositrons > 0) { + nLeptonPairs++; + } + if (nElectronsToBeDone > 0 && nPositronsToBeDone > 0) nLeptonPairsToBeDone++; + } + std::cout << "#events: " << nEvents << "\n" + << "#leptons: " << nLeptons << "\n" + << "#antileptons: " << nAntileptons << "\n" + << "#leptons to be done: " << nLeptonsToBeDone << "\n" + << "#antileptons to be done: " << nAntileptonsToBeDone << "\n" + << "#Open-beauty hadron pairs: " << nSignalPairs << "\n" + << "#leptons in acceptance: " << nLeptonsInAcceptance << "\n" + << "#Electron-positron pairs: " << nLeptonPairs << "\n" + << "#Electron-positron pairs to be done: " << nLeptonPairsToBeDone << "\n"; + if (nLeptons == 0 && nAntileptons == 0) { + std::cerr << "Number of leptons, number of anti-leptons should all be greater than 1.\n"; + return 1; + } + if (nLeptonPairs != nLeptonPairsToBeDone) { + std::cerr << "The number of lepton pairs should be the same as the number of lepton pairs which should be transported.\n"; + return 1; + } + if (nLeptons != nLeptonsToBeDone) { + std::cerr << "The number of leptons should be the same as the number of leptons which should be transported.\n"; + return 1; + } + if (nLeptonsInAcceptance == (nEvents/ratioTrigger)) { + std::cerr << "The number of leptons in acceptance should be at least equaled to the number of events.\n"; + return 1; + } + + return 0; +} diff --git a/MC/config/PWGEM/ini/tests/GeneratorHFGapTriggered_Charm_Gap5_pp5360GeV.C b/MC/config/PWGEM/ini/tests/GeneratorHFGapTriggered_Charm_Gap5_pp5360GeV.C new file mode 100644 index 000000000..9081b8a81 --- /dev/null +++ b/MC/config/PWGEM/ini/tests/GeneratorHFGapTriggered_Charm_Gap5_pp5360GeV.C @@ -0,0 +1,117 @@ +int External() +{ + + int checkPdgDecay = -11; + 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; + } + + float ratioTrigger = 1./3.; // one event triggered out of 3 + auto tree = (TTree*)file.Get("o2sim"); + std::vector* tracks{}; + tree->SetBranchAddress("MCTrack", &tracks); + + int nLeptonsInAcceptance{}; + int nLeptons{}; + int nAntileptons{}; + int nLeptonsToBeDone{}; + int nAntileptonsToBeDone{}; + int nSignalPairs{}; + int nLeptonPairs{}; + int nLeptonPairsToBeDone{}; + auto nEvents = tree->GetEntries(); + + for (int i = 0; i < nEvents; i++) { + tree->GetEntry(i); + int nElectrons = 0; + int nPositrons = 0; + int nElectronsToBeDone = 0; + int nPositronsToBeDone = 0; + int nOpenCharmPos = 0; + int nOpenCharmNeg = 0; + int nPositronsElectronsInAcceptance = 0; + for (auto& track : *tracks) { + auto pdg = track.GetPdgCode(); + auto y = track.GetRapidity(); + if (pdg == checkPdgDecay) { + int igmother = track.getMotherTrackId(); + if (igmother > 0) { + auto gmTrack = (*tracks)[igmother]; + int gmpdg = gmTrack.GetPdgCode(); + if (int(std::abs(gmpdg)/100.) == 4 || int(std::abs(gmpdg)/1000.) == 4) { + nLeptons++; + nElectrons++; + if (-1 < y && y < 1) nPositronsElectronsInAcceptance++; + if (track.getToBeDone()) { + nLeptonsToBeDone++; + nElectronsToBeDone++; + } + } + } + } else if (pdg == -checkPdgDecay) { + int igmother = track.getMotherTrackId(); + if (igmother > 0) { + auto gmTrack = (*tracks)[igmother]; + int gmpdg = gmTrack.GetPdgCode(); + if (int(TMath::Abs(gmpdg)/100.) == 4 || int(TMath::Abs(gmpdg)/1000.) == 4) { + nAntileptons++; + nPositrons++; + if (-1 < y && y < 1) nPositronsElectronsInAcceptance++; + if (track.getToBeDone()) { + nAntileptonsToBeDone++; + nPositronsToBeDone++; + } + } + } + } else if (pdg == 411 || pdg == 421 || pdg == 431 || pdg == 4122 || pdg == 4132 || pdg == 4232 || pdg == 4332) { + nOpenCharmPos++; + } else if (pdg == -411 || pdg == -421 || pdg == -431 || pdg == -4122 || pdg == -4132 || pdg == -4232 || pdg == -4332) { + nOpenCharmNeg++; + } + } + if (nOpenCharmPos > 0 && nOpenCharmNeg > 0) { + nSignalPairs++; + } + if (nPositronsElectronsInAcceptance > 1) { + nLeptonsInAcceptance++; + } + if (nElectrons > 0 && nPositrons > 0) { + nLeptonPairs++; + } + if (nElectronsToBeDone > 0 && nPositronsToBeDone > 0) nLeptonPairsToBeDone++; + } + std::cout << "#events: " << nEvents << "\n" + << "#leptons: " << nLeptons << "\n" + << "#antileptons: " << nAntileptons << "\n" + << "#leptons to be done: " << nLeptonsToBeDone << "\n" + << "#antileptons to be done: " << nAntileptonsToBeDone << "\n" + << "#open-charm hadron pairs: " << nSignalPairs << "\n" + << "#leptons in acceptance: " << nLeptonsInAcceptance << "\n" + << "#Electron-positron pairs: " << nLeptonPairs << "\n" + << "#Electron-positron pairs to be done: " << nLeptonPairsToBeDone << "\n"; + if (nLeptons == 0 && nAntileptons == 0) { + std::cerr << "Number of leptons, number of anti-leptons should all be greater than 1.\n"; + return 1; + } + if (nLeptonPairs != nLeptonPairsToBeDone) { + std::cerr << "The number of electron-positron pairs should be the same as the number of electron-positron pairs which should be transported.\n"; + return 1; + } + if (nLeptons != nLeptonsToBeDone) { + std::cerr << "The number of leptons should be the same as the number of leptons which should be transported.\n"; + return 1; + } + if (nLeptonsInAcceptance == (nEvents/ratioTrigger)) { + std::cerr << "The number of leptons in acceptance should be at least equaled to the number of events.\n"; + return 1; + } + if (nLeptonPairs < nLeptonsInAcceptance) { + std::cerr << "The number of positron-electron pairs should be at least equaled to the number of leptons in acceptance.\n"; + return 1; + } + + return 0; +} diff --git a/MC/config/PWGEM/pythia8/generator/pythia8_pp_5360_MB_gapevent.cfg b/MC/config/PWGEM/pythia8/generator/pythia8_pp_5360_MB_gapevent.cfg new file mode 100644 index 000000000..b3fdfdd99 --- /dev/null +++ b/MC/config/PWGEM/pythia8/generator/pythia8_pp_5360_MB_gapevent.cfg @@ -0,0 +1,15 @@ +### beams +Beams:idA 2212 # proton +Beams:idB 2212 # proton +Beams:eCM 5360 # GeV + +### processes +SoftQCD:inelastic on # all inelastic processes + +### per default it is Monash anyway +Tune:pp = 14 + +### decays +ParticleDecays:limitTau0 on +ParticleDecays:tau0Max 10. + diff --git a/MC/config/PWGEM/pythia8/generator/pythia8_pp_5360_bbbar.cfg b/MC/config/PWGEM/pythia8/generator/pythia8_pp_5360_bbbar.cfg new file mode 100644 index 000000000..3e1df36b7 --- /dev/null +++ b/MC/config/PWGEM/pythia8/generator/pythia8_pp_5360_bbbar.cfg @@ -0,0 +1,36 @@ +### beams +Beams:idA 2212 # proton +Beams:idB 2212 # proton +Beams:eCM 5360 # GeV + +### processes +#HardQCD:hardccbar on # scatterings g-g / q-qbar -> c-cbar +HardQCD:hardbbbar on # scatterings g-g / q-qbar -> b-bbar + +### decays +ParticleDecays:limitTau0 on +ParticleDecays:tau0Max 10. + +### switch on color reconnection in mode 2 (https://arxiv.org/pdf/1505.01681.pdf) +Tune:pp = 14 +ColourReconnection:mode = 1 +ColourReconnection:allowDoubleJunRem = off +ColourReconnection:m0 = 0.3 +ColourReconnection:allowJunctions = on +ColourReconnection:junctionCorrection = 1.20 +ColourReconnection:timeDilationMode = 2 +ColourReconnection:timeDilationPar = 0.18 +StringPT:sigma = 0.335 +StringZ:aLund = 0.36 +StringZ:bLund = 0.56 +StringFlav:probQQtoQ = 0.078 +StringFlav:ProbStoUD = 0.2 +StringFlav:probQQ1toQQ0join = 0.0275,0.0275,0.0275,0.0275 +MultiPartonInteractions:pT0Ref = 2.15 +BeamRemnants:remnantMode = 1 +BeamRemnants:saturation =5 + +# Correct OmegaC decay length (wrong in PYTHIA8 decay table) (mm/c) +4332:tau0 = 0.08000000000 +# Correct Lb decay length (wrong in PYTHIA8 decay table) +5122:tau0 = 4.41000e-01 diff --git a/MC/config/PWGEM/pythia8/generator/pythia8_pp_5360_bbbar_forceddecayscharmbeauty.cfg b/MC/config/PWGEM/pythia8/generator/pythia8_pp_5360_bbbar_forceddecayscharmbeauty.cfg new file mode 100644 index 000000000..c3beca4d5 --- /dev/null +++ b/MC/config/PWGEM/pythia8/generator/pythia8_pp_5360_bbbar_forceddecayscharmbeauty.cfg @@ -0,0 +1,127 @@ +### beams +Beams:idA 2212 # proton +Beams:idB 2212 # proton +Beams:eCM 5360 # GeV + +### processes +#HardQCD:hardccbar on # scatterings g-g / q-qbar -> c-cbar +HardQCD:hardbbbar on # scatterings g-g / q-qbar -> b-bbar + +### decays +ParticleDecays:limitTau0 on +ParticleDecays:tau0Max 10. + +### switch on color reconnection in mode 2 (https://arxiv.org/pdf/1505.01681.pdf) +Tune:pp = 14 +ColourReconnection:mode = 1 +ColourReconnection:allowDoubleJunRem = off +ColourReconnection:m0 = 0.3 +ColourReconnection:allowJunctions = on +ColourReconnection:junctionCorrection = 1.20 +ColourReconnection:timeDilationMode = 2 +ColourReconnection:timeDilationPar = 0.18 +StringPT:sigma = 0.335 +StringZ:aLund = 0.36 +StringZ:bLund = 0.56 +StringFlav:probQQtoQ = 0.078 +StringFlav:ProbStoUD = 0.2 +StringFlav:probQQ1toQQ0join = 0.0275,0.0275,0.0275,0.0275 +MultiPartonInteractions:pT0Ref = 2.15 +BeamRemnants:remnantMode = 1 +BeamRemnants:saturation =5 + +### only semileptonic decays from https://pdg.lbl.gov/2025/ +### D+ +411:oneChannel = 1 0.0881 0 -311 -11 12 +411:addChannel = 1 0.0402 0 -321 211 -11 12 +411:addChannel = 1 0.0540 0 -313 -11 12 +### D0 +421:oneChannel = 1 0.0354 0 -321 -11 12 +421:addChannel = 1 0.0216 0 -323 -11 12 +421:addChannel = 1 0.0160 0 -321 111 -11 12 +421:addChannel = 1 0.0144 0 -311 211 -11 12 +### Ds +431:oneChannel = 1 0.0234 0 333 -11 12 +431:addChannel = 1 0.0227 0 221 -11 12 +431:addChannel = 1 0.0081 0 331 -11 12 +431:addChannel = 1 0.0029 0 311 -11 12 +431:addChannel = 1 0.0021 0 313 -11 12 +### Lambdac +4122:oneChannel = 1 0.0356 0 3122 -11 12 +4122:oneChannel = 1 0.0009 0 2212 -321 -11 12 +4122:oneChannel = 1 0.0010 0 3124 -11 12 +4122:oneChannel = 1 0.0004 0 3126 -11 12 +### Xi_{c}^{+} +4232:oneChannel = 1 0.07 0 3322 -11 12 +### Xi_{c}^{0} +4132:oneChannel = 1 0.0105 0 3312 -11 12 +### Omega_{c} +4332:oneChannel = 1 0.01224 0 3334 -11 12 + +### only semileptonic decays for beauty from https://pdg.lbl.gov/2025/ +### B0 +511:oneChannel = 1 0.021000 0 12 -11 -411 +511:addChannel = 1 0.048700 0 12 -11 -413 +511:addChannel = 1 0.002300 0 12 -11 -415 +511:addChannel = 1 0.000150 0 12 -11 -211 +511:addChannel = 1 0.000294 0 12 -11 -213 +#511:addChannel = 1 0.004500 0 12 -11 -10411 +#511:addChannel = 1 0.005200 0 12 -11 -10413 +#511:addChannel = 1 0.008300 0 12 -11 -20413 +511:addChannel = 1 0.003640 0 12 -11 -421 -211 +511:addChannel = 1 0.005440 0 12 -11 -423 -211 +511:addChannel = 1 0.001450 0 12 -11 -411 -211 211 +511:addChannel = 1 0.000510 0 12 -11 -413 -211 211 + +### B+ +521:oneChannel = 1 0.000078 0 12 -11 111 +521:addChannel = 1 0.000158 0 12 -11 113 +521:addChannel = 1 0.000035 0 12 -11 221 +521:addChannel = 1 0.000119 0 12 -11 223 +521:addChannel = 1 0.000024 0 12 -11 331 +521:addChannel = 1 0.022600 0 12 -11 -421 +521:addChannel = 1 0.052600 0 12 -11 -423 +521:addChannel = 1 0.001590 0 12 -11 -425 +#521:addChannel = 1 0.000900 0 12 -11 -10421 +#521:addChannel = 1 0.002840 0 12 -11 -10423 +#521:addChannel = 1 0.001700 0 12 -11 -20423 +521:addChannel = 1 0.003820 0 12 -11 -411 211 +521:addChannel = 1 0.005420 0 12 -11 -413 211 +521:addChannel = 1 0.001730 0 12 -11 -421 -211 211 +521:addChannel = 1 0.000700 0 12 -11 -423 -211 211 +521:addChannel = 1 0.000300 0 12 -11 -431 321 +521:addChannel = 1 0.000290 0 12 -11 -433 321 + +### Bs +531:oneChannel = 1 0.000106 0 12 -11 -321 +531:addChannel = 1 0.000300 0 12 -11 -323 +531:addChannel = 1 0.022900 0 12 -11 -431 +531:addChannel = 1 0.052000 0 12 -11 -433 +531:addChannel = 1 0.007000 0 12 -11 -435 +531:addChannel = 1 0.000300 0 12 -11 -10323 +531:addChannel = 1 0.004000 0 12 -11 -10431 +531:addChannel = 1 0.007000 0 12 -11 -10433 +531:addChannel = 1 0.000200 0 12 -11 -20323 +531:addChannel = 1 0.004000 0 12 -11 -20433 + +### Lambdab +5122:oneChannel = 1 0.0546000 0 -12 11 4122 +5122:addChannel = 1 0.0096000 0 -12 11 4124 +5122:addChannel = 1 0.0128000 0 -12 11 14122 + +### Xi_{b}^{-} +5132:oneChannel = 1 0.1080010 0 -12 11 4 3101 +5132:addChannel = 1 0.0020000 0 -12 11 2 3101 +### Xi_{b}^{0} +5232:oneChannel = 1 0.1080010 0 -12 11 4 3201 +5232:addChannel = 1 0.0020000 0 -12 11 2 3201 +### Omega_{b}^{-} +5332:oneChannel = 1 0.1080010 1 -12 11 4 3303 +5332:oneChannel = 1 0.0020000 1 -12 11 2 3303 + + +# Correct OmegaC decay length (wrong in PYTHIA8 decay table) (mm/c) +4332:tau0 = 0.08000000000 +# Correct Lb decay length (wrong in PYTHIA8 decay table) +5122:tau0 = 4.41000e-01 + diff --git a/MC/config/PWGEM/pythia8/generator/pythia8_pp_5360_cr2_forceddecayscharm.cfg b/MC/config/PWGEM/pythia8/generator/pythia8_pp_5360_cr2_forceddecayscharm.cfg new file mode 100644 index 000000000..bcac14ef5 --- /dev/null +++ b/MC/config/PWGEM/pythia8/generator/pythia8_pp_5360_cr2_forceddecayscharm.cfg @@ -0,0 +1,70 @@ +### main + +Main:timesAllowErrors 2000 +#allow more errors in the pythia. + + +### beams +Beams:idA 2212 # proton +Beams:idB 2212 # proton +Beams:eCM 5360 # GeV + +### processes +# HardQCD:hardccbar on # ccbar production +SoftQCD:inelastic = on + +### decays +ParticleDecays:limitTau0 on +ParticleDecays:tau0Max 10. + +### switch on color reconnection in mode 2 (https://arxiv.org/pdf/1505.01681.pdf) +Tune:pp = 14 +ColourReconnection:mode = 1 +ColourReconnection:allowDoubleJunRem = off +ColourReconnection:m0 = 0.3 +ColourReconnection:allowJunctions = on +ColourReconnection:junctionCorrection = 1.20 +ColourReconnection:timeDilationMode = 2 +ColourReconnection:timeDilationPar = 0.18 +StringPT:sigma = 0.335 +StringZ:aLund = 0.36 +StringZ:bLund = 0.56 +StringFlav:probQQtoQ = 0.078 +StringFlav:ProbStoUD = 0.2 +StringFlav:probQQ1toQQ0join = 0.0275,0.0275,0.0275,0.0275 +MultiPartonInteractions:pT0Ref = 2.15 +BeamRemnants:remnantMode = 1 +BeamRemnants:saturation =5 + +### only semileptonic decays from https://pdg.lbl.gov/2025/ +### D+ +411:oneChannel = 1 0.0881 0 -311 -11 12 +411:addChannel = 1 0.0402 0 -321 211 -11 12 +411:addChannel = 1 0.0540 0 -313 -11 12 +### D0 +421:oneChannel = 1 0.0354 0 -321 -11 12 +421:addChannel = 1 0.0216 0 -323 -11 12 +421:addChannel = 1 0.0160 0 -321 111 -11 12 +421:addChannel = 1 0.0144 0 -311 211 -11 12 +### Ds +431:oneChannel = 1 0.0234 0 333 -11 12 +431:addChannel = 1 0.0227 0 221 -11 12 +431:addChannel = 1 0.0081 0 331 -11 12 +431:addChannel = 1 0.0029 0 311 -11 12 +431:addChannel = 1 0.0021 0 313 -11 12 +### Lambdac +4122:oneChannel = 1 0.0356 0 3122 -11 12 +4122:oneChannel = 1 0.0009 0 2212 -321 -11 12 +4122:oneChannel = 1 0.0010 0 3124 -11 12 +4122:oneChannel = 1 0.0004 0 3126 -11 12 +### Xi_{c}^{+} +4232:oneChannel = 1 0.07 0 3322 -11 12 +### Xi_{c}^{0} +4132:oneChannel = 1 0.0105 0 3312 -11 12 +### Omega_{c} +4332:oneChannel = 1 0.01224 0 3334 -11 12 + +# Correct OmegaC decay length (wrong in PYTHIA8 decay table) (mm/c) +4332:tau0 = 0.08000000000 +# Correct Lb decay length (wrong in PYTHIA8 decay table) +5122:tau0 = 4.41000e-01 diff --git a/MC/run/PWGEM/runAnchoredDYee_pp_5360_Gap5.sh b/MC/run/PWGEM/runAnchoredDYee_pp_5360_Gap5.sh new file mode 100644 index 000000000..6d703d179 --- /dev/null +++ b/MC/run/PWGEM/runAnchoredDYee_pp_5360_Gap5.sh @@ -0,0 +1,50 @@ +#!/bin/bash + +# +# Steering script for HF enhanced dielectron MC anchored to LHC24ap,aq apass1 +# + +# example anchoring +# taken from https://its.cern.ch/jira/browse/O2-5670 +export ALIEN_JDL_LPMANCHORPASSNAME=apass1 +export ALIEN_JDL_MCANCHOR=apass1 +export ALIEN_JDL_CPULIMIT=8 +export ALIEN_JDL_LPMRUNNUMBER=559348 +export ALIEN_JDL_LPMPRODUCTIONTYPE=MC +export ALIEN_JDL_LPMINTERACTIONTYPE=pp +export ALIEN_JDL_LPMPRODUCTIONTAG=LHC24a6 +export ALIEN_JDL_LPMANCHORRUN=559348 +export ALIEN_JDL_LPMANCHORPRODUCTION=LHC24ap +export ALIEN_JDL_LPMANCHORYEAR=2024 +export ALIEN_JDL_OUTPUT=*.dat@disk=1,*.txt@disk=1,*.root@disk=2 + +export NTIMEFRAMES=1 +export NSIGEVENTS=20 +export SPLITID=100 +export PRODSPLIT=153 +export CYCLE=0 + +# on the GRID, this is set and used as seed; when set, it takes precedence over SEED +#export ALIEN_PROC_ID=2963436952 +export SEED=0 + +# for pp and 50 events per TF, we launch only 4 workers. +export NWORKERS=2 + +# define the generator via ini file +# use 20/40/40 sampling for different generators +# generate random number +#RNDSIG=$(($RANDOM % 100)) + +CONFIGNAME="GeneratorDYee_GapTriggered_Gap5_pp5360GeV.ini" + +export ALIEN_JDL_ANCHOR_SIM_OPTIONS="-gen external -ini $O2DPG_ROOT/MC/config/PWGEM/ini/$CONFIGNAME" + +# run the central anchor steering script; this includes +# * derive timestamp +# * derive interaction rate +# * extract and prepare configurations (which detectors are contained in the run etc.) +# * run the simulation (and QC) +# To disable QC, uncomment the following line +#export DISABLE_QC=1 +${O2DPG_ROOT}/MC/run/ANCHOR/anchorMC.sh diff --git a/MC/run/PWGEM/runAnchoredHFGapToDielectrons_pp_5360_Gap5.sh b/MC/run/PWGEM/runAnchoredHFGapToDielectrons_pp_5360_Gap5.sh new file mode 100644 index 000000000..019a53415 --- /dev/null +++ b/MC/run/PWGEM/runAnchoredHFGapToDielectrons_pp_5360_Gap5.sh @@ -0,0 +1,57 @@ +#!/bin/bash + +# +# Steering script for HF enhanced dielectron MC anchored to LHC24ap,aq apass1 +# + +# example anchoring +# taken from https://its.cern.ch/jira/browse/O2-5670 +export ALIEN_JDL_LPMANCHORPASSNAME=apass1 +export ALIEN_JDL_MCANCHOR=apass1 +export ALIEN_JDL_CPULIMIT=8 +export ALIEN_JDL_LPMRUNNUMBER=559348 +export ALIEN_JDL_LPMPRODUCTIONTYPE=MC +export ALIEN_JDL_LPMINTERACTIONTYPE=pp +export ALIEN_JDL_LPMPRODUCTIONTAG=LHC24a6 +export ALIEN_JDL_LPMANCHORRUN=559348 +export ALIEN_JDL_LPMANCHORPRODUCTION=LHC24ap +export ALIEN_JDL_LPMANCHORYEAR=2024 +export ALIEN_JDL_OUTPUT=*.dat@disk=1,*.txt@disk=1,*.root@disk=2 + +export NTIMEFRAMES=1 +export NSIGEVENTS=20 +export SPLITID=100 +export PRODSPLIT=153 +export CYCLE=0 + +# on the GRID, this is set and used as seed; when set, it takes precedence over SEED +#export ALIEN_PROC_ID=2963436952 +export SEED=0 + +# for pp and 50 events per TF, we launch only 4 workers. +export NWORKERS=2 + +# define the generator via ini file +# use 20/40/40 sampling for different generators +# generate random number +RNDSIG=$(($RANDOM % 100)) + + +if [[ $RNDSIG -ge 0 && $RNDSIG -lt 20 ]]; +then + CONFIGNAME="GeneratorHFGapTriggered_Charm_Gap5_pp5360GeV.ini" +elif [[ $RNDSIG -ge 20 && $RNDSIG -lt 100 ]]; +then + CONFIGNAME="GeneratorHFGapTriggered_BeautyNoForcedDecay_Gap5_pp5360GeV.ini" +fi + +export ALIEN_JDL_ANCHOR_SIM_OPTIONS="-gen external -ini $O2DPG_ROOT/MC/config/PWGEM/ini/$CONFIGNAME" + +# run the central anchor steering script; this includes +# * derive timestamp +# * derive interaction rate +# * extract and prepare configurations (which detectors are contained in the run etc.) +# * run the simulation (and QC) +# To disable QC, uncomment the following line +#export DISABLE_QC=1 +${O2DPG_ROOT}/MC/run/ANCHOR/anchorMC.sh