41 using namespace ROOT::VecOps;
42 using RNode = ROOT::RDF::RNode;
43 using rvec_f =
const RVec<float> &;
44 using rvec_i =
const RVec<int> &;
46 const auto z_mass = 91.2;
49 RNode selection_4mu(RNode df)
51 auto df_ge4m = df.Filter(
"nMuon>=4",
"At least four muons");
52 auto df_iso = df_ge4m.Filter(
"All(abs(Muon_pfRelIso04_all)<0.40)",
"Require good isolation");
53 auto df_kin = df_iso.Filter(
"All(Muon_pt>5) && All(abs(Muon_eta)<2.4)",
"Good muon kinematics");
54 auto df_ip3d = df_kin.Define(
"Muon_ip3d",
"sqrt(Muon_dxy*Muon_dxy + Muon_dz*Muon_dz)");
55 auto df_sip3d = df_ip3d.Define(
"Muon_sip3d",
"Muon_ip3d/sqrt(Muon_dxyErr*Muon_dxyErr + Muon_dzErr*Muon_dzErr)");
56 auto df_pv = df_sip3d.Filter(
"All(Muon_sip3d<4) && All(abs(Muon_dxy)<0.5) && All(abs(Muon_dz)<1.0)",
57 "Track close to primary vertex with small uncertainty");
58 auto df_2p2n = df_pv.Filter(
"nMuon==4 && Sum(Muon_charge==1)==2 && Sum(Muon_charge==-1)==2",
59 "Two positive and two negative muons");
64 RNode selection_4el(RNode df)
66 auto df_ge4el = df.Filter(
"nElectron>=4",
"At least our electrons");
67 auto df_iso = df_ge4el.Filter(
"All(abs(Electron_pfRelIso03_all)<0.40)",
"Require good isolation");
68 auto df_kin = df_iso.Filter(
"All(Electron_pt>7) && All(abs(Electron_eta)<2.5)",
"Good Electron kinematics");
69 auto df_ip3d = df_kin.Define(
"Electron_ip3d",
"sqrt(Electron_dxy*Electron_dxy + Electron_dz*Electron_dz)");
70 auto df_sip3d = df_ip3d.Define(
"Electron_sip3d",
71 "Electron_ip3d/sqrt(Electron_dxyErr*Electron_dxyErr + Electron_dzErr*Electron_dzErr)");
72 auto df_pv = df_sip3d.Filter(
"All(Electron_sip3d<4) && All(abs(Electron_dxy)<0.5) && "
73 "All(abs(Electron_dz)<1.0)",
74 "Track close to primary vertex with small uncertainty");
75 auto df_2p2n = df_pv.Filter(
"nElectron==4 && Sum(Electron_charge==1)==2 && Sum(Electron_charge==-1)==2",
76 "Two positive and two negative electrons");
81 RNode selection_2el2mu(RNode df)
83 auto df_ge2el2mu = df.Filter(
"nElectron>=2 && nMuon>=2",
"At least two electrons and two muons");
84 auto df_eta = df_ge2el2mu.Filter(
"All(abs(Electron_eta)<2.5) && All(abs(Muon_eta)<2.4)",
"Eta cuts");
85 auto pt_cuts = [](rvec_f mu_pt, rvec_f el_pt) {
86 auto mu_pt_sorted = Reverse(Sort(mu_pt));
87 if (mu_pt_sorted[0] > 20 && mu_pt_sorted[1] > 10) {
90 auto el_pt_sorted = Reverse(Sort(el_pt));
91 if (el_pt_sorted[0] > 20 && el_pt_sorted[1] > 10) {
96 auto df_pt = df_eta.Filter(pt_cuts, {
"Muon_pt",
"Electron_pt"},
"Pt cuts");
97 auto dr_cuts = [](rvec_f mu_eta, rvec_f mu_phi, rvec_f el_eta, rvec_f el_phi) {
98 auto mu_dr = DeltaR(mu_eta[0], mu_eta[1], mu_phi[0], mu_phi[1]);
99 auto el_dr = DeltaR(el_eta[0], el_eta[1], el_phi[0], el_phi[1]);
100 if (mu_dr < 0.02 || el_dr < 0.02) {
105 auto df_dr = df_pt.Filter(dr_cuts, {
"Muon_eta",
"Muon_phi",
"Electron_eta",
"Electron_phi"},
"Dr cuts");
106 auto df_iso = df_dr.Filter(
"All(abs(Electron_pfRelIso03_all)<0.40) && All(abs(Muon_pfRelIso04_all)<0.40)",
107 "Require good isolation");
108 auto df_el_ip3d = df_iso.Define(
"Electron_ip3d_el",
"sqrt(Electron_dxy*Electron_dxy + Electron_dz*Electron_dz)");
109 auto df_el_sip3d = df_el_ip3d.Define(
"Electron_sip3d_el",
110 "Electron_ip3d_el/sqrt(Electron_dxyErr*Electron_dxyErr + "
111 "Electron_dzErr*Electron_dzErr)");
112 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)",
113 "Electron track close to primary vertex with small uncertainty");
114 auto df_mu_ip3d = df_el_track.Define(
"Muon_ip3d_mu",
"sqrt(Muon_dxy*Muon_dxy + Muon_dz*Muon_dz)");
115 auto df_mu_sip3d = df_mu_ip3d.Define(
"Muon_sip3d_mu",
116 "Muon_ip3d_mu/sqrt(Muon_dxyErr*Muon_dxyErr + Muon_dzErr*Muon_dzErr)");
117 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)",
118 "Muon track close to primary vertex with small uncertainty");
119 auto df_2p2n = df_mu_track.Filter(
"Sum(Electron_charge)==0 && Sum(Muon_charge)==0",
120 "Two opposite charged electron and muon pairs");
125 RVec<RVec<size_t>> reco_zz_to_4l(rvec_f pt, rvec_f eta, rvec_f phi, rvec_f mass, rvec_i charge)
127 RVec<RVec<size_t>> idx(2);
128 idx[0].reserve(2); idx[1].reserve(2);
131 auto idx_cmb = Combinations(pt, 2);
133 size_t best_i1 = 0;
size_t best_i2 = 0;
134 for (
size_t i = 0; i < idx_cmb[0].size(); i++) {
135 const auto i1 = idx_cmb[0][i];
136 const auto i2 = idx_cmb[1][i];
137 if (charge[i1] != charge[i2]) {
138 ROOT::Math::PtEtaPhiMVector p1(pt[i1], eta[i1], phi[i1], mass[i1]);
139 ROOT::Math::PtEtaPhiMVector p2(pt[i2], eta[i2], phi[i2], mass[i2]);
140 const auto this_mass = (p1 + p2).M();
141 if (std::abs(z_mass - this_mass) < std::abs(z_mass - best_mass)) {
142 best_mass = this_mass;
148 idx[0].emplace_back(best_i1);
149 idx[0].emplace_back(best_i2);
152 for (
size_t i = 0; i < 4; i++) {
153 if (i != best_i1 && i != best_i2) {
154 idx[1].emplace_back(i);
163 RVec<float> compute_z_masses_4l(
const RVec<RVec<size_t>> &idx, rvec_f pt, rvec_f eta, rvec_f phi, rvec_f mass)
165 RVec<float> z_masses(2);
166 for (
size_t i = 0; i < 2; i++) {
167 const auto i1 = idx[i][0];
const auto i2 = idx[i][1];
168 ROOT::Math::PtEtaPhiMVector p1(pt[i1], eta[i1], phi[i1], mass[i1]);
169 ROOT::Math::PtEtaPhiMVector p2(pt[i2], eta[i2], phi[i2], mass[i2]);
170 z_masses[i] = (p1 + p2).M();
172 if (std::abs(z_masses[0] - z_mass) < std::abs(z_masses[1] - z_mass)) {
175 return Reverse(z_masses);
180 float compute_higgs_mass_4l(
const RVec<RVec<size_t>> &idx, rvec_f pt, rvec_f eta, rvec_f phi, rvec_f mass)
182 const auto i1 = idx[0][0];
const auto i2 = idx[0][1];
183 const auto i3 = idx[1][0];
const auto i4 = idx[1][1];
184 ROOT::Math::PtEtaPhiMVector p1(pt[i1], eta[i1], phi[i1], mass[i1]);
185 ROOT::Math::PtEtaPhiMVector p2(pt[i2], eta[i2], phi[i2], mass[i2]);
186 ROOT::Math::PtEtaPhiMVector p3(pt[i3], eta[i3], phi[i3], mass[i3]);
187 ROOT::Math::PtEtaPhiMVector p4(pt[i4], eta[i4], phi[i4], mass[i4]);
188 return (p1 + p2 + p3 + p4).M();
192 RNode filter_z_candidates(RNode df)
194 auto df_z1_cut = df.Filter(
"Z_mass[0] > 40 && Z_mass[0] < 120",
"Mass of first Z candidate in [40, 120]");
195 auto df_z2_cut = df_z1_cut.Filter(
"Z_mass[1] > 12 && Z_mass[1] < 120",
"Mass of second Z candidate in [12, 120]");
200 RNode reco_higgs_to_4mu(RNode df)
203 auto df_base = selection_4mu(df);
207 df_base.Define(
"Z_idx", reco_zz_to_4l, {
"Muon_pt",
"Muon_eta",
"Muon_phi",
"Muon_mass",
"Muon_charge"});
210 auto filter_z_dr = [](
const RVec<RVec<size_t>> &idx, rvec_f eta, rvec_f phi) {
211 for (
size_t i = 0; i < 2; i++) {
212 const auto i1 = idx[i][0];
213 const auto i2 = idx[i][1];
214 const auto dr = DeltaR(eta[i1], eta[i2], phi[i1], phi[i2]);
222 df_z_idx.Filter(filter_z_dr, {
"Z_idx",
"Muon_eta",
"Muon_phi"},
"Delta R separation of muons building Z system");
226 df_z_dr.Define(
"Z_mass", compute_z_masses_4l, {
"Z_idx",
"Muon_pt",
"Muon_eta",
"Muon_phi",
"Muon_mass"});
229 auto df_z_cut = filter_z_candidates(df_z_mass);
233 df_z_cut.Define(
"H_mass", compute_higgs_mass_4l, {
"Z_idx",
"Muon_pt",
"Muon_eta",
"Muon_phi",
"Muon_mass"});
239 RNode reco_higgs_to_4el(RNode df)
242 auto df_base = selection_4el(df);
245 auto df_z_idx = df_base.Define(
"Z_idx", reco_zz_to_4l,
246 {
"Electron_pt",
"Electron_eta",
"Electron_phi",
"Electron_mass",
"Electron_charge"});
249 auto filter_z_dr = [](
const RVec<RVec<size_t>> &idx, rvec_f eta, rvec_f phi) {
250 for (
size_t i = 0; i < 2; i++) {
251 const auto i1 = idx[i][0];
252 const auto i2 = idx[i][1];
253 const auto dr = DeltaR(eta[i1], eta[i2], phi[i1], phi[i2]);
260 auto df_z_dr = df_z_idx.Filter(filter_z_dr, {
"Z_idx",
"Electron_eta",
"Electron_phi"},
261 "Delta R separation of Electrons building Z system");
264 auto df_z_mass = df_z_dr.Define(
"Z_mass", compute_z_masses_4l,
265 {
"Z_idx",
"Electron_pt",
"Electron_eta",
"Electron_phi",
"Electron_mass"});
268 auto df_z_cut = filter_z_candidates(df_z_mass);
271 auto df_h_mass = df_z_cut.Define(
"H_mass", compute_higgs_mass_4l,
272 {
"Z_idx",
"Electron_pt",
"Electron_eta",
"Electron_phi",
"Electron_mass"});
278 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,
279 rvec_f mu_eta, rvec_f mu_phi, rvec_f mu_mass)
281 ROOT::Math::PtEtaPhiMVector p1(mu_pt[0], mu_eta[0], mu_phi[0], mu_mass[0]);
282 ROOT::Math::PtEtaPhiMVector p2(mu_pt[1], mu_eta[1], mu_phi[1], mu_mass[1]);
283 ROOT::Math::PtEtaPhiMVector p3(el_pt[0], el_eta[0], el_phi[0], el_mass[0]);
284 ROOT::Math::PtEtaPhiMVector p4(el_pt[1], el_eta[1], el_phi[1], el_mass[1]);
285 auto mu_z = (p1 + p2).M();
286 auto el_z = (p3 + p4).M();
287 RVec<float> z_masses(2);
288 if (std::abs(mu_z - z_mass) < std::abs(el_z - z_mass)) {
299 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,
300 rvec_f mu_phi, rvec_f mu_mass)
302 ROOT::Math::PtEtaPhiMVector p1(mu_pt[0], mu_eta[0], mu_phi[0], mu_mass[0]);
303 ROOT::Math::PtEtaPhiMVector p2(mu_pt[1], mu_eta[1], mu_phi[1], mu_mass[1]);
304 ROOT::Math::PtEtaPhiMVector p3(el_pt[0], el_eta[0], el_phi[0], el_mass[0]);
305 ROOT::Math::PtEtaPhiMVector p4(el_pt[1], el_eta[1], el_phi[1], el_mass[1]);
306 return (p1 + p2 + p3 + p4).M();
310 RNode reco_higgs_to_2el2mu(RNode df)
313 auto df_base = selection_2el2mu(df);
317 df_base.Define(
"Z_mass", compute_z_masses_2el2mu, {
"Electron_pt",
"Electron_eta",
"Electron_phi",
"Electron_mass",
318 "Muon_pt",
"Muon_eta",
"Muon_phi",
"Muon_mass"});
321 auto df_z_cut = filter_z_candidates(df_z_mass);
324 auto df_h_mass = df_z_cut.Define(
325 "H_mass", compute_higgs_mass_2el2mu,
326 {
"Electron_pt",
"Electron_eta",
"Electron_phi",
"Electron_mass",
"Muon_pt",
"Muon_eta",
"Muon_phi",
"Muon_mass"});
333 template <
typename T>
334 void plot(T sig, T bkg, T data,
const std::string &x_label,
const std::string &filename)
337 gStyle->SetOptStat(0);
338 gStyle->SetTextFont(42);
339 auto c =
new TCanvas(
"c",
"", 800, 700);
340 c->SetLeftMargin(0.15);
346 auto h_cmb = *(TH1D*)(sig->Clone());
349 h_cmb.GetXaxis()->SetTitle(x_label.c_str());
350 h_cmb.GetXaxis()->SetTitleSize(0.04);
351 h_cmb.GetYaxis()->SetTitle(
"N_{Events}");
352 h_cmb.GetYaxis()->SetTitleSize(0.04);
353 h_cmb.SetLineColor(kRed);
354 h_cmb.SetLineWidth(2);
355 h_cmb.SetMaximum(18);
357 h_bkg.SetLineWidth(2);
358 h_bkg.SetFillStyle(1001);
359 h_bkg.SetLineColor(kBlack);
360 h_bkg.SetFillColor(kAzure - 9);
364 h_data.SetLineWidth(1);
365 h_data.SetMarkerStyle(20);
366 h_data.SetMarkerSize(1.0);
367 h_data.SetMarkerColor(kBlack);
368 h_data.SetLineColor(kBlack);
371 h_cmb.DrawClone(
"HIST");
372 h_bkg.DrawClone(
"HIST SAME");
373 h_data.DrawClone(
"PE1 SAME");
376 TLegend legend(0.62, 0.70, 0.82, 0.88);
377 legend.SetFillColor(0);
378 legend.SetBorderSize(0);
379 legend.SetTextSize(0.03);
380 legend.AddEntry(&h_data,
"Data",
"PE1");
381 legend.AddEntry(&h_bkg,
"ZZ",
"f");
382 legend.AddEntry(&h_cmb,
"m_{H} = 125 GeV",
"f");
387 cms_label.SetTextSize(0.04);
388 cms_label.DrawLatexNDC(0.16, 0.92,
"#bf{CMS Open Data}");
390 header.SetTextSize(0.03);
391 header.DrawLatexNDC(0.63, 0.92,
"#sqrt{s} = 8 TeV, L_{int} = 11.6 fb^{-1}");
394 c->SaveAs(filename.c_str());
397 void df103_NanoAODHiggsAnalysis()
400 ROOT::EnableImplicitMT();
405 ROOT::RDataFrame df_sig_4l(
"Events",
406 "root://eospublic.cern.ch//eos/root-eos/cms_opendata_2012_nanoaod/SMHiggsToZZTo4L.root");
411 ROOT::RDataFrame df_bkg_4mu(
"Events",
412 "root://eospublic.cern.ch//eos/root-eos/cms_opendata_2012_nanoaod/ZZTo4mu.root");
413 ROOT::RDataFrame df_bkg_4el(
"Events",
414 "root://eospublic.cern.ch//eos/root-eos/cms_opendata_2012_nanoaod/ZZTo4e.root");
415 ROOT::RDataFrame df_bkg_2el2mu(
"Events",
416 "root://eospublic.cern.ch//eos/root-eos/cms_opendata_2012_nanoaod/ZZTo2e2mu.root");
419 ROOT::RDataFrame df_data_doublemu(
420 "Events", {
"root://eospublic.cern.ch//eos/root-eos/cms_opendata_2012_nanoaod/Run2012B_DoubleMuParked.root",
421 "root://eospublic.cern.ch//eos/root-eos/cms_opendata_2012_nanoaod/Run2012C_DoubleMuParked.root"});
422 ROOT::RDataFrame df_data_doubleel(
423 "Events", {
"root://eospublic.cern.ch//eos/root-eos/cms_opendata_2012_nanoaod/Run2012B_DoubleElectron.root",
424 "root://eospublic.cern.ch//eos/root-eos/cms_opendata_2012_nanoaod/Run2012C_DoubleElectron.root"});
427 auto df_sig_4mu_reco = reco_higgs_to_4mu(df_sig_4l);
428 const auto luminosity = 11580.0;
429 const auto xsec_SMHiggsToZZTo4L = 0.0065;
430 const auto nevt_SMHiggsToZZTo4L = 299973.0;
431 const auto nbins = 36;
432 auto df_h_sig_4mu = df_sig_4mu_reco
433 .Define(
"weight", [&]() {
return luminosity * xsec_SMHiggsToZZTo4L / nevt_SMHiggsToZZTo4L; }, {})
434 .Histo1D({
"h_sig_4mu",
"", nbins, 70, 180},
"H_mass",
"weight");
436 const auto scale_ZZTo4l = 1.386;
437 const auto xsec_ZZTo4mu = 0.077;
438 const auto nevt_ZZTo4mu = 1499064.0;
439 auto df_bkg_4mu_reco = reco_higgs_to_4mu(df_bkg_4mu);
440 auto df_h_bkg_4mu = df_bkg_4mu_reco
441 .Define(
"weight", [&]() {
return luminosity * xsec_ZZTo4mu * scale_ZZTo4l / nevt_ZZTo4mu; }, {})
442 .Histo1D({
"h_bkg_4mu",
"", nbins, 70, 180},
"H_mass",
"weight");
444 auto df_data_4mu_reco = reco_higgs_to_4mu(df_data_doublemu);
445 auto df_h_data_4mu = df_data_4mu_reco
446 .Define(
"weight", []() {
return 1.0; }, {})
447 .Histo1D({
"h_data_4mu",
"", nbins, 70, 180},
"H_mass",
"weight");
450 auto df_sig_4el_reco = reco_higgs_to_4el(df_sig_4l);
451 auto df_h_sig_4el = df_sig_4el_reco
452 .Define(
"weight", [&]() {
return luminosity * xsec_SMHiggsToZZTo4L / nevt_SMHiggsToZZTo4L; }, {})
453 .Histo1D({
"h_sig_4el",
"", nbins, 70, 180},
"H_mass",
"weight");
455 const auto xsec_ZZTo4el = xsec_ZZTo4mu;
456 const auto nevt_ZZTo4el = 1499093.0;
457 auto df_bkg_4el_reco = reco_higgs_to_4el(df_bkg_4el);
458 auto df_h_bkg_4el = df_bkg_4el_reco
459 .Define(
"weight", [&]() {
return luminosity * xsec_ZZTo4el * scale_ZZTo4l / nevt_ZZTo4el; }, {})
460 .Histo1D({
"h_bkg_4el",
"", nbins, 70, 180},
"H_mass",
"weight");
462 auto df_data_4el_reco = reco_higgs_to_4el(df_data_doubleel);
463 auto df_h_data_4el = df_data_4el_reco.Define(
"weight", []() {
return 1.0; }, {})
464 .Histo1D({
"h_data_4el",
"", nbins, 70, 180},
"H_mass",
"weight");
467 auto df_sig_2el2mu_reco = reco_higgs_to_2el2mu(df_sig_4l);
468 auto df_h_sig_2el2mu = df_sig_2el2mu_reco
469 .Define(
"weight", [&]() {
return luminosity * xsec_SMHiggsToZZTo4L / nevt_SMHiggsToZZTo4L; }, {})
470 .Histo1D({
"h_sig_2el2mu",
"", nbins, 70, 180},
"H_mass",
"weight");
472 const auto xsec_ZZTo2el2mu = 0.18;
473 const auto nevt_ZZTo2el2mu = 1497445.0;
474 auto df_bkg_2el2mu_reco = reco_higgs_to_2el2mu(df_bkg_2el2mu);
475 auto df_h_bkg_2el2mu = df_bkg_2el2mu_reco
476 .Define(
"weight", [&]() {
return luminosity * xsec_ZZTo2el2mu * scale_ZZTo4l / nevt_ZZTo2el2mu; }, {})
477 .Histo1D({
"h_bkg_2el2mu",
"", nbins, 70, 180},
"H_mass",
"weight");
479 auto df_data_2el2mu_reco = reco_higgs_to_2el2mu(df_data_doublemu);
480 auto df_h_data_2el2mu = df_data_2el2mu_reco.Define(
"weight", []() {
return 1.0; }, {})
481 .Histo1D({
"h_data_2el2mu_doublemu",
"", nbins, 70, 180},
"H_mass",
"weight");
484 plot(df_h_sig_4mu, df_h_bkg_4mu, df_h_data_4mu,
"m_{4#mu} (GeV)",
"higgs_4mu.pdf");
485 plot(df_h_sig_4el, df_h_bkg_4el, df_h_data_4el,
"m_{4e} (GeV)",
"higgs_4el.pdf");
486 plot(df_h_sig_2el2mu, df_h_bkg_2el2mu, df_h_data_2el2mu,
"m_{2e2#mu} (GeV)",
"higgs_2el2mu.pdf");
489 auto h_data_4l = df_h_data_4mu.GetPtr();
490 h_data_4l->Add(df_h_data_4el.GetPtr());
491 h_data_4l->Add(df_h_data_2el2mu.GetPtr());
492 auto h_sig_4l = df_h_sig_4mu.GetPtr();
493 h_sig_4l->Add(df_h_sig_4el.GetPtr());
494 h_sig_4l->Add(df_h_sig_2el2mu.GetPtr());
495 auto h_bkg_4l = df_h_bkg_4mu.GetPtr();
496 h_bkg_4l->Add(df_h_bkg_4el.GetPtr());
497 h_bkg_4l->Add(df_h_bkg_2el2mu.GetPtr());
498 plot(h_sig_4l, h_bkg_4l, h_data_4l,
"m_{4l} (GeV)",
"higgs_4l.pdf");
503 df103_NanoAODHiggsAnalysis();