Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:06:37

0001 // GeneratorInput.h is a part of the PYTHIA event generator.
0002 // Copyright (C) 2024 Torbjorn Sjostrand.
0003 // PYTHIA is licenced under the GNU GPL v2 or later, see COPYING for details.
0004 // Please respect the MCnet Guidelines, see GUIDELINES for details.
0005 
0006 // Primary Author: Richard Corke
0007 // Secondary Author: Stephen Mrenna
0008 // This file provides the following classes:
0009 //   AlpgenPar:   a class for parsing ALPGEN parameter files
0010 //                and reading back out the values
0011 //   LHAupAlpgen: an LHAup derived class for reading in ALPGEN
0012 //                format event files
0013 //   AlpgenHooks: a UserHooks derived class for providing
0014 //                'Alpgen:*' user options
0015 //   MadgraphPar: a class for parsing MadGraph parameter files
0016 //                and reading back out the values
0017 // Example usage is shown in main32.cc, and further details
0018 // can be found in the 'Jet Matching Style' manual page.
0019 // Minor changes were made by the secondary author for integration
0020 // with Madgraph-style matching, and Madgraph input was added.
0021 
0022 #ifndef Pythia8_GeneratorInput_H
0023 #define Pythia8_GeneratorInput_H
0024 
0025 // Includes and namespace
0026 #include "Pythia8/Pythia.h"
0027 
0028 namespace Pythia8 {
0029 
0030 //==========================================================================
0031 
0032 // AlpgenPar: Class to parse ALPGEN parameter files and make them
0033 //            available through a simple interface
0034 
0035 class AlpgenPar {
0036 
0037 public:
0038 
0039   // Constructor
0040   AlpgenPar() {}
0041 
0042   // Parse as incoming ALPGEN parameter file (passed as string)
0043   bool parse(const string paramStr);
0044 
0045   // Parse an incoming parameter line
0046   void extractRunParam(string line);
0047 
0048   // Check if a parameter exists
0049   bool haveParam(const string &paramIn) {
0050     return (params.find(paramIn) == params.end()) ? false : true; }
0051 
0052   // Get a parameter as a double or integer.
0053   // Caller should have already checked existance of the parameter.
0054   double getParam(const string &paramIn) {
0055     return (haveParam(paramIn)) ? params[paramIn] : 0.; }
0056   int    getParamAsInt(const string &paramIn) {
0057     return (haveParam(paramIn)) ? int(params[paramIn]) : 0.; }
0058 
0059   // Print parameters read from the '.par' file
0060   void printParams();
0061 
0062 private:
0063 
0064   // Warn if a parameter is going to be overwriten
0065   void warnParamOverwrite(const string &paramIn, double val);
0066 
0067   // Simple string trimmer
0068   static string trim(string s);
0069 
0070   // Storage for parameters
0071   map<string,double> params;
0072 
0073   // Constants
0074   static const double ZEROTHRESHOLD;
0075 
0076 };
0077 
0078 //==========================================================================
0079 
0080 // LHAupAlpgen: LHAup derived class for reading in ALPGEN format
0081 //              event files.
0082 
0083 class LHAupAlpgen : public LHAup {
0084 
0085 public:
0086 
0087   // Constructor and destructor.
0088   LHAupAlpgen(const char *baseFNin);
0089   ~LHAupAlpgen() { closeFile(isUnw, ifsUnw); }
0090 
0091   // Override fileFound routine from LHAup.
0092   bool fileFound() { return (isUnw != nullptr); }
0093 
0094   // Override setInit/setEvent routines from LHAup.
0095   bool setInit();
0096   bool setEvent(int);
0097 
0098   // Print list of particles; mainly intended for debugging
0099   void printParticles();
0100 
0101 private:
0102 
0103   // Add resonances to incoming event.
0104   bool addResonances();
0105 
0106   // Rescale momenta to remove any imbalances.
0107   bool rescaleMomenta();
0108 
0109   // Class variables
0110   string    baseFN, parFN, unwFN;  // Incoming filenames
0111   AlpgenPar alpgenPar;             // Parameter database
0112   int      lprup;                  // Process code
0113   double   ebmupA, ebmupB;         // Beam energies
0114   int      ihvy1, ihvy2;           // Heavy flavours for certain processes
0115   double   mb;                     // Bottom mass
0116   ifstream  ifsUnw;                // Input file stream for 'unw' file
0117   istream*  isUnw;                 // Input stream for 'unw' file
0118   vector<LHAParticle> myParticles; // Local storage for particles
0119 
0120   // Constants
0121   static const bool   LHADEBUG, LHADEBUGRESCALE;
0122   static const double ZEROTHRESHOLD, EWARNTHRESHOLD, PTWARNTHRESHOLD,
0123                       INCOMINGMIN;
0124 
0125 };
0126 
0127 //==========================================================================
0128 
0129 // AlpgenHooks: provides Alpgen file reading options.
0130 // Note that it is defined with virtual inheritance, so that it can
0131 // be combined with other UserHooks classes, see e.g. main32.cc.
0132 
0133 class AlpgenHooks : virtual public UserHooks {
0134 
0135 public:
0136 
0137   // Constructor and destructor
0138   AlpgenHooks(Pythia &pythia);
0139   ~AlpgenHooks() {}
0140 
0141   // Override initAfterBeams routine from UserHooks
0142   bool initAfterBeams();
0143 
0144 private:
0145 
0146   // LHAupAlpgen pointer
0147   shared_ptr<LHAupAlpgen> LHAagPtr;
0148 
0149 };
0150 
0151 //==========================================================================
0152 
0153 // MadgraphPar: Class to parse the Madgraph header parameters and
0154 //               make them available through a simple interface
0155 
0156 class MadgraphPar {
0157 
0158 public:
0159 
0160   // Constructor
0161   MadgraphPar() {}
0162 
0163   // Parse an incoming Madgraph parameter file string
0164   bool parse(const string paramStr);
0165 
0166   // Parse an incoming parameter line
0167   void extractRunParam(string line);
0168 
0169   // Check if a parameter exists
0170   bool haveParam(const string &paramIn) {
0171     return (params.find(paramIn) == params.end()) ? false : true; }
0172 
0173   // Get a parameter as a double or integer.
0174   // Caller should have already checked existance of the parameter.
0175   double getParam(const string &paramIn) {
0176     return (haveParam(paramIn)) ? params[paramIn] : 0.; }
0177   int    getParamAsInt(const string &paramIn) {
0178     return (haveParam(paramIn)) ? int(params[paramIn]) : 0.; }
0179 
0180   // Print parameters read from the '.par' file
0181   void printParams();
0182 
0183 private:
0184 
0185   // Warn if a parameter is going to be overwriten
0186   void warnParamOverwrite(const string &paramIn, double val);
0187 
0188   // Simple string trimmer
0189   static string trim(string s);
0190 
0191   // Storage for parameters
0192   map<string,double> params;
0193 
0194   // Constants
0195   static const double ZEROTHRESHOLD;
0196 
0197 };
0198 
0199 //==========================================================================
0200 
0201 // Main implementation of AlpgenPar class.
0202 // This may be split out to a separate C++ file if desired,
0203 // but currently included here for ease of use.
0204 
0205 //--------------------------------------------------------------------------
0206 
0207 // Constants: could be changed here if desired, but normally should not.
0208 // These are of technical nature, as described for each.
0209 
0210 // A zero threshold value for double comparisons.
0211 const double AlpgenPar::ZEROTHRESHOLD = 1e-10;
0212 
0213 //--------------------------------------------------------------------------
0214 
0215 // Warn if e/pT imbalance greater than these values
0216 // Parse an incoming Alpgen parameter file string
0217 
0218 inline bool AlpgenPar::parse(const string paramStr) {
0219 
0220   // Read par file in blocks:
0221   //   0 - process information
0222   //   1 - run parameters
0223   //   2 - cross sections
0224   int block = 0;
0225 
0226   // Loop over incoming lines
0227   stringstream paramStream(paramStr);
0228   string line;
0229   while (getline(paramStream, line)) {
0230 
0231     // Change to 'run parameters' block
0232     if        (line.find("run parameters") != string::npos) {
0233       block = 1;
0234 
0235     // End of 'run parameters' block
0236     } else if (line.find("end parameters") != string::npos) {
0237       block = 2;
0238 
0239     // Do not extract anything from block 0 so far
0240     } else if (block == 0) {
0241 
0242     // Block 1 or 2: extract parameters
0243     } else {
0244       extractRunParam(line);
0245 
0246     }
0247   } // while (getline(paramStream, line))
0248 
0249   return true;
0250 }
0251 
0252 //--------------------------------------------------------------------------
0253 
0254 // Parse an incoming parameter line
0255 
0256 inline void AlpgenPar::extractRunParam(string line) {
0257 
0258   // Extract information to the right of the final '!' character
0259   size_t idx = line.rfind("!");
0260   if (idx == string::npos) return;
0261   string paramName = trim(line.substr(idx + 1));
0262   string paramVal  = trim(line.substr(0, idx));
0263   istringstream iss(paramVal);
0264 
0265   // Special case: 'hard process code' - single integer input
0266   double val;
0267   if (paramName == "hard process code") {
0268     iss >> val;
0269     warnParamOverwrite("hpc", val);
0270     params["hpc"] = val;
0271 
0272   // Special case: 'Crosssection +- error (pb)' - two double values
0273   } else if (paramName.find("Crosssection") == 0) {
0274     double xerrup;
0275     iss >> val >> xerrup;
0276     warnParamOverwrite("xsecup", val);
0277     warnParamOverwrite("xerrup", val);
0278     params["xsecup"] = val;
0279     params["xerrup"] = xerrup;
0280 
0281   // Special case: 'unwtd events, lum (pb-1)' - integer and double values
0282   } else if (paramName.find("unwtd events") == 0) {
0283     int nevent;
0284     iss >> nevent >> val;
0285     warnParamOverwrite("nevent", val);
0286     warnParamOverwrite("lum", val);
0287     params["nevent"] = nevent;
0288     params["lum"]    = val;
0289 
0290   // Special case: 'mc,mb,...' - split on ',' for name and ' ' for values
0291   } else if (paramName.find(",") != string::npos) {
0292 
0293     // Simple tokeniser
0294     string        paramNameNow;
0295     istringstream issName(paramName);
0296     while (getline(issName, paramNameNow, ',')) {
0297       iss >> val;
0298       warnParamOverwrite(paramNameNow, val);
0299       params[paramNameNow] = val;
0300     }
0301 
0302   // Default case: assume integer and double on the left
0303   } else {
0304     int paramIdx;
0305     iss >> paramIdx >> val;
0306     warnParamOverwrite(paramName, val);
0307     params[paramName] = val;
0308   }
0309 }
0310 
0311 //--------------------------------------------------------------------------
0312 
0313 // Print parameters read from the '.par' file
0314 
0315 inline void AlpgenPar::printParams() {
0316 
0317   // Loop over all stored parameters and print
0318   cout << fixed << setprecision(3) << endl
0319        << " *-------  Alpgen parameters  -------*" << endl;
0320   for (map < string, double >::iterator it = params.begin();
0321        it != params.end(); ++it)
0322     cout << " |  " << left << setw(13) << it->first
0323          << "  |  " << right << setw(13) << it->second
0324          << "  |" << endl;
0325   cout << " *-----------------------------------*" << endl;
0326 }
0327 
0328 //--------------------------------------------------------------------------
0329 
0330 // Warn if a parameter is going to be overwriten
0331 
0332 inline void AlpgenPar::warnParamOverwrite(const string &paramIn, double val) {
0333 
0334   // Check if present and if new value is different
0335   if (haveParam(paramIn) &&
0336       abs(getParam(paramIn) - val) > ZEROTHRESHOLD) {
0337     cout << "Warning in LHAupAlpgen::warnParamOverwrite:"
0338          << " overwriting existing parameter" << paramIn << endl;
0339   }
0340 }
0341 
0342 //--------------------------------------------------------------------------
0343 
0344 // Simple string trimmer
0345 
0346 inline string AlpgenPar::trim(string s) {
0347 
0348   // Remove whitespace in incoming string
0349   size_t i;
0350   if ((i = s.find_last_not_of(" \t\r\n")) != string::npos)
0351     s = s.substr(0, i + 1);
0352   if ((i = s.find_first_not_of(" \t\r\n")) != string::npos)
0353     s = s.substr(i);
0354   return s;
0355 }
0356 
0357 //==========================================================================
0358 
0359 // Main implementation of LHAupAlpgen class.
0360 // This may be split out to a separate C++ file if desired,
0361 // but currently included here for ease of use.
0362 
0363 // ----------------------------------------------------------------------
0364 
0365 // Constants: could be changed here if desired, but normally should not.
0366 // These are of technical nature, as described for each.
0367 
0368 // Debug flag to print all particles in each event.
0369 const bool LHAupAlpgen::LHADEBUG        = false;
0370 
0371 // Debug flag to print particles when an e/p imbalance is found.
0372 const bool LHAupAlpgen::LHADEBUGRESCALE = false;
0373 
0374 // A zero threshold value for double comparisons.
0375 const double LHAupAlpgen::ZEROTHRESHOLD   = 1e-10;
0376 
0377 // Warn if e/pT imbalance greater than these values
0378 const double LHAupAlpgen::EWARNTHRESHOLD  = 3e-3;
0379 const double LHAupAlpgen::PTWARNTHRESHOLD = 1e-3;
0380 
0381 // If incoming e/pZ is 0, it is reset to this value
0382 const double LHAupAlpgen::INCOMINGMIN     = 1e-3;
0383 
0384 // ----------------------------------------------------------------------
0385 
0386 // Constructor. Opens event file.
0387 
0388 LHAupAlpgen::LHAupAlpgen(const char* baseFNin)
0389   : baseFN(baseFNin), alpgenPar(), isUnw(nullptr) {
0390 
0391   // Open '.unw' events file (with possible gzip support)
0392 #ifdef GZIP
0393   unwFN = baseFN + ".unw.gz";
0394   isUnw = openFile(unwFN.c_str(), ifsUnw);
0395   if (!ifsUnw.is_open()) closeFile(isUnw, ifsUnw);
0396 #endif
0397   if (isUnw == nullptr) {
0398     unwFN = baseFN + ".unw";
0399     isUnw = openFile(unwFN.c_str(), ifsUnw);
0400     if (!ifsUnw.is_open()) {
0401       cout << "Error in LHAupAlpgen::LHAupAlpgen: "
0402            << "cannot open event file " << unwFN << endl;
0403       closeFile(isUnw, ifsUnw);
0404     }
0405   }
0406 }
0407 
0408 // ----------------------------------------------------------------------
0409 
0410 // setInit is a virtual method that must be finalised here.
0411 // Opens parameter file and parses it, sets up beams, strategy and processes.
0412 
0413 inline bool LHAupAlpgen::setInit() {
0414 
0415   // Read in '_unw.par' file to get parameters
0416   ifstream  ifsPar;
0417   istream*  isPar = nullptr;
0418 
0419   // Try gzip file first then normal file afterwards
0420 #ifdef GZIP
0421   parFN = baseFN + "_unw.par.gz";
0422   isPar = openFile(parFN.c_str(), ifsPar);
0423   if (!ifsPar.is_open()) closeFile(isPar, ifsPar);
0424 #endif
0425   if (isPar == nullptr) {
0426     parFN = baseFN + "_unw.par";
0427     isPar = openFile(parFN.c_str(), ifsPar);
0428     if (!ifsPar.is_open()) {
0429       cout << "Error in LHAupAlpgen::LHAupAlpgen: "
0430            << "cannot open parameter file " << parFN << endl;
0431       closeFile(isPar, ifsPar);
0432       return false;
0433     }
0434   }
0435 
0436   // Read entire contents into string and close file
0437   string paramStr((std::istreambuf_iterator<char>(isPar->rdbuf())),
0438                    std::istreambuf_iterator<char>());
0439 
0440   // Make sure we reached EOF and not other error
0441   if (ifsPar.bad()) {
0442     cout << "Error in LHAupAlpgen::LHAupAlpgen: "
0443          << "cannot read parameter file " << parFN << endl;
0444     return false;
0445   }
0446   closeFile(isPar, ifsPar);
0447 
0448   // Parse file and set LHEF header
0449   alpgenPar.parse(paramStr);
0450   setInfoHeader("AlpgenPar", paramStr);
0451 
0452   // Check that all required parameters are present
0453   if (!alpgenPar.haveParam("ih2") || !alpgenPar.haveParam("ebeam")  ||
0454       !alpgenPar.haveParam("hpc") || !alpgenPar.haveParam("xsecup") ||
0455       !alpgenPar.haveParam("xerrup")) {
0456     cout << "Error in LHAupAlpgen::setInit: "
0457          << "missing input parameters" << endl;
0458     return false;
0459   }
0460 
0461   // Beam IDs
0462   int ih2 = alpgenPar.getParamAsInt("ih2");
0463   int idbmupA = 2212;
0464   int idbmupB = (ih2 == 1) ? 2212 : -2212;
0465 
0466   // Beam energies
0467   double ebeam = alpgenPar.getParam("ebeam");
0468   ebmupA = ebeam;
0469   ebmupB = ebmupA;
0470 
0471   // PDF group and set (at the moment not set)
0472   int pdfgupA = 0, pdfsupA = 0;
0473   int pdfgupB = 0, pdfsupB = 0;
0474 
0475   // Strategy is for unweighted events and xmaxup not important
0476   int    idwtup = 3;
0477   double xmaxup = 0.;
0478 
0479   // Get hard process code
0480   lprup = alpgenPar.getParamAsInt("hpc");
0481 
0482   // Check for unsupported processes
0483   if (lprup == 7 || lprup == 8 || lprup == 13) {
0484     cout << "Error in LHAupAlpgen::setInit: "
0485          << "process not implemented" << endl;
0486     return false;
0487   }
0488 
0489   // Depending on the process code, get heavy flavour information:
0490   //    6 = QQbar           + jets
0491   //    7 = QQbar + Q'Qbar' + jets
0492   //    8 = QQbar + Higgs   + jets
0493   //   16 = QQbar + gamma   + jets
0494   if (lprup == 6 || lprup == 7 || lprup == 8 || lprup == 16) {
0495     if (!alpgenPar.haveParam("ihvy")) {
0496       cout << "Error in LHAupAlpgen::setInit: "
0497            << "heavy flavour information not present" << endl;
0498       return false;
0499     }
0500     ihvy1 = alpgenPar.getParamAsInt("ihvy");
0501 
0502   } else ihvy1 = -1;
0503   if (lprup == 7) {
0504     if (!alpgenPar.haveParam("ihvy2")) {
0505       cout << "Error in LHAupAlpgen::setInit: "
0506            << "heavy flavour information not present" << endl;
0507       return false;
0508     }
0509     ihvy2 = alpgenPar.getParamAsInt("ihvy2");
0510   } else ihvy2 = -1;
0511   // For single top (process 13), get b mass to set incoming
0512   mb = -1.;
0513   if (lprup == 13) {
0514     if (!alpgenPar.haveParam("mb")) {
0515       cout << "Error in LHAupAlpgen::setInit: "
0516            << "heavy flavour information not present" << endl;
0517       return false;
0518     }
0519     mb = alpgenPar.getParam("mb");
0520   }
0521 
0522   // Set the beams
0523   setBeamA(idbmupA, ebmupA, pdfgupA, pdfsupA);
0524   setBeamB(idbmupB, ebmupB, pdfgupB, pdfsupB);
0525   setStrategy(idwtup);
0526 
0527   // Add the process
0528   double xsecup = alpgenPar.getParam("xsecup");
0529   double xerrup = alpgenPar.getParam("xerrup");
0530   addProcess(lprup, xsecup, xerrup, xmaxup);
0531   xSecSumSave = xsecup;
0532   xErrSumSave = xerrup;
0533 
0534   // All okay
0535   return true;
0536 }
0537 
0538 // ----------------------------------------------------------------------
0539 
0540 // setEvent is a virtual method that must be finalised here.
0541 // Read in an event from the 'unw' file and setup.
0542 
0543 inline bool LHAupAlpgen::setEvent(int) {
0544 
0545   // Read in the first line of the event
0546   int    nEvent, iProc, nParton;
0547   double Swgt, Sq;
0548   string line;
0549   if (!getline(*isUnw, line)) {
0550     // Read was bad
0551     if (ifsUnw.bad()) {
0552       cout << "Error in LHAupAlpgen::setEvent: "
0553            << "could not read events from file" << endl;
0554       return false;
0555     }
0556     // End of file reached
0557     cout << "Error in LHAupAlpgen::setEvent: "
0558          << "end of file reached" << endl;
0559     return false;
0560   }
0561   istringstream iss1(line);
0562   iss1 >> nEvent >> iProc >> nParton >> Swgt >> Sq;
0563 
0564   // Set the process details (ignore alphaQED and alphaQCD parameters)
0565   double wgtT = Swgt, scaleT = Sq;
0566   setProcess(lprup, wgtT, scaleT);
0567 
0568   // Incoming flavour and x information for later
0569   int    id1T, id2T;
0570   double x1T, x2T;
0571   // Temporary storage for read in parton information
0572   int    idT, statusT, mother1T, mother2T, col1T, col2T;
0573   double pxT, pyT, pzT, eT, mT;
0574   // Leave tau and spin as default values
0575   double tauT = 0., spinT = 9.;
0576 
0577   // Store particles locally at first so that resonances can be added
0578   myParticles.clear();
0579 
0580   // Now read in partons
0581   for (int i = 0; i < nParton; i++) {
0582     // Get the next line
0583     if (!getline(*isUnw, line)) {
0584       cout << "Error in LHAupAlpgen::setEvent: "
0585            << "could not read events from file" << endl;
0586       return false;
0587     }
0588     istringstream iss2(line);
0589 
0590     // Incoming (flavour, colour, anticolour, pz)
0591     if (i < 2) {
0592       // Note that mothers will be set automatically by Pythia, and LHA
0593       // status -1 is for an incoming parton
0594       iss2 >> idT >> col1T >> col2T >> pzT;
0595       statusT  = -1;
0596       mother1T = mother2T = 0;
0597       pxT = pyT = mT = 0.;
0598       eT  = abs(pzT);
0599 
0600       // Adjust when zero pz/e
0601       if (pzT == 0.) {
0602         pzT = (i == 0) ? INCOMINGMIN : -INCOMINGMIN;
0603         eT  = INCOMINGMIN;
0604       }
0605 
0606     // Outgoing (flavour, colour, anticolour, px, py, pz, mass)
0607     } else {
0608       // Note that mothers 1 and 2 corresport to the incoming partons,
0609       // as set above, and LHA status +1 is for outgoing final state
0610       iss2 >> idT >> col1T >> col2T >> pxT >> pyT >> pzT >> mT;
0611       statusT  = 1;
0612       mother1T = 1;
0613       mother2T = 2;
0614       eT = sqrt(max(0., pxT*pxT + pyT*pyT + pzT*pzT + mT*mT));
0615     }
0616 
0617     // Add particle
0618     myParticles.push_back(LHAParticle(
0619         idT, statusT, mother1T, mother2T, col1T, col2T,
0620         pxT, pyT, pzT, eT, mT, tauT, spinT,-1.));
0621   }
0622 
0623   // Add resonances if required
0624   if (!addResonances()) return false;
0625 
0626   // Rescale momenta if required (must be done after full event
0627   // reconstruction in addResonances)
0628   if (!rescaleMomenta()) return false;
0629 
0630   // Pass particles on to Pythia
0631   for (size_t i = 0; i < myParticles.size(); i++)
0632     addParticle(myParticles[i]);
0633 
0634   // Set incoming flavour/x information and done
0635   id1T = myParticles[0].idPart;
0636   x1T  = myParticles[0].ePart / ebmupA;
0637   id2T = myParticles[1].idPart;
0638   x2T  = myParticles[1].ePart / ebmupA;
0639   setIdX(id1T, id2T, x1T, x2T);
0640   setPdf(id1T, id2T, x1T, x2T, 0., 0., 0., false);
0641   return true;
0642 }
0643 
0644 // ----------------------------------------------------------------------
0645 
0646 // Print list of particles; mainly intended for debugging
0647 
0648 inline void LHAupAlpgen::printParticles() {
0649 
0650   cout << endl << "---- LHAupAlpgen particle listing begin ----" << endl;
0651   cout << scientific << setprecision(6);
0652   for (int i = 0; i < int(myParticles.size()); i++) {
0653     cout << setw(5)  << i
0654          << setw(5)  << myParticles[i].idPart
0655          << setw(5)  << myParticles[i].statusPart
0656          << setw(15) << myParticles[i].pxPart
0657          << setw(15) << myParticles[i].pyPart
0658          << setw(15) << myParticles[i].pzPart
0659          << setw(15) << myParticles[i].ePart
0660          << setw(15) << myParticles[i].mPart
0661          << setw(5)  << myParticles[i].mother1Part - 1
0662          << setw(5)  << myParticles[i].mother2Part - 1
0663          << setw(5)  << myParticles[i].col1Part
0664          << setw(5)  << myParticles[i].col2Part
0665          << endl;
0666   }
0667   cout << "----  LHAupAlpgen particle listing end  ----" << endl;
0668 }
0669 
0670 // ----------------------------------------------------------------------
0671 
0672 // Routine to add resonances to an incoming event based on the
0673 // hard process code (now stored in lprup).
0674 
0675 inline bool LHAupAlpgen::addResonances() {
0676 
0677   // Temporary storage for resonance information
0678   int    idT, statusT, mother1T, mother2T, col1T, col2T;
0679   double pxT, pyT, pzT, eT, mT;
0680   // Leave tau and spin as default values
0681   double tauT = 0., spinT = 9.;
0682 
0683   // Alpgen process dependent parts. Processes:
0684   //    1 = W        + QQbar         + jets
0685   //    2 = Z/gamma* + QQbar         + jets
0686   //    3 = W                        + jets
0687   //    4 = Z/gamma*                 + jets
0688   //   10 = W        + c             + jets
0689   //   14 = W        + gamma         + jets
0690   //   15 = W        + QQbar + gamma + jets
0691   // When QQbar = ttbar, tops are not decayed in these processes.
0692   // Explicitly reconstruct W/Z resonances; assumption is that the
0693   // decay products are the last two particles.
0694   if (lprup <= 4 || lprup == 10 || lprup == 14 || lprup == 15) {
0695     // Decay products are the last two entries
0696     int i1 = myParticles.size() - 1, i2 = i1 - 1;
0697 
0698     // Follow 'alplib/alpsho.f' procedure to get ID
0699     if (myParticles[i1].idPart + myParticles[i2].idPart == 0)
0700       idT = 0;
0701     else
0702       idT = - (myParticles[i1].idPart % 2) - (myParticles[i2].idPart % 2);
0703     idT = (idT > 0) ? 24 : (idT < 0) ? -24 : 23;
0704 
0705     // Check that we get the expected resonance type; Z/gamma*
0706     if (lprup == 2 || lprup == 4) {
0707       if (idT != 23) {
0708         cout << "Error in "
0709              << "LHAupAlpgen::addResonances: wrong resonance type in event"
0710              << endl;
0711         return false;
0712       }
0713 
0714     // W's
0715     } else {
0716       if (abs(idT) != 24) {
0717         cout << "Error in "
0718              << "LHAupAlpgen::addResonances: wrong resonance type in event"
0719              << endl;
0720         return false;
0721       }
0722     }
0723 
0724     // Remaining input
0725     statusT  = 2;
0726     mother1T = 1;
0727     mother2T = 2;
0728     col1T = col2T = 0;
0729     pxT = myParticles[i1].pxPart + myParticles[i2].pxPart;
0730     pyT = myParticles[i1].pyPart + myParticles[i2].pyPart;
0731     pzT = myParticles[i1].pzPart + myParticles[i2].pzPart;
0732     eT  = myParticles[i1].ePart  + myParticles[i2].ePart;
0733     mT  = sqrt(eT*eT - pxT*pxT - pyT*pyT - pzT*pzT);
0734     myParticles.push_back(LHAParticle(
0735         idT, statusT, mother1T, mother2T, col1T, col2T,
0736         pxT, pyT, pzT, eT, mT, tauT, spinT, -1.));
0737 
0738     // Update decay product mothers (note array size as if from 1)
0739     myParticles[i1].mother1Part = myParticles[i2].mother1Part =
0740         myParticles.size();
0741     myParticles[i1].mother2Part = myParticles[i2].mother2Part = 0;
0742 
0743   // Processes:
0744   //    5 = nW + mZ + j gamma + lH + jets
0745   //    6 = QQbar         + jets    (QQbar = ttbar)
0746   //    8 = QQbar + Higgs + jets    (QQbar = ttbar)
0747   //   13 = top   + q               (topprc = 1)
0748   //   13 = top   + b               (topprc = 2)
0749   //   13 = top   + W     + jets    (topprc = 3)
0750   //   13 = top   + W     + b       (topprc = 4)
0751   //   16 = QQbar + gamma + jets    (QQbar = ttbar)
0752   //
0753   // When tops are present, they are decayed to Wb (both the W and b
0754   // are not given), with this W also decaying (decay products given).
0755   // The top is marked intermediate, the (intermediate) W is
0756   // reconstructed from its decay products, and the decay product mothers
0757   // updated. The final-state b is reconstructed from (top - W).
0758   //
0759   // W/Z resonances are given, as well as their decay products. The
0760   // W/Z is marked intermediate, and the decay product mothers updated.
0761   //
0762   // It is always assumed that decay products are at the end.
0763   // For processes 5 and 13, it is also assumed that the decay products
0764   // are in the same order as the resonances.
0765   // For processes 6, 8 and 16, the possibility of the decay products
0766   // being out-of-order is also taken into account.
0767   } else if ( ((lprup == 6 || lprup == 8 || lprup == 16) && ihvy1 == 6) ||
0768               lprup == 5 || lprup == 13) {
0769 
0770     // Go backwards through the particles looking for W/Z/top
0771     int idx = myParticles.size() - 1;
0772     for (int i = myParticles.size() - 1; i > -1; i--) {
0773 
0774       // W or Z
0775       if (myParticles[i].idPart == 23 ||
0776           abs(myParticles[i].idPart) == 24) {
0777 
0778         // Check that decay products and resonance match up
0779         int flav;
0780         if (myParticles[idx].idPart + myParticles[idx - 1].idPart == 0)
0781           flav = 0;
0782         else
0783           flav = - (myParticles[idx].idPart % 2)
0784                  - (myParticles[idx - 1].idPart % 2);
0785         flav = (flav > 0) ? 24 : (flav < 0) ? -24 : 23;
0786         if (flav != myParticles[i].idPart) {
0787           if (infoPtr)
0788             loggerPtr->ERROR_MSG("resonance does not match decay products");
0789           return false;
0790         }
0791 
0792         // Update status/mothers
0793         myParticles[i].statusPart      = 2;
0794         myParticles[idx  ].mother1Part = i + 1;
0795         myParticles[idx--].mother2Part = 0;
0796         myParticles[idx  ].mother1Part = i + 1;
0797         myParticles[idx--].mother2Part = 0;
0798 
0799       // Top
0800       } else if (abs(myParticles[i].idPart) == 6) {
0801 
0802         // Check that decay products and resonance match up
0803         int flav;
0804         if (myParticles[idx].idPart + myParticles[idx - 1].idPart == 0)
0805           flav = 0;
0806         else
0807           flav = - (myParticles[idx].idPart % 2)
0808                  - (myParticles[idx - 1].idPart % 2);
0809         flav = (flav > 0) ? 24 : (flav < 0) ? -24 : 23;
0810 
0811         bool outOfOrder = false, wrongFlavour = false;;
0812         if ( abs(flav) != 24 ||
0813              (flav ==  24 && myParticles[i].idPart !=  6) ||
0814              (flav == -24 && myParticles[i].idPart != -6) ) {
0815 
0816           // Processes 5 and 13, order should always be correct
0817           if (lprup == 5 || lprup == 13) {
0818             wrongFlavour = true;
0819 
0820           // Processes 6, 8 and 16, can have out of order decay products
0821           } else {
0822 
0823             // Go back two decay products and retry
0824             idx -= 2;
0825             if (myParticles[idx].idPart + myParticles[idx - 1].idPart == 0)
0826               flav = 0;
0827             else
0828               flav = - (myParticles[idx].idPart % 2)
0829                      - (myParticles[idx - 1].idPart % 2);
0830             flav = (flav > 0) ? 24 : (flav < 0) ? -24 : 23;
0831 
0832             // If still the wrong flavour then error
0833             if ( abs(flav) != 24 ||
0834                  (flav ==  24 && myParticles[i].idPart !=  6) ||
0835                  (flav == -24 && myParticles[i].idPart != -6) )
0836               wrongFlavour = true;
0837             else outOfOrder = true;
0838           }
0839 
0840           // Error if wrong flavour
0841           if (wrongFlavour) {
0842             if (infoPtr)
0843               loggerPtr->ERROR_MSG("resonance does not match decay products");
0844             return false;
0845           }
0846         }
0847 
0848         // Mark t/tbar as now intermediate
0849         myParticles[i].statusPart = 2;
0850 
0851         // New intermediate W+/W-
0852         idT      = flav;
0853         statusT  = 2;
0854         mother1T = i + 1;
0855         mother2T = 0;
0856         col1T = col2T = 0;
0857         pxT = myParticles[idx].pxPart + myParticles[idx - 1].pxPart;
0858         pyT = myParticles[idx].pyPart + myParticles[idx - 1].pyPart;
0859         pzT = myParticles[idx].pzPart + myParticles[idx - 1].pzPart;
0860         eT  = myParticles[idx].ePart  + myParticles[idx - 1].ePart;
0861         mT  = sqrt(eT*eT - pxT*pxT - pyT*pyT - pzT*pzT);
0862         myParticles.push_back(LHAParticle(
0863             idT, statusT, mother1T, mother2T, col1T, col2T,
0864             pxT, pyT, pzT, eT, mT, tauT, spinT, -1.));
0865 
0866         // Update the decay product mothers
0867         myParticles[idx  ].mother1Part = myParticles.size();
0868         myParticles[idx--].mother2Part = 0;
0869         myParticles[idx  ].mother1Part = myParticles.size();
0870         myParticles[idx--].mother2Part = 0;
0871 
0872         // New final-state b/bbar
0873         idT     = (flav == 24) ? 5 : -5;
0874         statusT = 1;
0875         // Colour from top
0876         col1T   = myParticles[i].col1Part;
0877         col2T   = myParticles[i].col2Part;
0878         // Momentum from (t/tbar - W+/W-)
0879         pxT     = myParticles[i].pxPart - myParticles.back().pxPart;
0880         pyT     = myParticles[i].pyPart - myParticles.back().pyPart;
0881         pzT     = myParticles[i].pzPart - myParticles.back().pzPart;
0882         eT      = myParticles[i].ePart  - myParticles.back().ePart;
0883         mT      = sqrt(eT*eT - pxT*pxT - pyT*pyT - pzT*pzT);
0884         myParticles.push_back(LHAParticle(
0885             idT, statusT, mother1T, mother2T, col1T, col2T,
0886             pxT, pyT, pzT, eT, mT, tauT, spinT, -1.));
0887 
0888         // If decay products were out of order, reset idx to point
0889         // at correct decay products
0890         if (outOfOrder) idx += 4;
0891 
0892       } // if (abs(myParticles[i].idPart) == 6)
0893     } // for (i)
0894 
0895 
0896   // Processes:
0897   //    7 = QQbar + Q'Qbar' + jets (tops are not decayed)
0898   //    9 =                   jets
0899   //   11 = gamma           + jets
0900   //   12 = Higgs           + jets
0901   } else if (lprup == 7 || lprup == 9 || lprup == 11 || lprup == 12) {
0902     // Nothing to do for these processes
0903   }
0904 
0905   // For single top, set incoming b mass if necessary
0906   if (lprup == 13) for (int i = 0; i < 2; i++)
0907     if (abs(myParticles[i].idPart) == 5) {
0908       myParticles[i].mPart = mb;
0909       myParticles[i].ePart = sqrt(pow2(myParticles[i].pzPart) + pow2(mb));
0910     }
0911 
0912   // Debug output and done.
0913   if (LHADEBUG) printParticles();
0914   return true;
0915 
0916 }
0917 
0918 // ----------------------------------------------------------------------
0919 
0920 // Routine to rescale momenta to remove any imbalances. The routine
0921 // assumes that any imbalances are due to decimal output/rounding
0922 // effects, and are therefore small.
0923 //
0924 // First any px/py imbalances are fixed by adjusting all outgoing
0925 // particles px/py and also updating their energy so mass is fixed.
0926 // Because incoming pT is zero, changes should be limited to ~0.001.
0927 //
0928 // Second, any pz/e imbalances are fixed by scaling the incoming beams
0929 // (again, no changes to masses required). Because incoming pz/e is not
0930 // zero, effects can be slightly larger ~0.002/0.003.
0931 
0932 inline bool LHAupAlpgen::rescaleMomenta() {
0933 
0934   // Total momenta in/out
0935   int  nOut = 0;
0936   Vec4 pIn, pOut;
0937   for (int i = 0; i < int(myParticles.size()); i++) {
0938     Vec4 pNow = Vec4(myParticles[i].pxPart, myParticles[i].pyPart,
0939                      myParticles[i].pzPart, myParticles[i].ePart);
0940     if (i < 2) pIn += pNow;
0941     else if (myParticles[i].statusPart == 1) {
0942       nOut++;
0943       pOut += pNow;
0944     }
0945   }
0946 
0947   // pT out to match pT in. Split any imbalances over all outgoing
0948   // particles, and scale energies also to keep m^2 fixed.
0949   if (abs(pOut.pT() - pIn.pT()) > ZEROTHRESHOLD) {
0950     // Differences in px/py
0951     double pxDiff = (pOut.px() - pIn.px()) / nOut,
0952            pyDiff = (pOut.py() - pIn.py()) / nOut;
0953 
0954     // Warn if resulting changes above warning threshold
0955     if (pxDiff > PTWARNTHRESHOLD || pyDiff > PTWARNTHRESHOLD) {
0956       cout << "Warning in LHAupAlpgen::setEvent: "
0957            << "large pT imbalance in incoming event" << endl;
0958 
0959       // Debug printout
0960       if (LHADEBUGRESCALE) {
0961         printParticles();
0962         cout << "pxDiff = " << pxDiff << ", pyDiff = " << pyDiff << endl;
0963       }
0964     }
0965 
0966     // Adjust all final-state outgoing
0967     pOut.reset();
0968     for (int i = 2; i < int(myParticles.size()); i++) {
0969       if (myParticles[i].statusPart != 1) continue;
0970       myParticles[i].pxPart -= pxDiff;
0971       myParticles[i].pyPart -= pyDiff;
0972       myParticles[i].ePart   = sqrt(max(0., pow2(myParticles[i].pxPart) +
0973           pow2(myParticles[i].pyPart) + pow2(myParticles[i].pzPart) +
0974           pow2(myParticles[i].mPart)));
0975       pOut += Vec4(myParticles[i].pxPart, myParticles[i].pyPart,
0976                    myParticles[i].pzPart, myParticles[i].ePart);
0977     }
0978   }
0979 
0980   // Differences in E/pZ and scaling factors
0981   double de = (pOut.e()  - pIn.e());
0982   double dp = (pOut.pz() - pIn.pz());
0983   double a  = 1 + (de + dp) / 2. / myParticles[0].ePart;
0984   double b  = 1 + (de - dp) / 2. / myParticles[1].ePart;
0985 
0986   // Warn if resulting energy changes above warning threshold.
0987   // Change in pz less than or equal to change in energy (incoming b
0988   // quark can have mass at this stage for process 13). Note that for
0989   // very small incoming momenta, the relative adjustment may be large,
0990   // but still small in absolute terms.
0991   if (abs(a - 1.) * myParticles[0].ePart > EWARNTHRESHOLD ||
0992       abs(b - 1.) * myParticles[1].ePart > EWARNTHRESHOLD) {
0993     cout << "Warning in LHAupAlpgen::setEvent: "
0994          << "large rescaling factor" << endl;
0995 
0996     // Debug printout
0997     if (LHADEBUGRESCALE) {
0998       printParticles();
0999       cout << "de = " << de << ", dp = " << dp
1000            << ", a = " << a << ", b = " << b << endl
1001            << "Absolute energy change for incoming 0 = "
1002            << abs(a - 1.) * myParticles[0].ePart << endl
1003            << "Absolute energy change for incoming 1 = "
1004            << abs(b - 1.) * myParticles[1].ePart << endl;
1005     }
1006   }
1007   myParticles[0].ePart  *= a;
1008   myParticles[0].pzPart *= a;
1009   myParticles[1].ePart  *= b;
1010   myParticles[1].pzPart *= b;
1011 
1012   // Recalculate resonance four vectors
1013   for (int i = 0; i < int(myParticles.size()); i++) {
1014     if (myParticles[i].statusPart != 2) continue;
1015 
1016     // Only mothers stored in LHA, so go through all
1017     Vec4 resVec;
1018     for (int j = 0; j < int(myParticles.size()); j++) {
1019       if (myParticles[j].mother1Part - 1 != i) continue;
1020       resVec += Vec4(myParticles[j].pxPart, myParticles[j].pyPart,
1021                      myParticles[j].pzPart, myParticles[j].ePart);
1022     }
1023 
1024     myParticles[i].pxPart = resVec.px();
1025     myParticles[i].pyPart = resVec.py();
1026     myParticles[i].pzPart = resVec.pz();
1027     myParticles[i].ePart  = resVec.e();
1028   }
1029 
1030   return true;
1031 }
1032 
1033 //==========================================================================
1034 
1035 // Main implementation of AlpgenHooks class.
1036 // This may be split out to a separate C++ file if desired,
1037 // but currently included here for ease of use.
1038 
1039 // ----------------------------------------------------------------------
1040 
1041 // Constructor: provides the 'Alpgen:file' option by directly
1042 //              changing the Pythia 'Beams' settings
1043 
1044 AlpgenHooks::AlpgenHooks(Pythia &pythia) {
1045 
1046   // If LHAupAlpgen needed, construct and pass to Pythia
1047   string agFile = pythia.settings.word("Alpgen:file");
1048   if (agFile != "void") {
1049     LHAagPtr = make_shared<LHAupAlpgen>(agFile.c_str());
1050     pythia.settings.mode("Beams:frameType", 5);
1051     pythia.setLHAupPtr(LHAagPtr);
1052   }
1053 }
1054 
1055 // ----------------------------------------------------------------------
1056 
1057 // Initialisation routine which is called by pythia.init().
1058 // This happens after the local pointers have been assigned and after
1059 // Pythia has processed the Beam information (and therefore LHEF header
1060 // information has been read in), but before any other internal
1061 // initialisation. Provides the remaining 'Alpgen:*' options.
1062 
1063 inline bool AlpgenHooks::initAfterBeams() {
1064 
1065   // Read in ALPGEN specific configuration variables
1066   bool setLightMasses = settingsPtr->flag("Alpgen:setLightMasses");
1067   bool setHeavyMasses = settingsPtr->flag("Alpgen:setHeavyMasses");
1068   bool setNjet   = settingsPtr->flag("Alpgen:setNjet");
1069   bool setMLM    = settingsPtr->flag("Alpgen:setMLM");
1070 
1071   // If ALPGEN parameters are present, then parse in AlpgenPar object
1072   AlpgenPar par;
1073   string parStr = infoPtr->header("AlpgenPar");
1074   if (!parStr.empty()) {
1075     par.parse(parStr);
1076     par.printParams();
1077   }
1078 
1079   // Set masses if requested
1080   if (setLightMasses) {
1081     if (par.haveParam("mc")) particleDataPtr->m0(4,  par.getParam("mc"));
1082     if (par.haveParam("mb")) particleDataPtr->m0(5,  par.getParam("mb"));
1083   }
1084   if (setHeavyMasses) {
1085     if (par.haveParam("mt")) particleDataPtr->m0(6,  par.getParam("mt"));
1086     if (par.haveParam("mz")) particleDataPtr->m0(23, par.getParam("mz"));
1087     if (par.haveParam("mw")) particleDataPtr->m0(24, par.getParam("mw"));
1088     if (par.haveParam("mh")) particleDataPtr->m0(25, par.getParam("mh"));
1089   }
1090 
1091   // Set MLM:nJets if requested
1092   if (setNjet) {
1093     if (par.haveParam("njets"))
1094       settingsPtr->mode("JetMatching:nJet", par.getParamAsInt("njets"));
1095     else
1096       cout << "Warning in AlpgenHooks:init: "
1097            << "no ALPGEN nJet parameter found" << endl;
1098   }
1099 
1100   // Set MLM merging parameters if requested
1101   if (setMLM) {
1102     if (par.haveParam("ptjmin") && par.haveParam("drjmin") &&
1103         par.haveParam("etajmax")) {
1104       double ptjmin = par.getParam("ptjmin");
1105       ptjmin = max(ptjmin + 5., 1.2 * ptjmin);
1106       settingsPtr->parm("JetMatching:eTjetMin",   ptjmin);
1107       settingsPtr->parm("JetMatching:coneRadius", par.getParam("drjmin"));
1108       settingsPtr->parm("JetMatching:etaJetMax",  par.getParam("etajmax"));
1109 
1110     // Warn if setMLM requested, but parameters not present
1111     } else {
1112       cout << "Warning in AlpgenHooks:init: "
1113            << "no ALPGEN merging parameters found" << endl;
1114     }
1115   }
1116 
1117   // Initialisation complete.
1118   return true;
1119 }
1120 
1121 //==========================================================================
1122 
1123 // Main implementation of MadgraphPar class.
1124 // This may be split out to a separate C++ file if desired,
1125 // but currently included here for ease of use.
1126 
1127 //--------------------------------------------------------------------------
1128 
1129 // Constants: could be changed here if desired, but normally should not.
1130 // These are of technical nature, as described for each.
1131 
1132 // A zero threshold value for double comparisons.
1133 const double MadgraphPar::ZEROTHRESHOLD = 1e-10;
1134 
1135 //--------------------------------------------------------------------------
1136 
1137 // Parse an incoming Madgraph parameter file string
1138 
1139 inline bool MadgraphPar::parse(const string paramStr) {
1140 
1141   // Loop over incoming lines
1142   stringstream paramStream(paramStr);
1143   string line;
1144   while ( getline(paramStream, line) ) extractRunParam(line);
1145   return true;
1146 
1147 }
1148 
1149 //--------------------------------------------------------------------------
1150 
1151 // Parse an incoming parameter line
1152 
1153 inline void MadgraphPar::extractRunParam(string line) {
1154 
1155   // Extract information to the right of the final '!' character
1156   size_t idz = line.find("#");
1157   if ( !(idz == string::npos) ) return;
1158   size_t idx = line.find("=");
1159   size_t idy = line.find("!");
1160   if (idy == string::npos) idy = line.size();
1161   if (idx == string::npos) return;
1162   string paramName = trim( line.substr( idx + 1, idy - idx - 1) );
1163   string paramVal  = trim( line.substr( 0, idx) );
1164   replace( paramVal.begin(), paramVal.end(), 'd', 'e');
1165 
1166   // Simple tokeniser
1167   istringstream iss(paramVal);
1168   double val;
1169   if (paramName.find(",") != string::npos) {
1170     string        paramNameNow;
1171     istringstream issName( paramName);
1172     while ( getline(issName, paramNameNow, ',') ) {
1173       iss >> val;
1174       warnParamOverwrite( paramNameNow, val);
1175       params[paramNameNow] = val;
1176     }
1177 
1178   // Default case: assume integer and double on the left
1179   } else {
1180     iss >> val;
1181     warnParamOverwrite( paramName, val);
1182     params[paramName] = val;
1183   }
1184 }
1185 
1186 //--------------------------------------------------------------------------
1187 
1188 // Print parameters read from the '.par' file
1189 
1190 inline void MadgraphPar::printParams() {
1191 
1192   // Loop over all stored parameters and print
1193   cout << endl
1194        << " *--------  Madgraph parameters  --------*" << endl;
1195   for (map<string,double>::iterator it = params.begin();
1196        it != params.end(); ++it)
1197     cout << " |  " << left << setw(15) << it->first
1198          << "  |  " << right << setw(15) << it->second
1199          << "  |" << endl;
1200   cout << " *---------------------------------------*" << endl;
1201 }
1202 
1203 //--------------------------------------------------------------------------
1204 
1205 // Warn if a parameter is going to be overwriten
1206 
1207 inline void MadgraphPar::warnParamOverwrite(const string &paramIn,
1208   double val) {
1209 
1210   // Check if present and if new value is different
1211   if (haveParam(paramIn) &&
1212       abs(getParam(paramIn) - val) > ZEROTHRESHOLD) {
1213     cout << "Warning in LHAupAlpgen::"
1214          << "warnParamOverwrite: overwriting existing parameter"
1215          << paramIn << endl;
1216   }
1217 }
1218 
1219 //--------------------------------------------------------------------------
1220 
1221 // Simple string trimmer
1222 
1223 inline string MadgraphPar::trim(string s) {
1224 
1225   // Remove whitespace in incoming string
1226   size_t i;
1227   if ( (i = s.find_last_not_of(" \t\r\n")) != string::npos)
1228     s = s.substr(0, i + 1);
1229   if ( (i = s.find_first_not_of(" \t\r\n")) != string::npos)
1230     s = s.substr(i);
1231   return s;
1232 }
1233 
1234 //==========================================================================
1235 
1236 } // end namespace Pythia8
1237 
1238 #endif //  Pythia8_GeneratorInput_H