Esempio n. 1
0
def gaussian_fit(x: np.array, y: np.array, seed: GaussPar,
                 n_sigma: int) -> Tuple[FitPar, FitResult]:
    """Gaussian fit to x,y variables, with fit range defined by n_sigma"""

    mu = seed.mu.value
    std = seed.std.value
    amp = seed.amp.value
    fit_range = mu - n_sigma * std, mu + n_sigma * std

    x, y = x[in_range(x, *fit_range)], y[in_range(x, *fit_range)]
    yu = poisson_sigma(y)
    fseed = (amp, mu, std)

    par, err = par_and_err_from_seed(seed)
    fr = FitResult(par=par, err=err, chi2=NN, valid=False)
    fp = None

    with warnings.catch_warnings():
        warnings.filterwarnings(
            'error')  # in order to handle fit failures here
        try:
            fp, fr = gfit(x, y, yu, fseed)
        except RuntimeWarning:  # this is the most usual failure, and usually solved trying fitx
            # with a different seed
            print(
                f' fit failed for seed  = {seed}, due to RunTimeWarning, retry fit '
            )
            fseed = (10 * fseed[0], fseed[1], fseed[2])
            try:
                fp, fr = gfit(x, y, yu, fseed)
            except RuntimeWarning:  #  Give up on second failure
                print(
                    f' fit failed for seed  = {seed}, due to RunTimeWarning, give up '
                )
        except OptimizeWarning:
            print(
                f' OptimizeWarning was raised for seed  = {seed} due to OptimizeWarning'
            )
        except RuntimeError:
            print(f' fit failed for seed  = {seed}  due to RunTimeError')
        except TypeError:
            print(f' fit failed for seed  = {seed}  due to TypeError')

    return fp, fr
Esempio n. 2
0
def fit_slices_1d_gauss(xdata,
                        ydata,
                        xbins,
                        ybins,
                        min_entries=1e2,
                        ignore_errors=_FIT_EXCEPTIONS):
    """
    Slice the data in x, histogram each slice, fit it to a gaussian
    and return the relevant values.

    Parameters
    ----------
    xdata, ydata: array_likes
        Values of each coordinate.
    xbins: array_like
        The bins in the x coordinate.
    ybins: array_like
        The bins in the y coordinate for histograming the data.
    min_entries: int (optional)
        Minimum amount of entries to perform the fit.

    Returns
    -------
    mean: Measurement(np.ndarray, np.ndarray)
        Values of mean with errors.
    sigma: Measurement(np.ndarray, np.ndarray)
        Values of sigma with errors.
    chi2: np.ndarray
        Chi2 from each fit.
    valid: boolean np.ndarray
        Where the fit has been succesfull.
    """
    nbins = np.size(xbins) - 1
    mean = np.zeros(nbins)
    sigma = np.zeros(nbins)
    meanu = np.zeros(nbins)
    sigmau = np.zeros(nbins)
    chi2 = np.zeros(nbins)
    valid = np.zeros(nbins, dtype=bool)

    for i in range(nbins):
        sel = in_range(xdata, *xbins[i:i + 2])
        if np.count_nonzero(sel) < min_entries: continue

        try:
            f = quick_gauss_fit(ydata[sel], ybins)
            mean[i] = f.values[1]
            meanu[i] = f.errors[1]
            sigma[i] = f.values[2]
            sigmau[i] = f.errors[2]
            chi2[i] = f.chi2
            valid[i] = True
        except Exception as exc:
            if not isinstance(exc, ignore_errors):
                raise
    return Measurement(mean, meanu), Measurement(sigma, sigmau), chi2, valid
Esempio n. 3
0
def lt_vs_t(z, v, t, znbins, zrange, vnbins, vrange, tnbins, trange):
    """ returns the profile-fit to the lifetime in slices of time
    """
    tbins = np.linspace(*trange, tnbins + 1)
    fs = []
    for i in range(tnbins):
        sel = in_range(t, tbins[i], tbins[i + 1])
        fi = lt(z[sel], v[sel], znbins, zrange, vnbins, vrange, plot=False)
        fs.append(fi)
    return fs
