CMS 3D CMS Logo

PowhegHooksBB4L.h
Go to the documentation of this file.
1 // PowhegHooksBB4L.h
2 // Copyright (C) 2017 Silvia Ferrario Ravasio, Tomas Jezo, Paolo Nason, Markus Seidel
3 // inspired by PowhegHooks.h by Richard Corke
4 // adjusted to work with EmissionVetoHook1 in CMSSW by Alexander Grohsjean
5 
6 #ifndef Pythia8_PowhegHooksBB4L_H
7 #define Pythia8_PowhegHooksBB4L_H
8 
9 // Includes
10 #include "Pythia8/Pythia.h"
11 #include <cassert>
12 struct {
13  int radtype;
14 } radtype_;
15 
16 namespace Pythia8 {
17 
18  class PowhegHooksBB4L : public UserHooks {
19  public:
20  //--- Constructor and destructor -------------------------------------------
22  ~PowhegHooksBB4L() override { std::cout << "Number of FSR vetoed in BB4l = " << nFSRvetoBB4l << std::endl; }
23 
24  //--- Initialization -----------------------------------------------------------------------
25  bool initAfterBeams() override {
26  // settings of this class
27  vetoFSREmission = settingsPtr->flag("POWHEG:bb4l:FSREmission:veto");
28  onlyDistance1 = settingsPtr->flag("POWHEG:bb4l:FSREmission:onlyDistance1");
29  dryRunFSR = settingsPtr->flag("POWHEG:bb4l:FSREmission:dryRun");
30  vetoAtPL = settingsPtr->flag("POWHEG:bb4l:FSREmission:vetoAtPL");
31  vetoQED = settingsPtr->flag("POWHEG:bb4l:FSREmission:vetoQED");
32  vetoPartonLevel = settingsPtr->flag("POWHEG:bb4l:PartonLevel:veto");
33  excludeFSRConflicting = settingsPtr->flag("POWHEG:bb4l:PartonLevel:excludeFSRConflicting");
34  debug = settingsPtr->flag("POWHEG:bb4l:DEBUG");
35  scaleResonanceVeto = settingsPtr->flag("POWHEG:bb4l:ScaleResonance:veto");
36  vetoDipoleFrame = settingsPtr->flag("POWHEG:bb4l:FSREmission:vetoDipoleFrame");
37  pTpythiaVeto = settingsPtr->flag("POWHEG:bb4l:FSREmission:pTpythiaVeto");
38  //vetoProduction = (settingsPtr->mode("POWHEG:veto")==1);
39  pTmin = settingsPtr->parm("POWHEG:bb4l:pTminVeto");
40  return true;
41  }
42 
43  //--- PROCESS LEVEL HOOK ---------------------------------------------------
44 
45  // called at the LHE level
46  inline bool canVetoProcessLevel() override { return true; }
47  inline bool doVetoProcessLevel(Event &e) override {
48  // extract the radtype from the event comment
49  stringstream ss;
50  // use eventattribute as comments not filled when using edm input
51  //ss << infoPtr->getEventComments();
52  ss << infoPtr->getEventAttribute("#rwgt");
53  string temp;
54  ss >> temp >> radtype_.radtype;
55  assert(temp == "#rwgt");
56 
57  // find last top and the last anti-top in the record
58  int i_top = -1, i_atop = -1;
59  for (int i = 0; i < e.size(); i++) {
60  if (e[i].id() == 6)
61  i_top = i;
62  if (e[i].id() == -6)
63  i_atop = i;
64  }
65  if (i_top != -1)
66  topresscale = findresscale(i_top, e);
67  else
68  topresscale = 1e30;
69  if (i_top != -1)
70  atopresscale = findresscale(i_atop, e);
71  else
72  atopresscale = 1e30;
73  // initialize stuff
74  doVetoFSRInit();
75  // do not veto, ever
76  return false;
77  }
78 
79  //--- PARTON LEVEL HOOK ----------------------------------------------------
80 
81  // called after shower
82  bool retryPartonLevel() override { return vetoPartonLevel || vetoAtPL; }
83  inline bool canVetoPartonLevel() override { return vetoPartonLevel || vetoAtPL; }
84  inline bool doVetoPartonLevel(const Event &e) override {
85  if (radtype_.radtype == 2)
86  return false;
87  if (debug) {
88  if (dryRunFSR && wouldVetoFsr) {
90  cout << "FSRdecScale = " << vetoDecScale << ", PLdecScale = " << scale << ", ratio = " << vetoDecScale / scale
91  << endl;
92  }
93  }
94  if (vetoPartonLevel) {
95  double topdecscale = getdechardness(1, e);
96  double atopdecscale = getdechardness(-1, e);
97  if ((topdecscale > topresscale) || (atopdecscale > atopresscale)) {
98  //if(dryRunFSR && ! wouldVetoFsr) mydatacontainer_.excludeEvent = excludeFSRConflicting?1:0;
99  return true;
100  } else
101  //if(dryRunFSR && wouldVetoFsr) mydatacontainer_.excludeEvent = excludeFSRConflicting?1:0;
102  return false;
103  }
104  if (vetoAtPL) {
105  if (dryRunFSR && wouldVetoFsr)
106  return true;
107  else
108  return false;
109  }
110  return false;
111  }
112 
113  //--- FSR EMISSION LEVEL HOOK ----------------------------------------------
114 
115  // FSR veto: this should be true if we want PowhegHooksBB4l veto in decay
116  // OR PowhegHooks veto in production. (The virtual method
117  // PowhegHooks::canVetoFSREmission has been replaced by
118  // PowhegHooksBB4L::canVetoFSREmission, so FSR veto in production
119  // must be handled here. ISR and MPI veto are instead still
120  // handled by PowhegHooks.)
121  inline bool canVetoFSREmission() override { return vetoFSREmission; } // || vetoProduction; }
122  inline bool doVetoFSREmission(int sizeOld, const Event &e, int iSys, bool inResonance) override {
124  //VETO INSIDE THE RESONANCE //
126  if (inResonance && vetoFSREmission) {
127  int iRecAft = e.size() - 1;
128  int iEmt = e.size() - 2;
129  int iRadAft = e.size() - 3;
130  int iRadBef = e[iEmt].mother1();
131 
132  // find the top resonance the radiator originates from
133  int iTop = e[iRadBef].mother1();
134  int distance = 1;
135  while (abs(e[iTop].id()) != 6 && iTop > 0) {
136  iTop = e[iTop].mother1();
137  distance++;
138  }
139  if (iTop == 0) {
140  infoPtr->errorMsg(
141  "Warning in PowhegHooksBB4L::doVetoFSREmission: emission in resonance not from top quark, not vetoing");
142  return doVetoFSR(false, 0, 0);
143  //return false;
144  }
145  int iTopCharge = (e[iTop].id() > 0) ? 1 : -1;
146 
147  // calculate the scale of the emission
148  double scale;
149  //using pythia pT definition ...
150  if (pTpythiaVeto)
151  scale = pTpythia(e, iRadAft, iEmt, iRecAft);
152  //.. or using POWHEG pT definition
153  else {
154  Vec4 pr(e[iRadAft].p()), pe(e[iEmt].p()), pt(e[iTop].p()), prec(e[iRecAft].p()), psystem;
155  // The computation of the POWHEG pT can be done in the top rest frame or in the diple one.
156  // pdipole = pemt +prec +prad (after the emission)
157  // For the first emission off the top resonance pdipole = pw +pb (before the emission) = ptop
158  if (vetoDipoleFrame)
159  psystem = pr + pe + prec;
160  else
161  psystem = pt;
162 
163  // gluon splitting into two partons
164  if (e[iRadBef].id() == 21)
165  scale = gSplittingScale(psystem, pr, pe);
166  // quark emitting a gluon (or a photon)
167  else if (abs(e[iRadBef].id()) == 5 && ((e[iEmt].id() == 21) && !vetoQED))
168  scale = qSplittingScale(psystem, pr, pe);
169  // other stuff (which we should not veto)
170  else
171  scale = 0;
172  }
173 
174  if (iTopCharge > 0) {
175  if (onlyDistance1) {
176  if (debug && (distance == 1) && scale > topresscale && !wouldVetoFsr)
177  cout << e[iTop].id() << ": " << e[iRadBef].id() << " > " << e[iRadAft].id() << " + " << e[iEmt].id()
178  << "; " << scale << endl;
179  return doVetoFSR((distance == 1) && scale > topresscale, scale, iTopCharge);
180  } else {
181  if (debug && scale > topresscale && !wouldVetoFsr)
182  cout << e[iTop].id() << ": " << e[iRadBef].id() << " > " << e[iRadAft].id() << " + " << e[iEmt].id()
183  << "; " << scale << endl;
184  return doVetoFSR(scale > topresscale, scale, iTopCharge);
185  }
186  } else if (iTopCharge < 0) {
187  if (onlyDistance1) {
188  if (debug && (distance == 1) && scale > atopresscale && !wouldVetoFsr)
189  cout << e[iTop].id() << ": " << e[iRadBef].id() << " > " << e[iRadAft].id() << " + " << e[iEmt].id()
190  << "; " << scale << endl;
191  return doVetoFSR((distance == 1) && scale > atopresscale, scale, iTopCharge);
192  } else {
193  if (debug && scale > topresscale && !wouldVetoFsr)
194  cout << e[iTop].id() << ": " << e[iRadBef].id() << " > " << e[iRadAft].id() << " + " << e[iEmt].id()
195  << "; " << scale << endl;
196  return doVetoFSR(scale > atopresscale, scale, iTopCharge);
197  }
198  } else {
199  cout << "Bug in PohwgeHooksBB4l" << endl;
200  }
201  }
203  // VETO THE PRODUCTION PROCESS //
205  // covered by multiuserhook, i.e. need to turn on EV1
206  // else if(!inResonance && vetoProduction){
207  // return EmissionVetoHook1::doVetoFSREmission(sizeOld, e, iSys, inResonance);
208  // }
209 
210  return false;
211  }
212 
213  inline bool doVetoFSR(bool condition, double scale, int iTopCharge) {
214  if (radtype_.radtype == 2)
215  return false;
216  if (condition) {
217  if (!wouldVetoFsr) {
218  wouldVetoFsr = true;
220  vetoTopCharge = iTopCharge;
221  }
222  if (dryRunFSR)
223  return false;
224  else {
225  nFSRvetoBB4l++;
226  return true;
227  }
228  } else
229  return false;
230  }
231 
232  inline void doVetoFSRInit() {
233  wouldVetoFsr = false;
234  vetoDecScale = -1;
235  vetoTopCharge = 0;
236  }
237 
238  //--- SCALE RESONANCE HOOK -------------------------------------------------
239  // called before each resonance decay shower
240  inline bool canSetResonanceScale() override { return scaleResonanceVeto; }
241  // if the resonance is the (anti)top set the scale to:
242  // ---> (anti)top virtuality if radtype=2
243  // ---> (a)topresscale otherwise
244  // if is not the top, set it to a big number
245  inline double scaleResonance(int iRes, const Event &e) override {
246  if (e[iRes].id() == 6) {
247  if (radtype_.radtype == 2)
248  return sqrt(e[iRes].m2Calc());
249  else
250  return topresscale;
251  } else if (e[iRes].id() == -6) {
252  if (radtype_.radtype == 2)
253  return sqrt(e[iRes].m2Calc());
254  else
255  return atopresscale;
256  } else
257  return pow(10.0, 30.);
258  }
259 
260  //--- Internal helper functions --------------------------------------------
261 
262  // Calculates the scale of the hardest emission from within the resonance system
263  // translated by Markus Seidel modified by Tomas Jezo
264  inline double findresscale(const int iRes, const Event &event) {
265  double scale = 0.;
266 
267  int nDau = event[iRes].daughterList().size();
268 
269  if (nDau == 0) {
270  // No resonance found, set scale to high value
271  // Pythia will shower any MC generated resonance unrestricted
272  scale = 1e30;
273  } else if (nDau < 3) {
274  // No radiating resonance found
275  scale = pTmin;
276  } else if (abs(event[iRes].id()) == 6) {
277  // Find top daughters
278  int idw = -1, idb = -1, idg = -1;
279 
280  for (int i = 0; i < nDau; i++) {
281  int iDau = event[iRes].daughterList()[i];
282  if (abs(event[iDau].id()) == 24)
283  idw = iDau;
284  if (abs(event[iDau].id()) == 5)
285  idb = iDau;
286  if (abs(event[iDau].id()) == 21)
287  idg = iDau;
288  }
289 
290  // Get daughter 4-vectors in resonance frame
291  Vec4 pw(event[idw].p());
292  pw.bstback(event[iRes].p());
293 
294  Vec4 pb(event[idb].p());
295  pb.bstback(event[iRes].p());
296 
297  Vec4 pg(event[idg].p());
298  pg.bstback(event[iRes].p());
299 
300  // Calculate scale
301  scale = sqrt(2 * pg * pb * pg.e() / pb.e());
302  } else {
303  scale = 1e30;
304  }
305 
306  return scale;
307  }
308 
309  // 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`,
310  // 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`
311  // respectively
312  // if exitOnExtraLegs==true, it will exit if the decay has more particles than expected, but not less
313  inline bool match_decay(int iparticle,
314  const Event &e,
315  const vector<int> &ids,
316  vector<int> &positions,
317  vector<Vec4> &momenta,
318  bool exitOnExtraLegs = true) {
319  // compare sizes
320  if (e[iparticle].daughterList().size() != ids.size()) {
321  if (exitOnExtraLegs && e[iparticle].daughterList().size() > ids.size()) {
322  cout << "extra leg" << endl;
323  exit(-1);
324  }
325  return false;
326  }
327  // compare content
328  for (unsigned i = 0; i < e[iparticle].daughterList().size(); i++) {
329  int di = e[iparticle].daughterList()[i];
330  if (ids[i] != 0 && e[di].id() != ids[i])
331  return false;
332  }
333  // reset the positions and momenta vectors (because they may be reused)
334  positions.clear();
335  momenta.clear();
336  // construct the array of momenta
337  for (unsigned i = 0; i < e[iparticle].daughterList().size(); i++) {
338  int di = e[iparticle].daughterList()[i];
339  positions.push_back(di);
340  momenta.push_back(e[di].p());
341  }
342  return true;
343  }
344 
345  inline double qSplittingScale(Vec4 pt, Vec4 p1, Vec4 p2) {
346  p1.bstback(pt);
347  p2.bstback(pt);
348  return sqrt(2 * p1 * p2 * p2.e() / p1.e());
349  }
350 
351  inline double gSplittingScale(Vec4 pt, Vec4 p1, Vec4 p2) {
352  p1.bstback(pt);
353  p2.bstback(pt);
354  return sqrt(2 * p1 * p2 * p1.e() * p2.e() / (pow(p1.e() + p2.e(), 2)));
355  }
356 
357  // Routines to calculate the pT (according to pTdefMode) in a FS splitting:
358  // i (radiator before) -> j (emitted after) k (radiator after)
359  // For the Pythia pT definition, a recoiler (after) must be specified.
360  // (INSPIRED BY pythia8F77_31.cc double pTpythia)
361  inline double pTpythia(const Event &e, int RadAfterBranch, int EmtAfterBranch, int RecAfterBranch) {
362  // Convenient shorthands for later
363  Vec4 radVec = e[RadAfterBranch].p();
364  Vec4 emtVec = e[EmtAfterBranch].p();
365  Vec4 recVec = e[RecAfterBranch].p();
366  int radID = e[RadAfterBranch].id();
367 
368  // Calculate virtuality of splitting
369  Vec4 Q(radVec + emtVec);
370  double Qsq = Q.m2Calc();
371 
372  // Mass term of radiator
373  double m2Rad = (abs(radID) >= 4 && abs(radID) < 7) ? pow2(particleDataPtr->m0(radID)) : 0.;
374 
375  // z values for FSR
376  double z, pTnow;
377  // Construct 2 -> 3 variables
378  Vec4 sum = radVec + recVec + emtVec;
379  double m2Dip = sum.m2Calc();
380 
381  double x1 = 2. * (sum * radVec) / m2Dip;
382  double x3 = 2. * (sum * emtVec) / m2Dip;
383  z = x1 / (x1 + x3);
384  pTnow = z * (1. - z);
385 
386  // Virtuality
387  pTnow *= (Qsq - m2Rad);
388 
389  if (pTnow < 0.) {
390  cout << "Warning: pTpythia was negative" << endl;
391  return -1.;
392  } else
393  return (sqrt(pTnow));
394  }
395 
396  inline double getdechardness(int topcharge, const Event &e) {
397  int tid = 6 * topcharge, wid = 24 * topcharge, bid = 5 * topcharge, gid = 21, wildcard = 0;
398  // find last top in the record
399  int i_top = -1;
400  Vec4 p_top, p_b, p_g, p_g1, p_g2;
401  for (int i = 0; i < e.size(); i++)
402  if (e[i].id() == tid) {
403  i_top = i;
404  p_top = e[i].p();
405  }
406  if (i_top == -1)
407  return -1.0;
408 
409  // summary of cases
410  // 1.) t > W b
411  // a.) b > 3 ... error
412  // b.) b > b g ... h = sqrt(2*p_g*p_b*p_g.e()/p_b.e())
413  // c.) b > other ... h = -1
414  // return h
415  // 2.) t > W b g
416  // a.) b > 3 ... error
417  // b.) b > b g ... h1 = sqrt(2*p_g*p_b*p_g.e()/p_b.e())
418  // c.) b > other ... h1 = -1
419  // i.) g > 3 ... error
420  // ii.) g > 2 ... h2 = sqrt(2*p_g1*p_g2*p_g1.e()*p_g2.e()/(pow(p_g1.e(),2)+pow(p_g2.e(),2))) );
421  // iii.) g > other ... h2 = -1
422  // return max(h1,h2)
423  // 3.) else ... error
424 
425  vector<Vec4> momenta;
426  vector<int> positions;
427 
428  // 1.) t > b W
429  if (match_decay(i_top, e, vector<int>{wid, bid}, positions, momenta, false)) {
430  double h;
431  int i_b = positions[1];
432  // a.+b.) b > 3 or b > b g
433  if (match_decay(i_b, e, vector<int>{bid, gid}, positions, momenta))
434  h = qSplittingScale(e[i_top].p(), momenta[0], momenta[1]);
435  // c.) b > other
436  else
437  h = -1;
438  return h;
439  }
440  // 2.) t > b W g
441  else if (match_decay(i_top, e, vector<int>{wid, bid, gid}, positions, momenta, false)) {
442  double h1, h2;
443  int i_b = positions[1], i_g = positions[2];
444  // a.+b.) b > 3 or b > b g
445  if (match_decay(i_b, e, vector<int>{bid, gid}, positions, momenta))
446  h1 = qSplittingScale(e[i_top].p(), momenta[0], momenta[1]);
447  // c.) b > other
448  else
449  h1 = -1;
450  // i.+ii.) g > 3 or g > 2
451  if (match_decay(i_g, e, vector<int>{wildcard, wildcard}, positions, momenta))
452  h2 = gSplittingScale(e[i_top].p(), momenta[0], momenta[1]);
453  // c.) b > other
454  else
455  h2 = -1;
456  return max(h1, h2);
457  }
458  // 3.) else
459  else {
460  cout << "getdechardness" << endl;
461  cout << "top at position " << i_top << endl;
462  cout << "with " << e[i_top].daughterList().size() << " daughters " << endl;
463  for (unsigned i = 0; i < e[i_top].daughterList().size(); i++) {
464  int di = e[i_top].daughterList()[i];
465  cout << "with daughter " << di << ": " << e[di].id() << endl;
466  }
467  exit(-1);
468  }
469  }
470 
471  //--------------------------------------------------------------------------
472 
473  // Functions to return information
474 
475  // inline int getNFSRveto() { return nFSRveto; }
476 
477  //--------------------------------------------------------------------------
478 
479  private:
480  // FSR emission veto flags
482  // Parton Level veto flags
484  // Scale Resonance veto flags
486  // other flags
487  bool debug;
488  // internal: resonance scales
490  // internal: inter veto communication
491  double vetoDecScale;
495  //bool vetoProduction;
496  double pTmin;
497  // Statistics on vetos
498  unsigned long int nFSRvetoBB4l;
499  };
500 
501  //==========================================================================
502 
503 } // end namespace Pythia8
504 
505 #endif // end Pythia8_PowhegHooksBB4L_H
double scaleResonance(int iRes, const Event &e) override
double pTpythia(const Event &e, int RadAfterBranch, int EmtAfterBranch, int RecAfterBranch)
double qSplittingScale(Vec4 pt, Vec4 p1, Vec4 p2)
assert(be >=bs)
bool initAfterBeams() override
double getdechardness(int topcharge, const Event &e)
constexpr int pow2(int x)
Definition: TauNNIdHW.h:59
bool canVetoProcessLevel() override
bool doVetoFSR(bool condition, double scale, int iTopCharge)
bool canVetoFSREmission() override
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:60
struct @756 radtype_
double findresscale(const int iRes, const Event &event)
double gSplittingScale(Vec4 pt, Vec4 p1, Vec4 p2)
bool doVetoFSREmission(int sizeOld, const Event &e, int iSys, bool inResonance) override
bool canVetoPartonLevel() override
int radtype
bool doVetoProcessLevel(Event &e) override
bool retryPartonLevel() override
bool canSetResonanceScale() override
bool doVetoPartonLevel(const Event &e) override
bool match_decay(int iparticle, const Event &e, const vector< int > &ids, vector< int > &positions, vector< Vec4 > &momenta, bool exitOnExtraLegs=true)
The Signals That Services Can Subscribe To This is based on ActivityRegistry h
Helper function to determine trigger accepts.
Definition: Activities.doc:4
unsigned long int nFSRvetoBB4l
Power< A, B >::type pow(const A &a, const B &b)
Definition: Power.h:29
Definition: event.py:1
def exit(msg="")