CMS 3D CMS Logo

HiggsTemplateCrossSections.cc
Go to the documentation of this file.
1 #ifndef TRUTHRIVETTOOLS_HIGGSTEMPLATECROSSSECTIONS_CC
2 #define TRUTHRIVETTOOLS_HIGGSTEMPLATECROSSSECTIONS_CC
3 
4 // -*- C++ -*-
5 #include "Rivet/Analysis.hh"
6 #include "Rivet/Particle.hh"
7 #include "Rivet/Projections/FastJets.hh"
8 
9 // Definition of the StatusCode and Category enums
10 //#include "HiggsTemplateCrossSections.h"
12 
13 #include <atomic>
14 
15 namespace Rivet {
16 
21  class HiggsTemplateCrossSections : public Analysis {
22  public:
23  // Constructor
25  : Analysis("HiggsTemplateCrossSections"),
27 
28  public:
29 
34 
37  if ( ptcl.genParticle()->end_vertex() ) {
38  if ( !hasChild(ptcl.genParticle(),ptcl.pdgId()) ) return ptcl;
39  else return getLastInstance(ptcl.children()[0]);
40  }
41  return ptcl;
42  }
43 
45  bool originateFrom(const Particle& p, const Particles& ptcls ) {
46  const GenVertex* prodVtx = p.genParticle()->production_vertex();
47  if (prodVtx == nullptr) return false;
48  // for each ancestor, check if it matches any of the input particles
49  for (const auto & ancestor:particles(prodVtx, HepMC::ancestors)){
50  for ( auto part:ptcls )
51  if ( ancestor==part.genParticle() ) return true;
52  }
53  // if we get here, no ancetor matched any input particle
54  return false;
55  }
56 
58  bool originateFrom(const Particle& p, const Particle& p2 ) {
59  Particles ptcls = {p2}; return originateFrom(p,ptcls);
60  }
61 
63  bool hasChild(const GenParticle *ptcl, int pdgID) {
64  for (auto child:Particle(*ptcl).children())
65  if (child.pdgId()==pdgID) return true;
66  return false;
67  }
68 
70  bool hasParent(const GenParticle *ptcl, int pdgID) {
71  for (auto parent:particles(ptcl->production_vertex(),HepMC::parents))
72  if (parent->pdg_id()==pdgID) return true;
73  return false;
74  }
75 
77  bool quarkDecay(const Particle &p) {
78  for (auto child:p.children())
79  if (PID::isQuark(child.pdgId())) return true;
80  return false;
81  }
82 
85  HiggsClassification error(HiggsClassification &cat, HTXS::ErrorCode err,
86  std::string msg="", int NmaxWarnings=20) {
87  // Set the error, and keep statistics
88  cat.errorCode = err;
89  ++m_errorCount[err];
90 
91  // Print warning message to the screen/log
92  static std::atomic<int> Nwarnings{0};
93  if ( !msg.empty() && ++Nwarnings < NmaxWarnings )
94  MSG_WARNING(msg);
95 
96  return cat;
97  }
99 
101  HiggsClassification classifyEvent(const Event& event, const HTXS::HiggsProdMode prodMode ) {
102 
104 
105  // the classification object
106  HiggsClassification cat;
107  cat.prodMode = prodMode;
108  cat.errorCode = HTXS::UNDEFINED;
109  cat.stage0_cat = HTXS::Stage0::UNKNOWN;
110  cat.stage1_cat_pTjet25GeV = HTXS::Stage1::UNKNOWN;
111  cat.stage1_cat_pTjet30GeV = HTXS::Stage1::UNKNOWN;
112  cat.stage1_1_cat_pTjet25GeV = HTXS::Stage1_1::UNKNOWN;
113  cat.stage1_1_cat_pTjet30GeV = HTXS::Stage1_1::UNKNOWN;
114  cat.stage1_1_fine_cat_pTjet25GeV = HTXS::Stage1_1_Fine::UNKNOWN;
115  cat.stage1_1_fine_cat_pTjet30GeV = HTXS::Stage1_1_Fine::UNKNOWN;
116 
117  if (prodMode == HTXS::UNKNOWN)
118  return error(cat,HTXS::PRODMODE_DEFINED,
119  "Unkown Higgs production mechanism. Cannot classify event."
120  " Classification for all events will most likely fail.");
121 
122  /*****
123  * Step 1.
124  * Idenfify the Higgs boson and the hard scatter vertex
125  * There should be only one of each.
126  */
127 
128  GenVertex *HSvtx = event.genEvent()->signal_process_vertex();
129  int Nhiggs=0;
130  for ( const GenParticle *ptcl : Rivet::particles(event.genEvent()) ) {
131 
132  // a) Reject all non-Higgs particles
133  if ( !PID::isHiggs(ptcl->pdg_id()) ) continue;
134  // b) select only the final Higgs boson copy, prior to decay
135  if ( ptcl->end_vertex() && !hasChild(ptcl,PID::HIGGS) ) {
136  cat.higgs = Particle(ptcl); ++Nhiggs;
137  }
138  // c) if HepMC::signal_proces_vertex is missing
139  // set hard-scatter vertex based on first Higgs boson
140  if ( HSvtx==nullptr && ptcl->production_vertex() && !hasParent(ptcl,PID::HIGGS) )
141  HSvtx = ptcl->production_vertex();
142  }
143 
144  // Make sure things are in order so far
145  if (Nhiggs!=1)
147  "Current event has "+std::to_string(Nhiggs)+" Higgs bosons. There must be only one.");
148  if (cat.higgs.children().size()<2)
150  "Could not identify Higgs boson decay products.");
151 
152  if (HSvtx == nullptr)
153  return error(cat,HTXS::HS_VTX_IDENTIFICATION,"Cannot find hard-scatter vertex of current event.");
154 
155  /*****
156  * Step 2.
157  * Identify associated vector bosons
158  */
159 
160  // Find associated vector bosons
161  bool is_uncatdV = false;
162  Particles uncatV_decays;
163  FourMomentum uncatV_p4(0,0,0,0);
164  FourVector uncatV_v4(0,0,0,0);
165  int nWs=0, nZs=0, nTop=0;
166  if ( isVH(prodMode) ) {
167  for (auto ptcl:particles(HSvtx,HepMC::children)) {
168  if (PID::isW(ptcl->pdg_id())) { ++nWs; cat.V=Particle(ptcl); }
169  if (PID::isZ(ptcl->pdg_id())) { ++nZs; cat.V=Particle(ptcl); }
170  }
171  if(nWs+nZs>0) cat.V = getLastInstance(cat.V);
172  else {
173  for (auto ptcl:particles(HSvtx,HepMC::children)) {
174  if (!PID::isHiggs(ptcl->pdg_id())) {
175  uncatV_decays += Particle(ptcl);
176  uncatV_p4 += Particle(ptcl).momentum();
177  // uncatV_v4 += Particle(ptcl).origin();
178  }
179  }
180  // is_uncatdV = true; cat.V = Particle(24,uncatV_p4,uncatV_v4);
181  is_uncatdV = true; cat.V = Particle(24,uncatV_p4);
182  }
183  }
184 
185  if ( !is_uncatdV ){
186 
187  if ( isVH(prodMode) && !cat.V.genParticle()->end_vertex() )
188  return error(cat,HTXS::VH_DECAY_IDENTIFICATION,"Vector boson does not decay!");
189 
190  if ( isVH(prodMode) && cat.V.children().size()<2 )
191  return error(cat,HTXS::VH_DECAY_IDENTIFICATION,"Vector boson does not decay!");
192 
193  if ( ( prodMode==HTXS::WH && (nZs>0||nWs!=1) ) ||
194  ( (prodMode==HTXS::QQ2ZH||prodMode==HTXS::GG2ZH) && (nZs!=1||nWs>0) ) )
195  return error(cat,HTXS::VH_IDENTIFICATION,"Found "+std::to_string(nWs)+" W-bosons and "+
196  std::to_string(nZs)+" Z-bosons. Inconsitent with VH expectation.");
197  }
198 
199  // Find and store the W-bosons from ttH->WbWbH
200  Particles Ws;
201  if ( prodMode==HTXS::TTH || prodMode==HTXS::TH ){
202  // loop over particles produced in hard-scatter vertex
203  for ( auto ptcl : particles(HSvtx,HepMC::children) ) {
204  if ( !PID::isTop(ptcl->pdg_id()) ) continue;
205  ++nTop;
206  Particle top = getLastInstance(Particle(ptcl));
207  if ( top.genParticle()->end_vertex() )
208  for (auto child:top.children())
209  if ( PID::isW(child.pdgId()) ) Ws += child;
210  }
211  }
212 
213  // Make sure result make sense
214  if ( (prodMode==HTXS::TTH && Ws.size()<2) || (prodMode==HTXS::TH && Ws.empty() ) )
215  return error(cat,HTXS::TOP_W_IDENTIFICATION,"Failed to identify W-boson(s) from t-decay!");
216 
217  /*****
218  * Step 3.
219  * Build jets
220  * Make sure all stable particles are present
221  */
222 
223  // Create a list of the vector bosons that decay leptonically
224  // Either the vector boson produced in association with the Higgs boson,
225  // or the ones produced from decays of top quarks produced with the Higgs
226  Particles leptonicVs;
227  if ( !is_uncatdV ){
228  if ( isVH(prodMode) && !quarkDecay(cat.V) ) leptonicVs += cat.V;
229  }else leptonicVs = uncatV_decays;
230  for ( auto W:Ws ) if ( W.genParticle()->end_vertex() && !quarkDecay(W) ) leptonicVs += W;
231 
232  // Obtain all stable, final-state particles
233  const ParticleVector FS = applyProjection<FinalState>(event, "FS").particles();
234  Particles hadrons;
235  FourMomentum sum(0,0,0,0), vSum(0,0,0,0), hSum(0,0,0,0);
236  for ( const Particle &p : FS ) {
237  // Add up the four momenta of all stable particles as a cross check
238  sum += p.momentum();
239  // ignore particles from the Higgs boson
240  if ( originateFrom(p,cat.higgs) ) { hSum += p.momentum(); continue; }
241  // Cross-check the V decay products for VH
242  if ( isVH(prodMode) && !is_uncatdV && originateFrom(p,Ws) ) vSum += p.momentum();
243  // ignore final state particles from leptonic V decays
244  if ( !leptonicVs.empty() && originateFrom(p,leptonicVs) ) continue;
245  // All particles reaching here are considered hadrons and will be used to build jets
246  hadrons += p;
247  }
248 
249  cat.p4decay_higgs = hSum;
250  cat.p4decay_V = vSum;
251 
252  FinalState fps_temp;
253  FastJets jets(fps_temp, FastJets::ANTIKT, 0.4 );
254  jets.calc(hadrons);
255 
256  cat.jets25 = jets.jetsByPt( Cuts::pT > 25.0 );
257  cat.jets30 = jets.jetsByPt( Cuts::pT > 30.0 );
258 
259  // check that four mometum sum of all stable particles satisfies momentum consevation
260 /*
261  if ( sum.pt()>0.1 )
262  return error(cat,HTXS::MOMENTUM_CONSERVATION,"Four vector sum does not amount to pT=0, m=E=sqrt(s), but pT="+
263  std::to_string(sum.pt())+" GeV and m = "+std::to_string(sum.mass())+" GeV");
264 */
265  // check if V-boson was not included in the event record but decay particles were
266  // EFT contact interaction: return UNKNOWN for category but set all event/particle kinematics
267  if(is_uncatdV)
268  return error(cat,HTXS::VH_IDENTIFICATION,"Failed to identify associated V-boson!");
269 
270  /*****
271  * Step 4.
272  * Classify and save output
273  */
274 
275  // Apply the categorization categorization
276  cat.stage0_cat = getStage0Category(prodMode,cat.higgs,cat.V);
277  cat.stage1_cat_pTjet25GeV = getStage1Category(prodMode,cat.higgs,cat.jets25,cat.V);
278  cat.stage1_cat_pTjet30GeV = getStage1Category(prodMode,cat.higgs,cat.jets30,cat.V);
279  cat.stage1_1_cat_pTjet25GeV = getStage1_1_Category(prodMode,cat.higgs,cat.jets25,cat.V);
280  cat.stage1_1_cat_pTjet30GeV = getStage1_1_Category(prodMode,cat.higgs,cat.jets30,cat.V);
281  cat.stage1_1_fine_cat_pTjet25GeV = getStage1_1_Fine_Category(prodMode,cat.higgs,cat.jets25,cat.V);
282  cat.stage1_1_fine_cat_pTjet30GeV = getStage1_1_Fine_Category(prodMode,cat.higgs,cat.jets30,cat.V);
283 
284  cat.errorCode = HTXS::SUCCESS; ++m_errorCount[HTXS::SUCCESS];
285 
286  return cat;
287  }
288 
294 
296  int getBin(double x, std::vector<double> bins) {
297  for (size_t i=1;i<bins.size();++i)
298  if (x<bins[i]) return i-1;
299  return bins.size()-1;
300  }
301 
305  int vbfTopology(const Jets &jets, const Particle &higgs) {
306  if (jets.size()<2) return 0;
307  const FourMomentum &j1=jets[0].momentum(), &j2=jets[1].momentum();
308  bool VBFtopo = (j1+j2).mass() > 400.0 && std::abs(j1.rapidity()-j2.rapidity()) > 2.8;
309  return VBFtopo ? (j1+j2+higgs.momentum()).pt()<25 ? 2 : 1 : 0;
310  }
311 
316  int vbfTopology_Stage1_1(const Jets &jets, const Particle &higgs) {
317  if (jets.size()<2) return 0;
318  const FourMomentum &j1=jets[0].momentum(), &j2=jets[1].momentum();
319  double mjj = (j1+j2).mass();
320  if(mjj>350 && mjj<=700) return (j1+j2+higgs.momentum()).pt()<25 ? 1 : 2;
321  else if(mjj>700) return (j1+j2+higgs.momentum()).pt()<25 ? 3 : 4;
322  else return 0;
323  }
324 
331  int vbfTopology_Stage1_1_Fine(const Jets &jets, const Particle &higgs) {
332  if (jets.size()<2) return 0;
333  const FourMomentum &j1=jets[0].momentum(), &j2=jets[1].momentum();
334  double mjj = (j1+j2).mass();
335  if(mjj>350 && mjj<=700) return (j1+j2+higgs.momentum()).pt()<25 ? 1 : 2;
336  else if(mjj>700 && mjj<=1000) return (j1+j2+higgs.momentum()).pt()<25 ? 3 : 4;
337  else if(mjj>1000 && mjj<=1500) return (j1+j2+higgs.momentum()).pt()<25 ? 5 : 6;
338  else if(mjj>1500) return (j1+j2+higgs.momentum()).pt()<25 ? 7 : 8;
339  else return 0;
340  }
341 
343  bool isVH(HTXS::HiggsProdMode p) { return p==HTXS::WH || p==HTXS::QQ2ZH || p==HTXS::GG2ZH; }
344 
347  const Particle &higgs,
348  const Particle &V) {
349  using namespace HTXS::Stage0;
350  int ctrlHiggs = std::abs(higgs.rapidity())<2.5;
351  // Special cases first, qq→Hqq
352  if ( (prodMode==HTXS::WH||prodMode==HTXS::QQ2ZH) && quarkDecay(V) ) {
353  return ctrlHiggs ? VH2HQQ : VH2HQQ_FWDH;
354  } else if ( prodMode==HTXS::GG2ZH && quarkDecay(V) ) {
355  return Category(HTXS::GGF*10 + ctrlHiggs);
356  }
357  // General case after
358  return Category(prodMode*10 + ctrlHiggs);
359  }
360 
363  const Particle &higgs,
364  const Jets &jets,
365  const Particle &V) {
366  using namespace HTXS::Stage1;
367  int Njets=jets.size(), ctrlHiggs = std::abs(higgs.rapidity())<2.5, fwdHiggs = !ctrlHiggs;
368  double pTj1 = !jets.empty() ? jets[0].momentum().pt() : 0;
369  int vbfTopo = vbfTopology(jets,higgs);
370 
371  // 1. GGF Stage 1 categories
372  // Following YR4 write-up: XXXXX
373  if (prodMode==HTXS::GGF || (prodMode==HTXS::GG2ZH && quarkDecay(V)) ) {
374  if (fwdHiggs) return GG2H_FWDH;
375  if (Njets==0) return GG2H_0J;
376  else if (Njets==1) return Category(GG2H_1J_PTH_0_60+getBin(higgs.pt(),{0,60,120,200}));
377  else if (Njets>=2) {
378  // events with pT_H>200 get priority over VBF cuts
379  if(higgs.pt()<=200){
380  if (vbfTopo==2) return GG2H_VBFTOPO_JET3VETO;
381  else if (vbfTopo==1) return GG2H_VBFTOPO_JET3;
382  }
383  // Njets >= 2jets without VBF topology
384  return Category(GG2H_GE2J_PTH_0_60+getBin(higgs.pt(),{0,60,120,200}));
385  }
386  }
387  // 2. Electroweak qq->Hqq Stage 1 categories
388  else if (prodMode==HTXS::VBF || ( isVH(prodMode) && quarkDecay(V)) ) {
389  if (std::abs(higgs.rapidity())>2.5) return QQ2HQQ_FWDH;
390  if (pTj1>200) return QQ2HQQ_PTJET1_GT200;
391  if (vbfTopo==2) return QQ2HQQ_VBFTOPO_JET3VETO;
392  if (vbfTopo==1) return QQ2HQQ_VBFTOPO_JET3;
393  double mjj = jets.size()>1 ? (jets[0].mom()+jets[1].mom()).mass():0;
394  if ( 60 < mjj && mjj < 120 ) return QQ2HQQ_VH2JET;
395  return QQ2HQQ_REST;
396  }
397  // 3. WH->Hlv categories
398  else if (prodMode==HTXS::WH) {
399  if (fwdHiggs) return QQ2HLNU_FWDH;
400  else if (V.pt()<150) return QQ2HLNU_PTV_0_150;
401  else if (V.pt()>250) return QQ2HLNU_PTV_GT250;
402  // 150 < pTV/GeV < 250
403  return jets.empty() ? QQ2HLNU_PTV_150_250_0J : QQ2HLNU_PTV_150_250_GE1J;
404  }
405  // 4. qq->ZH->llH categories
406  else if (prodMode==HTXS::QQ2ZH) {
407  if (fwdHiggs) return QQ2HLL_FWDH;
408  else if (V.pt()<150) return QQ2HLL_PTV_0_150;
409  else if (V.pt()>250) return QQ2HLL_PTV_GT250;
410  // 150 < pTV/GeV < 250
411  return jets.empty() ? QQ2HLL_PTV_150_250_0J : QQ2HLL_PTV_150_250_GE1J;
412  }
413  // 5. gg->ZH->llH categories
414  else if (prodMode==HTXS::GG2ZH ) {
415  if (fwdHiggs) return GG2HLL_FWDH;
416  if (V.pt()<150) return GG2HLL_PTV_0_150;
417  else if (jets.empty()) return GG2HLL_PTV_GT150_0J;
418  return GG2HLL_PTV_GT150_GE1J;
419  }
420  // 6.ttH,bbH,tH categories
421  else if (prodMode==HTXS::TTH) return Category(TTH_FWDH+ctrlHiggs);
422  else if (prodMode==HTXS::BBH) return Category(BBH_FWDH+ctrlHiggs);
423  else if (prodMode==HTXS::TH ) return Category(TH_FWDH+ctrlHiggs);
424  return UNKNOWN;
425  }
426 
429  const Particle &higgs,
430  const Jets &jets,
431  const Particle &V) {
432  using namespace HTXS::Stage1_1;
433  int Njets=jets.size(), ctrlHiggs = std::abs(higgs.rapidity())<2.5, fwdHiggs = !ctrlHiggs;
434  int vbfTopo = vbfTopology_Stage1_1(jets,higgs);
435 
436  // 1. GGF Stage 1 categories
437  // Following YR4 write-up: XXXXX
438  if (prodMode==HTXS::GGF || (prodMode==HTXS::GG2ZH && quarkDecay(V)) ) {
439  if (fwdHiggs) return GG2H_FWDH;
440  if ( higgs.pt()>200 ) return GG2H_PTH_GT200;
441  if (Njets==0) return higgs.pt()<10 ? GG2H_0J_PTH_0_10 : GG2H_0J_PTH_GT10;
442  if (Njets==1) return Category(GG2H_1J_PTH_0_60+getBin(higgs.pt(),{0,60,120,200}));
443  if (Njets>1){
444  //VBF topology
445  if(vbfTopo) return Category(GG2H_MJJ_350_700_PTHJJ_0_25+vbfTopo-1);
446  //Njets >= 2jets without VBF topology (mjj<350)
447  return Category(GG2H_GE2J_MJJ_0_350_PTH_0_60+getBin(higgs.pt(),{0,60,120,200}));
448  }
449  }
450 
451  // 2. Electroweak qq->Hqq Stage 1.1 categories
452  else if (prodMode==HTXS::VBF || ( isVH(prodMode) && quarkDecay(V)) ) {
453  if (std::abs(higgs.rapidity())>2.5) return QQ2HQQ_FWDH;
454  int Njets=jets.size();
455  if (Njets==0) return QQ2HQQ_0J;
456  else if (Njets==1) return QQ2HQQ_1J;
457  else if (Njets>=2) {
458  double mjj = (jets[0].mom()+jets[1].mom()).mass();
459  if ( mjj < 60 ) return QQ2HQQ_MJJ_0_60;
460  else if ( 60 < mjj && mjj < 120 ) return QQ2HQQ_MJJ_60_120;
461  else if ( 120 < mjj && mjj < 350 ) return QQ2HQQ_MJJ_120_350;
462  else if ( mjj > 350 ) {
463  if (higgs.pt()>200) return QQ2HQQ_MJJ_GT350_PTH_GT200;
464  if(vbfTopo) return Category(QQ2HQQ_MJJ_GT350_PTH_GT200+vbfTopo);
465  }
466  }
467  }
468  // 3. WH->Hlv categories
469  else if (prodMode==HTXS::WH) {
470  if (fwdHiggs) return QQ2HLNU_FWDH;
471  else if (V.pt()<75) return QQ2HLNU_PTV_0_75;
472  else if (V.pt()<150) return QQ2HLNU_PTV_75_150;
473  else if (V.pt()>250) return QQ2HLNU_PTV_GT250;
474  // 150 < pTV/GeV < 250
475  return jets.empty() ? QQ2HLNU_PTV_150_250_0J : QQ2HLNU_PTV_150_250_GE1J;
476  }
477  // 4. qq->ZH->llH categories
478  else if (prodMode==HTXS::QQ2ZH) {
479  if (fwdHiggs) return QQ2HLL_FWDH;
480  else if (V.pt()<75) return QQ2HLL_PTV_0_75;
481  else if (V.pt()<150) return QQ2HLL_PTV_75_150;
482  else if (V.pt()>250) return QQ2HLL_PTV_GT250;
483  // 150 < pTV/GeV < 250
484  return jets.empty() ? QQ2HLL_PTV_150_250_0J : QQ2HLL_PTV_150_250_GE1J;
485  }
486  // 5. gg->ZH->llH categories
487  else if (prodMode==HTXS::GG2ZH ) {
488  if (fwdHiggs) return GG2HLL_FWDH;
489  else if (V.pt()<75) return GG2HLL_PTV_0_75;
490  else if (V.pt()<150) return GG2HLL_PTV_75_150;
491  else if (V.pt()>250) return GG2HLL_PTV_GT250;
492  return jets.empty() ? GG2HLL_PTV_150_250_0J : GG2HLL_PTV_150_250_GE1J;
493  }
494  // 6.ttH,bbH,tH categories
495  else if (prodMode==HTXS::TTH) return Category(TTH_FWDH+ctrlHiggs);
496  else if (prodMode==HTXS::BBH) return Category(BBH_FWDH+ctrlHiggs);
497  else if (prodMode==HTXS::TH ) return Category(TH_FWDH+ctrlHiggs);
498  return UNKNOWN;
499  }
500 
503  const Particle &higgs,
504  const Jets &jets,
505  const Particle &V) {
506  using namespace HTXS::Stage1_1_Fine;
507  int Njets=jets.size(), ctrlHiggs = std::abs(higgs.rapidity())<2.5, fwdHiggs = !ctrlHiggs;
508  int vbfTopo = vbfTopology_Stage1_1_Fine(jets,higgs);
509 
510  // 1. GGF Stage 1.1 categories
511  // Following YR4 write-up: XXXXX
512  if (prodMode==HTXS::GGF || (prodMode==HTXS::GG2ZH && quarkDecay(V)) ) {
513  if (fwdHiggs) return GG2H_FWDH;
514  if ( higgs.pt()>200 ) return GG2H_PTH_GT200;
515  if (Njets==0) return higgs.pt()<10 ? GG2H_0J_PTH_0_10 : GG2H_0J_PTH_GT10;
516  if (Njets==1) return Category(GG2H_1J_PTH_0_60+getBin(higgs.pt(),{0,60,120,200}));
517  if (Njets>1){
518  //double mjj = (jets[0].mom()+jets[1].mom()).mass();
519  double pTHjj = (jets[0].momentum()+jets[1].momentum()+higgs.momentum()).pt();
520  //VBF topology
521  if(vbfTopo) return Category(GG2H_MJJ_350_700_PTHJJ_0_25+vbfTopo-1);
522  //Njets >= 2jets without VBF topology (mjj<350)
523  if (pTHjj<25) return Category(GG2H_GE2J_MJJ_0_350_PTH_0_60_PTHJJ_0_25+getBin(higgs.pt(),{0,60,120,200}));
524  else return Category(GG2H_GE2J_MJJ_0_350_PTH_0_60_PTHJJ_GT25+getBin(higgs.pt(),{0,60,120,200}));
525  }
526  }
527 
528  // 2. Electroweak qq->Hqq Stage 1.1 categories
529  else if (prodMode==HTXS::VBF || ( isVH(prodMode) && quarkDecay(V)) ) {
530  if (std::abs(higgs.rapidity())>2.5) return QQ2HQQ_FWDH;
531  int Njets=jets.size();
532  if (Njets==0) return QQ2HQQ_0J;
533  else if (Njets==1) return QQ2HQQ_1J;
534  else if (Njets>=2) {
535  double mjj = (jets[0].mom()+jets[1].mom()).mass();
536  double pTHjj = (jets[0].momentum()+jets[1].momentum()+higgs.momentum()).pt();
537  if (mjj<350){
538  if (pTHjj<25) return Category(QQ2HQQ_MJJ_0_60_PTHJJ_0_25+getBin(mjj,{0,60,120,350}));
539  else return Category(QQ2HQQ_MJJ_0_60_PTHJJ_GT25+getBin(mjj,{0,60,120,350}));
540  } else { //mjj>350 GeV
541  if (higgs.pt()<200){
542  return Category(QQ2HQQ_MJJ_350_700_PTHJJ_0_25+vbfTopo-1);
543  } else {
545  }
546  }
547  }
548  }
549  // 3. WH->Hlv categories
550  else if (prodMode==HTXS::WH) {
551  if (fwdHiggs) return QQ2HLNU_FWDH;
552  int Njets=jets.size();
553  if (Njets==0) return Category(QQ2HLNU_PTV_0_75_0J+getBin(V.pt(),{0,75,150,250,400}));
554  if (Njets==1) return Category(QQ2HLNU_PTV_0_75_1J+getBin(V.pt(),{0,75,150,250,400}));
555  return Category(QQ2HLNU_PTV_0_75_GE2J+getBin(V.pt(),{0,75,150,250,400}));
556  }
557  // 4. qq->ZH->llH categories
558  else if (prodMode==HTXS::QQ2ZH) {
559  if (fwdHiggs) return QQ2HLL_FWDH;
560  int Njets=jets.size();
561  if (Njets==0) return Category(QQ2HLL_PTV_0_75_0J+getBin(V.pt(),{0,75,150,250,400}));
562  if (Njets==1) return Category(QQ2HLL_PTV_0_75_1J+getBin(V.pt(),{0,75,150,250,400}));
563  return Category(QQ2HLL_PTV_0_75_GE2J+getBin(V.pt(),{0,75,150,250,400}));
564  }
565  // 5. gg->ZH->llH categories
566  else if (prodMode==HTXS::GG2ZH ) {
567  if (fwdHiggs) return GG2HLL_FWDH;
568  int Njets=jets.size();
569  if (Njets==0) return Category(GG2HLL_PTV_0_75_0J+getBin(V.pt(),{0,75,150,250,400}));
570  if (Njets==1) return Category(GG2HLL_PTV_0_75_1J+getBin(V.pt(),{0,75,150,250,400}));
571  return Category(GG2HLL_PTV_0_75_GE2J+getBin(V.pt(),{0,75,150,250,400}));
572  }
573  // 6.ttH,bbH,tH categories
574  else if (prodMode==HTXS::TTH) return Category(TTH_FWDH+ctrlHiggs);
575  else if (prodMode==HTXS::BBH) return Category(BBH_FWDH+ctrlHiggs);
576  else if (prodMode==HTXS::TH ) return Category(TH_FWDH+ctrlHiggs);
577  return UNKNOWN;
578  }
579 
580 
582 
583 
586 
588  void setHiggsProdMode( HTXS::HiggsProdMode prodMode ){ m_HiggsProdMode = prodMode; }
589 
593  void init() override {
594  printf("==============================================================\n");
595  printf("======== HiggsTemplateCrossSections Initialization =========\n");
596  printf("==============================================================\n");
597  // check that the production mode has been set
598  // if running in standalone Rivet the production mode is set through an env variable
600  char *pm_env = getenv("HIGGSPRODMODE");
601  string pm(pm_env==nullptr?"":pm_env);
602  if ( pm == "GGF" ) m_HiggsProdMode = HTXS::GGF;
603  else if ( pm == "VBF" ) m_HiggsProdMode = HTXS::VBF;
604  else if ( pm == "WH" ) m_HiggsProdMode = HTXS::WH;
605  else if ( pm == "ZH" ) m_HiggsProdMode = HTXS::QQ2ZH;
606  else if ( pm == "QQ2ZH" ) m_HiggsProdMode = HTXS::QQ2ZH;
607  else if ( pm == "GG2ZH" ) m_HiggsProdMode = HTXS::GG2ZH;
608  else if ( pm == "TTH" ) m_HiggsProdMode = HTXS::TTH;
609  else if ( pm == "BBH" ) m_HiggsProdMode = HTXS::BBH;
610  else if ( pm == "TH" ) m_HiggsProdMode = HTXS::TH;
611  else {
612  MSG_WARNING("No HIGGSPRODMODE shell variable found. Needed when running Rivet stand-alone.");
613  }
614  }
615 
616  // Projections for final state particles
617  const FinalState FS;
618  addProjection(FS,"FS");
619 
620  // initialize the histograms with for each of the stages
622  m_sumw = 0.0;
623  printf("==============================================================\n");
624  printf("======== Higgs prod mode %d =========\n",m_HiggsProdMode);
625  printf("======== Sucessful Initialization =========\n");
626  printf("==============================================================\n");
627  }
628 
629  // Perform the per-event analysis
630  void analyze(const Event& event) override {
631 
632  // get the classification
633  HiggsClassification cat = classifyEvent(event,m_HiggsProdMode);
634 
635  // Fill histograms: categorization --> linerize the categories
636  const double weight = event.weight();
637  m_sumw += weight;
638 
639  int F=cat.stage0_cat%10, P=cat.stage1_cat_pTjet30GeV/100;
640  hist_stage0->fill( cat.stage0_cat/10*2+F, weight );
641 
642  // Stage 1 enum offsets for each production mode: GGF=12, VBF=6, WH= 5, QQ2ZH=5, GG2ZH=4, TTH=2, BBH=2, TH=2
643  vector<int> offset({0,1,13,19,24,29,33,35,37,39});
644  int off = offset[P];
645  hist_stage1_pTjet25->fill(cat.stage1_cat_pTjet25GeV%100 + off, weight);
646  hist_stage1_pTjet30->fill(cat.stage1_cat_pTjet30GeV%100 + off, weight);
647 
648  // Fill histograms: variables used in the categorization
649  hist_pT_Higgs->fill(cat.higgs.pT(),weight);
650  hist_y_Higgs->fill(cat.higgs.rapidity(),weight);
651  hist_pT_V->fill(cat.V.pT(),weight);
652 
653  hist_Njets25->fill(cat.jets25.size(),weight);
654  hist_Njets30->fill(cat.jets30.size(),weight);
655 
656  // Jet variables. Use jet collection with pT threshold at 30 GeV
657  if (!cat.jets30.empty()) hist_pT_jet1->fill(cat.jets30[0].pt(),weight);
658  if (cat.jets30.size()>=2) {
659  const FourMomentum &j1 = cat.jets30[0].momentum(), &j2 = cat.jets30[1].momentum();
660  hist_deltay_jj->fill(std::abs(j1.rapidity()-j2.rapidity()),weight);
661  hist_dijet_mass->fill((j1+j2).mass(),weight);
662  hist_pT_Hjj->fill((j1+j2+cat.higgs.momentum()).pt(),weight);
663  }
664  }
665 
667  MSG_INFO (" ====================================================== ");
668  MSG_INFO (" Higgs Template X-Sec Categorization Tool ");
669  MSG_INFO (" Status Code Summary ");
670  MSG_INFO (" ====================================================== ");
671  bool allSuccess = (numEvents()==m_errorCount[HTXS::SUCCESS]);
672  if ( allSuccess ) MSG_INFO (" >>>> All "<< m_errorCount[HTXS::SUCCESS] <<" events successfully categorized!");
673  else{
674  MSG_INFO (" >>>> "<< m_errorCount[HTXS::SUCCESS] <<" events successfully categorized");
675  MSG_INFO (" >>>> --> the following errors occured:");
676  MSG_INFO (" >>>> "<< m_errorCount[HTXS::PRODMODE_DEFINED] <<" had an undefined Higgs production mode.");
677  MSG_INFO (" >>>> "<< m_errorCount[HTXS::MOMENTUM_CONSERVATION] <<" failed momentum conservation.");
678  MSG_INFO (" >>>> "<< m_errorCount[HTXS::HIGGS_IDENTIFICATION] <<" failed to identify a valid Higgs boson.");
679  MSG_INFO (" >>>> "<< m_errorCount[HTXS::HS_VTX_IDENTIFICATION] <<" failed to identify the hard scatter vertex.");
680  MSG_INFO (" >>>> "<< m_errorCount[HTXS::VH_IDENTIFICATION] <<" VH: to identify a valid V-boson.");
681  MSG_INFO (" >>>> "<< m_errorCount[HTXS::TOP_W_IDENTIFICATION] <<" failed to identify valid Ws from top decay.");
682  }
683  MSG_INFO (" ====================================================== ");
684  MSG_INFO (" ====================================================== ");
685  }
686 
687 
688  void finalize() override {
690  double sf = m_sumw>0?1.0/m_sumw:1.0;
693  scale(hist, sf);
694  }
695 
696  /*
697  * initialize histograms
698  */
699 
701  hist_stage0 = bookHisto1D("HTXS_stage0",20,0,20);
702  hist_stage1_pTjet25 = bookHisto1D("HTXS_stage1_pTjet25",40,0,40);
703  hist_stage1_pTjet30 = bookHisto1D("HTXS_stage1_pTjet30",40,0,40);
704  hist_pT_Higgs = bookHisto1D("pT_Higgs",80,0,400);
705  hist_y_Higgs = bookHisto1D("y_Higgs",80,-4,4);
706  hist_pT_V = bookHisto1D("pT_V",80,0,400);
707  hist_pT_jet1 = bookHisto1D("pT_jet1",80,0,400);
708  hist_deltay_jj = bookHisto1D("deltay_jj",50,0,10);
709  hist_dijet_mass = bookHisto1D("m_jj",50,0,2000);
710  hist_pT_Hjj = bookHisto1D("pT_Hjj",50,0,250);
711  hist_Njets25 = bookHisto1D("Njets25",10,0,10);
712  hist_Njets30 = bookHisto1D("Njets30",10,0,10);
713  }
715 
716  /*
717  * initialize private members used in the classification procedure
718  */
719 
720  private:
721  double m_sumw;
723  std::map<HTXS::ErrorCode,size_t> m_errorCount;
724  Histo1DPtr hist_stage0;
727  Histo1DPtr hist_pT_V, hist_pT_jet1;
730  };
731 
732  // the PLUGIN only needs to be decleared when running standalone Rivet
733  // and causes compilation / linking issues if included in Athena / RootCore
734  //check for Rivet environment variable RIVET_ANALYSIS_PATH
735 #ifdef RIVET_ANALYSIS_PATH
736  // The hook for the plugin system
738 #endif
739 
740 }
741 
742 #endif
743 
std::map< HTXS::ErrorCode, size_t > m_errorCount
int vbfTopology(const Jets &jets, const Particle &higgs)
VBF topolog selection 0 = fail loose selction: m_jj > 400 GeV and Dy_jj > 2.8 1 pass loose...
bool isVH(HTXS::HiggsProdMode p)
Whether the Higgs is produced in association with a vector boson (VH)
failed to identify associated vector boson
int getBin(double x, std::vector< double > bins)
Return bin index of x given the provided bin edges. 0=first bin, -1=underflow bin.
ErrorCode
Error code: whether the classification was successful or failed.
TPRegexp parents
Definition: eve_filter.cc:21
int vbfTopology_Stage1_1(const Jets &jets, const Particle &higgs)
VBF topology selection Stage1.1 0 = fail loose selection: m_jj > 350 GeV 1 pass loose, but fail additional cut pT(Hjj)<25. 2 pass pT(Hjj)>25 selection 3 pass tight (m_jj>700 GeV), but fail additional cut pT(Hjj)<25. 4 pass pT(Hjj)>25 selection.
bool originateFrom(const Particle &p, const Particle &p2)
Whether particle p originates from p2.
successful classification
bool hasParent(const GenParticle *ptcl, int pdgID)
Checks whether the input particle has a parent with a given PDGID.
0: Unidentified isolated particle
Definition: ParticleCode.h:19
HTXS::Stage1::Category getStage1Category(const HTXS::HiggsProdMode prodMode, const Particle &higgs, const Jets &jets, const Particle &V)
Stage-1 categorization.
failed to identify Higgs boson decay products
Definition: weight.py:1
HiggsProdMode
Higgs production modes, corresponding to input sample.
HTXS::Stage1_1::Category getStage1_1_Category(const HTXS::HiggsProdMode prodMode, const Particle &higgs, const Jets &jets, const Particle &V)
Stage-1.1 categorization.
int vbfTopology_Stage1_1_Fine(const Jets &jets, const Particle &higgs)
VBF topology selection for Stage1.1 Fine 0 = fail loose selection: m_jj > 350 GeV 1 pass loose...
void init() override
default Rivet Analysis::init method Booking of histograms, initializing Rivet projection Extracts Hig...
void analyze(const Event &event) override
def cat(path)
Definition: eostools.py:401
HTXS::Stage1_1_Fine::Category getStage1_1_Fine_Category(const HTXS::HiggsProdMode prodMode, const Particle &higgs, const Jets &jets, const Particle &V)
Stage-1_1 categorization.
bool hasChild(const GenParticle *ptcl, int pdgID)
Checks whether the input particle has a child with a given PDGID.
bool quarkDecay(const Particle &p)
Return true is particle decays to quarks.
failed momentum conservation
vector< PseudoJet > jets
DECLARE_RIVET_PLUGIN(CMS_2013_I1224539_DIJET)
Particle getLastInstance(Particle ptcl)
follow a "propagating" particle and return its last instance
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
Namespace for Stage0 categorization.
Higgs Template Cross Section namespace.
failed to identify associated vector boson decay products
void setHiggsProdMode(HTXS::HiggsProdMode prodMode)
Sets the Higgs production mode.
How EventSelector::AcceptEvent() decides whether to accept an event for output otherwise it is excluding the probing of A single or multiple positive and the trigger will pass if any such matching triggers are PASS or EXCEPTION[A criterion thatmatches no triggers at all is detected and causes a throw.] A single negative with an expectation of appropriate bit checking in the decision and the trigger will pass if any such matching triggers are FAIL or EXCEPTION A wildcarded negative criterion that matches more than one trigger in the trigger but the state exists so we define the behavior If all triggers are the negative crieriion will lead to accepting the event(this again matches the behavior of"!*"before the partial wildcard feature was incorporated).The per-event"cost"of each negative criterion with multiple relevant triggers is about the same as!*was in the past
double p2[4]
Definition: TauolaWrapper.h:90
HiggsClassification classifyEvent(const Event &event, const HTXS::HiggsProdMode prodMode)
Main classificaion method.
failed to identify Higgs boson
part
Definition: HCALResponse.h:20
Rivet routine for classifying MC events according to the Higgs template cross section categories...
failed to identify hard scatter vertex
std::pair< OmniClusterRef, TrackingParticleRef > P
tuple msg
Definition: mps_check.py:279
HTXS::Stage0::Category getStage0Category(const HTXS::HiggsProdMode prodMode, const Particle &higgs, const Particle &V)
Stage-0 HTXS categorization.
HiggsClassification error(HiggsClassification &cat, HTXS::ErrorCode err, std::string msg="", int NmaxWarnings=20)
Returns the classification object with the error code set. Prints an warning message, and keeps track of number of errors.
bool originateFrom(const Particle &p, const Particles &ptcls)
Whether particle p originate from any of the ptcls.
static uInt32 F(BLOWFISH_CTX *ctx, uInt32 x)
Definition: blowfish.cc:281
production mode not defined
Definition: event.py:1
failed to identify top decay