ATLAS Offline Software
CheckAppliedSFs.py
Go to the documentation of this file.
1 # Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
2 
3 #!/usr/bin/env python
4 from array import array
5 import ROOT, argparse, sys, gc, os, math
6 from PlotUtils import PlotUtils, DiagnosticHisto
7 
8 
9 
11  def __init__(self,
12  var_name = "", axis_title ="",
13  bins = -1, bmin = 0., bmax = 0., bin_width = -1,
14  bdir = None,
15 
16  name_old_rel ="", name_new_rel ="",
17 
18  test_tree = None,
19  branch_old = "", branch_new = "",
20  weight_old = None, weight_new = None,
21  log_binning = False
22  ):
23 
24  self.__old_branch = test_tree.GetLeaf(branch_old)
25  self.__new_branch = test_tree.GetLeaf(branch_new)
26  if not self.__old_branch:
27  raise NameError("Could not find "+branch_old+" in the Tree")
28 
29  if not self.__new_branch:
30  raise NameError("Could not find "+branch_new+" in the Tree")
31 
32  self.__old_weight = 1. if not weight_old else test_tree.GetLeaf(weight_old)
33  self.__new_weight = 1. if not weight_new else test_tree.GetLeaf(weight_new)
34  if weight_old and not self.__old_weight:
35  raise NameError("Could not find "+weight_old+" in the Tree")
36  if weight_new and not self.__new_weight:
37  raise NameError("Could not find "+weight_new+" in the Tree")
38 
39  self.__quality_branch = test_tree.GetLeaf("Muon_quality")
40  if branch_old.find("HighPt") != -1 : self.__quality_branch = test_tree.GetLeaf("Muon_isHighPt")
41  if branch_old.find("LowPt") != -1 : self.__quality_branch = test_tree.GetLeaf("Muon_isLowPt")
42 
43  self.__min_quality = 0 if branch_old.find("HighPt") != -1 and branch_old.find("LowPt") != -1 else 1
44  self.__max_quality = 2
45  if branch_old.find("Medium") != -1: self.__max_quality = 1
46  if branch_old.find("Tight") != -1: self.__max_quality = 0
47 
48 
49  self.__var_name = var_name
51  name = "%s_%s"%(name_old_rel, var_name),
52  axis_title = axis_title,
53  bins = bins, bmin = bmin, bmax = bmax,
54  bin_width = bin_width, bdir = bdir, log_binning = log_binning)
56  name = "%s_%s"%(name_new_rel, var_name),
57  axis_title = axis_title,
58  bins = bins, bmin = bmin, bmax = bmax,
59  bin_width = bin_width, bdir = bdir, log_binning = log_binning)
60 
61  def pass_cut(self):
62  return self.__min_quality >= self.__quality_branch .GetValue() and self.__quality_branch.GetValue() <= self.__max_quality
63  def fill(self):
64  if not self.pass_cut(): return
65  self.__old_histo.fill(value = self.__old_branch.GetValue(), weight= self.get_old_weight())
66  self.__new_histo.fill(value = self.__new_branch.GetValue(), weight= self.get_new_weight())
67  def get_old_histo(self):
68  return self.__old_histo
69  def get_new_histo(self):
70  return self.__new_histo
71  def get_old_var(self):
72  return self.__old_branch
73  def get_new_var(self):
74  return self.__new_branch
75  def get_old_weight(self):
76  if isinstance(self.__old_weight, float): return self.__old_weight
77  return self.__old_weight.GetValue()
78  def get_new_weight(self):
79  if isinstance(self.__new_weight, float): return self.__new_weight
80  return self.__new_weight.GetValue()
81  def finalize(self):
82  minimum = min(self.get_old_histo().min(), self.get_new_histo().min()) - 0.01
83  maximum = max(self.get_old_histo().max(), self.get_new_histo().max()) + 0.01
84  for H in [ self.get_old_histo(), self.get_new_histo()]:
85  H.setMinimum(minimum)
86  H.setMaximum(maximum)
87  H.write()
88 
89  def name(self):
90  return self.__var_name
92  def __init__(self,
93  var_name = "",
94  axis_title ="",
95  bins = -1,
96 
97  name_old_rel ="",
98  name_new_rel ="",
99 
100  test_tree = None,
101  branch_old = "",
102  branch_new = "",
103  weight_old = None,
104  weight_new = None,
105 
106  branch_sys_old = "",
107  branch_sys_new = "",
108  ):
109  ReleaseComparer.__init__(self,
110  var_name = var_name,
111  axis_title = axis_title,
112  bins = bins, bmin = 5.e-4, bmax = 4.,
113  name_old_rel =name_old_rel,
114  name_new_rel =name_new_rel,
115  test_tree = test_tree,
116  branch_old = branch_old,
117  branch_new = branch_new,
118  weight_old = weight_old,
119  weight_new = weight_new,
120  log_binning = True)
121  self.__sys_old = test_tree.GetLeaf(branch_sys_old)
122  self.__sys_new = test_tree.GetLeaf(branch_sys_new)
123  if not self.__sys_old:
124  raise NameError("Failed to retrieve "+branch_sys_old)
125  if not self.__sys_new:
126  raise NameError("Failed to retrieve "+branch_sys_new)
127 
128 
129  def fill(self):
130  self.get_old_histo().fill(value = math.fabs(self.get_old_var().GetValue() - self.__sys_old.GetValue()) / (self.get_old_var().GetValue() if self.get_old_var().GetValue() != 0. else 1.) ,
131  weight= self.get_old_weight())
132  self.get_new_histo().fill(value = math.fabs(self.get_new_var().GetValue() - self.__sys_new.GetValue()) / (self.get_new_var().GetValue() if self.get_new_var().GetValue() != 0. else 1.),
133  weight= self.get_new_weight())
134 
135 
136 
137 KnownWPs = {
138  "Loose" : "RECO",
139  "Medium" : "RECO",
140  "Tight" : "RECO",
141  "HightPt3Layers":"RECO",
142  "HighPt" : "RECO",
143  "LowPt" : "RECO",
144  "LowPtMVA" : "RECO",
145 
146  "TTVA" : "TTVA",
147  "FCLooseIso": "ISO",
148  "FCTight_FixedRadIso": "ISO",
149  "FCLoose_FixedRadIso": "ISO",
150  "FixedCutHighPtTrackOnlyIso": "ISO",
151  "FCTightIso": "ISO",
152  "FixedCutPflowLooseIso": "ISO",
153  "FCTightTrackOnlyIso": "ISO",
154  "FixedCutPflowTightIso": "ISO",
155  "FCTightTrackOnly_FixedRadIso": "ISO",
156  "BadMuonVeto_HighPt" : "BADMUON",
157  }
158 
160  parser = argparse.ArgumentParser(description='This script checks applied scale factors written to a file by MuonEfficiencyCorrections/MuonEfficiencyCorrectionsSFFilesTest. For more help type \"python CheckAppliedSFs.py -h\"', prog='CheckAppliedSFs', formatter_class=argparse.ArgumentDefaultsHelpFormatter)
161  parser.add_argument('-i', '--InputFile', help='Specify an input root file', default="SFTest.root")
162  parser.add_argument('-o', '--outDir', help='Specify a destination directory', default="Plots")
163  parser.add_argument('-l', '--label', help='Specify the dataset you used with MuonEfficiencyCorrectionsSFFilesTest', default="Internal")
164  parser.add_argument('-w', '--WP', help='Specify a WP to plot', nargs='+', default=[])
165  parser.add_argument('-c', '--SFConstituent', help='Specify if you want to plot nominal value, sys or stat error', nargs='+', default=["SF","DataEff","MCEff"])
166  parser.add_argument('--bonusname', help='Specify a bonus name for the filename', default="")
167  parser.add_argument('--bonuslabel', help='Specify a bonus label printed in the histogram', default="")
168  parser.add_argument('--noComparison', help='do not plot comparison to old release', action='store_true', default=False)
169  parser.add_argument('-n', '--nBins', help='specify number of bins for histograms', type=int, default=50)
170  return parser
171 
173  branchesInFile = [key.GetName() for key in tree.GetListOfBranches()]
174  calibReleases = []
175  allWPs = set([wp for wp in KnownWPs.iterkeys() ])
176  WPs = []
177  for i in branchesInFile:
178  print i
179  if not i.endswith("SF"): continue
180  if not i.startswith("c"): continue
181  calibCand = i[1:-3]
182 
183  wp_str = i[ : i.rfind("_")]
184  beststr = wp_str[wp_str.rfind("_")+1 : ]
185  if beststr in allWPs:
186  if not beststr in WPs: WPs.append(beststr)
187  if not calibCand[ : calibCand.find(beststr)-1] in calibReleases: calibReleases.append(calibCand[ : calibCand.find(beststr)-1])
188  print "INFO: Found the following working points: %s"%(", ".join(WPs))
189  return calibReleases, WPs
190 
191 def getSystematics(tree, wp, calib_release):
192  search_str = "c%s_%s_SF"%(calib_release, wp)
193  syst_names = [key.GetName()[len(search_str) + 2:] for key in tree.GetListOfBranches() if key.GetName().startswith(search_str) and key.GetName() != search_str]
194  print syst_names
195  return syst_names
196 
197 if __name__ == "__main__":
198  Options = getArgParser().parse_args()
199 
200  if not os.path.exists(Options.InputFile):
201  print 'ERROR: File %s does not exist!'%Options.InputFile
202  sys.exit(1)
203  infile = ROOT.TFile(Options.InputFile)
204 
205  tree = infile.Get("MuonEfficiencyTest")
206  calibReleases, WPs = getCalibReleasesAndWP(tree)
207 
208  if len(calibReleases)==2: print "INFO: Found the following calibration releases to compare: %s"%(",".join(calibReleases))
209 
210  if len(Options.WP)>0:
211  userWPs = []
212  for wp in Options.WP:
213  if wp in WPs: userWPs.append(wp)
214  WPs = userWPs
215  print 'INFO: WPs given by user, only plot: %s'%(",".join(WPs))
216 
217 
218  ROOT.gROOT.Macro("rootlogon.C")
219  ROOT.gROOT.SetStyle("ATLAS")
220  ROOT.gROOT.SetBatch(1)
221  gc.disable()
222 
223  if os.path.isdir(Options.outDir) == False:
224  os.system("mkdir -p %s"%(Options.outDir))
225 
226  bonusname=Options.bonusname
227 
228  Histos = []
229 
230  for wp in WPs:
231  systematics = getSystematics(tree,wp, calibReleases[0])+[""]
232  for t in Options.SFConstituent:
233  corrType = "Scale Factor"
234  if t == "DataEff": corrType = "Data efficiency"
235  elif t == "MCEff": corrType = "MC efficiency"
236 
237  for var in systematics:
238  if len(var) == 0:
239  Histos += [
241  var_name = "%s_%s"%(wp,t), axis_title = " %s %s"%(corrType,wp),
242  bmin = 1., bin_width = 0.0001,
243  name_old_rel =calibReleases[0], name_new_rel = calibReleases[1],
244  test_tree = tree,
245  branch_old = "c%s_%s_%s"%(calibReleases[0],wp,t), branch_new = "c%s_%s_%s"%(calibReleases[1],wp,t),
246  )]
247  else:
248  Histos +=[
250  var_name = "%s_%s_%s"%(wp,t,var.replace("RECO",KnownWPs[wp])),
251  axis_title = "%s %s (%s)"%(var.replace("RECO",KnownWPs[wp]), corrType,wp),
252  bins = Options.nBins,
253  name_old_rel =calibReleases[0], name_new_rel = calibReleases[1],
254  test_tree = tree,
255  branch_old = "c%s_%s_%s"%(calibReleases[0],wp,t), branch_new = "c%s_%s_%s"%(calibReleases[1],wp,t),
256 
257  branch_sys_old = "c%s_%s_%s__%s"%(calibReleases[0],wp,t,var),
258  branch_sys_new = "c%s_%s_%s__%s"%(calibReleases[1],wp,t,var),
259  )]
260 
261  continue
262  Histos +=[
263  ReleaseComparer(var_name = "pt_%s"%(wp), axis_title ="p_{T} #mu(%s) [MeV]"%(wp),
264  bins = 15, bmin = 15.e3, bmax = 200.e3,
265  name_old_rel =calibReleases[0], name_new_rel = calibReleases[1],
266  test_tree = tree,
267  branch_old = "Muon_pt", branch_new = "Muon_pt",
268  weight_old = "c%s_%s_SF"%(calibReleases[0],wp),
269  weight_new = "c%s_%s_SF"%(calibReleases[1],wp)),
270 
271  ReleaseComparer(var_name = "eta_%s"%(wp), axis_title ="#eta #mu(%s) [MeV]"%(wp),
272  bins = 54, bmin = -2.7, bmax = 2.7,
273  name_old_rel =calibReleases[0], name_new_rel = calibReleases[1],
274  test_tree = tree,
275  branch_old = "Muon_eta", branch_new = "Muon_eta",
276  weight_old = "c%s_%s_SF"%(calibReleases[0],wp),
277  weight_new = "c%s_%s_SF"%(calibReleases[1],wp)),
278  ReleaseComparer(var_name = "phi_%s"%(wp), axis_title ="#phi #mu(%s) [MeV]"%(wp),
279  bins = 16, bmin = -3.15, bmax = 3.15,
280  name_old_rel =calibReleases[0], name_new_rel = calibReleases[1],
281  test_tree = tree,
282  branch_old = "Muon_phi", branch_new = "Muon_phi",
283  weight_old = "c%s_%s_SF"%(calibReleases[0],wp),
284  weight_new = "c%s_%s_SF"%(calibReleases[1],wp)),
285 
286  ]
287 
288  for i in range(tree.GetEntries()):
289  tree.GetEntry(i)
290  if i > 0 and i % 2500 == 0:
291  print "INFO: %d/%d events processed"%(i, tree.GetEntries())
292 
293  if math.fabs(tree.Muon_eta) > 2.5 or math.fabs(tree.Muon_eta) < 0.1 or math.fabs(tree.Muon_pt) > 15.e3: continue
294  for H in Histos:
295  H.fill()
296 
297  print "INFO: Histograms filled"
298 
299 
300 
301  if len(calibReleases)==2:
302 
303  dummy = ROOT.TCanvas("dummy", "dummy", 800, 600)
304  dummy.SaveAs("%s/AllAppliedSFCheckPlots%s.pdf[" % (Options.outDir, bonusname))
305 
306  for comp in Histos:
307  comp.finalize()
308  histoCR1 = comp.get_old_histo().TH1()
309  histoCR2 = comp.get_new_histo().TH1()
310 
311  pu = PlotUtils(status = Options.label)
312  pu.Prepare1PadCanvas(comp.name())
313  pu.GetCanvas().SetLogy()
314  if comp.get_old_histo().has_log_binnnig(): pu.GetCanvas().SetLogx()
315 
316  histoCR1.GetYaxis().SetTitle("Fraction of muons")
317 
318  pu.drawStyling(histoCR1, 1, max([histoCR1.GetMaximum(),histoCR2.GetMaximum()]) *1.e3, TopPad = False)
319  histoCR1.SetTitle("%s, Mean: %.8f"%(calibReleases[0],histoCR1.GetMean()))
320  histoCR2.SetTitle("%s, Mean: %.8f"%(calibReleases[1],histoCR2.GetMean()))
321 
322  histoCR1.Draw("sameHIST")
323  histoCR2.SetLineColor(ROOT.kRed)
324  histoCR2.SetMarkerColor(ROOT.kRed)
325  histoCR2.SetLineStyle(9)
326  histoCR2.Draw("sameHIST")
327  pu.CreateLegend(0.2, 0.7, 0.6, 0.8,18)
328 
329  pu.AddToLegend([histoCR1, histoCR2])
330 
331  variationDrawn = "Nominal"
332  if "STAT" in comp.name(): variationDrawn = "|Stat-Nominal|/Nominal"
333  elif "SYS" in comp.name(): variationDrawn = "|Sys-Nominal|/Nominal"
334  type_drawn = "Scale factor"
335  if comp.name().split("_")[1] == "DataEff": type_drawn = "data efficiency"
336  elif comp.name().split("_")[1] == "MCEff": type_drawn = "MC efficiency"
337  pu.DrawTLatex(0.55, 0.5, Options.bonuslabel)
338  pu.DrawTLatex(0.55, 0.85, "WP: %s, %s"%(comp.name().split("_")[0],variationDrawn))
339  pu.DrawTLatex(0.55, 0.9, type_drawn)
340 
341  pu.DrawAtlas(0.2, 0.9)
342  pu.DrawSqrtS(0.2, 0.85)
343 
344  pu.DrawLegend()
345  pu.saveHisto("%s/AppliedSFCheck_%s%s"%(Options.outDir, comp.name(),bonusname), ["pdf"])
346  pu.saveHisto("%s/AllAppliedSFCheckPlots%s" % (Options.outDir, bonusname), ["pdf"])
347 
348  dummy.SaveAs("%s/AllAppliedSFCheckPlots%s.pdf]" % (Options.outDir, bonusname))
349 
350  else:
351  print "INFO: Currently, only release comaparisons are implemented"
352 
CheckAppliedSFs.getSystematics
def getSystematics(tree, wp, calib_release)
Definition: CheckAppliedSFs.py:191
CheckAppliedSFs.ReleaseComparer.get_old_histo
def get_old_histo(self)
Definition: CheckAppliedSFs.py:67
PlotUtils.PlotUtils
Definition: PlotUtils.py:97
CheckAppliedSFs.ReleaseComparer.pass_cut
def pass_cut(self)
Definition: CheckAppliedSFs.py:61
PlotUtils.DiagnosticHisto
Definition: PlotUtils.py:18
CheckAppliedSFs.SystematicComparer.fill
def fill(self)
Definition: CheckAppliedSFs.py:129
CheckAppliedSFs.ReleaseComparer.get_old_var
def get_old_var(self)
Definition: CheckAppliedSFs.py:71
max
#define max(a, b)
Definition: cfImp.cxx:41
CheckAppliedSFs.ReleaseComparer.__new_weight
__new_weight
Definition: CheckAppliedSFs.py:22
CheckAppliedSFs.SystematicComparer.__init__
def __init__(self, var_name="", axis_title="", bins=-1, name_old_rel="", name_new_rel="", test_tree=None, branch_old="", branch_new="", weight_old=None, weight_new=None, branch_sys_old="", branch_sys_new="")
Definition: CheckAppliedSFs.py:92
CheckAppliedSFs.ReleaseComparer.__old_histo
__old_histo
Definition: CheckAppliedSFs.py:39
CheckAppliedSFs.ReleaseComparer.finalize
def finalize(self)
Definition: CheckAppliedSFs.py:81
CheckAppliedSFs.SystematicComparer
Definition: CheckAppliedSFs.py:91
CheckAppliedSFs.ReleaseComparer.__var_name
__var_name
Definition: CheckAppliedSFs.py:38
CheckAppliedSFs.ReleaseComparer.__quality_branch
__quality_branch
Definition: CheckAppliedSFs.py:28
CheckAppliedSFs.ReleaseComparer.get_new_weight
def get_new_weight(self)
Definition: CheckAppliedSFs.py:78
CheckAppliedSFs.ReleaseComparer.__new_histo
__new_histo
Definition: CheckAppliedSFs.py:44
CheckAppliedSFs.ReleaseComparer.__old_branch
__old_branch
Direct access to the branch which are going to be compared.
Definition: CheckAppliedSFs.py:13
CheckAppliedSFs.ReleaseComparer.name
def name(self)
Definition: CheckAppliedSFs.py:89
plotBeamSpotVxVal.range
range
Definition: plotBeamSpotVxVal.py:195
CheckAppliedSFs.ReleaseComparer.__init__
def __init__(self, var_name="", axis_title="", bins=-1, bmin=0., bmax=0., bin_width=-1, bdir=None, name_old_rel="", name_new_rel="", test_tree=None, branch_old="", branch_new="", weight_old=None, weight_new=None, log_binning=False)
Definition: CheckAppliedSFs.py:11
CheckAppliedSFs.ReleaseComparer.__min_quality
__min_quality
Definition: CheckAppliedSFs.py:32
CheckAppliedSFs.ReleaseComparer.fill
def fill(self)
Definition: CheckAppliedSFs.py:63
CheckAppliedSFs.SystematicComparer.__sys_new
__sys_new
Definition: CheckAppliedSFs.py:106
CheckAppliedSFs.ReleaseComparer.get_old_weight
def get_old_weight(self)
Definition: CheckAppliedSFs.py:75
CxxUtils::set
constexpr std::enable_if_t< is_bitmask_v< E >, E & > set(E &lhs, E rhs)
Convenience function to set bits in a class enum bitmask.
Definition: bitmask.h:232
min
#define min(a, b)
Definition: cfImp.cxx:40
CheckAppliedSFs.ReleaseComparer.__old_weight
__old_weight
Weights as a function of the muon kinematics.
Definition: CheckAppliedSFs.py:21
TCS::join
std::string join(const std::vector< std::string > &v, const char c=',')
Definition: Trigger/TrigT1/L1Topo/L1TopoCommon/Root/StringUtils.cxx:10
CheckAppliedSFs.ReleaseComparer.__new_branch
__new_branch
Definition: CheckAppliedSFs.py:14
CheckAppliedSFs.ReleaseComparer
Definition: CheckAppliedSFs.py:10
CheckAppliedSFs.SystematicComparer.__sys_old
__sys_old
Definition: CheckAppliedSFs.py:105
CheckAppliedSFs.ReleaseComparer.get_new_histo
def get_new_histo(self)
Definition: CheckAppliedSFs.py:69
CheckAppliedSFs.getArgParser
def getArgParser()
Definition: CheckAppliedSFs.py:159
confTool.parse_args
def parse_args()
Definition: confTool.py:35
pickleTool.object
object
Definition: pickleTool.py:30
CheckAppliedSFs.ReleaseComparer.get_new_var
def get_new_var(self)
Definition: CheckAppliedSFs.py:73
Trk::split
@ split
Definition: LayerMaterialProperties.h:38
CheckAppliedSFs.getCalibReleasesAndWP
def getCalibReleasesAndWP(tree)
Definition: CheckAppliedSFs.py:172
CheckAppliedSFs.ReleaseComparer.__max_quality
__max_quality
Definition: CheckAppliedSFs.py:33