Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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 <map>
#include <unordered_set>
//#include <utility> // 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;
}
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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<o2::MCTrack>* 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;
}
Loading
Loading