Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PythiaGun.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file PythiaGun.cc
1 /*******************************************************************************
2  * Copyright (c) The JETSCAPE Collaboration, 2018
3  *
4  * Modular, task-based framework for simulating all aspects of heavy-ion collisions
5  *
6  * For the list of contributors see AUTHORS.
7  *
8  * Report issues at https://github.com/JETSCAPE/JETSCAPE/issues
9  *
10  * or via email to bugs.jetscape@gmail.com
11  *
12  * Distributed under the GNU General Public License 3.0 (GPLv3 or later).
13  * See COPYING for details.
14  ******************************************************************************/
15 
16 // Create a pythia collision at a specified point and return the two inital hard partons
17 
18 #include "PythiaGun.h"
19 #include <sstream>
20 #include <iostream>
21 #include <fstream>
22 #define MAGENTA "\033[35m"
23 
24 using namespace std;
25 
26 // Register the module with the base class
28 
30 
32 
33  JSDEBUG << "Initialize PythiaGun";
34  VERBOSE(8);
35 
36  // Show initialization at INFO level
37  readString("Init:showProcesses = off");
38  readString("Init:showChangedSettings = off");
39  readString("Init:showMultipartonInteractions = off");
40  readString("Init:showChangedParticleData = off");
41  if (JetScapeLogger::Instance()->GetInfo()) {
42  readString("Init:showProcesses = on");
43  readString("Init:showChangedSettings = on");
44  readString("Init:showMultipartonInteractions = on");
45  readString("Init:showChangedParticleData = on");
46  }
47 
48  // No event record printout.
49  readString("Next:numberShowInfo = 0");
50  readString("Next:numberShowProcess = 0");
51  readString("Next:numberShowEvent = 0");
52 
53  // For parsing text
55  numbf.setf(ios::fixed, ios::floatfield);
56  numbf.setf(ios::showpoint);
57  numbf.precision(1);
59 
60  std::string s = GetXMLElementText({"Hard", "PythiaGun", "name"});
61  SetId(s);
62  // cout << s << endl;
63 
64  //other Pythia settings
65  readString("HadronLevel:Decay = off");
66  readString("HadronLevel:all = off");
67  readString("PartonLevel:ISR = on");
68  readString("PartonLevel:MPI = on");
69  //readString("PartonLevel:FSR = on");
70  readString("PromptPhoton:all=on");
71  readString("WeakSingleBoson:all=off");
72  readString("WeakDoubleBoson:all=off");
73 
74  pTHatMin = GetXMLElementDouble({"Hard", "PythiaGun", "pTHatMin"});
75  pTHatMax = GetXMLElementDouble({"Hard", "PythiaGun", "pTHatMax"});
76 
77  if(pTHatMin < 0.01){ //assuming low bin where softQCD should be used
78  //running softQCD - inelastic nondiffrative (min-bias)
79  readString("HardQCD:all = off");
80  readString("SoftQCD:nonDiffractive = on");
81  softQCD = true;
82  }
83  else{ //running normal hardQCD
84  readString("HardQCD:all = on"); // will repeat this line in the xml for demonstration
85  // readString("HardQCD:gg2ccbar = on"); // switch on heavy quark channel
86  //readString("HardQCD:qqbar2ccbar = on");
87  numbf.str("PhaseSpace:pTHatMin = "); numbf << pTHatMin; readString(numbf.str());
88  numbf.str("PhaseSpace:pTHatMax = "); numbf << pTHatMax; readString(numbf.str());
89  softQCD = false;
90  }
91 
92  // SC: read flag for FSR
93  FSR_on = GetXMLElementInt({"Hard", "PythiaGun", "FSR_on"});
94  if (FSR_on)
95  readString("PartonLevel:FSR = on");
96  else
97  readString("PartonLevel:FSR = off");
98 
99  JSINFO << MAGENTA << "Pythia Gun with FSR_on: " << FSR_on;
100  JSINFO << MAGENTA << "Pythia Gun with " << pTHatMin << " < pTHat < " << pTHatMax;
101 
102  // random seed
103  // xml limits us to unsigned int :-/ -- but so does 32 bits Mersenne Twist
104  tinyxml2::XMLElement *RandomXmlDescription = GetXMLElement({"Random"});
105  readString("Random:setSeed = on");
106  numbi.str("Random:seed = ");
107  unsigned int seed = 0;
108  if (RandomXmlDescription) {
109  tinyxml2::XMLElement *xmle =
110  RandomXmlDescription->FirstChildElement("seed");
111  if (!xmle)
112  throw std::runtime_error("Cannot parse xml");
113  xmle->QueryUnsignedText(&seed);
114  } else {
115  JSWARN << "No <Random> element found in xml, seeding to 0";
116  }
117  VERBOSE(7) << "Seeding pythia to " << seed;
118  numbi << seed;
119  readString(numbi.str());
120 
121  // Species
122  readString("Beams:idA = 2212");
123  readString("Beams:idB = 2212");
124 
125  // Energy
126  eCM = GetXMLElementDouble({"Hard", "PythiaGun", "eCM"});
127  numbf.str("Beams:eCM = ");
128  numbf << eCM;
129  readString(numbf.str());
130 
131  //Reading vir_factor from xml for MATTER
132  vir_factor = GetXMLElementDouble({"Eloss", "Matter", "vir_factor"});
133  softMomentumCutoff = GetXMLElementDouble({"Hard", "PythiaGun", "softMomentumCutoff"});
134 
135  std::stringstream lines;
136  lines << GetXMLElementText({"Hard", "PythiaGun", "LinesToRead"}, false);
137  int i = 0;
138  while (std::getline(lines, s, '\n')) {
139  if (s.find_first_not_of(" \t\v\f\r") == s.npos)
140  continue; // skip empty lines
141  VERBOSE(7) << "Also reading in: " << s;
142  readString(s);
143  }
144 
145  // And initialize
146  if (!init()) { // Pythia>8.1
147  throw std::runtime_error("Pythia init() failed.");
148  }
149 
150  std::ofstream sigma_printer;
151  sigma_printer.open(printer, std::ios::trunc);
152 
153 
154 }
155 
157  VERBOSE(1) << "Run Hard Process : " << GetId() << " ...";
158  VERBOSE(8) << "Current Event #" << GetCurrentEvent();
159 
160  bool flag62 = false;
161  vector<Pythia8::Particle> p62;
162 
163  // sort by pt
164  struct greater_than_pt {
165  inline bool operator()(const Pythia8::Particle &p1,
166  const Pythia8::Particle &p2) {
167  return (p1.pT() > p2.pT());
168  }
169  };
170 
171  do {
172  next();
173  p62.clear();
174  if (!printer.empty()){
175  std::ofstream sigma_printer;
176  sigma_printer.open(printer, std::ios::out | std::ios::app);
177 
178  sigma_printer << "sigma = " << GetSigmaGen() << " Err = " << GetSigmaErr() << endl ;
179  //sigma_printer.close();
180 
181 // JSINFO << BOLDYELLOW << " sigma = " << GetSigmaGen() << " sigma err = " << GetSigmaErr() << " printer = " << printer << " is " << sigma_printer.is_open() ;
182  };
183 
184  // pTarr[0]=0.0; pTarr[1]=0.0;
185  // pindexarr[0]=0; pindexarr[1]=0;
186 
187  for (int parid = 0; parid < event.size(); parid++) {
188  if (parid < 3)
189  continue; // 0, 1, 2: total event and beams
190  Pythia8::Particle &particle = event[parid];
191 
192  //replacing diquarks with antiquarks (and anti-dq's with quarks)
193  //the id is set to the heaviest quark in the diquark (except down quark)
194  //this technically violates baryon number conservation over the entire event
195  //also can violate electric charge conservation
196  if( (std::abs(particle.id()) > 1100) && (std::abs(particle.id()) < 6000) && ((std::abs(particle.id())/10)%10 == 0) ){
197  if(particle.id() > 0){particle.id( -1*particle.id()/1000 );}
198  else{particle.id( particle.id()/1000 );}
199  }
200 
201  if (!FSR_on) {
202  // only accept particles after MPI
203  if (particle.status() != 62)
204  continue;
205  // only accept gluons and quarks
206  // Also accept Gammas to put into the hadron's list
207  if (fabs(particle.id()) > 5 &&
208  (particle.id() != 21 && particle.id() != 22))
209  continue;
210 
211  // reject rare cases of very soft particles that don't have enough e to get
212  // reasonable virtuality
213  if (vir_factor > 0. && (particle.pT() < softMomentumCutoff)) {
214  // this cutoff was 1.0/sqrt(vir_factor) in versions < 3.6
215  continue;
216  } else if(vir_factor < 0. && (particle.pAbs() < softMomentumCutoff)) {
217  continue;
218  } else if(vir_factor < rounding_error) {
219  JSWARN << "vir_factor should not be zero.";
220  exit(1);
221  }
222 
223  //if(particle.id()==22) cout<<"########this is a photon!######" <<endl;
224  // accept
225  } else { // FSR_on true: use Pythia vacuum shower instead of MATTER
226  if (!particle.isFinal())
227  continue;
228  // only accept gluons and quarks
229  // Also accept Gammas to put into the hadron's list
230  if (fabs(particle.id()) > 5 &&
231  (particle.id() != 21 && particle.id() != 22))
232  continue;
233  }
234  p62.push_back(particle);
235  }
236 
237  // if you want at least 2
238  if (p62.size() < 2)
239  continue;
240  //if ( p62.size() < 1 ) continue;
241 
242  // Now have all candidates, sort them
243  // sort by pt
244  std::sort(p62.begin(), p62.end(), greater_than_pt());
245  // // check...
246  // for (auto& p : p62 ) cout << p.pT() << endl;
247 
248  //skipping event if softQCD is on & pThat exceeds max (where next bin is HardQCD with this as pThatmin)
249  if(softQCD && (info.pTHat() >= pTHatMax)){continue;}
250 
251  flag62 = true;
252 
253  } while (!flag62);
254 
255  double p[4], xLoc[4];
256 
257  // This location should come from an initial state
258  for (int i = 0; i <= 3; i++) {
259  xLoc[i] = 0.0;
260  };
261 
262  // // Roll for a starting point
263  // // See: https://stackoverflow.com/questions/15039688/random-generator-from-vector-with-probability-distribution-in-c
264  // std::random_device device;
265  // std::mt19937 engine(device()); // Seed the random number engine
266 
267  if (!ini) {
268  VERBOSE(1) << "No initial state module, setting the starting location to "
269  "0. Make sure to add e.g. trento before PythiaGun.";
270  } else {
271  double x, y;
272  ini->SampleABinaryCollisionPoint(x, y);
273  xLoc[1] = x;
274  xLoc[2] = y;
275  }
276 
277  // Loop through particles
278 
279  // Only top two
280  //for(int np = 0; np<2; ++np){
281 
282  // Accept them all
283 
284  int hCounter = 0;
285  for (int np = 0; np < p62.size(); ++np) {
286  Pythia8::Particle &particle = p62.at(np);
287 
288  VERBOSE(7) << "Adding particle with pid = " << particle.id()
289  << " at x=" << xLoc[1] << ", y=" << xLoc[2] << ", z=" << xLoc[3];
290 
291  VERBOSE(7) << "Adding particle with pid = " << particle.id()
292  << ", pT = " << particle.pT() << ", eta = " << particle.eta()
293  << ", phi = " << particle.phi() << ", e = " << particle.e();
294 
295  VERBOSE(7) << " at x=" << xLoc[1] << ", y=" << xLoc[2] << ", z=" << xLoc[3];
296 
297  auto ptn = make_shared<Parton>(0, particle.id(), 0, particle.pT(), particle.eta(),particle.phi(), particle.e(), xLoc);
298  ptn->set_color(particle.col());
299  ptn->set_anti_color(particle.acol());
300  ptn->set_max_color(1000 * (np + 1));
301  AddParton(ptn);
302  }
303 
304  VERBOSE(8) << GetNHardPartons();
305 }