def lifetime_calculation(z, zrange, energy, erange, elim, slope, axes):
    """
    Measure the lifetime for the given events and plots the raw energy distribution and the energy vs drift time in a separate axes instance.

    Parameters:
    z = Array of events' drift time
    zrange = Range in drift time for the fit.
    energy = Array of events' energy.
    erange = Range in energy for plotting.
    elim = Limits for the energy at z=0.
    slope = slope of the exponential, used in the selection of the events, should be the inverse of the expected lifetime (1/[expected lifetime])
    axes = Axes object from a subplot, should have length >= 2.
    """

    axes[0].hist(energy, 50, erange, rasterized=True)
    histFun.labels("S2 energy (pes)", "Entries",
                   "Fiducialized energy spectrum")

    low_cut = elim[0] * np.exp(-slope * z)
    high_cut = elim[1] * np.exp(-slope * z)
    sel = coref.in_range(energy, low_cut,
                         high_cut)  # remove low and high E background

    axes[1].hist2d(z,
                   energy, (100, 50),
                   range=(zrange, erange),
                   rasterized=True)
    x, y, u_y = fitf.profileX(z[sel],
                              energy[sel],
                              100,
                              xrange=zrange,
                              yrange=erange)

    axes[1].plot(x, y, "--k", rasterized=True)
    axes[1].plot(z[z < 500], low_cut[z < 500], "k.", rasterized=True)
    axes[1].plot(z[z < 500], high_cut[z < 500], "k.", rasterized=True)

    Zrange_LT = zrange

    seed = np.max(y), (x[15] - x[5]) / np.log(y[15] / y[5])
    f = fitf.fit(fitf.expo, x, y, seed, fit_range=Zrange_LT, sigma=u_y)

    axes[1].plot(x, f.fn(x), "r", lw=3, rasterized=True)
    print("Energy at z=0 = {:.1f} +- {:.1f}".format(f.values[0], f.errors[0]))
    print("Lifetime      = {:.1f} +- {:.1f}".format(-f.values[1], f.errors[1]))
    print("Chi2          = {:.2f}          \n".format(f.chi2))

    #    axes[1].text(zrange[0] + 0.05*(zrange[1]-zrange[0]), erange[0] + 1000, \
    #        "Lifetime = {:.1f} $\pm$ {:.1f}".format(-f.values[1], f.errors[1]), color = "white")#, fontsize = 14)

    histFun.labels("Drift time ($\mu$s)", "S2 energy (pes)", "")

    return np.array([-f.values[1], f.errors[1]
                     ]), corrf.LifetimeCorrection(-f.values[1], f.errors[1])
Esempio n. 5
0
def drift_velocity(plots_dir, dst, label=''):
    """
    Input Z distribution
    Return value for the drift velocity
    """
    # To do: make plotting of drift velocities as for energy resolution

    Z = dst[in_range(dst.Z, 305, 350)].Z
    fit_z_range = (305, 350)

    fig = plt.figure(figsize=(12, 4))
    ax = fig.add_subplot(1, 2, 1)
    (_) = hist(dst.DT,
               bins=100,
               range=(0, 400),
               histtype='stepfilled',
               color='crimson')
    labels('Drit time ($\mu$s)', 'Entries')
    plt.legend(loc='upper right')

    ax = fig.add_subplot(1, 2, 2)
    (_) = hist(Z,
               bins=100,
               range=fit_z_range,
               histtype='stepfilled',
               color='crimson')
    labels('Drit time ($\mu$s)', 'Entries')
    plt.legend(loc='upper right')
    plt.show()

    sigmoid = lambda x, A, B, C, D: A / (1 + np.exp((x - B) / C)) + D
    mypdf = Extended(sigmoid)
    #describe(mypdf)
    chi2 = BinnedChi2(mypdf, Z, bins=100,
                      bound=fit_z_range)  #create cost function

    plt.figure(figsize=(7, 5))
    chi2.show(args={
        'A': 1400,
        'B': 330,
        'C': 1.1,
        'D': 43,
        'N': 1
    })  #another way to draw it

    m = Minuit(chi2, A=800, B=330, C=1.3, D=100, N=1)
    m.migrad()
    my_parmloc = (0.60, 0.90)
    #chi2.draw(m, parmloc=my_parmloc)
    plt.figure(figsize=(7, 5))
    chi2.show(m, parmloc=my_parmloc)

    plt.savefig(f'{plots_dir}/fit_energy_reso_{label}.png')
    print('plots saved in ' + plots_dir)
Esempio n. 6
0
def fbi_conf(fbisp, xnum=0, xmol='FBI'):
    if xmol == 'FBI':
        lr = fbisp.lrfbi
    else:
        lr = fbisp.lrfbi_ba
    df_1 = fbisp.fbidf[in_range(fbisp.fbidf.II, *lr[xnum])]
    df1 = pd_find_location(df_1, xmol, df_1[xmol].max())
    fabm = fbisp.abs_maxima
    assert df1["II"] == fabm[f'max{xnum+1}_{xmol.lower()}'].loc[0]
    assert df1["FBI_Ba"] == fabm[f'max{xnum+1}_{xmol.lower()}'].loc[1]
    assert df1["FBI"] == fabm[f'max{xnum+1}_{xmol.lower()}'].loc[2]
