Skip to content

Commit 2acc0a3

Browse files
committed
Add possibility to replace particles in the stack for HF generator
1 parent eb3f9e7 commit 2acc0a3

File tree

4 files changed

+422
-24
lines changed

4 files changed

+422
-24
lines changed

MC/config/PWGHF/external/generator/generator_pythia8_gaptriggered_hf.C

Lines changed: 128 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include "Generators/GeneratorPythia8.h"
33
#include "Pythia8/Pythia.h"
44
#include "TRandom.h"
5+
#include "TDatabasePDG.h"
56
#include <fairlogger/Logger.h>
67

78
#include <string>
@@ -16,7 +17,7 @@ public:
1617
GeneratorPythia8GapTriggeredHF() = default;
1718

1819
/// constructor
19-
GeneratorPythia8GapTriggeredHF(int inputTriggerRatio = 5, std::vector<int> quarkPdgList = {}, std::vector<int> hadronPdgList = {})
20+
GeneratorPythia8GapTriggeredHF(int inputTriggerRatio = 5, std::vector<int> quarkPdgList = {}, std::vector<int> hadronPdgList = {}, std::vector<std::array<int, 2>> partPdgToReplaceList = {}, std::vector<float> freqReplaceList = {})
2021
{
2122

2223
mGeneratedEvents = 0;
@@ -29,8 +30,22 @@ public:
2930
mHadronPdg = 0;
3031
mQuarkPdgList = quarkPdgList;
3132
mHadronPdgList = hadronPdgList;
33+
mPartPdgToReplaceList = partPdgToReplaceList;
34+
mFreqReplaceList = freqReplaceList;
35+
// Ds1*(2700), Ds1*(2860), Ds3*(2860), Xic(3055), Xic(3080)
36+
mCustomPartPdgs = {30433, 40433, 437, 4325, 4326};
37+
mCustomPartMasses[30433] = 2.714f;
38+
mCustomPartMasses[40433] = 2.859f;
39+
mCustomPartMasses[437] = 2.860f;
40+
mCustomPartMasses[4325] = 3.0559f;
41+
mCustomPartMasses[4326] = 3.0772f;
42+
mCustomPartWidths[30433] = 0.122f;
43+
mCustomPartWidths[40433] = 0.160f;
44+
mCustomPartWidths[437] = 0.053f;
45+
mCustomPartWidths[4325] = 0.0078f;
46+
mCustomPartWidths[4326] = 0.0036f;
3247
Print();
33-
}
48+
}
3449

3550
/// Destructor
3651
~GeneratorPythia8GapTriggeredHF() = default;
@@ -54,6 +69,11 @@ public:
5469
{
5570
LOG(info)<<Form("* %d ", pdg);
5671
}
72+
LOG(info)<<Form("* Replacements: ");
73+
for (auto iRepl{0u}; iRepl<mPartPdgToReplaceList.size(); ++iRepl)
74+
{
75+
LOGP(info, "* {} -> {} (freq. {})", mPartPdgToReplaceList[iRepl].at(0), mPartPdgToReplaceList[iRepl].at(1), mFreqReplaceList[iRepl]);
76+
}
5777
LOG(info)<<"***********************************************************************";
5878
}
5979

@@ -62,6 +82,21 @@ public:
6282
addSubGenerator(0, "Minimum bias");
6383
addSubGenerator(4, "Charm injected");
6484
addSubGenerator(5, "Beauty injected");
85+
86+
std::vector<int> pdgToReplace{};
87+
for (auto iRepl{0u}; iRepl<mPartPdgToReplaceList.size(); ++iRepl)
88+
{
89+
for (auto iPdgRep{0u}; iPdgRep<pdgToReplace.size(); ++iPdgRep) {
90+
if (mPartPdgToReplaceList[iRepl].at(0) == pdgToReplace[iPdgRep]) {
91+
mFreqReplaceList[iRepl] += mFreqReplaceList[iPdgRep];
92+
}
93+
}
94+
if (mFreqReplaceList[iRepl] > 1.f) {
95+
LOGP(fatal, "Replacing more than 100% of a particle!");
96+
}
97+
pdgToReplace.push_back(mPartPdgToReplaceList[iRepl].at(0));
98+
}
99+
65100
return o2::eventgen::GeneratorPythia8::Init();
66101
}
67102

