The following steps are performed for each sample with data and simulated events in order to reconstruct the Higgs boson from the selected muons and electrons:
The tutorial has the fast mode enabled by default, which reads the data from already skimmed datasets with a total size of only 51MB. If the fast mode is disabled, the tutorial runs over the full dataset with a size of 12GB.
#include <string>
const auto z_mass = 91.2;
RNode selection_4mu(RNode df)
{
auto df_ge4m = df.Filter("nMuon>=4", "At least four muons");
auto df_iso = df_ge4m.Filter("All(abs(Muon_pfRelIso04_all)<0.40)", "Require good isolation");
auto df_kin = df_iso.Filter("All(Muon_pt>5) && All(abs(Muon_eta)<2.4)", "Good muon kinematics");
auto df_ip3d = df_kin.Define("Muon_ip3d", "sqrt(Muon_dxy*Muon_dxy + Muon_dz*Muon_dz)");
auto df_sip3d = df_ip3d.Define("Muon_sip3d", "Muon_ip3d/sqrt(Muon_dxyErr*Muon_dxyErr + Muon_dzErr*Muon_dzErr)");
auto df_pv = df_sip3d.Filter("All(Muon_sip3d<4) && All(abs(Muon_dxy)<0.5) && All(abs(Muon_dz)<1.0)",
"Track close to primary vertex with small uncertainty");
auto df_2p2n = df_pv.Filter("nMuon==4 && Sum(Muon_charge==1)==2 && Sum(Muon_charge==-1)==2",
"Two positive and two negative muons");
return df_2p2n;
}
RNode selection_4el(RNode df)
{
auto df_ge4el = df.Filter("nElectron>=4", "At least our electrons");
auto df_iso = df_ge4el.Filter("All(abs(Electron_pfRelIso03_all)<0.40)", "Require good isolation");
auto df_kin = df_iso.Filter("All(Electron_pt>7) && All(abs(Electron_eta)<2.5)", "Good Electron kinematics");
auto df_ip3d = df_kin.Define("Electron_ip3d", "sqrt(Electron_dxy*Electron_dxy + Electron_dz*Electron_dz)");
auto df_sip3d = df_ip3d.Define(
"Electron_sip3d", "Electron_ip3d/sqrt(Electron_dxyErr*Electron_dxyErr + Electron_dzErr*Electron_dzErr)");
auto df_pv = df_sip3d.Filter("All(Electron_sip3d<4) && All(abs(Electron_dxy)<0.5) && "
"All(abs(Electron_dz)<1.0)",
"Track close to primary vertex with small uncertainty");
auto df_2p2n = df_pv.Filter("nElectron==4 && Sum(Electron_charge==1)==2 && Sum(Electron_charge==-1)==2",
"Two positive and two negative electrons");
return df_2p2n;
}
RNode selection_2el2mu(RNode df)
{
auto df_ge2el2mu = df.Filter("nElectron>=2 && nMuon>=2", "At least two electrons and two muons");
auto df_eta = df_ge2el2mu.Filter("All(abs(Electron_eta)<2.5) && All(abs(Muon_eta)<2.4)", "Eta cuts");
auto pt_cuts = [](cRVecF mu_pt, cRVecF el_pt) {
if (mu_pt_sorted[0] > 20 && mu_pt_sorted[1] > 10) {
return true;
}
if (el_pt_sorted[0] > 20 && el_pt_sorted[1] > 10) {
return true;
}
return false;
};
auto df_pt = df_eta.Filter(pt_cuts, {"Muon_pt", "Electron_pt"}, "Pt cuts");
auto dr_cuts = [](cRVecF mu_eta, cRVecF mu_phi, cRVecF el_eta, cRVecF el_phi) {
auto mu_dr =
DeltaR(mu_eta[0], mu_eta[1], mu_phi[0], mu_phi[1]);
auto el_dr =
DeltaR(el_eta[0], el_eta[1], el_phi[0], el_phi[1]);
if (mu_dr < 0.02 || el_dr < 0.02) {
return false;
}
return true;
};
auto df_dr = df_pt.Filter(dr_cuts, {"Muon_eta", "Muon_phi", "Electron_eta", "Electron_phi"}, "Dr cuts");
auto df_iso = df_dr.Filter("All(abs(Electron_pfRelIso03_all)<0.40) && All(abs(Muon_pfRelIso04_all)<0.40)",
"Require good isolation");
auto df_el_ip3d = df_iso.Define("Electron_ip3d_el", "sqrt(Electron_dxy*Electron_dxy + Electron_dz*Electron_dz)");
auto df_el_sip3d = df_el_ip3d.Define("Electron_sip3d_el", "Electron_ip3d_el/sqrt(Electron_dxyErr*Electron_dxyErr + "
"Electron_dzErr*Electron_dzErr)");
auto df_el_track =
df_el_sip3d.Filter("All(Electron_sip3d_el<4) && All(abs(Electron_dxy)<0.5) && All(abs(Electron_dz)<1.0)",
"Electron track close to primary vertex with small uncertainty");
auto df_mu_ip3d = df_el_track.Define("Muon_ip3d_mu", "sqrt(Muon_dxy*Muon_dxy + Muon_dz*Muon_dz)");
auto df_mu_sip3d =
df_mu_ip3d.Define("Muon_sip3d_mu", "Muon_ip3d_mu/sqrt(Muon_dxyErr*Muon_dxyErr + Muon_dzErr*Muon_dzErr)");
auto df_mu_track = df_mu_sip3d.Filter("All(Muon_sip3d_mu<4) && All(abs(Muon_dxy)<0.5) && All(abs(Muon_dz)<1.0)",
"Muon track close to primary vertex with small uncertainty");
auto df_2p2n = df_mu_track.Filter("Sum(Electron_charge)==0 && Sum(Muon_charge)==0",
"Two opposite charged electron and muon pairs");
return df_2p2n;
}
{
idx[0].reserve(2);
idx[1].reserve(2);
auto best_mass = -1;
size_t best_i1 = 0;
size_t best_i2 = 0;
for (size_t i = 0; i < idx_cmb[0].size(); i++) {
const auto i1 = idx_cmb[0][i];
const auto i2 = idx_cmb[1][i];
if (charge[i1] != charge[i2]) {
const auto this_mass = (p1 + p2).M();
if (std::abs(z_mass - this_mass) < std::abs(z_mass - best_mass)) {
best_mass = this_mass;
best_i1 = i1;
best_i2 = i2;
}
}
}
idx[0].emplace_back(best_i1);
idx[0].emplace_back(best_i2);
for (size_t i = 0; i < 4; i++) {
if (i != best_i1 && i != best_i2) {
idx[1].emplace_back(i);
}
}
return idx;
}
{
for (size_t i = 0; i < 2; i++) {
const auto i1 = idx[i][0];
const auto i2 = idx[i][1];
z_masses[i] = (p1 + p2).M();
}
if (std::abs(z_masses[0] - z_mass) < std::abs(z_masses[1] - z_mass)) {
return z_masses;
} else {
}
}
float compute_higgs_mass_4l(
const RVec<
RVec<size_t>> &idx, cRVecF
pt, cRVecF eta, cRVecF phi, cRVecF mass)
{
const auto i1 = idx[0][0];
const auto i2 = idx[0][1];
const auto i3 = idx[1][0];
const auto i4 = idx[1][1];
return (p1 + p2 + p3 + p4).M();
}
RNode filter_z_candidates(RNode df)
{
auto df_z1_cut = df.Filter("Z_mass[0] > 40 && Z_mass[0] < 120", "Mass of first Z candidate in [40, 120]");
auto df_z2_cut = df_z1_cut.Filter("Z_mass[1] > 12 && Z_mass[1] < 120", "Mass of second Z candidate in [12, 120]");
return df_z2_cut;
}
RNode reco_higgs_to_4mu(RNode df)
{
auto df_base = selection_4mu(df);
auto df_z_idx =
df_base.Define("Z_idx", reco_zz_to_4l, {"Muon_pt", "Muon_eta", "Muon_phi", "Muon_mass", "Muon_charge"});
for (size_t i = 0; i < 2; i++) {
const auto i1 = idx[i][0];
const auto i2 = idx[i][1];
const auto dr =
DeltaR(eta[i1], eta[i2], phi[i1], phi[i2]);
if (dr < 0.02) {
return false;
}
}
return true;
};
auto df_z_dr =
df_z_idx.Filter(filter_z_dr, {"Z_idx", "Muon_eta", "Muon_phi"}, "Delta R separation of muons building Z system");
auto df_z_mass =
df_z_dr.Define("Z_mass", compute_z_masses_4l, {"Z_idx", "Muon_pt", "Muon_eta", "Muon_phi", "Muon_mass"});
auto df_z_cut = filter_z_candidates(df_z_mass);
auto df_h_mass =
df_z_cut.Define("H_mass", compute_higgs_mass_4l, {"Z_idx", "Muon_pt", "Muon_eta", "Muon_phi", "Muon_mass"});
return df_h_mass;
}
RNode reco_higgs_to_4el(RNode df)
{
auto df_base = selection_4el(df);
auto df_z_idx = df_base.Define("Z_idx", reco_zz_to_4l,
{"Electron_pt", "Electron_eta", "Electron_phi", "Electron_mass", "Electron_charge"});
for (size_t i = 0; i < 2; i++) {
const auto i1 = idx[i][0];
const auto i2 = idx[i][1];
const auto dr =
DeltaR(eta[i1], eta[i2], phi[i1], phi[i2]);
if (dr < 0.02) {
return false;
}
}
return true;
};
auto df_z_dr = df_z_idx.Filter(filter_z_dr, {"Z_idx", "Electron_eta", "Electron_phi"},
"Delta R separation of Electrons building Z system");
auto df_z_mass = df_z_dr.Define("Z_mass", compute_z_masses_4l,
{"Z_idx", "Electron_pt", "Electron_eta", "Electron_phi", "Electron_mass"});
auto df_z_cut = filter_z_candidates(df_z_mass);
auto df_h_mass = df_z_cut.Define("H_mass", compute_higgs_mass_4l,
{"Z_idx", "Electron_pt", "Electron_eta", "Electron_phi", "Electron_mass"});
return df_h_mass;
}
ROOT::RVecF compute_z_masses_2el2mu(cRVecF el_pt, cRVecF el_eta, cRVecF el_phi, cRVecF el_mass, cRVecF mu_pt,
cRVecF mu_eta, cRVecF mu_phi, cRVecF mu_mass)
{
auto mu_z = (p1 + p2).M();
auto el_z = (p3 + p4).M();
if (std::abs(mu_z - z_mass) < std::abs(el_z - z_mass)) {
z_masses[0] = mu_z;
z_masses[1] = el_z;
} else {
z_masses[0] = el_z;
z_masses[1] = mu_z;
}
return z_masses;
}
float compute_higgs_mass_2el2mu(cRVecF el_pt, cRVecF el_eta, cRVecF el_phi, cRVecF el_mass, cRVecF mu_pt, cRVecF mu_eta,
cRVecF mu_phi, cRVecF mu_mass)
{
return (p1 + p2 + p3 + p4).M();
}
RNode reco_higgs_to_2el2mu(RNode df)
{
auto df_base = selection_2el2mu(df);
auto df_z_mass = df_base.Define(
"Z_mass", compute_z_masses_2el2mu,
{"Electron_pt", "Electron_eta", "Electron_phi", "Electron_mass", "Muon_pt", "Muon_eta", "Muon_phi", "Muon_mass"});
auto df_z_cut = filter_z_candidates(df_z_mass);
auto df_h_mass = df_z_cut.Define(
"H_mass", compute_higgs_mass_2el2mu,
{"Electron_pt", "Electron_eta", "Electron_phi", "Electron_mass", "Muon_pt", "Muon_eta", "Muon_phi", "Muon_mass"});
return df_h_mass;
}
template <typename T>
void plot(T sig, T bkg, T
data,
const std::string &x_label,
const std::string &
filename)
{
h_cmb->Add(h_bkg);
h_cmb->SetTitle("");
h_cmb->GetXaxis()->SetTitle(x_label.c_str());
h_cmb->GetXaxis()->SetTitleSize(0.04);
h_cmb->GetYaxis()->SetTitle("N_{Events}");
h_cmb->GetYaxis()->SetTitleSize(0.04);
h_cmb->SetLineColor(
kRed);
h_cmb->SetLineWidth(2);
h_cmb->SetMaximum(18);
h_bkg->SetLineWidth(2);
h_bkg->SetFillStyle(1001);
h_bkg->SetFillColor(
kAzure - 9);
h_data->SetLineWidth(1);
h_data->SetMarkerStyle(20);
h_data->SetMarkerSize(1.0);
h_data->SetMarkerColor(
kBlack);
h_cmb->Draw("HIST");
h_bkg->Draw("HIST SAME");
h_data->Draw("PE1 SAME");
auto legend =
new TLegend(0.62, 0.70, 0.82, 0.88);
legend->SetFillColor(0);
legend->SetBorderSize(0);
legend->SetTextSize(0.03);
legend->AddEntry(h_data, "Data", "pe");
legend->AddEntry(h_bkg, "ZZ", "f");
legend->AddEntry(h_cmb, "m_{H} = 125 GeV", "f");
legend->Draw();
header.
DrawLatexNDC(0.63, 0.92,
"#sqrt{s} = 8 TeV, L_{int} = 11.6 fb^{-1}");
}
void hist103_NanoAODHiggsAnalysis(const bool run_fast = true)
{
std::string path = "root://eospublic.cern.ch//eos/root-eos/cms_opendata_2012_nanoaod/";
if (run_fast)
path = "root://eospublic.cern.ch//eos/root-eos/cms_opendata_2012_nanoaod_skimmed/";
{path + "Run2012B_DoubleMuParked.root", path + "Run2012C_DoubleMuParked.root"});
{path + "Run2012B_DoubleElectron.root", path + "Run2012C_DoubleElectron.root"});
auto df_sig_4mu_reco = reco_higgs_to_4mu(df_sig_4l);
const auto luminosity = 11580.0;
const auto xsec_SMHiggsToZZTo4L = 0.0065;
const auto nevt_SMHiggsToZZTo4L = 299973.0;
auto df_h_sig_4mu =
df_sig_4mu_reco.Define("weight", [&] { return luminosity * xsec_SMHiggsToZZTo4L / nevt_SMHiggsToZZTo4L; })
.
Hist({axis}, {
"H_mass"},
"weight");
const auto scale_ZZTo4l = 1.386;
const auto xsec_ZZTo4mu = 0.077;
const auto nevt_ZZTo4mu = 1499064.0;
auto df_bkg_4mu_reco = reco_higgs_to_4mu(df_bkg_4mu);
auto df_h_bkg_4mu =
df_bkg_4mu_reco.Define("weight", [&] { return luminosity * xsec_ZZTo4mu * scale_ZZTo4l / nevt_ZZTo4mu; })
.
Hist({axis}, {
"H_mass"},
"weight");
auto df_data_4mu_reco = reco_higgs_to_4mu(df_data_doublemu);
auto df_h_data_4mu = df_data_4mu_reco.Define(
"weight", [] {
return 1.0; }).
Hist({axis}, {
"H_mass"},
"weight");
auto df_sig_4el_reco = reco_higgs_to_4el(df_sig_4l);
auto df_h_sig_4el =
df_sig_4el_reco.Define("weight", [&] { return luminosity * xsec_SMHiggsToZZTo4L / nevt_SMHiggsToZZTo4L; })
.
Hist({axis}, {
"H_mass"},
"weight");
const auto xsec_ZZTo4el = xsec_ZZTo4mu;
const auto nevt_ZZTo4el = 1499093.0;
auto df_bkg_4el_reco = reco_higgs_to_4el(df_bkg_4el);
auto df_h_bkg_4el =
df_bkg_4el_reco.Define("weight", [&] { return luminosity * xsec_ZZTo4el * scale_ZZTo4l / nevt_ZZTo4el; })
.
Hist({axis}, {
"H_mass"},
"weight");
auto df_data_4el_reco = reco_higgs_to_4el(df_data_doubleel);
auto df_h_data_4el = df_data_4el_reco.Define(
"weight", [] {
return 1.0; }).
Hist({axis}, {
"H_mass"},
"weight");
auto df_sig_2el2mu_reco = reco_higgs_to_2el2mu(df_sig_4l);
auto df_h_sig_2el2mu =
df_sig_2el2mu_reco.Define("weight", [&] { return luminosity * xsec_SMHiggsToZZTo4L / nevt_SMHiggsToZZTo4L; })
.
Hist({axis}, {
"H_mass"},
"weight");
const auto xsec_ZZTo2el2mu = 0.18;
const auto nevt_ZZTo2el2mu = 1497445.0;
auto df_bkg_2el2mu_reco = reco_higgs_to_2el2mu(df_bkg_2el2mu);
auto df_h_bkg_2el2mu =
df_bkg_2el2mu_reco.Define("weight", [&] { return luminosity * xsec_ZZTo2el2mu * scale_ZZTo4l / nevt_ZZTo2el2mu; })
.
Hist({axis}, {
"H_mass"},
"weight");
auto df_data_2el2mu_reco = reco_higgs_to_2el2mu(df_data_doublemu);
auto df_h_data_2el2mu = df_data_2el2mu_reco.Define(
"weight", [] {
return 1.0; }).
Hist({axis}, {
"H_mass"},
"weight");
ROOT::RDF::RunGraphs({df_h_sig_4mu, df_h_bkg_4mu, df_h_data_4mu, df_h_sig_4el, df_h_bkg_4el, df_h_data_4el,
df_h_sig_2el2mu, df_h_bkg_2el2mu, df_h_data_2el2mu});
plot(df_h_sig_4mu, df_h_bkg_4mu, df_h_data_4mu, "m_{4#mu} (GeV)", "hist103_higgs_4mu.pdf");
plot(df_h_sig_4el, df_h_bkg_4el, df_h_data_4el, "m_{4e} (GeV)", "hist103_higgs_4el.pdf");
plot(df_h_sig_2el2mu, df_h_bkg_2el2mu, df_h_data_2el2mu, "m_{2e2#mu} (GeV)", "hist103_higgs_2el2mu.pdf");
auto h_data_4l = df_h_data_4mu.GetPtr();
h_data_4l->Add(*df_h_data_4el);
h_data_4l->Add(*df_h_data_2el2mu);
auto h_sig_4l = df_h_sig_4mu.GetPtr();
h_sig_4l->Add(*df_h_sig_4el);
h_sig_4l->Add(*df_h_sig_2el2mu);
auto h_bkg_4l = df_h_bkg_4mu.GetPtr();
h_bkg_4l->Add(*df_h_bkg_4el);
h_bkg_4l->Add(*df_h_bkg_2el2mu);
plot(h_sig_4l, h_bkg_4l, h_data_4l, "m_{4l} (GeV)", "hist103_higgs_4l.pdf");
}
{
hist103_NanoAODHiggsAnalysis(true);
}
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void data
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char filename
R__EXTERN TStyle * gStyle
A regular axis with equidistant bins in the interval .
ROOT's RDataFrame offers a modern, high-level interface for analysis of data stored in TTree ,...
A "std::vector"-like collection of values implementing handy operation to analyse them.
virtual void SetTextSize(Float_t tsize=1)
Set the text size.
To draw Mathematical Formula.
TLatex * DrawLatexNDC(Double_t x, Double_t y, const char *text)
Draw this TLatex with new coordinates in NDC.
This class displays a legend box (TPaveText) containing several legend entries.
RVec< T > Reverse(const RVec< T > &v)
Return copy of reversed vector.
RVec< Common_t > DeltaR(const RVec< T0 > &eta1, const RVec< T1 > &eta2, const RVec< T2 > &phi1, const RVec< T3 > &phi2, const Common_t c=M_PI)
Return the distance on the - plane ( ) from the collections eta1, eta2, phi1 and phi2.
RVec< T > Sort(const RVec< T > &v)
Return copy of RVec with elements sorted in ascending order.
RVec< RVec< std::size_t > > Combinations(const std::size_t size1, const std::size_t size2)
Return the indices that represent all combinations of the elements of two RVecs.
std::unique_ptr< TH1D > ConvertToTH1D(const RHistEngine< double > &engine)
Convert a one-dimensional histogram to TH1D.
LorentzVector< PtEtaPhiM4D< double > > PtEtaPhiMVector
LorentzVector based on the cylindrical coordinates pt, eta, phi and Mass in double precision.
unsigned int RunGraphs(std::vector< RResultHandle > handles)
Run the event loops of multiple RDataFrames concurrently.
RInterface<::ROOT::Detail::RDF::RNodeBase > RNode
RResultPtr< ROOT::Experimental::RHist< BinContentType > > Hist(std::uint64_t nNormalBins, std::pair< double, double > interval, std::string_view vName)
Fill and return a one-dimensional RHist (lazy action).
void EnableImplicitMT(UInt_t numthreads=0)
Enable ROOT's implicit multi-threading for all objects and methods that provide an internal paralleli...
ROOT::VecOps::RVec< float > RVecF
ROOT::VecOps::RVec< int > RVecI