Belle II Software development
process_rungain.py
1
8
9"""Implements rungain correction"""
10
11import os
12import ROOT
13import pandas as pd
14import matplotlib.pyplot as plt
15import process_cosgain as cg
16from ROOT.Belle2 import CDCDedxValidationAlgorithm
17from matplotlib.backends.backend_pdf import PdfPages
18
19
20def compute_block_averages(values, nblocks):
21 block_size = max(1, len(values) // nblocks)
22 averages = []
23 for i in range(0, len(values), block_size):
24 block = values[i:i + block_size]
25 avg = sum(block) / len(block)
26 averages.extend([avg] * len(block))
27 return averages[:len(values)]
28
29
30def parse_database(database_file, calib_key):
31 """
32 Parses a calibration database file and returns:
33 {exp: [(run, rev), ...]}
34 """
35 exp_run_dict = {}
36
37 with open(database_file) as f:
38 for line in f:
39 if line.startswith(calib_key):
40 try:
41 parts = line.strip().split()
42 if len(parts) != 3:
43 continue
44 _, rev, iov_str = parts
45 exp, run = map(int, iov_str.split(',')[:2])
46
47 exp_run_dict.setdefault(exp, []).append((run, rev))
48 except Exception as e:
49 print(f"[WARNING] Skipping line: {line.strip()} | Error: {e}")
50 return exp_run_dict
51
52
53def getRunGain(gtpath, gt):
54 os.makedirs("plots/constant", exist_ok=True)
55 database_file = os.path.join(gtpath, "database.txt")
56 calib_key = "dbstore/CDCDedxRunGain"
57
58 exp_run_dict = parse_database(database_file, calib_key)
59 rows = []
60 prev = []
61
62 for exp, run_rev_list in exp_run_dict.items():
63 for run, rev in run_rev_list:
64 cal = CDCDedxValidationAlgorithm()
65 cal.setGlobalTag(gt)
66 prev_data = cal.getrungain(exp, run)
67 cal.setGlobalTag("")
68 if prev_data is not None:
69 prev.append({"exp": exp, "run": run, "gain": prev_data})
70
71 root_file = os.path.join(gtpath, f"dbstore_CDCDedxRunGain_rev_{rev}.root")
72 file = ROOT.TFile.Open(root_file, "READ")
73 if file and not file.IsZombie():
74 rgain = file.Get("CDCDedxRunGain")
75 if rgain:
76 gain = rgain.getRunGain()
77 rows.append({"exp": exp, "run": run, "gain": gain})
78 else:
79 print(f"[ERROR] Failed to open file or file is zombie: {root_file}")
80
81 # Create DataFrame
82 df_prev = pd.DataFrame(prev)
83 df = pd.DataFrame(rows)
84 if df.empty:
85 print("[WARNING] No data to process.")
86 return df
87
88 for exp, df_exp in df.groupby("exp"):
89 df_prev_exp = df_prev[df_prev["exp"] == exp]
90
91 gains = df_exp["gain"].tolist()
92 average = compute_block_averages(gains, nblocks=30)
93 df_exp["run"] = df_exp["run"].astype(str)
94
95 # Sort runs for matching
96 df_exp_sorted = df_exp.sort_values("run")
97 df_prev_exp_sorted = df_prev_exp.sort_values("run")
98
99 # Compute ratio (new/prev)
100 if len(df_prev_exp_sorted) == len(df_exp_sorted):
101 ratio = df_exp_sorted["gain"].values / df_prev_exp_sorted["gain"].values
102 else:
103 print(f"[WARNING] Exp {exp}: mismatch in number of runs, skipping ratio plot.")
104 ratio = None
105
106 sorted_gains = sorted(gains)
107 y_min, y_max = min(sorted_gains) - 0.04, max(sorted_gains) + 0.04
108 spacing = max(1, len(gains) // 10)
109
110 # Open PDF for this experiment
111 with PdfPages(f"plots/constant/rungain_exp{exp}.pdf") as pdf:
112 fig, ax = plt.subplots(1, 2, figsize=(20, 6))
113
114 # Left plot: RunGain constants
115 cg.hist(y_min=y_min, y_max=y_max, xlabel="Run", ylabel="RunGain constant", space=spacing, ax=ax[0])
116 ax[0].plot(df_exp["run"], df_exp["gain"], '*', rasterized=True, label=f"exp{exp}")
117 ax[0].plot(df_exp["run"], average, '-', rasterized=True, label="Block Avg (30 blocks)")
118 ax[0].legend(fontsize=12)
119
120 # Right plot: Ratio (if available)
121 if ratio is not None:
122 cg.hist(0.99, 1.01, xlabel="Run", ylabel="Gain Ratio (new/prev)", space=spacing, ax=ax[1])
123 ax[1].plot(df_exp_sorted["run"], ratio, '*', rasterized=True, label="New / Prev")
124 ax[1].axhline(1.0, color='gray', linestyle='--')
125 ax[1].legend(fontsize=12)
126 else:
127 ax[1].text(0.5, 0.5, "Ratio unavailable", ha="center", va="center", fontsize=15)
128 ax[1].set_axis_off()
129
130 fig.suptitle(f"RunGain Calibration - Experiment {exp}", fontsize=20)
131 plt.tight_layout()
132 pdf.savefig(fig)
133 plt.close()
134
135 return df
STL class.
Definition plot.py:1