Esempio n. 7
0
def select_in_TRange(kre: KrEvent, tmin: float, tmax: float) -> KrEvent:
    """ Selects a KrEvent in  a range of T values"""

    sel = in_range(kre.T, tmin, tmax)

    return KrEvent(X=kre.X[sel],
                   Y=kre.Y[sel],
                   Z=kre.Z[sel],
                   E=kre.E[sel],
                   S1=kre.S1[sel],
                   T=kre.T[sel],
                   Q=kre.Q[sel])
Esempio n. 8
0
def get_sensor_response(sns_response : pd.DataFrame,
                        detector     : Detector,
                        sns_type     : str
                       ) -> pd.DataFrame:
    """
    Returns a data frame with the charge and time of each sensor
    of the provided sensor type.
    """
    assert sns_type in detector.get_sensor_types(), f"{sns_type} not present in {detector.name}"

    sns_range = detector.get_sensor_ids(sns_type)
    return sns_response[in_range(sns_response.index.get_level_values("sensor_id"),
                        sns_range[0], sns_range[1])].sort_index()
Esempio n. 9
0
def s1s2_selection(dst, fout, dst_out_dir, run, rmax, save=False):
    """
    Input one file with a dst dataframe and run number
    Returns dst and writes to disk a reduced dst with events that pass
    the 1s1 and 1s2 selection criteria
    """

    dst_s1   = dst     [in_range(dst.nS1,    1,2)]
    dst_s2   = dst_s1  [in_range(dst_s1.nS2, 1,2)]


    tot_ev  = dst.   event.nunique()
    s1_ev   = dst_s1.event.nunique()
    s1s2_ev = dst_s2.event.nunique()

    eff_s1      = s1_ev   / tot_ev
    eff_s2      = s1s2_ev / tot_ev
    eff_s1s2    = s1s2_ev / s1_ev

    fout.write(f'ev_1s1 {s1_ev }\n')
    fout.write(f'ev_1s1s2 {s1s2_ev }\n')

    fout.write(f'eff_1s1_check {eff_s1*100:.5f}\n')
    fout.write(f'eff_1s1_u_check {error_eff(tot_ev, s1_ev/tot_ev)*100:.5f}\n')

    fout.write(f'eff_1s1s2 {eff_s2*100:.5f}\n')
    fout.write(f'eff_1s1s2_u {error_eff(tot_ev, s1s2_ev/tot_ev)*100:.5f}\n')

    fout.write(f'rel_eff_1s2_from_1s1  {eff_s1s2*100:.5f}\n')
    fout.write(f'rel_eff_1s2_from_1s1_u {error_eff(s1_ev, s1s2_ev/s1_ev)*100:.5f}\n')


    if save:
        dir_file_name = f'{dst_out_dir}/reduced_{run}_kdst_{rmax}.h5'
        save_dst_to_file(dst_s2, dir_file_name)
        print(f'Save reduced kdst with 1s1 and 1s2 in: {dir_file_name}')

    return dst_s2
Esempio n. 10
0
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))
Esempio n. 11
0
def ltmap_vs_t_lsqfit(X, Y, Z, E, T, XYbins, Tbins, min_entries=20):
    """ returns the LT-maps and Geo-maps in time T intervals using the unbinned fit
    """
    fs = []
    for i in range(len(Tbins) - 1):
        sel = in_range(T, Tbins[i], Tbins[i + 1])
        fi = ltmap_lsqfit(X[sel],
                          Y[sel],
                          Z[sel],
                          E[sel],
                          XYbins,
                          min_entries=min_entries)
        fs.append(fi)
    return fs
Esempio n. 12
0
def plt_var_xymap_wslice(V, X, Y, W, Vnbins, Vrange, XYnbins, XYrange, Wnbins, Wrange, label = ''):
    """ plot the XY map of a variable V in slices of second W variable. Vrange fix the range of the xymap
    """
    vmin, vmax = Vrange
    c = hst.Canvas(Vnbins/2, Vnbins/2)
    zzs = np.linspace(Wrange[0], Wrange[1], Wnbins+1)
    for ii in range(len(zzs)-1):
        sel = in_range(W, zzs[ii], zzs[ii+1])
        x, y, z, uz = fitf.profileXY(X[sel], Y[sel], V[sel], XYnbins, XYnbins,
                                     xrange=XYrange, yrange=XYrange)
        hst.display_matrix(x, y, z, cmap = default_cmap, canvas=c(ii+1), vmin = vmin, vmax=vmax,
                           xylabels=('x (mm)', 'y (mm)', label+ ' in ['+str(zzs[ii])+', '+str(zzs[ii+1])+']') );
        plt.tight_layout()
    return c
