コード例 #1
0
ファイル: minuit.py プロジェクト: mahmoud-lsw/gammatools
class Minuit(object):
    """A wrapper class to initialize a minuit object with a numpy array.

    Positional args:
        myFCN : A python callable
        params : An array (or other python sequence) of parameters

    Keyword args:

        limits [None] : a nested sequence of (lower_limit,upper_limit) for each parameter.
        steps [[.1]*npars] : Estimated errors for the parameters, used as an initial step size.
        tolerance [.001] : Tolerance to test for convergence.  Minuit considers convergence to be
                            when the estimated distance to the minimum (edm) is <= .001*up*tolerance,
                            or 5e-7 by default.
        up [.5]  : Change in the objective function that determines 1-sigma error.  .5 if 
                          the objective function is -log(Likelihood), 1 for chi-squared.
        max_calls [10000] : Maximum number of calls to the objective function.
        param_names ['p0','p1',...] : a list of names for the parameters
        args [()] : a tuple of extra arguments to pass to myFCN and gradient.
        gradient [None] : a function that takes a list of parameters and returns a list of 
                          first derivatives of myFCN.  Assumed to take the same args as myFCN.
        force_gradient [0] : Set to 1 to force Minuit to use the user-provided gradient function.
        strategy[1] : Strategy for minuit to use, from 0 (fast) to 2 (safe) 
        fixed [False, False, ...] : If passed, an array of all the parameters to fix
    """
    def __init__(self, myFCN, params, **kwargs):

        from ROOT import TMinuit, Long, Double

        self.limits = np.zeros((len(params), 2))
        self.steps = .04 * np.ones(
            len(params))  # about 10 percent in log10 space
        self.tolerance = .001
        self.maxcalls = 10000
        self.printMode = 0
        self.up = 0.5
        self.param_names = ['p%i' % i for i in xrange(len(params))]
        self.erflag = Long()
        self.npars = len(params)
        self.args = ()
        self.gradient = None
        self.force_gradient = 0
        self.strategy = 1
        self.fixed = np.zeros_like(params)
        self.__dict__.update(kwargs)

        self.params = np.asarray(params, dtype='float')
        self.fixed = np.asarray(self.fixed, dtype=bool)
        self.fcn = FCN(myFCN,
                       self.params,
                       args=self.args,
                       gradient=self.gradient)
        self.fval = self.fcn.fval
        self.minuit = TMinuit(self.npars)
        self.minuit.SetPrintLevel(self.printMode)
        self.minuit.SetFCN(self.fcn)
        if self.gradient:
            self.minuit.mncomd('SET GRA %i' % (self.force_gradient),
                               self.erflag)
        self.minuit.mncomd('SET STR %i' % self.strategy, Long())

        for i in xrange(self.npars):

            if self.limits[i][0] is None: self.limits[i][0] = 0.0
            if self.limits[i][1] is None: self.limits[i][1] = 0.0

            self.minuit.DefineParameter(i, self.param_names[i], self.params[i],
                                        self.steps[i], self.limits[i][0],
                                        self.limits[i][1])

        self.minuit.SetErrorDef(self.up)

        for index in np.where(self.fixed)[0]:
            self.minuit.FixParameter(int(index))

    def minimize(self, method='MIGRAD'):

        from ROOT import TMinuit, Long, Double

        self.minuit.mncomd(
            '%s %i %f' % (method, self.maxcalls, self.tolerance), self.erflag)
        for i in xrange(self.npars):
            val, err = Double(), Double()
            self.minuit.GetParameter(i, val, err)
            self.params[i] = val
        self.fval = self.fcn.fcn(self.params)
        return (self.params, self.fval)

    def errors(self, method='HESSE'):
        """method ['HESSE']   : how to calculate the errors; Currently, only 'HESSE' works."""
        if not np.any(self.fixed):
            mat = np.zeros(self.npars**2)
            if method == 'HESSE':
                self.minuit.mnhess()
            else:
                raise Exception("Method %s not recognized." % method)
            self.minuit.mnemat(mat, self.npars)
            return mat.reshape((self.npars, self.npars))
        else:
            # Kind of ugly, but for fixed parameters, you need to expand out the covariance matrix.
            nf = int(np.sum(~self.fixed))
            mat = np.zeros(nf**2)
            if method == 'HESSE':
                self.minuit.mnhess()
            else:
                raise Exception("Method %s not recognized." % method)
            self.minuit.mnemat(mat, nf)

            # Expand out the covariance matrix.
            cov = np.zeros((self.npars, self.npars))
            cov[np.outer(~self.fixed, ~self.fixed)] = np.ravel(mat)
            return cov

    def uncorrelated_minos_error(self):
        """ Kind of a kludge, but a compromise between the speed of
            HESSE errors and the accuracy of MINOS errors.  It accounts
            for non-linearities in the likelihood by varying each function
            until the value has fallen by the desired amount using hte
            MINOS code. But does not account for correlations between
            the parameters by fixing all other parameters during the
            minimzation. 
            
            Again kludgy, but what is returned is an effective covariance
            matrix. The diagonal errors are calcualted by averaging the
            upper and lower errors and the off diagonal terms are set
            to 0. """

        cov = np.zeros((self.npars, self.npars))

        # fix all parameters
        for i in range(self.npars):
            self.minuit.FixParameter(int(i))

        # loop over free paramters getting error
        for i in np.where(self.fixed == False)[0]:
            self.minuit.Release(int(i))

            # compute error
            self.minuit.mnmnos()
            low, hi, parab, gcc = ROOT.Double(), ROOT.Double(), ROOT.Double(
            ), ROOT.Double()

            # get error
            self.minuit.mnerrs(int(i), low, hi, parab, gcc)
            cov[i, i] = ((abs(low) + abs(hi)) / 2.0)**2
            self.minuit.FixParameter(int(i))

        for i, fixed in enumerate(self.fixed):
            if fixed:
                self.minuit.FixParameter(int(i))
            else:
                self.minuit.Release(int(i))

        return cov
