コード例 #1
0
ファイル: HomeMade.py プロジェクト: Vinther901/PUK
def gauss_chi2(data,
               ax,
               bins=None,
               range=None,
               coords=(0.05, 0.95),
               decimals=4):
    vals, bincenter, binwidth = hist(data, bins, range)
    svals = np.sqrt(vals)
    mask = vals > 0

    def fitfunc(x, mu, sigma):
        normalization = len(data) * binwidth
        return normalization / np.sqrt(2 * np.pi) / sigma * np.exp(
            -0.5 * (x - mu)**2 / sigma**2)

    chi2_obj = Chi2Regression(fitfunc, bincenter[mask], vals[mask],
                              svals[mask])
    minuit = Minuit(chi2_obj,
                    pedantic=False,
                    mu=np.mean(data),
                    sigma=np.std(data))
    minuit.migrad()

    if not minuit.migrad_ok():
        print('minuit.migrad() did not converge!')
    if not minuit.matrix_accurate():
        print('Hessematrix is not accurate!')

    ax.errorbar(bincenter[mask],
                vals[mask],
                svals[mask],
                drawstyle='steps-mid',
                capsize=2,
                linewidth=1,
                color='k',
                ecolor='r',
                label='data')
    ax.plot(bincenter[np.logical_not(mask)],
            vals[np.logical_not(mask)],
            'gx',
            label='Bins with 0')

    x = np.linspace(min(bincenter), max(bincenter), 500)
    ax.plot(x, fitfunc(x, *minuit.args), 'b', label='$\\chi^2$ fit')

    ndof = np.sum(mask) - len(minuit.args)
    d = {
        'Chi2/ndof:': f"{minuit.fval:.3f}/{ndof:d}",
        "p": stats.chi2.sf(minuit.fval, ndof),
        "mu": minuit.values['mu'],
        "sigma": minuit.values['sigma']
    }
    add_text_to_ax(*coords,
                   nice_string_output(d, decimals=decimals),
                   ax,
                   fontsize=12)
    return minuit
コード例 #2
0
ファイル: HomeMade.py プロジェクト: Vinther901/PUK
def weighted_mean(x,
                  errs,
                  ax=None,
                  plot_ticks=None,
                  point_label=None,
                  coords=(0.1, 0.9),
                  dec=3):
    """
    This function takes as input measurents and errors and returns the weighted mean along with the error.
    The weighted mean is calculated by doing a Chi-Square fit with a constant.
    if ax is given, the function will plot the fit, data and errors on it. 
    The function return weighted_mean, err, and a dictionairy with chi-square value and p-value
    """
    def constant(x, k):
        return k

    from AppStatFunctions import Chi2Regression, nice_string_output, add_text_to_ax

    ticks = np.arange(len(x))

    chi2_object = Chi2Regression(constant, ticks, x, errs)
    chi2_min = Minuit(chi2_object, pedantic=False)
    chi2_min.migrad()

    Chi2 = chi2_min.fval
    p_val = chi2.sf(Chi2, len(x) - 1)
    k = chi2_min.args[0]
    err = chi2_min.errors[0]

    if ax:
        if type(plot_ticks) != type(None):
            ticks = plot_ticks
        ax.plot(ticks, x, 'r.', label=point_label)
        ax.errorbar(ticks, x, errs, c = 'k', elinewidth = 1, \
                       capsize = 2, ls = 'none')
        ax.hlines(k, min(ticks), max(ticks), ls='--', label="Weighted mean")
        d = {"chisquare":   Chi2, \
             "p:":           p_val, \
             "mean:":        k,\
             "mean_err":     err}

        add_text_to_ax(*coords,
                       nice_string_output(d, decimals=dec),
                       ax,
                       fontsize=10)
        ax.legend()

    return k, err, {"chi2": Chi2, "p": p_val}