Esempio n. 13
0
def energy_in_XYRange(kre: KrEvent, xr: Tuple[float], yr: Tuple[float],
                      ernb: ExyzNBins) -> KrFit:

    sel = in_range(kre.X, *xr) & in_range(kre.Y, *yr)
    e = kre.E[sel]
    bins = ernb.E
    frame_data = plt.gcf().add_axes((.1, .3, .8, .6))

    y, b, _ = plt.hist(e,
                       bins=bins,
                       histtype='step',
                       edgecolor='black',
                       linewidth=1.5)
    x = shift_to_bin_centers(b)

    seed = gauss_seed(x, y)
    fit_range = seed[1] - 2.0 * seed[2], seed[1] + 2.0 * seed[2]
    x, y = x[in_range(x, *fit_range)], y[in_range(x, *fit_range)]
    f = fitf.fit(fitf.gauss, x, y, seed, sigma=poisson_sigma(y))

    yu = poisson_sigma(y)
    plt.plot(x, f.fn(x), "r-", lw=4)

    frame_data.set_xticklabels([])
    labels("", "Entries", "Energy fit example")
    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)

    kf = KrFit(par=np.array(f.values),
               err=np.array(f.errors),
               chi2=chi2(f, x, y, yu))
    return kf
Esempio n. 14
0
    def fbi_abs_spectrum(self):
        """Compute the absorption spectrum and related variables"""

        self.fbidf    = \
        pd.read_excel(f"{os.environ['SABATDATA']}/EDI_029_absorption.xlsx")

        # normalise to the value of the cross section in l_peak
        if self.norm:
            s = pd_find_location(self.fbidf, "II", self.l_peak)
            sfbi_ba_au = s['FBI_Ba']
            sfbi_au = s['FBI']
            self.sfbi_ba_nm = self.s_fbi_ba / sfbi_ba_au
            self.sfbi_nm = self.s_fbi / sfbi_au
        else:
            self.sfbi_ba_nm = 1
            self.sfbi_nm = 1

        # Define Sector data frames according to lrfbi and lrfbi_ba
        # These are portions of the spectrum that contained a single maximum
        fbiS = [
            self.fbidf[in_range(self.fbidf.II, *self.lrfbi[i])]
            for i in range(4)
        ]
        fbibaS = [
            self.fbidf[in_range(self.fbidf.II, *self.lrfbi_ba[i])]
            for i in range(4)
        ]

        # Store a DF with W, FBI, FBI_Ba data for each sector
        self.max_fbi = [
            pd_find_location(fbi, 'FBI', fbi['FBI'].max()) for fbi in fbiS
        ]

        self.max_fbi_ba = [
            pd_find_location(fbi, 'FBI_Ba', fbi['FBI_Ba'].max())
            for fbi in fbibaS
        ]
Esempio n. 15
0
def quality_cut(dst: pd.DataFrame, r_max: float) -> pd.DataFrame:
    """
    Does basic quality cut : R inside the r_max
    Parameters
    ----------
    dst : pd.DataFrame
        Input dst to obtain the mask from.
    r_max: float
        Upper limit for R.
    Returns
    ----------
    mask : pd.DataFrame
        Mask for filtering events not matching the criteria
    """
    mask = in_range(dst.R, 0, r_max)
    return mask
Esempio n. 16
0
def get_time_series(time_bins: Number, time_range: Tuple[float, float],
                    kre: KrEvent) -> Tuple[np.array, List[np.array]]:
    """

    Returns a time series (ts) and a list of masks which are used to divide
    the event in time tranches.

        Parameters
        ----------
            time_bins
                Number of time bines.
            time_range
                Time range.
            kre
                A kr_event (a subset of dst).

        Returns
        -------
            A Tuple with:
            np.array       : This is the ts vector
            List[np.array] : This are the list of masks defining the events in the time series.

    """

    logging.debug(f'function: get_time_series')
    nt = time_bins
    x = int((time_range[-1] - time_range[0]) / nt)
    tfirst = int(time_range[0])
    tlast = int(time_range[-1])
    if x == 1:
        indx = [(tfirst, tlast)]
    else:
        indx = [(i, i + x) for i in range(tfirst, int(tlast - x), x)]
        indx.append((x * (nt - 1), tlast))

    ts = [(indx[i][0] + indx[i][1]) / 2 for i in range(len(indx))]

    logging.debug(
        f' number of time bins = {nt}, t_first = {tfirst} t_last = {tlast}')
    logging.debug(f'indx = {indx}')
    logging.debug(f'ts = {ts}')

    masks = [
        in_range(kre.DT, indx[i][0], indx[i][1]) for i in range(len(indx))
    ]

    return np.array(ts), masks