コード例 #2
0
class Fits:
    def __init__(self):

        self.p_n = [
            0,
        ] * 100
        self.e_n = [
            0,
        ] * 100
        self.stored_parameters = [
            0,
        ] * 100

        self.num_bins = 0
        self.xmins = []
        self.xmaxes = []

        self.data = []
        self.errors = []
        self.data_fits = []

        self.model_scale_values = []
        self.final = False

        self.exclude_regions = ((0, 0), )

        self.col1 = 1
        self.col2 = TColor.GetColor(27, 158, 119)
        self.col3 = TColor.GetColor(217, 95, 2)
        self.col4 = TColor.GetColor(117, 112, 179)

    def run_mass_fit(self, peak_scale_initial, mass=0):
        self.gMinuit = TMinuit(30)
        self.gMinuit.SetPrintLevel(-1)
        self.gMinuit.SetFCN(self.Fitfcn_max_likelihood)

        arglist = array("d", [
            0,
        ] * 10)
        ierflg = ROOT.Long(0)
        arglist[0] = ROOT.Double(1)

        # peak_scale_initial = ROOT.Double(peak_scale_initial)

        tmp = array("d", [
            0,
        ])
        self.gMinuit.mnexcm("SET NOWarnings", tmp, 0, ierflg)

        self.gMinuit.mnexcm("SET ERR", arglist, 1, ierflg)
        self.gMinuit.mnparm(0, "p1", 5e-6, 1e-7, 0, 0, ierflg)
        self.gMinuit.mnparm(1, "p2", 10, 10, 0, 0, ierflg)
        self.gMinuit.mnparm(2, "p3", -5.3, 1, 0, 0, ierflg)
        self.gMinuit.mnparm(3, "p4", -4e-2, 1e-2, 0, 0, ierflg)
        self.gMinuit.mnparm(4, "p5", peak_scale_initial,
                            peak_scale_initial / 50, 0, 0, ierflg)

        self.background_fit_only = [
            0,
        ] * len(self.data)

        arglist[0] = ROOT.Double(0)
        arglist[1] = ROOT.Double(0)

        #self.exclude_regions = ((2.2, 3.3),)
        self.gMinuit.FixParameter(2)
        self.gMinuit.FixParameter(3)
        self.gMinuit.FixParameter(4)

        self.gMinuit.mnexcm("simplex", arglist, 2, ierflg)
        self.gMinuit.mnexcm("MIGRAD", arglist, 2, ierflg)

        self.gMinuit.Release(2)
        self.gMinuit.mnexcm("simplex", arglist, 2, ierflg)
        self.gMinuit.mnexcm("MIGRAD", arglist, 2, ierflg)

        self.gMinuit.Release(3)
        self.gMinuit.mnexcm("simplex", arglist, 2, ierflg)
        self.gMinuit.mnexcm("MIGRAD", arglist, 2, ierflg)

        # Find an actual best fit
        #self.exclude_regions = ((0, 2), (3.3, 100),)
        self.gMinuit.FixParameter(0)
        self.gMinuit.FixParameter(1)
        self.gMinuit.FixParameter(2)
        self.gMinuit.FixParameter(3)
        self.gMinuit.Release(4)
        self.gMinuit.mnexcm("simplex", arglist, 2, ierflg)
        self.gMinuit.mnexcm("MIGRAD", arglist, 2, ierflg)

        self.exclude_regions = ()
        self.gMinuit.Release(0)
        self.gMinuit.Release(1)
        self.gMinuit.Release(2)
        self.gMinuit.Release(3)
        self.gMinuit.mnexcm("simplex", arglist, 2, ierflg)
        self.gMinuit.mnexcm("MIGRAD", arglist, 2, ierflg)

        best_fit_value = ROOT.Double(0)
        self.gMinuit.mnstat(best_fit_value, ROOT.Double(0), ROOT.Double(0),
                            ROOT.Long(0), ROOT.Long(0), ROOT.Long(0))
        #print("Best fit value", best_fit_value)

        # And prepare for iterating over fit values for N injected events
        self.gMinuit.Release(0)
        self.gMinuit.Release(1)
        self.gMinuit.Release(2)
        self.gMinuit.Release(3)
        self.exclude_regions = ()

        #self.data_fits = no_peak_data_fits
        x_values = []
        y_values = []

        fitted_N = ROOT.Double(0)
        self.gMinuit.GetParameter(4, fitted_N, ROOT.Double(0))
        best_fit_likelihood = self.calc_likelihood(fitted_N)

        step = 5
        if int(mass) >= 4000:
            step = 1
        if int(mass) >= 5000:
            step = 0.2
        if int(mass) >= 6000:
            step = 0.1
        if int(mass) >= 6500:
            step = 0.05

        N = 0

        while N < 5000:
            start_sum = sum([math.exp(-a) for a in y_values])
            fit_likelihood = self.calc_likelihood(N)
            x_values.append(N)
            y_values.append(fit_likelihood - best_fit_likelihood)

            probabilities = [math.exp(-a) for a in y_values]
            end_sum = sum(probabilities)

            max_prob = max(probabilities)
            normalised_probabilities = [a / max_prob for a in probabilities]

            if N / step > 50 and all(
                [v > 0.99 for v in normalised_probabilities]):
                print(
                    "Probability=1 everywhere, probably something wrong with fit"
                )
                print(normalised_probabilities)
                return None, None

            # if new value changes total by less than 0.1%, end loop
            if N > 0 and (end_sum - start_sum) / start_sum < 0.0001:
                print("Iterated up to {0}".format(N))
                break

            N += step

        self.iflag = int(ierflg)
        return x_values, y_values

    def Fitfcn_max_likelihood(self, npar, gin, fcnVal, par, iflag):
        likelihood = 0
        mf = ROOT.MyMassSpectrum()
        mf.SetParameters(par)
        ig = GaussIntegrator()
        ig.SetFunction(mf)
        ig.SetRelTolerance(0.00001)

        for i in range(0, self.num_bins):
            for lower, higher in self.exclude_regions:
                if lower < self.xmins[i] < higher:
                    continue

            model_val = ig.Integral(self.xmins[i], self.xmaxes[i]) / (
                self.xmaxes[i] - self.xmins[i])
            self.background_fit_only[i] = model_val
            model_val += self.model_scale_values[i] * par[4]
            self.data_fits[i] = model_val

            likelihood += model_val - self.data[i]
            if self.data[i] > 0 and model_val > 0:
                likelihood += self.data[i] * (math.log(self.data[i]) -
                                              math.log(model_val))

        fcnVal[0] = likelihood

    def calc_likelihood(self, peak_scale):
        like = 0

        for i in range(0, self.num_bins):
            if self.data_fits[i] <= 0:
                continue

            p = peak_scale * self.model_scale_values[i]
            tmp = ROOT.TMath.PoissonI(self.data[i],
                                      self.background_fit_only[i] + p)
            #if peak_scale == 40000:
            #    print(i, "\txmin", self.xmins[i], "\tdata", self.data[i], "\tdata_fit", self.data_fits[i], "\tp", p, "\tdata_fit+p", self.data_fits[i]+p)
            if tmp == 0:
                print("tmp == 0 here")
                logtmp = math.log(sys.float_info.min)
            else:
                logtmp = math.log(tmp)
            like += logtmp

        return -like
