5 Plot comparisons of Zee/Zmumu and Z/ATLAS over entire data-periods.
6 This can be done as a function of time (validated, working perfectly),
7 and pileup (not yet fully validated).
13 import python_tools
as pt
15 from array
import array
19 parser = argparse.ArgumentParser()
20 parser.add_argument(
'--year', type=str, help=
'15-18 or 22-23, Run3 for full Run-3')
21 parser.add_argument(
'--channel', type=str, help=
'Zee or Zmumu')
22 parser.add_argument(
'--comp', action=
'store_true', help=
'Compare Zee and Zmumu?')
23 parser.add_argument(
'--absolute', action=
'store_true', help=
'Compare absolute luminosity')
24 parser.add_argument(
'--indir', type=str, help=
'Input directory for CSV files')
25 parser.add_argument(
'--outdir', type=str, help=
'Output directory for plots')
26 parser.add_argument(
'--dir_2022', type=str, help=
'Input directory for 2022 data')
27 parser.add_argument(
'--dir_2023', type=str, help=
'Input directory for 2023 data')
29 args = parser.parse_args()
31 channel = args.channel
32 absolute = args.absolute
35 dir_2022 = args.dir_2022
36 dir_2023 = args.dir_2023
38 print(
"------------------------------------------")
39 print(
"Begin Yearwise Lumi vs Time")
40 print(
"------------------------------------------")
48 ymin, ymax = 1.01, 1.11
50 ymin, ymax = 0.95, 1.05
51 xtitle =
'Month / Year'
52 date_tag =
"Run 3, #sqrt{s} = 13.6 TeV"
54 if channel
is not None:
65 ymin, ymax = 0.94, 1.06
66 xtitle =
'Date in 20' + year
67 date_tag =
"Data 20" + year +
", #sqrt{s} = 13.6 TeV"
75 zstring =
"Z #rightarrow ee counting"
76 ytitle =
'L_{Z #rightarrow ee}/L_{ATLAS}'
78 leg_entry =
"L_{Z #rightarrow ee}"
80 leg_entry =
"L_{Z #rightarrow ee}^{"+norm_type+
"-normalised}/L_{ATLAS}"
81 elif channel ==
"Zmumu":
82 zstring =
"Z #rightarrow #mu#mu counting"
83 ytitle =
'L_{Z #rightarrow #mu#mu}/L_{ATLAS}'
85 leg_entry =
"L_{Z #rightarrow #mu#mu}"
87 leg_entry =
"L_{Z #rightarrow #mu#mu}^{"+norm_type+
"-normalised}/L_{ATLAS}"
88 elif channel ==
"Zll":
89 zstring =
"Z #rightarrow ll counting"
90 ytitle =
'L_{Z #rightarrow ll}/L_{ATLAS}'
92 leg_entry =
"L_{Z #rightarrow ll}"
94 leg_entry =
"L_{Z #rightarrow ll}^{"+norm_type+
"-normalised}/L_{ATLAS}"
104 print(
"------------------------------------------")
105 print(
"Begin Yearwise Lumi Channel Comparison vs Time")
106 print(
"------------------------------------------")
111 print(
"year = ", year)
112 grl = pt.get_grl(year)
115 maindir = args.indir + dir_2023
116 print(
"2023 grl = ", grl)
119 maindir = args.indir + dir_2022
120 print(
"2022 grl = ", grl)
123 grl = pt.get_grl(year)
124 print(
"other grl = ", grl)
126 for channel
in [
"Zee",
"Zmumu"]:
129 dfz = pd.read_csv(maindir +
"run_" + run +
".csv")
131 dfz_small[
'ZLumi'] = dfz_small[channel +
'Lumi']
132 dfz_small[
'ZLumiErr'] = dfz_small[channel +
'LumiErr']
133 dfz_small = dfz_small.drop(dfz_small[dfz_small.ZLumi == 0].index)
134 dfz_small = dfz_small.drop(dfz_small[(dfz_small[
'LBLive']<10) | (dfz_small[
'PassGRL']==0)].index)
136 if dfz_small[
'LBLive'].
sum()/60 < 40:
137 print(
"Skip Run", run,
"because of live time", dfz_small[
'LBLive'].
sum()/60,
"min")
140 dfz_small[
'ZLumi'] *= dfz_small[
'LBLive']
141 dfz_small[
'ZLumiErr'] *= dfz_small[
'LBLive']
143 zlumi = dfz_small[
'ZLumi'].
sum()
145 dfz_small[
'ZLumiErr'] *= dfz_small[
'ZLumiErr']
146 zerr = math.sqrt(dfz_small[
'ZLumiErr'].
sum())
149 run_start = dfz_small[
'LBStart'].iloc[0]
150 timestamp = time.gmtime(run_start)
151 timestamp = R.TDatime(timestamp[0], timestamp[1], timestamp[2], timestamp[3], timestamp[4], timestamp[5])
152 timestamp = timestamp.Convert()
153 dict_zlumi[channel, run] = (zlumi, zerr, timestamp)
155 vec_times =
array(
'd')
156 vec_ratio =
array(
'd')
157 vec_ratio_err =
array(
'd')
158 keys = [key[1]
for key
in dict_zlumi
if "Zee" in key]
163 ratio = dict_zlumi[
"Zee", key][0]/dict_zlumi[
"Zmumu", key][0]
164 error = ratio * math.sqrt(
pow(dict_zlumi[
"Zee", key][1]/dict_zlumi[
"Zee", key][0], 2) +
pow(dict_zlumi[
"Zmumu", key][1]/dict_zlumi[
"Zmumu", key][0], 2) )
165 date = dict_zlumi[
"Zee", key][2]
167 if ratio < ymin
or ratio > ymax:
168 print(
"Run", key,
"has ratio", ratio)
169 print(
"Outside of y-axis range")
171 vec_times.append(date)
172 vec_ratio.append(ratio)
173 vec_ratio_err.append(error)
175 print(
"Cannot do ratio for", key)
177 tg = R.TGraphErrors(len(vec_times), vec_times, vec_ratio, R.nullptr, vec_ratio_err)
178 leg = R.TLegend(0.645, 0.72, 0.805, 0.91)
181 if out_tag ==
"_run3":
182 c1 = R.TCanvas(
"c1",
"c1", 2000, 1000)
187 tg.GetYaxis().SetTitle(
'L_{Z #rightarrow ee} / L_{Z #rightarrow #mu#mu}')
189 tg.GetFunction(
'pol0').SetLineColor(R.kRed)
191 mean =
round(tg.GetFunction(
'pol0').GetParameter(0), 4)
194 stdev = np.percentile(abs(vec_ratio - np.median(vec_ratio)), 68)
195 line1 = pt.make_bands(vec_times, stdev, mean)
197 tg.GetFunction(
'pol0').Draw(
"same l")
203 leg.SetTextSize(0.045)
204 leg.AddEntry(tg,
"L_{Z #rightarrow ee}/L_{Z #rightarrow #mu#mu}",
"ep")
205 leg.AddEntry(tg.GetFunction(
"pol0"),
"Mean = " +
str(
round(mean, 3)),
"l")
206 leg.AddEntry(line1,
"68% band",
"f")
209 pt.drawAtlasLabel(xval, 0.86,
"Internal")
210 pt.drawText(xval, 0.80, date_tag, set_size)
212 new_trig_line = R.TLine(1683743066.0, 0.95, 1683743066.0, 1.05)
214 new_trig_line.SetLineColor(R.kBlue)
215 new_trig_line.SetLineWidth(3)
216 new_trig_line.SetLineStyle(2)
217 new_trig_line.Draw(
"same")
220 tg.GetYaxis().SetRangeUser(ymin, ymax)
221 tg.GetXaxis().SetTitle(xtitle)
222 tg.GetXaxis().SetTimeDisplay(2)
223 tg.GetXaxis().SetNdivisions(9,R.kFALSE)
224 tg.GetXaxis().SetTimeFormat(time_format)
225 tg.GetXaxis().SetTimeOffset(0,
"gmt")
227 if years == [
"22",
"23"]:
228 plot_title =
"Ratio of Electron and Muon channel Z-counting Luminosities across Run 3"
230 plot_title =
"Ratio of Electron and Muon channel Z-counting Luminosities across 20" + years[0]
232 tg.SetTitle(plot_title)
234 c1.SaveAs(outdir +
"channel_comp_data"+out_tag+
".pdf")
239 Plot normalised comparison of Z-counting luminosity to ATLAS luminosity.
240 This can be done as a function of time and pileup.
243 print(
"------------------------------------------")
244 print(
"Begin Yearwise ", channel,
" Lumi ATLAS comparison vs Time")
245 print(
"------------------------------------------")
254 print(
"year = ", year)
257 maindir = args.indir + dir_2023
258 grl = pt.get_grl(year)
259 print(
"2023 grl = ", grl)
262 maindir = args.indir + dir_2022
263 grl = pt.get_grl(year)
264 print(
"2022 grl = ", grl)
267 grl = pt.get_grl(year)
268 print(
"other grl = ", grl)
272 dfz = pd.read_csv(maindir +
"run_" + run +
".csv")
274 dfz_small[
'ZLumi'] = dfz_small[channel +
'Lumi']
275 dfz_small[
'ZLumiErr'] = dfz_small[channel +
'LumiErr']
276 dfz_small[
'LBLive'] = dfz_small[
'LBLive']
277 dfz_small = dfz_small.drop(dfz_small[dfz_small.ZLumi == 0].index)
278 dfz_small = dfz_small.drop(dfz_small[(dfz_small[
'LBLive']<10) | (dfz_small[
'PassGRL']==0)].index)
281 if dfz_small[
'LBLive'].
sum()/60 < 40:
282 print(
"Skip Run", run,
"because of live time", dfz_small[
'LBLive'].
sum()/60,
"min")
286 run_start = dfz_small[
'LBStart'].iloc[0]
287 timestamp = time.gmtime(run_start)
288 timestamp = R.TDatime(timestamp[0], timestamp[1], timestamp[2], timestamp[3], timestamp[4], timestamp[5])
289 timestamp = timestamp.Convert()
292 dfz_small[
'OffLumi'] *= dfz_small[
'LBLive']
293 olumi = dfz_small[
'OffLumi'].
sum()
296 dfz_small[
'ZLumi'] *= dfz_small[
'LBLive']
297 zlumi = dfz_small[
'ZLumi'].
sum()
300 dfz_small[
'ZLumiErr'] *= dfz_small[
'LBLive']
301 dfz_small[
'ZLumiErr'] *= dfz_small[
'ZLumiErr']
302 zerr = math.sqrt(dfz_small[
'ZLumiErr'].
sum())
305 arr_date.append(timestamp)
306 arr_olumi.append(olumi)
307 arr_zlumi.append(zlumi)
308 arr_zerr.append(zerr)
312 arr_date =
array(
'd', arr_date)
314 arr_olumi = np.array(arr_olumi)
315 arr_zlumi = np.array(arr_zlumi)
316 arr_zerr = np.array(arr_zerr)
317 total_zlumi = arr_zlumi.sum()/1000000
318 total_zlumi_string =
"Official Data Quality, " +
str(
round(total_zlumi, 2)) +
" fb^-1"
326 normalisation = np.sum(arr_zlumi) / np.sum(arr_olumi)
328 arr_zlumi /= normalisation
329 arr_zerr /= normalisation
332 arr_zlumi_ratio = arr_zlumi/arr_olumi
333 arr_zerr_ratio = arr_zerr/arr_olumi
337 tg = R.TGraphErrors(len(arr_date), arr_date,
array(
'd',arr_zlumi_ratio), R.nullptr,
array(
'd',arr_zerr_ratio))
340 plot_title =
"Ratio of absolute "+ zstring +
" Luminosity to ATLAS Luminosity across " + norm_type
342 plot_title =
"Ratio of normalised "+ zstring +
" Luminosity to ATLAS Luminosity across " + norm_type
343 tg.SetTitle(plot_title+
";"+xtitle+
";"+ytitle)
346 if out_tag ==
"_run3":
347 c1 = R.TCanvas(
"c1",
"c1", 2000, 1200)
350 c1 = R.TCanvas(
"c1",
"c1", 1000, 750)
354 tg.GetYaxis().SetRangeUser(ymin, ymax)
357 stdev = np.percentile(abs(arr_zlumi_ratio - np.median(arr_zlumi_ratio)), 68)
358 print(
"68% band =", stdev)
360 mean = tg.GetFunction(
'pol0').GetParameter(0)
361 print(
"const of pol0 fit", mean)
362 print(
"median", np.median(arr_zlumi_ratio))
363 print(
"mean", np.mean(arr_zlumi_ratio))
365 line1 = pt.make_bands(arr_date, stdev, mean)
369 leg = R.TLegend(0.55, 0.20, 0.69, 0.45)
371 leg.SetTextSize(0.045)
372 leg.AddEntry(tg, leg_entry,
"ep")
373 leg.AddEntry(line1,
"68% band",
"f")
377 pt.drawAtlasLabel(xval, yval-0.47,
"Internal")
378 pt.drawText(xval, yval-0.53, date_tag, set_size)
379 pt.drawText(xval, yval-0.59, zstring, set_size)
380 pt.drawText(xval, yval-0.65,
"OflLumi-Run3-003", set_size)
382 pt.drawAtlasLabel(xval, yval-0.47,
"Internal")
383 pt.drawText(xval, yval-0.53, date_tag, set_size)
384 pt.drawText(xval, yval-0.59, zstring, set_size)
385 pt.drawText(xval, yval-0.65,
"OflLumi-Run3-003", set_size)
386 pt.drawText(xval, yval-0.02, total_zlumi_string, set_size)
388 pt.drawText(xval-0.12, 0.95, plot_title, set_size)
390 tg.GetYaxis().SetRangeUser(ymin, ymax)
391 tg.GetXaxis().SetTimeDisplay(2)
392 tg.GetXaxis().SetLabelSize(0.04)
393 tg.GetYaxis().SetLabelSize(0.04)
394 tg.GetXaxis().SetNdivisions(9,R.kFALSE)
395 tg.GetXaxis().SetTimeFormat(time_format)
396 tg.GetXaxis().SetTimeOffset(0,
"gmt")
402 c1.SaveAs(outdir + channel +
"_counting_data"+out_tag+
"_abs.pdf")
403 outfile = R.TFile(outdir + channel +
"_counting_data"+out_tag+
"_abs.root",
"RECREATE")
405 c1.SaveAs(outdir + channel +
"_counting_data"+out_tag+
".pdf")
406 outfile = R.TFile(outdir + channel +
"_counting_data"+out_tag+
".root",
"RECREATE")
409 line1.SetName(
"Line")
415 Fit over a sub-range of the data and print the mean and chi^2/NDF.
416 Useful to test the remaining trends after the global Run-3 normalisation.
419 tg.Fit(
'pol0',
'Rq0',
'0', start, end)
420 mean =
round(tg.GetFunction(
'pol0').GetParameter(0), 3)
421 chi2 = tg.GetFunction(
'pol0').GetChisquare()
422 ndf = tg.GetFunction(
'pol0').GetNDF()
423 print(
"|", year,
"|", mean,
"|",
round(chi2/ndf, 3),
"|")
426 if __name__ ==
"__main__":
428 R.gROOT.SetBatch(R.kTRUE)