Skip to content

Commit 2f444c4

Browse files
authored
Add simple coalescence generator for He3 (#1619)
1 parent e23d5aa commit 2f444c4

File tree

4 files changed

+228
-0
lines changed

4 files changed

+228
-0
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[GeneratorExternal]
2+
fileName = ${O2DPG_ROOT}/MC/config/PWGLF/pythia8/generator_pythia8_coalescence.C
3+
funcName = generateCoalescence(5)
4+
5+
[GeneratorPythia8]
6+
config=${O2_ROOT}/share/Generators/egconfig/pythia8_inel.cfg
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
int External()
2+
{
3+
std::string path{"o2sim_Kine.root"};
4+
5+
TFile file(path.c_str(), "READ");
6+
if (file.IsZombie())
7+
{
8+
std::cerr << "Cannot open ROOT file " << path << "\n";
9+
return 1;
10+
}
11+
12+
auto tree = (TTree *)file.Get("o2sim");
13+
if (!tree)
14+
{
15+
std::cerr << "Cannot find tree o2sim in file " << path << "\n";
16+
return 1;
17+
}
18+
std::vector<o2::MCTrack> *tracks{};
19+
tree->SetBranchAddress("MCTrack", &tracks);
20+
21+
auto nEvents = tree->GetEntries();
22+
auto nInjected = tree->Scan("MCTrack.GetPdgCode()", "MCTrack.GetPdgCode() == -1000020030"); /// don't check matter, too many secondaries
23+
if (nEvents / nInjected != 10)
24+
{
25+
std::cerr << "Unexpected ratio of events to injected nuclei\n";
26+
return 1;
27+
}
28+
return 0;
29+
}
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
#if !defined(__CLING__) || defined(__ROOTCLING__)
2+
#include "Pythia8/Pythia.h"
3+
#include "FairGenerator.h"
4+
#include "FairPrimaryGenerator.h"
5+
#include "Generators/GeneratorPythia8.h"
6+
#include "fairlogger/Logger.h"
7+
#include "TRandom3.h"
8+
#include "TParticlePDG.h"
9+
#include "TDatabasePDG.h"
10+
#include "TSystem.h"
11+
#include "TMath.h"
12+
#include <cmath>
13+
#include <vector>
14+
#include <fstream>
15+
#include <string>
16+
using namespace Pythia8;
17+
#endif
18+
19+
/// First version of the simple coalescence generator based PYTHIA8
20+
/// TODO: extend to other nuclei (only He3 is implemented now)
21+
22+
class GeneratorPythia8Coalescence : public o2::eventgen::GeneratorPythia8
23+
{
24+
public:
25+
/// Constructor
26+
GeneratorPythia8Coalescence(int input_trigger_ratio = 1, double coal_momentum = 0.4)
27+
: o2::eventgen::GeneratorPythia8()
28+
{
29+
fmt::printf(">> Coalescence generator %d\n", input_trigger_ratio);
30+
mInverseTriggerRatio = input_trigger_ratio;
31+
mCoalMomentum = coal_momentum;
32+
}
33+
/// Destructor
34+
~GeneratorPythia8Coalescence() = default;
35+
36+
bool Init() override
37+
{
38+
addSubGenerator(0, "Minimum bias");
39+
addSubGenerator(1, "Coalescence");
40+
return o2::eventgen::GeneratorPythia8::Init();
41+
}
42+
43+
protected:
44+
bool generateEvent() override
45+
{
46+
fmt::printf(">> Generating event %d\n", mGeneratedEvents);
47+
// Simple straightforward check to alternate generators
48+
if (mGeneratedEvents % mInverseTriggerRatio == 0)
49+
{
50+
bool genOk = false;
51+
int localCounter{0};
52+
while (!genOk)
53+
{
54+
if (GeneratorPythia8::generateEvent())
55+
{
56+
genOk = selectEvent(mPythia.event);
57+
}
58+
localCounter++;
59+
}
60+
fmt::printf(">> Coalescence successful after %i generations\n", localCounter);
61+
std::cout << std::endl << std::endl;
62+
notifySubGenerator(1);
63+
}
64+
else
65+
{
66+
// Generate minimum-bias event
67+
bool genOk = false;
68+
while (!genOk)
69+
{
70+
genOk = GeneratorPythia8::generateEvent();
71+
}
72+
notifySubGenerator(0);
73+
}
74+
75+
mGeneratedEvents++;
76+
77+
return true;
78+
}
79+
80+
bool selectEvent(Pythia8::Event &event)
81+
{
82+
static int sign = -1; // start with antimatter
83+
std::vector<int> protons, neutrons, lambdas;
84+
for (auto iPart{0}; iPart < event.size(); ++iPart)
85+
{
86+
if (std::abs(event[iPart].y()) > 1.) // skip particles with y > 1
87+
{
88+
continue;
89+
}
90+
if (event[iPart].id() == 2212 * sign)
91+
{
92+
protons.push_back(iPart);
93+
}
94+
else if (event[iPart].id() == 2112 * sign)
95+
{
96+
neutrons.push_back(iPart);
97+
}
98+
else if (event[iPart].id() == 3122 * sign)
99+
{
100+
lambdas.push_back(iPart);
101+
}
102+
}
103+
double coalescenceRadius{0.5 * 1.122462 * mCoalMomentum}; /// 1.122462 [2^(1/6)] from PRL 126, 101101 (2021), only for 3 body coalescence
104+
if (protons.size() < 2 || neutrons.size() < 1) // at least 2 protons and 1 neutron
105+
{
106+
return false;
107+
}
108+
for (uint32_t i{0}; i < protons.size(); ++i)
109+
{
110+
for (uint32_t j{i + 1}; j < protons.size(); ++j)
111+
{
112+
for (uint32_t k{0}; k < neutrons.size(); ++k)
113+
{
114+
auto p1 = event[protons[i]].p();
115+
auto p2 = event[protons[j]].p();
116+
auto p3 = event[neutrons[k]].p();
117+
auto p = p1 + p2 + p3;
118+
p1.bstback(p);
119+
p2.bstback(p);
120+
p3.bstback(p);
121+
122+
if (p1.pAbs() <= coalescenceRadius && p2.pAbs() <= coalescenceRadius && p3.pAbs() <= coalescenceRadius)
123+
{
124+
p.e(std::hypot(p.pAbs(), 2.80839160743));
125+
/// In order to avoid the transport of the mother particles, but to still keep them in the stack, we set the status to negative and we mark the nucleus status as 94 (decay product)
126+
event.append(sign * 1000020030, 94, 0, 0, 0, 0, 0, 0, p.px(), p.py(), p.pz(), p.e(), 2.80839160743);
127+
event[protons[i]].statusNeg();
128+
event[protons[i]].daughter1(event.size() - 1);
129+
event[protons[j]].statusNeg();
130+
event[protons[j]].daughter1(event.size() - 1);
131+
event[neutrons[k]].statusNeg();
132+
event[neutrons[k]].daughter1(event.size() - 1);
133+
134+
fmt::printf(">> Adding a He3 with p = %f, %f, %f, E = %f\n", p.px(), p.py(), p.pz(), p.e());
135+
std::cout << std::endl;
136+
std::cout << std::endl;
137+
138+
sign *= -1;
139+
return true;
140+
}
141+
}
142+
}
143+
}
144+
return false;
145+
}
146+
147+
private:
148+
// Control gap-triggering
149+
float mCoalMomentum = 0.4;
150+
uint64_t mGeneratedEvents = 0; /// number of events generated so far
151+
int mInverseTriggerRatio = 1; /// injection gap
152+
};
153+
154+
///___________________________________________________________
155+
FairGenerator *generateCoalescence(int input_trigger_ratio, double coal_momentum = 0.4)
156+
{
157+
auto myGen = new GeneratorPythia8Coalescence(input_trigger_ratio, coal_momentum);
158+
auto seed = (gRandom->TRandom::GetSeed() % 900000000);
159+
myGen->readString("Random:setSeed on");
160+
myGen->readString("Random:seed " + std::to_string(seed));
161+
return myGen;
162+
}

MC/run/PWGLF/run_Coalescence_pp.sh

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#!/bin/bash
2+
3+
#
4+
# A example workflow MC->RECO->AOD for a simple pp min bias
5+
# production, targetting test beam conditions.
6+
7+
# make sure O2DPG + O2 is loaded
8+
[ ! "${O2DPG_ROOT}" ] && echo "Error: This needs O2DPG loaded" && exit 1
9+
[ ! "${O2_ROOT}" ] && echo "Error: This needs O2 loaded" && exit 1
10+
11+
# ----------- LOAD UTILITY FUNCTIONS --------------------------
12+
. ${O2_ROOT}/share/scripts/jobutils.sh
13+
14+
# ----------- START ACTUAL JOB -----------------------------
15+
16+
NWORKERS=${NWORKERS:-8}
17+
MODULES="--skipModules ZDC"
18+
SIMENGINE=${SIMENGINE:-TGeant4}
19+
NSIGEVENTS=${NSIGEVENTS:-1}
20+
NTIMEFRAMES=${NTIMEFRAMES:-1}
21+
INTRATE=${INTRATE:-500000}
22+
SYSTEM=${SYSTEM:-pp}
23+
ENERGY=${ENERGY:-13600}
24+
[[ ${SPLITID} != "" ]] && SEED="-seed ${SPLITID}" || SEED=""
25+
26+
# create workflow
27+
${O2DPG_ROOT}/MC/bin/o2dpg_sim_workflow.py -eCM ${ENERGY} -col ${SYSTEM} -gen external -j ${NWORKERS} -ns ${NSIGEVENTS} -tf ${NTIMEFRAMES} -interactionRate ${INTRATE} -confKey "Diamond.width[0]=0.005;Diamond.width[1]=0.005;Diamond.width[2]=6." -e ${SIMENGINE} ${SEED} -mod "--skipModules ZDC" \
28+
-ini $O2DPG_ROOT/MC/config/PWGLF/ini/GeneratorLF_Coalescence.ini
29+
30+
# run workflow
31+
${O2DPG_ROOT}/MC/bin/o2_dpg_workflow_runner.py -f workflow.json -tt aod --cpu-limit 32

0 commit comments

Comments
 (0)