コード例 #3
0
def main():
    global freqs_hz, pv, sigq, sigu
    parser = OptionParser(usage)

    parser.add_option("-r", "--rm", type="float", dest="rm", default=0.,
                            help="Estimate of the RM")
    parser.add_option("-n", "--norm", action="store_true", dest="norm",
			    default=False, help="Verbose mode")
    parser.add_option("-b", "--baseline", action="store_true", dest="baseline",
			    default=False, help="Fit for a baseline")
    parser.add_option("-f", "--nofit", action="store_true", dest="nofit",
			    default=False, help="Don't fit for the RM with Minuit")
    parser.add_option("-c", "--clean", action="store_true", dest="clean",
			    default=False, help="Clean the baseline")

    (opts, args) = parser.parse_args()

    #if opts.help:
    #    print full_usage

    arch = psrchive.Archive_load(sys.argv[1])
    arch.tscrunch()
    arch.bscrunch(2)
    #arch.fscrunch(2)
    arch.dedisperse()
    arch.remove_baseline()
    arch.convert_state('Stokes')
    arch.centre_max_bin()
    #arch.rotate(0.5)
    data = arch.get_data()

    MJD = arch.get_first_Integration().get_epoch().strtempo()

    w = arch.get_weights().sum(0)
    I = data[:,0,:,:].mean(0)
    Q = data[:,1,:,:].mean(0)
    U = data[:,2,:,:].mean(0)
    #V = data[:,3,:,:].mean(0)

    I = ma.masked_array(I)
    Q = ma.masked_array(Q)
    U = ma.masked_array(U)
    #V = ma.masked_array(V)

    I[w==0] = np.ma.masked
    Q[w==0] = np.ma.masked
    U[w==0] = np.ma.masked


    # Get Freqs
    nchan = arch.get_nchan()
    freqs = np.zeros(nchan)
    for i in range(nchan):
	freqs[i] = arch.get_Profile(0,0,i).get_centre_frequency() 

    ## Determine phase range
    arch.fscrunch()
    arch.tscrunch()
    arch.pscrunch()
    prof = arch.get_Profile(0,0,0)
    #print prof.get_amps()

    lowbin, hibin = get_pulse_range(arch)

    #lowbin, hibin = 458,531
    #lowbin, hibin = 20,120



    if opts.clean:
      for n in range(nchan):
	if n%20: continue
        baseline_idx = np.append(np.arange(0, lowbin), np.arange(hibin, arch.get_nbin()))
	baseline_dat = I[n][baseline_idx]
	print n, baseline_idx, baseline_dat
	poly = np.polyfit(baseline_idx, baseline_dat, 1)
	p = np.poly1d(poly)
	pylab.plot(I[n])
	I[n] = I[n] - p(np.arange(0, arch.get_nbin()))
	pylab.plot(I[n])
	pylab.show()

    
    for ii, wx in enumerate(w):
	I[ii] *= wx/np.max(w)
	Q[ii] *= wx/np.max(w)
	U[ii] *= wx/np.max(w)
	#V[ii] *= wx

    if opts.norm:
        print "Will normalize by the rms of the noise"
	scale = np.std(I, axis=1) / np.max(np.std(I, axis=1))
	for ii, s in enumerate(scale):
	    I[ii,:] /= s
	    Q[ii,:] /= s
	    U[ii,:] /= s
    #Q = Q / scale	
    #U = U / scale	
	
    freq_lo = freqs[0]
    freq_hi = freqs[-1]


    lowphase = lowbin / float(arch.get_nbin())
    hiphase = hibin / float(arch.get_nbin())

    #lowphase= 0.48
    #hiphase = 0.515
    #lowphase = 0.515
    #hiphase = 0.54
    print "Pulse phase window: ", lowphase, hiphase

    #pylab.plot(np.sum(I), axis)
    #pylab.show()

    # 2D plot
    f = pylab.figure() 

    pylab.subplot(321)
    #print np.sum(I,axis=0)
    #pylab.plot(np.sum(I, axis=0))
    pylab.plot(prof.get_amps())
    pylab.xlim([0, arch.get_nbin()])

    f.text( .5, 0.95, r'%s'%os.path.split(sys.argv[1])[1], horizontalalignment='center') 
    pylab.subplot(323)
    pylab.axis([0,1,freq_lo,freq_hi])
    pylab.imshow(I,extent=(0,1,freq_lo,freq_hi), origin='lower', aspect='auto', vmax=I.max()/1.5, vmin=I.min()/1.5)
    pylab.xlabel('Pulse phase')
    pylab.ylabel('Frequency (MHz)')

    # Compute errors of Q and U
    sigq = np.std(Q[:,lowbin:hibin], axis=1) / np.sqrt(hibin-lowbin) 
    sigu = np.std(U[:,lowbin:hibin], axis=1) / np.sqrt(hibin-lowbin)
    #sigq = np.std(Q[:,:], axis=1) 
    #sigu = np.std(U[:,:], axis=1) 

    pylab.plot([lowphase,lowphase], [freq_lo, freq_hi], 'r--')
    pylab.plot([hiphase,hiphase], [freq_lo, freq_hi], 'r--')

    freqs_hz = freqs * 1e6
    # Select phase range
    lowbin = int(lowphase * arch.get_nbin())
    hibin = int(hiphase * arch.get_nbin())
    dat = Q + 1j * U
    pv = dat[:,lowbin:hibin].mean(1) # Select phase range and average

    #rhos = np.arange(-90000, 90000, 10)
    rhos = np.arange(-2000, 2000, 1)
    res = np.absolute(getL(rhos, pv))

    # Plot I f(RM)
    pylab.subplot(324)
    pylab.plot(rhos, res, 'b-')
    pylab.xlabel('RM')
    pylab.ylabel('I')


    # Plot Q
    pylab.subplot(325)
    pylab.errorbar(freqs, np.real(pv), yerr=sigq, ls='None')
    pylab.plot(freqs, np.real(pv), 'bo')
    pylab.xlabel('Frequency (MHz)')
    pylab.ylabel('Q')


    # Plot U
    pylab.subplot(326)
    pylab.errorbar(freqs, np.imag(pv), yerr=sigu, ls='None')
    pylab.plot(freqs, np.imag(pv), 'bo')
    pylab.xlabel('Frequency (MHz)')
    pylab.ylabel('U')

    # Should get the initial RM
    if opts.rm:
	initial_RM = -opts.rm
    else:
        initial_RM = -rhos[np.argmax(res)]
	print "Will use initial RM", initial_RM
    initial_L = getL(np.array([initial_RM]), pv) / (hibin-lowbin)


    if not opts.nofit:
	# Minuit part
	gMinuit = TMinuit(5)
	#gMinuit.SetErrorDef(1) # 1-Sigma Error
	gMinuit.SetErrorDef(4) # 2-Sigma Error
	gMinuit.SetFCN(fcn)
	arglist = arr('d', 2*[0.01])
	ierflg = Long(0)

	#arglist[0] = 1
	#gMinuit.mnexcm("SET ERR", arglist ,1,ierflg)


	# Set initial parameter values for fit
	vstart = arr( 'd', (np.real(initial_L), np.imag(initial_L), initial_RM) )
	#vstart = arr( 'd', (2*np.real(initial_L), 2*np.imag(initial_L), initial_RM) )
	# Set step size for fit
	step =   arr( 'd', (0.001, 0.001, 0.001) )

	# Define the parameters for the fit
	gMinuit.mnparm(0, "Qf",  vstart[0], step[0], 0,0,ierflg)
	gMinuit.mnparm(1, "Uf",  vstart[1], step[1], 0,0,ierflg)
	gMinuit.mnparm(2, "RM",  vstart[2], step[2], 0,0,ierflg)

	gMinuit.mnparm(3, "a",  0.0, step[2], 0,0,ierflg)
	gMinuit.mnparm(4, "b",  0.0, step[2], 0,0,ierflg)
	
	#gMinuit.FixParameter(2)

	if not opts.baseline:
	    gMinuit.FixParameter(3)
	    gMinuit.FixParameter(4)

	arglist[0] = 6000 # Number of calls to FCN before giving up. 
	arglist[1] = 0.1  # Tolerance
	gMinuit.mnexcm("MIGRAD", arglist ,2,ierflg)

	amin, edm, errdef = Double(0.18), Double(0.19), Double(1.0)
	nvpar, nparx, icstat = Long(1), Long(2), Long(3)
	gMinuit.mnstat(amin,edm,errdef,nvpar,nparx,icstat);

	gMinuit.mnmnos();
	gMinuit.mnprin(3,amin);

	finalQ, finalQ_err = Double(0), Double(0)
	finalU, finalU_err = Double(0), Double(0)
	finalRM, finalRM_err = Double(0), Double(0)
	A, A_err = Double(0), Double(0)
	B, B_err = Double(0), Double(0)
	print "\n\n"

	gMinuit.GetParameter(0, finalQ, finalQ_err)
	gMinuit.GetParameter(1, finalU, finalU_err)
	gMinuit.GetParameter(2, finalRM, finalRM_err)
	gMinuit.GetParameter(3, A, A_err)
	gMinuit.GetParameter(4, B, B_err)

	finalRM *= -1.

	print finalQ, finalU
	line1 =  "Final RM: %.1f"%(finalRM) + "(+/-) %.1f "%(finalRM_err) + " (2-sig)    "
	line2 = "Chi**2r = %.2f"%(get_chi2((finalQ,finalU,-finalRM,A,B)) / ( 2*pv.size - 3 - 1 -2))
	print line1
	print line2
        f.text( .5, 0.92, line1 + line2, horizontalalignment='center') 

	print MJD, np.mean(freqs), finalRM, finalRM_err, get_chi2((finalQ,finalU,finalRM,A,B)), 2*pv.count()

	# Plot best fit model
	finalRM *= -1.
	pylab.subplot(325)
	pylab.plot(freqs, np.real( -A+getPV(finalQ+1j*finalU, finalRM) ))

	pylab.subplot(326)
	pylab.plot(freqs, np.imag( -B+getPV(finalQ+1j*finalU, finalRM) ))

    pylab.show()
