5from pathlib
import Path
6from initialise
import load_pueoEvent_Dataset
8dirname =
"simplesim_lat885_lat88_lat87_snr5ish_200evt"
10if __name__ ==
"__main__":
12 from scipy.optimize
import minimize
13 import matplotlib.pyplot
as plt
16 from calibration
import generate_antenna_phase_center_pairs_with_placeholders, load_dataset_and_measure_time_delays
17 from calibration
import retrieve_relevant_antennas_from_all_pairs, compute_time_delay_residuals, objective_function, _plot_calibration_result
24 calibration.dirname = dirname
25 calibration.UPSAMPLE_FACTOR=50
29 j25: Path = os.environ.get(
"PUEO_UTIL_INSTALL_DIR") / Path(
"share/pueo/geometry/jun25/qrh.dat")
30 a25: Path = os.environ.get(
"PUEO_UTIL_INSTALL_DIR") / Path(
"share/pueo/geometry/aug25/qrh.dat")
31 offset_inSIM: Path = os.environ.get(
"PUEO_UTIL_INSTALL_DIR") / Path(
"share/pueo/geometry/jun25/phase_center_offset_MI.dat")
33 j25: Path = os.environ.get(
"PUEO_UTIL_INSTALL_DIR") / Path(
"share/pueo/geometry/jun25/lf_cal.dat")
34 a25: Path = os.environ.get(
"PUEO_UTIL_INSTALL_DIR") / Path(
"share/pueo/geometry/aug25/lf.dat")
35 offset_inSIM: Path = os.environ.get(
"PUEO_UTIL_INSTALL_DIR") / Path(
"share/pueo/geometry/jun25/phase_center_offset_LF.dat")
37 print(
"Ant type doesn't exist!")
39 nominal_pairs = generate_antenna_phase_center_pairs_with_placeholders(qrh_dot_dat=j25, offset_inSIM=offset_inSIM, ant_type=ant_type)
42 ds: ROOT.pueo.Dataset = load_pueoEvent_Dataset(pueo_mc_data=Path(f
"/users/PAS0654/yuchieh/pueo_2025/components/pueoAnalysisTools/SharedUtils/{dirname}/"), run_number=20)
44 Icefinalpath=f
'./{dirname}/'
48 pulser_directions_and_pairwise_time_delays = (
49 load_dataset_and_measure_time_delays(dataset=ds, phase_center_pairs=nominal_pairs, MC=
True, AntType=ant_type, IcefinalFileDir=Icefinalpath, corr_fcn=
'ZNCC')
52 corr = pulser_directions_and_pairwise_time_delays[
"max correlation"].to_numpy()
53 N_tot_pairs = len(corr)
54 print(
"N_tot_pairs=", N_tot_pairs)
56 pXX = np.percentile(corr, percentage)
57 print(f
"{percentage}th percentile =", pXX)
60 plt.figure(figsize=(8,5))
61 plt.hist(corr, bins=100)
62 plt.axvline(pXX, linestyle=
"--", linewidth=2, label=f
"{percentage}% = {pXX:.3f}")
63 plt.xlabel(
"max correlation")
67 os.makedirs(f
"plot/{dirname}", exist_ok=
True)
68 plt.savefig(f
"plot/{dirname}/max_correlation.png")
70 pulser_directions_and_pairwise_time_delays = pulser_directions_and_pairwise_time_delays.filter((pl.col(
"max correlation")> pXX) | (pl.col(
"max correlation")> 0.95))
71 pulser_directions_and_pairwise_time_delays = pulser_directions_and_pairwise_time_delays.filter(pl.col(
"measured time delays (ns)").is_between(-16, 16))
76 pulser_directions_and_pairwise_time_delays = pulser_directions_and_pairwise_time_delays.with_row_index(
"row_id")
80 N_pairs = pulser_directions_and_pairwise_time_delays.height
85 print(
"N pairs=", N_pairs)
88 retrieve_relevant_antennas_from_all_pairs(
89 phase_center_pairs=pulser_directions_and_pairwise_time_delays
92 print(
"relevant_antennas=", relevant_antennas)
93 axis_list_initial = [
"Rho",
"Phi",
"Z",
"CableDelay"]
94 plot_range=[0.1,0.1,10/180*3.1415926]
95 unit_scale=[100,100,180/3.1415926]
100 best_result_rho =
None
102 best_result_phi =
None
103 best_result_cabledelay =
None
107 result_cabledelay =
None
113 for trials
in range(50):
114 for index, axis_label
in enumerate(axis_list_initial):
119 x0_randomguess[axis_label] = relevant_antennas[axis_label].to_numpy().copy()
120 fixed_antenna[axis_label] = x0_randomguess[axis_label][0]
122 x0_randomguess[axis_label][1:] = x0_randomguess[axis_label][1:] + np.random.uniform(-0.1, 0.1, size=len(relevant_antennas)-1)
124 elif axis_label==
'Phi':
125 x0_randomguess[axis_label][1:] = x0_randomguess[axis_label][1:] + np.random.uniform(-0.05, 0.05, size=len(relevant_antennas)-1)
127 elif axis_label==
'Rho':
128 x0_randomguess[axis_label][1:] = x0_randomguess[axis_label][1:] + np.random.uniform(-0.1, 0.1, size=len(relevant_antennas)-1)
130 elif axis_label==
'CableDelay':
131 x0_randomguess[axis_label][1:] = x0_randomguess[axis_label][1:] + np.random.uniform(-0.05, 0.05, size=len(relevant_antennas)-1)
134 pulser_directions_and_pairwise_time_delays = (
135 pulser_directions_and_pairwise_time_delays
137 pl.col(f
"A1_{axis_label} (placeholder)")
138 .replace_strict(relevant_antennas[f
"{axis_label} (placeholder)"], x0_randomguess[axis_label])
139 .alias(f
"A1_{axis_label}"),
141 pl.col(f
"A2_{axis_label} (placeholder)")
142 .replace_strict(relevant_antennas[f
"{axis_label} (placeholder)"], x0_randomguess[axis_label])
143 .alias(f
"A2_{axis_label}")
147 x0_randomguess[axis_label] = (
148 relevant_antennas[axis_label].to_numpy()
153 axis_list.extend([[
"CableDelay"],[
"Rho"], [
"Phi"],[
"Z"]])
155 axis_list.extend([[
"CableDelay"], [
"Z"]])
156 axis_list.extend([[
"Rho"], [
"Phi"]])
159 fig1, ax1 = plt.subplots(figsize=(8, 5))
161 for index, axis_label
in enumerate(axis_list):
166 x0 = x0_randomguess[AXIS]
171 placeholder = relevant_antennas[f
"{AXIS} (placeholder)"][1:]
174 placeholder = relevant_antennas[f
"{AXIS} (placeholder)"][1:]
177 bounds = [(1.0, 2.5)] * (len(x0))
180 bounds = [(-3.14, 3.14)] * (len(x0))
182 bounds =[(-12, -4)] * (len(x0))
183 if AXIS==
'CableDelay':
184 bounds =[(-0.3, 0.3)] * (len(x0))
186 result = minimize(fun=objective_function,
189 pulser_directions_and_pairwise_time_delays, AXIS),
190 method=
'Nelder-Mead',
192 options={
'maxiter': 500000000})
194 print(
"result=",result.fun)
195 tmp_trace.append(result.fun)
198 pulser_directions_and_pairwise_time_delays = (
199 pulser_directions_and_pairwise_time_delays
201 pl.col(f
"A1_{AXIS} (placeholder)")
202 .replace_strict(placeholder, result.x, default=pl.col(f
"A1_{AXIS}"))
203 .alias(f
"A1_{AXIS}"),
205 pl.col(f
"A2_{AXIS} (placeholder)")
206 .replace_strict(placeholder, result.x, default = pl.col(f
"A1_{AXIS}"))
211 resultx = np.insert(result.x, 0, x0_randomguess[AXIS][0])
212 x0_randomguess[AXIS] = resultx
215 df_resid = compute_time_delay_residuals(
216 phase_center_guess=resultx,
217 phase_center_placeholders=relevant_antennas[f
"{AXIS} (placeholder)"],
218 pulser_directions_and_measured_time_delays=pulser_directions_and_pairwise_time_delays,
222 residuals = df_resid[
"residual (ns)"].to_numpy()
224 color = cmap(index / (len(axis_list) - 1))
if len(axis_list) > 1
else cmap(1.0)
225 ax1.hist(residuals, bins=80, alpha=0.3, label=f
'{index}:[{AXIS}]', color=color)
227 if (index==8
and RemoveOutlier==
True and RemoveOutlierTimes<1):
228 RemoveOutlierTimes=RemoveOutlierTimes+1
229 row_before = df_resid.height
231 resid_col =
"residual (ns)"
233 mu = df_resid.select(pl.col(resid_col).mean()).item()
234 sigma = df_resid.select(pl.col(resid_col).std()).item()
236 print(
"You're removing outlier over 3 sigma, mu=", mu,
"sigma=", sigma)
239 .filter((pl.col(resid_col) - mu).abs() <= 3 * sigma)
243 row_after = good_rows.height
245 print(
"Removing", row_before-row_after,
"rows")
246 pulser_directions_and_pairwise_time_delays = (
247 pulser_directions_and_pairwise_time_delays
248 .join(good_rows, on=
"row_id", how=
"inner")
264 elif AXIS ==
'CableDelay':
265 result_cabledelay = result
270 print(
"result.fun=", result.fun,
"result.success=", result.success)
271 if result.fun < best_value
and result.success:
272 best_trace = tmp_trace.copy()
273 best_value = result.fun
274 best_result_rho = result_rho
275 best_result_phi = result_phi
276 best_result_z = result_z
277 best_result_cabledelay = result_cabledelay
278 print(
"temp best_value=", best_value)
279 print(
"temp best result=", best_result_rho.x)
281 ax1.set_xlabel(
"measured - expected (ns)")
282 ax1.set_ylabel(
"Counts")
283 ax1.set_title(
"Residual time delays")
284 ax1.grid(
True, alpha=0.3)
287 fig1.savefig(f
"plot/{dirname}/{ant_type}step_timediff.png")
291 resultList = [best_result_rho, best_result_phi, best_result_z, best_result_cabledelay]
292 for i, AXIS
in enumerate([
"Rho",
"Phi",
"Z",
"CableDelay"]):
294 resultx_full_axis = np.insert(resultList[i].x, 0, fixed_antenna[AXIS])
295 print(f
"{AXIS} resultx_full_axis=", resultx_full_axis)
296 _plot_calibration_result(axis=AXIS, before=relevant_antennas, after=resultx_full_axis, anttype=ant_type)
298 print(
"best_value=", best_value)
300 print(
"best_trace=", best_trace)
301 plt.figure(figsize=(8,5))
302 step = len(best_trace)
304 plt.plot(np.arange(step), np.sqrt(np.asarray(best_trace))/N_pairs)
307 plt.xlabel(
"Minimization iteration")
308 plt.ylabel(
"Averging $\Delta$ T per pair (ns)")
309 print(f
"plot/{dirname}/{ant_type}best_trace.png")
310 plt.savefig(f
"plot/{dirname}/{ant_type}best_trace.png")