StRoot  1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
LHAHelaconia.h
1 // LHAHelaconia.h is a part of the PYTHIA event generator.
2 // Copyright (C) 2018 Torbjorn Sjostrand.
3 // PYTHIA is licenced under the GNU GPL v2 or later, see COPYING for details.
4 // Please respect the MCnet Guidelines, see GUIDELINES for details.
5 
6 // Author: Philip Ilten, December 2017.
7 
8 #ifndef Pythia8_LHAHelaconia_H
9 #define Pythia8_LHAHelaconia_H
10 
11 #include "Pythia8/Pythia.h"
12 #include <unistd.h>
13 #include <sys/stat.h>
14 #include <limits>
15 
16 namespace Pythia8 {
17 
18 //==========================================================================
19 
20 // A derived class from LHAup which generates events with HelacOnia.
21 
22 // This class automatically generates hard processes with HelacOnia
23 // and reads in the LHEF file output.
24 
25 // The user can send commands to HelacOnia via the readString
26 // method. The launch command, random seed, and shower choice are
27 // automatically handled. For example, the following will produce
28 // J/psi events from 13 TeV proton proton collisions:
29 
30 // readString("generate u u~ > cc~(3S11) g")
31 
32 // The number of events generated per HelacOnia run is controlled by
33 // setEvents, while the random seed is controlled by setSeed.
34 
35 class LHAupHelaconia : public LHAup {
36 
37 public:
38 
39  // Constructor.
40  LHAupHelaconia(Pythia *pythiaIn, string dirIn = "helaconiarun",
41  string exeIn = "ho_cluster");
42 
43  // Destructor.
44  ~LHAupHelaconia();
45 
46  // Read a HelacOnia command string.
47  bool readString(string line);
48 
49  // Set the number of events to generate per run.
50  void setEvents(int eventsIn);
51 
52  // Set the random seed and maximum runs.
53  bool setSeed(int seedIn, int runsIn = 30081);
54 
55  // Set the initialization information.
56  bool setInit();
57 
58  // Set the event information.
59  bool setEvent(int = 0);
60 
61 protected:
62 
63  // Execute a system command.
64  bool execute(string line);
65 
66  // Run HelacOnia.
67  bool run(int eventsIn, int seedIn = -1);
68 
69  // Create the LHEF reader.
70  bool reader(bool init);
71 
72  // Convert the color octet HelacOnia ID to a Pythia 8 ID.
73  int convert(int idIn);
74 
75  // The PYTHIA object and LHEF file reader and matching hook.
76  Pythia *pythia;
77  LHAupLHEF *lhef;
78 
79  // Stored members.
80  int events, seed, runs, nRuns, nId, nQ, nR, nL, nJ;
81  string dir, exe, lhegz;
82  double sigWgt, wgt, mQ;
83 
84  // The HelacOnia commands.
85  vector<string> lines;
86 
87 };
88 
89 //--------------------------------------------------------------------------
90 
91 // Constructor.
92 
93 LHAupHelaconia::LHAupHelaconia(Pythia *pythiaIn, string dirIn, string exeIn) :
94  pythia(pythiaIn), lhef(0), events(10000), seed(-1), runs(30081),
95  nRuns(0), nId(443), nQ(4), nR(0), nL(0), nJ(3),
96  dir(dirIn), exe(exeIn), lhegz(dirIn + "/events.lhe"), mQ(-2) {
97  mkdir(dir.c_str(), 0777);
98  if (pythia) pythia->readString("Beams:frameType = 5");
99  pythia->settings.addMode("Onia:state", -1, false, false, 0, 0);
100 }
101 
102 //--------------------------------------------------------------------------
103 
104 // Destructor.
105 
106 LHAupHelaconia::~LHAupHelaconia() {if (lhef) delete lhef;}
107 
108 //--------------------------------------------------------------------------
109 
110 // Read a HelacOnia command string.
111 
112 // The special command "set state = <pid>" is not passed to HelacOnia,
113 // but rather is used to set the color singlet state being produced
114 // from the color octet state (if a color octet state is being
115 // produced). If color octet production is enabled then the
116 // appropriate quark mass is modified to half the mass of the color
117 // octet state plus the color octet mass splitting.
118 
119 bool LHAupHelaconia::readString(string line) {
120 
121  size_t n = line.find("state");
122  if (line.find("8)") != string::npos) mQ = -1;
123  if (n != string::npos && pythia) {
124  pythia->settings.readString("Onia:" + line.substr(n));
125  nId = abs(pythia->settings.mode("Onia:state"));
126  nQ = int(nId/1e2) % 10;
127  nR = int(nId/1e5) % 10;
128  nL = int(nId/1e4) % 10;
129  nJ = int(nId/1e0) % 10;
130  } else lines.push_back(line);
131  return true;
132 
133 }
134 
135 //--------------------------------------------------------------------------
136 
137 // Set the random seed and maximum allowed runs.
138 
139 // If the random seed is negative (default of -1), then the HelacOnia
140 // seed is taken as the Pythia parameter "Random:seed", which must be
141 // greater than 0. If the maximum number of allowed runs is exceeded
142 // (default of 30081) an error is thrown. The seed for a HelacOnia run
143 // is set as:
144 
145 // (random seed - 1) * (maximum runs) + (number of runs) + 1
146 
147 // HelacOnia can only handle random seeds up to 30081 * 30081. So, with
148 // this strategy, one can generate Pythia jobs with seeds from 0 to
149 // 30081, with each job running HelacOnia less than 30081 times, and
150 // ensure a fully statistically independent sample. If more than 30081
151 // jobs are needed, then the maximum allowed runs can be lowered
152 // accordingly, and if need be, setEvents can be used to increase the
153 // number of events generated per run.
154 
155 bool LHAupHelaconia::setSeed(int seedIn, int runsIn) {
156 
157  if (!pythia) return false;
158  seed = seedIn;
159  if (seed < 0) {
160  seed = pythia->settings.mode("Random:seed");
161  if (seed < 1) {
162  pythia->info.errorMsg("Error from LHAupHelaconia::setSeed: the given "
163  "Pythia seed is less than 1."); return false;}
164  }
165  runs = runsIn;
166  if (seed * runs > 30081 * 30081) {
167  pythia->info.errorMsg("Error from LHAupHelaconia::setSeed: the given seed "
168  "exceeds the HelacOnia limit."); return false;}
169  nRuns = 0;
170  return true;
171 
172 }
173 
174 //--------------------------------------------------------------------------
175 
176 // Set the number of events to generate per HelacOnia run; default is 10000.
177 
178 void LHAupHelaconia::setEvents(int eventsIn) {events = eventsIn;}
179 
180 //--------------------------------------------------------------------------
181 
182 // Execute a system command.
183 
184 bool LHAupHelaconia::execute(string line) {return system(line.c_str()) != -1;}
185 
186 //--------------------------------------------------------------------------
187 
188 // Run HelacOnia.
189 
190 bool LHAupHelaconia::run(int eventsIn, int seedIn) {
191 
192  // Set up run and seed.
193  if (!pythia) return false;
194  if (nRuns >= runs) {
195  pythia->info.errorMsg("Error from LHAupHelaconia::run: maximum number "
196  "of allowed runs exceeded."); return false;}
197  if (seed < 0 && !setSeed(seed, runs)) return false;
198  if (seedIn < 0) seedIn = (seed - 1) * runs + nRuns + 1;
199 
200  // Determine the heavy quark mass.
201  if (mQ == -1)
202  mQ = (pythia->particleData.m0(nId)
203  + pythia->settings.parm("Onia:massSplit"))/2.0;
204 
205  // Write the generation file.
206  if (!pythia) return false;
207  fstream config((dir + "/generate.py").c_str(), ios::out);
208  for (int iLine = 0; iLine < (int)lines.size(); ++iLine)
209  config << lines[iLine] << "\n";
210  config << "set seed = " << seedIn << "\n"
211  << "set unwgt = T\n"
212  << "set unwevt = " << eventsIn << "\n"
213  << "set preunw = " << 3.0/2.0*eventsIn << "\n";
214  if (mQ > 0) config << "set " << (nQ == 4 ? "c" : "b") << "mass = " << mQ
215  << "\n";
216  config << "launch\n";
217  config.close();
218 
219  // Create the event shuffler.
220  fstream shuffle((dir + "/shuffle.py").c_str(), ios::out);
221  shuffle <<
222  "import random, os\n"
223  "random.seed(" << seedIn << "); tag, pre, post, events = '', [], [], []\n"
224  "for line in open('events.lhe').readlines():\n"
225  " if line.strip().startswith('<'):\n"
226  " tag = line.strip()\n"
227  " if tag == '<event>': events += ['<event>\\n']; continue\n"
228  " if tag == '</event>': events[-1] += '</event>\\n'; continue\n"
229  " if tag == '<event>': events[-1] += line\n"
230  " elif len(events) == 0: pre += [line]\n"
231  " else: post += [line]\n"
232  "random.shuffle(events); os.unlink('events.lhe')\n"
233  "open('events.lhe', 'w').writelines(pre + events + post)\n";
234  shuffle.close();
235 
236  // Execute the run commands.
237  if (!execute("rm -rf " + dir + "/PROC* " + lhegz)) return false;
238  if (!execute("cd " + dir + "; cat generate.py | " + exe)) return false;
239  if (!execute("cd " + dir + "; ln -s PROC_HO_0/P0_calc_0/output/*.lhe "
240  "events.lhe;# python shuffle.py")) return false;
241  if (access(lhegz.c_str(), F_OK) == -1) return false;
242  ++nRuns;
243  return true;
244 
245 }
246 
247 //--------------------------------------------------------------------------
248 
249 // Create the LHEF reader.
250 
251 bool LHAupHelaconia::reader(bool init) {
252 
253  // Check valid LHE file.
254  if (!pythia) return false;
255  if (lhef) delete lhef;
256  bool setScales(pythia->settings.flag("Beams:setProductionScalesFromLHEF"));
257  lhef = new LHAupLHEF(&pythia->info, lhegz.c_str(), NULL, false, setScales);
258  if (!lhef->setInit()) {
259  pythia->info.errorMsg("Error from LHAupHelaconia::reader: failed to "
260  "initialize the LHEF reader"); return false;}
261  if (lhef->sizeProc() != 1) {
262  pythia->info.errorMsg("Error from LHAupHelaconia::reader: number of "
263  "processes is not 1"); return false;}
264 
265  if (init) {
266 
267  // Determine the cross-section (if needed).
268  double sig(lhef->xSec(0)), err(lhef->xErr(0));
269 
270  // Set the info.
271  setBeamA(lhef->idBeamA(), lhef->eBeamA(), lhef->pdfGroupBeamA(),
272  lhef->pdfSetBeamA());
273  setBeamB(lhef->idBeamB(), lhef->eBeamB(), lhef->pdfGroupBeamB(),
274  lhef->pdfSetBeamB());
275  setStrategy(lhef->strategy());
276  addProcess(lhef->idProcess(0), sig, err, lhef->xMax(0));
277  xSecSumSave = sig; xErrSumSave = err;
278  }
279  return true;
280 
281 }
282 
283 //--------------------------------------------------------------------------
284 
285 // Convert the color octet HelacOnia ID to a Pythia 8 ID.
286 
287 int LHAupHelaconia::convert(int idIn) {
288 
289  if (abs(idIn) < 9900000) return idIn;
290  else idIn = abs(idIn) - 9900000;
291  int nS = 2;
292  if (idIn == nQ*110 + 3) nS = 0;
293  else if (idIn == nQ*110 + 1) nS = 1;
294  return 9900000 + 10000*nQ + 1000*nS + 100*nR + 10*nL + nJ;
295 
296 }
297 
298 //--------------------------------------------------------------------------
299 
300 // Set the initialization information.
301 
302 bool LHAupHelaconia::setInit() {
303 
304  // Create the LHEF LHAup object and run setInit.
305  if (!pythia) return false;
306  if (!run(events)) return false;
307  if (!reader(true)) return false;
308  listInit();
309  return true;
310 
311 }
312 
313 //--------------------------------------------------------------------------
314 
315 // Set the event information.
316 
317 bool LHAupHelaconia::setEvent(int) {
318 
319  // Run setEvent from the LHEF object and launch HelacOnia if failed.
320  if (!pythia) return false;
321  if (!lhef) {
322  pythia->info.errorMsg("Error from LHAupHelaconia::setEvent: LHAupLHEF "
323  "object not correctly initialized"); return false;}
324  if (!lhef->fileFound()) {
325  pythia->info.errorMsg("Error from LHAupHelaconia::setEvent: LHEF "
326  "event file was not found"); return false;}
327  if (!lhef->setEvent()) {
328  if (!run(events)) return false;
329  if (!reader(false)) return false;
330  lhef->setEvent();
331  }
332 
333  // Read the event from the LHEF object.
334  particlesSave.clear();
335  int mom1, mom2;
336  for (int ip = 1; ip < lhef->sizePart(); ++ip) {
337  mom1 = lhef->mother1(ip);
338  mom2 = lhef->mother2(ip);
339  particlesSave.push_back
340  (LHAParticle(convert(lhef->id(ip)),
341  lhef->status(ip), mom1, mom2, lhef->col1(ip),
342  lhef->col2(ip), lhef->px(ip), lhef->py(ip), lhef->pz(ip),
343  lhef->e(ip), lhef->m(ip), lhef->tau(ip), lhef->spin(ip),
344  lhef->scale(ip)));
345  if (mom1 > 0 && mom1 < (int)particlesSave.size() && mom2 == 0)
346  particlesSave[mom1 - 1].statusPart = 2;
347  }
348 
349  // Write the event.
350  setProcess(lhef->idProcess(), lhef->weight(), lhef->scale(),
351  lhef->alphaQED(), lhef->alphaQCD());
352  for (int ip = 0; ip < (int)particlesSave.size(); ++ip)
353  addParticle(particlesSave[ip]);
354  setIdX(lhef->id1(), lhef->id2(), lhef->x1(), lhef->x2());
355  setPdf(lhef->id1pdf(), lhef->id2pdf(), lhef->x1pdf(), lhef->x2pdf(),
356  lhef->scalePDF(), lhef->pdf1(), lhef->pdf2(), lhef->pdfIsSet());
357  return true;
358 
359 }
360 
361 //==========================================================================
362 
363 } // end namespace Pythia8
364 
365 #endif // Pythia8_LHAHelaconia_H