Rivet analyses
Monte Carlo validation observables for HH → 4b production
Experiment: ()
Status: VALIDATED
Authors: - Jai Mohan - Christian Gutschow
References: none listed
Beams: * *
Beam energies: ANY
Run details: - 4b production in a di-Higgs mass range.
Observables sensitive to the kinematics of the b-jets in HH → 4b events and up to four additional light jets.
Source
code:MC_HH4B.cc
#include "Rivet/Analysis.hh"
#include "Rivet/Projections/FinalState.hh"
#include "Rivet/Projections/FastJets.hh"
namespace Rivet {
/// @brief Monte Carlo validation observables for HH->4b production
class MC_HH4B : public Analysis {
public:
/// @name Constructors etc.
//@{
/// Constructor
RIVET_DEFAULT_ANALYSIS_CTOR(MC_HH4B);
//@}
/// @name Analysis methods
//@{
/// Book histograms and initialise projections before the run
void init() {
// set ptcut from input option
const double jetptcut = getOption<double>("PTJMIN", 50.0);
_jetptcut = jetptcut * GeV;
// set clustering radius from input option
const double R = getOption<double>("R", 0.4);
// set clustering algorithm from input option
JetAlg clusterAlgo;
const string algoopt = getOption("ALGO", "ANTIKT");
if ( algoopt == "KT" ) {
clusterAlgo = JetAlg::KT;
} else if ( algoopt == "CA" ) {
clusterAlgo = JetAlg::CA;
} else if ( algoopt == "ANTIKT" ) {
clusterAlgo = JetAlg::ANTIKT;
} else {
MSG_WARNING("Unknown jet clustering algorithm option " + algoopt + ". Defaulting to anti-kT");
clusterAlgo = JetAlg::ANTIKT;
}
declare(FastJets(FinalState(), clusterAlgo, R), "jets");
/// Book histograms
for (const string& type : vector<string>{"bjet_"s, "ljet_"s}) {
for (const string& num : vector<string>{"1_"s, "2_"s, "3_"s, "4_"s}) {
book(_h[type+num+"eta"], type+num+"eta", 50, -4., 4.);
book(_h[type+num+"phi"], type+num+"phi", 50, 0., 1.);
book(_h[type+num+"pT"], type+num+"pT", 50, 0., 500.);
book(_h[type+num+"mass"], type+num+"mass", 50, 0., 500.);
}
}
book(_d["nbjets"], "nbjets", {0, 1, 2, 3, 4, 5, 6, 7, 8});
book(_d["njets"], "njets", {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10});
book(_h["H1Mass"], "HiggsMass1", 50, 0., 250.); // Higgs candidate 1 mass
book(_h["H2Mass"], "HiggsMass2", 50, 0., 250.); // Higgs candidate 2 mass
book(_h["H1Pt"], "HiggsPt1", 50, 0., 1000.); // Higgs candidate 1 pt
book(_h["H2Pt"], "HiggsPt2", 50, 0., 1000.); // Higgs candidate 2 pt
book(_h["DiHiggsMass"], "DiHiggsMass", 50, 0., 2000.); // Di-Higgs system mass
book(_h["DiHiggsPt"], "DiHiggsPt", 50, 0., 1000.); // Di-Higgs system pT
book(_h["HiggsMassDiff"], "HiggsMassDiff", 50, 0., 100.); // Di-Higgs system mass
}
/// Perform the per-event analysis
void analyze(const Event& event) {
const Jets jets = apply<FastJets>(event, "jets").jetsByPt(Cuts::pT > _jetptcut && Cuts::abseta < 4.0);
_d["njets"]->fill(jets.size());
// Identify the b-jets
Jets bjets;
int ljets = 0;
for (const Jet& jet : jets) {
const double jetEta = jet.eta();
const double jetPhi = jet.phi();
const double jetPt = jet.pT();
const double jetMass = jet.mass();
if (jet.bTagged()) {
bjets += jet;
if (bjets.size() > 4) continue;
const string pre("bjet_"+toString(bjets.size()));
_h[pre+"_eta"]->fill(jetEta);
_h[pre+"_phi"]->fill(jetPhi/2/M_PI);
_h[pre+"_pT"]->fill(jetPt/GeV);
_h[pre+"_mass"]->fill(jetMass/GeV);
}
else if (ljets < 4) {
const string pre("ljet_"+toString(++ljets));
_h[pre+"_eta"]->fill(jetEta);
_h[pre+"_phi"]->fill(jetPhi/2/M_PI);
_h[pre+"_pT"]->fill(jetPt/GeV);
_h[pre+"_mass"]->fill(jetMass/GeV);
}
}
_d["nbjets"]->fill(bjets.size());
// if(bjets.empty()) vetoEvent;
if (bjets.size() < 4) vetoEvent;
double best_mass_diff = FLT_MAX;
std::pair<Jet, Jet> bpair1, bpair2;
for (size_t i = 0; i < bjets.size(); ++i) {
for (size_t j = i + 1; j < bjets.size(); ++j) {
for (size_t k = 0; k < bjets.size(); ++k) {
if (k == i || k == j) continue;
for (size_t l = k + 1; l < bjets.size(); ++l) {
if (l == i || l == j) continue;
// Calculate masses
const double m1 = (bjets[i].mom() + bjets[j].mom()).mass();
const double m2 = (bjets[k].mom() + bjets[l].mom()).mass();
const double mass_diff = fabs(m1 - m2);
bool isOneHiggsInMassRange = inRange(m1, 95*GeV, 145*GeV) || inRange(m2, 95*GeV, 145*GeV);
if (!isOneHiggsInMassRange) continue;
// Check for best pairing
// and mass_diff < 20.0*GeV && isOneHiggsInMassRange
if (mass_diff < best_mass_diff && mass_diff < 20*GeV) {
best_mass_diff = mass_diff;
bpair1 = make_pair(bjets[i], bjets[j]);
bpair2 = make_pair(bjets[k], bjets[l]);
}
}
}
}
}
if (best_mass_diff > 20*GeV) vetoEvent;
// Reconstruct Higgs masses
const FourMomentum H1 = bpair1.first.mom() + bpair1.second.mom();
const FourMomentum H2 = bpair2.first.mom() + bpair2.second.mom();
bool h1_inrange = inRange(H1.mass(), 95*GeV, 145*GeV);
bool h2_inrange = inRange(H2.mass(), 95*GeV, 145*GeV);
if (!h1_inrange && !h2_inrange) vetoEvent;
const double mass_diff = fabs(H1.mass() - H2.mass());
// Fill histograms (redundant mass check)
_h["H1Mass"]->fill(H1.mass()/GeV);
_h["H1Pt"]->fill(H1.pT()/GeV);
_h["H2Mass"]->fill(H2.mass()/GeV);
_h["H2Pt"]->fill(H2.pT()/GeV);
_h["HiggsMassDiff"]->fill(mass_diff/GeV);
// Reconstruct di-Higgs
const FourMomentum dihiggs = H1 + H2;
_h["DiHiggsMass"]->fill(dihiggs.mass()/GeV);
_h["DiHiggsPt"]->fill(dihiggs.pT()/GeV);
}
/// Normalise histograms etc., after the run
void finalize() {
const double sf = crossSection()/femtobarn/sumOfWeights();
scale(_h, sf);
scale(_d, sf);
}
//@}
private:
/// @name Histograms
//@{
map<string,Histo1DPtr> _h;
map<string,BinnedHistoPtr<int>> _d;
double _jetptcut;
//@}
};
RIVET_DECLARE_PLUGIN(MC_HH4B);
}