コード例 #3
0
ファイル: HomeMade.py プロジェクト: Vinther901/PUK
def fit_mass(xs,
             vals,
             errs,
             ax=None,
             guesses_bkgr=[0, 0, -10, 2000],
             guesses_sig=[498, 6, 17000]):
    if not ax:
        fig, ax = plt.subplots(figsize=(16, 10), ncols=2)
        ax_sig = ax[1]
        ax_all = ax[0]
        ax_all.plot(xs, vals, 'r.')
        ax_all.errorbar(xs,
                        vals,
                        errs,
                        color='k',
                        elinewidth=1,
                        capsize=2,
                        ls='none')

    def background_fit(x, a, b, c, d):
        return a * (x - 498)**3 + b * (x - 498)**2 + c * (x - 498) + d

    # The signal fit  Here gauss
    def add_signal(x, mean, sig, size):
        return size * norm.pdf(x, mean, sig)

    # The full fit
    def full_fit(x, mean, sig, size, a, b, c, d):
        return background_fit(x, a, b, c, d) + add_signal(x, mean, sig, size)

    # Background fit under here
    vals_b, cov_b = curve_fit(background_fit, xs, vals, p0=guesses_bkgr)

    b1, b2, b3, b4 = vals_b

    bkgr_chi2 = Chi2Regression(background_fit, xs, vals, errs)
    bkgr_min = Minuit(bkgr_chi2, pedantic=False, a=b1, b=b2, c=b3, d=b4)

    bkgr_min.migrad()

    # Plot result and save guesses
    #     ax_all.plot(xs, background_fit(xs, *bkgr_min.args),'b--',  label = "background_fit")

    b1, b2, b3, b4 = bkgr_min.args
    s1, s2, s3 = guesses_sig

    # Full fit
    full_chi2 = Chi2Regression(full_fit, xs, vals, errs)
    full_min  = Minuit(full_chi2, pedantic = False, a = b1, b = b2, c = b3, d = b4, \
                       mean = s1, sig = s2, size = s3)

    full_min.migrad()

    s1, s2, s3, b1, b2, b3, b4 = full_min.args

    ax_all.plot(xs, full_fit(xs, *full_min.args), "k-", label="full_fit")
    ax_all.plot(xs,
                background_fit(xs, *full_min.args[3:]),
                'b--',
                label="background_fit")

    ax_all.legend(loc="upper right")

    # Details:
    text = {'chi2': full_min.fval, \
            'pval': chi2.sf(full_min.fval, len(xs) - len(full_min.args)), \
            'mean': f"{full_min.values['mean']:.1f} +/- {full_min.errors['mean']:.1f}",\
            'N':    f"{full_min.values['size']:.1f} +/- {full_min.errors['size']:.1f}"}

    text_output = nice_string_output(text)
    add_text_to_ax(0.60, 0.925, text_output, ax_all)

    # Plot signal seperately
    ax_sig.fill_between(xs,
                        add_signal(xs, s1, s2, s3),
                        color='red',
                        alpha=0.5,
                        label="sig fit")

    vals_sig = vals - background_fit(xs, b1, b2, b3, b4)

    ax_sig.plot(xs, vals_sig, 'r.')
    ax_sig.errorbar(xs,
                    vals_sig,
                    errs,
                    color='k',
                    elinewidth=1,
                    capsize=2,
                    ls='none')

    sig_amount = np.sum(add_signal(xs, s1, s2, s3))
    bak_amount = np.sum(background_fit(xs, b1, b2, b3, b4))

    text_a = {'sig': np.round(sig_amount), \
              'bkgr': np.round(bak_amount), \
              's/b': sig_amount / bak_amount}

    text_output = nice_string_output(text_a, decimals=2)
    add_text_to_ax(0.70, 0.90, text_output, ax_sig)

    fig.tight_layout()

    bak_func = lambda x: background_fit(x, b1, b2, b3, b4)
    sig_func = lambda x: add_signal(x, s1, s2, s3)

    return fig, ax, full_min, bak_func, sig_func, [s1, s2, s3, b1, b2, b3, b4]