Esempio n. 17
0
def xymap_vprofile_zslice(V, X, Y, Z, Zbins, XYnbins, XYrange, std=True):
    vs, vus, voks = [], [], []
    for ii in range(len(Zbins) - 1):
        sel_ii = in_range(Z, Zbins[ii], Zbins[ii + 1])
        x, y, z, uz = fitf.profileXY(X[sel_ii],
                                     Y[sel_ii],
                                     V[sel_ii],
                                     XYnbins,
                                     XYnbins,
                                     xrange=XYrange,
                                     yrange=XYrange,
                                     std=std)
        ok = z > 0
        vs.append(z)
        vus.append(uz)
        voks.append(ok)
    return vs, vus, voks
Esempio n. 18
0
def plt_entries_xymap_wslice(X, Y, W, XYnbins, XYrange, Wnbins, Wrange, Crange, vname = ''):
    """ plot the number of entries in a XY map in slices of W variable,
    Crange fix the range of events of the xymap
    """
    wmin, wmax = Wrange
    c = hst.Canvas(Wnbins/2, Wnbins/2)
    zzs = np.linspace(wmin, wmax, Wnbins+1)
    for ii in range(len(zzs)-1):
        sel = in_range(W, zzs[ii], zzs[ii+1])
        hst.hist2d(X[sel], Y[sel], (XYnbins, XYnbins), (XYrange, XYrange),
                    cmap = cmap_default, canvas = c(ii+1),
                    xylabels = ('x (mm)', 'y (mm)',
                               'evts '+vname+' in ['+str(zzs[ii])+', '+str(zzs[ii+1])+']') );
        plt.colorbar().set_label("Number of events")
        plt.clim(*Crange)
        plt.tight_layout()
    return c
Esempio n. 19
0
def profile_and_fit(X, Y, xrange, yrange, nbins, fitpar, label):
    fitOpt = "r"
    xe = (xrange[1] - xrange[0]) / nbins

    x, y, sy = fitf.profileX(X,
                             Y,
                             nbins=nbins,
                             xrange=xrange,
                             yrange=yrange,
                             drop_nan=True)
    sel = in_range(x, xrange[0], xrange[1])
    x, y, sy = x[sel], y[sel], sy[sel]
    f = fitf.fit(fitf.expo, x, y, fitpar, sigma=sy)

    plt.errorbar(x=x, xerr=xe, y=y, yerr=sy, linestyle='none', marker='.')
    plt.plot(x, f.fn(x), fitOpt)
    #set_plot_labels(xlabel=label[0], ylabel=label[1], grid=True)
    return f, x, y, sy
Esempio n. 20
0
def find_outliers(maps: ASectorMap, x2range: Tuple[float, float] = (0, 2)):
    """
    For a given maps and deserved range, it returns a mask where values are
    within the interval.

    Parameters
    ---------
    maps: ASectorMap
        Map to check the outliers
    x2range : Tuple[float, float]
        Range for chi2

    Returns
    ---------
    mask: pd.DataFrame
        Mask.
    """
    mask = in_range(maps.chi2, *x2range)
    return mask
Esempio n. 21
0
def event_energy_cut(dst, emin, emax):
    """ input dst in which each entry correspond to a given sipm"""
    
    group      = dst.groupby(['event']).sum()
    group_Ecut = group[in_range(group.E, emin, emax)]
    dstCoreE   = dst[dst.event.isin(group_Ecut.index)]
    group_CoreE = dstCoreE.groupby(['event']).sum()

    # plot selected energy
    sns.set_style("white")
    sns.set_style("ticks")
    plot_event_energy(dstCoreE, group_CoreE, 50, [3000, 7000], 50, [100, 300], loc_E= 'upper left',
            loc_Q= 'upper right', figsize=(15,11))

    # plot e/q for sipm
    sns.set_style("white")
    sns.set_style("ticks")
    plot_EQ(dst, 50, [0, 1000], 50, [0, 100], figsize=(15,11))

    return dstCoreE
