The data and simulated events are taken from CERN OpenData representing a subset of the data recorded in 2012 with the CMS detector at the LHC. The tutorials follows the Higgs to four leptons analysis published on CERN Open Data portal (10.7483/OPENDATA.CMS.JKB8.RR42). The resulting plots show the invariant mass of the selected four lepton systems in different decay modes (four muons, four electrons and two of each kind) and in a combined plot indicating the decay of the Higgs boson with a mass of about 125 GeV.
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:
using rvec_f = const RVec<float> &;
using rvec_i = const RVec<int> &;
const auto z_mass = 91.2;
{
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;
}
{
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;
}
{
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 = [](rvec_f mu_pt, rvec_f 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 = [](rvec_f mu_eta, rvec_f mu_phi, rvec_f el_eta, rvec_f 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;
}
RVec<RVec<size_t>> reco_zz_to_4l(rvec_f
pt, rvec_f eta, rvec_f phi, rvec_f mass, rvec_i charge)
{
RVec<RVec<size_t>> idx(2);
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;
}
RVec<float> compute_z_masses_4l(
const RVec<RVec<size_t>> &idx, rvec_f
pt, rvec_f eta, rvec_f phi, rvec_f mass)
{
RVec<float> z_masses(2);
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, rvec_f
pt, rvec_f eta, rvec_f phi, rvec_f 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();
}
{
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;
}
{
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"});
auto filter_z_dr = [](const RVec<RVec<size_t>> &idx, rvec_f eta, rvec_f phi) {
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;
}
{
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"});
auto filter_z_dr = [](const RVec<RVec<size_t>> &idx, rvec_f eta, rvec_f phi) {
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;
}
RVec<float> compute_z_masses_2el2mu(rvec_f el_pt, rvec_f el_eta, rvec_f el_phi, rvec_f el_mass, rvec_f mu_pt,
rvec_f mu_eta, rvec_f mu_phi, rvec_f mu_mass)
{
auto mu_z = (p1 + p2).M();
auto el_z = (p3 + p4).M();
RVec<float> z_masses(2);
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(rvec_f el_pt, rvec_f el_eta, rvec_f el_phi, rvec_f el_mass, rvec_f mu_pt, rvec_f mu_eta,
rvec_f mu_phi, rvec_f mu_mass)
{
return (p1 + p2 + p3 + p4).M();
}
{
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)
{
auto c =
new TCanvas(
"c",
"", 800, 700);
auto h_sig = *sig;
auto h_bkg = *bkg;
auto h_cmb = *(
TH1D*)(sig->Clone());
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);
auto h_data = *data;
h_data.SetLineWidth(1);
h_data.SetMarkerStyle(20);
h_data.SetMarkerSize(1.0);
h_data.SetMarkerColor(
kBlack);
h_cmb.DrawClone("HIST");
h_bkg.DrawClone("HIST SAME");
h_data.DrawClone("PE1 SAME");
TLegend legend(0.62, 0.70, 0.82, 0.88);
legend.SetFillColor(0);
legend.SetBorderSize(0);
legend.SetTextSize(0.03);
legend.AddEntry(&h_data, "Data", "PE1");
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}");
c->SaveAs(filename.c_str());
}
{
"root://eospublic.cern.ch//eos/root-eos/cms_opendata_2012_nanoaod/SMHiggsToZZTo4L.root");
"root://eospublic.cern.ch//eos/root-eos/cms_opendata_2012_nanoaod/ZZTo4mu.root");
"root://eospublic.cern.ch//eos/root-eos/cms_opendata_2012_nanoaod/ZZTo4e.root");
"root://eospublic.cern.ch//eos/root-eos/cms_opendata_2012_nanoaod/ZZTo2e2mu.root");
"Events", {"root://eospublic.cern.ch//eos/root-eos/cms_opendata_2012_nanoaod/Run2012B_DoubleMuParked.root",
"root://eospublic.cern.ch//eos/root-eos/cms_opendata_2012_nanoaod/Run2012C_DoubleMuParked.root"});
"Events", {"root://eospublic.cern.ch//eos/root-eos/cms_opendata_2012_nanoaod/Run2012B_DoubleElectron.root",
"root://eospublic.cern.ch//eos/root-eos/cms_opendata_2012_nanoaod/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;
const auto nbins = 36;
auto df_h_sig_4mu = df_sig_4mu_reco
.Define("weight", [&]() { return luminosity * xsec_SMHiggsToZZTo4L / nevt_SMHiggsToZZTo4L; }, {})
.Histo1D({"h_sig_4mu", "", nbins, 70, 180}, "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; }, {})
.Histo1D({"h_bkg_4mu", "", nbins, 70, 180}, "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; }, {})
.Histo1D({"h_data_4mu", "", nbins, 70, 180}, "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; }, {})
.Histo1D({"h_sig_4el", "", nbins, 70, 180}, "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; }, {})
.Histo1D({"h_bkg_4el", "", nbins, 70, 180}, "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; }, {})
.Histo1D({"h_data_4el", "", nbins, 70, 180}, "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; }, {})
.Histo1D({"h_sig_2el2mu", "", nbins, 70, 180}, "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; }, {})
.Histo1D({"h_bkg_2el2mu", "", nbins, 70, 180}, "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; }, {})
.Histo1D({"h_data_2el2mu_doublemu", "", nbins, 70, 180}, "H_mass", "weight");
plot(df_h_sig_4mu, df_h_bkg_4mu, df_h_data_4mu, "m_{4#mu} (GeV)", "higgs_4mu.pdf");
plot(df_h_sig_4el, df_h_bkg_4el, df_h_data_4el, "m_{4e} (GeV)", "higgs_4el.pdf");
plot(df_h_sig_2el2mu, df_h_bkg_2el2mu, df_h_data_2el2mu, "m_{2e2#mu} (GeV)", "higgs_2el2mu.pdf");
auto h_data_4l = df_h_data_4mu.GetPtr();
h_data_4l->Add(df_h_data_4el.GetPtr());
h_data_4l->Add(df_h_data_2el2mu.GetPtr());
auto h_sig_4l = df_h_sig_4mu.GetPtr();
h_sig_4l->Add(df_h_sig_4el.GetPtr());
h_sig_4l->Add(df_h_sig_2el2mu.GetPtr());
auto h_bkg_4l = df_h_bkg_4mu.GetPtr();
h_bkg_4l->Add(df_h_bkg_4el.GetPtr());
h_bkg_4l->Add(df_h_bkg_2el2mu.GetPtr());
plot(h_sig_4l, h_bkg_4l, h_data_4l, "m_{4l} (GeV)", "higgs_4l.pdf");
}
{
}
R__EXTERN TStyle * gStyle
ROOT's RDataFrame offers a high level interface for analyses of data stored in TTrees,...
virtual void SetTextFont(Font_t tfont=62)
Set the text font.
virtual void SetTextSize(Float_t tsize=1)
Set the text size.
1-D histogram with a double per channel (see TH1 documentation)}
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.
void SetOptStat(Int_t stat=1)
The type of information printed in the histogram statistics box can be selected via the parameter mod...
int main(int argc, char **argv)
ROOT::VecOps::RVec< T > RVec
Vector1::Scalar DeltaR(const Vector1 &v1, const Vector2 &v2)
Find difference in pseudorapidity (Eta) and Phi betwen two generic vectors The only requirements on t...
RInterface<::ROOT::Detail::RDF::RNodeBase, void > RNode
RVec< T > Reverse(const RVec< T > &v)
Return copy of reversed vector.
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.
void EnableImplicitMT(UInt_t numthreads=0)
Enable ROOT's implicit multi-threading for all objects and methods that provide an internal paralleli...
void Sort(Index n, const Element *a, Index *index, Bool_t down=kTRUE)