CMS 3D CMS Logo

PowhegHooksBB4L.h
Go to the documentation of this file.
1 // PowhegHooksBB4L.h
2 // Rewritten by T. Jezo in 2021. With various contributions from S. Ferrario
3 // Ravasio, B. Nachman, P. Nason and M. Seidel. Inspired by
4 // ttb_NLO_dec/main-PYTHIA8.f by P. Nason and E. Re and by PowhegHooks.h by R.
5 // Corke.
6 //
7 // Adapted for CMSSW by Laurids Jeppe.
8 
9 // # Introduction
10 //
11 // This hook is intended for use together with POWHEG-BOX-RES/b_bbar_4l NLO LHE
12 // events. This also includes events in which one of the W bosons was
13 // re-decayed hadronically. (Note that LHE format version larger than 3 may not
14 // require this hook).
15 //
16 // The hook inherits from PowhegHooks and as such it indirectly implements the
17 // following:
18 // - doVetoMPIStep
19 // - doVetoISREmission
20 // - doVetoMPIEmission
21 // and it overloads:
22 // - doVetoFSREmission, which works as follows (if POWHEG:veto==1):
23 // - if inResonance==true it vetoes all the emission that is harder than
24 // the scale of its parent (anti-)top quark or W^+(-)
25 // - if inResonance==false, it calls PowhegHooks::doVetoISREmission
26 // and it also implements:
27 // - doVetoProcessLevel, which is never used for vetoing (i.e. it always
28 // returns false). Instead it is used for the calculation of reconance scales
29 // using LHE kinematics.
30 //
31 // This version of the hooks is only suitable for use with fully compatible
32 // POWHEG-BOX Les Houches readers (such the one in main-PYTHIA82-lhef but
33 // not the one in main31.cc.)
34 //
35 //
36 // # Basic use
37 //
38 // In order to use this hook you must replace all the declarations and
39 // constructor calls of PowhegHooks to PowhegHooksBB4L:
40 //
41 // PowhegHooks *powhegHooks; -> PowhegHooksBB4L *powhegHooks;
42 // *powhegHooks = new PowhegHooks(); -> *powhegHooks = new PowhegHooksBB4L();
43 //
44 // In order to switch it on set POWHEG:veto = 1 and
45 // POWHEG:bb4l:FSREmission:veto = 1. This will lead to a veto in ISR, FSR and
46 // MPI steps of pythia as expected using PowhegHooks in all the cases other than
47 // the case of FSR emission in resonance decay. Within resonance decays
48 // PowhegHooksBB4L takes over the control.
49 //
50 // Furthermore, this hook can also be used standalone without PowhegHooks, i.e.
51 // only the FSR emission from resonances will be vetoed (the default use in
52 // 1801.03944 and 1906.09166). In order to do that set
53 // POWHEG:bb4l:FSREmission:veto = 1 and POWHEG:veto = 0. Note that the this is
54 // not recommended for comparing against data but because it is easier to
55 // interpret it is often done in theoretical studies.
56 //
57 // Note that this version of the hook relies on the event "radtype" (1 for
58 // btilde, 2 for remnant) to be set by an external program, such as
59 // main-PYTHIA82-lhef in the radtype_ common block.
60 // There also exists a version of this hook in which the event "radtype" is
61 // read in from the .lhe file using pythia built in functionality. You need
62 // that version if you want to use this hook with main31.cc.
63 //
64 //
65 // # Expert use
66 //
67 // This hook also implements an alternative veto procedure which allows to
68 // assign a "SCALUP" type of scale to a resonance using the scaleResonance
69 // method. This is a much simpler veto but it is also clearly inferior as
70 // compared to the one implemented using the doVetoFSREmission method because
71 // the definition of the scale of the emission does not match the
72 // POWHEG-BOX-RES definition. Nevertheless, it can be activated using
73 // POWHEG:bb4l:ScaleResonance:veto = 1. Additionally one MUST switch off the
74 // other veto by calling on POWHEG:bb4l:FSREmission:veto = 0.
75 //
76 // The following settings are at the disposal of the user to control the
77 // behaviour of the hook
78 // - On/off switches for the veto:
79 // - POWHEG:bb4l:FSREmission:veto
80 // on/off switch for the default veto based on doFSREmission
81 // - POWHEG:bb4l:ScaleResonance:veto
82 // on/off switch for the alternative veto based on scaleResonance (only
83 // for expert users)
84 // - Important settings:
85 // - POWHEG:bb4l:ptMinVeto: MUST be set to the same value as the
86 // corresponding flag in POWHEG-BOX-RES
87 // - Alternatives for scale calculations
88 // - default: emission scale is calculated using POWHEG definitions and in
89 // the resonance rest frame
90 // - POWHEG:bb4l:FSREmission:vetoDipoleFrame: emission scale is calculated
91 // using POWHEG definitions in the dipole frame
92 // - POWHEG:bb4l:FSREmission:pTpythiaVeto: emission scale is calculated
93 // using Pythia definitions
94 // - Other flags:
95 // - POWHEG:bb4l:FSREmission:vetoQED: decides whether or not QED emission
96 // off quarks should also be vetoed (not implemented in the case of
97 // the ScaleResonance:veto)
98 // - POWHEG:bb4l:DEBUG: enables debug printouts on standard output
99 
100 #ifndef Pythia8_PowhegHooksBB4L_H
101 #define Pythia8_PowhegHooksBB4L_H
102 
103 #include "Pythia8/Pythia.h"
104 #include <cassert>
105 
106 namespace Pythia8 {
107 
108  class PowhegHooksBB4L : public UserHooks {
109  public:
111  ~PowhegHooksBB4L() { std::cout << "Number of FSR vetoed in BB4l = " << nInResonanceFSRveto << std::endl; }
112 
113  //--- Initialization -------------------------------------------------------
114  bool initAfterBeams() {
115  // initialize settings of this class
116  vetoFSREmission = settingsPtr->flag("POWHEG:bb4l:FSREmission:veto");
117  vetoDipoleFrame = settingsPtr->flag("POWHEG:bb4l:FSREmission:vetoDipoleFrame");
118  pTpythiaVeto = settingsPtr->flag("POWHEG:bb4l:FSREmission:pTpythiaVeto");
119  vetoQED = settingsPtr->flag("POWHEG:bb4l:FSREmission:vetoQED");
120  scaleResonanceVeto = settingsPtr->flag("POWHEG:bb4l:ScaleResonance:veto");
121  debug = settingsPtr->flag("POWHEG:bb4l:DEBUG");
122  pTmin = settingsPtr->parm("POWHEG:bb4l:pTminVeto");
123  vetoAllRadtypes = settingsPtr->flag("POWHEG:bb4l:vetoAllRadtypes");
125  return true;
126  }
127 
128  //--- PROCESS LEVEL HOOK ---------------------------------------------------
129  // This hook gets triggered for each event before the shower starts, i.e. at
130  // the LHE level. We use it to calculate the scales of resonances.
131  inline bool canVetoProcessLevel() { return true; }
132  inline bool doVetoProcessLevel(Event &e) {
133  // extract the radtype from the event comment
134  stringstream ss;
135  // use eventattribute as comments not filled when using edm input
136  ss << infoPtr->getEventAttribute("#rwgt");
137  string temp;
138  ss >> temp >> radtype;
139  assert(temp == "#rwgt");
140  // we only calculate resonance scales for btilde events (radtype==1)
141  // remnant events are not vetoed
142  if (!vetoAllRadtypes && radtype == 2)
143  return false;
144  // find last top and the last anti-top in the record
145  int i_top = -1, i_atop = -1, i_wp = -1, i_wm = -1;
146  for (int i = 0; i < e.size(); i++) {
147  if (e[i].id() == 6)
148  i_top = i;
149  if (e[i].id() == -6)
150  i_atop = i;
151  if (e[i].id() == 24)
152  i_wp = i;
153  if (e[i].id() == -24)
154  i_wm = i;
155  }
156  // if found calculate the resonance scale
157  topresscale = findresscale(i_top, e);
158  // similarly for anti-top
159  atopresscale = findresscale(i_atop, e);
160  // and for W^+ and W^-
161  wpresscale = findresscale(i_wp, e);
162  wmresscale = findresscale(i_wm, e);
163 
164  // do not veto, ever
165  return false;
166  }
167 
168  //--- FSR EMISSION LEVEL HOOK ----------------------------------------------
169  // This hook gets triggered everytime the parton shower attempts to attach
170  // a FSR emission.
171  inline bool canVetoFSREmission() { return vetoFSREmission; }
172  inline bool doVetoFSREmission(int sizeOld, const Event &e, int iSys, bool inResonance) {
173  // FSR VETO INSIDE THE RESONANCE (if it is switched on)
174  if (inResonance && vetoFSREmission) {
175  // get the participants of the splitting: the recoiler, the radiator and the emitted
176  int iRecAft = e.size() - 1;
177  int iEmt = e.size() - 2;
178  int iRadAft = e.size() - 3;
179  int iRadBef = e[iEmt].mother1();
180 
181  // find the resonance the radiator originates from
182  int iRes = e[iRadBef].mother1();
183  while (iRes > 0 && (abs(e[iRes].id()) != 6 && abs(e[iRes].id()) != 24)) {
184  iRes = e[iRes].mother1();
185  }
186  if (iRes == 0) {
187  infoPtr->errorMsg(
188  "Warning in PowhegHooksBB4L::doVetoFSREmission: emission in resonance not from the top quark or from the "
189  "W boson, not vetoing");
190  return doVetoFSR(false, 0);
191  }
192  int iResId = e[iRes].id();
193 
194  // calculate the scale of the emission
195  double scale;
196  //using pythia pT definition ...
197  if (pTpythiaVeto)
198  scale = pTpythia(e, iRadAft, iEmt, iRecAft);
199  //.. or using POWHEG pT definition
200  else {
201  Vec4 pr(e[iRadAft].p()), pe(e[iEmt].p()), pres(e[iRes].p()), prec(e[iRecAft].p()), psystem;
202  // The computation of the POWHEG pT can be done in the top rest frame or in the diple one.
203  // pdipole = pemt +prec +prad (after the emission)
204  // For the first emission off the top resonance pdipole = pw +pb (before the emission) = ptop
205  if (vetoDipoleFrame)
206  psystem = pr + pe + prec;
207  else
208  psystem = pres;
209 
210  // gluon splitting into two partons
211  if (e[iRadBef].id() == 21)
212  scale = gSplittingScale(psystem, pr, pe);
213  // quark emitting a gluon (or a photon)
214  else if (abs(e[iRadBef].id()) <= 5 && ((e[iEmt].id() == 21) && !vetoQED))
215  scale = qSplittingScale(psystem, pr, pe);
216  // other stuff (which we should not veto)
217  else {
218  scale = 0;
219  }
220  }
221 
222  // compare the current splitting scale to the correct resonance scale
223  if (iResId == 6) {
224  if (debug && scale > topresscale)
225  cout << iResId << ": " << e[iRadBef].id() << " > " << e[iRadAft].id() << " + " << e[iEmt].id() << "; "
226  << scale << endl;
227  return doVetoFSR(scale > topresscale, scale);
228  } else if (iResId == -6) {
229  if (debug && scale > atopresscale)
230  cout << iResId << ": " << e[iRadBef].id() << " > " << e[iRadAft].id() << " + " << e[iEmt].id() << "; "
231  << scale << endl;
232  return doVetoFSR(scale > atopresscale, scale);
233  } else if (iResId == 24) {
234  if (debug && scale > wpresscale)
235  cout << iResId << ": " << e[iRadBef].id() << " > " << e[iRadAft].id() << " + " << e[iEmt].id() << "; "
236  << scale << endl;
237  return doVetoFSR(scale > wpresscale, scale);
238  } else if (iResId == -24) {
239  if (debug && scale > wmresscale)
240  cout << iResId << ": " << e[iRadBef].id() << " > " << e[iRadAft].id() << " + " << e[iEmt].id() << "; "
241  << scale << endl;
242  return doVetoFSR(scale > wmresscale, scale);
243  } else {
244  infoPtr->errorMsg("Error in PowhegHooksBB4L::doVetoFSREmission: unimplemented case");
245  exit(-1);
246  }
247  }
248  // In CMSSW, the production process veto is done in EmissionVetoHook1.cc
249  // so for events outside resonance, nothing needs to be done here
250  else {
251  return false;
252  }
253  }
254 
255  inline bool doVetoFSR(bool condition, double scale) {
256  if (!vetoAllRadtypes && radtype == 2)
257  return false;
258  if (condition) {
260  return true;
261  }
262  return false;
263  }
264 
265  //--- SCALE RESONANCE HOOK -------------------------------------------------
266  // called before each resonance decay shower
267  inline bool canSetResonanceScale() { return scaleResonanceVeto; }
268  // if the resonance is the (anti)top or W+/W- set the scale to:
269  // - if radtype=2 (remnant): resonance virtuality
270  // - if radtype=1 (btilde):
271  // - (a)topresscale/wp(m)resscale for tops and Ws
272  // - a large number otherwise
273  // if is not the top, set it to a big number
274  inline double scaleResonance(int iRes, const Event &e) {
275  if (!vetoAllRadtypes && radtype == 2)
276  return sqrt(e[iRes].m2Calc());
277  else {
278  if (e[iRes].id() == 6)
279  return topresscale;
280  else if (e[iRes].id() == -6)
281  return atopresscale;
282  else if (e[iRes].id() == 24)
283  return wpresscale;
284  else if (e[iRes].id() == 24)
285  return wmresscale;
286  else
287  return 1e30;
288  }
289  }
290 
291  //--- Internal helper functions --------------------------------------------
292  // Calculates the scale of the hardest emission from within the resonance system
293  // translated by Markus Seidel modified by Tomas Jezo
294  inline double findresscale(const int iRes, const Event &event) {
295  // return large scale if the resonance position is ill defined
296  if (iRes < 0)
297  return 1e30;
298 
299  // get number of resonance decay products
300  int nDau = event[iRes].daughterList().size();
301 
302  // iRes is not decayed, return high scale equivalent to
303  // unrestricted shower
304  if (nDau == 0) {
305  return 1e30;
306  }
307  // iRes did not radiate, this means that POWHEG pt scale has
308  // evolved all the way down to pTmin
309  else if (nDau < 3) {
310  return pTmin;
311  }
312  // iRes is a (anti-)top quark
313  else if (abs(event[iRes].id()) == 6) {
314  // find top daughters
315  int idw = -1, idb = -1, idg = -1;
316  for (int i = 0; i < nDau; i++) {
317  int iDau = event[iRes].daughterList()[i];
318  if (abs(event[iDau].id()) == 24)
319  idw = iDau;
320  if (abs(event[iDau].id()) == 5)
321  idb = iDau;
322  if (abs(event[iDau].id()) == 21)
323  idg = iDau;
324  }
325 
326  // Get daughter 4-vectors in resonance frame
327  Vec4 pw(event[idw].p());
328  pw.bstback(event[iRes].p());
329  Vec4 pb(event[idb].p());
330  pb.bstback(event[iRes].p());
331  Vec4 pg(event[idg].p());
332  pg.bstback(event[iRes].p());
333 
334  // Calculate scale and return it
335  return sqrt(2 * pg * pb * pg.e() / pb.e());
336  }
337  // iRes is a W+(-) boson
338  else if (abs(event[iRes].id()) == 24) {
339  // Find W daughters
340  int idq = -1, ida = -1, idg = -1;
341  for (int i = 0; i < nDau; i++) {
342  int iDau = event[iRes].daughterList()[i];
343  if (event[iDau].id() == 21)
344  idg = iDau;
345  else if (event[iDau].id() > 0)
346  idq = iDau;
347  else if (event[iDau].id() < 0)
348  ida = iDau;
349  }
350 
351  // Get daughter 4-vectors in resonance frame
352  Vec4 pq(event[idq].p());
353  pq.bstback(event[iRes].p());
354  Vec4 pa(event[ida].p());
355  pa.bstback(event[iRes].p());
356  Vec4 pg(event[idg].p());
357  pg.bstback(event[iRes].p());
358 
359  // Calculate scale
360  Vec4 pw = pq + pa + pg;
361  double q2 = pw * pw;
362  double csi = 2 * pg.e() / sqrt(q2);
363  double yq = 1 - pg * pq / (pg.e() * pq.e());
364  double ya = 1 - pg * pa / (pg.e() * pa.e());
365  // and return it
366  return sqrt(min(1 - yq, 1 - ya) * pow2(csi) * q2 / 2);
367  }
368  // in any other case just return a high scale equivalent to
369  // unrestricted shower
370  return 1e30;
371  }
372 
373  // 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`,
374  // 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`
375  // respectively
376  // if exitOnExtraLegs==true, it will exit if the decay has more particles than expected, but not less
377  inline bool match_decay(int iparticle,
378  const Event &e,
379  const vector<int> &ids,
380  vector<int> &positions,
381  vector<Vec4> &momenta,
382  bool exitOnExtraLegs = true) {
383  // compare sizes
384  if (e[iparticle].daughterList().size() != ids.size()) {
385  if (exitOnExtraLegs && e[iparticle].daughterList().size() > ids.size()) {
386  cout << "extra leg" << endl;
387  exit(-1);
388  }
389  return false;
390  }
391  // compare content
392  for (unsigned i = 0; i < e[iparticle].daughterList().size(); i++) {
393  int di = e[iparticle].daughterList()[i];
394  if (ids[i] != 0 && e[di].id() != ids[i])
395  return false;
396  }
397  // reset the positions and momenta vectors (because they may be reused)
398  positions.clear();
399  momenta.clear();
400  // construct the array of momenta
401  for (unsigned i = 0; i < e[iparticle].daughterList().size(); i++) {
402  int di = e[iparticle].daughterList()[i];
403  positions.push_back(di);
404  momenta.push_back(e[di].p());
405  }
406  return true;
407  }
408 
409  inline double qSplittingScale(Vec4 pt, Vec4 p1, Vec4 p2) {
410  p1.bstback(pt);
411  p2.bstback(pt);
412  return sqrt(2 * p1 * p2 * p2.e() / p1.e());
413  }
414 
415  inline double gSplittingScale(Vec4 pt, Vec4 p1, Vec4 p2) {
416  p1.bstback(pt);
417  p2.bstback(pt);
418  return sqrt(2 * p1 * p2 * p1.e() * p2.e() / (pow(p1.e() + p2.e(), 2)));
419  }
420 
421  // Routines to calculate the pT (according to pTdefMode) in a FS splitting:
422  // i (radiator before) -> j (emitted after) k (radiator after)
423  // For the Pythia pT definition, a recoiler (after) must be specified.
424  // (INSPIRED BY pythia8F77_31.cc double pTpythia)
425  inline double pTpythia(const Event &e, int RadAfterBranch, int EmtAfterBranch, int RecAfterBranch) {
426  // Convenient shorthands for later
427  Vec4 radVec = e[RadAfterBranch].p();
428  Vec4 emtVec = e[EmtAfterBranch].p();
429  Vec4 recVec = e[RecAfterBranch].p();
430  int radID = e[RadAfterBranch].id();
431 
432  // Calculate virtuality of splitting
433  Vec4 Q(radVec + emtVec);
434  double Qsq = Q.m2Calc();
435 
436  // Mass term of radiator
437  double m2Rad = (abs(radID) >= 4 && abs(radID) < 7) ? pow2(particleDataPtr->m0(radID)) : 0.;
438 
439  // z values for FSR
440  double z, pTnow;
441  // Construct 2 -> 3 variables
442  Vec4 sum = radVec + recVec + emtVec;
443  double m2Dip = sum.m2Calc();
444 
445  double x1 = 2. * (sum * radVec) / m2Dip;
446  double x3 = 2. * (sum * emtVec) / m2Dip;
447  z = x1 / (x1 + x3);
448  pTnow = z * (1. - z);
449 
450  // Virtuality
451  pTnow *= (Qsq - m2Rad);
452 
453  if (pTnow < 0.) {
454  cout << "Warning: pTpythia was negative" << endl;
455  return -1.;
456  } else
457  return (sqrt(pTnow));
458  }
459 
460  // Functions to return statistics about the veto
462 
463  //--------------------------------------------------------------------------
464 
465  private:
466  // FSR emission veto flags
468  // scale Resonance veto flags
470  // other flags
471  bool debug;
474  double pTmin;
476  // veto counter
478  // internal: resonance scales
480  int radtype;
481  };
482 
483  //==========================================================================
484 
485 } // end namespace Pythia8
486 
487 #endif // end Pythia8_PowhegHooksBB4L_H
size
Write out results.
bool doVetoFSREmission(int sizeOld, const Event &e, int iSys, bool inResonance)
double pTpythia(const Event &e, int RadAfterBranch, int EmtAfterBranch, int RecAfterBranch)
double qSplittingScale(Vec4 pt, Vec4 p1, Vec4 p2)
assert(be >=bs)
double scaleResonance(int iRes, const Event &e)
bool doVetoProcessLevel(Event &e)
T sqrt(T t)
Definition: SSEVec.h:19
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
ExtVec< T, 4 > Vec4
Definition: ExtVec.h:64
double findresscale(const int iRes, const Event &event)
double gSplittingScale(Vec4 pt, Vec4 p1, Vec4 p2)
bool match_decay(int iparticle, const Event &e, const vector< int > &ids, vector< int > &positions, vector< Vec4 > &momenta, bool exitOnExtraLegs=true)
bool doVetoFSR(bool condition, double scale)
Power< A, B >::type pow(const A &a, const B &b)
Definition: Power.h:29
Definition: event.py:1
def exit(msg="")