CMS 3D CMS Logo

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