Back to home page

EIC code displayed by LXR

 
 

    


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

0001 // PowhegHooks.h is a part of the PYTHIA event generator.
0002 // Copyright (C) 2024 Richard Corke, 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 // Author: Richard Corke, modified by Christian T Preuss.
0007 // This class is used to perform a vetoed shower, where emissions
0008 // already covered in a POWHEG NLO generator should be omitted.
0009 // To first approximation the handover should happen at the SCALE
0010 // of the LHA, but since the POWHEG-BOX uses a different pT definition
0011 // than PYTHIA, both for ISR and FSR, a more sophisticated treatment
0012 // is needed. See the online manual on POWHEG matching for details.
0013 
0014 #ifndef Pythia8_PowhegHooks_H
0015 #define Pythia8_PowhegHooks_H
0016 
0017 // Includes
0018 #include "Pythia8/Pythia.h"
0019 #include "Pythia8/Plugins.h"
0020 
0021 namespace Pythia8 {
0022 
0023 //==========================================================================
0024 
0025 // Use userhooks to veto PYTHIA emissions above the POWHEG scale.
0026 
0027 class PowhegHooks : public UserHooks {
0028 
0029 public:
0030 
0031   // Constructors and destructor.
0032   PowhegHooks() {}
0033   PowhegHooks(Pythia*, Settings*, Logger*) {}
0034   ~PowhegHooks() {}
0035 
0036   //--------------------------------------------------------------------------
0037 
0038   // Initialize settings, detailing merging strategy to use.
0039   bool initAfterBeams() {
0040     nFinal      = settingsPtr->mode("POWHEG:nFinal");
0041     vetoMode    = settingsPtr->mode("POWHEG:veto");
0042     vetoCount   = settingsPtr->mode("POWHEG:vetoCount");
0043     pThardMode  = settingsPtr->mode("POWHEG:pThard");
0044     pTemtMode   = settingsPtr->mode("POWHEG:pTemt");
0045     emittedMode = settingsPtr->mode("POWHEG:emitted");
0046     pTdefMode   = settingsPtr->mode("POWHEG:pTdef");
0047     MPIvetoMode = settingsPtr->mode("POWHEG:MPIveto");
0048     QEDvetoMode = settingsPtr->mode("POWHEG:QEDveto");
0049     showerModel = settingsPtr->mode("PartonShowers:model");
0050     return true;
0051   }
0052 
0053   //--------------------------------------------------------------------------
0054 
0055   // Routines to calculate the pT (according to pTdefMode) in a branching:
0056   //   ISR: i (radiator after)  -> j (emitted after) k (radiator before)
0057   //   FSR: i (radiator before) -> j (emitted after) k (radiator after)
0058   // For the Pythia pT definitions, a recoiler (after) must be specified.
0059 
0060   // Top-level wrapper for shower pTs.
0061   inline double pT(const Event& e, int RadAfterBranch,
0062     int EmtAfterBranch, int RecAfterBranch, bool FSR) {
0063     // VINCIA pT definition.
0064     if (showerModel == 2)
0065       return pTvincia(e, RadAfterBranch, EmtAfterBranch, RecAfterBranch);
0066     // DIRE pT definition.
0067     if (showerModel == 3)
0068       return pTdire(e, RadAfterBranch, EmtAfterBranch, RecAfterBranch);
0069     return pTpythia(e, RadAfterBranch, EmtAfterBranch, RecAfterBranch, FSR);
0070   }
0071 
0072   //--------------------------------------------------------------------------
0073 
0074   // Compute the Pythia pT separation.
0075   // Based on pTLund function in History.cc and identical to pTevol.
0076   inline double pTpythia(const Event& e, int RadAfterBranch,
0077     int EmtAfterBranch, int RecAfterBranch, bool FSR) {
0078 
0079     // Convenient shorthands for later
0080     Vec4 radVec = e[RadAfterBranch].p();
0081     Vec4 emtVec = e[EmtAfterBranch].p();
0082     Vec4 recVec = e[RecAfterBranch].p();
0083     int  radID  = e[RadAfterBranch].id();
0084 
0085     // Calculate virtuality of splitting
0086     double sign = (FSR) ? 1. : -1.;
0087     Vec4 Q(radVec + sign * emtVec);
0088     double Qsq = sign * Q.m2Calc();
0089 
0090     // Mass term of radiator
0091     double m2Rad = (abs(radID) >= 4 && abs(radID) < 7) ?
0092                    pow2(particleDataPtr->m0(radID)) : 0.;
0093 
0094     // z values for FSR and ISR
0095     double z, pTnow;
0096     if (FSR) {
0097       // Construct 2 -> 3 variables
0098       Vec4 sum = radVec + recVec + emtVec;
0099       double m2Dip = sum.m2Calc();
0100       double x1 = 2. * (sum * radVec) / m2Dip;
0101       double x3 = 2. * (sum * emtVec) / m2Dip;
0102       z     = x1 / (x1 + x3);
0103       pTnow = z * (1. - z);
0104 
0105     } else {
0106       // Construct dipoles before/after splitting
0107       Vec4 qBR(radVec - emtVec + recVec);
0108       Vec4 qAR(radVec + recVec);
0109       z     = qBR.m2Calc() / qAR.m2Calc();
0110       pTnow = (1. - z);
0111     }
0112 
0113     // Virtuality with correct sign
0114     pTnow *= (Qsq - sign * m2Rad);
0115 
0116     // Can get negative pT for massive splittings.
0117     if (pTnow < 0.) {
0118       loggerPtr->WARNING_MSG("negative pT");
0119       return -1.;
0120     }
0121 
0122     // Return pT
0123     return sqrt(pTnow);
0124   }
0125 
0126   //--------------------------------------------------------------------------
0127 
0128   // Compute the Vincia pT as in Eq. (2.63)-(2.66) in arXiv:2003.00702.
0129   // Branching is assumed to be {13} {23} -> 1 3 2.
0130   inline double pTvincia(const Event& event, int i1, int i3, int i2) {
0131 
0132     // Shorthands.
0133     Vec4 p1 = event[i1].p();
0134     Vec4 p3 = event[i3].p();
0135     Vec4 p2 = event[i2].p();
0136 
0137     // Fetch mothers of 1 and 2.
0138     int iMoth1 = event[i1].mother1();
0139     int iMoth2 = event[i2].mother1();
0140     if (iMoth1 == 0 || iMoth2 == 0) {
0141       loggerPtr->ABORT_MSG("could not find mothers of particles");
0142       exit(1);
0143     }
0144 
0145     // Invariants defined as in Eq. (5) in arXiv:2008.09468.
0146     double mMoth1Sq = event[iMoth1].m2();
0147     double mMoth2Sq = event[iMoth2].m2();
0148     double sgn1 = event[i1].isFinal() ? 1. : -1.;
0149     double sgn2 = event[i2].isFinal() ? 1. : -1.;
0150     double qSq13 = sgn1*(m2(sgn1*p1+p3) - mMoth1Sq);
0151     double qSq23 = sgn2*(m2(sgn2*p2+p3) - mMoth2Sq);
0152 
0153     // Normalisation as in Eq. (6) in arXiv:2008.09468.
0154     double sMax = -1.;
0155     if (event[i1].isFinal() && event[i2].isFinal()) {
0156       // FF.
0157       sMax = m2(p1+p2+p3) - mMoth1Sq - mMoth2Sq;
0158     } else if ((event[i1].isResonance() && event[i2].isFinal())
0159       || (!event[i1].isFinal() && event[i2].isFinal())) {
0160       // RF or IF.
0161       sMax = 2.*p1*p3 + 2.*p1*p2;
0162     } else if ((event[i1].isFinal() && event[i2].isResonance())
0163       || (event[i1].isFinal() && !event[i2].isFinal())) {
0164       // FR or FI.
0165       sMax = 2.*p2*p3 + 2.*p1*p2;
0166     } else if (!event[i1].isFinal() || !event[i2].isFinal()) {
0167       // II.
0168       sMax = 2.*p1*p2;
0169     } else {
0170       loggerPtr->ABORT_MSG("could not determine branching type");
0171       exit(1);
0172     }
0173 
0174     // Calculate pT2 as in Eq. (5) in arXiv:2008.09468.
0175     double pT2now = qSq13*qSq23/sMax;
0176 
0177     // Sanity check.
0178     if (pT2now < 0.) {
0179       loggerPtr->WARNING_MSG("negative pT");
0180       return -1.;
0181     }
0182 
0183     // Return pT.
0184     return sqrt(pT2now);
0185   }
0186 
0187   //--------------------------------------------------------------------------
0188 
0189   // Compute the Dire pT as in
0190   // DireTimes::pT2_FF, DireTimes::pT2_FI,
0191   // DireSpace::pT2_IF, DireSpace::pT2_II.
0192   inline double pTdire(const Event& event, int iRad, int iEmt, int iRec) {
0193 
0194     // Shorthands.
0195     const Particle& rad = event[iRad];
0196     const Particle& emt = event[iEmt];
0197     const Particle& rec = event[iRec];
0198 
0199     // Calculate pT2 depending on dipole configuration.
0200     double pT2 = -1.;
0201     if (rad.isFinal() && rec.isFinal()) {
0202       // FF -- copied from DireTimes::pT2_FF.
0203       const double sij = 2.*rad.p()*emt.p();
0204       const double sik = 2.*rad.p()*rec.p();
0205       const double sjk = 2.*rec.p()*emt.p();
0206       pT2 = sij*sjk/(sij+sik+sjk);
0207     } else if (rad.isFinal() && !rec.isFinal()) {
0208       // FI.
0209       const double sij =  2.*rad.p()*emt.p();
0210       const double sai = -2.*rec.p()*rad.p();
0211       const double saj = -2.*rec.p()*emt.p();
0212       pT2 = sij*saj/(sai+saj)*(sij+saj+sai)/(sai+saj);
0213       if (sij+saj+sai < 1e-5 && abs(sij+saj+sai) < 1e-5) pT2 = sij;
0214     } else if (!rad.isFinal() && rec.isFinal()) {
0215       // IF.
0216       const double sai = -2.*rad.p()*emt.p();
0217       const double sik =  2.*rec.p()*emt.p();
0218       const double sak = -2.*rad.p()*rec.p();
0219       pT2 = sai*sik/(sai+sak)*(sai+sik+sak)/(sai+sak);
0220     } else if (!rad.isFinal() || !rec.isFinal()) {
0221       // II.
0222       const double sai = -2.*rad.p()*emt.p();
0223       const double sbi = -2.*rec.p()*emt.p();
0224       const double sab =  2.*rad.p()*rec.p();
0225       pT2 = sai*sbi/sab*(sai+sbi+sab)/sab;
0226     } else {
0227       loggerPtr->ABORT_MSG("could not determine branching type");
0228       exit(1);
0229     }
0230 
0231     // Sanity check.
0232     if (pT2 < 0.) {
0233       loggerPtr->WARNING_MSG("negative pT");
0234       return -1.;
0235     }
0236 
0237     // Return pT.
0238     return sqrt(pT2);
0239   }
0240 
0241   //--------------------------------------------------------------------------
0242 
0243   // Compute the POWHEG pT separation between i and j.
0244   inline double pTpowheg(const Event &e, int i, int j, bool FSR) {
0245 
0246     // pT value for FSR and ISR
0247     double pTnow = 0.;
0248     if (FSR) {
0249       // POWHEG d_ij (in CM frame). Note that the incoming beams have not
0250       // been updated in the parton systems pointer yet (i.e. prior to any
0251       // potential recoil).
0252       int iInA = partonSystemsPtr->getInA(0);
0253       int iInB = partonSystemsPtr->getInB(0);
0254       double betaZ = - ( e[iInA].pz() + e[iInB].pz() ) /
0255                        ( e[iInA].e()  + e[iInB].e()  );
0256       Vec4 iVecBst(e[i].p()), jVecBst(e[j].p());
0257       iVecBst.bst(0., 0., betaZ);
0258       jVecBst.bst(0., 0., betaZ);
0259       pTnow = sqrt( (iVecBst + jVecBst).m2Calc() *
0260                     iVecBst.e() * jVecBst.e() /
0261                     pow2(iVecBst.e() + jVecBst.e()) );
0262 
0263     } else {
0264       // POWHEG pT_ISR is just kinematic pT
0265       pTnow = e[j].pT();
0266     }
0267 
0268     // Check result.
0269     if (pTnow < 0.) {
0270       loggerPtr->WARNING_MSG("negative pT");
0271       return -1.;
0272     }
0273 
0274     return pTnow;
0275   }
0276 
0277   //--------------------------------------------------------------------------
0278 
0279   // Calculate pT for a splitting based on pTdefMode.
0280   // If j is -1, all final-state partons are tried.
0281   // If i, k, r and xSR are -1, then all incoming and outgoing
0282   // partons are tried.
0283   // xSR set to 0 means ISR, while xSR set to 1 means FSR.
0284   inline double pTcalc(const Event &e, int i, int j, int k, int r, int xSRin) {
0285 
0286     // Loop over ISR and FSR if necessary
0287     double pTemt = -1., pTnow;
0288     int xSR1 = (xSRin == -1) ? 0 : xSRin;
0289     int xSR2 = (xSRin == -1) ? 2 : xSRin + 1;
0290     for (int xSR = xSR1; xSR < xSR2; xSR++) {
0291       // FSR flag
0292       bool FSR = (xSR == 0) ? false : true;
0293 
0294       // If all necessary arguments have been given, then directly calculate.
0295       // POWHEG ISR and FSR, need i and j.
0296       if ((pTdefMode == 0 || pTdefMode == 1) && i > 0 && j > 0) {
0297         pTemt = pTpowheg(e, i, j, (pTdefMode == 0) ? false : FSR);
0298 
0299       // Pythia ISR, need i, j and r.
0300       } else if (!FSR && pTdefMode == 2 && i > 0 && j > 0 && r > 0) {
0301         pTemt = pT(e, i, j, r, FSR);
0302 
0303       // Pythia FSR, need k, j and r.
0304       } else if (FSR && pTdefMode == 2 && j > 0 && k > 0 && r > 0) {
0305         pTemt = pT(e, k, j, r, FSR);
0306 
0307       // Otherwise need to try all possible combinations.
0308       } else {
0309         // Start by finding incoming legs to the hard system after
0310         // branching (radiator after branching, i for ISR).
0311         // Use partonSystemsPtr to find incoming just prior to the
0312         // branching and track mothers.
0313         int iInA = partonSystemsPtr->getInA(0);
0314         int iInB = partonSystemsPtr->getInB(0);
0315         while (e[iInA].mother1() != 1) { iInA = e[iInA].mother1(); }
0316         while (e[iInB].mother1() != 2) { iInB = e[iInB].mother1(); }
0317 
0318         // If we do not have j, then try all final-state partons.
0319         int jNow = (j > 0) ? j : 0;
0320         int jMax = (j > 0) ? j + 1 : e.size();
0321         for (; jNow < jMax; jNow++) {
0322 
0323           // Final-state only.
0324           if (!e[jNow].isFinal()) continue;
0325           // Exclude photons (and W/Z!)
0326           if (QEDvetoMode==0 && e[jNow].colType() == 0) continue;
0327 
0328           // POWHEG.
0329           if (pTdefMode == 0 || pTdefMode == 1) {
0330 
0331             // ISR - only done once as just kinematical pT.
0332             if (!FSR) {
0333               pTnow = pTpowheg(e, iInA, jNow, (pTdefMode == 0) ? false : FSR);
0334               if (pTnow > 0.) pTemt = (pTemt < 0) ? pTnow : min(pTemt, pTnow);
0335 
0336             // FSR - try all outgoing partons from system before branching
0337             // as i. Note that for the hard system, there is no
0338             // "before branching" information.
0339             } else {
0340 
0341               int outSize = partonSystemsPtr->sizeOut(0);
0342               for (int iMem = 0; iMem < outSize; iMem++) {
0343                 int iNow = partonSystemsPtr->getOut(0, iMem);
0344 
0345                 // i != jNow and no carbon copies
0346                 if (iNow == jNow ) continue;
0347                 // Exclude photons (and W/Z!)
0348                 if (QEDvetoMode==0 && e[iNow].colType() == 0) continue;
0349                 if (jNow == e[iNow].daughter1()
0350                   && jNow == e[iNow].daughter2()) continue;
0351 
0352                 pTnow = pTpowheg(e, iNow, jNow, (pTdefMode == 0)
0353                   ? false : FSR);
0354                 if (pTnow > 0.) pTemt = (pTemt < 0)
0355                   ? pTnow : min(pTemt, pTnow);
0356               }
0357              // for (iMem)
0358             }
0359             // if (!FSR)
0360           // Pythia.
0361           } else if (pTdefMode == 2) {
0362 
0363             // ISR - other incoming as recoiler.
0364             if (!FSR) {
0365               pTnow = pT(e, iInA, jNow, iInB, FSR);
0366               if (pTnow > 0.) pTemt = (pTemt < 0) ? pTnow : min(pTemt, pTnow);
0367               pTnow = pT(e, iInB, jNow, iInA, FSR);
0368               if (pTnow > 0.) pTemt = (pTemt < 0) ? pTnow : min(pTemt, pTnow);
0369 
0370             // FSR - try all final-state coloured partons as radiator
0371             //       after emission (k).
0372             } else {
0373               for (int kNow = 0; kNow < e.size(); kNow++) {
0374                 if (kNow == jNow || !e[kNow].isFinal()) continue;
0375                 if (QEDvetoMode==0 && e[kNow].colType() == 0) continue;
0376 
0377                 // For this kNow, need to have a recoiler.
0378                 // Try two incoming.
0379                 pTnow = pT(e, kNow, jNow, iInA, FSR);
0380                 if (pTnow > 0.) pTemt = (pTemt < 0)
0381                   ? pTnow : min(pTemt, pTnow);
0382                 pTnow = pT(e, kNow, jNow, iInB, FSR);
0383                 if (pTnow > 0.) pTemt = (pTemt < 0)
0384                   ? pTnow : min(pTemt, pTnow);
0385 
0386                 // Try all other outgoing.
0387                 for (int rNow = 0; rNow < e.size(); rNow++) {
0388                   if (rNow == kNow || rNow == jNow ||
0389                       !e[rNow].isFinal()) continue;
0390                   if(QEDvetoMode==0 && e[rNow].colType() == 0) continue;
0391                   pTnow = pT(e, kNow, jNow, rNow, FSR);
0392                   if (pTnow > 0.) pTemt = (pTemt < 0)
0393                     ? pTnow : min(pTemt, pTnow);
0394                 }
0395               // for (rNow)
0396               }
0397             // for (kNow)
0398             }
0399           // if (!FSR)
0400           }
0401         // if (pTdefMode)
0402         }
0403       // for (j)
0404       }
0405     }
0406     // for (xSR)
0407 
0408     return pTemt;
0409   }
0410 
0411   //--------------------------------------------------------------------------
0412 
0413   // Extraction of pThard based on the incoming event.
0414   // Assume that all the final-state particles are in a continuous block
0415   // at the end of the event and the final entry is the POWHEG emission.
0416   // If there is no POWHEG emission, then pThard is set to SCALUP.
0417 
0418   inline bool canVetoMPIStep()    { return true; }
0419   inline int  numberVetoMPIStep() { return 1; }
0420   inline bool doVetoMPIStep(int nMPI, const Event &e) {
0421     // Extra check on nMPI
0422     if (nMPI > 1) return false;
0423     int iEmt = -1;
0424     double pT1(0.), pTsum(0.);
0425 
0426     // When nFinal is set, be strict about comparing the number of final-state
0427     // particles with expectation from Born and single-real emission states.
0428     // (Note: the default from 8.309 onwards is nFinal = -1).
0429     if (nFinal > 0) {
0430       // Find if there is a POWHEG emission. Go backwards through the
0431       // event record until there is a non-final particle. Also sum pT and
0432       // find pT_1 for possible MPI vetoing
0433       int count = 0;
0434       for (int i = e.size() - 1; i > 0; i--) {
0435         if (e[i].isFinal()) {
0436           count++;
0437           pT1    = e[i].pT();
0438           pTsum += e[i].pT();
0439         } else break;
0440       }
0441       // Extra check that we have the correct final state
0442       if (count != nFinal && count != nFinal + 1) {
0443         loggerPtr->ABORT_MSG("wrong number of final state particles in event");
0444         exit(1);
0445       }
0446       // Flag if POWHEG radiation present and index
0447       isEmt = (count == nFinal) ? false : true;
0448       iEmt  = (isEmt) ? e.size() - 1 : -1;
0449 
0450     // If nFinal == -1, then go through the event and extract only the
0451     // information on the emission and its pT, but do not enforce strict
0452     // comparisons of final state multiplicity.
0453     } else {
0454 
0455       // Flag whether POWHEG radiation is present, and save index of emission.
0456       isEmt = false;
0457       for (int i = e.size() - 1; i > 0; i--) {
0458         if (e[i].isFinal()) {
0459           if ( e[i].isParton() && iEmt < 0
0460             && e[e[i].mother1()].isParton() ) {
0461             isEmt = true;
0462             iEmt = i;
0463           }
0464           pT1    = e[i].pT();
0465           pTsum += e[i].pT();
0466         } else break;
0467       }
0468     }
0469 
0470     // If there is no radiation or if pThardMode is 0 then set pThard = SCALUP.
0471     if (!isEmt || pThardMode == 0) {
0472       pThard = infoPtr->scalup();
0473 
0474     // If pThardMode is 1 then the pT of the POWHEG emission is checked against
0475     // all other incoming and outgoing partons, with the minimal value taken.
0476     } else if (pThardMode == 1) {
0477       if (nFinal < 0) {
0478         loggerPtr->WARNING_MSG(
0479           "pThard == 1 not available for nFinal == -1, reset pThard = 0.");
0480         pThardMode = 0;
0481         pThard = infoPtr->scalup();
0482       } else {
0483         pThard = pTcalc(e, -1, iEmt, -1, -1, -1);
0484       }
0485 
0486     // If pThardMode is 2, then the pT of all final-state partons is checked
0487     // against all other incoming and outgoing partons, with the minimal value
0488     // taken.
0489     } else if (pThardMode == 2) {
0490       if (nFinal < 0) {
0491         loggerPtr->WARNING_MSG(
0492           "pThard == 2 not available for nFinal == -1, reset pThard = 0.");
0493         pThardMode = 0;
0494         pThard = infoPtr->scalup();
0495       } else {
0496         pThard = pTcalc(e, -1, -1, -1, -1, -1);
0497       }
0498     }
0499 
0500     // Find MPI veto pT if necessary.
0501     if (MPIvetoMode == 1) {
0502       pTMPI = (isEmt) ? pTsum / 2. : pT1;
0503     }
0504 
0505     // Initialise other variables.
0506     accepted   = false;
0507     nAcceptSeq = nISRveto = nFSRveto = 0;
0508 
0509     // Do not veto the event
0510     return false;
0511   }
0512 
0513   //--------------------------------------------------------------------------
0514 
0515   // ISR veto.
0516 
0517   inline bool canVetoISREmission() { return (vetoMode == 0) ? false : true; }
0518   inline bool doVetoISREmission(int, const Event &e, int iSys) {
0519     // Must be radiation from the hard system
0520     if (iSys != 0) return false;
0521 
0522     // If we already have accepted 'vetoCount' emissions in a row, do nothing
0523     if (vetoMode == 1 && nAcceptSeq >= vetoCount) return false;
0524 
0525     // Pythia radiator after, emitted and recoiler after.
0526     int iRadAft = -1, iEmt = -1, iRecAft = -1;
0527     for (int i = e.size() - 1; i > 0; i--) {
0528       if (showerModel == 1) {
0529         // Pythia.
0530         if      (iRadAft == -1 && e[i].status() == -41) iRadAft = i;
0531         else if (iEmt    == -1 && e[i].status() ==  43) iEmt    = i;
0532         else if (iRecAft == -1 && e[i].status() == -42) iRecAft = i;
0533       } else if (showerModel == 2) {
0534         // Vincia.
0535         if      (iRadAft == -1 && e[i].status() == -41) iRadAft = i;
0536         else if (iEmt    == -1 && e[i].status() ==  43) iEmt    = i;
0537         else if (iRecAft == -1
0538           && (e[i].status() == -41 || e[i].status() == 44)) iRecAft = i;
0539       } else if (showerModel == 3) {
0540         // Dire.
0541         if      (iRadAft == -1 && e[i].status() == -41) iRadAft = i;
0542         else if (iEmt    == -1 && e[i].status() ==  43) iEmt    = i;
0543         else if (iRecAft == -1
0544           && (e[i].status() == -41
0545             || e[i].status() == 44 || e[i].status() == 48)) iRecAft = i;
0546       }
0547       if (iRadAft != -1 && iEmt != -1 && iRecAft != -1) break;
0548     }
0549     if (iRadAft == -1 || iEmt == -1 || iRecAft == -1) {
0550       loggerPtr->ABORT_MSG("could not find ISR emission");
0551       exit(1);
0552     }
0553 
0554     // pTemtMode == 0: pT of emitted w.r.t. radiator
0555     // pTemtMode == 1: min(pT of emitted w.r.t. all incoming/outgoing)
0556     // pTemtMode == 2: min(pT of all outgoing w.r.t. all incoming/outgoing)
0557     int xSR      = (pTemtMode == 0) ? 0       : -1;
0558     int i        = (pTemtMode == 0) ? iRadAft : -1;
0559     int j        = (pTemtMode != 2) ? iEmt    : -1;
0560     int k        = -1;
0561     int r        = (pTemtMode == 0) ? iRecAft : -1;
0562     double pTemt = pTcalc(e, i, j, k, r, xSR);
0563 
0564     // If a Born configuration, and a photon, and QEDvetoMode=2,
0565     //  then don't veto photons, W, or Z harder than pThard.
0566     bool vetoParton = (!isEmt && e[iEmt].colType()==0 && QEDvetoMode==2)
0567       ? false: true;
0568 
0569     // Veto if pTemt > pThard.
0570     if (pTemt > pThard) {
0571       if(!vetoParton) {
0572         // Don't veto ANY emissions afterwards.
0573         nAcceptSeq = vetoCount-1;
0574       } else {
0575         nAcceptSeq = 0;
0576         nISRveto++;
0577         return true;
0578       }
0579     }
0580 
0581     // Else mark that an emission has been accepted and continue.
0582     nAcceptSeq++;
0583     accepted = true;
0584     return false;
0585   }
0586 
0587   //--------------------------------------------------------------------------
0588 
0589   // FSR veto.
0590 
0591   inline bool canVetoFSREmission() { return (vetoMode == 0) ? false : true; }
0592   inline bool doVetoFSREmission(int, const Event &e, int iSys, bool) {
0593     // Must be radiation from the hard system.
0594     if (iSys != 0) return false;
0595 
0596     // If we already have accepted 'vetoCount' emissions in a row, do nothing.
0597     if (vetoMode == 1 && nAcceptSeq >= vetoCount) return false;
0598 
0599     // Pythia radiator (before and after), emitted and recoiler (after).
0600     int iRecAft = e.size() - 1;
0601     int iEmt    = e.size() - 2;
0602     int iRadAft = e.size() - 3;
0603     int iRadBef = e[iEmt].mother1();
0604     bool stop = false;
0605     if (showerModel == 1 || showerModel == 3) {
0606       // Pythia or Dire.
0607       if ( (e[iRecAft].status() != 52 && e[iRecAft].status() != -53) ||
0608         e[iEmt].status() != 51 || e[iRadAft].status() != 51) stop = true;
0609     } else if (showerModel == 2) {
0610       // Vincia.
0611       if ( (e[iRecAft].status() != 51 && e[iRecAft].status() != 52) ||
0612         e[iEmt].status() != 51 || e[iRadAft].status() != 51) stop = true;
0613     }
0614     if (stop) {
0615       loggerPtr->ABORT_MSG("could not find FSR emission");
0616       exit(1);
0617     }
0618 
0619     // Behaviour based on pTemtMode:
0620     //  0 - pT of emitted w.r.t. radiator before
0621     //  1 - min(pT of emitted w.r.t. all incoming/outgoing)
0622     //  2 - min(pT of all outgoing w.r.t. all incoming/outgoing)
0623     int xSR = (pTemtMode == 0) ? 1       : -1;
0624     int i   = (pTemtMode == 0) ? iRadBef : -1;
0625     int k   = (pTemtMode == 0) ? iRadAft : -1;
0626     int r   = (pTemtMode == 0) ? iRecAft : -1;
0627 
0628     // When pTemtMode is 0 or 1, iEmt has been selected.
0629     double pTemt = 0.;
0630     if (pTemtMode == 0 || pTemtMode == 1) {
0631       // Which parton is emitted, based on emittedMode:
0632       //  0 - Pythia definition of emitted
0633       //  1 - Pythia definition of radiated after emission
0634       //  2 - Random selection of emitted or radiated after emission
0635       //  3 - Try both emitted and radiated after emission
0636       int j = iRadAft;
0637       if (emittedMode == 0 || (emittedMode == 2 && rndmPtr->flat() < 0.5)) j++;
0638 
0639       for (int jLoop = 0; jLoop < 2; jLoop++) {
0640         if      (jLoop == 0) pTemt = pTcalc(e, i, j, k, r, xSR);
0641         else if (jLoop == 1) pTemt = min(pTemt, pTcalc(e, i, j, k, r, xSR));
0642 
0643         // For emittedMode == 3, have tried iRadAft, now try iEmt
0644         if (emittedMode != 3) break;
0645         if (k != -1) swap(j, k); else j = iEmt;
0646       }
0647 
0648     // If pTemtMode is 2, then try all final-state partons as emitted
0649     } else if (pTemtMode == 2) {
0650       pTemt = pTcalc(e, i, -1, k, r, xSR);
0651 
0652     }
0653 
0654     // If a Born configuration, and a photon, and QEDvetoMode=2,
0655     //  then don't veto photons, W's or Z's harder than pThard
0656     bool vetoParton = (!isEmt && e[iEmt].colType()==0 && QEDvetoMode==2)
0657       ? false: true;
0658 
0659     // Veto if pTemt > pThard
0660     if (pTemt > pThard) {
0661       if(!vetoParton) {
0662         // Don't veto ANY emissions afterwards
0663         nAcceptSeq = vetoCount-1;
0664       } else {
0665         nAcceptSeq = 0;
0666         nFSRveto++;
0667         return true;
0668       }
0669     }
0670 
0671     // Else mark that an emission has been accepted and continue
0672     nAcceptSeq++;
0673     accepted = true;
0674     return false;
0675   }
0676 
0677   //--------------------------------------------------------------------------
0678 
0679   // MPI veto.
0680 
0681   inline bool canVetoMPIEmission() {return (MPIvetoMode == 0) ? false : true;}
0682   inline bool doVetoMPIEmission(int, const Event &e) {
0683     if (MPIvetoMode == 1) {
0684       if (e[e.size() - 1].pT() > pTMPI) return true;
0685     }
0686     return false;
0687   }
0688 
0689   //--------------------------------------------------------------------------
0690 
0691   // Functions to return information.
0692 
0693   inline int getNISRveto() { return nISRveto; }
0694   inline int getNFSRveto() { return nFSRveto; }
0695 
0696   //--------------------------------------------------------------------------
0697 
0698  private:
0699   int    showerModel, nFinal, vetoMode, MPIvetoMode, QEDvetoMode, vetoCount;
0700   int    pThardMode, pTemtMode, emittedMode, pTdefMode;
0701   double pThard, pTMPI;
0702   bool   accepted, isEmt;
0703   // The number of accepted emissions (in a row)
0704   // Flag for PowHeg Born or Radiation
0705   int nAcceptSeq;
0706   // Statistics on vetos
0707   unsigned long int nISRveto, nFSRveto;
0708 
0709 };
0710 
0711 //--------------------------------------------------------------------------
0712 
0713 // Declare the plugin.
0714 
0715 PYTHIA8_PLUGIN_CLASS(UserHooks, PowhegHooks, false, false, false)
0716 PYTHIA8_PLUGIN_VERSIONS(PYTHIA_VERSION_INTEGER)
0717 
0718 //==========================================================================
0719 
0720 } // end namespace Pythia8
0721 
0722 #endif // end Pythia8_PowhegHooks_H