Esempio n. 22
0
def ltmap_vs_t(X, Y, Z, E, T, XYbins, Znbins, Zrange, Tnbins, Trange):
    """ returns the LT XYmap and Geo XYMap in time T intervals
    """
    xs, ys = 0.5 * (XYbins[:-1] + XYbins[1:]), 0.5 * (XYbins[:-1] + XYbins[1:])
    # e0map = XYMap(xs, ys,  Escale_rel.value, Escale_rel.uncertainty, Eok)
    # ltmap = XYMap(xs, ys, -ELT_rel.value   , ELT_rel.uncertainty   , Eok)
    # return e0map, ltmap
    tbins = np.linspace(*Trange, Tnbins + 1)
    e0maps, ltmaps = [], []
    for i in range(Tnbins):
        sel = in_range(T, tbins[i], tbins[i + 1])
        Escale, ELT, Echi2, Eok = ltmap(X[sel], Y[sel], Z[sel], E[sel], XYbins,
                                        Znbins, Zrange)
        e0map = XYMap(xs, ys, Escale.value, Escale.uncertainty, Eok)
        e0map.chi2 = Echi2
        ltmap = XYMap(xs, ys, ELT.value, ELT.uncertainty, Eok)
        ltmap.chi2 = Echi2
        e0maps.append(ie0map)
        ltmaps.append(iltmap)
    return e0maps, ltmaps
Esempio n. 23
0
def get_time_series_df(
        time_bins: Number,
        time_range: Tuple[float, float],
        dst: DataFrame,
        time_column: str = 'time') -> Tuple[np.array, List[np.array]]:
    """

    Given a dst (DataFrame) with a time column specified by the name time,
    this function returns a time series (ts) and a list of masks which are used to divide
    the event in time tranches.

    More generically, one can produce a "time series" using any column of the dst
    simply specifying time_column = ColumName

        Parameters
        ----------
            time_bins
                Number of time bines.
            time_range
                Time range.
            dst
                A Data Frame
            time_column
            A string specifyng the dst column to be divided in time slices.

        Returns
        -------
            A Tuple with:
            np.array       : This is the ts vector
            List[np.array] : This are the list of masks defining the events in the time series.

    """
    #Add small number to right edge to be included with in_range function
    modified_right_limit = np.nextafter(time_range[-1], np.inf)
    ip = np.linspace(time_range[0], modified_right_limit, time_bins + 1)
    masks = np.array([
        in_range(dst[time_column].values, ip[i], ip[i + 1])
        for i in range(len(ip) - 1)
    ])
    return shift_to_bin_centers(ip), masks
Esempio n. 24
0
def gaussian_parameters(x : np.array, range : Tuple[Number], bin_size : float = 1)->GaussPar:
    """
    Return the parameters defining a Gaussian
    g = N * exp(x - mu)**2 / (2 * std**2)
    where N is the normalization: N = 1 / (sqrt(2 * np.pi) * std)
    The parameters returned are the mean (mu), standard deviation (std)
    and the amplitude (inverse of N).
    """
    mu, std = mean_and_std(x, range)
    ff     = np.sqrt(2 * np.pi) * std

    amp     = len(x) * bin_size / ff

    sel  = in_range(x, *range)
    N = len(x[sel])              # number of samples in range
    mu_u  = std / np.sqrt(N)
    std_u = std / np.sqrt(2 * (N -1))
    amp_u = np.sqrt(2 * np.pi) * std_u

    return GaussPar(mu  = Measurement(mu, mu_u),
                    std = Measurement(std, std_u),
                    amp = Measurement(amp, amp_u))
Esempio n. 25
0
def mean_and_std(x: np.array, range_: Tuple[Number,
                                            Number]) -> Tuple[Number, Number]:
    """Computes mean and std for an array within a range: takes into account nans"""

    mu = NN
    std = NN

    if all(np.isnan(x)):  # all elements are nan
        mu = NN
        std = NN
    else:
        x_nonnan = x[np.isfinite(x)]
        y = x_nonnan[in_range(x_nonnan, *range_)]
        if len(y) == 0:
            warnings.warn(
                f'warning, empty slice of x = {x} in range = {range_}')
            mu = NN
            std = NN
        else:
            mu = np.mean(y)
            std = np.std(y)

    return mu, std