コード例 #4
0
ファイル: HomeMade.py プロジェクト: Vinther901/PUK
def double_gauss_fit(mass,
                     bins=100,
                     range=(400, 600),
                     ax=None,
                     verbose=True,
                     guesses=None,
                     max_size=None,
                     plimit=0,
                     color="red",
                     type='ks'):
    # Fit third degree polynomium to background
    if type == 'ks':

        def background_fit(x, a, b, c, d):
            res = a * (x - 498)**3 + b * (x - 498)**2 + c * (x - 498) + d
            return res
    elif type == 'la':

        def background_fit(x, a, b, c, d):
            res = a * (x - 1116)**3 + b * (x - 1116)**2 + c * (x - 1116) + d
            return res

    # The double gauss signal
    def add_signal(x, mean, sig, size, ratio, sig_ratio):
        return size * binwidth *  (ratio * norm.pdf(x, mean, sig) + \
                                   (1 - ratio) * norm.pdf(x, mean, sig_ratio * sig))

    # The full fit
    def full_fit(x, mean, sig, size, ratio, sig_ratio, a, b, c, d):
        return background_fit(x, a, b, c, d) + add_signal(
            x, mean, sig, size, ratio, sig_ratio)

    # Make histogram
    vals, edges = np.histogram(mass, bins=bins, range=range)
    xs = (edges[1:] + edges[:-1]) / 2

    binwidth = xs[1] - xs[0]

    mask = vals > 0
    vals = vals[mask]
    xs = xs[mask]
    errs = np.sqrt(vals)

    # Get guesses for a background fit
    if not guesses:
        if type == 'ks':
            back_data_mask = abs(xs - xs[np.argmax(vals)]) > 10
        if type == 'la':
            back_data_mask = abs(xs - 1117) > 5
        background_guess = [0, 0, (vals[-1] - vals[0]) / 100, vals.min()]

        if len(vals[back_data_mask]) == 0:
            return None, None, None, None

        try:
            vals_b, cov_b = curve_fit(background_fit,
                                      xs[back_data_mask],
                                      vals[back_data_mask],
                                      p0=background_guess)
        except:
            vals_b = background_guess
        b1, b2, b3, b4 = vals_b

        bkgr_chi2 = Chi2Regression(background_fit, xs[back_data_mask],
                                   vals[back_data_mask], errs[back_data_mask])
        bkgr_min = Minuit(bkgr_chi2, pedantic=False, a=b1, b=b2, c=b3, d=b4)
        bkgr_min.migrad()
        counter = 0
        while not bkgr_min.valid and counter < 50:
            bkgr_min.migrad()
            counter += 1
        if not bkgr_min.valid: print("No background valid minimum found!")

        #Save guesses
        b1, b2, b3, b4 = bkgr_min.args

        if type == 'ks':
            guesses_sig = [498, 7, 2000, 0.5, 2]
        elif type == 'la':
            guesses_sig = [1116, 3, 3700, 0.5, 2]
        try:
            vals_f, cov_f = curve_fit(full_fit,
                                      xs,
                                      vals,
                                      p0=guesses_sig + [b1, b2, b3, b4])
        except:
            vals_f = np.hstack([guesses_sig, vals_b])

        s1, s2, s3, s4, s5, b1, b2, b3, b4 = vals_f
    else:
        s1, s2, s3, s4, s5, b1, b2, b3, b4 = guesses

    full_chi2 = Chi2Regression(full_fit, xs, vals, errs)
    if type == 'ks':
        full_min  = Minuit(full_chi2, pedantic = False, a = b1, b = b2, c = b3, d = b4, \
                           mean = s1, sig = s2, size = s3, ratio = s4, sig_ratio = s5, limit_sig_ratio = (1, 4), \
                           limit_ratio = (0, 1.0), limit_mean = (490, 510), limit_size = (0, max_size), limit_sig = (3, 10))
    elif type == 'la':
        full_min  = Minuit(full_chi2, pedantic = False, a = b1, b = b2, c = b3, d = b4, \
                           mean = s1, sig = s2, size = s3, ratio = s4, sig_ratio = s5, limit_sig_ratio = (1, 4), \
                           limit_ratio = (0, 1.0), limit_mean = (1115,1118), limit_size = (0, max_size), limit_sig = (0.1,10))
    full_min.migrad()

    full_min.migrad()
    counter = 0
    while not full_min.valid and counter < 200:
        full_min.migrad()
        counter += 1
    if not full_min.valid: print("No valid minimum found!")

    # Check fit
    chi = full_min.fval
    pval = chi2.sf(chi, np.sum(mask) - len(full_min.args))

    if verbose:
        print(f"Completed fit with Chi2: {chi:.1f}, p-val: {pval:.3f} and the total amount of signal " + \
            f"{full_min.values['size']:.0f} +/- {full_min.errors['size']:.0f}, background: {len(mass) - int(full_min.values['size'])}")

    if ax:
        ax.plot(xs, vals, alpha=1, color=color)


#         ax.errorbar(xs, vals, errs, elinewidth = 1, color = 'k', capsize = 2, linestyle = 'none', alpha = 0.25)
#         ax.plot(xs, full_fit(xs, *full_min.args), '--', alpha = 0.5)

