Skip to content

Commit 2d4e03e

Browse files
authored
PWGLF: add long lived gen with flow
1 parent 05fde30 commit 2d4e03e

File tree

1 file changed

+298
-0
lines changed

1 file changed

+298
-0
lines changed
Lines changed: 298 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,298 @@
1+
2+
#include "Pythia8/Pythia.h"
3+
#include "Pythia8/HeavyIons.h" // for event plane angle
4+
5+
#if !defined(__CLING__) || defined(__ROOTCLING__)
6+
#include "FairGenerator.h"
7+
#include "FairPrimaryGenerator.h"
8+
#include "Generators/GeneratorPythia8.h"
9+
#include "fairlogger/Logger.h"
10+
#include "CCDB/BasicCCDBManager.h"
11+
#include "TRandom3.h"
12+
#include "TParticlePDG.h"
13+
#include "TDatabasePDG.h"
14+
#include "TSystem.h"
15+
#include "TMath.h"
16+
#include <cmath>
17+
#include <vector>
18+
#include <fstream>
19+
#include <string>
20+
using namespace Pythia8;
21+
#endif
22+
23+
class GeneratorPythia8LongLivedGapTriggered : public o2::eventgen::GeneratorPythia8
24+
{
25+
public:
26+
/// Constructor
27+
GeneratorPythia8LongLivedGapTriggered(std::vector<int> input_pdg, int input_trigger_ratio = 1, int n_injected = 1, float pt_min = 1, float pt_max = 10, float y_min = -1, float y_max = 1, bool addSyntheticFlow = false)
28+
{
29+
mPdg = input_pdg;
30+
setNinjected(n_injected);
31+
mInverseTriggerRatio = input_trigger_ratio;
32+
setPt(pt_min, pt_max);
33+
setY(y_min, y_max);
34+
mMass = getMass(input_pdg);
35+
mGeneratedEvents = 0;
36+
mAlternatingPDGsign = true;
37+
mAddSyntheticFlow = addSyntheticFlow;
38+
39+
if(mAddSyntheticFlow){
40+
lutGen = new o2::eventgen::FlowMapper();
41+
42+
// -------- CONFIGURE SYNTHETIC FLOW ------------
43+
// establish connection to ccdb
44+
o2::ccdb::CcdbApi ccdb_api;
45+
ccdb_api.init("https://alice-ccdb.cern.ch");
46+
47+
// config was placed at midpoint of run 544122, retrieve that
48+
std::map<string, string> metadataRCT, headers;
49+
headers = ccdb_api.retrieveHeaders("RCT/Info/RunInformation/544122", metadataRCT, -1);
50+
int64_t tsSOR = atol(headers["SOR"].c_str());
51+
int64_t tsEOR = atol(headers["EOR"].c_str());
52+
int64_t midRun = 0.5*tsSOR+0.5*tsEOR;
53+
54+
map<string, string> metadata; // can be empty
55+
auto list = ccdb_api.retrieveFromTFileAny<TList>("Users/d/ddobrigk/syntheflow", metadata, midRun);
56+
57+
TH1D *hv2vspT = (TH1D*) list->FindObject("hFlowVsPt_ins1116150_v1_Table_1");
58+
TH1D *heccvsb = (TH1D*) list->FindObject("hEccentricityVsB");
59+
60+
cout<<"Generating LUT for flow test"<<endl;
61+
lutGen->CreateLUT(hv2vspT, heccvsb);
62+
cout<<"Finished creating LUT!"<<endl;
63+
// -------- END CONFIGURE SYNTHETIC FLOW ------------
64+
}
65+
}
66+
67+
/// Constructor from config file
68+
GeneratorPythia8LongLivedGapTriggered(std::string file_name, int input_trigger_ratio = 1, bool addSyntheticFlow = false)
69+
{
70+
auto expanded_file_name = gSystem->ExpandPathName(file_name.c_str());
71+
std::ifstream config_file(expanded_file_name);
72+
LOGF(info, "Using configuration file %s", expanded_file_name);
73+
std::string header;
74+
int pdg = 0;
75+
unsigned long n_inj = 0;
76+
float pt_min = 0.;
77+
float pt_max = 0.;
78+
float y_min = 0.;
79+
float y_max = 0.;
80+
if (!config_file.is_open())
81+
{
82+
LOGF(fatal, "File %s cannot be opened.", expanded_file_name);
83+
}
84+
std::getline(config_file, header); // skip first line
85+
while (config_file >> pdg >> n_inj >> pt_min >> pt_max >> y_min >> y_max)
86+
{
87+
mPdg.push_back(pdg);
88+
mNinjected.push_back(n_inj);
89+
mPtMin.push_back(pt_min);
90+
mPtMax.push_back(pt_max);
91+
mYmin.push_back(y_min);
92+
mYmax.push_back(y_max);
93+
}
94+
config_file.close();
95+
mInverseTriggerRatio = input_trigger_ratio;
96+
mMass = getMass(mPdg);
97+
mGeneratedEvents = 0;
98+
mAlternatingPDGsign = true;
99+
mAddSyntheticFlow = addSyntheticFlow;
100+
101+
if(mAddSyntheticFlow){
102+
lutGen = new o2::eventgen::FlowMapper();
103+
104+
// -------- CONFIGURE SYNTHETIC FLOW ------------
105+
// establish connection to ccdb
106+
o2::ccdb::CcdbApi ccdb_api;
107+
ccdb_api.init("https://alice-ccdb.cern.ch");
108+
109+
// config was placed at midpoint of run 544122, retrieve that
110+
std::map<string, string> metadataRCT, headers;
111+
headers = ccdb_api.retrieveHeaders("RCT/Info/RunInformation/544122", metadataRCT, -1);
112+
int64_t tsSOR = atol(headers["SOR"].c_str());
113+
int64_t tsEOR = atol(headers["EOR"].c_str());
114+
int64_t midRun = 0.5*tsSOR+0.5*tsEOR;
115+
116+
map<string, string> metadata; // can be empty
117+
auto list = ccdb_api.retrieveFromTFileAny<TList>("Users/d/ddobrigk/syntheflow", metadata, midRun);
118+
119+
TH1D *hv2vspT = (TH1D*) list->FindObject("hFlowVsPt_ins1116150_v1_Table_1");
120+
TH1D *heccvsb = (TH1D*) list->FindObject("hEccentricityVsB");
121+
122+
cout<<"Generating LUT for flow test"<<endl;
123+
lutGen->CreateLUT(hv2vspT, heccvsb);
124+
cout<<"Finished creating LUT!"<<endl;
125+
// -------- END CONFIGURE SYNTHETIC FLOW ------------
126+
}
127+
}
128+
129+
/// Destructor
130+
~GeneratorPythia8LongLivedGapTriggered() = default;
131+
132+
/// Randomize the PDG code sign of core particle
133+
void setAlternatingPDGsign(bool val) { mAlternatingPDGsign = val; }
134+
135+
/// Set transverse momentum
136+
void setPt(float pt_min, float pt_max)
137+
{
138+
for (auto part : mPdg)
139+
{
140+
mPtMin.push_back(pt_min);
141+
mPtMax.push_back(pt_max);
142+
}
143+
}
144+
145+
/// Set rapidity
146+
void setY(float y_min, float y_max)
147+
{
148+
for (auto part : mPdg)
149+
{
150+
mYmin.push_back(y_min);
151+
mYmax.push_back(y_max);
152+
}
153+
}
154+
155+
/// Set pseudorapidity
156+
void setNinjected(unsigned long n_injected)
157+
{
158+
for (auto part : mPdg)
159+
{
160+
mNinjected.push_back(n_injected);
161+
}
162+
}
163+
164+
/// Get mass from TParticlePDG
165+
static std::vector<double> getMass(std::vector<int> input_pdg)
166+
{
167+
std::vector<double> mass_vec;
168+
for (auto pdg : input_pdg)
169+
{
170+
double mass = 0;
171+
if (TDatabasePDG::Instance())
172+
{
173+
TParticlePDG *particle = TDatabasePDG::Instance()->GetParticle(pdg);
174+
if (particle)
175+
{
176+
mass = particle->Mass();
177+
}
178+
else
179+
{
180+
std::cout << "===> Unknown particle requested with PDG " << pdg << ", mass set to 0" << std::endl;
181+
}
182+
}
183+
mass_vec.push_back(mass);
184+
}
185+
return mass_vec;
186+
}
187+
188+
Bool_t importParticles() override
189+
{
190+
GeneratorPythia8::importParticles();
191+
if (mGeneratedEvents % mInverseTriggerRatio == 0)
192+
{
193+
static int sign = 1;
194+
int injectionIndex = (int)gRandom->Uniform(0, mPdg.size());
195+
int currentPdg = mPdg[injectionIndex];
196+
double currentMass = mMass[injectionIndex];
197+
for (int i = 0; i < mNinjected[injectionIndex]; ++i)
198+
{
199+
const double pt = gRandom->Uniform(mPtMin[injectionIndex], mPtMax[injectionIndex]);
200+
const double rapidity = gRandom->Uniform(mYmin[injectionIndex], mYmax[injectionIndex]);
201+
const double phi = gRandom->Uniform(0, TMath::TwoPi());
202+
const double px{pt * std::cos(phi)};
203+
const double py{pt * std::sin(phi)};
204+
const double mt{std::hypot(pt, currentMass)};
205+
const double pz{mt * std::sinh(rapidity)};
206+
const double et{mt * std::cosh(rapidity)};
207+
if (mAlternatingPDGsign)
208+
{
209+
sign *= 1 - 2 * (gRandom->Uniform() > 0.5);
210+
}
211+
mParticles.push_back(TParticle(sign * currentPdg, 1, -1, -1, -1, -1, px, py, pz, et, 0., 0., 0., 0.));
212+
// make sure status code is encoded properly. Transport flag will be set by default and we have nothing
213+
// to do since all pushed particles should be tracked.
214+
o2::mcutils::MCGenHelper::encodeParticleStatusAndTracking(mParticles.back());
215+
}
216+
}
217+
218+
if(mAddSyntheticFlow){
219+
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
220+
// loop over the entire event record and rotate all particles
221+
// synthetic flow exercise
222+
// first: get event plane
223+
float eventPlaneAngle = mPythia.info.hiInfo->phi();
224+
float impactParameter = mPythia.info.hiInfo->b();
225+
226+
for ( Long_t j=0; j < mPythia.event.size(); j++ ) {
227+
float pyphi = mPythia.event[j].phi();
228+
float pypT = mPythia.event[j].pT();
229+
230+
// calculate delta with EP
231+
float deltaPhiEP = pyphi - eventPlaneAngle;
232+
float shift = 0.0;
233+
while(deltaPhiEP<0.0){
234+
deltaPhiEP += 2*TMath::Pi();
235+
shift += 2*TMath::Pi();
236+
}
237+
while(deltaPhiEP>2*TMath::Pi()){
238+
deltaPhiEP -= 2*TMath::Pi();
239+
shift -= 2*TMath::Pi();
240+
}
241+
float newDeltaPhiEP = lutGen->MapPhi(deltaPhiEP, impactParameter, pypT);
242+
float pyphiNew = newDeltaPhiEP - shift + eventPlaneAngle;
243+
244+
if(pyphiNew>TMath::Pi())
245+
pyphiNew -= 2.0*TMath::Pi();
246+
if(pyphiNew<-TMath::Pi())
247+
pyphiNew += 2.0*TMath::Pi();
248+
mPythia.event[j].rot(0.0, pyphiNew-pyphi);
249+
}
250+
}
251+
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
252+
253+
mGeneratedEvents++;
254+
return true;
255+
}
256+
257+
private:
258+
std::vector<int> mPdg; /// particle mPdg code
259+
std::vector<double> mMass; /// particle mass [GeV/c^2]
260+
261+
std::vector<double> mPtMin; /// minimum transverse momentum for generated particles
262+
std::vector<double> mPtMax; /// maximum transverse momentum for generated particles
263+
std::vector<double> mYmin; /// minimum rapidity for generated particles
264+
std::vector<double> mYmax; /// maximum rapidity for generated particles
265+
266+
bool mAlternatingPDGsign = true; /// bool to randomize the PDG code of the core particle
267+
bool mAddSyntheticFlow = false; /// switch to add synthetic flow (requires EP angle from PYTHIA)
268+
269+
std::vector<int> mNinjected; /// Number of injected particles
270+
271+
// Control gap-triggering
272+
unsigned long long mGeneratedEvents; /// number of events generated so far
273+
int mInverseTriggerRatio; /// injection gap
274+
275+
o2::eventgen::FlowMapper *lutGen; // for mapping phi angles
276+
};
277+
278+
///___________________________________________________________
279+
FairGenerator *generateLongLivedGapTriggered(std::vector<int> mPdg, int input_trigger_ratio, int n_injected = 1, float pt_min = 1, float pt_max = 10, float y_min = -1, float y_max = 1, bool alternate_sign = true, bool addSyntheticFlow = false)
280+
{
281+
auto myGen = new GeneratorPythia8LongLivedGapTriggered(mPdg, input_trigger_ratio, n_injected, pt_min, pt_max, y_min, y_max, addSyntheticFlow);
282+
myGen->setAlternatingPDGsign(alternate_sign);
283+
auto seed = (gRandom->TRandom::GetSeed() % 900000000);
284+
myGen->readString("Random:setSeed on");
285+
myGen->readString("Random:seed " + std::to_string(seed));
286+
return myGen;
287+
}
288+
289+
///___________________________________________________________
290+
FairGenerator *generateLongLivedGapTriggered(std::string config_file_name, int input_trigger_ratio, bool alternate_sign = true, bool addSyntheticFlow = false)
291+
{
292+
auto myGen = new GeneratorPythia8LongLivedGapTriggered(config_file_name, input_trigger_ratio, addSyntheticFlow);
293+
myGen->setAlternatingPDGsign(alternate_sign);
294+
auto seed = (gRandom->TRandom::GetSeed() % 900000000);
295+
myGen->readString("Random:setSeed on");
296+
myGen->readString("Random:seed " + std::to_string(seed));
297+
return myGen;
298+
}

0 commit comments

Comments
 (0)