10Validation plots for CDC dedx calibration.
17import matplotlib.pyplot
as plt
20from matplotlib.backends.backend_pdf
import PdfPages
23import process_wiregain
as pw
24import process_cosgain
as pc
25import process_onedcell
as oned
26import process_rungain
as rg
28from prompt
import ValidationSettings
31logging.basicConfig(level=logging.INFO)
32logger = logging.getLogger(__name__)
34settings = ValidationSettings(name=
"CDC dedx calibration",
38 "GT":
"data_prompt_rel08",
42def save_plot(filename):
43 """Saves the plot with tight layout."""
48def rungain_validation(path, suffix):
50 val_path = os.path.join(path,
"plots",
"run", f
"dedx_vs_run_{suffix}.txt")
51 df = pd.read_csv(val_path, sep=
" ", header=
None, names=[
"run",
"mean",
"mean_err",
"reso",
"reso_err"])
52 except FileNotFoundError:
53 logger.error(f
"File {val_path} not found!")
56 df[
'run'] = df[
'run'].astype(str)
58 pdf_path = os.path.join(
"plots",
"validation", f
"dedx_vs_run_{suffix}.pdf")
59 os.makedirs(os.path.dirname(pdf_path), exist_ok=
True)
61 with PdfPages(pdf_path)
as pdf:
62 fig, ax = plt.subplots(1, 2, figsize=(20, 6))
65 ymin = df[df[
'mean'] > 0][
'mean'].min()
66 ymax = df[
'mean'].max()
67 pc.hist(y_min=ymin-0.02, y_max=ymax+0.02, xlabel=
"Run range", ylabel=
"dE/dx mean", space=30, ax=ax[0])
68 ax[0].errorbar(df[
'run'], df[
'mean'], yerr=df[
'mean_err'], fmt=
'*', markersize=8, rasterized=
True, label=
'Bhabha mean')
69 ax[0].legend(fontsize=12)
70 ax[0].set_title(
'dE/dx Mean vs Run', fontsize=14)
73 ymin = df[df[
'reso'] > 0][
'reso'].min()
74 ymax = df[
'reso'].max()
75 pc.hist(y_min=ymin-0.01, y_max=ymax+0.01, xlabel=
"Run range", ylabel=
"dE/dx reso", space=30, ax=ax[1])
76 ax[1].errorbar(df[
'run'], df[
'reso'], yerr=df[
'reso_err'], fmt=
'*', markersize=8, rasterized=
True, label=
'Bhabha reso')
77 ax[1].legend(fontsize=12)
78 ax[1].set_title(
'dE/dx Resolution vs Run', fontsize=14)
80 fig.suptitle(
"dE/dx vs Run", fontsize=20)
85 print(f
"Saved combined PDF: {pdf_path}")
88def wiregain_validation(path, suffix):
89 pdf_path = os.path.join(
"plots",
"validation", f
"dedx_vs_wire_layer_{suffix}.pdf")
90 os.makedirs(os.path.dirname(pdf_path), exist_ok=
True)
92 with PdfPages(pdf_path)
as pdf:
93 fig, ax = plt.subplots(2, 2, figsize=(20, 12))
97 val_path_gwire = os.path.join(path,
"plots",
"wire", f
"dedx_mean_gwire_{suffix}.txt")
98 df_gwire = pd.read_csv(val_path_gwire, sep=
" ", header=
None, names=[
"wire",
"mean"])
99 val_path_bwire = os.path.join(path,
"plots",
"wire", f
"dedx_mean_badwire_{suffix}.txt")
100 df_bwire = pd.read_csv(val_path_bwire, sep=
" ", header=
None, names=[
"wire",
"mean"])
101 except FileNotFoundError:
102 print(f
"File not found: {val_path_gwire}")
105 ymin = df_gwire[
'mean'].min()
106 ymax = df_gwire[
'mean'].max()
108 pc.hist(y_min=ymin-0.05, y_max=ymax+0.05, xlabel=
"Wire", ylabel=
"dE/dx mean", space=1000, ax=ax[0, 0])
109 ax[0, 0].
plot(df_gwire[
'wire'], df_gwire[
'mean'],
'*', markersize=5, rasterized=
True)
110 ax[0, 0].set_title(
'dE/dx Mean vs good Wire', fontsize=14)
112 ymin = df_bwire[
'mean'].min()
113 ymax = df_bwire[
'mean'].max()
114 pc.hist(y_min=ymin-0.05, y_max=ymax+0.05, xlabel=
"Wire", ylabel=
"dE/dx mean", space=1000, ax=ax[1, 0])
115 ax[1, 0].
plot(df_bwire[
'wire'], df_bwire[
'mean'],
'*', markersize=5, rasterized=
True)
116 ax[1, 0].set_title(
'dE/dx Mean vs bad Wire', fontsize=14)
120 val_path_layer = os.path.join(path,
"plots",
"wire", f
"dedx_mean_layer_{suffix}.txt")
121 df_layer = pd.read_csv(val_path_layer, sep=
" ", header=
None, names=[
"layer",
"mean",
"gmean"])
122 except FileNotFoundError:
123 print(f
"File not found: {val_path_layer}")
126 ymin = df_layer[
'mean'].min()
127 ymax = df_layer[
'mean'].max()
129 pc.hist(x_min=0, x_max=56, y_min=ymin-0.05, y_max=ymax+0.05, xlabel=
"Layer", ylabel=
"dE/dx mean", space=3, ax=ax[0, 1])
130 ax[0, 1].
plot(df_layer[
'layer'], df_layer[
'mean'],
'*', markersize=10, rasterized=
True)
131 ax[0, 1].set_title(
'dE/dx Mean vs Layer', fontsize=14)
133 ymin = df_layer[
'gmean'].min()
134 ymax = df_layer[
'gmean'].max()
135 pc.hist(x_min=0, x_max=56, y_min=ymin-0.02, y_max=ymax+0.02, xlabel=
"Layer", ylabel=
"dE/dx mean", space=3, ax=ax[1, 1])
136 ax[1, 1].
plot(df_layer[
'layer'], df_layer[
'gmean'],
'*', markersize=10, rasterized=
True)
137 ax[1, 1].set_title(
'dE/dx Mean vs Layer (good wires)', fontsize=14)
139 fig.suptitle(
"dE/dx vs #wire", fontsize=20)
144 print(f
"Saved combined PDF: {pdf_path}")
147def cosgain_validation(path, suffix):
149 val_path_el = os.path.join(path,
"plots",
"costh", f
"dedx_vs_cos_electrons_{suffix}.txt")
150 val_path_po = os.path.join(path,
"plots",
"costh", f
"dedx_vs_cos_positrons_{suffix}.txt")
151 df_el = pd.read_csv(val_path_el, sep=
" ", header=
None, names=[
"cos",
"mean",
"mean_err",
"reso",
"reso_err"])
152 df_po = pd.read_csv(val_path_po, sep=
" ", header=
None, names=[
"cos",
"mean",
"mean_err",
"reso",
"reso_err"])
153 except FileNotFoundError:
154 logger.error(f
"Cosine data files not found in {path}/plots/costh/")
158 df_el = df_el.sort_values(by=
'cos').reset_index(drop=
True)
159 df_po = df_po.sort_values(by=
'cos').reset_index(drop=
True)
162 mean_avg = (df_el[
'mean'] + df_po[
'mean']) / 2
163 err_avg = err_avg = 0.5 * np.sqrt(df_el[
'mean_err']**2 + df_po[
'mean_err']**2)
164 df_sum = pd.DataFrame({
'cos': df_el[
'cos'],
'mean_sum': mean_avg,
'err_avg': err_avg})
166 pdf_path = os.path.join(
"plots",
"validation", f
"dedx_vs_cosine_{suffix}.pdf")
167 os.makedirs(os.path.dirname(pdf_path), exist_ok=
True)
169 with PdfPages(pdf_path)
as pdf:
170 fig, ax = plt.subplots(1, 2, figsize=(20, 6))
172 pc.hist(x_min=-1.0, x_max=1.0, y_min=0.96, y_max=1.03, xlabel=
r"cos#theta", ylabel=
"dE/dx mean", space=0.1, ax=ax[0])
176 yerr=df_el[
'mean_err'],
184 yerr=df_po[
'mean_err'],
189 ax[0].errorbar(df_sum[
'cos'], df_sum[
'mean_sum'], yerr=df_sum[
'err_avg'], fmt=
'*',
190 markersize=10, rasterized=
True, label=
r'avergae of e^{+} and e^{-}')
191 ax[0].legend(fontsize=17)
192 ax[0].set_title(
'dE/dx Mean vs cosine', fontsize=14)
195 pc.hist(x_min=-1.0, x_max=1.0, y_min=0.04, y_max=0.13, xlabel=
r"cos#theta", ylabel=
"dE/dx reso", space=0.1, ax=ax[1])
199 yerr=df_el[
'reso_err'],
207 yerr=df_po[
'reso_err'],
212 ax[1].legend(fontsize=17)
213 ax[1].set_title(
'dE/dx Resolution vs cosine', fontsize=14)
215 fig.suptitle(
r"dE/dx vs cos$\theta$", fontsize=20)
221def injection_validation(path, suffix):
223 val_path_ler = os.path.join(path,
"plots",
"injection", f
"dedx_vs_inj_ler_{suffix}.txt")
224 val_path_her = os.path.join(path,
"plots",
"injection", f
"dedx_vs_inj_her_{suffix}.txt")
225 df_ler = pd.read_csv(val_path_ler, sep=
" ", header=
None, names=[
"var",
"bin",
"mean",
"mean_err",
"reso",
"reso_err"])
226 df_her = pd.read_csv(val_path_her, sep=
" ", header=
None, names=[
"var",
"bin",
"mean",
"mean_err",
"reso",
"reso_err"])
227 except FileNotFoundError:
228 logger.error(f
"Injection data files not found in {path}/plots/injection/")
231 df_ler[
'bin'] = df_ler[
'bin'].astype(str)
233 pdf_path = os.path.join(
"plots",
"validation", f
"dedx_mean_inj_{suffix}.pdf")
234 os.makedirs(os.path.dirname(pdf_path), exist_ok=
True)
236 with PdfPages(pdf_path)
as pdf:
237 fig, ax = plt.subplots(1, 1, figsize=(20, 6))
239 ymin = df_ler[df_ler[
'mean'] > 0][
'mean'].min()
240 ymax = df_ler[
'mean'].max()
242 pc.hist(y_min=ymin-0.01, y_max=ymax+0.01, xlabel=
"injection time", ylabel=
"dE/dx mean", space=3, ax=ax)
243 ax.errorbar(df_ler[
'bin'], df_ler[
'mean'], yerr=df_ler[
'mean_err'], fmt=
'*', markersize=10, rasterized=
True, label=
'LER')
244 ax.errorbar(df_her[
'bin'], df_her[
'mean'], yerr=df_her[
'mean_err'], fmt=
'*', markersize=10, rasterized=
True, label=
'HER')
245 ax.legend(fontsize=19)
247 fig.suptitle(
"dE/dx vs Injection time", fontsize=20)
253def mom_validation(path, suffix):
257 "cos$\\theta > 0.0$",
258 "cos$\\theta < 0.0$",
259 "cos$\\theta \\leq -0.8$",
260 "cos$\\theta > -0.8$ and $\\cos\\theta \\leq -0.6$",
261 "cos$\\theta > -0.6$ and $\\cos\\theta \\leq -0.4$",
262 "cos$\\theta > -0.4$ and $\\cos\\theta \\leq -0.2$",
263 "cos$\\theta > -0.2$ and $\\cos\\theta \\leq 0$",
264 "cos$\\theta > 0$ and $\\cos\\theta \\leq 0.2$",
265 "cos$\\theta > 0.2$ and $\\cos\\theta \\leq 0.4$",
266 "cos$\\theta > 0.4$ and $\\cos\\theta \\leq 0.6$",
267 "cos$\\theta > 0.6$ and $\\cos\\theta \\leq 0.8$",
273 "low": os.path.join(
"plots",
"validation", f
"dedx_vs_mom_{suffix}.pdf"),
274 "high": os.path.join(
"plots",
"validation", f
"dedx_vs_mom_{suffix}_cosbins.pdf"),
276 os.makedirs(os.path.dirname(pdf_paths[
"low"]), exist_ok=
True)
278 with PdfPages(pdf_paths[
"low"])
as pdf_low, PdfPages(pdf_paths[
"high"])
as pdf_high:
281 val_path_el = os.path.join(path,
"plots",
"mom",
282 f
"dedx_vs_mom_{i}_elec_{suffix}.txt")
283 val_path_po = os.path.join(path,
"plots",
"mom",
284 f
"dedx_vs_mom_{i}_posi_{suffix}.txt")
286 df_el = pd.read_csv(val_path_el, sep=
" ", header=
None,
287 names=[
"mom",
"mean",
"mean_err",
"reso",
"reso_err"])
288 df_po = pd.read_csv(val_path_po, sep=
" ", header=
None,
289 names=[
"mom",
"mean",
"mean_err",
"reso",
"reso_err"])
290 except FileNotFoundError:
291 logger.error(f
"Missing momentum data for bin {i} (suffix={suffix})")
296 fig, ax = plt.subplots(2, 2, figsize=(20, 12))
298 ymin = df_el[df_el[
'mean'] > 0][
'mean'].min()
299 ymax = df_el[
'mean'].max()
302 {
"xlim": (-7, 7),
"ylim": (ymin-0.01, ymax+0.01),
303 "ylabel":
"dE/dx mean",
"df_col":
"mean",
"err_col":
"mean_err",
304 "title":
"dE/dx Mean vs momentum"},
305 {
"xlim": (-7, 7),
"ylim": (0.04, 0.1),
306 "ylabel":
"dE/dx reso",
"df_col":
"reso",
"err_col":
"reso_err",
307 "title":
"dE/dx resolution vs momentum"},
308 {
"xlim": (-3, 3),
"ylim": (ymin-0.01, ymax+0.01),
309 "ylabel":
"dE/dx mean",
"df_col":
"mean",
"err_col":
"mean_err",
310 "title":
"dE/dx Mean vs momentum (zoomed)"},
311 {
"xlim": (-3, 3),
"ylim": (0.04, 0.1),
312 "ylabel":
"dE/dx reso",
"df_col":
"reso",
"err_col":
"reso_err",
313 "title":
"dE/dx resolution vs momentum (zoomed)"},
316 for ax_i, panel
in zip(ax.flat, panels):
317 pc.hist(x_min=panel[
"xlim"][0], x_max=panel[
"xlim"][1],
318 y_min=panel[
"ylim"][0], y_max=panel[
"ylim"][1],
319 xlabel=
"Momentum", ylabel=panel[
"ylabel"],
322 ax_i.errorbar(df_el[
'mom'], df_el[panel[
"df_col"]],
323 yerr=df_el[panel[
"err_col"]],
324 fmt=
'*', markersize=10, rasterized=
True, label=
'electron')
325 ax_i.errorbar(df_po[
'mom'], df_po[panel[
"df_col"]],
326 yerr=df_po[panel[
"err_col"]],
327 fmt=
'*', markersize=10, rasterized=
True, label=
'positron')
328 ax_i.legend(fontsize=17)
329 ax_i.set_title(panel[
"title"], fontsize=14)
330 if i == 3
and panel[
"df_col"] ==
"reso":
331 ymin, ymax = ax_i.get_ylim()
332 ax_i.set_ylim(ymin, ymax * 1.5)
334 fig.suptitle(f
"dE/dx vs Momentum ({cos_labels[i]})", fontsize=20)
341 pdf_high.savefig(fig)
345def oneDcell_validation(path, suffix):
347 val_path_il = os.path.join(path,
"plots",
"oneD", f
"dedx_vs_1D_IL_{suffix}.txt")
348 val_path_ol = os.path.join(path,
"plots",
"oneD", f
"dedx_vs_1D_OL_{suffix}.txt")
349 df_il = pd.read_csv(val_path_il, sep=
" ", header=
None, names=[
"enta",
"mean"])
350 df_ol = pd.read_csv(val_path_ol, sep=
" ", header=
None, names=[
"enta",
"mean"])
351 except FileNotFoundError:
352 logger.error(f
"1D data files not found in {path}/plots/oneD/")
355 pdf_path = os.path.join(
"plots",
"validation", f
"dedx_vs_enta_{suffix}.pdf")
356 os.makedirs(os.path.dirname(pdf_path), exist_ok=
True)
357 with PdfPages(pdf_path)
as pdf:
358 fig, ax = plt.subplots(2, 2, figsize=(20, 12))
360 pc.hist(x_min=-1.5, x_max=1.5, y_min=0.9, y_max=1.07, xlabel=
r"entaRS", ylabel=
"dE/dx mean", space=0.3, ax=ax[0, 0])
361 ax[0, 0].
plot(df_il[
'enta'], df_il[
'mean'],
'-', markersize=10, rasterized=
True, label=
'IL')
362 ax[0, 0].legend(fontsize=17)
363 ax[0, 0].set_title(
'dE/dx Mean vs entaRS (IL)', fontsize=14)
365 pc.hist(x_min=-1.5, x_max=1.5, y_min=0.9, y_max=1.05, xlabel=
r"entaRS", ylabel=
"dE/dx mean", space=0.3, ax=ax[0, 1])
366 ax[0, 1].
plot(df_ol[
'enta'], df_ol[
'mean'],
'-', markersize=10, rasterized=
True, label=
'OL')
367 ax[0, 1].legend(fontsize=17)
368 ax[0, 1].set_title(
'dE/dx Mean vs entaRS (OL)', fontsize=14)
370 pc.hist(x_min=-0.2, x_max=0.2, y_min=0.9, y_max=1.07, xlabel=
r"entaRS", ylabel=
"dE/dx mean", space=0.02, ax=ax[1, 0])
371 ax[1, 0].
plot(df_il[
'enta'], df_il[
'mean'],
'-', markersize=10, rasterized=
True, label=
'IL')
372 ax[1, 0].legend(fontsize=17)
373 ax[1, 0].set_title(
'dE/dx Mean vs entaRS (IL) zoom', fontsize=14)
375 pc.hist(x_min=-0.2, x_max=0.2, y_min=0.9, y_max=1.05, xlabel=
r"entaRS", ylabel=
"dE/dx mean", space=0.02, ax=ax[1, 1])
376 ax[1, 1].
plot(df_ol[
'enta'], df_ol[
'mean'],
'-', markersize=10, rasterized=
True, label=
'OL')
377 ax[1, 1].legend(fontsize=17)
378 ax[1, 1].set_title(
'dE/dx Mean vs entaRS (OL) zoom', fontsize=14)
380 fig.suptitle(
"dE/dx vs entaRS", fontsize=20)
386def run_validation(job_path, input_data_path, requested_iov, expert_config, **kwargs):
388 Makes validation plots
389 :job_path: path to cdcdedx calibration output
390 :input_data_path: path to the input files
391 :requested_iov: required argument but not used
392 :expert_config: required argument
394 if not os.path.exists(
'plots/validation'):
395 os.makedirs(
'plots/validation')
397 if not os.path.exists(
'plots/constant'):
398 os.makedirs(
'plots/constant')
400 expert_config = json.loads(expert_config)
401 GT = expert_config[
"GT"]
403 logger.info(
"Starting validation...")
405 logger.info(
"Processing run gain payloads...")
406 gtpath = os.path.join(job_path,
'rungain2',
'outputdb')
407 rg.getRunGain(gtpath, GT)
409 logger.info(
"Processing coscorr payloads...")
410 ccpath = os.path.join(job_path,
'coscorr1',
'outputdb')
411 pc.process_cosgain(ccpath, GT)
413 logger.info(
"Processing wire gain payloads...")
414 wgpath = os.path.join(job_path,
'wiregain0',
'outputdb')
415 exp_run_dict = pw.process_wiregain(wgpath, GT)
417 logger.info(
"Processing 1D gain payloads...")
418 ccpath = os.path.join(job_path,
'onedcell0',
'outputdb')
419 oned.process_onedgain(ccpath, GT)
421 logger.info(
"Generating validation plots...")
422 val_path = os.path.join(job_path,
'validation0',
'0',
'algorithm_output')
424 for exp, run_list
in exp_run_dict.items():
426 logger.info(
"Processing rungain validation plots...")
427 suffix = f
'e{exp}_r{run}'
428 rungain_validation(val_path, suffix)
430 logger.info(
"Processing wire gain validation plots...")
431 wiregain_validation(val_path, suffix)
433 logger.info(
"Processing cosine correction validation plots...")
434 cosgain_validation(val_path, suffix)
436 logger.info(
"Processing injection time validation plots...")
437 injection_validation(val_path, suffix)
439 logger.info(
"Processing momentum validation plots...")
440 mom_validation(val_path, suffix)
442 logger.info(
"Processing 1D validation plots...")
443 oneDcell_validation(val_path, suffix)
445 source_path = os.path.join(job_path,
'validation0',
'0',
'algorithm_output',
'plots')
446 shutil.copy(source_path+f
"/costh/dedxpeaks_vs_cos_e{exp}_r{run}.pdf",
'plots/validation/')
448 shutil.copy(source_path+f
"/mom/dedxpeaks_vs_mom_e{exp}_r{run}.pdf",
'plots/validation/')
451if __name__ ==
"__main__":