def lifetimes_in_TRange(kre: KrEvent, krnb: KrNBins, krb: KrBins, krr: KrRanges, TL) -> List[KrFit]: """ Plots lifetime fitted to a range of T values""" # Specify the range and number of bins in Z Znbins = krnb.Z Zrange = krr.Z kfs = [] for tlim in TL: # select data kre_t = select_in_TRange(kre, *tlim) z, e = kre_t.Z, kre_t.E x, y, yu = fitf.profileX(z, e, Znbins, Zrange) # Fit profile to an exponential seed = expo_seed(x, y) f = fitf.fit(fitf.expo, x, y, seed, sigma=yu) kf = KrFit(par=np.array(f.values), err=np.array(f.errors), chi2=chi2(f, x, y, yu)) #krf.print_fit(kf) kfs.append(kf) return kfs
def fit_lifetime(kB, kf, title="Lifetime Fit"): x = shift_to_bin_centers(kB.Z) y = kf.par yu = kf.err plt.errorbar(x, y, yu, np.diff(x)[0] / 2, fmt="kp", ms=7, lw=3) seed = expo_seed(x, y) f = fitf.fit(fitf.expo, x, y, seed, sigma=yu) plt.plot(x, f.fn(x), "r-", lw=4) print_fit(f) print('chi2 = {}'.format(chi2(f, x, y, yu)))
def lifetimes_in_XYRange(kre: KrEvent, krnb: KrNBins, krb: KrBins, krr: KrRanges, xyr: XYRanges, XL=[(-125, -75), (-125, -75), (75, 125), (75, 125)], YL=[(-125, -75), (75, 125), (75, 125), (-125, -75)], nx=2, ny=2, figsize=(8, 8)) -> KrFit: """ Plots lifetime fitted to a range of XY values""" # Specify the range and number of bins in Z Znbins = krnb.Z Zrange = krr.Z fig = plt.figure(figsize=figsize) # XL = [(-125, -75), (-125, -75), (75, 125),(75, 125)] # YL = [(-125, -75), (75, 125), (75, 125),(-125, -75)] KF = [] for i, pair in enumerate(zip(XL, YL)): xlim = pair[0] ylim = pair[1] print(f'xlim = {xlim}, ylim ={ylim}') # select data in region defined by xyr xyr = XYRanges(X=xlim, Y=ylim) kre_xy = select_in_XYRange(kre, xyr) z, e = kre_xy.Z, kre_xy.E ax = fig.add_subplot(nx, ny, i + 1) x, y, yu = fitf.profileX(z, e, Znbins, Zrange) plt.errorbar(x, y, yu, np.diff(x)[0] / 2, fmt="kp", ms=7, lw=3) # Fit profile to an exponential seed = expo_seed(x, y) f = fitf.fit(fitf.expo, x, y, seed, sigma=yu) # plot fitted value plt.plot(x, f.fn(x), "r-", lw=4) labels("", "Energy (pes)", "Lifetime fit") kf = KrFit(par=np.array(f.values), err=np.array(f.errors), chi2=chi2(f, x, y, yu)) KF.append(kf) return KF
def lifetime_in_XYRange(kre: KrEvent, krnb: KrNBins, krb: KrBins, krr: KrRanges, xyr: XYRanges) -> KrFit: """ Fits lifetime to a range of XY values""" # select data in region defined by xyr kre_xy = select_in_XYRange(kre, xyr) z, e = kre_xy.Z, kre_xy.E # Specify the range and number of bins in Z Znbins = krnb.Z Zrange = krr.Z # create a figure and plot 2D histogram and profile frame_data = plt.gcf().add_axes((.1, .3, .8, .6)) plt.hist2d(z, e, (krb.Z, krb.E)) x, y, yu = fitf.profileX(z, e, Znbins, Zrange) plt.errorbar(x, y, yu, np.diff(x)[0] / 2, fmt="kp", ms=7, lw=3) # Fit profile to an exponential seed = expo_seed(x, y) f = fitf.fit(fitf.expo, x, y, seed, sigma=yu) # plot fitted value plt.plot(x, f.fn(x), "r-", lw=4) # labels and ticks frame_data.set_xticklabels([]) labels("", "Energy (pes)", "Lifetime fit") # add a second frame lims = plt.xlim() frame_res = plt.gcf().add_axes((.1, .1, .8, .2)) # Plot (y - f(x)) / sigma(y) as a function of x plt.errorbar(x, (f.fn(x) - y) / yu, 1, np.diff(x)[0] / 2, fmt="p", c="k") plt.plot(lims, (0, 0), "g--") plt.xlim(*lims) plt.ylim(-5, +5) labels("Drift time (µs)", "Standarized residual") return KrFit(par=np.array(f.values), err=np.array(f.errors), chi2=chi2(f, x, y, yu))
def fit_lifetime_from_profile(kre: KrEvent, kR: KrRanges, kNB: KrNBins, kB: KrBins, kL: KrRanges, title="Lifetime Fit") -> KrFit: sel = in_range(kre.X, *kL.XY) & in_range(kre.Y, *kL.XY) z, e = kre.Z[sel], kre.E[sel] frame_data = plt.gcf().add_axes((.1, .35, .8, .6)) plt.hist2d(z, e, (kB.Z, kB.E)) x, y, yu = fitf.profileX(z, e, kNB.Z, kR.Z, kR.E) plt.errorbar(x, y, yu, np.diff(x)[0] / 2, fmt="kp", ms=7, lw=3) seed = expo_seed(x, y) f = fitf.fit(fitf.expo, x, y, seed, sigma=yu) plt.plot(x, f.fn(x), "r-", lw=4) frame_data.set_xticklabels([]) labels("", "Energy (pes)", title) lims = plt.xlim() frame_res = plt.gcf().add_axes((.1, .1, .8, .2)) plt.errorbar(x, (f.fn(x) - y) / yu, 1, np.diff(x)[0] / 2, fmt="p", c="k") plt.plot(lims, (0, 0), "g--") plt.xlim(*lims) plt.ylim(-5, +5) labels("Drift time (µs)", "Standarized residual") print_fit(f) print('chi2 = {}'.format(chi2(f, x, y, yu))) return KrFit(par=np.array(f.values[1]), err=np.array(f.errors[1]), chi2=np.array(chi2(f, x, y, yu)), valid=np.ones(1))
def fit_lifetime_slices(kre: KrEvent, krnb: KrNBins, krb: KrBins, krr: KrRanges, fit_var="E", min_entries=1e2) -> KrLTSlices: """ Slice the data in x and y, make the profile in z of E, fit it to a exponential and return the relevant values. """ xybins = krb.XY nbins_xy = np.size(xybins) - 1 nbins_z = krnb.Z nbins = nbins_xy, nbins_xy const = np.zeros(nbins) slope = np.zeros(nbins) constu = np.zeros(nbins) slopeu = np.zeros(nbins) chi2 = np.zeros(nbins) valid = np.zeros(nbins, dtype=bool) zrange = krr.Z for i in range(nbins_xy): sel_x = in_range(kre.X, *xybins[i:i + 2]) for j in range(nbins_xy): #print(f' bin =({i},{j}); index = {index}') sel_y = in_range(kre.Y, *xybins[j:j + 2]) sel = sel_x & sel_y entries = np.count_nonzero(sel) if entries < min_entries: #print(f'entries ={entries} not enough to fit bin (i,j) =({i},{j})') valid[i, j] = False continue try: z = kre.Z[sel] t = kre.E[sel] if fit_var == "Q": t = kre.Q[sel] x, y, yu = fitf.profileX(z, t, nbins_z, zrange) seed = expo_seed(x, y) f = fitf.fit(fitf.expo, x, y, seed, sigma=yu) re = np.abs(f.errors[1] / f.values[1]) #print(f' E +- Eu = {f.values[0]} +- {f.errors[0]}') #print(f' LT +- LTu = {-f.values[1]} +- {f.errors[1]}') #print(f' LTu/LT = {re} chi2 = {f.chi2}') const[i, j] = f.values[0] constu[i, j] = f.errors[0] slope[i, j] = -f.values[1] slopeu[i, j] = f.errors[1] chi2[i, j] = f.chi2 valid[i, j] = True if re > 0.5: # print(f'Relative error to large, re ={re} for bin (i,j) =({i},{j})') # print(f' LT +- LTu = {-f.values[1]} +- {f.errors[1]}') # print(f' LTu/LT = {re} chi2 = {f.chi2}') valid[i, j] = False except: print(f'fit failed for bin (i,j) =({i},{j})') pass return KrLTSlices(Es=Measurement(const, constu), LT=Measurement(slope, slopeu), chi2=chi2, valid=valid)
def fit_and_plot_slices_2d_expo( kre: KrEvent, krnb: KrNBins, krb: KrBins, krr: KrRanges, fit_var="E", min_entries=1e2, figsize=(12, 12)) -> KrLTSlices: """ Slice the data in x and y, make the profile in z of E, fit it to a exponential and return the relevant values. """ xybins = krb.XY nbins_xy = np.size(xybins) - 1 nbins_z = krnb.Z nbins = nbins_xy, nbins_xy const = np.zeros(nbins) slope = np.zeros(nbins) constu = np.zeros(nbins) slopeu = np.zeros(nbins) chi2 = np.zeros(nbins) valid = np.zeros(nbins, dtype=bool) zrange = krr.Z fig = plt.figure(figsize=figsize) # Creates a new figure k = 0 index = 0 for i in range(nbins_xy): sel_x = in_range(kre.X, *xybins[i:i + 2]) for j in range(nbins_xy): index += 1 #print(f' bin =({i},{j}); index = {index}') if k % 25 == 0: k = 0 fig = plt.figure(figsize=figsize) ax = fig.add_subplot(5, 5, k + 1) k += 1 sel_y = in_range(kre.Y, *xybins[j:j + 2]) sel = sel_x & sel_y entries = np.count_nonzero(sel) if entries < min_entries: print( f'entries ={entries} not enough to fit bin (i,j) =({i},{j})' ) valid[i, j] = False continue try: z = kre.Z[sel] t = kre.E[sel] if fit_var == "Q": t = kre.Q[sel] x, y, yu = fitf.profileX(z, t, nbins_z, zrange) ax.errorbar(x, y, yu, np.diff(x)[0] / 2, fmt="kp", ms=7, lw=3) seed = expo_seed(x, y) f = fitf.fit(fitf.expo, x, y, seed, sigma=yu) plt.plot(x, f.fn(x), "r-", lw=4) plt.grid(True) re = np.abs(f.errors[1] / f.values[1]) #print(f' E +- Eu = {f.values[0]} +- {f.errors[0]}') #print(f' LT +- LTu = {-f.values[1]} +- {f.errors[1]}') #print(f' LTu/LT = {re} chi2 = {f.chi2}') if re > 0.5: print( f'Relative error to large, re ={re} for bin (i,j) =({i},{j})' ) print(f' LT +- LTu = {-f.values[1]} +- {f.errors[1]}') print(f' LTu/LT = {re} chi2 = {f.chi2}') valid[i, j] = False const[i, j] = f.values[0] constu[i, j] = f.errors[0] slope[i, j] = -f.values[1] slopeu[i, j] = f.errors[1] chi2[i, j] = f.chi2 valid[i, j] = True except: print(f'fit failed for bin (i,j) =({i},{j})') pass plt.tight_layout() return KrLTSlices(Ez0=Measurement(const, constu), LT=Measurement(slope, slopeu), chi2=chi2, valid=valid)