5#ifndef TRUTHRIVETTOOLS_HIGGSTEMPLATECROSSSECTIONS_H
6#define TRUTHRIVETTOOLS_HIGGSTEMPLATECROSSSECTIONS_H
9#include "Rivet/Analysis.hh"
10#include "Rivet/Particle.hh"
11#include "Rivet/Projections/FastJets.hh"
18#include "TLorentzVector.h"
37 :
Analysis(
"HiggsTemplateCrossSections"),
49 if ( ptcl.genParticle()->end_vertex() ) {
50 if ( !
hasChild(ptcl.genParticle(),ptcl.pid()) )
return ptcl;
58 auto prodVtx = p.genParticle()->production_vertex();
59 if (prodVtx ==
nullptr)
return false;
61 for (
auto ancestor:Rivet::HepMCUtils::particles(std::move(prodVtx),Relatives::ANCESTORS)){
62 for (
const auto & part:ptcls )
63 if ( ancestor==part.genParticle() )
return true;
76 for (
const Particle& child:Particle(*ptcl).children())
77 if (child.pid()==pdgID)
return true;
83 for (
auto parent:Rivet::HepMCUtils::particles(ptcl->production_vertex(),Relatives::PARENTS))
84 if (parent->pdg_id()==pdgID)
return true;
90 for (
const Particle& child:p.children())
91 if (PID::isQuark(child.pid()))
return true;
97 for (
const Particle& child:p.children())
99#
if RIVET_VERSION_CODE >= 40000
100 PID::isChargedLepton(child.pid())
102 PID::isChLepton(child.pid())
111 std::string
msg=
"",
int NmaxWarnings=20)
const {
117 static std::atomic<int> Nwarnings = 0;
118 if ( !
msg.empty() && ++Nwarnings < NmaxWarnings )
129 HiggsClassification cat;
130 cat.prodMode = prodMode;
142 "Unkown Higgs production mechanism. Cannot classify event."
143 " Classification for all events will most likely fail.");
153 for (
auto ptcl : Rivet::HepMCUtils::particles(event.genEvent()) ) {
156 if ( !PID::isHiggs(ptcl->pdg_id()) )
continue;
158 if ( ptcl->end_vertex() && !
hasChild(ptcl,PID::HIGGS) ) {
159 cat.higgs = Particle(ptcl); ++Nhiggs;
163 if ( HSvtx==
nullptr && ptcl->production_vertex() && !
hasParent(ptcl,PID::HIGGS) )
164 HSvtx = ptcl->production_vertex();
170 "Current event has "+std::to_string(Nhiggs)+
" Higgs bosons. There must be only one.");
171 if (cat.higgs.children().size()<2)
173 "Could not identify Higgs boson decay products.");
175 if (HSvtx ==
nullptr)
184 bool is_uncatdV =
false;
185 Particles uncatV_decays;
186 FourMomentum uncatV_p4(0,0,0,0);
187 FourVector uncatV_v4(0,0,0,0);
189 if (
isVH(prodMode) ) {
190 for (
auto ptcl:Rivet::HepMCUtils::particles(HSvtx,Relatives::CHILDREN)) {
191 if (PID::isW(ptcl->pdg_id())) { ++nWs; cat.V=Particle(ptcl); }
192 if (PID::isZ(ptcl->pdg_id())) { ++nZs; cat.V=Particle(std::move(ptcl)); }
196 for (
auto ptcl:Rivet::HepMCUtils::particles(HSvtx,Relatives::CHILDREN)) {
197 if (!PID::isHiggs(ptcl->pdg_id())) {
198 uncatV_decays += Particle(ptcl);
199 uncatV_p4 += Particle(ptcl).momentum();
200 uncatV_v4 += Particle(std::move(ptcl)).origin();
203 is_uncatdV =
true; cat.V = Particle(24,uncatV_p4,uncatV_v4);
209 if (
isVH(prodMode) && !cat.V.genParticle()->end_vertex() )
212 if (
isVH(prodMode) && cat.V.children().size()<2 )
215 if ( ( prodMode==
HTXS::WH && (nZs>0||nWs!=1) ) ||
218 std::to_string(nZs)+
" Z-bosons. Inconsitent with VH expectation.");
225 for (
auto ptcl : Rivet::HepMCUtils::particles(std::move(HSvtx),Relatives::CHILDREN) ) {
226 if ( !PID::isTop(ptcl->pdg_id()) )
continue;
228 if (
top.genParticle()->end_vertex() )
229 for (
const auto &child:
top.children())
235 if ( (prodMode==
HTXS::TTH && Ws.size()<2) || (prodMode==
HTXS::TH && Ws.size()<1 ) )
247 Particles leptonicVs;
250 }
else leptonicVs = std::move(uncatV_decays);
251 for (
const auto & W:Ws )
if ( W.genParticle()->end_vertex() && !
quarkDecay(W) ) leptonicVs += W;
254 const Particles FS = apply<FinalState>(event,
"FS").particles();
256 FourMomentum sum(0,0,0,0), vSum(0,0,0,0), hSum(0,0,0,0);
257 for (
const Particle &p : FS ) {
261 if (
originateFrom(p,cat.higgs) ) { hSum += p.momentum();
continue; }
263 if (
isVH(prodMode) && !is_uncatdV &&
originateFrom(p,Ws) ) vSum += p.momentum();
265 if ( leptonicVs.size() &&
originateFrom(p,leptonicVs) )
continue;
270 cat.p4decay_higgs = hSum;
271 cat.p4decay_V = vSum;
274 FastJets jets(fps_temp,
275#
if RIVET_VERSION_CODE >= 40000
283 cat.jets25 = jets.jetsByPt( Cuts::pT > 25.0 );
284 cat.jets30 = jets.jetsByPt( Cuts::pT > 30.0 );
289 std::to_string(sum.pt())+
" GeV and m = "+std::to_string(sum.mass())+
" GeV");
302 cat.isZ2vvDecay =
false;
305 cat.stage1_cat_pTjet25GeV =
getStage1Category(prodMode,cat.higgs,cat.jets25,cat.V);
306 cat.stage1_cat_pTjet30GeV =
getStage1Category(prodMode,cat.higgs,cat.jets30,cat.V);
325 throw std::invalid_argument(
"Input value is out of bin range or bins vector is empty.");
328 for (
size_t i = 1; i <
bins.size(); ++i) {
330 return static_cast<int>(i - 1);
334 return static_cast<int>(
bins.size() - 1);
341 if (jets.size()<2)
return 0;
342 const FourMomentum &j1=jets[0].momentum(), &j2=jets[1].momentum();
343 bool VBFtopo = (j1+j2).mass() > 400.0 && std::abs(j1.rapidity()-j2.rapidity()) > 2.8;
344 return VBFtopo ? (j1+j2+higgs.momentum()).pt()<25 ? 2 : 1 : 0;
351 if (jets.size()<2)
return 0;
352 const FourMomentum &j1=jets[0].momentum(), &j2=jets[1].momentum();
353 double mjj = (j1+j2).mass();
354 if(mjj>350 && mjj<=700)
return (j1+j2+higgs.momentum()).pt()<25 ? 1 : 2;
355 else if(mjj>700)
return (j1+j2+higgs.momentum()).pt()<25 ? 3 : 4;
365 if (jets.size()<2)
return 0;
366 const FourMomentum &j1=jets[0].momentum(), &j2=jets[1].momentum();
367 double mjj = (j1+j2).mass();
368 if(mjj>350 && mjj<=700)
return (j1+j2+higgs.momentum()).pt()<25 ? 1 : 2;
369 else if(mjj>700 && mjj<=1000)
return (j1+j2+higgs.momentum()).pt()<25 ? 3 : 4;
370 else if(mjj>1000 && mjj<=1500)
return (j1+j2+higgs.momentum()).pt()<25 ? 5 : 6;
371 else if(mjj>1500)
return (j1+j2+higgs.momentum()).pt()<25 ? 7 : 8;
380 const Particle &higgs,
381 const Particle &V)
const {
383 int ctrlHiggs = std::abs(higgs.rapidity())<2.5;
391 return Category(prodMode*10 + ctrlHiggs);
396 const Particle &higgs,
398 const Particle &V)
const {
400 int Njets=jets.size(), ctrlHiggs = std::abs(higgs.rapidity())<2.5, fwdHiggs = !ctrlHiggs;
401 double pTj1 = jets.size() ? jets[0].momentum().pt() : 0;
422 if (std::abs(higgs.rapidity())>2.5)
return QQ2HQQ_FWDH;
426 double mjj = jets.size()>1 ? (jets[0].mom()+jets[1].mom()).mass():0;
462 const Particle &higgs,
464 const Particle &V)
const {
466 int Njets=jets.size(), ctrlHiggs = std::abs(higgs.rapidity())<2.5, fwdHiggs = !ctrlHiggs;
486 if (std::abs(higgs.rapidity())>2.5)
return QQ2HQQ_FWDH;
487 int Njets=jets.size();
491 double mjj = (jets[0].mom()+jets[1].mom()).mass();
495 else if ( mjj > 350 ) {
539 const Particle &higgs,
541 const Particle &V)
const {
543 int Njets=jets.size(), ctrlHiggs = std::abs(higgs.rapidity())<2.5, fwdHiggs = !ctrlHiggs;
550 if ( higgs.pt()>200 ){
552 double pTHj = (jets[0].momentum()+higgs.momentum()).pt();
562 double pTHjj = (jets[0].momentum()+jets[1].momentum()+higgs.momentum()).pt();
573 if (std::abs(higgs.rapidity())>2.5)
return QQ2HQQ_FWDH;
574 int Njets=jets.size();
578 double mjj = (jets[0].mom()+jets[1].mom()).mass();
579 double pTHjj = (jets[0].momentum()+jets[1].momentum()+higgs.momentum()).pt();
595 int Njets=jets.size();
603 int Njets=jets.size();
611 int Njets=jets.size();
639 printf(
"==============================================================\n");
640 printf(
"======== HiggsTemplateCrossSections Initialization =========\n");
641 printf(
"==============================================================\n");
645 char *pm_env = getenv(
"HIGGSPRODMODE");
646 string pm(pm_env==
nullptr?
"":pm_env);
657 MSG_WARNING(
"No HIGGSPRODMODE shell variable found. Needed when running Rivet stand-alone.");
668 printf(
"==============================================================\n");
670 printf(
"======== Sucessful Initialization =========\n");
671 printf(
"==============================================================\n");
681 const double weight = 1.;
684 int F=cat.stage0_cat%10,
P=cat.stage1_cat_pTjet30GeV/100;
688 static const vector<int> offset({0,1,13,19,24,29,33,35,37,39});
691 static const vector<int> offset1_2({0,1,18,29,35,41,47,53,55,57});
692 int off1_2 = offset1_2[
P];
694 static const vector<int> offset1_2_Fine({0,1,29,54,70,86,102,109,111,113});
695 int off1_2_Fine = offset1_2_Fine[
P];
715 if (cat.jets30.size())
m_hist_pT_jet1->fill(cat.jets30[0].pt(),weight);
716 if (cat.jets30.size()>=2) {
717 const FourMomentum &j1 = cat.jets30[0].momentum(), &j2 = cat.jets30[1].momentum();
720 m_hist_pT_Hjj->fill((j1+j2+cat.higgs.momentum()).pt(),weight);
725 MSG_INFO (
" ====================================================== ");
726 MSG_INFO (
" Higgs Template X-Sec Categorization Tool ");
728 MSG_INFO (
" ====================================================== ");
729 bool allSuccess = (numEvents()==m_errorCount[
HTXS::SUCCESS]);
730 if ( allSuccess )
MSG_INFO (
" >>>> All "<< m_errorCount[
HTXS::SUCCESS] <<
" events successfully categorized!");
733 MSG_INFO (
" >>>> --> the following errors occured:");
741 MSG_INFO (
" ====================================================== ");
742 MSG_INFO (
" ====================================================== ");
801#ifdef RIVET_ANALYSIS_PATH
static const std::vector< std::string > bins
Define macros for attributes used to control the static checker.
Rivet routine for classifying MC events according to the Higgs template cross section categories.
Histo1DPtr m_hist_Njets25
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,...
HiggsTemplateCrossSections()
Histo1DPtr m_hist_stage1_2_fine_pTjet30
HTXS::HiggsProdMode m_HiggsProdMode
Histo1DPtr m_hist_stage1_2_fine_pTjet25
Histo1DPtr m_hist_stage1_pTjet30
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...
Histo1DPtr m_hist_stage1_2_pTjet30
bool originateFrom(const Particle &p, const Particles &ptcls) const
Whether particle p originate from any of the ptcls.
HiggsClassification error(HiggsClassification &cat, HTXS::ErrorCode err, std::string msg="", int NmaxWarnings=20) const
Returns the classification object with the error code set.
Histo1DPtr m_hist_y_Higgs
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...
bool isVH(HTXS::HiggsProdMode p) const
Whether the Higgs is produced in association with a vector boson (VH)
Histo1DPtr m_hist_pT_jet1
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 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.
Histo1DPtr m_hist_Njets30
bool hasChild(HepMC::ConstGenParticlePtr ptcl, int pdgID) const
Checks whether the input particle has a child with a given PDGID.
Histo1DPtr m_hist_stage1_2_pTjet25
HTXS::Stage1::Category getStage1Category(const HTXS::HiggsProdMode prodMode, const Particle &higgs, const Jets &jets, const Particle &V) const
Stage-1 categorization.
Histo1DPtr m_hist_deltay_jj
void printClassificationSummary()
HTXS::Stage0::Category getStage0Category(const HTXS::HiggsProdMode prodMode, const Particle &higgs, const Particle &V) const
Stage-0 HTXS categorization.
Histo1DPtr m_hist_dijet_mass
void analyze(const Event &event)
bool ChLeptonDecay(const Particle &p) const
Return true if particle decays to charged leptons.
Histo1DPtr m_hist_pT_Higgs
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
Histo1DPtr m_hist_stage1_pTjet25
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....
@ QQ2HQQ_GE2J_MJJ_0_60_PTHJJ_GT25
@ GG2H_GE2J_MJJ_0_350_PTH_0_60_PTHJJ_0_25
@ QQ2HQQ_GE2J_MJJ_0_60_PTHJJ_0_25
@ QQ2HQQ_GE2J_MJJ_350_700_PTH_GT200_PTHJJ_0_25
@ GG2H_PTH_200_300_PTHJoverPTH_0_15
@ GG2H_GE2J_MJJ_0_350_PTH_0_60_PTHJJ_GT25
@ GG2H_PTH_200_300_PTHJoverPTH_GT15
Categorization Stage 1.2: Three digit integer of format PF Where P is a digit representing the proces...
@ GG2HLL_PTV_150_250_GE1J
@ QQ2HQQ_GE2J_MJJ_350_700_PTH_0_200_PTHJJ_0_25
@ GG2H_GE2J_MJJ_350_700_PTH_0_200_PTHJJ_0_25
@ QQ2HQQ_GE2J_MJJ_GT350_PTH_GT200
@ GG2H_GE2J_MJJ_0_350_PTH_0_60
@ QQ2HQQ_GE2J_MJJ_120_350
Categorization Stage 1: Three digit integer of format PF Where P is a digit representing the process ...
@ QQ2HQQ_VBFTOPO_JET3VETO
@ QQ2HLL_PTV_150_250_GE1J
@ QQ2HLNU_PTV_150_250_GE1J
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.
const GenParticle * ConstGenParticlePtr
GenVertex * signal_process_vertex(const GenEvent *e)