Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
df103_NanoAODHiggsAnalysis.C
Go to the documentation of this file.
1/// \file
2/// \ingroup tutorial_dataframe
3/// \notebook -draw
4/// An example of complex analysis with RDataFrame: reconstructing the Higgs boson.
5///
6/// This tutorial is a simplified but yet complex example of an analysis reconstructing
7/// the Higgs boson decaying to two Z bosons from events with four leptons. The data
8/// and simulated events are taken from CERN OpenData representing a subset of the data
9/// recorded in 2012 with the CMS detector at the LHC. The tutorials follows the Higgs
10/// to four leptons analysis published on CERN Open Data portal
11/// ([10.7483/OPENDATA.CMS.JKB8.RR42](http://opendata.cern.ch/record/5500)).
12/// The resulting plots show the invariant mass of the selected four lepton systems
13/// in different decay modes (four muons, four electrons and two of each kind)
14/// and in a combined plot indicating the decay of the Higgs boson with a mass
15/// of about 125 GeV.
16///
17/// The following steps are performed for each sample with data and simulated events
18/// in order to reconstruct the Higgs boson from the selected muons and electrons:
19/// 1. Select interesting events with multiple cuts on event properties, e.g.,
20/// number of leptons, kinematics of the leptons and quality of the tracks.
21/// 2. Reconstruct two Z bosons of which only one on the mass shell from the selected events and apply additional cuts
22/// on the reconstructed objects.
23/// 3. Reconstruct the Higgs boson from the remaining Z boson candidates and calculate
24/// its invariant mass.
25///
26/// The tutorial has the fast mode enabled by default, which reads the data from already skimmed
27/// datasets with a total size of only 51MB. If the fast mode is disabled, the tutorial runs over
28/// the full dataset with a size of 12GB.
29///
30/// \macro_image
31/// \macro_code
32/// \macro_output
33///
34/// \date October 2018
35/// \author Stefan Wunsch (KIT, CERN)
36
37#include "ROOT/RDataFrame.hxx"
38#include "ROOT/RVec.hxx"
40#include "TCanvas.h"
41#include "TH1D.h"
42#include "TLatex.h"
43#include "TLegend.h"
44#include <Math/Vector4Dfwd.h>
47#include "TStyle.h"
48#include <string>
49
50using namespace ROOT::VecOps;
52using cRVecF = const ROOT::RVecF &;
53
54const auto z_mass = 91.2;
55
56// Select interesting events with four muons
57RNode selection_4mu(RNode df)
58{
59 auto df_ge4m = df.Filter("nMuon>=4", "At least four muons");
60 auto df_iso = df_ge4m.Filter("All(abs(Muon_pfRelIso04_all)<0.40)", "Require good isolation");
61 auto df_kin = df_iso.Filter("All(Muon_pt>5) && All(abs(Muon_eta)<2.4)", "Good muon kinematics");
62 auto df_ip3d = df_kin.Define("Muon_ip3d", "sqrt(Muon_dxy*Muon_dxy + Muon_dz*Muon_dz)");
63 auto df_sip3d = df_ip3d.Define("Muon_sip3d", "Muon_ip3d/sqrt(Muon_dxyErr*Muon_dxyErr + Muon_dzErr*Muon_dzErr)");
64 auto df_pv = df_sip3d.Filter("All(Muon_sip3d<4) && All(abs(Muon_dxy)<0.5) && All(abs(Muon_dz)<1.0)",
65 "Track close to primary vertex with small uncertainty");
66 auto df_2p2n = df_pv.Filter("nMuon==4 && Sum(Muon_charge==1)==2 && Sum(Muon_charge==-1)==2",
67 "Two positive and two negative muons");
68 return df_2p2n;
69}
70
71// Select interesting events with four electrons
72RNode selection_4el(RNode df)
73{
74 auto df_ge4el = df.Filter("nElectron>=4", "At least our electrons");
75 auto df_iso = df_ge4el.Filter("All(abs(Electron_pfRelIso03_all)<0.40)", "Require good isolation");
76 auto df_kin = df_iso.Filter("All(Electron_pt>7) && All(abs(Electron_eta)<2.5)", "Good Electron kinematics");
77 auto df_ip3d = df_kin.Define("Electron_ip3d", "sqrt(Electron_dxy*Electron_dxy + Electron_dz*Electron_dz)");
78 auto df_sip3d = df_ip3d.Define("Electron_sip3d",
79 "Electron_ip3d/sqrt(Electron_dxyErr*Electron_dxyErr + Electron_dzErr*Electron_dzErr)");
80 auto df_pv = df_sip3d.Filter("All(Electron_sip3d<4) && All(abs(Electron_dxy)<0.5) && "
81 "All(abs(Electron_dz)<1.0)",
82 "Track close to primary vertex with small uncertainty");
83 auto df_2p2n = df_pv.Filter("nElectron==4 && Sum(Electron_charge==1)==2 && Sum(Electron_charge==-1)==2",
84 "Two positive and two negative electrons");
85 return df_2p2n;
86}
87
88// Select interesting events with two electrons and two muons
89RNode selection_2el2mu(RNode df)
90{
91 auto df_ge2el2mu = df.Filter("nElectron>=2 && nMuon>=2", "At least two electrons and two muons");
92 auto df_eta = df_ge2el2mu.Filter("All(abs(Electron_eta)<2.5) && All(abs(Muon_eta)<2.4)", "Eta cuts");
93 auto pt_cuts = [](cRVecF mu_pt, cRVecF el_pt) {
94 auto mu_pt_sorted = Reverse(Sort(mu_pt));
95 if (mu_pt_sorted[0] > 20 && mu_pt_sorted[1] > 10) {
96 return true;
97 }
98 auto el_pt_sorted = Reverse(Sort(el_pt));
99 if (el_pt_sorted[0] > 20 && el_pt_sorted[1] > 10) {
100 return true;
101 }
102 return false;
103 };
104 auto df_pt = df_eta.Filter(pt_cuts, {"Muon_pt", "Electron_pt"}, "Pt cuts");
105 auto dr_cuts = [](cRVecF mu_eta, cRVecF mu_phi, cRVecF el_eta, cRVecF el_phi) {
106 auto mu_dr = DeltaR(mu_eta[0], mu_eta[1], mu_phi[0], mu_phi[1]);
107 auto el_dr = DeltaR(el_eta[0], el_eta[1], el_phi[0], el_phi[1]);
108 if (mu_dr < 0.02 || el_dr < 0.02) {
109 return false;
110 }
111 return true;
112 };
113 auto df_dr = df_pt.Filter(dr_cuts, {"Muon_eta", "Muon_phi", "Electron_eta", "Electron_phi"}, "Dr cuts");
114 auto df_iso = df_dr.Filter("All(abs(Electron_pfRelIso03_all)<0.40) && All(abs(Muon_pfRelIso04_all)<0.40)",
115 "Require good isolation");
116 auto df_el_ip3d = df_iso.Define("Electron_ip3d_el", "sqrt(Electron_dxy*Electron_dxy + Electron_dz*Electron_dz)");
117 auto df_el_sip3d = df_el_ip3d.Define("Electron_sip3d_el",
118 "Electron_ip3d_el/sqrt(Electron_dxyErr*Electron_dxyErr + "
119 "Electron_dzErr*Electron_dzErr)");
120 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)",
121 "Electron track close to primary vertex with small uncertainty");
122 auto df_mu_ip3d = df_el_track.Define("Muon_ip3d_mu", "sqrt(Muon_dxy*Muon_dxy + Muon_dz*Muon_dz)");
123 auto df_mu_sip3d = df_mu_ip3d.Define("Muon_sip3d_mu",
124 "Muon_ip3d_mu/sqrt(Muon_dxyErr*Muon_dxyErr + Muon_dzErr*Muon_dzErr)");
125 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)",
126 "Muon track close to primary vertex with small uncertainty");
127 auto df_2p2n = df_mu_track.Filter("Sum(Electron_charge)==0 && Sum(Muon_charge)==0",
128 "Two opposite charged electron and muon pairs");
129 return df_2p2n;
130}
131
132// Reconstruct two Z candidates from four leptons of the same kind
133RVec<RVec<size_t>> reco_zz_to_4l(cRVecF pt, cRVecF eta, cRVecF phi, cRVecF mass, const ROOT::RVecI & charge)
134{
135 RVec<RVec<size_t>> idx(2);
136 idx[0].reserve(2); idx[1].reserve(2);
137
138 // Find first lepton pair with invariant mass closest to Z mass
139 auto idx_cmb = Combinations(pt, 2);
140 auto best_mass = -1;
141 size_t best_i1 = 0; size_t best_i2 = 0;
142 for (size_t i = 0; i < idx_cmb[0].size(); i++) {
143 const auto i1 = idx_cmb[0][i];
144 const auto i2 = idx_cmb[1][i];
145 if (charge[i1] != charge[i2]) {
146 ROOT::Math::PtEtaPhiMVector p1(pt[i1], eta[i1], phi[i1], mass[i1]);
147 ROOT::Math::PtEtaPhiMVector p2(pt[i2], eta[i2], phi[i2], mass[i2]);
148 const auto this_mass = (p1 + p2).M();
149 if (std::abs(z_mass - this_mass) < std::abs(z_mass - best_mass)) {
150 best_mass = this_mass;
151 best_i1 = i1;
152 best_i2 = i2;
153 }
154 }
155 }
156 idx[0].emplace_back(best_i1);
157 idx[0].emplace_back(best_i2);
158
159 // Reconstruct second Z from remaining lepton pair
160 for (size_t i = 0; i < 4; i++) {
161 if (i != best_i1 && i != best_i2) {
162 idx[1].emplace_back(i);
163 }
164 }
165
166 // Return indices of the pairs building two Z bosons
167 return idx;
168}
169
170// Compute Z masses from four leptons of the same kind and sort ascending in distance to Z mass
171ROOT::RVecF compute_z_masses_4l(const RVec<RVec<size_t>> &idx, cRVecF pt, cRVecF eta, cRVecF phi, cRVecF mass)
172{
173 ROOT::RVecF z_masses(2);
174 for (size_t i = 0; i < 2; i++) {
175 const auto i1 = idx[i][0]; const auto i2 = idx[i][1];
176 ROOT::Math::PtEtaPhiMVector p1(pt[i1], eta[i1], phi[i1], mass[i1]);
177 ROOT::Math::PtEtaPhiMVector p2(pt[i2], eta[i2], phi[i2], mass[i2]);
178 z_masses[i] = (p1 + p2).M();
179 }
180 if (std::abs(z_masses[0] - z_mass) < std::abs(z_masses[1] - z_mass)) {
181 return z_masses;
182 } else {
183 return Reverse(z_masses);
184 }
185}
186
187// Compute mass of Higgs from four leptons of the same kind
188float compute_higgs_mass_4l(const RVec<RVec<size_t>> &idx, cRVecF pt, cRVecF eta, cRVecF phi, cRVecF mass)
189{
190 const auto i1 = idx[0][0]; const auto i2 = idx[0][1];
191 const auto i3 = idx[1][0]; const auto i4 = idx[1][1];
192 ROOT::Math::PtEtaPhiMVector p1(pt[i1], eta[i1], phi[i1], mass[i1]);
193 ROOT::Math::PtEtaPhiMVector p2(pt[i2], eta[i2], phi[i2], mass[i2]);
194 ROOT::Math::PtEtaPhiMVector p3(pt[i3], eta[i3], phi[i3], mass[i3]);
195 ROOT::Math::PtEtaPhiMVector p4(pt[i4], eta[i4], phi[i4], mass[i4]);
196 return (p1 + p2 + p3 + p4).M();
197}
198
199// Apply selection on reconstructed Z candidates
200RNode filter_z_candidates(RNode df)
201{
202 auto df_z1_cut = df.Filter("Z_mass[0] > 40 && Z_mass[0] < 120", "Mass of first Z candidate in [40, 120]");
203 auto df_z2_cut = df_z1_cut.Filter("Z_mass[1] > 12 && Z_mass[1] < 120", "Mass of second Z candidate in [12, 120]");
204 return df_z2_cut;
205}
206
207// Reconstruct Higgs from four muons
208RNode reco_higgs_to_4mu(RNode df)
209{
210 // Filter interesting events
211 auto df_base = selection_4mu(df);
212
213 // Reconstruct Z systems
214 auto df_z_idx =
215 df_base.Define("Z_idx", reco_zz_to_4l, {"Muon_pt", "Muon_eta", "Muon_phi", "Muon_mass", "Muon_charge"});
216
217 // Cut on distance between muons building Z systems
218 auto filter_z_dr = [](const RVec<RVec<size_t>> &idx, cRVecF eta, cRVecF phi) {
219 for (size_t i = 0; i < 2; i++) {
220 const auto i1 = idx[i][0];
221 const auto i2 = idx[i][1];
222 const auto dr = DeltaR(eta[i1], eta[i2], phi[i1], phi[i2]);
223 if (dr < 0.02) {
224 return false;
225 }
226 }
227 return true;
228 };
229 auto df_z_dr =
230 df_z_idx.Filter(filter_z_dr, {"Z_idx", "Muon_eta", "Muon_phi"}, "Delta R separation of muons building Z system");
231
232 // Compute masses of Z systems
233 auto df_z_mass =
234 df_z_dr.Define("Z_mass", compute_z_masses_4l, {"Z_idx", "Muon_pt", "Muon_eta", "Muon_phi", "Muon_mass"});
235
236 // Cut on mass of Z candidates
237 auto df_z_cut = filter_z_candidates(df_z_mass);
238
239 // Reconstruct H mass
240 auto df_h_mass =
241 df_z_cut.Define("H_mass", compute_higgs_mass_4l, {"Z_idx", "Muon_pt", "Muon_eta", "Muon_phi", "Muon_mass"});
242
243 return df_h_mass;
244}
245
246// Reconstruct Higgs from four electrons
247RNode reco_higgs_to_4el(RNode df)
248{
249 // Filter interesting events
250 auto df_base = selection_4el(df);
251
252 // Reconstruct Z systems
253 auto df_z_idx = df_base.Define("Z_idx", reco_zz_to_4l,
254 {"Electron_pt", "Electron_eta", "Electron_phi", "Electron_mass", "Electron_charge"});
255
256 // Cut on distance between Electrons building Z systems
257 auto filter_z_dr = [](const RVec<RVec<size_t>> &idx, cRVecF eta, cRVecF phi) {
258 for (size_t i = 0; i < 2; i++) {
259 const auto i1 = idx[i][0];
260 const auto i2 = idx[i][1];
261 const auto dr = DeltaR(eta[i1], eta[i2], phi[i1], phi[i2]);
262 if (dr < 0.02) {
263 return false;
264 }
265 }
266 return true;
267 };
268 auto df_z_dr = df_z_idx.Filter(filter_z_dr, {"Z_idx", "Electron_eta", "Electron_phi"},
269 "Delta R separation of Electrons building Z system");
270
271 // Compute masses of Z systems
272 auto df_z_mass = df_z_dr.Define("Z_mass", compute_z_masses_4l,
273 {"Z_idx", "Electron_pt", "Electron_eta", "Electron_phi", "Electron_mass"});
274
275 // Cut on mass of Z candidates
276 auto df_z_cut = filter_z_candidates(df_z_mass);
277
278 // Reconstruct H mass
279 auto df_h_mass = df_z_cut.Define("H_mass", compute_higgs_mass_4l,
280 {"Z_idx", "Electron_pt", "Electron_eta", "Electron_phi", "Electron_mass"});
281
282 return df_h_mass;
283}
284
285// Compute mass of two Z candidates from two electrons and two muons and sort ascending in distance to Z mass
286ROOT::RVecF compute_z_masses_2el2mu(cRVecF el_pt, cRVecF el_eta, cRVecF el_phi, cRVecF el_mass, cRVecF mu_pt,
287 cRVecF mu_eta, cRVecF mu_phi, cRVecF mu_mass)
288{
289 ROOT::Math::PtEtaPhiMVector p1(mu_pt[0], mu_eta[0], mu_phi[0], mu_mass[0]);
290 ROOT::Math::PtEtaPhiMVector p2(mu_pt[1], mu_eta[1], mu_phi[1], mu_mass[1]);
291 ROOT::Math::PtEtaPhiMVector p3(el_pt[0], el_eta[0], el_phi[0], el_mass[0]);
292 ROOT::Math::PtEtaPhiMVector p4(el_pt[1], el_eta[1], el_phi[1], el_mass[1]);
293 auto mu_z = (p1 + p2).M();
294 auto el_z = (p3 + p4).M();
295 ROOT::RVecF z_masses(2);
296 if (std::abs(mu_z - z_mass) < std::abs(el_z - z_mass)) {
297 z_masses[0] = mu_z;
298 z_masses[1] = el_z;
299 } else {
300 z_masses[0] = el_z;
301 z_masses[1] = mu_z;
302 }
303 return z_masses;
304}
305
306// Compute Higgs mass from two electrons and two muons
307float compute_higgs_mass_2el2mu(cRVecF el_pt, cRVecF el_eta, cRVecF el_phi, cRVecF el_mass, cRVecF mu_pt, cRVecF mu_eta,
308 cRVecF mu_phi, cRVecF mu_mass)
309{
310 ROOT::Math::PtEtaPhiMVector p1(mu_pt[0], mu_eta[0], mu_phi[0], mu_mass[0]);
311 ROOT::Math::PtEtaPhiMVector p2(mu_pt[1], mu_eta[1], mu_phi[1], mu_mass[1]);
312 ROOT::Math::PtEtaPhiMVector p3(el_pt[0], el_eta[0], el_phi[0], el_mass[0]);
313 ROOT::Math::PtEtaPhiMVector p4(el_pt[1], el_eta[1], el_phi[1], el_mass[1]);
314 return (p1 + p2 + p3 + p4).M();
315}
316
317// Reconstruct Higgs from two electrons and two muons
318RNode reco_higgs_to_2el2mu(RNode df)
319{
320 // Filter interesting events
321 auto df_base = selection_2el2mu(df);
322
323 // Compute masses of Z systems
324 auto df_z_mass =
325 df_base.Define("Z_mass", compute_z_masses_2el2mu, {"Electron_pt", "Electron_eta", "Electron_phi", "Electron_mass",
326 "Muon_pt", "Muon_eta", "Muon_phi", "Muon_mass"});
327
328 // Cut on mass of Z candidates
329 auto df_z_cut = filter_z_candidates(df_z_mass);
330
331 // Reconstruct H mass
332 auto df_h_mass = df_z_cut.Define(
333 "H_mass", compute_higgs_mass_2el2mu,
334 {"Electron_pt", "Electron_eta", "Electron_phi", "Electron_mass", "Muon_pt", "Muon_eta", "Muon_phi", "Muon_mass"});
335
336 return df_h_mass;
337}
338
339// Plot invariant mass for signal and background processes from simulated events
340// overlay the measured data.
341template <typename T>
342void plot(T sig, T bkg, T data, const std::string &x_label, const std::string &filename)
343{
344 // Canvas and general style options
345 gStyle->SetOptStat(0);
346 gStyle->SetTextFont(42);
347 auto c = new TCanvas("c", "", 800, 700);
348 c->SetLeftMargin(0.15);
349
350 // Get signal and background histograms and stack them to show Higgs signal
351 // on top of the background process
352 auto h_sig = *sig;
353 auto h_bkg = *bkg;
354 auto h_cmb = *(TH1D*)(sig->Clone());
355 h_cmb.Add(&h_bkg);
356 h_cmb.SetTitle("");
357 h_cmb.GetXaxis()->SetTitle(x_label.c_str());
358 h_cmb.GetXaxis()->SetTitleSize(0.04);
359 h_cmb.GetYaxis()->SetTitle("N_{Events}");
360 h_cmb.GetYaxis()->SetTitleSize(0.04);
361 h_cmb.SetLineColor(kRed);
362 h_cmb.SetLineWidth(2);
363 h_cmb.SetMaximum(18);
364
365 h_bkg.SetLineWidth(2);
366 h_bkg.SetFillStyle(1001);
367 h_bkg.SetLineColor(kBlack);
368 h_bkg.SetFillColor(kAzure - 9);
369
370 // Get histogram of data points
371 auto h_data = *data;
372 h_data.SetLineWidth(1);
373 h_data.SetMarkerStyle(20);
374 h_data.SetMarkerSize(1.0);
375 h_data.SetMarkerColor(kBlack);
376 h_data.SetLineColor(kBlack);
377
378 // Draw histograms
379 h_cmb.DrawClone("HIST");
380 h_bkg.DrawClone("HIST SAME");
381 h_data.DrawClone("PE1 SAME");
382
383 // Add legend
384 TLegend legend(0.62, 0.70, 0.82, 0.88);
385 legend.SetFillColor(0);
386 legend.SetBorderSize(0);
387 legend.SetTextSize(0.03);
388 legend.AddEntry(&h_data, "Data", "PE1");
389 legend.AddEntry(&h_bkg, "ZZ", "f");
390 legend.AddEntry(&h_cmb, "m_{H} = 125 GeV", "f");
391 legend.DrawClone();
392
393 // Add header
394 TLatex cms_label;
395 cms_label.SetTextSize(0.04);
396 cms_label.DrawLatexNDC(0.16, 0.92, "#bf{CMS Open Data}");
397 TLatex header;
398 header.SetTextSize(0.03);
399 header.DrawLatexNDC(0.63, 0.92, "#sqrt{s} = 8 TeV, L_{int} = 11.6 fb^{-1}");
400
401 // Save plot
402 c->SaveAs(filename.c_str());
403}
404
405void df103_NanoAODHiggsAnalysis(const bool run_fast = true)
406{
407 // Enable multi-threading
409
410 // In fast mode, take samples from */cms_opendata_2012_nanoaod_skimmed/*, which has
411 // the preselections from the selection_* functions already applied.
412 std::string path = "root://eospublic.cern.ch//eos/root-eos/cms_opendata_2012_nanoaod/";
413 if (run_fast) path = "root://eospublic.cern.ch//eos/root-eos/cms_opendata_2012_nanoaod_skimmed/";
414
415 // Create dataframes for signal, background and data samples
416
417 // Signal: Higgs -> 4 leptons
418 ROOT::RDataFrame df_sig_4l("Events", path + "SMHiggsToZZTo4L.root");
419
420 // Background: ZZ -> 4 leptons
421 // Note that additional background processes from the original paper with minor contribution were left out for this
422 // tutorial.
423 ROOT::RDataFrame df_bkg_4mu("Events", path + "ZZTo4mu.root");
424 ROOT::RDataFrame df_bkg_4el("Events", path + "ZZTo4e.root");
425 ROOT::RDataFrame df_bkg_2el2mu("Events", path + "ZZTo2e2mu.root");
426
427 // CMS data taken in 2012 (11.6 fb^-1 integrated luminosity)
428 ROOT::RDataFrame df_data_doublemu(
429 "Events", {path + "Run2012B_DoubleMuParked.root", path + "Run2012C_DoubleMuParked.root"});
430 ROOT::RDataFrame df_data_doubleel(
431 "Events", {path + "Run2012B_DoubleElectron.root", path + "Run2012C_DoubleElectron.root"});
432
433 // Reconstruct Higgs to 4 muons
434 auto df_sig_4mu_reco = reco_higgs_to_4mu(df_sig_4l);
435 const auto luminosity = 11580.0; // Integrated luminosity of the data samples
436 const auto xsec_SMHiggsToZZTo4L = 0.0065; // H->4l: Standard Model cross-section
437 const auto nevt_SMHiggsToZZTo4L = 299973.0; // H->4l: Number of simulated events
438 const auto nbins = 36; // Number of bins for the invariant mass spectrum
439 auto df_h_sig_4mu = df_sig_4mu_reco
440 .Define("weight", [&]() { return luminosity * xsec_SMHiggsToZZTo4L / nevt_SMHiggsToZZTo4L; }, {})
441 .Histo1D({"h_sig_4mu", "", nbins, 70, 180}, "H_mass", "weight");
442
443 const auto scale_ZZTo4l = 1.386; // ZZ->4mu: Scale factor for ZZ to four leptons
444 const auto xsec_ZZTo4mu = 0.077; // ZZ->4mu: Standard Model cross-section
445 const auto nevt_ZZTo4mu = 1499064.0; // ZZ->4mu: Number of simulated events
446 auto df_bkg_4mu_reco = reco_higgs_to_4mu(df_bkg_4mu);
447 auto df_h_bkg_4mu = df_bkg_4mu_reco
448 .Define("weight", [&]() { return luminosity * xsec_ZZTo4mu * scale_ZZTo4l / nevt_ZZTo4mu; }, {})
449 .Histo1D({"h_bkg_4mu", "", nbins, 70, 180}, "H_mass", "weight");
450
451 auto df_data_4mu_reco = reco_higgs_to_4mu(df_data_doublemu);
452 auto df_h_data_4mu = df_data_4mu_reco
453 .Define("weight", []() { return 1.0; }, {})
454 .Histo1D({"h_data_4mu", "", nbins, 70, 180}, "H_mass", "weight");
455
456 // Reconstruct Higgs to 4 electrons
457 auto df_sig_4el_reco = reco_higgs_to_4el(df_sig_4l);
458 auto df_h_sig_4el = df_sig_4el_reco
459 .Define("weight", [&]() { return luminosity * xsec_SMHiggsToZZTo4L / nevt_SMHiggsToZZTo4L; }, {})
460 .Histo1D({"h_sig_4el", "", nbins, 70, 180}, "H_mass", "weight");
461
462 const auto xsec_ZZTo4el = xsec_ZZTo4mu; // ZZ->4el: Standard Model cross-section
463 const auto nevt_ZZTo4el = 1499093.0; // ZZ->4el: Number of simulated events
464 auto df_bkg_4el_reco = reco_higgs_to_4el(df_bkg_4el);
465 auto df_h_bkg_4el = df_bkg_4el_reco
466 .Define("weight", [&]() { return luminosity * xsec_ZZTo4el * scale_ZZTo4l / nevt_ZZTo4el; }, {})
467 .Histo1D({"h_bkg_4el", "", nbins, 70, 180}, "H_mass", "weight");
468
469 auto df_data_4el_reco = reco_higgs_to_4el(df_data_doubleel);
470 auto df_h_data_4el = df_data_4el_reco.Define("weight", []() { return 1.0; }, {})
471 .Histo1D({"h_data_4el", "", nbins, 70, 180}, "H_mass", "weight");
472
473 // Reconstruct Higgs to 2 electrons and 2 muons
474 auto df_sig_2el2mu_reco = reco_higgs_to_2el2mu(df_sig_4l);
475 auto df_h_sig_2el2mu = df_sig_2el2mu_reco
476 .Define("weight", [&]() { return luminosity * xsec_SMHiggsToZZTo4L / nevt_SMHiggsToZZTo4L; }, {})
477 .Histo1D({"h_sig_2el2mu", "", nbins, 70, 180}, "H_mass", "weight");
478
479 const auto xsec_ZZTo2el2mu = 0.18; // ZZ->2el2mu: Standard Model cross-section
480 const auto nevt_ZZTo2el2mu = 1497445.0; // ZZ->2el2mu: Number of simulated events
481 auto df_bkg_2el2mu_reco = reco_higgs_to_2el2mu(df_bkg_2el2mu);
482 auto df_h_bkg_2el2mu = df_bkg_2el2mu_reco
483 .Define("weight", [&]() { return luminosity * xsec_ZZTo2el2mu * scale_ZZTo4l / nevt_ZZTo2el2mu; }, {})
484 .Histo1D({"h_bkg_2el2mu", "", nbins, 70, 180}, "H_mass", "weight");
485
486 auto df_data_2el2mu_reco = reco_higgs_to_2el2mu(df_data_doublemu);
487 auto df_h_data_2el2mu = df_data_2el2mu_reco.Define("weight", []() { return 1.0; }, {})
488 .Histo1D({"h_data_2el2mu_doublemu", "", nbins, 70, 180}, "H_mass", "weight");
489
490 // RunGraphs allows to run the event loops of the separate RDataFrame graphs
491 // concurrently. This results in an improved usage of the available resources
492 // if each separate RDataFrame can not utilize all available resources, e.g.,
493 // because not enough data is available.
494 ROOT::RDF::RunGraphs({df_h_sig_4mu, df_h_bkg_4mu, df_h_data_4mu,
495 df_h_sig_4el, df_h_bkg_4el, df_h_data_4el,
496 df_h_sig_2el2mu, df_h_bkg_2el2mu, df_h_data_2el2mu});
497
498 // Make plots
499 plot(df_h_sig_4mu, df_h_bkg_4mu, df_h_data_4mu, "m_{4#mu} (GeV)", "higgs_4mu.pdf");
500 plot(df_h_sig_4el, df_h_bkg_4el, df_h_data_4el, "m_{4e} (GeV)", "higgs_4el.pdf");
501 plot(df_h_sig_2el2mu, df_h_bkg_2el2mu, df_h_data_2el2mu, "m_{2e2#mu} (GeV)", "higgs_2el2mu.pdf");
502
503 // Combine channels for final plot
504 auto h_data_4l = df_h_data_4mu.GetPtr();
505 h_data_4l->Add(df_h_data_4el.GetPtr());
506 h_data_4l->Add(df_h_data_2el2mu.GetPtr());
507 auto h_sig_4l = df_h_sig_4mu.GetPtr();
508 h_sig_4l->Add(df_h_sig_4el.GetPtr());
509 h_sig_4l->Add(df_h_sig_2el2mu.GetPtr());
510 auto h_bkg_4l = df_h_bkg_4mu.GetPtr();
511 h_bkg_4l->Add(df_h_bkg_4el.GetPtr());
512 h_bkg_4l->Add(df_h_bkg_2el2mu.GetPtr());
513 plot(h_sig_4l, h_bkg_4l, h_data_4l, "m_{4l} (GeV)", "higgs_4l.pdf");
514}
515
516int main()
517{
518 df103_NanoAODHiggsAnalysis(/*fast=*/true);
519}
int main()
Definition Prototype.cxx:12
#define c(i)
Definition RSha256.hxx:101
@ kRed
Definition Rtypes.h:66
@ kBlack
Definition Rtypes.h:65
@ kAzure
Definition Rtypes.h:67
R__EXTERN TStyle * gStyle
Definition TStyle.h:413
Class describing a generic LorentzVector in the 4D space-time, using the specified coordinate system ...
ROOT's RDataFrame offers a high level interface for analyses of data stored in TTree,...
virtual void SetTextFont(Font_t tfont=62)
Set the text font.
Definition TAttText.h:46
virtual void SetTextSize(Float_t tsize=1)
Set the text size.
Definition TAttText.h:47
The Canvas class.
Definition TCanvas.h:23
1-D histogram with a double per channel (see TH1 documentation)}
Definition TH1.h:618
To draw Mathematical Formula.
Definition TLatex.h:18
TLatex * DrawLatexNDC(Double_t x, Double_t y, const char *text)
Draw this TLatex with new coordinates in NDC.
Definition TLatex.cxx:1955
This class displays a legend box (TPaveText) containing several legend entries.
Definition TLegend.h:23
virtual void SaveAs(const char *filename="", Option_t *option="") const
Save this object in the file specified by filename.
Definition TObject.cxx:671
void SetOptStat(Int_t stat=1)
The type of information printed in the histogram statistics box can be selected via the parameter mod...
Definition TStyle.cxx:1589
TPaveText * pt
RVec< T > Reverse(const RVec< T > &v)
Return copy of reversed vector.
Definition RVec.hxx:2326
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.
Definition RVec.hxx:2451
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...
Definition VectorUtil.h:110
RInterface<::ROOT::Detail::RDF::RNodeBase, void > RNode
void RunGraphs(std::vector< RResultHandle > handles)
Trigger the event loop of multiple RDataFrames concurrently.
void EnableImplicitMT(UInt_t numthreads=0)
Enable ROOT's implicit multi-threading for all objects and methods that provide an internal paralleli...
Definition TROOT.cxx:527
void Sort(Index n, const Element *a, Index *index, Bool_t down=kTRUE)
Definition TMathBase.h:358