Belle II Software development
process_wiregain.py
1
8
9"""Implements wirgain correction"""
10
11import pandas as pd
12import numpy as np
13import matplotlib.pyplot as plt
14import ROOT
15from ROOT.Belle2 import CDCDedxValidationAlgorithm
16import process_cosgain as cg
17from matplotlib.backends.backend_pdf import PdfPages
18ROOT.gROOT.SetBatch(True)
19
20
21def remove_nowg(df):
22 # Inner layers: index < 1280 and wiregain != 0
23 il = df.loc[(df.index < 1280) & (df['wiregain'] != 0)].copy()
24
25 # Outer layers: index >= 1280 and wiregain != 0
26 ol = df.loc[(df.index >= 1280) & (df['wiregain'] != 0)].copy()
27
28 return il, ol
29
30
31def sep_inout(df):
32 il = df[df.index < 8].copy()
33 ol = df[df.index >= 8].copy()
34 return il, ol
35
36
37def fetch_wiregain_pair(cal, exp, run, database_file, gt):
38 """
39 Fetch previous and new wiregain payloads once for a given exp/run.
40 """
41 prev_data = None
42 new_data = None
43
44 try:
45 cal.setGlobalTag(gt)
46 prev_data = cal.getwiregain(exp, run)
47 finally:
48 cal.setGlobalTag("")
49
50 try:
51 cal.setTestingPayload(database_file)
52 new_data = cal.getwiregain(exp, run)
53 finally:
54 cal.setTestingPayload("")
55
56 return prev_data, new_data
57
58
59def process_wiregain_pair(prev_data, new_data, exp, run):
60 """Process wiregain for a given exp-run pair."""
61
62 # Extract wiregain vectors
63 prev_wg = prev_data.wiregain if prev_data else []
64 new_wg = new_data.wiregain if new_data else []
65
66 # Skip empty payloads
67 if not prev_wg or not new_wg:
68 print(f"[WARNING] Empty wiregain data for exp={exp}, run={run}. Skipping.")
69 return None, None, None, None
70
71 # Convert to DataFrames
72 df_prev = pd.DataFrame([[x] for x in prev_wg], columns=['wiregain'])
73 df_new = pd.DataFrame([[x] for x in new_wg], columns=['wiregain'])
74
75 # Split into inner and outer layers
76 il_prev, ol_prev = remove_nowg(df_prev)
77 il_new, ol_new = remove_nowg(df_new)
78
79 return il_prev, ol_prev, il_new, ol_new
80
81
82def process_layermean(prev_data, new_data, exp, run):
83
84 # Also add layer mean plots
85 if prev_data is None or new_data is None:
86 print(f"[WARNING] Missing layermean data for exp={exp}, run={run}. Skipping.")
87 return pd.Series(dtype=float), pd.Series(dtype=float)
88
89 prev_layermean = list(prev_data.layermean) if hasattr(prev_data, "layermean") else []
90 new_layermean = list(new_data.layermean) if hasattr(new_data, "layermean") else []
91
92 if len(prev_layermean) == 0 or len(new_layermean) == 0:
93 print(f"[WARNING] Empty layermean data for exp={exp}, run={run}. Skipping.")
94 return pd.Series(dtype=float), pd.Series(dtype=float)
95
96 df_prev_lm = pd.DataFrame(prev_layermean, columns=["layergain"])
97 df_new_lm = pd.DataFrame(new_layermean, columns=["layergain"])
98 il_lm_prev, ol_lm_prev = sep_inout(df_prev_lm)
99 il_lm_new, ol_lm_new = sep_inout(df_new_lm)
100
101 return il_lm_prev, ol_lm_prev, il_lm_new, ol_lm_new
102
103
104def plot_wiregain_all(il_prev, ol_prev, il_new, ol_new, exp, run, pdf):
105 """Plot overlay, ratio and difference into a single PDF page."""
106
107 fig, ax = plt.subplots(2, 2, figsize=(20, 12))
108
109 # 1.raw wiregain plots
110 raw_panels = [
111 (ax[0, 0], il_prev, "wiregain", "Inner previous Wiregain", "o", "Inner (prev)", 0., 4, 100),
112 (ax[0, 1], ol_prev, "wiregain", "Outer previous Wiregain", "^", "Outer (prev)", 0., 3, 1000),
113 (ax[1, 0], il_new, "wiregain", "Inner new Wiregain", "s", "Inner (new)", 0., 4, 100),
114 (ax[1, 1], ol_new, "wiregain", "Outer new Wiregain", "D", "Outer (new)", 0., 3, 1000),
115 ]
116
117 for axi, df, col, title, marker, label, ymin, ymax, space in raw_panels:
118 axi.set_title(title)
119 cg.hist(ymin, ymax, xlabel="#wire", ylabel="wg constant", space=space, ax=axi)
120 axi.plot(df[col], marker, label=label, markersize=5, alpha=0.7)
121 axi.legend(fontsize=12)
122
123 fig.suptitle(f"WireGain Calibration - Experiment {exp}, Run {run}", fontsize=20)
124 plt.tight_layout()
125 pdf.savefig(fig)
126 plt.close(fig)
127
128 fig, ax = plt.subplots(2, 2, figsize=(20, 12))
129
130 # # 2. Ratio (top-right)
131 il_r = (il_new["wiregain"] / il_prev["wiregain"]).dropna()
132 ol_r = (ol_new["wiregain"] / ol_prev["wiregain"]).dropna()
133
134 ratio_panels = [
135 (ax[0, 0], il_r, "Inner Wiregain Ratio", 0.7, 1.5, 100, "Inner Layer"),
136 (ax[0, 1], ol_r, "Outer Wiregain Ratio", 0.7, 1.5, 1000, "Outer Layer"),
137 (ax[1, 0], il_r, "Inner Wiregain Ratio (zoom)", 0.92, 1.05, 100, "Inner Layer"),
138 (ax[1, 1], ol_r, "Outer Wiregain Ratio (zoom)", 0.92, 1.05, 1000, "Outer Layer"),
139 ]
140
141 for axi, series, title, ymin, ymax, space, label in ratio_panels:
142 axi.set_title(title)
143 cg.hist(ymin, ymax, xlabel="#wire", ylabel="wiregain ratio", space=space, ax=axi)
144 axi.plot(series, "*", rasterized=True, label=label)
145 axi.legend(fontsize=12)
146
147 plt.tight_layout()
148 pdf.savefig(fig)
149 plt.close(fig)
150
151 fig, ax = plt.subplots(1, 2, figsize=(20, 6))
152
153 # 5. Ratio Histogram (bottom -left)
154 # 5. Ratio Histogram (filled)
155 ax[0].set_title("Wiregain Ratio histo")
156 cg.hist(x_min=0.7, x_max=1.5, xlabel=r"$\Delta$ wiregains", ylabel="Normalized count", fs1=10, fs2=6, ax=ax[0])
157
158 scale1 = 1 / il_r.shape[0] if il_r.shape[0] > 0 else 1
159 scale2 = 1 / ol_r.shape[0] if ol_r.shape[0] > 0 else 1
160
161 ax[0].hist(il_r, bins=200, weights=np.ones_like(il_r) * scale1, histtype='stepfilled', alpha=0.5, label='Inner layer')
162
163 ax[0].hist(ol_r, bins=200, weights=np.ones_like(ol_r) * scale2, histtype='stepfilled', alpha=0.5, label='Outer Layer')
164
165 ax[0].legend(fontsize=12)
166
167 plt.tight_layout()
168 pdf.savefig(fig)
169 plt.close(fig)
170
171
172def plot_layergain(il_lm_prev, ol_lm_prev, il_lm_new, ol_lm_new, exp, run, pdf):
173 """Compact combined plot with color separation."""
174
175 fig, ax = plt.subplots(1, 2, figsize=(20, 6))
176
177 data = [
178 ("Inner prev", il_lm_prev, "blue", "o"),
179 ("Inner new", il_lm_new, "cyan", "o"),
180 ("Outer prev", ol_lm_prev, "red", "s"),
181 ("Outer new", ol_lm_new, "orange", "s"),
182 ]
183
184 # --- Overlay ---
185 cg.hist(0.5, 1.9, xlabel="#layer", ylabel="layer gain", fs1=10, fs2=6, space=2, ax=ax[0])
186 ax[0].set_title("Layer Mean")
187
188 for label, df, color, marker in data:
189 ax[0].plot(df["layergain"], marker, color=color, label=f"{label}")
190
191 ax[0].legend(fontsize=10)
192
193 # --- Ratio ---
194 cg.hist(0.9, 1.1, xlabel="#layer", ylabel="ratio", fs1=10, fs2=6, space=2, ax=ax[1])
195 ax[1].set_title("Layer Ratio")
196
197 ratios = [
198 ("Inner", il_lm_new, il_lm_prev, "blue", "o"),
199 ("Outer", ol_lm_new, ol_lm_prev, "red", "s"),
200 ]
201 for label, prev_df, new_df, color, marker in ratios:
202 ratio = (new_df["layergain"] / prev_df["layergain"]).dropna()
203 ax[1].plot(ratio, marker, color=color, label=f"{label}")
204
205 ax[1].legend(fontsize=10)
206
207 fig.suptitle(f"Exp {exp}, Run {run}", fontsize=16)
208
209 plt.tight_layout()
210 pdf.savefig(fig)
211 plt.close(fig)
212
213
214def process_wiregain(wgpath, gt):
215 """Main function to process wiregain data and generate plots."""
216 import os
217 os.makedirs('plots/constant', exist_ok=True)
218 database_file = f'{wgpath}/database.txt'
219
220 exp_run_dict = cg.parse_database(database_file, "dbstore/CDCDedxWireGain")
221
222 for exp, run_list in exp_run_dict.items():
223 for run in run_list:
224 print(f"[INFO] Processing exp={exp}, run={run}")
225 cal = CDCDedxValidationAlgorithm()
226 try:
227 prev_data, new_data = fetch_wiregain_pair(cal, exp, run, database_file, gt)
228 except Exception as e:
229 print(f"[ERROR] Failed to fetch wiregain for exp={exp}, run={run}: {e}")
230 continue
231
232 il_prev, ol_prev, il_new, ol_new = process_wiregain_pair(prev_data, new_data, exp, run)
233
234 if il_prev is None or ol_prev is None or il_new is None or ol_new is None:
235 continue
236
237 il_lm_prev, ol_lm_prev, il_lm_new, ol_lm_new = process_layermean(prev_data, new_data, exp, run)
238
239 pdf_path = f'plots/constant/wiregain_e{exp}_r{run}.pdf'
240 with PdfPages(pdf_path) as pdf:
241 plot_wiregain_all(il_prev, ol_prev, il_new, ol_new, exp, run, pdf)
242 plot_layergain(il_lm_prev, ol_lm_prev, il_lm_new, ol_lm_new, exp, run, pdf)
243
244 return exp_run_dict
Definition plot.py:1