StRoot  1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
GeneratorInput.h
1 // GeneratorInput.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 // Primary Author: Richard Corke
7 // Secondary Author: Stephen Mrenna
8 // This file provides the following classes:
9 // AlpgenPar: a class for parsing ALPGEN parameter files
10 // and reading back out the values
11 // LHAupAlpgen: an LHAup derived class for reading in ALPGEN
12 // format event files
13 // AlpgenHooks: a UserHooks derived class for providing
14 // 'Alpgen:*' user options
15 // MadgraphPar: a class for parsing MadGraph parameter files
16 // and reading back out the values
17 // Example usage is shown in main32.cc, and further details
18 // can be found in the 'Jet Matching Style' manual page.
19 // Minor changes were made by the secondary author for integration
20 // with Madgraph-style matching, and Madgraph input was added.
21 
22 #ifndef Pythia8_GeneratorInput_H
23 #define Pythia8_GeneratorInput_H
24 
25 // Includes and namespace
26 #include "Pythia8/Pythia.h"
27 
28 namespace Pythia8 {
29 
30 //==========================================================================
31 
32 // AlpgenPar: Class to parse ALPGEN parameter files and make them
33 // available through a simple interface
34 
35 class AlpgenPar {
36 
37 public:
38 
39  // Constructor
40  AlpgenPar(Info *infoPtrIn = NULL) : infoPtr(infoPtrIn) {}
41 
42  // Parse as incoming ALPGEN parameter file (passed as string)
43  bool parse(const string paramStr);
44 
45  // Parse an incoming parameter line
46  void extractRunParam(string line);
47 
48  // Check if a parameter exists
49  bool haveParam(const string &paramIn) {
50  return (params.find(paramIn) == params.end()) ? false : true; }
51 
52  // Get a parameter as a double or integer.
53  // Caller should have already checked existance of the parameter.
54  double getParam(const string &paramIn) {
55  return (haveParam(paramIn)) ? params[paramIn] : 0.; }
56  int getParamAsInt(const string &paramIn) {
57  return (haveParam(paramIn)) ? int(params[paramIn]) : 0.; }
58 
59  // Print parameters read from the '.par' file
60  void printParams();
61 
62 private:
63 
64  // Warn if a parameter is going to be overwriten
65  void warnParamOverwrite(const string &paramIn, double val);
66 
67  // Simple string trimmer
68  static string trim(string s);
69 
70  // Storage for parameters
71  map<string,double> params;
72 
73  // Info pointer if provided
74  Info* infoPtr;
75 
76  // Constants
77  static const double ZEROTHRESHOLD;
78 
79 };
80 
81 //==========================================================================
82 
83 // LHAupAlpgen: LHAup derived class for reading in ALPGEN format
84 // event files.
85 
86 class LHAupAlpgen : public LHAup {
87 
88 public:
89 
90  // Constructor and destructor.
91  LHAupAlpgen(const char *baseFNin, Info *infoPtrIn = NULL);
92  ~LHAupAlpgen() { closeFile(isUnw, ifsUnw); }
93 
94  // Override fileFound routine from LHAup.
95  bool fileFound() { return (isUnw != NULL); }
96 
97  // Override setInit/setEvent routines from LHAup.
98  bool setInit();
99  bool setEvent(int);
100 
101  // Print list of particles; mainly intended for debugging
102  void printParticles();
103 
104 private:
105 
106  // Add resonances to incoming event.
107  bool addResonances();
108 
109  // Rescale momenta to remove any imbalances.
110  bool rescaleMomenta();
111 
112  // Class variables
113  string baseFN, parFN, unwFN; // Incoming filenames
114  AlpgenPar alpgenPar; // Parameter database
115  int lprup; // Process code
116  double ebmupA, ebmupB; // Beam energies
117  int ihvy1, ihvy2; // Heavy flavours for certain processes
118  double mb; // Bottom mass
119  ifstream ifsUnw; // Input file stream for 'unw' file
120  istream* isUnw; // Input stream for 'unw' file
121  vector<LHAParticle> myParticles; // Local storage for particles
122 
123  // Constants
124  static const bool LHADEBUG, LHADEBUGRESCALE;
125  static const double ZEROTHRESHOLD, EWARNTHRESHOLD, PTWARNTHRESHOLD,
126  INCOMINGMIN;
127 
128 };
129 
130 //==========================================================================
131 
132 // AlpgenHooks: provides Alpgen file reading options.
133 // Note that it is defined with virtual inheritance, so that it can
134 // be combined with other UserHooks classes, see e.g. main32.cc.
135 
136 class AlpgenHooks : virtual public UserHooks {
137 
138 public:
139 
140  // Constructor and destructor
141  AlpgenHooks(Pythia &pythia);
142  ~AlpgenHooks() { if (LHAagPtr) delete LHAagPtr; }
143 
144  // Override initAfterBeams routine from UserHooks
145  bool initAfterBeams();
146 
147 private:
148 
149  // LHAupAlpgen pointer
150  LHAupAlpgen* LHAagPtr;
151 
152 };
153 
154 //==========================================================================
155 
156 // MadgraphPar: Class to parse the Madgraph header parameters and
157 // make them available through a simple interface
158 
159 class MadgraphPar {
160 
161 public:
162 
163  // Constructor
164  MadgraphPar(Info *infoPtrIn = NULL) : infoPtr(infoPtrIn) {}
165 
166  // Parse an incoming Madgraph parameter file string
167  bool parse(const string paramStr);
168 
169  // Parse an incoming parameter line
170  void extractRunParam(string line);
171 
172  // Check if a parameter exists
173  bool haveParam(const string &paramIn) {
174  return (params.find(paramIn) == params.end()) ? false : true; }
175 
176  // Get a parameter as a double or integer.
177  // Caller should have already checked existance of the parameter.
178  double getParam(const string &paramIn) {
179  return (haveParam(paramIn)) ? params[paramIn] : 0.; }
180  int getParamAsInt(const string &paramIn) {
181  return (haveParam(paramIn)) ? int(params[paramIn]) : 0.; }
182 
183  // Print parameters read from the '.par' file
184  void printParams();
185 
186 private:
187 
188  // Warn if a parameter is going to be overwriten
189  void warnParamOverwrite(const string &paramIn, double val);
190 
191  // Simple string trimmer
192  static string trim(string s);
193 
194  // Storage for parameters
195  map<string,double> params;
196 
197  // Info pointer if provided
198  Info *infoPtr;
199 
200  // Constants
201  static const double ZEROTHRESHOLD;
202 
203 };
204 
205 //==========================================================================
206 
207 // Main implementation of AlpgenPar class.
208 // This may be split out to a separate C++ file if desired,
209 // but currently included here for ease of use.
210 
211 //--------------------------------------------------------------------------
212 
213 // Constants: could be changed here if desired, but normally should not.
214 // These are of technical nature, as described for each.
215 
216 // A zero threshold value for double comparisons.
217 const double AlpgenPar::ZEROTHRESHOLD = 1e-10;
218 
219 //--------------------------------------------------------------------------
220 
221 // Warn if e/pT imbalance greater than these values
222 // Parse an incoming Alpgen parameter file string
223 
224 inline bool AlpgenPar::parse(const string paramStr) {
225 
226  // Read par file in blocks:
227  // 0 - process information
228  // 1 - run parameters
229  // 2 - cross sections
230  int block = 0;
231 
232  // Loop over incoming lines
233  stringstream paramStream(paramStr);
234  string line;
235  while (getline(paramStream, line)) {
236 
237  // Change to 'run parameters' block
238  if (line.find("run parameters") != string::npos) {
239  block = 1;
240 
241  // End of 'run parameters' block
242  } else if (line.find("end parameters") != string::npos) {
243  block = 2;
244 
245  // Do not extract anything from block 0 so far
246  } else if (block == 0) {
247 
248  // Block 1 or 2: extract parameters
249  } else {
250  extractRunParam(line);
251 
252  }
253  } // while (getline(paramStream, line))
254 
255  return true;
256 }
257 
258 //--------------------------------------------------------------------------
259 
260 // Parse an incoming parameter line
261 
262 inline void AlpgenPar::extractRunParam(string line) {
263 
264  // Extract information to the right of the final '!' character
265  size_t idx = line.rfind("!");
266  if (idx == string::npos) return;
267  string paramName = trim(line.substr(idx + 1));
268  string paramVal = trim(line.substr(0, idx));
269  istringstream iss(paramVal);
270 
271  // Special case: 'hard process code' - single integer input
272  double val;
273  if (paramName == "hard process code") {
274  iss >> val;
275  warnParamOverwrite("hpc", val);
276  params["hpc"] = val;
277 
278  // Special case: 'Crosssection +- error (pb)' - two double values
279  } else if (paramName.find("Crosssection") == 0) {
280  double xerrup;
281  iss >> val >> xerrup;
282  warnParamOverwrite("xsecup", val);
283  warnParamOverwrite("xerrup", val);
284  params["xsecup"] = val;
285  params["xerrup"] = xerrup;
286 
287  // Special case: 'unwtd events, lum (pb-1)' - integer and double values
288  } else if (paramName.find("unwtd events") == 0) {
289  int nevent;
290  iss >> nevent >> val;
291  warnParamOverwrite("nevent", val);
292  warnParamOverwrite("lum", val);
293  params["nevent"] = nevent;
294  params["lum"] = val;
295 
296  // Special case: 'mc,mb,...' - split on ',' for name and ' ' for values
297  } else if (paramName.find(",") != string::npos) {
298 
299  // Simple tokeniser
300  string paramNameNow;
301  istringstream issName(paramName);
302  while (getline(issName, paramNameNow, ',')) {
303  iss >> val;
304  warnParamOverwrite(paramNameNow, val);
305  params[paramNameNow] = val;
306  }
307 
308  // Default case: assume integer and double on the left
309  } else {
310  int paramIdx;
311  iss >> paramIdx >> val;
312  warnParamOverwrite(paramName, val);
313  params[paramName] = val;
314  }
315 }
316 
317 //--------------------------------------------------------------------------
318 
319 // Print parameters read from the '.par' file
320 
321 inline void AlpgenPar::printParams() {
322 
323  // Loop over all stored parameters and print
324  cout << fixed << setprecision(3) << endl
325  << " *------- Alpgen parameters -------*" << endl;
326  for (map < string, double >::iterator it = params.begin();
327  it != params.end(); ++it)
328  cout << " | " << left << setw(13) << it->first
329  << " | " << right << setw(13) << it->second
330  << " |" << endl;
331  cout << " *-----------------------------------*" << endl;
332 }
333 
334 //--------------------------------------------------------------------------
335 
336 // Warn if a parameter is going to be overwriten
337 
338 inline void AlpgenPar::warnParamOverwrite(const string &paramIn, double val) {
339 
340  // Check if present and if new value is different
341  if (haveParam(paramIn) &&
342  abs(getParam(paramIn) - val) > ZEROTHRESHOLD) {
343  if (infoPtr) infoPtr->errorMsg("Warning in LHAupAlpgen::"
344  "warnParamOverwrite: overwriting existing parameter", paramIn);
345  }
346 }
347 
348 //--------------------------------------------------------------------------
349 
350 // Simple string trimmer
351 
352 inline string AlpgenPar::trim(string s) {
353 
354  // Remove whitespace in incoming string
355  size_t i;
356  if ((i = s.find_last_not_of(" \t\r\n")) != string::npos)
357  s = s.substr(0, i + 1);
358  if ((i = s.find_first_not_of(" \t\r\n")) != string::npos)
359  s = s.substr(i);
360  return s;
361 }
362 
363 //==========================================================================
364 
365 // Main implementation of LHAupAlpgen class.
366 // This may be split out to a separate C++ file if desired,
367 // but currently included here for ease of use.
368 
369 // ----------------------------------------------------------------------
370 
371 // Constants: could be changed here if desired, but normally should not.
372 // These are of technical nature, as described for each.
373 
374 // Debug flag to print all particles in each event.
375 const bool LHAupAlpgen::LHADEBUG = false;
376 
377 // Debug flag to print particles when an e/p imbalance is found.
378 const bool LHAupAlpgen::LHADEBUGRESCALE = false;
379 
380 // A zero threshold value for double comparisons.
381 const double LHAupAlpgen::ZEROTHRESHOLD = 1e-10;
382 
383 // Warn if e/pT imbalance greater than these values
384 const double LHAupAlpgen::EWARNTHRESHOLD = 3e-3;
385 const double LHAupAlpgen::PTWARNTHRESHOLD = 1e-3;
386 
387 // If incoming e/pZ is 0, it is reset to this value
388 const double LHAupAlpgen::INCOMINGMIN = 1e-3;
389 
390 // ----------------------------------------------------------------------
391 
392 // Constructor. Opens parameter file and parses then opens event file.
393 
394 LHAupAlpgen::LHAupAlpgen(const char* baseFNin, Info* infoPtrIn)
395  : baseFN(baseFNin), alpgenPar(infoPtrIn), isUnw(NULL) {
396 
397  // Set the info pointer if given
398  if (infoPtrIn) setPtr(infoPtrIn);
399 
400  // Read in '_unw.par' file to get parameters
401  ifstream ifsPar;
402  istream* isPar = NULL;
403 
404  // Try gzip file first then normal file afterwards
405 #ifdef GZIPSUPPORT
406  parFN = baseFN + "_unw.par.gz";
407  isPar = openFile(parFN.c_str(), ifsPar);
408  if (!ifsPar.is_open()) closeFile(isPar, ifsPar);
409 #endif
410  if (isPar == NULL) {
411  parFN = baseFN + "_unw.par";
412  isPar = openFile(parFN.c_str(), ifsPar);
413  if (!ifsPar.is_open()) {
414  if (infoPtr) infoPtr->errorMsg("Error in LHAupAlpgen::LHAupAlpgen: "
415  "cannot open parameter file", parFN);
416  closeFile(isPar, ifsPar);
417  return;
418  }
419  }
420 
421  // Read entire contents into string and close file
422  string paramStr((std::istreambuf_iterator<char>(isPar->rdbuf())),
423  std::istreambuf_iterator<char>());
424 
425  // Make sure we reached EOF and not other error
426  if (ifsPar.bad()) {
427  if (infoPtr) infoPtr->errorMsg("Error in LHAupAlpgen::LHAupAlpgen: "
428  "cannot read parameter file", parFN);
429  return;
430  }
431  closeFile(isPar, ifsPar);
432 
433  // Parse file and set LHEF header
434  alpgenPar.parse(paramStr);
435  if (infoPtr) setInfoHeader("AlpgenPar", paramStr);
436 
437  // Open '.unw' events file (with possible gzip support)
438 #ifdef GZIPSUPPORT
439  unwFN = baseFN + ".unw.gz";
440  isUnw = openFile(unwFN.c_str(), ifsUnw);
441  if (!ifsUnw.is_open()) closeFile(isUnw, ifsUnw);
442 #endif
443  if (isUnw == NULL) {
444  unwFN = baseFN + ".unw";
445  isUnw = openFile(unwFN.c_str(), ifsUnw);
446  if (!ifsUnw.is_open()) {
447  if (infoPtr) infoPtr->errorMsg("Error in LHAupAlpgen::LHAupAlpgen: "
448  "cannot open event file", unwFN);
449  closeFile(isUnw, ifsUnw);
450  }
451  }
452 }
453 
454 // ----------------------------------------------------------------------
455 
456 // setInit is a virtual method that must be finalised here.
457 // Sets up beams, strategy and processes.
458 
459 inline bool LHAupAlpgen::setInit() {
460 
461  // Check that all required parameters are present
462  if (!alpgenPar.haveParam("ih2") || !alpgenPar.haveParam("ebeam") ||
463  !alpgenPar.haveParam("hpc") || !alpgenPar.haveParam("xsecup") ||
464  !alpgenPar.haveParam("xerrup")) {
465  if (infoPtr) infoPtr->errorMsg("Error in LHAupAlpgen::setInit: "
466  "missing input parameters");
467  return false;
468  }
469 
470  // Beam IDs
471  int ih2 = alpgenPar.getParamAsInt("ih2");
472  int idbmupA = 2212;
473  int idbmupB = (ih2 == 1) ? 2212 : -2212;
474 
475  // Beam energies
476  double ebeam = alpgenPar.getParam("ebeam");
477  ebmupA = ebeam;
478  ebmupB = ebmupA;
479 
480  // PDF group and set (at the moment not set)
481  int pdfgupA = 0, pdfsupA = 0;
482  int pdfgupB = 0, pdfsupB = 0;
483 
484  // Strategy is for unweighted events and xmaxup not important
485  int idwtup = 3;
486  double xmaxup = 0.;
487 
488  // Get hard process code
489  lprup = alpgenPar.getParamAsInt("hpc");
490 
491  // Check for unsupported processes
492  if (lprup == 7 || lprup == 8 || lprup == 13) {
493  if (infoPtr) infoPtr->errorMsg("Error in LHAupAlpgen::setInit: "
494  "process not implemented");
495  return false;
496  }
497 
498  // Depending on the process code, get heavy flavour information:
499  // 6 = QQbar + jets
500  // 7 = QQbar + Q'Qbar' + jets
501  // 8 = QQbar + Higgs + jets
502  // 16 = QQbar + gamma + jets
503  if (lprup == 6 || lprup == 7 || lprup == 8 || lprup == 16) {
504  if (!alpgenPar.haveParam("ihvy")) {
505  if (infoPtr) infoPtr->errorMsg("Error in LHAupAlpgen::setInit: "
506  "heavy flavour information not present");
507  return false;
508  }
509  ihvy1 = alpgenPar.getParamAsInt("ihvy");
510 
511  } else ihvy1 = -1;
512  if (lprup == 7) {
513  if (!alpgenPar.haveParam("ihvy2")) {
514  if (infoPtr) infoPtr->errorMsg("Error in LHAupAlpgen::setInit: "
515  "heavy flavour information not present");
516  return false;
517  }
518  ihvy2 = alpgenPar.getParamAsInt("ihvy2");
519  } else ihvy2 = -1;
520  // For single top (process 13), get b mass to set incoming
521  mb = -1.;
522  if (lprup == 13) {
523  if (!alpgenPar.haveParam("mb")) {
524  if (infoPtr) infoPtr->errorMsg("Error in LHAupAlpgen::setInit: "
525  "heavy flavour information not present");
526  return false;
527  }
528  mb = alpgenPar.getParam("mb");
529  }
530 
531  // Set the beams
532  setBeamA(idbmupA, ebmupA, pdfgupA, pdfsupA);
533  setBeamB(idbmupB, ebmupB, pdfgupB, pdfsupB);
534  setStrategy(idwtup);
535 
536  // Add the process
537  double xsecup = alpgenPar.getParam("xsecup");
538  double xerrup = alpgenPar.getParam("xerrup");
539  addProcess(lprup, xsecup, xerrup, xmaxup);
540  xSecSumSave = xsecup;
541  xErrSumSave = xerrup;
542 
543  // All okay
544  return true;
545 }
546 
547 // ----------------------------------------------------------------------
548 
549 // setEvent is a virtual method that must be finalised here.
550 // Read in an event from the 'unw' file and setup.
551 
552 inline bool LHAupAlpgen::setEvent(int) {
553 
554  // Read in the first line of the event
555  int nEvent, iProc, nParton;
556  double Swgt, Sq;
557  string line;
558  if (!getline(*isUnw, line)) {
559  // Read was bad
560  if (ifsUnw.bad()) {
561  if (infoPtr) infoPtr->errorMsg("Error in LHAupAlpgen::setEvent: "
562  "could not read events from file");
563  return false;
564  }
565  // End of file reached
566  if (infoPtr) infoPtr->errorMsg("Error in LHAupAlpgen::setEvent: "
567  "end of file reached");
568  return false;
569  }
570  istringstream iss1(line);
571  iss1 >> nEvent >> iProc >> nParton >> Swgt >> Sq;
572 
573  // Set the process details (ignore alphaQED and alphaQCD parameters)
574  double wgtT = Swgt, scaleT = Sq;
575  setProcess(lprup, wgtT, scaleT);
576 
577  // Incoming flavour and x information for later
578  int id1T, id2T;
579  double x1T, x2T;
580  // Temporary storage for read in parton information
581  int idT, statusT, mother1T, mother2T, col1T, col2T;
582  double pxT, pyT, pzT, eT, mT;
583  // Leave tau and spin as default values
584  double tauT = 0., spinT = 9.;
585 
586  // Store particles locally at first so that resonances can be added
587  myParticles.clear();
588 
589  // Now read in partons
590  for (int i = 0; i < nParton; i++) {
591  // Get the next line
592  if (!getline(*isUnw, line)) {
593  if (infoPtr) infoPtr->errorMsg("Error in LHAupAlpgen::setEvent: "
594  "could not read events from file");
595  return false;
596  }
597  istringstream iss2(line);
598 
599  // Incoming (flavour, colour, anticolour, pz)
600  if (i < 2) {
601  // Note that mothers will be set automatically by Pythia, and LHA
602  // status -1 is for an incoming parton
603  iss2 >> idT >> col1T >> col2T >> pzT;
604  statusT = -1;
605  mother1T = mother2T = 0;
606  pxT = pyT = mT = 0.;
607  eT = abs(pzT);
608 
609  // Adjust when zero pz/e
610  if (pzT == 0.) {
611  pzT = (i == 0) ? INCOMINGMIN : -INCOMINGMIN;
612  eT = INCOMINGMIN;
613  }
614 
615  // Outgoing (flavour, colour, anticolour, px, py, pz, mass)
616  } else {
617  // Note that mothers 1 and 2 corresport to the incoming partons,
618  // as set above, and LHA status +1 is for outgoing final state
619  iss2 >> idT >> col1T >> col2T >> pxT >> pyT >> pzT >> mT;
620  statusT = 1;
621  mother1T = 1;
622  mother2T = 2;
623  eT = sqrt(max(0., pxT*pxT + pyT*pyT + pzT*pzT + mT*mT));
624  }
625 
626  // Add particle
627  myParticles.push_back(LHAParticle(
628  idT, statusT, mother1T, mother2T, col1T, col2T,
629  pxT, pyT, pzT, eT, mT, tauT, spinT,-1.));
630  }
631 
632  // Add resonances if required
633  if (!addResonances()) return false;
634 
635  // Rescale momenta if required (must be done after full event
636  // reconstruction in addResonances)
637  if (!rescaleMomenta()) return false;
638 
639  // Pass particles on to Pythia
640  for (size_t i = 0; i < myParticles.size(); i++)
641  addParticle(myParticles[i]);
642 
643  // Set incoming flavour/x information and done
644  id1T = myParticles[0].idPart;
645  x1T = myParticles[0].ePart / ebmupA;
646  id2T = myParticles[1].idPart;
647  x2T = myParticles[1].ePart / ebmupA;
648  setIdX(id1T, id2T, x1T, x2T);
649  setPdf(id1T, id2T, x1T, x2T, 0., 0., 0., false);
650  return true;
651 }
652 
653 // ----------------------------------------------------------------------
654 
655 // Print list of particles; mainly intended for debugging
656 
657 inline void LHAupAlpgen::printParticles() {
658 
659  cout << endl << "---- LHAupAlpgen particle listing begin ----" << endl;
660  cout << scientific << setprecision(6);
661  for (int i = 0; i < int(myParticles.size()); i++) {
662  cout << setw(5) << i
663  << setw(5) << myParticles[i].idPart
664  << setw(5) << myParticles[i].statusPart
665  << setw(15) << myParticles[i].pxPart
666  << setw(15) << myParticles[i].pyPart
667  << setw(15) << myParticles[i].pzPart
668  << setw(15) << myParticles[i].ePart
669  << setw(15) << myParticles[i].mPart
670  << setw(5) << myParticles[i].mother1Part - 1
671  << setw(5) << myParticles[i].mother2Part - 1
672  << setw(5) << myParticles[i].col1Part
673  << setw(5) << myParticles[i].col2Part
674  << endl;
675  }
676  cout << "---- LHAupAlpgen particle listing end ----" << endl;
677 }
678 
679 // ----------------------------------------------------------------------
680 
681 // Routine to add resonances to an incoming event based on the
682 // hard process code (now stored in lprup).
683 
684 inline bool LHAupAlpgen::addResonances() {
685 
686  // Temporary storage for resonance information
687  int idT, statusT, mother1T, mother2T, col1T, col2T;
688  double pxT, pyT, pzT, eT, mT;
689  // Leave tau and spin as default values
690  double tauT = 0., spinT = 9.;
691 
692  // Alpgen process dependent parts. Processes:
693  // 1 = W + QQbar + jets
694  // 2 = Z/gamma* + QQbar + jets
695  // 3 = W + jets
696  // 4 = Z/gamma* + jets
697  // 10 = W + c + jets
698  // 14 = W + gamma + jets
699  // 15 = W + QQbar + gamma + jets
700  // When QQbar = ttbar, tops are not decayed in these processes.
701  // Explicitly reconstruct W/Z resonances; assumption is that the
702  // decay products are the last two particles.
703  if (lprup <= 4 || lprup == 10 || lprup == 14 || lprup == 15) {
704  // Decay products are the last two entries
705  int i1 = myParticles.size() - 1, i2 = i1 - 1;
706 
707  // Follow 'alplib/alpsho.f' procedure to get ID
708  if (myParticles[i1].idPart + myParticles[i2].idPart == 0)
709  idT = 0;
710  else
711  idT = - (myParticles[i1].idPart % 2) - (myParticles[i2].idPart % 2);
712  idT = (idT > 0) ? 24 : (idT < 0) ? -24 : 23;
713 
714  // Check that we get the expected resonance type; Z/gamma*
715  if (lprup == 2 || lprup == 4) {
716  if (idT != 23) {
717  if (infoPtr) infoPtr->errorMsg("Error in "
718  "LHAupAlpgen::addResonances: wrong resonance type in event");
719  return false;
720  }
721 
722  // W's
723  } else {
724  if (abs(idT) != 24) {
725  if (infoPtr) infoPtr->errorMsg("Error in "
726  "LHAupAlpgen::addResonances: wrong resonance type in event");
727  return false;
728  }
729  }
730 
731  // Remaining input
732  statusT = 2;
733  mother1T = 1;
734  mother2T = 2;
735  col1T = col2T = 0;
736  pxT = myParticles[i1].pxPart + myParticles[i2].pxPart;
737  pyT = myParticles[i1].pyPart + myParticles[i2].pyPart;
738  pzT = myParticles[i1].pzPart + myParticles[i2].pzPart;
739  eT = myParticles[i1].ePart + myParticles[i2].ePart;
740  mT = sqrt(eT*eT - pxT*pxT - pyT*pyT - pzT*pzT);
741  myParticles.push_back(LHAParticle(
742  idT, statusT, mother1T, mother2T, col1T, col2T,
743  pxT, pyT, pzT, eT, mT, tauT, spinT, -1.));
744 
745  // Update decay product mothers (note array size as if from 1)
746  myParticles[i1].mother1Part = myParticles[i2].mother1Part =
747  myParticles.size();
748  myParticles[i1].mother2Part = myParticles[i2].mother2Part = 0;
749 
750  // Processes:
751  // 5 = nW + mZ + j gamma + lH + jets
752  // 6 = QQbar + jets (QQbar = ttbar)
753  // 8 = QQbar + Higgs + jets (QQbar = ttbar)
754  // 13 = top + q (topprc = 1)
755  // 13 = top + b (topprc = 2)
756  // 13 = top + W + jets (topprc = 3)
757  // 13 = top + W + b (topprc = 4)
758  // 16 = QQbar + gamma + jets (QQbar = ttbar)
759  //
760  // When tops are present, they are decayed to Wb (both the W and b
761  // are not given), with this W also decaying (decay products given).
762  // The top is marked intermediate, the (intermediate) W is
763  // reconstructed from its decay products, and the decay product mothers
764  // updated. The final-state b is reconstructed from (top - W).
765  //
766  // W/Z resonances are given, as well as their decay products. The
767  // W/Z is marked intermediate, and the decay product mothers updated.
768  //
769  // It is always assumed that decay products are at the end.
770  // For processes 5 and 13, it is also assumed that the decay products
771  // are in the same order as the resonances.
772  // For processes 6, 8 and 16, the possibility of the decay products
773  // being out-of-order is also taken into account.
774  } else if ( ((lprup == 6 || lprup == 8 || lprup == 16) && ihvy1 == 6) ||
775  lprup == 5 || lprup == 13) {
776 
777  // Go backwards through the particles looking for W/Z/top
778  int idx = myParticles.size() - 1;
779  for (int i = myParticles.size() - 1; i > -1; i--) {
780 
781  // W or Z
782  if (myParticles[i].idPart == 23 ||
783  abs(myParticles[i].idPart) == 24) {
784 
785  // Check that decay products and resonance match up
786  int flav;
787  if (myParticles[idx].idPart + myParticles[idx - 1].idPart == 0)
788  flav = 0;
789  else
790  flav = - (myParticles[idx].idPart % 2)
791  - (myParticles[idx - 1].idPart % 2);
792  flav = (flav > 0) ? 24 : (flav < 0) ? -24 : 23;
793  if (flav != myParticles[i].idPart) {
794  if (infoPtr)
795  infoPtr->errorMsg("Error in LHAupAlpgen::addResonance: "
796  "resonance does not match decay products");
797  return false;
798  }
799 
800  // Update status/mothers
801  myParticles[i].statusPart = 2;
802  myParticles[idx ].mother1Part = i + 1;
803  myParticles[idx--].mother2Part = 0;
804  myParticles[idx ].mother1Part = i + 1;
805  myParticles[idx--].mother2Part = 0;
806 
807  // Top
808  } else if (abs(myParticles[i].idPart) == 6) {
809 
810  // Check that decay products and resonance match up
811  int flav;
812  if (myParticles[idx].idPart + myParticles[idx - 1].idPart == 0)
813  flav = 0;
814  else
815  flav = - (myParticles[idx].idPart % 2)
816  - (myParticles[idx - 1].idPart % 2);
817  flav = (flav > 0) ? 24 : (flav < 0) ? -24 : 23;
818 
819  bool outOfOrder = false, wrongFlavour = false;;
820  if ( abs(flav) != 24 ||
821  (flav == 24 && myParticles[i].idPart != 6) ||
822  (flav == -24 && myParticles[i].idPart != -6) ) {
823 
824  // Processes 5 and 13, order should always be correct
825  if (lprup == 5 || lprup == 13) {
826  wrongFlavour = true;
827 
828  // Processes 6, 8 and 16, can have out of order decay products
829  } else {
830 
831  // Go back two decay products and retry
832  idx -= 2;
833  if (myParticles[idx].idPart + myParticles[idx - 1].idPart == 0)
834  flav = 0;
835  else
836  flav = - (myParticles[idx].idPart % 2)
837  - (myParticles[idx - 1].idPart % 2);
838  flav = (flav > 0) ? 24 : (flav < 0) ? -24 : 23;
839 
840  // If still the wrong flavour then error
841  if ( abs(flav) != 24 ||
842  (flav == 24 && myParticles[i].idPart != 6) ||
843  (flav == -24 && myParticles[i].idPart != -6) )
844  wrongFlavour = true;
845  else outOfOrder = true;
846  }
847 
848  // Error if wrong flavour
849  if (wrongFlavour) {
850  if (infoPtr)
851  infoPtr->errorMsg("Error in LHAupAlpgen::addResonance: "
852  "resonance does not match decay products");
853  return false;
854  }
855  }
856 
857  // Mark t/tbar as now intermediate
858  myParticles[i].statusPart = 2;
859 
860  // New intermediate W+/W-
861  idT = flav;
862  statusT = 2;
863  mother1T = i + 1;
864  mother2T = 0;
865  col1T = col2T = 0;
866  pxT = myParticles[idx].pxPart + myParticles[idx - 1].pxPart;
867  pyT = myParticles[idx].pyPart + myParticles[idx - 1].pyPart;
868  pzT = myParticles[idx].pzPart + myParticles[idx - 1].pzPart;
869  eT = myParticles[idx].ePart + myParticles[idx - 1].ePart;
870  mT = sqrt(eT*eT - pxT*pxT - pyT*pyT - pzT*pzT);
871  myParticles.push_back(LHAParticle(
872  idT, statusT, mother1T, mother2T, col1T, col2T,
873  pxT, pyT, pzT, eT, mT, tauT, spinT, -1.));
874 
875  // Update the decay product mothers
876  myParticles[idx ].mother1Part = myParticles.size();
877  myParticles[idx--].mother2Part = 0;
878  myParticles[idx ].mother1Part = myParticles.size();
879  myParticles[idx--].mother2Part = 0;
880 
881  // New final-state b/bbar
882  idT = (flav == 24) ? 5 : -5;
883  statusT = 1;
884  // Colour from top
885  col1T = myParticles[i].col1Part;
886  col2T = myParticles[i].col2Part;
887  // Momentum from (t/tbar - W+/W-)
888  pxT = myParticles[i].pxPart - myParticles.back().pxPart;
889  pyT = myParticles[i].pyPart - myParticles.back().pyPart;
890  pzT = myParticles[i].pzPart - myParticles.back().pzPart;
891  eT = myParticles[i].ePart - myParticles.back().ePart;
892  mT = sqrt(eT*eT - pxT*pxT - pyT*pyT - pzT*pzT);
893  myParticles.push_back(LHAParticle(
894  idT, statusT, mother1T, mother2T, col1T, col2T,
895  pxT, pyT, pzT, eT, mT, tauT, spinT, -1.));
896 
897  // If decay products were out of order, reset idx to point
898  // at correct decay products
899  if (outOfOrder) idx += 4;
900 
901  } // if (abs(myParticles[i].idPart) == 6)
902  } // for (i)
903 
904 
905  // Processes:
906  // 7 = QQbar + Q'Qbar' + jets (tops are not decayed)
907  // 9 = jets
908  // 11 = gamma + jets
909  // 12 = Higgs + jets
910  } else if (lprup == 7 || lprup == 9 || lprup == 11 || lprup == 12) {
911  // Nothing to do for these processes
912  }
913 
914  // For single top, set incoming b mass if necessary
915  if (lprup == 13) for (int i = 0; i < 2; i++)
916  if (abs(myParticles[i].idPart) == 5) {
917  myParticles[i].mPart = mb;
918  myParticles[i].ePart = sqrt(pow2(myParticles[i].pzPart) + pow2(mb));
919  }
920 
921  // Debug output and done.
922  if (LHADEBUG) printParticles();
923  return true;
924 
925 }
926 
927 // ----------------------------------------------------------------------
928 
929 // Routine to rescale momenta to remove any imbalances. The routine
930 // assumes that any imbalances are due to decimal output/rounding
931 // effects, and are therefore small.
932 //
933 // First any px/py imbalances are fixed by adjusting all outgoing
934 // particles px/py and also updating their energy so mass is fixed.
935 // Because incoming pT is zero, changes should be limited to ~0.001.
936 //
937 // Second, any pz/e imbalances are fixed by scaling the incoming beams
938 // (again, no changes to masses required). Because incoming pz/e is not
939 // zero, effects can be slightly larger ~0.002/0.003.
940 
941 inline bool LHAupAlpgen::rescaleMomenta() {
942 
943  // Total momenta in/out
944  int nOut = 0;
945  Vec4 pIn, pOut;
946  for (int i = 0; i < int(myParticles.size()); i++) {
947  Vec4 pNow = Vec4(myParticles[i].pxPart, myParticles[i].pyPart,
948  myParticles[i].pzPart, myParticles[i].ePart);
949  if (i < 2) pIn += pNow;
950  else if (myParticles[i].statusPart == 1) {
951  nOut++;
952  pOut += pNow;
953  }
954  }
955 
956  // pT out to match pT in. Split any imbalances over all outgoing
957  // particles, and scale energies also to keep m^2 fixed.
958  if (abs(pOut.pT() - pIn.pT()) > ZEROTHRESHOLD) {
959  // Differences in px/py
960  double pxDiff = (pOut.px() - pIn.px()) / nOut,
961  pyDiff = (pOut.py() - pIn.py()) / nOut;
962 
963  // Warn if resulting changes above warning threshold
964  if (pxDiff > PTWARNTHRESHOLD || pyDiff > PTWARNTHRESHOLD) {
965  if (infoPtr) infoPtr->errorMsg("Warning in LHAupAlpgen::setEvent: "
966  "large pT imbalance in incoming event");
967 
968  // Debug printout
969  if (LHADEBUGRESCALE) {
970  printParticles();
971  cout << "pxDiff = " << pxDiff << ", pyDiff = " << pyDiff << endl;
972  }
973  }
974 
975  // Adjust all final-state outgoing
976  pOut.reset();
977  for (int i = 2; i < int(myParticles.size()); i++) {
978  if (myParticles[i].statusPart != 1) continue;
979  myParticles[i].pxPart -= pxDiff;
980  myParticles[i].pyPart -= pyDiff;
981  myParticles[i].ePart = sqrt(max(0., pow2(myParticles[i].pxPart) +
982  pow2(myParticles[i].pyPart) + pow2(myParticles[i].pzPart) +
983  pow2(myParticles[i].mPart)));
984  pOut += Vec4(myParticles[i].pxPart, myParticles[i].pyPart,
985  myParticles[i].pzPart, myParticles[i].ePart);
986  }
987  }
988 
989  // Differences in E/pZ and scaling factors
990  double de = (pOut.e() - pIn.e());
991  double dp = (pOut.pz() - pIn.pz());
992  double a = 1 + (de + dp) / 2. / myParticles[0].ePart;
993  double b = 1 + (de - dp) / 2. / myParticles[1].ePart;
994 
995  // Warn if resulting energy changes above warning threshold.
996  // Change in pz less than or equal to change in energy (incoming b
997  // quark can have mass at this stage for process 13). Note that for
998  // very small incoming momenta, the relative adjustment may be large,
999  // but still small in absolute terms.
1000  if (abs(a - 1.) * myParticles[0].ePart > EWARNTHRESHOLD ||
1001  abs(b - 1.) * myParticles[1].ePart > EWARNTHRESHOLD) {
1002  if (infoPtr) infoPtr->errorMsg("Warning in LHAupAlpgen::setEvent: "
1003  "large rescaling factor");
1004 
1005  // Debug printout
1006  if (LHADEBUGRESCALE) {
1007  printParticles();
1008  cout << "de = " << de << ", dp = " << dp
1009  << ", a = " << a << ", b = " << b << endl
1010  << "Absolute energy change for incoming 0 = "
1011  << abs(a - 1.) * myParticles[0].ePart << endl
1012  << "Absolute energy change for incoming 1 = "
1013  << abs(b - 1.) * myParticles[1].ePart << endl;
1014  }
1015  }
1016  myParticles[0].ePart *= a;
1017  myParticles[0].pzPart *= a;
1018  myParticles[1].ePart *= b;
1019  myParticles[1].pzPart *= b;
1020 
1021  // Recalculate resonance four vectors
1022  for (int i = 0; i < int(myParticles.size()); i++) {
1023  if (myParticles[i].statusPart != 2) continue;
1024 
1025  // Only mothers stored in LHA, so go through all
1026  Vec4 resVec;
1027  for (int j = 0; j < int(myParticles.size()); j++) {
1028  if (myParticles[j].mother1Part - 1 != i) continue;
1029  resVec += Vec4(myParticles[j].pxPart, myParticles[j].pyPart,
1030  myParticles[j].pzPart, myParticles[j].ePart);
1031  }
1032 
1033  myParticles[i].pxPart = resVec.px();
1034  myParticles[i].pyPart = resVec.py();
1035  myParticles[i].pzPart = resVec.pz();
1036  myParticles[i].ePart = resVec.e();
1037  }
1038 
1039  return true;
1040 }
1041 
1042 //==========================================================================
1043 
1044 // Main implementation of AlpgenHooks class.
1045 // This may be split out to a separate C++ file if desired,
1046 // but currently included here for ease of use.
1047 
1048 // ----------------------------------------------------------------------
1049 
1050 // Constructor: provides the 'Alpgen:file' option by directly
1051 // changing the Pythia 'Beams' settings
1052 
1053 AlpgenHooks::AlpgenHooks(Pythia &pythia) : LHAagPtr(NULL) {
1054 
1055  // If LHAupAlpgen needed, construct and pass to Pythia
1056  string agFile = pythia.settings.word("Alpgen:file");
1057  if (agFile != "void") {
1058  LHAagPtr = new LHAupAlpgen(agFile.c_str(), &pythia.info);
1059  pythia.settings.mode("Beams:frameType", 5);
1060  pythia.setLHAupPtr(LHAagPtr);
1061  }
1062 }
1063 
1064 // ----------------------------------------------------------------------
1065 
1066 // Initialisation routine which is called by pythia.init().
1067 // This happens after the local pointers have been assigned and after
1068 // Pythia has processed the Beam information (and therefore LHEF header
1069 // information has been read in), but before any other internal
1070 // initialisation. Provides the remaining 'Alpgen:*' options.
1071 
1072 inline bool AlpgenHooks::initAfterBeams() {
1073 
1074  // Read in ALPGEN specific configuration variables
1075  bool setLightMasses = settingsPtr->flag("Alpgen:setLightMasses");
1076  bool setHeavyMasses = settingsPtr->flag("Alpgen:setHeavyMasses");
1077  bool setNjet = settingsPtr->flag("Alpgen:setNjet");
1078  bool setMLM = settingsPtr->flag("Alpgen:setMLM");
1079 
1080  // If ALPGEN parameters are present, then parse in AlpgenPar object
1081  AlpgenPar par(infoPtr);
1082  string parStr = infoPtr->header("AlpgenPar");
1083  if (!parStr.empty()) {
1084  par.parse(parStr);
1085  par.printParams();
1086  }
1087 
1088  // Set masses if requested
1089  if (setLightMasses) {
1090  if (par.haveParam("mc")) particleDataPtr->m0(4, par.getParam("mc"));
1091  if (par.haveParam("mb")) particleDataPtr->m0(5, par.getParam("mb"));
1092  }
1093  if (setHeavyMasses) {
1094  if (par.haveParam("mt")) particleDataPtr->m0(6, par.getParam("mt"));
1095  if (par.haveParam("mz")) particleDataPtr->m0(23, par.getParam("mz"));
1096  if (par.haveParam("mw")) particleDataPtr->m0(24, par.getParam("mw"));
1097  if (par.haveParam("mh")) particleDataPtr->m0(25, par.getParam("mh"));
1098  }
1099 
1100  // Set MLM:nJets if requested
1101  if (setNjet) {
1102  if (par.haveParam("njets"))
1103  settingsPtr->mode("JetMatching:nJet", par.getParamAsInt("njets"));
1104  else
1105  infoPtr->errorMsg("Warning in AlpgenHooks:init: "
1106  "no ALPGEN nJet parameter found");
1107  }
1108 
1109  // Set MLM merging parameters if requested
1110  if (setMLM) {
1111  if (par.haveParam("ptjmin") && par.haveParam("drjmin") &&
1112  par.haveParam("etajmax")) {
1113  double ptjmin = par.getParam("ptjmin");
1114  ptjmin = max(ptjmin + 5., 1.2 * ptjmin);
1115  settingsPtr->parm("JetMatching:eTjetMin", ptjmin);
1116  settingsPtr->parm("JetMatching:coneRadius", par.getParam("drjmin"));
1117  settingsPtr->parm("JetMatching:etaJetMax", par.getParam("etajmax"));
1118 
1119  // Warn if setMLM requested, but parameters not present
1120  } else {
1121  infoPtr->errorMsg("Warning in AlpgenHooks:init: "
1122  "no ALPGEN merging parameters found");
1123  }
1124  }
1125 
1126  // Initialisation complete.
1127  return true;
1128 }
1129 
1130 //==========================================================================
1131 
1132 // Main implementation of MadgraphPar class.
1133 // This may be split out to a separate C++ file if desired,
1134 // but currently included here for ease of use.
1135 
1136 //--------------------------------------------------------------------------
1137 
1138 // Constants: could be changed here if desired, but normally should not.
1139 // These are of technical nature, as described for each.
1140 
1141 // A zero threshold value for double comparisons.
1142 const double MadgraphPar::ZEROTHRESHOLD = 1e-10;
1143 
1144 //--------------------------------------------------------------------------
1145 
1146 // Parse an incoming Madgraph parameter file string
1147 
1148 inline bool MadgraphPar::parse(const string paramStr) {
1149 
1150  // Loop over incoming lines
1151  stringstream paramStream(paramStr);
1152  string line;
1153  while ( getline(paramStream, line) ) extractRunParam(line);
1154  return true;
1155 
1156 }
1157 
1158 //--------------------------------------------------------------------------
1159 
1160 // Parse an incoming parameter line
1161 
1162 inline void MadgraphPar::extractRunParam(string line) {
1163 
1164  // Extract information to the right of the final '!' character
1165  size_t idz = line.find("#");
1166  if ( !(idz == string::npos) ) return;
1167  size_t idx = line.find("=");
1168  size_t idy = line.find("!");
1169  if (idy == string::npos) idy = line.size();
1170  if (idx == string::npos) return;
1171  string paramName = trim( line.substr( idx + 1, idy - idx - 1) );
1172  string paramVal = trim( line.substr( 0, idx) );
1173  replace( paramVal.begin(), paramVal.end(), 'd', 'e');
1174 
1175  // Simple tokeniser
1176  istringstream iss(paramVal);
1177  double val;
1178  if (paramName.find(",") != string::npos) {
1179  string paramNameNow;
1180  istringstream issName( paramName);
1181  while ( getline(issName, paramNameNow, ',') ) {
1182  iss >> val;
1183  warnParamOverwrite( paramNameNow, val);
1184  params[paramNameNow] = val;
1185  }
1186 
1187  // Default case: assume integer and double on the left
1188  } else {
1189  iss >> val;
1190  warnParamOverwrite( paramName, val);
1191  params[paramName] = val;
1192  }
1193 }
1194 
1195 //--------------------------------------------------------------------------
1196 
1197 // Print parameters read from the '.par' file
1198 
1199 inline void MadgraphPar::printParams() {
1200 
1201  // Loop over all stored parameters and print
1202  cout << endl
1203  << " *-------- Madgraph parameters --------*" << endl;
1204  for (map<string,double>::iterator it = params.begin();
1205  it != params.end(); ++it)
1206  cout << " | " << left << setw(15) << it->first
1207  << " | " << right << setw(15) << it->second
1208  << " |" << endl;
1209  cout << " *---------------------------------------*" << endl;
1210 }
1211 
1212 //--------------------------------------------------------------------------
1213 
1214 // Warn if a parameter is going to be overwriten
1215 
1216 inline void MadgraphPar::warnParamOverwrite(const string &paramIn,
1217  double val) {
1218 
1219  // Check if present and if new value is different
1220  if (haveParam(paramIn) &&
1221  abs(getParam(paramIn) - val) > ZEROTHRESHOLD) {
1222  if (infoPtr) infoPtr->errorMsg("Warning in LHAupAlpgen::"
1223  "warnParamOverwrite: overwriting existing parameter", paramIn);
1224  }
1225 }
1226 
1227 //--------------------------------------------------------------------------
1228 
1229 // Simple string trimmer
1230 
1231 inline string MadgraphPar::trim(string s) {
1232 
1233  // Remove whitespace in incoming string
1234  size_t i;
1235  if ( (i = s.find_last_not_of(" \t\r\n")) != string::npos)
1236  s = s.substr(0, i + 1);
1237  if ( (i = s.find_first_not_of(" \t\r\n")) != string::npos)
1238  s = s.substr(i);
1239  return s;
1240 }
1241 
1242 //==========================================================================
1243 
1244 } // end namespace Pythia8
1245 
1246 #endif // Pythia8_GeneratorInput_H