Esempio n. 26
0
def event_energy_cut(dst,
                     emin,
                     emax,
                     qmin=100,
                     qmax=300,
                     e_sipm_max=1000,
                     q_sipm_max=100):
    """ input dst in which each entry correspond to a given sipm"""

    group = dst.groupby(['event']).sum()
    group_Ecut = group[in_range(group.E, emin, emax)]
    dstCoreE = dst[dst.event.isin(group_Ecut.index)]
    group_CoreE = dstCoreE.groupby(['event']).sum()

    # plot selected energy
    sns.set_style("white")
    sns.set_style("ticks")
    plot_event_energy(dstCoreE,
                      group_CoreE,
                      50, [emin, emax],
                      50, [qmin, qmax],
                      loc_E='upper left',
                      loc_Q='upper right',
                      figsize=(15, 11))

    # plot e/q for sipm
    sns.set_style("white")
    sns.set_style("ticks")
    # 24 juliol he canviat dst --> dstcore, no se si hi havia rao.

    #plot_EQ(dst, 50, [0, 1000], 50, [0, 100], figsize=(15,11))
    plot_EQ(dstCoreE,
            50, [0, e_sipm_max],
            50, [0, q_sipm_max],
            figsize=(15, 11))

    return dstCoreE
Esempio n. 27
0
def mean_and_std(x : np.array, range_ : Tuple[Number, Number])->Tuple[Number, Number]:
    """Computes mean and std for an array within a range: takes into account nans"""

    mu = NN
    std = NN

    if np.count_nonzero(np.isnan(x)) == len(x):  # all elements are nan
        mu  = NN
        std  = NN
    elif np.count_nonzero(np.isnan(x)) > 0:
        mu = np.nanmean(x)
        std = np.nanstd(x)
    else:
        x = np.array(x)
        if len(x) > 0:
            y = x[in_range(x, *range_)]
            if len(y) == 0:
                print(f'warning, empty slice of x = {x} in range = {range_}')
                print(f'returning mean and std of x = {x}')
                y = x
            mu = np.mean(y)
            std = np.std(y)

    return mu, std
Esempio n. 28
0
def fit_lifetime_unbined(
        z: np.array, e: np.array, nbins_z: int,
        range_z: Tuple[float, float]) -> Tuple[FitPar, FitPar, FitResult]:
    """
    Based on

    numpy.polyfit(x, y, deg, rcond=None, full=False, w=None, cov=False)
    Fit a polynomial p(x) = p[0] * x**deg + ... + p[deg] of degree deg to points (x, y).
    Returns a vector of coefficients p that minimises the squared error.

    E = E0 exp(-z/lt)
    y = -log(E) = (z/lt) - log(E)

    Parameters
    ----------
        z
            Array of z values.
        e
            Array of energy values.
        nbins_z
            Number of bins in Z for the profile fit.
        range_z
            Range in Z for fit.


    Returns
    -------
        A Tuple with:
            FitPar : Fit parameters (arrays of fitted values and errors, fit function)
            FitPar : Fit parameters
            FirResults: Fit results (lt, e0, errors, chi2)

    """

    logging.debug(' fit_liftime_unbined')
    logging.debug(f' len (z) ={len(z)}, len (e) ={len(e)} ')
    logging.debug(f' nbins_z ={nbins_z}, range_z ={range_z} ')

    fp = None
    fp2 = None
    valid = True
    c2 = NN
    par = NN * np.ones(2)
    err = NN * np.ones(2)
    try:
        el = -np.log(e)
        z_sel = in_range(z, *range_z)
        cc, cov = np.polyfit(z[z_sel],
                             el[z_sel],
                             deg=1,
                             full=False,
                             w=None,
                             cov=True)
        a, b = cc[0], cc[1]

        lt = 1 / a
        par[1] = lt
        err[1] = lt**2 * np.sqrt(cov[0, 0])

        e0 = np.exp(-b)
        par[0] = e0
        err[0] = e0 * np.sqrt(cov[1, 1])

        x, y, yu = profile1d(z, e, nbins_z, range_z)
        xs, ys, yus = profile1d(z, el, nbins_z, range_z)
        xu = np.diff(x) * 0.5
        xus = np.diff(xs) * 0.5

        logging.debug(f' after profile: len (x) ={len(x)}, len (y) ={len(y)} ')

        c2 = chi2f(lambda z: a * xs + b, 2, xs, ys, yus)

        logging.debug(f' e0z ={par[0]} +- {err[0]} ')
        logging.debug(f' lt ={par[1]} +- {err[1]} ')
        logging.debug(f' c2 ={c2} ')

        fp = FitPar(x=x, y=y, xu=xu, yu=yu, f=lambda z: e0 * np.exp(-z / lt))
        fp2 = FitPar(x=xs, y=ys, xu=xus, yu=yus, f=lambda z: a * xs + b)

    except ValueError:
        logging.warn(
            f'Value Error found in fit_lifetime_unbined: not enough events for fit'
        )
        valid = False

    except TypeError:
        logging.warn(
            f'Type error found in fit_lifetime_unbined: not enough events for fit'
        )
        valid = False

    except LinAlgError:
        logging.warn(
            f'LinAlgError error found in fit_lifetime_unbined: not enough events for fit'
        )
        valid = False

    fr = FitResult(par=par, err=err, chi2=c2, valid=valid)

    return fp, fp2, fr