コード例 #4
0
def bkgfit(data_hist,
           bkgfunction,
           bkgname,
           doFloatZ=False,
           signal_hist=None,
           z_hist=None):
    isBkgPlusZFit = False
    isSpuriousFit = False

    binning = HistBinsToList(data_hist)
    data_x = HistToList(data_hist)
    data_error = HistErrorList(data_hist)

    z_x = []
    signal_x = []

    if z_hist != None:
        isBkgPlusZFit = True
        z_x = HistToList(z_hist)

    if signal_hist != None:
        isSpuriousFit = True
        signal_x = HistToList(signal_hist)

    parfunction = bkgfunction.GetNumberFreeParameters()
    partot = bkgfunction.GetNumberFreeParameters() + 2

    ### the fucntion used for TMinuit
    def fcn(npar, gin, f, par, ifag):
        L = 0

        # calculate likelihood, input par[0] is the N_B, par[1] is N_C, par[2] is N_L
        for ibin in range(len(binning)):
            if (data_x[ibin] < 0.5):
                continue

            bincen = binning[ibin]

            bkg = 0
            data = data_x[ibin]

            if bkgname == "BernsteinO2":
                bkg = (par[0] * (1 - (bincen - fit_start) / fit_range)**2 +
                       2 * par[1] * (1 - (bincen - fit_start) / fit_range) *
                       ((bincen - fit_start) / fit_range) + par[2] *
                       ((bincen - fit_start) / fit_range)**2)

            if bkgname == "BernsteinO3":
                bkg = par[0] * (1 - (
                    (bincen - fit_start) / fit_range))**3 + par[1] * (
                        3 * ((bincen - fit_start) / fit_range) *
                        (1 -
                         ((bincen - fit_start) / fit_range))**2) + par[2] * (
                             3 * ((bincen - fit_start) / fit_range)**2 *
                             (1 -
                              ((bincen - fit_start) / fit_range))) + par[3] * (
                                  (bincen - fit_start) / fit_range)**3

            if bkgname == "BernsteinO4":
                bkg = par[0] * (1 - (
                    (bincen - fit_start) / fit_range))**4 + par[1] * (
                        4 * ((bincen - fit_start) / fit_range) *
                        (1 -
                         ((bincen - fit_start) / fit_range))**3) + par[2] * (
                             6 * ((bincen - fit_start) / fit_range)**2 *
                             (1 - ((bincen - fit_start) / fit_range))**2
                         ) + par[3] * (
                             4 * ((bincen - fit_start) / fit_range)**3 *
                             (1 -
                              ((bincen - fit_start) / fit_range))) + par[4] * (
                                  (bincen - fit_start) / fit_range)**4

            if bkgname == "BernsteinO5":
                bkg = par[0] * (1 - (
                    (bincen - fit_start) / fit_range))**5 + par[1] * (5 * (
                        (bincen - fit_start) / fit_range) * (1 - (
                            (bincen - fit_start) / fit_range))**4) + par[2] * (
                                10 * ((bincen - fit_start) / fit_range)**2 *
                                (1 - ((bincen - fit_start) / fit_range))**3
                            ) + par[3] * (10 * (
                                (bincen - fit_start) / fit_range)**3 * (1 - (
                                    (bincen - fit_start) / fit_range
                                ))**2) + par[4] * (5 * (
                                    (bincen - fit_start) / fit_range)**4 *
                                                   (1 -
                                                    ((bincen - fit_start) /
                                                     fit_range))) + par[5] * (
                                                         (bincen - fit_start) /
                                                         fit_range)**5

            if bkgname == "BernsteinO6":
                bkg = (par[0] * (1 - ((bincen - fit_start) / fit_range))**6 +
                       par[1] * (6 * ((bincen - fit_start) / fit_range)**1 *
                                 (1 - ((bincen - fit_start) / fit_range))**5) +
                       par[2] * (15 * ((bincen - fit_start) / fit_range)**2 *
                                 (1 - ((bincen - fit_start) / fit_range))**4) +
                       par[3] * (20 * ((bincen - fit_start) / fit_range)**3 *
                                 (1 - ((bincen - fit_start) / fit_range))**3) +
                       par[4] * (15 * ((bincen - fit_start) / fit_range)**4 *
                                 (1 - ((bincen - fit_start) / fit_range))**2) +
                       par[5] * (6 * ((bincen - fit_start) / fit_range)**5 *
                                 (1 - ((bincen - fit_start) / fit_range))**1) +
                       par[6] * ((bincen - fit_start) / fit_range)**6)

            if bkgname == "ExpoBernsteinO2":
                try:
                    bkg = exp(par[0] * (bincen - fit_start) / fit_range) * (
                        par[1] *
                        (1 -
                         (bincen - fit_start) / fit_range)**2 + 2 * par[2] *
                        (1 - (bincen - fit_start) / fit_range) *
                        ((bincen - fit_start) / fit_range) + par[3] *
                        ((bincen - fit_start) / fit_range)**2)
                except OverflowError:
                    bkg = 0

            if bkgname == "ExpoBernsteinO3":
                try:
                    bkg = exp(par[0] * (bincen - fit_start) / fit_range) * (
                        par[1] *
                        (1 - ((bincen - fit_start) / fit_range))**3 + par[2] *
                        (3 * ((bincen - fit_start) / fit_range) *
                         (1 -
                          ((bincen - fit_start) / fit_range))**2) + par[3] *
                        (3 * ((bincen - fit_start) / fit_range)**2 *
                         (1 - ((bincen - fit_start) / fit_range))) + par[4] *
                        ((bincen - fit_start) / fit_range)**3)
                except OverflowError:
                    bkg = 0

            if bkgname == "ExpoBernsteinO4":
                try:
                    bkg = exp(par[0] * (bincen - fit_start) / fit_range) * (
                        par[1] *
                        (1 - ((bincen - fit_start) / fit_range))**4 + par[2] *
                        (4 * ((bincen - fit_start) / fit_range) *
                         (1 -
                          ((bincen - fit_start) / fit_range))**3) + par[3] *
                        (6 * ((bincen - fit_start) / fit_range)**2 *
                         (1 -
                          ((bincen - fit_start) / fit_range))**2) + par[4] *
                        (4 * ((bincen - fit_start) / fit_range)**3 *
                         (1 - ((bincen - fit_start) / fit_range))) + par[5] *
                        ((bincen - fit_start) / fit_range)**4)
                except OverflowError:
                    bkg = 0

            if bkgname == "ExpoBernsteinO5":
                try:
                    bkg = exp(par[0] * (bincen - fit_start) / fit_range) * (
                        par[1] *
                        (1 - ((bincen - fit_start) / fit_range))**5 + par[2] *
                        (5 * ((bincen - fit_start) / fit_range) *
                         (1 -
                          ((bincen - fit_start) / fit_range))**4) + par[3] *
                        (10 * ((bincen - fit_start) / fit_range)**2 *
                         (1 -
                          ((bincen - fit_start) / fit_range))**3) + par[4] *
                        (10 * ((bincen - fit_start) / fit_range)**3 *
                         (1 -
                          ((bincen - fit_start) / fit_range))**2) + par[5] *
                        (5 * ((bincen - fit_start) / fit_range)**4 *
                         (1 - ((bincen - fit_start) / fit_range))) + par[6] *
                        ((bincen - fit_start) / fit_range)**5)
                except OverflowError:
                    bkg = 0

            if bkgname == "ExpoPolO2":
                bkg = exp(-(par[0] + par[1] *
                            ((bincen - fit_start) / fit_range) + par[2] *
                            ((bincen - fit_start) / fit_range)**2))

            if bkgname == "ExpoPolO3":
                bkg = exp(-(par[0] + par[1] *
                            ((bincen - fit_start) / fit_range) + par[2] *
                            ((bincen - fit_start) / fit_range)**2 + par[3] *
                            ((bincen - fit_start) / fit_range)**3))

            if bkgname == "ExpoPolO4":
                bkg = exp(-(par[0] + par[1] *
                            ((bincen - fit_start) / fit_range) + par[2] *
                            ((bincen - fit_start) / fit_range)**2 + par[3] *
                            ((bincen - fit_start) / fit_range)**3 + par[4] *
                            ((bincen - fit_start) / fit_range)**4))

            mu_x = bkg

            #if isBkgPlusZFit:
            #    mu_x = mu_x + (par[partot-1] *z_x[ibin])

            if isSpuriousFit:
                mu_x = mu_x + par[partot - 2] * signal_x[ibin]

            #L = L + mu_x - data*log(mu_x)

            L = L + ((mu_x - data) / data_error[ibin])**2

        f[0] = L

    # initialize the TMinuit object
    arglist_p = 10 * [0]

    arglist = array.array('d')
    arglist.fromlist(arglist_p)
    ierflag = Long(0)
    maxiter = 1000000000

    arglist_p = [1]
    gMinuit = TMinuit(partot)
    gMinuit.mnexcm('SET PRIntout', arglist, 0, ierflag)

    gMinuit.SetPrintLevel(1)
    gMinuit.SetErrorDef(1.0)
    gMinuit.SetFCN(fcn)

    arglist_p = [2]
    arglist = array.array('d')
    arglist.fromlist(arglist_p)
    gMinuit.mnexcm('SET STRategy', arglist, 1, ierflag)

    arglist_p = [maxiter, 0.0000001]
    arglist = array.array('d')
    arglist.fromlist(arglist_p)
    gMinuit.mnexcm('MIGrad', arglist, 2, ierflag)
    gMinuit.SetMaxIterations(maxiter)

    # initialize fitting the variables
    vstart = [100.0] * partot
    # start alpha_z with 1
    vstart[partot - 1] = 1.0
    vstart[partot - 2] = 0

    step = [0.1] * partot
    upper = [100000] * partot
    lower = [0.1] * partot
    varname = []

    if "ExpoPol" in bkgname:
        upper = [1000] * partot
        lower = [-1000] * partot

    if "ExpoBernstein" in bkgname:
        vstart[0] = -1
        upper[0] = 0
        lower[0] = -10

    for i in range(parfunction):
        varname.append("p" + str(i))

    varname.append("alpha_sig")
    varname.append("alpha_z")

    if doFloatZ:
        vstart[partot - 1] = 1.0
        upper[partot - 1] = 2
        lower[partot - 1] = 0
        step[partot - 1] = 0.01

    if isSpuriousFit:
        upper[partot - 2] = 10.0
        lower[partot - 2] = -10.0
        step[partot - 2] = 0.1
        vstart[partot - 2] = 1

    for i in range(partot):
        gMinuit.mnparm(i, varname[i], vstart[i], step[i], lower[i], upper[i],
                       ierflag)

    if not isSpuriousFit:
        vstart[partot - 2] = 0
        gMinuit.FixParameter(partot - 2)

    if not doFloatZ:
        lower[partot - 1] = 1
        upper[partot - 1] = 1
        gMinuit.FixParameter(partot - 1)

    if not isBkgPlusZFit:
        vstart[partot - 1] = 0.0
        gMinuit.FixParameter(partot - 1)

    # fitting procedure
    migradstat = gMinuit.Command('MIGrad ' + str(maxiter) + ' ' + str(0.001))
    improvestat = gMinuit.Command('IMProve ' + str(maxiter) + ' ' + str(0.01))

    for i in range(partot):
        arglist_p.append(i + 1)

    arglist = array.array('d')
    arglist.fromlist(arglist_p)

    #gMinuit.mnmnos()

    # get fitting parameters
    fitval_p = [Double(0)] * partot
    fiterr_p = [Double(0)] * partot
    errup_p = [Double(0)] * partot
    errdown_p = [Double(0)] * partot
    eparab_p = [Double(0)] * partot
    gcc_p = [Double(0)] * partot

    fmin_p = [Double(0)]
    fedm_p = [Double(0)]
    errdef_p = [Double(0)]
    npari_p = Long(0)
    nparx_p = Long(0)
    istat_p = Long(0)

    fitval = array.array('d')
    fiterr = array.array('d')
    errup = array.array('d')
    errdown = array.array('d')
    eparab = array.array('d')
    gcc = array.array('d')

    for i in range(partot):
        gMinuit.GetParameter(i, fitval_p[i], fiterr_p[i])
        fitval.append(fitval_p[i])
        fiterr.append(fiterr_p[i])
        errup.append(errup_p[i])
        errdown.append(errdown_p[i])
        eparab.append(eparab_p[i])
        gcc.append(gcc_p[i])

    gMinuit.mnstat(fmin_p[0], fedm_p[0], errdef_p[0], npari_p, nparx_p,
                   istat_p)

    for p in range(bkgfunction.GetNumberFreeParameters()):
        bkgfunction.SetParameter(p, fitval[p])
        print "fit uncert", fiterr_p[p]

    bkgfunction.SetChisquare(fmin_p[0])

    return fitval[partot - 1], fitval[partot - 2]
