ATLAS Offline Software
Loading...
Searching...
No Matches
HiggsTemplateCrossSections.h
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
5#ifndef TRUTHRIVETTOOLS_HIGGSTEMPLATECROSSSECTIONS_H
6#define TRUTHRIVETTOOLS_HIGGSTEMPLATECROSSSECTIONS_H
7
8// -*- C++ -*-
9#include "Rivet/Analysis.hh"
10#include "Rivet/Particle.hh"
11#include "Rivet/Projections/FastJets.hh"
12
13// Definition of the StatusCode and Category enums
14// Note: the Template XSec Defs *depends* on having included
15// the TLorentzVector header *before* it is included -- it
16// uses the include guard from TLorentzVector to decide
17// what is available
18#include "TLorentzVector.h"
21#include "AtlasHepMC/GenEvent.h"
25#include <string>
26#include <string_view>
27
28
29namespace Rivet {
30
36 public:
37 // Constructor
39 : Analysis("HiggsTemplateCrossSections"),
40 m_HiggsProdMode(HTXS::UNKNOWN) {}
41
42 public:
43
48
50 Particle getLastInstance(const Particle & ptcl) const {
51 if ( ptcl.genParticle()->end_vertex() ) {
52 if ( !hasChild(ptcl.genParticle(),ptcl.pid()) ) return ptcl;
53 else return getLastInstance(ptcl.children()[0]);
54 }
55 return ptcl;
56 }
57
59 bool originateFrom(const Particle& p, const Particles& ptcls ) const {
60 auto prodVtx = p.genParticle()->production_vertex();
61 if (prodVtx == nullptr) return false;
62 // for each ancestor, check if it matches any of the input particles
63 for (auto ancestor:Rivet::HepMCUtils::particles(std::move(prodVtx),Relatives::ANCESTORS)){
64 for ( const auto & part:ptcls )
65 if ( ancestor==part.genParticle() ) return true;
66 }
67 // if we get here, no ancestor matched any input particle
68 return false;
69 }
70
72 bool originateFrom(const Particle& p, const Particle& p2 ) const {
73 Particles ptcls = {p2}; return originateFrom(p,ptcls);
74 }
75
77 bool hasChild(HepMC::ConstGenParticlePtr ptcl, int pdgID) const {
78 for (const Particle& child:Particle(*ptcl).children())
79 if (child.pid()==pdgID) return true;
80 return false;
81 }
82
84 bool hasParent(HepMC::ConstGenParticlePtr ptcl, int pdgID) const {
85 for (auto parent:Rivet::HepMCUtils::particles(ptcl->production_vertex(),Relatives::PARENTS))
86 if (parent->pdg_id()==pdgID) return true;
87 return false;
88 }
89
91 bool quarkDecay(const Particle &p) const {
92 for (const Particle& child:p.children())
93 if (PID::isQuark(child.pid())) return true;
94 return false;
95 }
96
98 bool ChLeptonDecay(const Particle &p) const {
99 for (const Particle& child:p.children())
100 if (
101#if RIVET_VERSION_CODE >= 40000
102 PID::isChargedLepton(child.pid())
103#else
104 PID::isChLepton(child.pid())
105#endif // RIVET_VERSION_CODE
106 ) return true;
107 return false;
108 }
109
112 HiggsClassification error(HiggsClassification &cat, HTXS::ErrorCode err,
113 std::string_view msg={}, int NmaxWarnings=20) const {
114 // Set the error, and keep statistics
115 cat.errorCode = err;
116 const auto errIndex = static_cast<std::size_t>(err);
117 if (errIndex < std::size(m_errorCount)) {
118 ++m_errorCount[errIndex];
119 } else {
120 MSG_WARNING("Invalid HTXS error code: " << errIndex);
121 }
122 // Print warning message to the screen/log
123 static std::atomic<int> Nwarnings = 0;
124 if ( !msg.empty() && ++Nwarnings < NmaxWarnings )
126
127 return cat;
128 }
129
130
132 HiggsClassification classifyEvent(const Event& event, const HTXS::HiggsProdMode prodMode ) const {
133
134 // the classification object
135 HiggsClassification cat;
136 cat.prodMode = prodMode;
137 cat.errorCode = HTXS::UNDEFINED;
138 cat.stage0_cat = HTXS::Stage0::UNKNOWN;
139 cat.stage1_cat_pTjet25GeV = HTXS::Stage1::UNKNOWN;
140 cat.stage1_cat_pTjet30GeV = HTXS::Stage1::UNKNOWN;
141 cat.stage1_2_cat_pTjet25GeV = HTXS::Stage1_2::UNKNOWN;
142 cat.stage1_2_cat_pTjet30GeV = HTXS::Stage1_2::UNKNOWN;
143 cat.stage1_2_fine_cat_pTjet25GeV = HTXS::Stage1_2_Fine::UNKNOWN;
144 cat.stage1_2_fine_cat_pTjet30GeV = HTXS::Stage1_2_Fine::UNKNOWN;
145 cat.stage1_3_cat_pTjet25GeV = HTXS::Stage1_3::UNKNOWN;
146 cat.stage1_3_cat_pTjet30GeV = HTXS::Stage1_3::UNKNOWN;
147 cat.stage1_3_fine_cat_pTjet25GeV = HTXS::Stage1_3_Fine::UNKNOWN;
148 cat.stage1_3_fine_cat_pTjet30GeV = HTXS::Stage1_3_Fine::UNKNOWN;
149 cat.isTHW = false;
150
151 if (prodMode == HTXS::UNKNOWN)
152 return error(cat,HTXS::PRODMODE_DEFINED,
153 "Unkown Higgs production mechanism. Cannot classify event."
154 " Classification for all events will most likely fail.");
155
156 /*****
157 * Step 1.
158 * Idenfify the Higgs boson and the hard scatter vertex
159 * There should be only one of each.
160 */
161
162 auto HSvtx = HepMC::signal_process_vertex(event.genEvent());
163 int Nhiggs=0;
164 for (auto ptcl : Rivet::HepMCUtils::particles(event.genEvent()) ) {
165
166 // a) Reject all non-Higgs particles
167 if ( !PID::isHiggs(ptcl->pdg_id()) ) continue;
168 // b) select only the final Higgs boson copy, prior to decay
169 if ( ptcl->end_vertex() && !hasChild(ptcl,PID::HIGGS) ) {
170 cat.higgs = Particle(ptcl); ++Nhiggs;
171 }
172 // c) if HepMC::signal_proces_vertex is missing
173 // set hard-scatter vertex based on first Higgs boson
174 if ( HSvtx==nullptr && ptcl->production_vertex() && !hasParent(ptcl,PID::HIGGS) )
175 HSvtx = ptcl->production_vertex();
176 }
177
178 // Make sure things are in order so far
179 if (Nhiggs!=1)
181 "Current event has "+std::to_string(Nhiggs)+" Higgs bosons. There must be only one.");
182 if (cat.higgs.children().size()<2)
184 "Could not identify Higgs boson decay products.");
185
186 if (HSvtx == nullptr)
187 return error(cat,HTXS::HS_VTX_IDENTIFICATION,"Cannot find hard-scatter vertex of current event.");
188
189 /*****
190 * Step 2.
191 * Identify associated vector bosons
192 */
193
194 // Find associated vector bosons
195 bool is_uncatdV = false;
196 Particles uncatV_decays;
197 FourMomentum uncatV_p4(0,0,0,0);
198 FourVector uncatV_v4(0,0,0,0);
199 int nWs=0, nZs=0;
200 if ( isVH(prodMode) ) {
201 for (auto ptcl:Rivet::HepMCUtils::particles(HSvtx,Relatives::CHILDREN)) {
202 if (PID::isW(ptcl->pdg_id())) { ++nWs; cat.V=Particle(ptcl); }
203 if (PID::isZ(ptcl->pdg_id())) { ++nZs; cat.V=Particle(std::move(ptcl)); }
204 }
205 if(nWs+nZs>0) cat.V = getLastInstance(cat.V);
206 else {
207 for (auto ptcl:Rivet::HepMCUtils::particles(HSvtx,Relatives::CHILDREN)) {
208 if (!PID::isHiggs(ptcl->pdg_id())) {
209 uncatV_decays += Particle(ptcl);
210 uncatV_p4 += Particle(ptcl).momentum();
211 uncatV_v4 += Particle(std::move(ptcl)).origin();
212 }
213 }
214 is_uncatdV = true; cat.V = Particle(24,uncatV_p4,uncatV_v4);
215 }
216 }
217
218 if ( !is_uncatdV ){
219
220 if ( isVH(prodMode) && !cat.V.genParticle()->end_vertex() )
221 return error(cat,HTXS::VH_DECAY_IDENTIFICATION,"Vector boson does not decay!");
222
223 if ( isVH(prodMode) && cat.V.children().size()<2 )
224 return error(cat,HTXS::VH_DECAY_IDENTIFICATION,"Vector boson does not decay!");
225
226 if ( ( prodMode==HTXS::WH && (nZs>0||nWs!=1) ) ||
227 ( (prodMode==HTXS::QQ2ZH||prodMode==HTXS::GG2ZH) && (nZs!=1||nWs>0) ) )
228 return error(cat,HTXS::VH_IDENTIFICATION,"Found "+std::to_string(nWs)+" W-bosons and "+
229 std::to_string(nZs)+" Z-bosons. Inconsitent with VH expectation.");
230 }
231
232 // Find and store the W-bosons from ttH->WbWbH
233 Particles Ws;
234 if ( prodMode==HTXS::TTH || prodMode==HTXS::TH ){
235 // loop over particles produced in hard-scatter vertex
236 for ( auto ptcl : Rivet::HepMCUtils::particles(std::move(HSvtx),Relatives::CHILDREN) ) {
237 if ( !PID::isTop(ptcl->pdg_id()) ) continue;
238 Particle top = getLastInstance(Particle(std::move(ptcl)));
239 if ( top.genParticle()->end_vertex() )
240 for (const auto &child:top.children())
241 if ( PID::isW(child.pid()) ) Ws += getLastInstance(child);
242 }
243 }
244
245 // Make sure result make sense
246 if ( (prodMode==HTXS::TTH && Ws.size()<2) || (prodMode==HTXS::TH && Ws.size()<1 ) )
247 return error(cat,HTXS::TOP_W_IDENTIFICATION,"Failed to identify W-boson(s) from t-decay!");
248
249 // Differentiate tHq from tHW by presence of W in HSvtx children.
250 if (prodMode == HTXS::TH) {
251 for ( auto ptcl : Rivet::HepMCUtils::particles(std::move(HSvtx),Relatives::CHILDREN) ) {
252 if (PID::isW(ptcl->pdg_id())) {
253 cat.isTHW = true;
254 break;
255 }
256 }
257 }
258
259 /*****
260 * Step 3.
261 * Build jets
262 * Make sure all stable particles are present
263 */
264
265 // Create a list of the vector bosons that decay leptonically
266 // Either the vector boson produced in association with the Higgs boson,
267 // or the ones produced from decays of top quarks produced with the Higgs
268 Particles leptonicVs;
269 if ( !is_uncatdV ){
270 if ( isVH(prodMode) && !quarkDecay(cat.V) ) leptonicVs += cat.V;
271 }else leptonicVs = std::move(uncatV_decays);
272 for ( const auto & W:Ws ) if ( W.genParticle()->end_vertex() && !quarkDecay(W) ) leptonicVs += W;
273
274 // Obtain all stable, final-state particles
275 const Particles FS = apply<FinalState>(event, "FS").particles();
276 Particles hadrons;
277 FourMomentum sum(0,0,0,0), vSum(0,0,0,0), hSum(0,0,0,0);
278 for ( const Particle &p : FS ) {
279 // Add up the four momenta of all stable particles as a cross check
280 sum += p.momentum();
281 // ignore particles from the Higgs boson
282 if ( originateFrom(p,cat.higgs) ) { hSum += p.momentum(); continue; }
283 // Cross-check the V decay products for VH
284 if ( isVH(prodMode) && !is_uncatdV && originateFrom(p,Ws) ) vSum += p.momentum();
285 // ignore final state particles from leptonic V decays
286 if ( leptonicVs.size() && originateFrom(p,leptonicVs) ) continue;
287 // All particles reaching here are considered hadrons and will be used to build jets
288 hadrons += p;
289 }
290
291 cat.p4decay_higgs = hSum;
292 cat.p4decay_V = vSum;
293
294 FinalState fps_temp;
295 FastJets jets(fps_temp,
296#if RIVET_VERSION_CODE >= 40000
297 JetAlg::ANTIKT,
298#else
299 FastJets::ANTIKT,
300#endif // RIVET_VERSION_CODE
301 0.4 );
302 jets.calc(hadrons);
303
304 cat.jets25 = jets.jetsByPt( Cuts::pT > 25.0 );
305 cat.jets30 = jets.jetsByPt( Cuts::pT > 30.0 );
306
307 // check that four mometum sum of all stable particles satisfies momentum consevation
308 if ( sum.pt()>0.1 )
309 return error(cat,HTXS::MOMENTUM_CONSERVATION,"Four vector sum does not amount to pT=0, m=E=sqrt(s), but pT="+
310 std::to_string(sum.pt())+" GeV and m = "+std::to_string(sum.mass())+" GeV");
311
312 // check if V-boson was not included in the event record but decay particles were
313 // EFT contact interaction: return UNKNOWN for category but set all event/particle kinematics
314 if(is_uncatdV)
315 return error(cat,HTXS::VH_IDENTIFICATION,"Failed to identify associated V-boson!");
316
317 /*****
318 * Step 4.
319 * Classify and save output
320 */
321
322 // Apply the categorization categorization
323 cat.isZ2vvDecay = false;
324 if( (prodMode==HTXS::GG2ZH || prodMode==HTXS::QQ2ZH) && !quarkDecay(cat.V) && !ChLeptonDecay(cat.V) ) cat.isZ2vvDecay = true;
325 cat.stage0_cat = getStage0Category(prodMode,cat.higgs,cat.V);
326 cat.stage1_cat_pTjet25GeV = getStage1Category(prodMode,cat.higgs,cat.jets25,cat.V);
327 cat.stage1_cat_pTjet30GeV = getStage1Category(prodMode,cat.higgs,cat.jets30,cat.V);
328 cat.stage1_2_cat_pTjet25GeV = getStage1_2_Category(prodMode,cat.higgs,cat.jets25,cat.V);
329 cat.stage1_2_cat_pTjet30GeV = getStage1_2_Category(prodMode,cat.higgs,cat.jets30,cat.V);
330 cat.stage1_2_fine_cat_pTjet25GeV = getStage1_2_Fine_Category(prodMode,cat.higgs,cat.jets25,cat.V);
331 cat.stage1_2_fine_cat_pTjet30GeV = getStage1_2_Fine_Category(prodMode,cat.higgs,cat.jets30,cat.V);
332 cat.stage1_3_cat_pTjet25GeV = getStage1_3_Category(prodMode,cat.higgs,cat.jets25,cat.V);
333 cat.stage1_3_cat_pTjet30GeV = getStage1_3_Category(prodMode,cat.higgs,cat.jets30,cat.V);
334 cat.stage1_3_fine_cat_pTjet25GeV = getStage1_3_Fine_Category(prodMode,cat.higgs,cat.jets25,cat.V,cat.isTHW);
335 cat.stage1_3_fine_cat_pTjet30GeV = getStage1_3_Fine_Category(prodMode,cat.higgs,cat.jets30,cat.V,cat.isTHW);
336 cat.errorCode = HTXS::SUCCESS; ++m_errorCount[HTXS::SUCCESS];
337
338 return cat;
339 }
340
346
348int getBin(double x, const std::vector<double>& bins) const {
349 if (bins.empty() || x < bins.front()) {
350 throw std::invalid_argument("Input value is out of bin range or bins vector is empty.");
351 }
352
353 for (size_t i = 1; i < bins.size(); ++i) {
354 if (x < bins[i]) {
355 return static_cast<int>(i - 1);
356 }
357 }
358
359 return static_cast<int>(bins.size() - 1);
360}
361
365 int vbfTopology(const Jets &jets, const Particle &higgs) const {
366 if (jets.size()<2) return 0;
367 const FourMomentum &j1=jets[0].momentum(), &j2=jets[1].momentum();
368 bool VBFtopo = (j1+j2).mass() > 400.0 && std::abs(j1.rapidity()-j2.rapidity()) > 2.8;
369 return VBFtopo ? (j1+j2+higgs.momentum()).pt()<25 ? 2 : 1 : 0;
370 }
371
375 int vbfTopology_Stage1_2(const Jets &jets, const Particle &higgs) const {
376 if (jets.size()<2) return 0;
377 const FourMomentum &j1=jets[0].momentum(), &j2=jets[1].momentum();
378 double mjj = (j1+j2).mass();
379 if(mjj>350 && mjj<=700) return (j1+j2+higgs.momentum()).pt()<25 ? 1 : 2;
380 else if(mjj>700) return (j1+j2+higgs.momentum()).pt()<25 ? 3 : 4;
381 else return 0;
382 }
383
389 int vbfTopology_Stage1_2_Fine(const Jets &jets, const Particle &higgs) const {
390 if (jets.size()<2) return 0;
391 const FourMomentum &j1=jets[0].momentum(), &j2=jets[1].momentum();
392 double mjj = (j1+j2).mass();
393 if(mjj>350 && mjj<=700) return (j1+j2+higgs.momentum()).pt()<25 ? 1 : 2;
394 else if(mjj>700 && mjj<=1000) return (j1+j2+higgs.momentum()).pt()<25 ? 3 : 4;
395 else if(mjj>1000 && mjj<=1500) return (j1+j2+higgs.momentum()).pt()<25 ? 5 : 6;
396 else if(mjj>1500) return (j1+j2+higgs.momentum()).pt()<25 ? 7 : 8;
397 else return 0;
398 }
399
402 int vbfTopology_Stage1_3_Fine(const Jets &jets, const Particle &higgs) const {
403 if (jets.size() < 2) return 0;
404 const FourMomentum &j1 = jets[0].momentum(), &j2 = jets[1].momentum();
405 double mjj = (j1 + j2).mass();
406 double pthjj = (j1 + j2 + higgs.momentum()).pt();
407 double deltaphijj =
408 j1.eta() > j2.eta()
409 ? deltaPhi(j1, j2)
410 : -1*deltaPhi(j1, j2);
411 // mjj-pthjj binning
412 int mjj_pthjj_bin = 0;
413 if (mjj > 350 && mjj <= 700)
414 mjj_pthjj_bin = pthjj < 25 ? 1 : 2;
415 else if (mjj > 700 && mjj <= 1000)
416 mjj_pthjj_bin = pthjj < 25 ? 3 : 4;
417 else if (mjj > 1000 && mjj <= 1500)
418 mjj_pthjj_bin = pthjj < 25 ? 5 : 6;
419 else if (mjj > 1500)
420 mjj_pthjj_bin = pthjj < 25 ? 7 : 8;
421 else
422 mjj_pthjj_bin = 0;
423 // deltaphijj binning
424 constexpr double pi = 3.14159265358979323846;
425 int deltaphijj_bin = mjj > 350 ? 8*getBin(deltaphijj, {-1*pi, -0.5*pi, 0, 0.5*pi, pi}) : 0;
426 // total vbfTopo binning
427 return deltaphijj_bin + mjj_pthjj_bin;
428 }
429
430
432 bool isVH(HTXS::HiggsProdMode p) const { return p==HTXS::WH || p==HTXS::QQ2ZH || p==HTXS::GG2ZH; }
433
436 const Particle &higgs,
437 const Particle &V) const {
438 using namespace HTXS::Stage0;
439 int ctrlHiggs = std::abs(higgs.rapidity())<2.5;
440 // Special cases first, qq→Hqq
441 if ( (prodMode==HTXS::WH||prodMode==HTXS::QQ2ZH) && quarkDecay(V) ) {
442 return ctrlHiggs ? VH2HQQ : VH2HQQ_FWDH;
443 } else if ( prodMode==HTXS::GG2ZH && quarkDecay(V) ) {
444 return Category(HTXS::GGF*10 + ctrlHiggs);
445 }
446 // General case after
447 return Category(prodMode*10 + ctrlHiggs);
448 }
449
452 const Particle &higgs,
453 const Jets &jets,
454 const Particle &V) const {
455 using namespace HTXS::Stage1;
456 int Njets=jets.size(), ctrlHiggs = std::abs(higgs.rapidity())<2.5, fwdHiggs = !ctrlHiggs;
457 double pTj1 = jets.size() ? jets[0].momentum().pt() : 0;
458 int vbfTopo = vbfTopology(jets,higgs);
459
460 // 1. GGF Stage 1 categories
461 // Following YR4 write-up: XXXXX
462 if (prodMode==HTXS::GGF || (prodMode==HTXS::GG2ZH && quarkDecay(V)) ) {
463 if (fwdHiggs) return GG2H_FWDH;
464 if (Njets==0) return GG2H_0J;
465 else if (Njets==1) return Category(GG2H_1J_PTH_0_60+getBin(higgs.pt(),{0,60,120,200}));
466 else if (Njets>=2) {
467 // events with pT_H>200 get priority over VBF cuts
468 if(higgs.pt()<=200){
469 if (vbfTopo==2) return GG2H_VBFTOPO_JET3VETO;
470 else if (vbfTopo==1) return GG2H_VBFTOPO_JET3;
471 }
472 // Njets >= 2jets without VBF topology
473 return Category(GG2H_GE2J_PTH_0_60+getBin(higgs.pt(),{0,60,120,200}));
474 }
475 }
476 // 2. Electroweak qq->Hqq Stage 1 categories
477 else if (prodMode==HTXS::VBF || ( isVH(prodMode) && quarkDecay(V)) ) {
478 if (std::abs(higgs.rapidity())>2.5) return QQ2HQQ_FWDH;
479 if (pTj1>200) return QQ2HQQ_PTJET1_GT200;
480 if (vbfTopo==2) return QQ2HQQ_VBFTOPO_JET3VETO;
481 if (vbfTopo==1) return QQ2HQQ_VBFTOPO_JET3;
482 double mjj = jets.size()>1 ? (jets[0].mom()+jets[1].mom()).mass():0;
483 if ( 60 < mjj && mjj < 120 ) return QQ2HQQ_VH2JET;
484 return QQ2HQQ_REST;
485 }
486 // 3. WH->Hlv categories
487 else if (prodMode==HTXS::WH) {
488 if (fwdHiggs) return QQ2HLNU_FWDH;
489 else if (V.pt()<150) return QQ2HLNU_PTV_0_150;
490 else if (V.pt()>250) return QQ2HLNU_PTV_GT250;
491 // 150 < pTV/GeV < 250
492 return jets.size()==0 ? QQ2HLNU_PTV_150_250_0J : QQ2HLNU_PTV_150_250_GE1J;
493 }
494 // 4. qq->ZH->llH categories
495 else if (prodMode==HTXS::QQ2ZH) {
496 if (fwdHiggs) return QQ2HLL_FWDH;
497 else if (V.pt()<150) return QQ2HLL_PTV_0_150;
498 else if (V.pt()>250) return QQ2HLL_PTV_GT250;
499 // 150 < pTV/GeV < 250
500 return jets.size()==0 ? QQ2HLL_PTV_150_250_0J : QQ2HLL_PTV_150_250_GE1J;
501 }
502 // 5. gg->ZH->llH categories
503 else if (prodMode==HTXS::GG2ZH ) {
504 if (fwdHiggs) return GG2HLL_FWDH;
505 if (V.pt()<150) return GG2HLL_PTV_0_150;
506 else if (jets.size()==0) return GG2HLL_PTV_GT150_0J;
508 }
509 // 6.ttH,bbH,tH categories
510 else if (prodMode==HTXS::TTH) return Category(TTH_FWDH+ctrlHiggs);
511 else if (prodMode==HTXS::BBH) return Category(BBH_FWDH+ctrlHiggs);
512 else if (prodMode==HTXS::TH ) return Category(TH_FWDH+ctrlHiggs);
513 return UNKNOWN;
514 }
515
518 const Particle &higgs,
519 const Jets &jets,
520 const Particle &V) const {
521 using namespace HTXS::Stage1_2;
522 int Njets=jets.size(), ctrlHiggs = std::abs(higgs.rapidity())<2.5, fwdHiggs = !ctrlHiggs;
523 int vbfTopo = vbfTopology_Stage1_2(jets,higgs);
524
525 // 1. GGF Stage 1 categories
526 // Following YR4 write-up: XXXXX
527 if (prodMode==HTXS::GGF || (prodMode==HTXS::GG2ZH && quarkDecay(V)) ) {
528 if (fwdHiggs) return GG2H_FWDH;
529 if ( higgs.pt()>200 ) return Category(GG2H_PTH_200_300+getBin(higgs.pt(),{200,300,450,650}));
530 if (Njets==0) return higgs.pt()<10 ? GG2H_0J_PTH_0_10 : GG2H_0J_PTH_GT10;
531 if (Njets==1) return Category(GG2H_1J_PTH_0_60+getBin(higgs.pt(),{0,60,120,200}));
532 if (Njets>1){
533 //VBF topology
534 if(vbfTopo) return Category(GG2H_GE2J_MJJ_350_700_PTH_0_200_PTHJJ_0_25+vbfTopo-1);
535 //Njets >= 2jets without VBF topology (mjj<350)
536 return Category(GG2H_GE2J_MJJ_0_350_PTH_0_60+getBin(higgs.pt(),{0,60,120,200}));
537 }
538 }
539
540 // 2. Electroweak qq->Hqq Stage 1.2 categories
541 else if (prodMode==HTXS::VBF || ( isVH(prodMode) && quarkDecay(V)) ) {
542 if (std::abs(higgs.rapidity())>2.5) return QQ2HQQ_FWDH;
543 int Njets=jets.size();
544 if (Njets==0) return QQ2HQQ_0J;
545 else if (Njets==1) return QQ2HQQ_1J;
546 else if (Njets>=2) {
547 double mjj = (jets[0].mom()+jets[1].mom()).mass();
548 if ( mjj < 60 ) return QQ2HQQ_GE2J_MJJ_0_60;
549 else if ( 60 < mjj && mjj < 120 ) return QQ2HQQ_GE2J_MJJ_60_120;
550 else if ( 120 < mjj && mjj < 350 ) return QQ2HQQ_GE2J_MJJ_120_350;
551 else if ( mjj > 350 ) {
552 if (higgs.pt()>200) return QQ2HQQ_GE2J_MJJ_GT350_PTH_GT200;
553 if(vbfTopo) return Category(QQ2HQQ_GE2J_MJJ_GT350_PTH_GT200+vbfTopo);
554 }
555 }
556 }
557 // 3. WH->Hlv categories
558 else if (prodMode==HTXS::WH) {
559 if (fwdHiggs) return QQ2HLNU_FWDH;
560 else if (V.pt()<75) return QQ2HLNU_PTV_0_75;
561 else if (V.pt()<150) return QQ2HLNU_PTV_75_150;
562 else if (V.pt()>250) return QQ2HLNU_PTV_GT250;
563 // 150 < pTV/GeV < 250
564 return jets.size()==0 ? QQ2HLNU_PTV_150_250_0J : QQ2HLNU_PTV_150_250_GE1J;
565 }
566 // 4. qq->ZH->llH categories
567 else if (prodMode==HTXS::QQ2ZH) {
568 if (fwdHiggs) return QQ2HLL_FWDH;
569 else if (V.pt()<75) return QQ2HLL_PTV_0_75;
570 else if (V.pt()<150) return QQ2HLL_PTV_75_150;
571 else if (V.pt()>250) return QQ2HLL_PTV_GT250;
572 // 150 < pTV/GeV < 250
573 return jets.size()==0 ? QQ2HLL_PTV_150_250_0J : QQ2HLL_PTV_150_250_GE1J;
574 }
575 // 5. gg->ZH->llH categories
576 else if (prodMode==HTXS::GG2ZH ) {
577 if (fwdHiggs) return GG2HLL_FWDH;
578 else if (V.pt()<75) return GG2HLL_PTV_0_75;
579 else if (V.pt()<150) return GG2HLL_PTV_75_150;
580 else if (V.pt()>250) return GG2HLL_PTV_GT250;
581 return jets.size()==0 ? GG2HLL_PTV_150_250_0J : GG2HLL_PTV_150_250_GE1J;
582 }
583 // 6.ttH,bbH,tH categories
584 else if (prodMode==HTXS::TTH) {
585 if (fwdHiggs) return TTH_FWDH;
586 else return Category(TTH_PTH_0_60+getBin(higgs.pt(),{0,60,120,200,300}));
587 }
588 else if (prodMode==HTXS::BBH) return Category(BBH_FWDH+ctrlHiggs);
589 else if (prodMode==HTXS::TH ) return Category(TH_FWDH+ctrlHiggs);
590 return UNKNOWN;
591 }
592
595 const Particle &higgs,
596 const Jets &jets,
597 const Particle &V) const {
598 using namespace HTXS::Stage1_2_Fine;
599 int Njets=jets.size(), ctrlHiggs = std::abs(higgs.rapidity())<2.5, fwdHiggs = !ctrlHiggs;
600 int vbfTopo = vbfTopology_Stage1_2_Fine(jets,higgs);
601
602 // 1. GGF Stage 1.2 categories
603 // Following YR4 write-up: XXXXX
604 if (prodMode==HTXS::GGF || (prodMode==HTXS::GG2ZH && quarkDecay(V)) ) {
605 if (fwdHiggs) return GG2H_FWDH;
606 if ( higgs.pt()>200 ){
607 if (Njets>0){
608 double pTHj = (jets[0].momentum()+higgs.momentum()).pt();
609 if( pTHj/higgs.pt()>0.15 ) return Category(GG2H_PTH_200_300_PTHJoverPTH_GT15+getBin(higgs.pt(),{200,300,450,650}));
610 else return Category(GG2H_PTH_200_300_PTHJoverPTH_0_15+getBin(higgs.pt(),{200,300,450,650}));
611 }
612 else return Category(GG2H_PTH_200_300_PTHJoverPTH_0_15+getBin(higgs.pt(),{200,300,450,650}));
613 }
614 if (Njets==0) return higgs.pt()<10 ? GG2H_0J_PTH_0_10 : GG2H_0J_PTH_GT10;
615 if (Njets==1) return Category(GG2H_1J_PTH_0_60+getBin(higgs.pt(),{0,60,120,200}));
616 if (Njets>1){
617 //double mjj = (jets[0].mom()+jets[1].mom()).mass();
618 double pTHjj = (jets[0].momentum()+jets[1].momentum()+higgs.momentum()).pt();
619 //VBF topology
620 if(vbfTopo) return Category(GG2H_GE2J_MJJ_350_700_PTH_0_200_PTHJJ_0_25+vbfTopo-1);
621 //Njets >= 2jets without VBF topology (mjj<350)
622 if (pTHjj<25) return Category(GG2H_GE2J_MJJ_0_350_PTH_0_60_PTHJJ_0_25+getBin(higgs.pt(),{0,60,120,200}));
623 else return Category(GG2H_GE2J_MJJ_0_350_PTH_0_60_PTHJJ_GT25+getBin(higgs.pt(),{0,60,120,200}));
624 }
625 }
626
627 // 2. Electroweak qq->Hqq Stage 1.2 categories
628 else if (prodMode==HTXS::VBF || ( isVH(prodMode) && quarkDecay(V)) ) {
629 if (std::abs(higgs.rapidity())>2.5) return QQ2HQQ_FWDH;
630 int Njets=jets.size();
631 if (Njets==0) return QQ2HQQ_0J;
632 else if (Njets==1) return QQ2HQQ_1J;
633 else if (Njets>=2) {
634 double mjj = (jets[0].mom()+jets[1].mom()).mass();
635 double pTHjj = (jets[0].momentum()+jets[1].momentum()+higgs.momentum()).pt();
636 if (mjj<350){
637 if (pTHjj<25) return Category(QQ2HQQ_GE2J_MJJ_0_60_PTHJJ_0_25+getBin(mjj,{0,60,120,350}));
638 else return Category(QQ2HQQ_GE2J_MJJ_0_60_PTHJJ_GT25+getBin(mjj,{0,60,120,350}));
639 } else { //mjj>350 GeV
640 if (higgs.pt()<200){
642 } else {
644 }
645 }
646 }
647 }
648 // 3. WH->Hlv categories
649 else if (prodMode==HTXS::WH) {
650 if (fwdHiggs) return QQ2HLNU_FWDH;
651 int Njets=jets.size();
652 if (Njets==0) return Category(QQ2HLNU_PTV_0_75_0J+getBin(V.pt(),{0,75,150,250,400}));
653 if (Njets==1) return Category(QQ2HLNU_PTV_0_75_1J+getBin(V.pt(),{0,75,150,250,400}));
654 return Category(QQ2HLNU_PTV_0_75_GE2J+getBin(V.pt(),{0,75,150,250,400}));
655 }
656 // 4. qq->ZH->llH categories
657 else if (prodMode==HTXS::QQ2ZH) {
658 if (fwdHiggs) return QQ2HLL_FWDH;
659 int Njets=jets.size();
660 if (Njets==0) return Category(QQ2HLL_PTV_0_75_0J+getBin(V.pt(),{0,75,150,250,400}));
661 if (Njets==1) return Category(QQ2HLL_PTV_0_75_1J+getBin(V.pt(),{0,75,150,250,400}));
662 return Category(QQ2HLL_PTV_0_75_GE2J+getBin(V.pt(),{0,75,150,250,400}));
663 }
664 // 5. gg->ZH->llH categories
665 else if (prodMode==HTXS::GG2ZH ) {
666 if (fwdHiggs) return GG2HLL_FWDH;
667 int Njets=jets.size();
668 if (Njets==0) return Category(GG2HLL_PTV_0_75_0J+getBin(V.pt(),{0,75,150,250,400}));
669 if (Njets==1) return Category(GG2HLL_PTV_0_75_1J+getBin(V.pt(),{0,75,150,250,400}));
670 return Category(GG2HLL_PTV_0_75_GE2J+getBin(V.pt(),{0,75,150,250,400}));
671 }
672 // 6.ttH,bbH,tH categories
673 else if (prodMode==HTXS::TTH) {
674 if (fwdHiggs) return TTH_FWDH;
675 else return Category(TTH_PTH_0_60+getBin(higgs.pt(),{0,60,120,200,300,450}));
676 }
677 else if (prodMode==HTXS::BBH) return Category(BBH_FWDH+ctrlHiggs);
678 else if (prodMode==HTXS::TH ) return Category(TH_FWDH+ctrlHiggs);
679 return UNKNOWN;
680 }
681
683 const Jets &jets, const Particle &V) const {
684 using namespace HTXS::Stage1_3;
685 int Njets = jets.size(), ctrlHiggs = std::abs(higgs.rapidity()) < 2.5, fwdHiggs = !ctrlHiggs;
686 int vbfTopo = vbfTopology(jets, higgs);
687
688 // 1. GGF Stage 1.3 categories
689 if (prodMode == HTXS::GGF || (prodMode == HTXS::GG2ZH && quarkDecay(V))) {
690 if (fwdHiggs) return GG2H_FWDH;
691 if (higgs.pt() > 200) return Category(GG2H_PTH_200_300 + getBin(higgs.pt(), {200, 300, 450, 650, 1000}));
692 if (Njets == 0) return Category(GG2H_0J_PTH_0_5 + getBin(higgs.pt(), {0, 5, 10, 15, 20, 25, 30, 200}));
693 if (Njets == 1) return Category(GG2H_1J_PTH_0_30 + getBin(higgs.pt(), {0, 30, 60, 120, 200}));
694 if (Njets > 1) {
695 // VBF topology
696 if (vbfTopo) return Category(GG2H_GE2J_MJJ_350_700_PTH_0_200_PTHJJ_0_25 + vbfTopo - 1);
697 // Njets >= 2jets without VBF topology (mjj<350)
698 return Category(GG2H_GE2J_MJJ_0_350_PTH_0_30 + getBin(higgs.pt(), {0, 30, 60, 120, 200}));
699 }
700 }
701 // 2. Electroweak qq->Hqq Stage 1.3 categories
702 else if (prodMode == HTXS::VBF || (isVH(prodMode) && quarkDecay(V))) {
703 if (std::abs(higgs.rapidity()) > 2.5) return QQ2HQQ_FWDH;
704 int Njets = jets.size();
705 if (Njets == 0)
706 return QQ2HQQ_0J;
707 else if (Njets == 1)
708 return QQ2HQQ_1J;
709 else if (Njets >= 2) {
710 double mjj = (jets[0].mom() + jets[1].mom()).mass();
711 if (mjj < 60)
713 else if (60 < mjj && mjj < 120)
715 else if (120 < mjj && mjj < 350)
717 else if (mjj > 350) {
718 if (higgs.pt() > 200)
720 if (vbfTopo) return Category(QQ2HQQ_GE2J_MJJ_350_700_PTH_0_200_PTHJJ_0_25 + vbfTopo - 1);
721 }
722 }
723 }
724 // 3. WH->Hlv Stage 1.3 categories
725 else if (prodMode == HTXS::WH) {
726 if (fwdHiggs)
727 return QQ2HLNU_FWDH;
728 else if (V.pt() < 75)
729 return QQ2HLNU_PTV_0_75;
730 else if (V.pt() < 150)
731 return QQ2HLNU_PTV_75_150;
732 else if (V.pt() < 250)
733 return jets.size() == 0 ? QQ2HLNU_PTV_150_250_0J : QQ2HLNU_PTV_150_250_GE1J;
734 else if (V.pt() < 400)
735 return jets.size() == 0 ? QQ2HLNU_PTV_250_400_0J : QQ2HLNU_PTV_250_400_GE1J;
736 else if (V.pt() < 600)
737 return QQ2HLNU_PTV_400_600;
738 return QQ2HLNU_PTV_GT600;
739 }
740 // 4. qq->ZH->llH Stage 1.3 categories
741 else if (prodMode == HTXS::QQ2ZH) {
742 if (fwdHiggs)
743 return QQ2HLL_FWDH;
744 else if (V.pt() < 75)
745 return QQ2HLL_PTV_0_75;
746 else if (V.pt() < 150)
747 return QQ2HLL_PTV_75_150;
748 else if (V.pt() < 250)
749 return jets.size() == 0 ? QQ2HLL_PTV_150_250_0J : QQ2HLL_PTV_150_250_GE1J;
750 else if (V.pt() < 400)
751 return jets.size() == 0 ? QQ2HLL_PTV_250_400_0J : QQ2HLL_PTV_250_400_GE1J;
752 else if (V.pt() < 600)
753 return QQ2HLL_PTV_400_600;
754 return QQ2HLL_PTV_GT600;
755 }
756 // 5. gg->ZH->llH Stage 1.3 categories
757 else if (prodMode == HTXS::GG2ZH) {
758 if (fwdHiggs)
759 return GG2HLL_FWDH;
760 else if (V.pt() < 75)
761 return GG2HLL_PTV_0_75;
762 else if (V.pt() < 150)
763 return GG2HLL_PTV_75_150;
764 else if (V.pt() < 250)
765 return jets.size() == 0 ? GG2HLL_PTV_150_250_0J : GG2HLL_PTV_150_250_GE1J;
766 else if (V.pt() < 400)
767 return jets.size() == 0 ? GG2HLL_PTV_250_400_0J : GG2HLL_PTV_250_400_GE1J;
768 else if (V.pt() < 600)
769 return GG2HLL_PTV_400_600;
770 return GG2HLL_PTV_GT600;
771 }
772 // 6.ttH,bbH,tH Stage 1.3 categories
773 else if (prodMode == HTXS::TTH) {
774 if (fwdHiggs)
775 return TTH_FWDH;
776 else
777 return Category(TTH_PTH_0_60 + getBin(higgs.pt(), {0, 60, 120, 200, 300, 450, 650}));
778 } else if (prodMode == HTXS::BBH)
779 return Category(BBH_FWDH + ctrlHiggs);
780 else if (prodMode == HTXS::TH)
781 return Category(TH_FWDH + ctrlHiggs);
782 return UNKNOWN;
783 }
784
787 const Jets &jets, const Particle &V, const bool isTHW) const {
788 using namespace HTXS::Stage1_3_Fine;
789 int Njets = jets.size(), ctrlHiggs = std::abs(higgs.rapidity()) < 2.5, fwdHiggs = !ctrlHiggs;
790 int vbfTopo = vbfTopology_Stage1_3_Fine(jets, higgs);
791
792 // For debugging:
793 std::cout << "[Event] pth = " << higgs.pt() << ", yh = " << std::abs(higgs.rapidity()) << ", njet = " << Njets << ", ptv = " << V.pt() << std::endl;
794 if (Njets >= 1){
795 double pthj = (jets[0].momentum() + higgs.momentum()).pt();
796 std::cout << "pthj/pth = " << pthj/higgs.pt() << std::endl;
797 }
798 if (Njets >= 2){
799 double mjj = (jets[0].mom() + jets[1].mom()).mass();
800 double pthjj = (jets[0].momentum() + jets[1].momentum() + higgs.momentum()).pt();
801 double deltaphijj =
802 jets[0].eta() > jets[1].eta()
803 ? deltaPhi(jets[0], jets[1])
804 : -1*deltaPhi(jets[0], jets[1]);
805 std::cout << "mjj = " << mjj << ", pthjj = " << pthjj << ", dphijj = " << deltaphijj << std::endl;
806 }
807
808 // 1. GGF Stage 1.3 categories (fine)
809 if (prodMode == HTXS::GGF || (prodMode == HTXS::GG2ZH && quarkDecay(V))) {
810 if (fwdHiggs) return GG2H_FWDH;
811 if (higgs.pt() > 200) {
812 if (Njets > 0) {
813 double pthj = (jets[0].momentum() + higgs.momentum()).pt();
814 if (pthj / higgs.pt() > 0.15)
815 return Category(GG2H_PTH_200_300_PTHJoverPTH_GT15 + getBin(higgs.pt(), {200, 300, 450, 650, 1000}));
816 else
817 return Category(GG2H_PTH_200_300_PTHJoverPTH_0_15 + getBin(higgs.pt(), {200, 300, 450, 650, 1000}));
818 } else
819 return Category(GG2H_PTH_200_300_PTHJoverPTH_0_15 + getBin(higgs.pt(), {200, 300, 450, 650, 1000}));
820 }
821 if (Njets == 0) return Category(GG2H_0J_PTH_0_5 + getBin(higgs.pt(), {0, 5, 10, 15, 20, 25, 30, 200}));
822 if (Njets == 1) return Category(GG2H_1J_PTH_0_30 + getBin(higgs.pt(), {0, 30, 60, 120, 200}));
823 if (Njets > 1) {
824 double mjj = (jets[0].mom()+jets[1].mom()).mass();
825 double pthjj = (jets[0].momentum() + jets[1].momentum() + higgs.momentum()).pt();
826 // VBF topology
827 if (mjj < 350){
828 if (pthjj < 25)
829 return Category(GG2H_GE2J_MJJ_0_350_PTH_0_30_PTHJJ_0_25 + getBin(higgs.pt(), {0, 30, 60, 120, 200}));
830 else
831 return Category(GG2H_GE2J_MJJ_0_350_PTH_0_30_PTHJJ_GT25 + getBin(higgs.pt(), {0, 30, 60, 120, 200}));
832 } else
834 }
835 }
836
837 // 2. Electroweak qq->Hqq Stage 1.3 categories (fine)
838 else if (prodMode == HTXS::VBF || (isVH(prodMode) && quarkDecay(V))) {
839 if (std::abs(higgs.rapidity()) > 2.5) return QQ2HQQ_FWDH;
840 int Njets = jets.size();
841 if (Njets == 0)
842 return QQ2HQQ_0J;
843 else if (Njets == 1)
844 return Category(QQ2HQQ_1J_PTH_0_200 + getBin(higgs.pt(), {0, 200, 450, 650}));
845 else if (Njets >= 2) {
846 double mjj = (jets[0].mom() + jets[1].mom()).mass();
847 double pthjj = (jets[0].momentum() + jets[1].momentum() + higgs.momentum()).pt();
848 if (mjj < 350) {
849 if (higgs.pt() < 200){
850 if (pthjj < 25)
851 return Category(QQ2HQQ_GE2J_MJJ_0_60_PTH_0_200_PTHJJ_0_25 + getBin(mjj, {0, 60, 120, 350}));
852 else
853 return Category(QQ2HQQ_GE2J_MJJ_0_60_PTH_0_200_PTHJJ_GT25 + getBin(mjj, {0, 60, 120, 350}));
854 } else {
855 if (pthjj < 25)
856 return Category(QQ2HQQ_GE2J_MJJ_0_60_PTH_GT200_PTHJJ_0_25 + getBin(mjj, {0, 60, 120, 350}));
857 else
858 return Category(QQ2HQQ_GE2J_MJJ_0_60_PTH_GT200_PTHJJ_GT25 + getBin(mjj, {0, 60, 120, 350}));
859 }
860 } else { // mjj>350 GeV
861 if (higgs.pt() < 200)
863 else if (higgs.pt() < 450)
865 else
866 return Category(QQ2HQQ_GE2J_MJJ_350_700_PTH_GT450 + getBin(mjj, {350, 700, 1000, 1500}));
867 }
868 }
869 }
870
871 // 3. WH->Hlv Stage 1.3 categories (fine)
872 else if (prodMode == HTXS::WH) {
873 if (fwdHiggs) return QQ2HLNU_FWDH;
874 int Njets = jets.size();
875 if (Njets == 0) return Category(QQ2HLNU_PTV_0_75_0J + getBin(V.pt(), {0, 75, 150, 250, 400, 600}));
876 if (Njets == 1) return Category(QQ2HLNU_PTV_0_75_1J + getBin(V.pt(), {0, 75, 150, 250, 400, 600}));
877 return Category(QQ2HLNU_PTV_0_75_GE2J + getBin(V.pt(), {0, 75, 150, 250, 400, 600}));
878 }
879
880 // 4. qq->ZH->llH Stage 1.3 categories (fine)
881 else if (prodMode == HTXS::QQ2ZH) {
882 if (fwdHiggs) return QQ2HLL_FWDH;
883 int Njets = jets.size();
884 if (Njets == 0) return Category(QQ2HLL_PTV_0_75_0J + getBin(V.pt(), {0, 75, 150, 250, 400, 600}));
885 if (Njets == 1) return Category(QQ2HLL_PTV_0_75_1J + getBin(V.pt(), {0, 75, 150, 250, 400, 600}));
886 return Category(QQ2HLL_PTV_0_75_GE2J + getBin(V.pt(), {0, 75, 150, 250, 400, 600}));
887 }
888
889 // 5. gg->ZH->llH Stage 1.3 categories (fine)
890 else if (prodMode == HTXS::GG2ZH) {
891 if (fwdHiggs) return GG2HLL_FWDH;
892 int Njets = jets.size();
893 if (Njets == 0) return Category(GG2HLL_PTV_0_75_0J + getBin(V.pt(), {0, 75, 150, 250, 400, 600}));
894 if (Njets == 1) return Category(GG2HLL_PTV_0_75_1J + getBin(V.pt(), {0, 75, 150, 250, 400, 600}));
895 return Category(GG2HLL_PTV_0_75_GE2J + getBin(V.pt(), {0, 75, 150, 250, 400, 600}));
896 }
897
898 // 6.ttH,bbH,tH Stage 1.3 categories (fine)
899 else if (prodMode == HTXS::TTH) {
900 if (fwdHiggs)
901 return TTH_FWDH;
902 else
903 return Category(TTH_PTH_0_60 + getBin(higgs.pt(), {0, 60, 120, 200, 300, 450, 650}));
904 } else if (prodMode == HTXS::BBH)
905 return Category(BBH_FWDH + ctrlHiggs);
906 else if (prodMode == HTXS::TH)
907 return Category(THQ_FWDH + 2*isTHW + ctrlHiggs);
908 return UNKNOWN;
909 }
910
911
914
917
921 void init() {
922 printf("==============================================================\n");
923 printf("======== HiggsTemplateCrossSections Initialization =========\n");
924 printf("==============================================================\n");
925 // check that the production mode has been set
926 // if running in standalone Rivet the production mode is set through an env variable
928 char *pm_env = getenv("HIGGSPRODMODE");
929 string pm(pm_env==nullptr?"":pm_env);
930 if ( pm == "GGF" ) m_HiggsProdMode = HTXS::GGF;
931 else if ( pm == "VBF" ) m_HiggsProdMode = HTXS::VBF;
932 else if ( pm == "WH" ) m_HiggsProdMode = HTXS::WH;
933 else if ( pm == "ZH" ) m_HiggsProdMode = HTXS::QQ2ZH;
934 else if ( pm == "QQ2ZH" ) m_HiggsProdMode = HTXS::QQ2ZH;
935 else if ( pm == "GG2ZH" ) m_HiggsProdMode = HTXS::GG2ZH;
936 else if ( pm == "TTH" ) m_HiggsProdMode = HTXS::TTH;
937 else if ( pm == "BBH" ) m_HiggsProdMode = HTXS::BBH;
938 else if ( pm == "TH" ) m_HiggsProdMode = HTXS::TH;
939 else {
940 MSG_WARNING("No HIGGSPRODMODE shell variable found. Needed when running Rivet stand-alone.");
941 }
942 }
943
944 // Projections for final state particles
945 const FinalState FS;
946 declare(FS,"FS");
947
948 // initialize the histograms with for each of the stages
950 m_sumw = 0.0;
951 printf("==============================================================\n");
952 printf("======== Higgs prod mode %d =========\n",m_HiggsProdMode);
953 printf("======== Sucessful Initialization =========\n");
954 printf("==============================================================\n");
955 }
956
957 // Perform the per-event analysis
958 void analyze(const Event& event) {
959
960 // get the classification
961 HiggsClassification cat = classifyEvent(event,m_HiggsProdMode);
962
963 // Fill histograms: categorization --> linerize the categories
964 const double weight = 1.; // Event weights are now all 1 in Rivet
965 m_sumw += weight;
966
967 int F=cat.stage0_cat%10, P=cat.stage1_cat_pTjet30GeV/100;
968 m_hist_stage0->fill( cat.stage0_cat/10*2+F, weight );
969
970 // Stage 1 enum offsets for each production mode: GGF=12, VBF=6, WH= 5, QQ2ZH=5, GG2ZH=4, TTH=2, BBH=2, TH=2
971 static const vector<int> offset({0,1,13,19,24,29,33,35,37,39});
972 int off = offset[P];
973 // Stage 1.2 enum offsets for each production mode: GGF=17, VBF=11, WH= 6, QQ2ZH=6, GG2ZH=6, TTH=6, BBH=2, TH=2
974 static const vector<int> offset1_2({0,1,18,29,35,41,47,53,55,57});
975 int off1_2 = offset1_2[P];
976 // Stage 1.2-Fine enum offsets for each production mode: GGF=28, VBF=25, WH= 16, QQ2ZH=16, GG2ZH=16, TTH=7, BBH=2, TH=2
977 static const vector<int> offset1_2_Fine({0,1,29,54,70,86,102,109,111,113});
978 int off1_2_Fine = offset1_2_Fine[P];
979 // Stage 1_3 enum offsets for each production mode: GGF=25, VBF=15, WH= 9, QQ2ZH=9, GG2ZH=9, TTH=8, BBH=2, TH=2
980 static const vector<int> offset1_3({0,1,26,41,50,59,68,76,78,80});
981 int off1_3 = offset1_3[P];
982 // Stage 1_3 Fine enum offsets for each production mode: GGF=62, VBF=86, WH= 19, QQ2ZH=19, GG2ZH=19, TTH=8, BBH=2, TH=3
983 static const vector<int> offset1_3_fine({0,1,63,149,168,187,206,214,216,219});
984 int off1_3_fine = offset1_3_fine[P];
985
986
987 m_hist_stage1_pTjet25->fill(cat.stage1_cat_pTjet25GeV%100 + off, weight);
988 m_hist_stage1_pTjet30->fill(cat.stage1_cat_pTjet30GeV%100 + off, weight);
989 m_hist_stage1_2_pTjet25->fill(cat.stage1_2_cat_pTjet25GeV%100 + off1_2, weight);
990 m_hist_stage1_2_pTjet30->fill(cat.stage1_2_cat_pTjet30GeV%100 + off1_2, weight);
991 m_hist_stage1_2_fine_pTjet25->fill(cat.stage1_2_fine_cat_pTjet25GeV%100 + off1_2_Fine, weight);
992 m_hist_stage1_2_fine_pTjet30->fill(cat.stage1_2_fine_cat_pTjet30GeV%100 + off1_2_Fine, weight);
993 m_hist_stage1_3_pTjet25->fill(cat.stage1_3_cat_pTjet25GeV%100 + off1_3, weight);
994 m_hist_stage1_3_pTjet30->fill(cat.stage1_3_cat_pTjet30GeV%100 + off1_3, weight);
995 m_hist_stage1_3_fine_pTjet25->fill(cat.stage1_3_fine_cat_pTjet25GeV%100 + off1_3_fine, weight);
996 m_hist_stage1_3_fine_pTjet30->fill(cat.stage1_3_fine_cat_pTjet30GeV%100 + off1_3_fine, weight);
997
998 // Fill histograms: variables used in the categorization
999 m_hist_pT_Higgs->fill(cat.higgs.pT(),weight);
1000 m_hist_y_Higgs->fill(cat.higgs.rapidity(),weight);
1001 m_hist_pT_V->fill(cat.V.pT(),weight);
1002
1003 m_hist_Njets25->fill(cat.jets25.size(),weight);
1004 m_hist_Njets30->fill(cat.jets30.size(),weight);
1005
1006 m_hist_isZ2vv->fill(cat.isZ2vvDecay, weight);
1007
1008 // Jet variables. Use jet collection with pT threshold at 30 GeV
1009 if (cat.jets30.size()) m_hist_pT_jet1->fill(cat.jets30[0].pt(),weight);
1010 if (cat.jets30.size()>=2) {
1011 const FourMomentum &j1 = cat.jets30[0].momentum(), &j2 = cat.jets30[1].momentum();
1012 m_hist_deltay_jj->fill(std::abs(j1.rapidity()-j2.rapidity()),weight);
1013 m_hist_dijet_mass->fill((j1+j2).mass(),weight);
1014 m_hist_pT_Hjj->fill((j1+j2+cat.higgs.momentum()).pt(),weight);
1015 }
1016 }
1017
1019 MSG_INFO (" ====================================================== ");
1020 MSG_INFO (" Higgs Template X-Sec Categorization Tool ");
1021 MSG_INFO (" Status Code Summary ");
1022 MSG_INFO (" ====================================================== ");
1023 bool allSuccess = (numEvents()==m_errorCount[HTXS::SUCCESS]);
1024 if ( allSuccess ) MSG_INFO (" >>>> All "<< m_errorCount[HTXS::SUCCESS] <<" events successfully categorized!");
1025 else{
1026 MSG_INFO (" >>>> "<< m_errorCount[HTXS::SUCCESS] <<" events successfully categorized");
1027 MSG_INFO (" >>>> --> the following errors occured:");
1028 MSG_INFO (" >>>> "<< m_errorCount[HTXS::PRODMODE_DEFINED] <<" had an undefined Higgs production mode.");
1029 MSG_INFO (" >>>> "<< m_errorCount[HTXS::MOMENTUM_CONSERVATION] <<" failed momentum conservation.");
1030 MSG_INFO (" >>>> "<< m_errorCount[HTXS::HIGGS_IDENTIFICATION] <<" failed to identify a valid Higgs boson.");
1031 MSG_INFO (" >>>> "<< m_errorCount[HTXS::HS_VTX_IDENTIFICATION] <<" failed to identify the hard scatter vertex.");
1032 MSG_INFO (" >>>> "<< m_errorCount[HTXS::VH_IDENTIFICATION] <<" VH: to identify a valid V-boson.");
1033 MSG_INFO (" >>>> "<< m_errorCount[HTXS::TOP_W_IDENTIFICATION] <<" failed to identify valid Ws from top decay.");
1034 }
1035 MSG_INFO (" ====================================================== ");
1036 MSG_INFO (" ====================================================== ");
1037 }
1038
1039
1047
1048 /*
1049 * initialize histograms
1050 */
1051
1053 book(m_hist_stage0,"HTXS_stage0",20,0,20);
1054 book(m_hist_stage1_pTjet25,"HTXS_stage1_pTjet25",40,0,40);
1055 book(m_hist_stage1_pTjet30,"HTXS_stage1_pTjet30",40,0,40);
1056 book(m_hist_stage1_2_pTjet25,"HTXS_stage1_2_pTjet25",57,0,57);
1057 book(m_hist_stage1_2_pTjet30,"HTXS_stage1_2_pTjet30",57,0,57);
1058 book(m_hist_stage1_2_fine_pTjet25,"HTXS_stage1_2_fine_pTjet25",113,0,113);
1059 book(m_hist_stage1_2_fine_pTjet30,"HTXS_stage1_2_fine_pTjet30",113,0,113);
1060 book(m_hist_stage1_3_pTjet25, "STXS_stage1_3_pTjet25", 80, 0, 80);
1061 book(m_hist_stage1_3_pTjet30, "STXS_stage1_3_pTjet30", 80, 0, 80);
1062 book(m_hist_stage1_3_fine_pTjet25, "STXS_stage1_3_fine_pTjet25", 220, 0, 220);
1063 book(m_hist_stage1_3_fine_pTjet30, "STXS_stage1_3_fine_pTjet30", 220, 0, 220);
1064 book(m_hist_pT_Higgs,"pT_Higgs",80,0,400);
1065 book(m_hist_y_Higgs,"y_Higgs",80,-4,4);
1066 book(m_hist_pT_V,"pT_V",80,0,400);
1067 book(m_hist_pT_jet1,"pT_jet1",80,0,400);
1068 book(m_hist_deltay_jj ,"deltay_jj",50,0,10);
1069 book(m_hist_dijet_mass,"m_jj",50,0,2000);
1070 book(m_hist_pT_Hjj,"pT_Hjj",50,0,250);
1071 book(m_hist_Njets25,"Njets25",10,0,10);
1072 book(m_hist_Njets30,"Njets30",10,0,10);
1073 book(m_hist_isZ2vv,"isZ2vv",2,0,2);
1074 }
1075
1076
1077 /*
1078 * initialize private members used in the classification procedure
1079 */
1080
1081 private:
1082 double m_sumw=0.0;
1084 mutable std::array<std::atomic<size_t>, HTXS::NUM_ERRORCODES> m_errorCount ATLAS_THREAD_SAFE {};
1085 Histo1DPtr m_hist_stage0;
1095 Histo1DPtr m_hist_isZ2vv;
1096 };
1097
1098 // the PLUGIN only needs to be decleared when running standalone Rivet
1099 // and causes compilation / linking issues if included in Athena / RootCore
1100 //check for Rivet environment variable RIVET_ANALYSIS_PATH
1101#ifdef RIVET_ANALYSIS_PATH
1102 // The hook for the plugin system
1103 DECLARE_RIVET_PLUGIN(HiggsTemplateCrossSections);
1104#endif
1105
1106}
1107
1108#endif
Scalar deltaPhi(const MatrixBase< Derived > &vec) const
static Double_t P(Double_t *tt, Double_t *par)
#define F(x, y, z)
Definition MD5.cxx:112
static const std::vector< std::string > bins
#define pi
@ top
#define x
Define macros for attributes used to control the static checker.
Rivet routine for classifying MC events according to the Higgs template cross section categories.
int vbfTopology_Stage1_2_Fine(const Jets &jets, const Particle &higgs) const
VBF topology selection for Stage1_2 0 = fail loose selection: m_jj > 350 GeV 1 pass loose,...
HiggsClassification error(HiggsClassification &cat, HTXS::ErrorCode err, std::string_view msg={}, int NmaxWarnings=20) const
Returns the classification object with the error code set.
bool originateFrom(const Particle &p, const Particle &p2) const
Whether particle p originates from p2.
void setHiggsProdMode(HTXS::HiggsProdMode prodMode)
Sets the Higgs production mode.
void init()
default Rivet Analysis::init method Booking of histograms, initializing Rivet projection Extracts Hig...
bool originateFrom(const Particle &p, const Particles &ptcls) const
Whether particle p originate from any of the ptcls.
int vbfTopology_Stage1_2(const Jets &jets, const Particle &higgs) const
VBF topology selection 0 = fail loose selection: m_jj > 350 GeV 1 pass loose, but fail additional cut...
HTXS::Stage1_3::Category getStage1_3_Category(const HTXS::HiggsProdMode prodMode, const Particle &higgs, const Jets &jets, const Particle &V) const
Stage-1.3 categorization.
bool isVH(HTXS::HiggsProdMode p) const
Whether the Higgs is produced in association with a vector boson (VH).
Particle getLastInstance(const Particle &ptcl) const
follow a "propagating" particle and return its last instance
HTXS::Stage1_2_Fine::Category getStage1_2_Fine_Category(const HTXS::HiggsProdMode prodMode, const Particle &higgs, const Jets &jets, const Particle &V) const
Stage-1.2_Fine categorization.
bool quarkDecay(const Particle &p) const
Return true is particle decays to quarks.
bool hasParent(HepMC::ConstGenParticlePtr ptcl, int pdgID) const
Checks whether the input particle has a parent with a given PDGID.
int vbfTopology_Stage1_3_Fine(const Jets &jets, const Particle &higgs) const
VBF topology selection for Stage1_3 Includes additional deltaphijj binning.
int getBin(double x, const std::vector< double > &bins) const
Return bin index of x given the provided bin edges. 0=first bin, -1=underflow bin.
HiggsClassification classifyEvent(const Event &event, const HTXS::HiggsProdMode prodMode) const
Main classificaion method.
bool hasChild(HepMC::ConstGenParticlePtr ptcl, int pdgID) const
Checks whether the input particle has a child with a given PDGID.
HTXS::Stage1::Category getStage1Category(const HTXS::HiggsProdMode prodMode, const Particle &higgs, const Jets &jets, const Particle &V) const
Stage-1 categorization.
HTXS::Stage1_3_Fine::Category getStage1_3_Fine_Category(const HTXS::HiggsProdMode prodMode, const Particle &higgs, const Jets &jets, const Particle &V, const bool isTHW) const
Stage-1.3 Fine categorization.
HTXS::Stage0::Category getStage0Category(const HTXS::HiggsProdMode prodMode, const Particle &higgs, const Particle &V) const
Stage-0 HTXS categorization.
bool ChLeptonDecay(const Particle &p) const
Return true if particle decays to charged leptons.
HTXS::Stage1_2::Category getStage1_2_Category(const HTXS::HiggsProdMode prodMode, const Particle &higgs, const Jets &jets, const Particle &V) const
Stage-1.2 categorization.
std::array< std::atomic< size_t >, HTXS::NUM_ERRORCODES > m_errorCount ATLAS_THREAD_SAFE
int vbfTopology(const Jets &jets, const Particle &higgs) const
VBF topolog selection 0 = fail loose selction: m_jj > 400 GeV and Dy_jj > 2.8 1 pass loose,...
The namespace of all packages in PhysicsAnalysis/JetTagging.
Two digit number of format PF P is digit for the physics process and F is 0 for |yH|>2....
Categorization Stage 1.2: Three digit integer of format PF Where P is a digit representing the proces...
Categorization Stage 1.3: Three digit integer of format PF Where P is a digit representing the proces...
Categorization Stage 1: Three digit integer of format PF Where P is a digit representing the process ...
Higgs Template Cross Section namespace.
ErrorCode
Error code: whether the classification was successful or failed.
@ HS_VTX_IDENTIFICATION
failed to identify hard scatter vertex
@ PRODMODE_DEFINED
production mode not defined
@ SUCCESS
successful classification
@ VH_DECAY_IDENTIFICATION
failed to identify associated vector boson decay products
@ HIGGS_IDENTIFICATION
failed to identify Higgs boson
@ TOP_W_IDENTIFICATION
failed to identify top decay
@ HIGGS_DECAY_IDENTIFICATION
failed to identify Higgs boson decay products
@ MOMENTUM_CONSERVATION
failed momentum conservation
@ NUM_ERRORCODES
number of error codes (keep this unnumbered and last)
@ VH_IDENTIFICATION
failed to identify associated vector boson
HiggsProdMode
Higgs production modes, corresponding to input sample.
ConstGenVertexPtr signal_process_vertex(const GenEvent *e)
Definition GenEvent.h:597
HepMC3::ConstGenParticlePtr ConstGenParticlePtr
Definition GenParticle.h:20
Definition Jets.py:1
#define MSG_WARNING(ARG)
#define MSG_INFO(ARG)
MsgStream & msg
Definition testRead.cxx:32