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