@@ -115,7 +150,7 @@ protected:
115150
{
116151
if (GeneratorPythia8::generateEvent())
117152
{
118-
genOk = selectEvent(mPythia.event);
153+
genOk = selectEvent();
119154
}
120155
}
121156
notifySubGenerator(mQuarkPdg);
@@ -136,34 +171,35 @@ protected:
136171
return true;
137172
}
138173

139-
bool selectEvent(const Pythia8::Event &event)
174+
bool selectEvent()
140175
{
141176

142177
bool isGoodAtPartonLevel{mQuarkPdgList.size() == 0};
143178
bool isGoodAtHadronLevel{mHadronPdgList.size() == 0};
179+
bool anyPartToReplace{mPartPdgToReplaceList.size() > 0};
144180

145-
for (auto iPart{0}; iPart < event.size(); ++iPart)
181+
for (auto iPart{0}; iPart < mPythia.event.size(); ++iPart)
146182
{
147183

148184
// search for Q-Qbar mother with at least one Q in rapidity window
149185
if (!isGoodAtPartonLevel)
150186
{
151-
auto daughterList = event[iPart].daughterList();
187+
auto daughterList = mPythia.event[iPart].daughterList();
152188
bool hasQ = false, hasQbar = false, atSelectedY = false;
153189
for (auto iDau : daughterList)
154190
{
155-
if (event[iDau].id() == mQuarkPdg)
191+
if (mPythia.event[iDau].id() == mQuarkPdg)
156192
{
157193
hasQ = true;
158-
if ((event[iDau].y() > mQuarkRapidityMin) && (event[iDau].y() < mQuarkRapidityMax))
194+
if ((mPythia.event[iDau].y() > mQuarkRapidityMin) && (mPythia.event[iDau].y() < mQuarkRapidityMax))
159195
{
160196
atSelectedY = true;
161197
}
162198
}
163-
if (event[iDau].id() == -mQuarkPdg)
199+
if (mPythia.event[iDau].id() == -mQuarkPdg)
164200
{
165201
hasQbar = true;
166-
if ((event[iDau].y() > mQuarkRapidityMin) && (event[iDau].y() < mQuarkRapidityMax))
202+
if ((mPythia.event[iDau].y() > mQuarkRapidityMin) && (mPythia.event[iDau].y() < mQuarkRapidityMax))
167203
{
168204
atSelectedY = true;
169205
}
@@ -178,26 +214,89 @@ protected:
178214
// search for hadron in rapidity window
179215
if (!isGoodAtHadronLevel)
180216
{
181-
int id = std::abs(event[iPart].id());
182-
float rap = event[iPart].y();
217+
int id = std::abs(mPythia.event[iPart].id());
218+
float rap = mPythia.event[iPart].y();
183219
if (id == mHadronPdg && rap > mHadRapidityMin && rap < mHadRapidityMax)
184220
{
185221
isGoodAtHadronLevel = true;
186222
}
187223
}
188224

189-
// we send the trigger
190-
if (isGoodAtPartonLevel && isGoodAtHadronLevel)
225+
// if requested, we replace the particle
226+
const double pseudoRndm = mPythia.event[iPart].pT() * 1000. - (int64_t)(mPythia.event[iPart].pT() * 1000);
227+
for (auto iPartToReplace{0u}; iPartToReplace<mPartPdgToReplaceList.size(); ++iPartToReplace) {
228+
if (std::abs(mPythia.event[iPart].id()) == mPartPdgToReplaceList[iPartToReplace][0] && pseudoRndm < mFreqReplaceList[iPartToReplace]) {
229+
LOGP(debug, "REPLACING PARTICLE {} WITH {}, BEING RNDM {}", mPartPdgToReplaceList[iPartToReplace][0], mPartPdgToReplaceList[iPartToReplace][1], pseudoRndm);
230+
replaceParticle(iPart, mPartPdgToReplaceList[iPartToReplace][1]);
231+
break;
232+
}
233+
}
234+
235+
// we send the trigger immediately (if there are no particles to replace, that can be different from the trigger ones)
236+
if (isGoodAtPartonLevel && isGoodAtHadronLevel && !anyPartToReplace)
191237
{
192-
LOG(debug)<<"EVENT SELECTED: Found particle "<<event[iPart].id()<<" at rapidity "<<event[iPart].y()<<"\n";
238+
LOG(debug)<<"EVENT SELECTED: Found particle "<<mPythia.event[iPart].id()<<" at rapidity "<<mPythia.event[iPart].y()<<"\n";
193239
return true;
194240
}
195241
}
196242

243+
// we send the trigger
244+
if (isGoodAtPartonLevel && isGoodAtHadronLevel) {
245+
return true;
246+
}
247+
197248
return false;
198249
};
199250

200-
private:
251+
bool replaceParticle(int iPartToReplace, int pdgCodeNew) {
252+
253+
std::array<int, 2> mothers = {mPythia.event[iPartToReplace].mother1(), mPythia.event[iPartToReplace].mother2()};
254+
255+
std::array<int, 25> pdgDiquarks = {1103, 2101, 2103, 2203, 3101, 3103, 3201, 3203, 3303, 4101, 4103, 4201, 4203, 4301, 4303, 4403, 5101, 5103, 5201, 5203, 5301, 5303, 5401, 5403, 5503};
256+
257+
for (auto const& mother: mothers) {
258+
auto pdgMother = std::abs(mPythia.event[mother].id());
259+
if (pdgMother > 100 && std::find(pdgDiquarks.begin(), pdgDiquarks.end(), pdgMother) == pdgDiquarks.end()) {
260+
return false;
261+
}
262+
}
263+
264+
int charge = mPythia.event[iPartToReplace].id() / std::abs(mPythia.event[iPartToReplace].id());
265+
int status = mPythia.event[iPartToReplace].status();
266+
float px = mPythia.event[iPartToReplace].px();
267+
float py = mPythia.event[iPartToReplace].py();
268+
float pz = mPythia.event[iPartToReplace].pz();
269+
float mass = 0.f;
270+
271+
if (std::find(mCustomPartPdgs.begin(), mCustomPartPdgs.end(), pdgCodeNew) == mCustomPartPdgs.end()) { // not a custom particle
272+
float width = TDatabasePDG::Instance()->GetParticle(pdgCodeNew)->Width();
273+
float massRest = TDatabasePDG::Instance()->GetParticle(pdgCodeNew)->Mass();
274+
if (width > 0.f) {
275+
mass = gRandom->BreitWigner(massRest, width);
276+
} else {
277+
mass = massRest;
278+
}
279+
} else {
280+
if (mCustomPartWidths[pdgCodeNew] > 0.f) {
281+
mass = gRandom->BreitWigner(mCustomPartMasses[pdgCodeNew], mCustomPartWidths[pdgCodeNew]);
282+
} else {
283+
mass = mCustomPartMasses[pdgCodeNew];
284+
}
285+
}
286+
float energy = std::sqrt(px*px + py*py + pz*pz + mass*mass);
287+
288+
mPythia.event.remove(iPartToReplace, iPartToReplace, true); // we remove the original particle
289+
mPythia.event.append(charge * pdgCodeNew, status, 0, 0, 0, 0, 0, 0, px, py, pz, energy, mass);
290+
mPythia.event[mPythia.event.size()-1].mother1(mothers[0]);
291+
mPythia.event[mPythia.event.size()-1].mother2(mothers[1]);
292+
mPythia.moreDecays(); // we need to decay the new particle
293+
294+
return true;
295+
}
296+
297+
// id:all = name antiName spinType chargeType colType m0 mWidth mMin mMax tau0
298+
299+
private:
201300
// Interface to override import particles
202301
Pythia8::Event mOutputEvent;
203302

@@ -209,6 +308,11 @@ private:
209308
float mHadRapidityMin;
210309
float mHadRapidityMax;
211310
unsigned int mUsedSeed;
311+
std::vector<std::array<int, 2>> mPartPdgToReplaceList;
312+
std::vector<float> mFreqReplaceList;
313+
std::vector<int> mCustomPartPdgs;
314+
std::map<int, float> mCustomPartMasses;
315+
std::map<int, float> mCustomPartWidths;
212316

213317
// Control gap-triggering
214318
unsigned long long mGeneratedEvents;
@@ -223,9 +327,9 @@ private:
223327

224328
// Predefined generators:
225329
// Charm-enriched
226-
FairGenerator *GeneratorPythia8GapTriggeredCharm(int inputTriggerRatio, float yQuarkMin = -1.5, float yQuarkMax = 1.5, float yHadronMin = -1.5, float yHadronMax = 1.5, std::vector<int> hadronPdgList = {})
330+
FairGenerator *GeneratorPythia8GapTriggeredCharm(int inputTriggerRatio, float yQuarkMin = -1.5, float yQuarkMax = 1.5, float yHadronMin = -1.5, float yHadronMax = 1.5, std::vector<int> hadronPdgList = {}, std::vector<std::array<int, 2>> partPdgToReplaceList = {}, std::vector<float> freqReplaceList = {})
227331
{
228-
auto myGen = new GeneratorPythia8GapTriggeredHF(inputTriggerRatio, std::vector<int>{4}, hadronPdgList);
332+
auto myGen = new GeneratorPythia8GapTriggeredHF(inputTriggerRatio, std::vector<int>{4}, hadronPdgList, partPdgToReplaceList, freqReplaceList);
229333
auto seed = (gRandom->TRandom::GetSeed() % 900000000);
230334
myGen->setUsedSeed(seed);
231335
myGen->readString("Random:setSeed on");
@@ -239,9 +343,9 @@ FairGenerator *GeneratorPythia8GapTriggeredCharm(int inputTriggerRatio, float yQ
239343
}
240344

241345
// Beauty-enriched
242-
FairGenerator *GeneratorPythia8GapTriggeredBeauty(int inputTriggerRatio, float yQuarkMin = -1.5, float yQuarkMax = 1.5, float yHadronMin = -1.5, float yHadronMax = 1.5, std::vector<int> hadronPdgList = {})
346+
FairGenerator *GeneratorPythia8GapTriggeredBeauty(int inputTriggerRatio, float yQuarkMin = -1.5, float yQuarkMax = 1.5, float yHadronMin = -1.5, float yHadronMax = 1.5, std::vector<int> hadronPdgList = {}, std::vector<std::array<int, 2>> partPdgToReplaceList = {}, std::vector<float> freqReplaceList = {})
243347
{
244-
auto myGen = new GeneratorPythia8GapTriggeredHF(inputTriggerRatio, std::vector<int>{5}, hadronPdgList);
348+
auto myGen = new GeneratorPythia8GapTriggeredHF(inputTriggerRatio, std::vector<int>{5}, hadronPdgList, partPdgToReplaceList, freqReplaceList);
245349
auto seed = (gRandom->TRandom::GetSeed() % 900000000);
246350
myGen->setUsedSeed(seed);
247351
myGen->readString("Random:setSeed on");
@@ -255,9 +359,9 @@ FairGenerator *GeneratorPythia8GapTriggeredBeauty(int inputTriggerRatio, float y
255359
}
256360

257361
// Charm and beauty enriched (with same ratio)
258-
FairGenerator *GeneratorPythia8GapTriggeredCharmAndBeauty(int inputTriggerRatio, float yQuarkMin = -1.5, float yQuarkMax = 1.5, float yHadronMin = -1.5, float yHadronMax = 1.5, std::vector<int> hadronPdgList = {})
362+
FairGenerator *GeneratorPythia8GapTriggeredCharmAndBeauty(int inputTriggerRatio, float yQuarkMin = -1.5, float yQuarkMax = 1.5, float yHadronMin = -1.5, float yHadronMax = 1.5, std::vector<int> hadronPdgList = {}, std::vector<std::array<int, 2>> partPdgToReplaceList = {}, std::vector<float> freqReplaceList = {})
259363
{
260-
auto myGen = new GeneratorPythia8GapTriggeredHF(inputTriggerRatio, std::vector<int>{4, 5}, hadronPdgList);
364+
auto myGen = new GeneratorPythia8GapTriggeredHF(inputTriggerRatio, std::vector<int>{4, 5}, hadronPdgList, partPdgToReplaceList, freqReplaceList);
261365
auto seed = (gRandom->TRandom::GetSeed() % 900000000);
262366
myGen->setUsedSeed(seed);
263367
myGen->readString("Random:setSeed on");
@@ -270,13 +374,13 @@ FairGenerator *GeneratorPythia8GapTriggeredCharmAndBeauty(int inputTriggerRatio,
270374
return myGen;
271375
}
272376

273-
FairGenerator *GeneratorPythia8GapHF(int inputTriggerRatio, float yQuarkMin = -1.5, float yQuarkMax = 1.5, float yHadronMin = -1.5, float yHadronMax = 1.5, std::vector<int> quarkPdgList = {}, std::vector<int> hadronPdgList = {})
377+
FairGenerator *GeneratorPythia8GapHF(int inputTriggerRatio, float yQuarkMin = -1.5, float yQuarkMax = 1.5, float yHadronMin = -1.5, float yHadronMax = 1.5, std::vector<int> quarkPdgList = {}, std::vector<int> hadronPdgList = {}, std::vector<std::array<int, 2>> partPdgToReplaceList = {}, std::vector<float> freqReplaceList = {})
274378
{
275379
if (hadronPdgList.size() == 0 && quarkPdgList.size() == 0)
276380
{
277381
LOG(fatal) << "GeneratorPythia8GapHF: At least one quark or hadron PDG code must be specified";
278382
}
279-
auto myGen = new GeneratorPythia8GapTriggeredHF(inputTriggerRatio, quarkPdgList, hadronPdgList);
383+
auto myGen = new GeneratorPythia8GapTriggeredHF(inputTriggerRatio, quarkPdgList, hadronPdgList, partPdgToReplaceList, freqReplaceList);
280384
auto seed = (gRandom->TRandom::GetSeed() % 900000000);
281385
myGen->setUsedSeed(seed);
282386
myGen->readString("Random:setSeed on");
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
### The external generator derives from GeneratorPythia8.
2+
[GeneratorExternal]
3+
fileName=${O2DPG_MC_CONFIG_ROOT}/MC/config/PWGHF/external/generator/generator_pythia8_gaptriggered_hf.C
4+
funcName=GeneratorPythia8GapTriggeredCharmAndBeauty(5, -1.5, 1.5, -1.5, 1.5, {10433, 435}, {{10433, 30433}, {10433, 437}, {435, 4325}, {435, 4326}}, {0.1, 0.1, 0.1, 0.1})
5+
6+
[GeneratorPythia8]
7+
config=${O2DPG_MC_CONFIG_ROOT}/MC/config/PWGHF/pythia8/generator/pythia8_charmhadronic_with_decays_DResoTrigger.cfg
8+
includePartonEvent=true

0 commit comments

Comments
 (0)