Esempio n. 29
0
def selection_in_band(E,
                      Z,
                      Erange,
                      Zrange,
                      Zfitrange,
                      nsigma=3.5,
                      Znbins=50,
                      Enbins=100,
                      plot=True):
    """ This returns a selection of the events that are inside the Kr E vz Z
    returns: np.array(bool)
        If plot=True, it draws E vs Z and the band
    """
    Zfit = Zfitrange

    Zbins = np.linspace(*Zrange, Znbins + 1)
    Ebins = np.linspace(*Erange, Enbins + 1)

    Zcenters = shift_to_bin_centers(Zbins)
    Zerror = np.diff(Zbins) * 0.5

    sel_e = in_range(E, *Erange)
    mean, sigma, chi2, ok = fit_slices_1d_gauss(Z[sel_e],
                                                E[sel_e],
                                                Zbins,
                                                Ebins,
                                                min_entries=5e2)
    ok = ok & in_range(Zcenters, *Zfit)

    def _line_cut(sign):
        x = Zcenters[ok]
        y = mean.value[ok] + sign * nsigma * sigma.value[ok]
        yu = mean.uncertainty[ok]
        seed = expo_seed(x, y)
        efit = fitf.fit(fitf.expo, x, y, seed, sigma=yu)
        assert np.all(efit.values != seed)
        return efit.fn

    lowE_cut = _line_cut(-1.)
    highE_cut = _line_cut(+1.)

    sel_inband = in_range(E, lowE_cut(Z), highE_cut(Z))

    if (plot == False): return sel_inband

    plt.hist2d(Z, E, (Zbins, Ebins), cmap=default_cmap)
    plt.errorbar(Zcenters[ok],
                 mean.value[ok],
                 sigma.value[ok],
                 Zerror[ok],
                 "kp",
                 label="Kr peak energy $\pm 1 \sigma$")
    f = fitf.fit(fitf.expo, Zcenters[ok], mean.value[ok], (1e4, -1e3))
    plt.plot(Zcenters, f.fn(Zcenters), "r-")
    print(f.values)
    plt.plot(Zbins,
             lowE_cut(Zbins),
             "m",
             lw=2,
             label="$\pm " + str(nsigma) + " \sigma$ region")
    plt.plot(Zbins, highE_cut(Zbins), "m", lw=2)
    plt.legend()
    labels("Drift time (µs)", "S2 energy (pes)", "Energy vs drift")

    return sel_inband
Esempio n. 30
0
def fit_slices_2d_expo(xdata, ydata, zdata, tdata,
                       xbins, ybins, nbins_z, zrange=None,
                       min_entries   = 1e2,
                       ignore_errors = _FIT_EXCEPTIONS):
    """
    Slice the data in x and y, make the profile in z of t,
    fit it to a exponential and return the relevant values.

    Parameters
    ----------
    xdata, ydata, zdata, tdata: array_likes
        Values of each coordinate.
    xbins, ybins: array_like
        The bins in the x coordinate.
    nbins_z: int
        The number of bins in the z coordinate for the profile.
    zrange: length-2 tuple (optional)
        Fix the range in z. Default is computed from min and max
        of the input data.
    min_entries: int (optional)
        Minimum amount of entries to perform the fit.

    Returns
    -------
    const: Measurement(np.ndarray, np.ndarray)
        Values of const with errors.
    slope: Measurement(np.ndarray, np.ndarray)
        Values of slope with errors.
    chi2: np.ndarray
        Chi2 from each fit.
    valid: boolean np.ndarray
        Where the fit has been succesfull.
    """
    nbins_x = np.size (xbins) - 1
    nbins_y = np.size (ybins) - 1
    nbins   = nbins_x, nbins_y
    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)

    if zrange is None:
        zrange = np.min(zdata), np.max(zdata)
    for i in range(nbins_x):
        sel_x = in_range(xdata, *xbins[i:i + 2])
        for j in range(nbins_y):
            sel_y = in_range(ydata, *ybins[j:j + 2])
            sel   = sel_x & sel_y
            if np.count_nonzero(sel) < min_entries: continue

            try:
                f = fit_profile_1d_expo(zdata[sel], tdata[sel], nbins_z, xrange=zrange)
                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 Exception as exc:
                if not isinstance(exc, ignore_errors):
                    raise

    return Measurement(const, constu), Measurement(slope, slopeu), chi2, valid