5from pathlib
import Path
6from initialise
import load_pueoEvent_Dataset
8dirname =
"simplesim_lat885_lat88_lat87_snr5ish_200evt"
11if __name__ ==
"__main__":
13 from scipy.optimize
import minimize
14 import matplotlib.pyplot
as plt
17 from calibration
import generate_antenna_phase_center_pairs_with_placeholders, load_dataset_and_measure_time_delays
18 from calibration
import retrieve_relevant_antennas_from_all_pairs, compute_time_delay_residuals, objective_function, _plot_calibration_result
25 calibration.dirname = dirname
26 calibration.UPSAMPLE_FACTOR=50
30 j25: Path = os.environ.get(
"PUEO_UTIL_INSTALL_DIR") / Path(
"share/pueo/geometry/jun25/qrh.dat")
31 a25: Path = os.environ.get(
"PUEO_UTIL_INSTALL_DIR") / Path(
"share/pueo/geometry/aug25/qrh.dat")
32 offset_inSIM: Path = os.environ.get(
"PUEO_UTIL_INSTALL_DIR") / Path(
"share/pueo/geometry/jun25/phase_center_offset_MI.dat")
34 j25: Path = os.environ.get(
"PUEO_UTIL_INSTALL_DIR") / Path(
"share/pueo/geometry/jun25/lf_cal.dat")
35 a25: Path = os.environ.get(
"PUEO_UTIL_INSTALL_DIR") / Path(
"share/pueo/geometry/aug25/lf.dat")
36 offset_inSIM: Path = os.environ.get(
"PUEO_UTIL_INSTALL_DIR") / Path(
"share/pueo/geometry/jun25/phase_center_offset_LF.dat")
38 print(
"Ant type doesn't exist!")
40 nominal_pairs = generate_antenna_phase_center_pairs_with_placeholders(qrh_dot_dat=j25, offset_inSIM=offset_inSIM, ant_type=ant_type)
43 ds: ROOT.pueo.Dataset = load_pueoEvent_Dataset(pueo_mc_data=Path(f
"/users/PAS0654/yuchieh/pueo_2025/components/pueoAnalysisTools/SharedUtils/{dirname}/"), run_number=20)
45 Icefinalpath=f
'./{dirname}/'
49 pulser_directions_and_pairwise_time_delays = (
50 load_dataset_and_measure_time_delays(dataset=ds, phase_center_pairs=nominal_pairs, MC=
True, AntType=ant_type, IcefinalFileDir=Icefinalpath, corr_fcn=
'ZNCC')
53 corr = pulser_directions_and_pairwise_time_delays[
"max correlation"].to_numpy()
54 N_tot_pairs = len(corr)
55 print(
"N_tot_pairs=", N_tot_pairs)
57 pXX = np.percentile(corr, percentage)
58 print(f
"{percentage}th percentile =", pXX)
61 plt.figure(figsize=(8,5))
62 plt.hist(corr, bins=100)
63 plt.axvline(pXX, linestyle=
"--", linewidth=2, label=f
"{percentage}% = {pXX:.3f}")
64 plt.xlabel(
"max correlation")
68 os.makedirs(f
"plot/{dirname}", exist_ok=
True)
69 plt.savefig(f
"plot/{dirname}/max_correlation.png")
71 pulser_directions_and_pairwise_time_delays = pulser_directions_and_pairwise_time_delays.filter((pl.col(
"max correlation")> pXX) | (pl.col(
"max correlation")> 0.95))
72 pulser_directions_and_pairwise_time_delays = pulser_directions_and_pairwise_time_delays.filter(pl.col(
"measured time delays (ns)").is_between(-16, 16))
77 pulser_directions_and_pairwise_time_delays = pulser_directions_and_pairwise_time_delays.with_row_index(
"row_id")
81 N_pairs = pulser_directions_and_pairwise_time_delays.height
86 print(
"N pairs=", N_pairs)
89 retrieve_relevant_antennas_from_all_pairs(
90 phase_center_pairs=pulser_directions_and_pairwise_time_delays
93 print(
"relevant_antennas=", relevant_antennas)
94 axis_list_initial = [
"Rho",
"Phi",
"Z",
"CableDelay"]
95 plot_range=[0.1,0.1,10/180*3.1415926]
96 unit_scale=[100,100,180/3.1415926]
101 best_result_rho =
None
103 best_result_phi =
None
104 best_result_cabledelay =
None
108 result_cabledelay =
None
114 for trials
in range(150):
115 for index, axis_label
in enumerate(axis_list_initial):
120 x0_randomguess[axis_label] = relevant_antennas[axis_label].to_numpy().copy()
121 fixed_antenna[axis_label] = x0_randomguess[axis_label][0]
123 x0_randomguess[axis_label][1:] = x0_randomguess[axis_label][1:] + np.random.uniform(-0.1, 0.1, size=len(relevant_antennas)-1)
125 elif axis_label==
'Phi':
126 x0_randomguess[axis_label][1:] = x0_randomguess[axis_label][1:] + np.random.uniform(-0.05, 0.05, size=len(relevant_antennas)-1)
128 elif axis_label==
'Rho':
129 x0_randomguess[axis_label][1:] = x0_randomguess[axis_label][1:] + np.random.uniform(-0.1, 0.1, size=len(relevant_antennas)-1)
131 elif axis_label==
'CableDelay':
132 x0_randomguess[axis_label][1:] = x0_randomguess[axis_label][1:] + np.random.uniform(-0.066, 0.066, size=len(relevant_antennas)-1)
135 pulser_directions_and_pairwise_time_delays = (
136 pulser_directions_and_pairwise_time_delays
138 pl.col(f
"A1_{axis_label} (placeholder)")
139 .replace_strict(relevant_antennas[f
"{axis_label} (placeholder)"], x0_randomguess[axis_label])
140 .alias(f
"A1_{axis_label}"),
142 pl.col(f
"A2_{axis_label} (placeholder)")
143 .replace_strict(relevant_antennas[f
"{axis_label} (placeholder)"], x0_randomguess[axis_label])
144 .alias(f
"A2_{axis_label}")
148 x0_randomguess[axis_label] = (
149 relevant_antennas[axis_label].to_numpy()
154 axis_list.extend([[
"CableDelay"],[
"Rho"], [
"Phi"],[
"Z"]])
156 axis_list.extend([[
"CableDelay"], [
"Z"]])
157 axis_list.extend([[
"Rho"], [
"Phi"]])
160 fig1, ax1 = plt.subplots(figsize=(8, 5))
162 for index, axis_label
in enumerate(axis_list):
167 x0 = x0_randomguess[AXIS]
172 placeholder = relevant_antennas[f
"{AXIS} (placeholder)"][1:]
175 placeholder = relevant_antennas[f
"{AXIS} (placeholder)"][1:]
178 bounds = [(1.0, 2.5)] * (len(x0))
181 bounds = [(-3.14, 3.14)] * (len(x0))
183 bounds =[(-12, -4)] * (len(x0))
184 if AXIS==
'CableDelay':
185 bounds =[(-0.1, 0.1)] * (len(x0))
187 result = minimize(fun=objective_function,
190 pulser_directions_and_pairwise_time_delays, AXIS),
191 method=
'Nelder-Mead',
193 options={
'maxiter': 500000000})
195 print(
"result=",result.fun)
196 tmp_trace.append(result.fun)
199 pulser_directions_and_pairwise_time_delays = (
200 pulser_directions_and_pairwise_time_delays
202 pl.col(f
"A1_{AXIS} (placeholder)")
203 .replace_strict(placeholder, result.x, default=pl.col(f
"A1_{AXIS}"))
204 .alias(f
"A1_{AXIS}"),
206 pl.col(f
"A2_{AXIS} (placeholder)")
207 .replace_strict(placeholder, result.x, default = pl.col(f
"A1_{AXIS}"))
212 resultx = np.insert(result.x, 0, x0_randomguess[AXIS][0])
213 x0_randomguess[AXIS] = resultx
216 df_resid = compute_time_delay_residuals(
217 phase_center_guess=resultx,
218 phase_center_placeholders=relevant_antennas[f
"{AXIS} (placeholder)"],
219 pulser_directions_and_measured_time_delays=pulser_directions_and_pairwise_time_delays,
223 residuals = df_resid[
"residual (ns)"].to_numpy()
225 color = cmap(index / (len(axis_list) - 1))
if len(axis_list) > 1
else cmap(1.0)
226 ax1.hist(residuals, bins=80, alpha=0.3, label=f
'{index}:[{AXIS}]', color=color)
228 if (index>=8
and RemoveOutlier==
True and RemoveOutlierTimes<5):
229 RemoveOutlierTimes=RemoveOutlierTimes+1
230 row_before = df_resid.height
232 resid_col =
"residual (ns)"
234 mu = df_resid.select(pl.col(resid_col).mean()).item()
235 sigma = df_resid.select(pl.col(resid_col).std()).item()
237 print(
"You're removing outlier over 3 sigma, mu=", mu,
"sigma=", sigma)
240 .filter((pl.col(resid_col) - mu).abs() <= 3 * sigma)
244 row_after = good_rows.height
246 print(
"Removing", row_before-row_after,
"rows")
247 pulser_directions_and_pairwise_time_delays = (
248 pulser_directions_and_pairwise_time_delays
249 .join(good_rows, on=
"row_id", how=
"inner")
265 elif AXIS ==
'CableDelay':
266 result_cabledelay = result
271 print(
"result.fun=", result.fun,
"result.success=", result.success)
272 if result.fun < best_value
and result.success:
273 best_trace = tmp_trace.copy()
274 best_value = result.fun
275 best_result_rho = result_rho
276 best_result_phi = result_phi
277 best_result_z = result_z
278 best_result_cabledelay = result_cabledelay
279 print(
"temp best_value=", best_value)
280 print(
"temp best result=", best_result_rho.x)
282 ax1.set_xlabel(
"measured - expected (ns)")
283 ax1.set_ylabel(
"Counts")
284 ax1.set_title(
"Residual time delays")
285 ax1.grid(
True, alpha=0.3)
288 fig1.savefig(f
"plot/{dirname}/{ant_type}step_timediff.png")
292 resultList = [best_result_rho, best_result_phi, best_result_z, best_result_cabledelay]
293 for i, AXIS
in enumerate([
"Rho",
"Phi",
"Z",
"CableDelay"]):
295 resultx_full_axis = np.insert(resultList[i].x, 0, fixed_antenna[AXIS])
296 print(f
"{AXIS} resultx_full_axis=", resultx_full_axis)
297 _plot_calibration_result(axis=AXIS, before=relevant_antennas, after=resultx_full_axis, anttype=ant_type)
299 print(
"best_value=", best_value)
301 print(
"best_trace=", best_trace)
302 plt.figure(figsize=(8,5))
303 step = len(best_trace)
305 plt.plot(np.arange(step), np.sqrt(np.asarray(best_trace))/N_pairs)
308 plt.xlabel(
"Minimization iteration")
309 plt.ylabel(
"Averging $\Delta$ T per pair (ns)")
310 print(f
"plot/{dirname}/{ant_type}best_trace.png")
311 plt.savefig(f
"plot/{dirname}/{ant_type}best_trace.png")