#         s1, s2, s3, s4, s5, b1, b2, b3, b4 = full_min.args
#         ax.plot(xs,background_fit(xs,b1,b2,b3,b4),color=color)
#         ax.plot(xs,add_signal(xs,s1,s2,s3,s4,s5)+background_fit(xs,b1,b2,b3,b4),color='k',ls='--')

    if True:  #full_min.errors['size'] < full_min.values['size'] and full_min.valid and pval > plimit:
        return full_min.values['size'], len(mass) - full_min.values[
            'size'], full_min.errors['size'], full_min.args
    else:
        return None, None, None, None
コード例 #5
0
ファイル: HomeMade.py プロジェクト: Vinther901/PUK
def fit_mass2(xs,
              vals,
              errs,
              ax=None,
              guesses_bkgr=[0, 0, -10, 2000],
              guesses_sig=[497, 6, 17000],
              plot=True,
              type='ks',
              second_axis=None):
    guesses_bkgr[-1] = 0.5 * (vals[0] + vals[-1])
    guesses_sig[-1] = 20 * max(
        vals
    )  #np.sqrt(2*np.pi*guesses_sig[1]**2)*(max(vals))# - guesses_bkgr[-1])

    if not ax and plot:
        fig, ax = plt.subplots(figsize=(16, 10), ncols=2)
        ax_sig = ax[1]
        ax_all = ax[0]
        ax_all.plot(xs, vals, 'r.')
        ax_all.errorbar(xs,
                        vals,
                        errs,
                        color='k',
                        elinewidth=1,
                        capsize=2,
                        ls='none')
    elif plot:
        fig = None
        ax_sig = ax[1]
        ax_all = ax[0]
        ax_all.plot(xs, vals, 'r.')
        ax_all.errorbar(xs,
                        vals,
                        errs,
                        color='k',
                        elinewidth=1,
                        capsize=2,
                        ls='none')

    def background_fit(x, a, b, c, d):
        return a * (x - guesses_sig[0])**3 + b * (
            x - guesses_sig[0])**2 + c * (x - guesses_sig[0]) + d

    # The signal fit  Here gauss
    def sig1(x, mean, sig, size):
        return size * norm.pdf(x, mean, sig)

    def sig2(x, mean, sig, size):
        return size * norm.pdf(x, mean, sig)

    # The full fit
    def full_fit(x, mean, sig, size, f, sigmp, a, b, c, d):
        return background_fit(x, a, b, c, d) + f * sig1(
            x, mean, sig, size) + (1 - f) * sig2(x, mean, sigmp * sig, size)

    # Background fit under here
    if type == 'ks':
        bkgr_mask = (xs < 475) | (xs > 525)
    elif type == 'la':
        bkgr_mask = abs(xs - 1117) > 5
    try:
        vals_b, cov_b = curve_fit(background_fit,
                                  xs[bkgr_mask],
                                  vals[bkgr_mask],
                                  p0=guesses_bkgr)
        b1, b2, b3, b4 = vals_b
    except:
        b1, b2, b3, b4 = guesses_bkgr
    bkgr_chi2 = Chi2Regression(background_fit, xs[bkgr_mask], vals[bkgr_mask],
                               errs[bkgr_mask])
    bkgr_min = Minuit(bkgr_chi2, pedantic=False, a=b1, b=b2, c=b3, d=b4)

    with warnings.catch_warnings():
        warnings.simplefilter('ignore')

        bkgr_min.migrad()
        counter = 0
        while not bkgr_min.valid and counter < 50:
            bkgr_min.migrad()
            counter += 1
    if not bkgr_min.valid: print("No background valid minimum found!")

    #Save guesses
    b1, b2, b3, b4 = bkgr_min.args
    s1, s2, s3 = guesses_sig
    if type == 'la':
        s1 = 1117

    # Full fit
    full_chi2 = Chi2Regression(full_fit, xs, vals, errs)
    full_min  = Minuit(full_chi2, pedantic = False, a = b1, b = b2, c = b3, d = b4, \
                       mean = s1, sig = s2, size = s3, f = 0.5, sigmp = 2, \
                      limit_mean=(475,525), limit_f=(0,1), limit_size=(0,None))
    #     full_min  = Minuit(full_chi2, pedantic = False, a = b1, b = b2, c = b3, d = b4, \
    #                        mean = s1, sig = s2, size = s3, f = 0.5, sigmp = 2, \
    #                       limit_f=(0,1), limit_size=(0,None),limit_sig=(0.1,10))
    with warnings.catch_warnings():
        warnings.simplefilter('ignore')

        full_min.migrad()
        counter = 0
        while not full_min.valid and counter < 200:
            full_min.migrad()
            counter += 1
    if not full_min.valid: print("No valid minimum found!")

    mean, sig, size, f, sigmp, b1, b2, b3, b4 = full_min.args

    sig_amount = np.sum(f * sig1(xs, mean, sig, size) +
                        (1 - f) * sig2(xs, mean, sigmp * sig, size))
    bak_amount = np.sum(background_fit(xs, b1, b2, b3, b4))

    neg_bkgr = any(background_fit(xs, b1, b2, b3, b4) < 0)

    def signal():
        def signal_func(x):
            return f * sig1(x, mean, sig, size) + (1 - f) * sig2(
                x, mean, sigmp * sig, size)

        return signal_func

    def background():
        def background_func(x):
            return background_fit(x, b1, b2, b3, b4)

        return background_func

    if plot:
        ax_all.plot(xs, full_fit(xs, *full_min.args), "k-", label="full_fit")
        ax_all.plot(xs,
                    background_fit(xs, b1, b2, b3, b4),
                    'b--',
                    label="background_fit")

        ax_all.legend(loc="upper right")

        # Details:
        text = {'chi2': full_min.fval, \
                'pval': chi2.sf(full_min.fval, len(xs) - len(full_min.args)), \
                'mean': f"{full_min.values['mean']:.1f} +/- {full_min.errors['mean']:.1f}",\
                'N':    f"{full_min.values['size']:.1f} +/- {full_min.errors['size']:.1f}"}

        text_output = nice_string_output(text)
        add_text_to_ax(0.60, 0.925, text_output, ax_all)

        # Plot signal seperately
        ax_sig.fill_between(xs,
                            f * sig1(xs, mean, sig, size) +
                            (1 - f) * sig2(xs, mean, sigmp * sig, size),
                            color='red',
                            alpha=0.5,
                            label="sig fit")
        ax_sig.plot(xs,
                    f * sig1(xs, mean, sig, size),
                    ls='--',
                    color='blue',
                    alpha=0.5,
                    label="sig fit")
        ax_sig.plot(xs, (1 - f) * sig2(xs, mean, sigmp * sig, size),
                    ls='--',
                    color='green',
                    alpha=0.5,
                    label="sig fit")

        vals_sig = vals - background_fit(xs, b1, b2, b3, b4)

        ax_sig.plot(xs, vals_sig, 'r.')
        ax_sig.errorbar(xs,
                        vals_sig,
                        errs,
                        color='k',
                        elinewidth=1,
                        capsize=2,
                        ls='none')

        text_a = {'sig': np.round(sig_amount), \
                  'bkgr': np.round(bak_amount), \
                  's/b': sig_amount / bak_amount}

        text_output = nice_string_output(text_a, decimals=2)
        add_text_to_ax(0.70, 0.90, text_output, ax_sig)
        try:
            fig.tight_layout()
        except:
            pass

        return {
            'fig': fig,
            'ax': ax,
            'M': full_min,
            'sig': sig_amount,
            'bkgr': bak_amount,
            'neg_bkgr': neg_bkgr,
            'sig_func': signal(),
            'bkgr_func': background()
        }

    only_text = True
    if only_text and second_axis:
        N_sig = full_min.values['size']
        N_background = sum(vals) - N_sig
        text = {
            'mean': f"{full_min.values['mean']:.1f} +/- {full_min.errors['mean']:.1f}",\
            'sigma': f"{full_min.values['sig']:.2f} +/- {full_min.errors['sig']:.2f}",\
            'sigma-mp': f"{full_min.values['sigmp']:.2f} +/- {full_min.errors['sigmp']:.2f}",\
            'f': f"{full_min.values['f']:.2f} +/- {full_min.errors['f']:.2f}",\
            'signal':    f"{N_sig:.0f} +/- {full_min.errors['size']:.0f}",\
              'background': f"{N_background:.0f} +/- {full_min.errors['size']:.0f}", \
              's/b': f"{N_sig/N_background:.3f} +/- {N_sig/N_background*full_min.errors['size']*np.sqrt(1/N_sig**2 + 1/N_background**2):.3f}"}

        text_output = nice_string_output(text, extra_spacing=1)
        add_text_to_ax(0.01, 0.99, text_output, second_axis)

    return {
        'M': full_min,
        'sig': sig_amount,
        'bkgr': bak_amount,
        'neg_bkgr': neg_bkgr,
        'sig_func': signal(),
        'bkgr_func': background()
    }