コード例 #5
0
class Fits:
    def __init__(self):

        self.p_n = [
            0,
        ] * 100
        self.e_n = [
            0,
        ] * 100
        self.stored_parameters = [
            0,
        ] * 100

        self.num_bins = 0
        self.xmins = []
        self.xmaxes = []

        self.data = []
        self.errors = []
        self.data_fits = []

        self.model_scale_values = []
        self.final = False

        self.exclude_regions = ((0, 0), )

        self.col1 = 1
        self.col2 = TColor.GetColor(27, 158, 119)
        self.col3 = TColor.GetColor(217, 95, 2)
        self.col4 = TColor.GetColor(117, 112, 179)

    def run_mass_fit(self, peak_scale_initial):
        self.gMinuit = TMinuit(30)
        self.gMinuit.SetPrintLevel(-1)
        self.gMinuit.SetFCN(self.Fitfcn_max_likelihood)

        self.fit_failed = False

        arglist = array("d", [
            0,
        ] * 10)
        ierflg = ROOT.Long(0)
        arglist[0] = ROOT.Double(1)

        # peak_scale_initial = ROOT.Double(peak_scale_initial)

        tmp = array("d", [
            0,
        ])
        self.gMinuit.mnexcm("SET NOWarnings", tmp, 0, ierflg)

        self.gMinuit.mnexcm("SET ERR", arglist, 1, ierflg)
        self.gMinuit.mnparm(0, "p1", 30, 20, 0, 100, ierflg)
        self.gMinuit.mnparm(1, "p2", 10, 1, 0, 0, ierflg)
        self.gMinuit.mnparm(2, "p3", -5.3, 1, 0, 0, ierflg)
        self.gMinuit.mnparm(3, "p4", -4e-2, 1e-2, 0, 0, ierflg)
        self.gMinuit.mnparm(4, "p5", peak_scale_initial, 1, 0, 10000, ierflg)

        self.background_fit_only = [
            0,
        ] * len(self.data)

        arglist[0] = ROOT.Double(0)
        arglist[1] = ROOT.Double(0)

        #self.exclude_regions = ((2.2, 3.3),)
        self.gMinuit.FixParameter(1)
        self.gMinuit.FixParameter(2)
        self.gMinuit.FixParameter(3)
        self.gMinuit.FixParameter(4)

        self.gMinuit.mnexcm("simplex", arglist, 2, ierflg)
        self.gMinuit.mnexcm("MIGRAD", arglist, 2, ierflg)
        print("Run fit 0")
        if self.fit_failed:
            print("Fit failed, returning")
            return None, None

        self.gMinuit.Release(1)
        self.gMinuit.mnexcm("simplex", arglist, 2, ierflg)
        self.gMinuit.mnexcm("MIGRAD", arglist, 2, ierflg)
        print("Run fit 1")
        if self.fit_failed:
            print("Fit failed, returning")
            return None, None

        self.gMinuit.Release(2)
        self.gMinuit.mnexcm("simplex", arglist, 2, ierflg)
        self.gMinuit.mnexcm("MIGRAD", arglist, 2, ierflg)
        print("Run fit 2")
        if self.fit_failed:
            print("Fit failed, returning")
            return None, None

        self.gMinuit.Release(3)
        self.gMinuit.mnexcm("simplex", arglist, 2, ierflg)
        self.gMinuit.mnexcm("MIGRAD", arglist, 2, ierflg)
        print("Run fit 3")
        if self.fit_failed:
            print("Fit failed, returning")
            return None, None

        # Find an actual best fit
        #self.exclude_regions = ((0, 2), (3.3, 100),)
        self.gMinuit.FixParameter(0)
        self.gMinuit.FixParameter(1)
        self.gMinuit.FixParameter(2)
        self.gMinuit.FixParameter(3)
        self.gMinuit.Release(4)
        self.gMinuit.mnexcm("simplex", arglist, 2, ierflg)
        self.gMinuit.mnexcm("MIGRAD", arglist, 2, ierflg)
        print("Run fit 4")
        if self.fit_failed:
            print("Fit failed, returning")
            return None, None

        self.exclude_regions = ()
        self.gMinuit.Release(0)
        self.gMinuit.Release(1)
        self.gMinuit.Release(2)
        self.gMinuit.Release(3)
        self.gMinuit.mnexcm("simplex", arglist, 2, ierflg)
        self.gMinuit.mnexcm("MIGRAD", arglist, 2, ierflg)

        print("Run last fitting stage")
        if self.fit_failed:
            print("Fit failed, returning")
            return None, None

        best_fit_value = ROOT.Double(0)
        self.gMinuit.mnstat(best_fit_value, ROOT.Double(0), ROOT.Double(0),
                            ROOT.Long(0), ROOT.Long(0), ROOT.Long(0))
        #print("Best fit value", best_fit_value)

        # And prepare for iterating over fit values for N injected events
        self.gMinuit.Release(0)
        self.gMinuit.Release(1)
        self.gMinuit.Release(2)
        self.gMinuit.Release(3)
        self.exclude_regions = ()

        #self.data_fits = no_peak_data_fits
        x_values = []
        y_values = []

        for i in range(0, 5):
            p = ROOT.Double(0)
            self.gMinuit.GetParameter(i, p, ROOT.Double(0))
            print("Parameter", i, p)

        fitted_N = ROOT.Double(0)
        self.gMinuit.GetParameter(4, fitted_N, ROOT.Double(0))
        best_fit_likelihood = self.calc_likelihood(fitted_N)

        self.iflag = int(ierflg)
        print("iflag:", self.iflag)

        step = 5
        if int(MASS_FILE) >= 4000:
            step = 1
        if int(MASS_FILE) >= 5000:
            step = 0.2
        if int(MASS_FILE) >= 6000:
            step = 0.1
        if int(MASS_FILE) >= 6500:
            step = 0.1
        N = 0
        print("About to start likelihood testing loop")
        while N < 10000:
            start_sum = sum([math.exp(-a) for a in y_values])
            fit_likelihood = self.calc_likelihood(N)
            if fit_likelihood is None:
                print("Bad fit_likelihood")
                return None, None
            x_values.append(N)
            y_values.append(fit_likelihood - best_fit_likelihood)

            probabilities = [math.exp(-a) for a in y_values]
            end_sum = sum(probabilities)

            max_prob = max(probabilities)
            if max_prob == 0:
                print("max_prob == 0")
                return None, None
            normalised_probabilities = [a / max_prob for a in probabilities]

            if N / step > 50 and all(
                [v > 0.99 for v in normalised_probabilities]):
                print(
                    "Probability=1 everywhere, probably something wrong with fit"
                )
                print(normalised_probabilities)
                return None, None

            # if new value changes total by less than 0.1%, end loop
            if N > 0 and (end_sum - start_sum) / start_sum < 0.0001:
                print("Iterated up to {0}".format(N))
                break

            N += step

        self.iflag = int(ierflg)
        return x_values, y_values

    def Fitfcn_max_likelihood(self, npar, gin, fcnVal, par, iflag):
        likelihood = 0
        mf = ROOT.MyMassSpectrum()
        mf.SetParameters(par)
        ig = GaussIntegrator()
        ig.SetFunction(mf)
        ig.SetRelTolerance(0.00001)

        for i in range(0, self.num_bins):
            for lower, higher in self.exclude_regions:
                if lower < self.xmins[i] < higher:
                    continue

            model_val = ig.Integral(self.xmins[i], self.xmaxes[i]) / (
                self.xmaxes[i] - self.xmins[i])
            self.background_fit_only[i] = model_val
            model_val += self.model_scale_values[i] * par[4]
            self.data_fits[i] = model_val

            mv = model_val
            di = self.data[i]

            #print("mv", mv, "di", di)
            #sys.stdout.flush()
            if di > 1e10 or math.isinf(mv) or math.isnan(mv):
                self.fit_failed = True
                return

            likelihood += mv - di
            if di > 0 and mv > 0:
                likelihood += di * (TMath.Log(di) - TMath.Log(mv))
            #sys.stderr.flush()

        fcnVal[0] = likelihood

    def calc_likelihood(self, peak_scale):
        like = 0

        for i in range(0, self.num_bins):
            if self.data_fits[i] <= 0:
                continue

            p = peak_scale * self.model_scale_values[i]
            tmp = ROOT.TMath.PoissonI(self.data[i],
                                      self.background_fit_only[i] + p)
            if tmp == 0:
                return None
                print("tmp == 0 here")
                logtmp = math.log(sys.float_info.min)
            else:
                logtmp = math.log(tmp)
            like += logtmp

        return -like