ATLAS Offline Software
Loading...
Searching...
No Matches
python_tools.py
Go to the documentation of this file.
1#!/usr/bin/env python
2# Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3
4import subprocess
5import re
6import ROOT as R
7from subprocess import Popen, PIPE
8from array import array
9import pandas as pd
10import math
11import time
12
13narrowspace="#kern[-0.8]{ }"
14plotlabel = {}
15plotlabel["Zee"] = "Z"+narrowspace+"#rightarrow"+narrowspace+"ee"
16plotlabel["Zmumu"] = "Z"+narrowspace+"#rightarrow"+narrowspace+"#mu#mu"
17plotlabel["Zll"] = "Z"+narrowspace+"#rightarrow"+narrowspace+"ll"
18Leemumuratiolabel = "L_{"+plotlabel["Zee"]+"} / L_{"+plotlabel["Zmumu"]+"}"
19
20# global run livetime cut in seconds, for paper 40min, reduce to 10min for now
21runlivetimecut = 10*60 # in seconds
22# global lumiblock livetime cut in seconds, 9sec for now
23lblivetimecut = 9 # in seconds
24
25def get_grl(year, verbose=True):
26 '''
27 Get a list of runs for a year from the baseline GRL
28 '''
29 CVMFS = "/cvmfs/atlas.cern.ch/repo/sw/database/GroupData/GoodRunsLists"
30 grl = {}
31 grl["15"] = CVMFS + "/data15_13TeV/20190708/data15_13TeV.periodAllYear_DetStatus-v105-pro22-13_Unknown_PHYS_StandardGRL_All_Good_25ns.xml"
32 grl["16"] = CVMFS + "/data16_13TeV/20190708/data16_13TeV.periodAllYear_DetStatus-v105-pro22-13_Unknown_PHYS_StandardGRL_All_Good_25ns_WITH_IGNORES.xml"
33 grl["17"] = CVMFS + "/data17_13TeV/20190708/data17_13TeV.periodAllYear_DetStatus-v105-pro22-13_Unknown_PHYS_StandardGRL_All_Good_25ns_Triggerno17e33prim.xml"
34 grl["18"] = CVMFS + "/data18_13TeV/20190708/data18_13TeV.periodAllYear_DetStatus-v105-pro22-13_Unknown_PHYS_StandardGRL_All_Good_25ns_Triggerno17e33prim.xml"
35 grl["22"] = CVMFS + "/data22_13p6TeV/20230207/data22_13p6TeV.periodAllYear_DetStatus-v109-pro28-04_MERGED_PHYS_StandardGRL_All_Good_25ns.xml"
36 grl["23"] = CVMFS + "/data23_13p6TeV/20230828/data23_13p6TeV.periodAllYear_DetStatus-v110-pro31-06_MERGED_PHYS_StandardGRL_All_Good_25ns.xml"
37 grl["24"] = CVMFS + "/data24_13p6TeV/20241118/data24_13p6TeV.periodsEtoO_DetStatus-v130-pro36-08_MERGED_PHYS_StandardGRL_All_Good_25ns.xml"
38 grl["25"] = "/eos/atlas/atlascerngroupdisk/perf-lumi/Zcounting/Run3/MergedOutputs/data25_13p6TeV/latest_GRL.xml"
39
40 if year != "25":
41 pipe = Popen(["grep", "RunList", grl[year]], stdout=PIPE, stderr=PIPE)
42 runs = re.sub("[^0-9,]", "", str(pipe.communicate()[0])).split(",")
43
44 elif year == "25":
45 # preliminary GRL does not include "RunList" field, concatenate <Run> fields
46 runs=subprocess.check_output("grep '<Run>' "+grl[year]+" | tr -dc ' [:digit:] '", shell=True).decode('ascii').split()
47 if verbose:
48 print("20"+year+": list or runs =", runs)
49
50 return runs
51
53 R.gROOT.SetStyle("Plain")
54
55 # use plain black on white colors
56 icol = 0
57 R.gStyle.SetFrameBorderMode(icol)
58 R.gStyle.SetFrameFillColor(icol)
59 R.gStyle.SetCanvasBorderMode(icol)
60 R.gStyle.SetCanvasColor(icol)
61 R.gStyle.SetPadBorderMode(icol)
62 R.gStyle.SetPadColor(icol)
63 R.gStyle.SetStatColor(icol)
64
65 R.gStyle.SetLineColor(R.kBlack)
66
67 # set the paper & margin sizes
68 R.gStyle.SetPaperSize(20,26)
69
70 # set margin sizes
71 R.gStyle.SetPadTopMargin(0.05)
72 R.gStyle.SetPadRightMargin(0.05)
73 R.gStyle.SetPadBottomMargin(0.16)
74 R.gStyle.SetPadLeftMargin(0.16)
75
76 # set title offsets (for axis label)
77 R.gStyle.SetTitleXOffset(1.4)
78 R.gStyle.SetTitleYOffset(1.4)
79
80 # use large fonts
81 font=42 # Helvetica
82 tsize=0.05
83 R.gStyle.SetTextFont(font)
84 R.gStyle.SetTextSize(tsize)
85 R.gStyle.SetLegendFont(font)
86 R.gStyle.SetLabelFont(font,"xyz")
87 R.gStyle.SetTitleFont(font,"xyz")
88
89 R.gStyle.SetLabelSize(tsize,"xyz")
90 R.gStyle.SetTitleSize(tsize,"xyz")
91
92 # use bold lines and markers
93 R.gStyle.SetMarkerStyle(20)
94 R.gStyle.SetMarkerSize(1.2)
95 R.gStyle.SetLineStyleString(2,"[12 12]") # postscript dashes
96
97 R.gStyle.SetEndErrorSize(0.)
98
99 # do not display any of the standard histogram decorations
100 R.gStyle.SetOptTitle(0)
101 R.gStyle.SetOptStat(0)
102 R.gStyle.SetOptFit(0)
103
104 # put tick marks on top and RHS of plots
105 R.gStyle.SetPadTickX(1)
106 R.gStyle.SetPadTickY(1)
107 R.gROOT.ForceStyle()
108
109def drawAtlasLabel(x, y, text = "", color = R.kBlack):
110 l = R.TLatex()
111 l.SetNDC()
112 l.SetTextFont(72)
113 l.SetTextColor(color)
114
115 delx = 0.115*696*R.gPad.GetWh()/(472*R.gPad.GetWw())
116
117 l.DrawLatex(x,y,"ATLAS")
118 if len(text) > 0:
119 p = R.TLatex()
120 p.SetNDC()
121 p.SetTextFont(42)
122 p.SetTextColor(color)
123 p.DrawLatex(x+delx,y,text)
124
125def drawText(x, y, text, size=27, color = R.kBlack):
126 l = R.TLatex()
127 l.SetNDC()
128 if size > 0:
129 l.SetTextSize(size)
130 l.SetTextFont(43)
131 l.SetTextColor(color)
132 l.DrawLatex(x,y,text)
133
134def make_bands(vec_in, stdev, yval):
135 vec_y = array('d', [yval] * (len(vec_in) + 2))
136 vec_x = array('d', sorted(vec_in))
137 err_y = array('d', [stdev] * (len(vec_in) + 2))
138
139 vec_x.insert(0, 0)
140 vec_x.append(9999999999)
141
142 line = R.TGraphErrors(len(vec_x), vec_x, vec_y, R.nullptr, err_y)
143 line.SetFillColorAlpha(8, 0.35)
144 line.SetFillStyle(4050)
145
146 return line
147
148def get_year(run):
149 run=int(run)
150 if run >= 495667: return "25"
151 elif run >= 472553: return "24"
152 elif run >= 450227: return "23"
153 elif run >= 427394: return "22"
154 elif run >= 348885: return "18"
155 elif run >= 325713: return "17"
156 elif run >= 297730: return "16"
157 elif run >= 276262: return "15"
158 else:
159 print("ERROR: Cannot classify run", run)
160 exit(1)
161
162def get_yearsqrtstxt(run_number):
163 yearsqrtstxt = "Data 20" + get_year(run_number) + ",#kern[-0.5]{ }"
164 if run_number < 427394:
165 yearsqrtstxt += "#sqrt{s} = 13 TeV"
166 else:
167 yearsqrtstxt += "#sqrt{s} = 13.6 TeV"
168 return yearsqrtstxt
169
170def get_dfz(basedir, year, run, channel, standardcuts = True):
171 '''
172 Standard retrieval of Z counting Panda dataframe from CSV
173 '''
174 if year=="run3" or len(year.split("_")) > 1:
175 mydir = basedir + "data"+get_year(run)+"_13p6TeV/physics_Main/"
176 elif year=="run2":
177 mydir = basedir + "data"+get_year(run)+"_13TeV/physics_Main/"
178 elif int(year) >= 22:
179 mydir = basedir + "data" + year + "_13p6TeV/physics_Main/"
180 else:
181 mydir = basedir + "data" + year + "_13TeV/physics_Main/" # untested
182
183 try:
184 dfz = pd.read_csv(mydir + "run_" + run + ".csv")
185 except FileNotFoundError:
186 print("WARNING: CVS for run", run, "not found, will skip.")
187 return -1., 0., 0., 0., 0., None
188
189 dfz_small = dfz
190
191 if channel is not None:
192 # reading a specific channel and calculating some integrated quantities
193 dfz_small['ZLumi'] = dfz_small[channel + 'Lumi']
194 dfz_small['ZLumiErr'] = dfz_small[channel + 'LumiErr']
195 if standardcuts:
196 dfz_small = dfz_small.drop(dfz_small[dfz_small.ZLumi == 0].index)
197 dfz_small = dfz_small.drop(dfz_small[(dfz_small['LBLive']<lblivetimecut) | (dfz_small['PassGRL']==0)].index)
198
199 dfz_small['ZLumi'] *= dfz_small['LBLive']
200 dfz_small['ZLumiErr'] *= dfz_small['LBLive']
201 zlumi = dfz_small['ZLumi'].sum()
202
203 dfz_small['ZLumiErr'] *= dfz_small['ZLumiErr']
204 zerr = math.sqrt(dfz_small['ZLumiErr'].sum())
205 else:
206 # reading both Zee and Zll, some preparatory calculations, but nothing final
207 if standardcuts:
208 dfz_small = dfz_small.drop(dfz_small[(dfz_small.ZeeLumi == 0) | (dfz_small.ZmumuLumi == 0)].index)
209 dfz_small = dfz_small.drop(dfz_small[(dfz_small['LBLive']<lblivetimecut) | (dfz_small['PassGRL']==0)].index)
210 dfz_small['ZeeLumi'] *= dfz_small['LBLive']
211 dfz_small['ZeeLumiErr'] *= dfz_small['LBLive']
212 dfz_small['ZeeLumiErr'] *= dfz_small['ZeeLumiErr']
213 dfz_small['ZmumuLumi'] *= dfz_small['LBLive']
214 dfz_small['ZmumuLumiErr'] *= dfz_small['LBLive']
215 dfz_small['ZmumuLumiErr'] *= dfz_small['ZmumuLumiErr']
216 zlumi, zerr = 0., 0.
217
218 livetime = dfz_small['LBLive'].sum()
219
220 # Calculate integrated ATLAS luminosity
221 dfz_small['OffLumi'] *= dfz_small['LBLive']
222 olumi = dfz_small['OffLumi'].sum()
223
224 # Grab start of the run for plotting later on
225 try:
226 run_start = dfz_small['LBStart'].iloc[0]
227 timestamp = time.gmtime(run_start)
228 timestamp = R.TDatime(timestamp[0], timestamp[1], timestamp[2], timestamp[3], timestamp[4], timestamp[5])
229 timestamp = timestamp.Convert()
230 except IndexError:
231 timestamp = 0
232
233 return livetime, zlumi, zerr, olumi, timestamp, dfz_small
234
235
236def local_fit(tg, start, end, year):
237 """
238 Fit over a sub-range of the data and print the mean and chi^2/NDF.
239 Useful to test the remaining trends after the global Run-3 normalisation.
240 """
241
242 tg.Fit('pol0', 'Rq0','0', start, end)
243 mean = tg.GetFunction('pol0').GetParameter(0)
244 chi2 = tg.GetFunction('pol0').GetChisquare()
245 ndf = tg.GetFunction('pol0').GetNDF()
246 print("|", year, "|", round(mean,3), "|", round(chi2/ndf, 2), "|")
void print(char *figname, TCanvas *c1)
STL class.
std::vector< std::string > split(const std::string &s, const std::string &t=":")
Definition hcg.cxx:177
drawAtlasLabel(x, y, text="", color=R.kBlack)
make_bands(vec_in, stdev, yval)
drawText(x, y, text, size=27, color=R.kBlack)
local_fit(tg, start, end, year)
get_grl(year, verbose=True)
get_yearsqrtstxt(run_number)
get_dfz(basedir, year, run, channel, standardcuts=True)