Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
df104.py
Go to the documentation of this file.
1## \file
2## \ingroup tutorial_rcanvas
3## The Higgs to two photons analysis from the ATLAS Open Data 2020 release, with RDataFrame.
4##
5## This tutorial is the Higgs to two photons analysis from the ATLAS Open Data release in 2020
6## (http://opendata.atlas.cern/release/2020/documentation/). The data was taken with the ATLAS detector
7## during 2016 at a center-of-mass energy of 13 TeV. Although the Higgs to two photons decay is very rare,
8## the contribution of the Higgs can be seen as a narrow peak around 125 GeV because of the excellent
9## reconstruction and identification efficiency of photons at the ATLAS experiment.
10##
11## The analysis is translated to a RDataFrame workflow processing 1.7 GB of simulated events and data.
12##
13## This macro is replica of tutorials/analysis/dataframe/df104_HiggsToTwoPhotons.py, but with usage of ROOT7 graphics
14## Run macro with python3 -i df104.py command to get interactive canvas
15##
16## \macro_image (df104.png)
17## \macro_code
18##
19## \date 2021-06-15
20## \authors Stefan Wunsch (KIT, CERN) Sergey Linev (GSI)
21
22import ROOT
23import os
24from ROOT.Experimental import (
25 RCanvas,
26 RText,
27 RAttrText,
28 RAttrFont,
29 RAttrFill,
30 RAttrLine,
31 RLegend,
32 RPadPos,
33 RPadExtent,
34 TObjectDrawable,
35)
36
37# Enable multi-threading
39
40# Create a ROOT dataframe for each dataset
41path = "root://eospublic.cern.ch//eos/opendata/atlas/OutreachDatasets/2020-01-22"
42df = {}
43df["data"] = ROOT.RDataFrame(
44 "mini", (os.path.join(path, "GamGam/Data/data_{}.GamGam.root".format(x)) for x in ("A", "B", "C", "D"))
45)
46df["ggH"] = ROOT.RDataFrame("mini", os.path.join(path, "GamGam/MC/mc_343981.ggH125_gamgam.GamGam.root"))
47df["VBF"] = ROOT.RDataFrame("mini", os.path.join(path, "GamGam/MC/mc_345041.VBFH125_gamgam.GamGam.root"))
48processes = list(df.keys())
49
50# Apply scale factors and MC weight for simulated events and a weight of 1 for the data
51for p in ["ggH", "VBF"]:
52 df[p] = df[p].Define("weight", "scaleFactor_PHOTON * scaleFactor_PhotonTRIGGER * scaleFactor_PILEUP * mcWeight")
53df["data"] = df["data"].Define("weight", "1.0")
54
55# Select the events for the analysis
56for p in processes:
57 # Apply preselection cut on photon trigger
58 df[p] = df[p].Filter("trigP")
59
60 # Find two good muons with tight ID, pt > 25 GeV and not in the transition region between barrel and encap
61 df[p] = (
62 df[p]
63 .Define(
64 "goodphotons",
65 "photon_isTightID && (photon_pt > 25000) && (abs(photon_eta) < 2.37) && ((abs(photon_eta) < 1.37) || (abs(photon_eta) > 1.52))",
66 )
67 .Filter("Sum(goodphotons) == 2")
68 )
69
70 # Take only isolated photons
71 df[p] = (
72 df[p]
73 .Filter("Sum(photon_ptcone30[goodphotons] / photon_pt[goodphotons] < 0.065) == 2")
74 .Filter("Sum(photon_etcone20[goodphotons] / photon_pt[goodphotons] < 0.065) == 2")
75 )
76
77# Compile a function to compute the invariant mass of the diphoton system
79 """
80using Vec_t = const ROOT::VecOps::RVec<float>;
81float ComputeInvariantMass(Vec_t& pt, Vec_t& eta, Vec_t& phi, Vec_t& e) {
82 ROOT::Math::PtEtaPhiEVector p1(pt[0], eta[0], phi[0], e[0]);
83 ROOT::Math::PtEtaPhiEVector p2(pt[1], eta[1], phi[1], e[1]);
84 return (p1 + p2).mass() / 1000.0;
85}
86"""
87)
88
89# Define a new column with the invariant mass and perform final event selection
90hists = {}
91for p in processes:
92 # Make four vectors and compute invariant mass
93 df[p] = df[p].Define(
94 "m_yy",
95 "ComputeInvariantMass(photon_pt[goodphotons], photon_eta[goodphotons], photon_phi[goodphotons], photon_E[goodphotons])",
96 )
97
98 # Make additional kinematic cuts and select mass window
99 df[p] = (
100 df[p]
101 .Filter("photon_pt[goodphotons][0] / 1000.0 / m_yy > 0.35")
102 .Filter("photon_pt[goodphotons][1] / 1000.0 / m_yy > 0.25")
103 .Filter("m_yy > 105 && m_yy < 160")
104 )
105
106 # Book histogram of the invariant mass with this selection
107 hists[p] = df[p].Histo1D(
108 ROOT.RDF.TH1DModel(p, "Diphoton invariant mass; m_{#gamma#gamma} [GeV];Events", 30, 105, 160), "m_yy", "weight"
109 )
110
111# Run the event loop
112
113# RunGraphs allows to run the event loops of the separate RDataFrame graphs
114# concurrently. This results in an improved usage of the available resources
115# if each separate RDataFrame can not utilize all available resources, e.g.,
116# because not enough data is available.
117ROOT.RDF.RunGraphs([hists[s] for s in ["ggH", "VBF", "data"]])
118
119ggh = hists["ggH"].GetValue()
120vbf = hists["VBF"].GetValue()
121data = hists["data"].GetValue()
122
123# Create the plot
124
125# Set styles - not yet available for v7
126# ROOT.gROOT.SetStyle("ATLAS")
127
128# Create canvas with pads for main plot and data/MC ratio
129c = RCanvas.Create("df104_HiggsToTwoPhotons")
130
131lower_pad = c.AddPad(RPadPos(0, 0.65), RPadExtent(1, 0.35))
132upper_pad = c.AddPad(RPadPos(0, 0), RPadExtent(1, 0.65))
133
134upper_frame = upper_pad.AddFrame()
139
140lower_frame = lower_pad.AddFrame()
145
146# Fit signal + background model to data
147fit = ROOT.TF1("fit", "([0]+[1]*x+[2]*x^2+[3]*x^3)+[4]*exp(-0.5*((x-[5])/[6])^2)", 105, 160)
148fit.FixParameter(5, 125.0)
149fit.FixParameter(4, 119.1)
150fit.FixParameter(6, 2.39)
154# do not draw fit function
155data.Fit("fit", "0", "", 105, 160)
156
157# Draw data
161data.SetLineColor("black")
162data.SetMinimum(1e-3)
164data.GetYaxis().SetLabelSize(0.045)
165data.GetYaxis().SetTitleSize(0.05)
166data.GetYaxis().SetTitleOffset(1.4)
167data.SetStats(False)
169
170data_drawable = upper_pad.Add[TObjectDrawable]()
171data_drawable.Set(data, "E")
172
173# Draw fit
174fit_drawable = upper_pad.Add[TObjectDrawable]()
175fit_drawable.Set(fit, "SAME")
176
177# Draw background
178bkg = ROOT.TF1("bkg", "([0]+[1]*x+[2]*x^2+[3]*x^3)", 105, 160)
179for i in range(4):
184bkg_drawable = upper_pad.Add[TObjectDrawable]()
185bkg_drawable.Set(bkg, "SAME")
186
187# Scale simulated events with luminosity * cross-section / sum of weights
188# and merge to single Higgs signal
189lumi = 10064.0
190ggh.Scale(lumi * 0.102 / 55922617.6297)
191vbf.Scale(lumi * 0.008518764 / 3441426.13711)
192higgs = ggh.Clone()
193higgs.Add(vbf)
194higgs_drawable = upper_pad.Add[TObjectDrawable]()
195higgs_drawable.Set(higgs, "HIST SAME")
196
197# Draw ratio
198
199ratiobkg = ROOT.TH1I("zero", "", 10, 105, 160)
206ratiobkg.GetXaxis().SetLabelSize(0.08)
207ratiobkg.GetXaxis().SetTitleSize(0.12)
208ratiobkg.GetXaxis().SetTitleOffset(1.0)
209ratiobkg.GetYaxis().SetLabelSize(0.08)
210ratiobkg.GetYaxis().SetTitleSize(0.09)
211ratiobkg.GetYaxis().SetTitle("Data - Bkg.")
212ratiobkg.GetYaxis().SetTitleOffset(0.7)
213ratiobkg.GetYaxis().CenterTitle()
214ratiobkg.GetYaxis().SetNdivisions(503, False)
215ratiobkg.GetYaxis().ChangeLabel(-1, -1, 0)
216ratiobkg.GetXaxis().SetTitle("m_{#gamma#gamma} [GeV]")
217lower_pad.Add[TObjectDrawable]().Set(ratiobkg, "AXIS")
218
219ratiosig = ROOT.TH1F("ratiosig", "ratiosig", 5500, 105, 160)
220ratiosig.Eval(fit)
224ratiosig.Add(bkg, -1)
225lower_pad.Add[TObjectDrawable]().Set(ratiosig, "SAME")
226
227ratiodata = data.Clone()
228ratiodata.Add(bkg, -1)
229for i in range(1, data.GetNbinsX()):
231
232lower_pad.Add[TObjectDrawable]().Set(ratiodata, "E SAME")
233
234# Add RLegend
235legend = upper_pad.Draw[RLegend](RPadPos(0.01, 0.01), RPadExtent(0.3, 0.4))
236legend.text.size = 0.05
242
243legend.AddEntry(data_drawable, "Data", "lme")
244legend.AddEntry(bkg_drawable, "Background", "l")
245legend.AddEntry(fit_drawable, "Signal + Bkg.", "l")
246legend.AddEntry(higgs_drawable, "Signal", "l")
247
248# Add ATLAS labels
249lbl1 = upper_pad.Draw[RText](RPadPos(0.05, 0.88), "ATLAS")
250lbl1.onFrame = True
252lbl1.text.size = 0.04
254lbl2 = upper_pad.Draw[RText](RPadPos(0.05 + 0.16, 0.88), "Open Data")
255lbl2.onFrame = True
257lbl2.text.size = 0.04
259lbl3 = upper_pad.Draw[RText](RPadPos(0.05, 0.82), "#sqrt{s} = 13 TeV, 10 fb^{-1}")
260lbl3.onFrame = True
262lbl3.text.size = 0.03
264
265# show canvas finally
266c.SetSize(700, 780)
267c.Show()
268
269# Save plot in PNG file
270if c.SaveAs("df104.png"):
271 print("Saved figure to df104.png")
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
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 Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t format
ROOT's RDataFrame offers a modern, high-level interface for analysis of data stored in TTree ,...
A struct which stores some basic parameters of a TH1D.