Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-05-02 05:09:45

0001 // PowhegHooksBB4L.h
0002 // Rewritten by T. Jezo in 2021.  With various contributions from S. Ferrario
0003 // Ravasio, B. Nachman, P.  Nason and M. Seidel. Inspired by
0004 // ttb_NLO_dec/main-PYTHIA8.f by P. Nason and E. Re and by PowhegHooks.h by R.
0005 // Corke.
0006 //
0007 // Adapted for CMSSW by Laurids Jeppe.
0008 
0009 // # Introduction
0010 //
0011 // This hook is intended for use together with POWHEG-BOX-RES/b_bbar_4l NLO LHE
0012 // events. This also includes events in which one of the W bosons was
0013 // re-decayed hadronically. (Note that LHE format version larger than 3 may not
0014 // require this hook).
0015 //
0016 // The hook inherits from PowhegHooks and as such it indirectly implements the
0017 // following:
0018 //  - doVetoMPIStep
0019 //  - doVetoISREmission
0020 //  - doVetoMPIEmission
0021 // and it overloads:
0022 //  - doVetoFSREmission, which works as follows (if POWHEG:veto==1):
0023 //    - if inResonance==true it vetoes all the emission that is harder than
0024 //    the scale of its parent (anti-)top quark or W^+(-)
0025 //    - if inResonance==false, it calls PowhegHooks::doVetoISREmission
0026 // and it also implements:
0027 //  - doVetoProcessLevel, which is never used for vetoing (i.e. it always
0028 //  returns false). Instead it is used for the calculation of reconance scales
0029 //  using LHE kinematics.
0030 //
0031 // This version of the hooks is only suitable for use with fully compatible
0032 // POWHEG-BOX Les Houches readers (such the one in main-PYTHIA82-lhef but
0033 // not the one in main31.cc.)
0034 //
0035 //
0036 // # Basic use
0037 //
0038 // In order to use this hook you must replace all the declarations and
0039 // constructor calls of PowhegHooks to PowhegHooksBB4L:
0040 //
0041 //   PowhegHooks *powhegHooks; -> PowhegHooksBB4L *powhegHooks;
0042 //   *powhegHooks = new PowhegHooks(); -> *powhegHooks = new PowhegHooksBB4L();
0043 //
0044 // In order to switch it on set POWHEG:veto = 1 and
0045 // POWHEG:bb4l:FSREmission:veto = 1. This will lead to a veto in ISR, FSR and
0046 // MPI steps of pythia as expected using PowhegHooks in all the cases other than
0047 // the case of FSR emission in resonance decay. Within resonance decays
0048 // PowhegHooksBB4L takes over the control.
0049 //
0050 // Furthermore, this hook can also be used standalone without PowhegHooks, i.e.
0051 // only the FSR emission from resonances will be vetoed (the default use in
0052 // 1801.03944 and 1906.09166). In order to do that set
0053 // POWHEG:bb4l:FSREmission:veto = 1 and POWHEG:veto = 0. Note that the this is
0054 // not recommended for comparing against data but because it is easier to
0055 // interpret it is often done in theoretical studies.
0056 //
0057 // Note that this version of the hook relies on the event "radtype" (1 for
0058 // btilde, 2 for remnant) to be set by an external program, such as
0059 // main-PYTHIA82-lhef in the radtype_ common block.
0060 // There also exists a version of this hook in which the event "radtype" is
0061 // read in from the .lhe file using pythia built in functionality. You need
0062 // that version if you want to use this hook with main31.cc.
0063 //
0064 //
0065 // # Expert use
0066 //
0067 // This hook also implements an alternative veto procedure which allows to
0068 // assign a "SCALUP" type of scale to a resonance using the scaleResonance
0069 // method. This is a much simpler veto but it is also clearly inferior as
0070 // compared to the one implemented using the doVetoFSREmission method because
0071 // the definition of the scale of the emission does not match the
0072 // POWHEG-BOX-RES definition. Nevertheless, it can be activated using
0073 // POWHEG:bb4l:ScaleResonance:veto = 1. Additionally one MUST switch off the
0074 // other veto by calling on POWHEG:bb4l:FSREmission:veto = 0.
0075 //
0076 // The following settings are at the disposal of the user to control the
0077 // behaviour of the hook
0078 //   - On/off switches for the veto:
0079 //    - POWHEG:bb4l:FSREmission:veto
0080 //      on/off switch for the default veto based on doFSREmission
0081 //    - POWHEG:bb4l:ScaleResonance:veto
0082 //      on/off switch for the alternative veto based on scaleResonance (only
0083 //      for expert users)
0084 //   - Important settings:
0085 //    - POWHEG:bb4l:ptMinVeto: MUST be set to the same value as the
0086 //    corresponding flag in POWHEG-BOX-RES
0087 //   - Alternatives for scale calculations
0088 //    - default: emission scale is calculated using POWHEG definitions and in
0089 //    the resonance rest frame
0090 //    - POWHEG:bb4l:FSREmission:vetoDipoleFrame: emission scale is calculated
0091 //    using POWHEG definitions in the dipole frame
0092 //    - POWHEG:bb4l:FSREmission:pTpythiaVeto: emission scale is calculated
0093 //    using Pythia definitions
0094 //   - Other flags:
0095 //    - POWHEG:bb4l:FSREmission:vetoQED: decides whether or not QED emission
0096 //    off quarks should also be vetoed (not implemented in the case of
0097 //    the ScaleResonance:veto)
0098 //    - POWHEG:bb4l:DEBUG: enables debug printouts on standard output
0099 
0100 #ifndef Pythia8_PowhegHooksBB4L_H
0101 #define Pythia8_PowhegHooksBB4L_H
0102 
0103 #include "Pythia8/Pythia.h"
0104 #include <cassert>
0105 
0106 namespace Pythia8 {
0107 
0108   class PowhegHooksBB4L : public UserHooks {
0109   public:
0110     PowhegHooksBB4L() {}
0111     ~PowhegHooksBB4L() { std::cout << "Number of FSR vetoed in BB4l = " << nInResonanceFSRveto << std::endl; }
0112 
0113     //--- Initialization -------------------------------------------------------
0114     bool initAfterBeams() {
0115       // initialize settings of this class
0116       vetoFSREmission = settingsPtr->flag("POWHEG:bb4l:FSREmission:veto");
0117       vetoDipoleFrame = settingsPtr->flag("POWHEG:bb4l:FSREmission:vetoDipoleFrame");
0118       pTpythiaVeto = settingsPtr->flag("POWHEG:bb4l:FSREmission:pTpythiaVeto");
0119       vetoQED = settingsPtr->flag("POWHEG:bb4l:FSREmission:vetoQED");
0120       scaleResonanceVeto = settingsPtr->flag("POWHEG:bb4l:ScaleResonance:veto");
0121       debug = settingsPtr->flag("POWHEG:bb4l:DEBUG");
0122       pTmin = settingsPtr->parm("POWHEG:bb4l:pTminVeto");
0123       vetoAllRadtypes = settingsPtr->flag("POWHEG:bb4l:vetoAllRadtypes");
0124       nInResonanceFSRveto = 0;
0125       return true;
0126     }
0127 
0128     //--- PROCESS LEVEL HOOK ---------------------------------------------------
0129     // This hook gets triggered for each event before the shower starts, i.e. at
0130     // the LHE level. We use it to calculate the scales of resonances.
0131     inline bool canVetoProcessLevel() { return true; }
0132     inline bool doVetoProcessLevel(Event &e) {
0133       // extract the radtype from the event comment
0134       stringstream ss;
0135       // use eventattribute as comments not filled when using edm input
0136       ss << infoPtr->getEventAttribute("#rwgt");
0137       string temp;
0138       ss >> temp >> radtype;
0139       assert(temp == "#rwgt");
0140       // we only calculate resonance scales for btilde events (radtype==1)
0141       // remnant events are not vetoed
0142       if (!vetoAllRadtypes && radtype == 2)
0143         return false;
0144       // find last top and the last anti-top in the record
0145       int i_top = -1, i_atop = -1, i_wp = -1, i_wm = -1;
0146       for (int i = 0; i < e.size(); i++) {
0147         if (e[i].id() == 6)
0148           i_top = i;
0149         if (e[i].id() == -6)
0150           i_atop = i;
0151         if (e[i].id() == 24)
0152           i_wp = i;
0153         if (e[i].id() == -24)
0154           i_wm = i;
0155       }
0156       // if found calculate the resonance scale
0157       topresscale = findresscale(i_top, e);
0158       // similarly for anti-top
0159       atopresscale = findresscale(i_atop, e);
0160       // and for W^+ and W^-
0161       wpresscale = findresscale(i_wp, e);
0162       wmresscale = findresscale(i_wm, e);
0163 
0164       // do not veto, ever
0165       return false;
0166     }
0167 
0168     //--- FSR EMISSION LEVEL HOOK ----------------------------------------------
0169     // This hook gets triggered everytime the parton shower attempts to attach
0170     // a FSR emission.
0171     inline bool canVetoFSREmission() { return vetoFSREmission; }
0172     inline bool doVetoFSREmission(int sizeOld, const Event &e, int iSys, bool inResonance) {
0173       // FSR VETO INSIDE THE RESONANCE (if it is switched on)
0174       if (inResonance && vetoFSREmission) {
0175         // get the participants of the splitting: the recoiler, the radiator and the emitted
0176         int iRecAft = e.size() - 1;
0177         int iEmt = e.size() - 2;
0178         int iRadAft = e.size() - 3;
0179         int iRadBef = e[iEmt].mother1();
0180 
0181         // find the resonance the radiator originates from
0182         int iRes = e[iRadBef].mother1();
0183         while (iRes > 0 && (abs(e[iRes].id()) != 6 && abs(e[iRes].id()) != 24)) {
0184           iRes = e[iRes].mother1();
0185         }
0186         if (iRes == 0) {
0187           loggerPtr->errorMsg("PowhegHooksBB4L::doVetoFSREmission",
0188                               "Emission in resonance not from the top quark or from the "
0189                               "W boson, not vetoing");
0190           return doVetoFSR(false, 0);
0191         }
0192         int iResId = e[iRes].id();
0193 
0194         // calculate the scale of the emission
0195         double scale;
0196         //using pythia pT definition ...
0197         if (pTpythiaVeto)
0198           scale = pTpythia(e, iRadAft, iEmt, iRecAft);
0199         //.. or using POWHEG pT definition
0200         else {
0201           Vec4 pr(e[iRadAft].p()), pe(e[iEmt].p()), pres(e[iRes].p()), prec(e[iRecAft].p()), psystem;
0202           // The computation of the POWHEG pT can be done in the top rest frame or in the diple one.
0203           // pdipole = pemt +prec +prad (after the emission)
0204           // For the first emission off the top resonance pdipole = pw +pb (before the emission) = ptop
0205           if (vetoDipoleFrame)
0206             psystem = pr + pe + prec;
0207           else
0208             psystem = pres;
0209 
0210           // gluon splitting into two partons
0211           if (e[iRadBef].id() == 21)
0212             scale = gSplittingScale(psystem, pr, pe);
0213           // quark emitting a gluon (or a photon)
0214           else if (abs(e[iRadBef].id()) <= 5 && ((e[iEmt].id() == 21) && !vetoQED))
0215             scale = qSplittingScale(psystem, pr, pe);
0216           // other stuff (which we should not veto)
0217           else {
0218             scale = 0;
0219           }
0220         }
0221 
0222         // compare the current splitting scale to the correct resonance scale
0223         if (iResId == 6) {
0224           if (debug && scale > topresscale)
0225             cout << iResId << ": " << e[iRadBef].id() << " > " << e[iRadAft].id() << " + " << e[iEmt].id() << "; "
0226                  << scale << endl;
0227           return doVetoFSR(scale > topresscale, scale);
0228         } else if (iResId == -6) {
0229           if (debug && scale > atopresscale)
0230             cout << iResId << ": " << e[iRadBef].id() << " > " << e[iRadAft].id() << " + " << e[iEmt].id() << "; "
0231                  << scale << endl;
0232           return doVetoFSR(scale > atopresscale, scale);
0233         } else if (iResId == 24) {
0234           if (debug && scale > wpresscale)
0235             cout << iResId << ": " << e[iRadBef].id() << " > " << e[iRadAft].id() << " + " << e[iEmt].id() << "; "
0236                  << scale << endl;
0237           return doVetoFSR(scale > wpresscale, scale);
0238         } else if (iResId == -24) {
0239           if (debug && scale > wmresscale)
0240             cout << iResId << ": " << e[iRadBef].id() << " > " << e[iRadAft].id() << " + " << e[iEmt].id() << "; "
0241                  << scale << endl;
0242           return doVetoFSR(scale > wmresscale, scale);
0243         } else {
0244           loggerPtr->errorMsg("PowhegHooksBB4L::doVetoFSREmissio", "Unimplemented case");
0245           exit(-1);
0246         }
0247       }
0248       // In CMSSW, the production process veto is done in EmissionVetoHook1.cc
0249       // so for events outside resonance, nothing needs to be done here
0250       else {
0251         return false;
0252       }
0253     }
0254 
0255     inline bool doVetoFSR(bool condition, double scale) {
0256       if (!vetoAllRadtypes && radtype == 2)
0257         return false;
0258       if (condition) {
0259         nInResonanceFSRveto++;
0260         return true;
0261       }
0262       return false;
0263     }
0264 
0265     //--- SCALE RESONANCE HOOK -------------------------------------------------
0266     // called before each resonance decay shower
0267     inline bool canSetResonanceScale() { return scaleResonanceVeto; }
0268     // if the resonance is the (anti)top or W+/W- set the scale to:
0269     // - if radtype=2 (remnant): resonance virtuality
0270     // - if radtype=1 (btilde):
0271     //  - (a)topresscale/wp(m)resscale for tops and Ws
0272     //  - a large number otherwise
0273     // if is not the top, set it to a big number
0274     inline double scaleResonance(int iRes, const Event &e) {
0275       if (!vetoAllRadtypes && radtype == 2)
0276         return sqrt(e[iRes].m2Calc());
0277       else {
0278         if (e[iRes].id() == 6)
0279           return topresscale;
0280         else if (e[iRes].id() == -6)
0281           return atopresscale;
0282         else if (e[iRes].id() == 24)
0283           return wpresscale;
0284         else if (e[iRes].id() == 24)
0285           return wmresscale;
0286         else
0287           return 1e30;
0288       }
0289     }
0290 
0291     //--- Internal helper functions --------------------------------------------
0292     // Calculates the scale of the hardest emission from within the resonance system
0293     // translated by Markus Seidel modified by Tomas Jezo
0294     inline double findresscale(const int iRes, const Event &event) {
0295       // return large scale if the resonance position is ill defined
0296       if (iRes < 0)
0297         return 1e30;
0298 
0299       // get number of resonance decay products
0300       int nDau = event[iRes].daughterList().size();
0301 
0302       // iRes is not decayed, return high scale equivalent to
0303       // unrestricted shower
0304       if (nDau == 0) {
0305         return 1e30;
0306       }
0307       // iRes did not radiate, this means that POWHEG pt scale has
0308       // evolved all the way down to pTmin
0309       else if (nDau < 3) {
0310         return pTmin;
0311       }
0312       // iRes is a (anti-)top quark
0313       else if (abs(event[iRes].id()) == 6) {
0314         // find top daughters
0315         int idw = -1, idb = -1, idg = -1;
0316         for (int i = 0; i < nDau; i++) {
0317           int iDau = event[iRes].daughterList()[i];
0318           if (abs(event[iDau].id()) == 24)
0319             idw = iDau;
0320           if (abs(event[iDau].id()) == 5)
0321             idb = iDau;
0322           if (abs(event[iDau].id()) == 21)
0323             idg = iDau;
0324         }
0325 
0326         // Get daughter 4-vectors in resonance frame
0327         Vec4 pw(event[idw].p());
0328         pw.bstback(event[iRes].p());
0329         Vec4 pb(event[idb].p());
0330         pb.bstback(event[iRes].p());
0331         Vec4 pg(event[idg].p());
0332         pg.bstback(event[iRes].p());
0333 
0334         // Calculate scale and return it
0335         return sqrt(2 * pg * pb * pg.e() / pb.e());
0336       }
0337       // iRes is a W+(-) boson
0338       else if (abs(event[iRes].id()) == 24) {
0339         // Find W daughters
0340         int idq = -1, ida = -1, idg = -1;
0341         for (int i = 0; i < nDau; i++) {
0342           int iDau = event[iRes].daughterList()[i];
0343           if (event[iDau].id() == 21)
0344             idg = iDau;
0345           else if (event[iDau].id() > 0)
0346             idq = iDau;
0347           else if (event[iDau].id() < 0)
0348             ida = iDau;
0349         }
0350 
0351         // Get daughter 4-vectors in resonance frame
0352         Vec4 pq(event[idq].p());
0353         pq.bstback(event[iRes].p());
0354         Vec4 pa(event[ida].p());
0355         pa.bstback(event[iRes].p());
0356         Vec4 pg(event[idg].p());
0357         pg.bstback(event[iRes].p());
0358 
0359         // Calculate scale
0360         Vec4 pw = pq + pa + pg;
0361         double q2 = pw * pw;
0362         double csi = 2 * pg.e() / sqrt(q2);
0363         double yq = 1 - pg * pq / (pg.e() * pq.e());
0364         double ya = 1 - pg * pa / (pg.e() * pa.e());
0365         // and return it
0366         return sqrt(min(1 - yq, 1 - ya) * pow2(csi) * q2 / 2);
0367       }
0368       // in any other case just return a high scale equivalent to
0369       // unrestricted shower
0370       return 1e30;
0371     }
0372 
0373     // The following routine will match daughters of particle `e[iparticle]` to an expected pattern specified via the list of expected particle PDG ID's `ids`,
0374     // id wildcard is specified as 0 if match is obtained, the positions and the momenta of these particles are returned in vectors `positions` and `momenta`
0375     // respectively
0376     // if exitOnExtraLegs==true, it will exit if the decay has more particles than expected, but not less
0377     inline bool match_decay(int iparticle,
0378                             const Event &e,
0379                             const vector<int> &ids,
0380                             vector<int> &positions,
0381                             vector<Vec4> &momenta,
0382                             bool exitOnExtraLegs = true) {
0383       // compare sizes
0384       if (e[iparticle].daughterList().size() != ids.size()) {
0385         if (exitOnExtraLegs && e[iparticle].daughterList().size() > ids.size()) {
0386           cout << "extra leg" << endl;
0387           exit(-1);
0388         }
0389         return false;
0390       }
0391       // compare content
0392       for (unsigned i = 0; i < e[iparticle].daughterList().size(); i++) {
0393         int di = e[iparticle].daughterList()[i];
0394         if (ids[i] != 0 && e[di].id() != ids[i])
0395           return false;
0396       }
0397       // reset the positions and momenta vectors (because they may be reused)
0398       positions.clear();
0399       momenta.clear();
0400       // construct the array of momenta
0401       for (unsigned i = 0; i < e[iparticle].daughterList().size(); i++) {
0402         int di = e[iparticle].daughterList()[i];
0403         positions.push_back(di);
0404         momenta.push_back(e[di].p());
0405       }
0406       return true;
0407     }
0408 
0409     inline double qSplittingScale(Vec4 pt, Vec4 p1, Vec4 p2) {
0410       p1.bstback(pt);
0411       p2.bstback(pt);
0412       return sqrt(2 * p1 * p2 * p2.e() / p1.e());
0413     }
0414 
0415     inline double gSplittingScale(Vec4 pt, Vec4 p1, Vec4 p2) {
0416       p1.bstback(pt);
0417       p2.bstback(pt);
0418       return sqrt(2 * p1 * p2 * p1.e() * p2.e() / (pow(p1.e() + p2.e(), 2)));
0419     }
0420 
0421     // Routines to calculate the pT (according to pTdefMode) in a FS splitting:
0422     // i (radiator before) -> j (emitted after) k (radiator after)
0423     // For the Pythia pT definition, a recoiler (after) must be specified.
0424     // (INSPIRED BY pythia8F77_31.cc double pTpythia)
0425     inline double pTpythia(const Event &e, int RadAfterBranch, int EmtAfterBranch, int RecAfterBranch) {
0426       // Convenient shorthands for later
0427       Vec4 radVec = e[RadAfterBranch].p();
0428       Vec4 emtVec = e[EmtAfterBranch].p();
0429       Vec4 recVec = e[RecAfterBranch].p();
0430       int radID = e[RadAfterBranch].id();
0431 
0432       // Calculate virtuality of splitting
0433       Vec4 Q(radVec + emtVec);
0434       double Qsq = Q.m2Calc();
0435 
0436       // Mass term of radiator
0437       double m2Rad = (abs(radID) >= 4 && abs(radID) < 7) ? pow2(particleDataPtr->m0(radID)) : 0.;
0438 
0439       // z values for FSR
0440       double z, pTnow;
0441       // Construct 2 -> 3 variables
0442       Vec4 sum = radVec + recVec + emtVec;
0443       double m2Dip = sum.m2Calc();
0444 
0445       double x1 = 2. * (sum * radVec) / m2Dip;
0446       double x3 = 2. * (sum * emtVec) / m2Dip;
0447       z = x1 / (x1 + x3);
0448       pTnow = z * (1. - z);
0449 
0450       // Virtuality
0451       pTnow *= (Qsq - m2Rad);
0452 
0453       if (pTnow < 0.) {
0454         cout << "Warning: pTpythia was negative" << endl;
0455         return -1.;
0456       } else
0457         return (sqrt(pTnow));
0458     }
0459 
0460     // Functions to return statistics about the veto
0461     inline int getNInResonanceFSRVeto() { return nInResonanceFSRveto; }
0462 
0463     //--------------------------------------------------------------------------
0464 
0465   private:
0466     // FSR emission veto flags
0467     bool vetoFSREmission, vetoQED;
0468     // scale Resonance veto flags
0469     double scaleResonanceVeto;
0470     // other flags
0471     bool debug;
0472     bool vetoDipoleFrame;
0473     bool pTpythiaVeto;
0474     double pTmin;
0475     bool vetoAllRadtypes;
0476     // veto counter
0477     int nInResonanceFSRveto;
0478     // internal: resonance scales
0479     double topresscale, atopresscale, wpresscale, wmresscale;
0480     int radtype;
0481   };
0482 
0483   //==========================================================================
0484 
0485 }  // end namespace Pythia8
0486 
0487 #endif  // end Pythia8_PowhegHooksBB4L_H