コード例 #1
0
    def test1MinuitFit(self):
        """Test minuit callback and fit"""

        # setup minuit and callback
        gMinuit = TMinuit(5)
        gMinuit.SetPrintLevel(-1)  # quiet
        gMinuit.SetGraphicsMode(ROOT.kFALSE)
        gMinuit.SetFCN(fcn)

        arglist = array('d', 10 * [0.])
        ierflg = Long()

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

        # set starting values and step sizes for parameters
        vstart = array('d', [3, 1, 0.1, 0.01])
        step = array('d', [0.1, 0.1, 0.01, 0.001])
        gMinuit.mnparm(0, "a1", vstart[0], step[0], 0, 0, ierflg)
        gMinuit.mnparm(1, "a2", vstart[1], step[1], 0, 0, ierflg)
        gMinuit.mnparm(2, "a3", vstart[2], step[2], 0, 0, ierflg)
        gMinuit.mnparm(3, "a4", vstart[3], step[3], 0, 0, ierflg)

        # now ready for minimization step
        arglist[0] = 500
        arglist[1] = 1.
        gMinuit.mnexcm("MIGRAD", arglist, 2, ierflg)

        # verify results
        amin, edm, errdef = Double(), Double(), Double()
        nvpar, nparx, icstat = Long(), Long(), Long()
        gMinuit.mnstat(amin, edm, errdef, nvpar, nparx, icstat)
        # gMinuit.mnprin( 3, amin )

        self.assertEqual(nvpar, 4)
        self.assertEqual(nparx, 4)

        # success means that full covariance matrix is available (icstat==3)
        self.assertEqual(icstat, 3)

        # check results (somewhat debatable ... )
        par, err = Double(), Double()

        gMinuit.GetParameter(0, par, err)
        self.assertEqual(round(par - 2.15, 2), 0.)
        self.assertEqual(round(err - 0.10, 2), 0.)

        gMinuit.GetParameter(1, par, err)
        self.assertEqual(round(par - 0.81, 2), 0.)
        self.assertEqual(round(err - 0.25, 2), 0.)

        gMinuit.GetParameter(2, par, err)
        self.assertEqual(round(par - 0.17, 2), 0.)
        self.assertEqual(round(err - 0.40, 2), 0.)

        gMinuit.GetParameter(3, par, err)
        self.assertEqual(round(par - 0.10, 2), 0.)
        self.assertEqual(round(err - 0.16, 2), 0.)
コード例 #2
0
   def test1MinuitFit( self ):
      """Test minuit callback and fit"""

    # setup minuit and callback
      gMinuit = TMinuit(5)
      gMinuit.SetPrintLevel( -1 )            # quiet
      gMinuit.SetGraphicsMode( ROOT.kFALSE )
      gMinuit.SetFCN( fcn )

      arglist = array( 'd', 10*[0.] )
      ierflg = Long()

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

    # set starting values and step sizes for parameters
      vstart = array( 'd', [ 3,  1,  0.1,  0.01  ] )
      step   = array( 'd', [ 0.1, 0.1, 0.01, 0.001 ] )
      gMinuit.mnparm( 0, "a1", vstart[0], step[0], 0, 0, ierflg )
      gMinuit.mnparm( 1, "a2", vstart[1], step[1], 0, 0, ierflg )
      gMinuit.mnparm( 2, "a3", vstart[2], step[2], 0, 0, ierflg )
      gMinuit.mnparm( 3, "a4", vstart[3], step[3], 0, 0, ierflg )

    # now ready for minimization step
      arglist[0] = 500
      arglist[1] = 1.
      gMinuit.mnexcm( "MIGRAD", arglist, 2, ierflg )

    # verify results
      amin, edm, errdef = Double(), Double(), Double()
      nvpar, nparx, icstat = Long(), Long(), Long()
      gMinuit.mnstat( amin, edm, errdef, nvpar, nparx, icstat )
    # gMinuit.mnprin( 3, amin )

      self.assertEqual( nvpar, 4 )
      self.assertEqual( nparx, 4 )

    # success means that full covariance matrix is available (icstat==3)
      self.assertEqual( icstat, 3 )

    # check results (somewhat debatable ... )
      par, err = Double(), Double()

      gMinuit.GetParameter( 0, par, err )
      self.assertEqual( round( par - 2.15, 2 ), 0. )
      self.assertEqual( round( err - 0.10, 2 ), 0. )

      gMinuit.GetParameter( 1, par, err )
      self.assertEqual( round( par - 0.81, 2 ), 0. )
      self.assertEqual( round( err - 0.25, 2 ), 0. )

      gMinuit.GetParameter( 2, par, err )
      self.assertEqual( round( par - 0.17, 2 ), 0. )
      self.assertEqual( round( err - 0.40, 2 ), 0. )

      gMinuit.GetParameter( 3, par, err )
      self.assertEqual( round( par - 0.10, 2 ), 0. )
      self.assertEqual( round( err - 0.16, 2 ), 0. )
コード例 #3
0
ファイル: Fitting.py プロジェクト: phy6phs/DailyPythonScripts
    def fit(self):
        numberOfParameters = len(self.samples)
        gMinuit = TMinuit(numberOfParameters)
        if self.method == "logLikelihood":  # set function for minimisation
            gMinuit.SetFCN(self.logLikelihood)
        gMinuit.SetPrintLevel(-1)
        # Error definition: 1 for chi-squared, 0.5 for negative log likelihood
        gMinuit.SetErrorDef(1)
        # error flag for functions passed as reference.set to as 0 is no error
        errorFlag = Long(2)

        N_total = self.normalisation[self.data_label] * 2
        N_min = 0

        param_index = 0
        for sample in self.samples:  # all samples but data
            gMinuit.mnparm(param_index, sample, self.normalisation[sample], 10.0, N_min, N_total, errorFlag)
            param_index += 1

        #        N_signal = self.normalisation['signal']
        #        gMinuit.mnparm(0, "N_signal(ttbar+single_top)", N_signal, 10.0, N_min, N_total, errorFlag)
        #        gMinuit.mnparm(1, "bkg1", 10, 10.0, N_min, N_total, errorFlag)

        arglist = array("d", 10 * [0.0])
        # minimisation strategy: 1 standard, 2 try to improve minimum (a bit slower)
        arglist[0] = 2
        # minimisation itself
        gMinuit.mnexcm("SET STR", arglist, 1, errorFlag)
        gMinuit.Migrad()
        self.module = gMinuit
        self.performedFit = True

        if not self.module:
            raise Exception("No fit results available. Please run fit method first")

        results = {}
        param_index = 0
        for sample in self.samples:
            temp_par = Double(0)
            temp_err = Double(0)
            self.module.GetParameter(param_index, temp_par, temp_err)
            if math.isnan(temp_err):
                self.logger.warning("Template fit error is NAN, setting to sqrt(N).")
                temp_err = math.sqrt(temp_par)

            results[sample] = (temp_par, temp_err)
            param_index += 1

        self.results = results
コード例 #4
0
def runMinuit(numParameters):
  minuit = TMinuit(numParameters)
  minuit.SetPrintLevel(0) 
  
  minuit.SetFCN(fcn)
  arglist = np.zeros(numParameters) + 0.01
  internalFlag, arglist[0] = Long(0), 0.5
  minuit.mnexcm("SET ERR", arglist, 1, internalFlag)
  
  initialValues = np.zeros(numParameters) + 0.01
  steps = np.zeros(numParameters) + 0.0001
  
  for i in xrange(numParameters):
    name = "epsilon%s" % i
    minuit.mnparm(i, name, initialValues[i], steps[i], 0, 1, internalFlag)
  
  # arglist[0] = 2
  # minuit.mnexcm("SET STR", arglist, 1, internalFlag)
  
  arglist[0], arglist[1] = 10000, 0.1
  minuit.mnexcm("SIMPLEX", arglist, 1, internalFlag)
  minuit.mnexcm("MIGRAD", arglist, 1, internalFlag)
  
  print "FIT STATUS is " +str(minuit.GetStatus())
  return ratesAndErrors(numParameters, minuit)
コード例 #5
0
ファイル: ProfileL.py プロジェクト: diegoasanz/HiggsProjekt
 def fit_mu(self, background, signal):
     myMinuit = TMinuit(self.npar)
     myMinuit.SetFCN(self.fcn)
     gMinuit.Command('SET PRINT -1')
     ierflg = Long(0)
     myMinuit.mnparm(0, 'mu', self.start_value_mu, self.init_step_mu, self.min_mu, self.max_mu, ierflg)
     arglist = array('d', (0, 0))
     arglist[0] = self.max_iterations
     arglist[1] = self.tolerance
     myMinuit.mnexcm("MINIMIZE", arglist, 2, ierflg)
     # check TMinuit status
     amin, edm, errdef = Double(0.), Double(0.), Double(0.)
     nvpar, nparx, icstat = Long(0), Long(0), Long(0)
     myMinuit.mnstat(amin, edm, errdef, nvpar, nparx, icstat)
     # get final results
     p, pe = Double(0), Double(0)
     myMinuit.GetParameter(0, p, pe)
     # finalPar = float(p)
     # finalParErr = float(pe)
     # print_banner('MINUIT fit completed:')
     # print ' fcn@minimum = %.3g' %(amin)," error code =", ierflg, " status =", icstat
     # print " Results: \t value error"
     # print ' %s: \t%10.3e +/- %.1e '%('mu', finalPar, finalParErr)
     return p
コード例 #6
0
ファイル: kinfit.py プロジェクト: eminizer/Reconstructor
	def dofit(self) :
		#print 'starting fit for hypothesis index %d'%(self.fitindex)#DEBUG
		#set up the minuit object, etc.
		parNames = ['fitindex','pZv','scalelep','scaleblep','scalehad1','scalehad2','scalehad3']
		parinivals = [self.fitindex,0.,1.,1.,1.,1.,1.]
		parerrs = [0.0,0.0,0.0,0.0,0.0,0.0,0.0]
		bestParValues = []
		nPars = 6 if self.topology==1 else 7
		for i in range(1,nPars) :
			bestParValues.append(parinivals[i])
		ierflag = Long(1)
		arglist = array( 'd', [-1.0] )
		minuit = TMinuit(nPars)
		minuit.mnexcm('SET PRINT', arglist, 1,ierflag)
		minuit.mnexcm('SET NOWARNINGS',arglist,1,ierflag)
		arglist[0] = 100000.
		#add parameters to the fitter
		for i in range(nPars) :
			minuit.mnparm(i,parNames[i],parinivals[i],1.0,0.,0.,ierflag)
		#fix the first 'fit index' parameter
		minuit.mnfixp(0,ierflag)
		#set the minimization function to use
		if self.topology==1 : minuit.SetFCN(fcnt1)
		elif self.topology==2 : minuit.SetFCN(fcnt2)
		elif self.topology==3 : minuit.SetFCN(fcnt3)
		#minimize and get the error flag
		minuit.mnexcm('MIGRAD', arglist, 1, ierflag)
		#print 'index = %d, errflag = %s'%(self.fitindex,ierflag) #DEBUG
		errflag = int(ierflag)
		#Check fit Chi2 
		tmp1 = Double(1.0); tmp2 = Double(1.0); tmp3 = Double(1.0)
		minuit.mnstat(tmp1,tmp2,tmp3,Long(1),Long(1),Long(1))
		#print 'chi2 = %.4f'%(tmp1) #DEBUG
		chi2value = float(tmp1)
		#Get the bestfit parameters back from minuit
		for j in range(1,nPars) :
			tmp = Double(1.0)
			minuit.GetParameter(j,tmp,Double(parerrs[j]))
			bestParValues[j-1] = float(tmp)
		return errflag, chi2value, bestParValues
コード例 #7
0
    def prepareAndRunOptimizer(self,
                               xValues,
                               yValues,
                               erryValues,
                               fixParams,
                               optFunction,
                               parValues,
                               parNames,
                               printOutLevel=0):
        self.xValues = xValues
        self.yValues = yValues
        self.erryValues = erryValues
        self.fixParams = fixParams

        initialError = 0.1

        nBins = len(self.xValues)
        gMinuit = TMinuit(nBins)
        gMinuit.SetFCN(optFunction)

        arglist = array('d', nBins * [0])
        ierflg = c_int(0)

        arglist[0] = 1  # 1 for chi2, 0.5 for likelihood
        gMinuit.mnexcm('SET ERR', arglist, 1, ierflg)

        # Set starting values and step sizes for parameters
        vStart = parValues
        vStep = [initialError for i in range(len(parValues))]
        for i, name in enumerate(parNames):
            gMinuit.mnparm(i, name, vStart[i], vStep[i], 0, 0, ierflg)

        # Fix parameters (counting from 1)
        for i, fix in enumerate(self.fixParams):
            arglist[i] = fix + 1
        gMinuit.mnexcm('FIX', arglist, len(self.fixParams), ierflg)

        # Define printout level
        arglist[0] = printOutLevel
        # -1 = no output except from SHOW
        #  0 = minimum output (no starting values or intermediate results) default value, normal output
        #  1 = additional output giving intermediate results.
        #  2 = maximum output, showing progress of minimizations.
        gMinuit.mnexcm('SET PRI', arglist, 1, ierflg)

        # Now ready for minimization step
        arglist[0] = 5000  # Max calls
        arglist[1] = 0.1  # Tolerance
        gMinuit.mnexcm('MIGRAD', arglist, 2, ierflg)

        # Print results
        self.dof = self.nMeas - len(parValues) + len(self.fixParams)
        fmin, fedm, errdef = c_double(0.), c_double(0.), c_double(0.)
        npari, nparx, istat = c_int(0), c_int(0), c_int(0)
        gMinuit.mnstat(fmin, fedm, errdef, npari, nparx, istat)
        print('\nFMIN:', round(fmin.value,
                               2), '\tFEDM:', '{:.1e}'.format(fedm.value),
              '\tERRDEF:', errdef.value, '\tNPARI:', npari.value, '\tNPARX:',
              nparx.value, '\tISTAT:', istat.value)
        print('chi-2:', round(self.chi2, 2), '\td.o.f.:', self.dof,
              '\tchi-2/d.o.f.:', round(self.chi2 / self.dof, 2), '\n')

        return gMinuit, istat
コード例 #8
0
X_predictions_for_fit = np.column_stack([x for x in X_predicted_all])



mpvs=[]

print 'here'
fit_quantile=[]
gMinuit = TMinuit(4)
gMinuit.SetPrintLevel(-1)
gMinuit.SetFCN( fcn )
arglist = np.array( 10*[0.] )
ierflg = 0 
arglist[0] = 1
gMinuit.mnexcm( "SET ERR", arglist, 1, Long(ierflg) )
arglist[0] = 0
gMinuit.mnexcm("SET PRINT", arglist ,0,Long(ierflg));
vstart = np.array( [  -2 , 4,-1, 0.5] )
step   = np.array(  [ 0.001, 0.001, 0.01, 0.01 ] )
gMinuit.mnparm( 0, "a1", vstart[0], step[0], 0, 0, Long(ierflg) )
gMinuit.mnparm( 1, "a2", vstart[1], step[1], 0, 0, Long(ierflg) )
gMinuit.mnparm( 2, "a3", vstart[2], step[2], 0, 0, Long(ierflg) )
gMinuit.mnparm( 3, "a4", vstart[3], step[3], 0, 0, Long(ierflg) )
arglist[0] = 500
arglist[1] = 1.
fParamVal = Double(0.)
fParamErr = Double(0.)
for i in range(5):
	changeme(X_predictions_for_fit[i])
	gMinuit.mnexcm( "MIGRAD", arglist, 2, Long(ierflg) )
コード例 #9
0
s = error_w1[3]*error_w2[3]
t = error_w1[4]*error_w2[4]

global kor_matirx
kor_matirx = np.array([[g1, s+t], [ s+t, g2]])
kor_matirx_inv = inv(kor_matirx)
print kor_matirx

# --> set up MINUIT
myMinuit = TMinuit(npar)  # initialize TMinuit with maximum of npar parameters
myMinuit.SetFCN(fcn)      # set function to minimize
arglist = arr('d', 2*[0.01]) # set error definition 
ierflg = Long(0)             
arglist[0] = 1.              # 1 sigma is Delta chi^2 = 1
myMinuit.mnexcm("SET ERR", arglist ,1,ierflg)


# --> Set starting values and step sizes for parameters
# Define the parameters for the fit
myMinuit.mnparm(1, "mean", 400, 0.001, 0,0,ierflg)

arglist[0] = 6000 # Number of calls to FCN before giving up.
arglist[1] = 0.3  # Tolerance
myMinuit.mnexcm("MIGRAD", arglist ,2,ierflg)  # execute the minimisation

# --> check TMinuit status 
amin, edm, errdef = Double(0.), Double(0.), Double(0.)
nvpar, nparx, icstat = Long(0), Long(0), Long(0)
myMinuit.mnstat(amin,edm,errdef,nvpar,nparx,icstat)
# meaning of parameters:
コード例 #10
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
コード例 #11
0
def signalfit(data_hist, signalfunction, signalname, process):

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

    parfunction = signalfunction.GetNumberFreeParameters()
    partot = signalfunction.GetNumberFreeParameters()
    print partot

    ### 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):
            #    continue

            bincen = binning[ibin]

            mu_x = 0
            data = data_x[ibin]
            if data_error[ibin] == 0:
                continue
            #if data<0.1:
            #    continue

            if signalname == "CrystalBall":

                if par[3] < 0:
                    mu_x = 0

                else:
                    t = (bincen - par[2]) / (par[3])
                    if (par[0] < 0):
                        t = -t

                    absAlpha = abs(par[0])

                    if (t >= -absAlpha):
                        mu_x = par[4] * exp(-0.5 * t * t)

                    else:

                        nDivAlpha = par[1] / absAlpha
                        AA = exp(-0.5 * absAlpha * absAlpha)
                        B = nDivAlpha - absAlpha
                        arg = nDivAlpha / (B - t)

                        mu_x = par[4] * (arg**par[1])

            if signalname == "CrystalBallGaus":

                if par[3] < 0:
                    mu_x = 0

                else:
                    t = (bincen - par[2]) / (par[3])
                    if (par[0] < 0):
                        t = -t

                    absAlpha = abs(par[0])

                    if (t >= -absAlpha):
                        mu_x = par[4] * exp(-0.5 * t * t +
                                            exp(-(bincen - par[5])**2 /
                                                (2 * par[6]**2)))

                    else:

                        nDivAlpha = par[1] / absAlpha
                        AA = exp(-0.5 * absAlpha * absAlpha)
                        B = nDivAlpha - absAlpha
                        arg = nDivAlpha / (B - t)

                        mu_x = par[4] * (arg**par[1] +
                                         exp(-(bincen - par[5])**2 /
                                             (2 * par[6]**2)))

            #print mu_x, data, data_error[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 = [125.0] * partot

    step = [0.1] * partot
    upper = [1000000] * partot
    lower = [-100] * partot
    varname = []

    lower[3] = 0
    lower[4] = 0
    lower[1] = 0
    vstart[4] = data_hist.Integral()

    if process == "signal":
        vstart[2] = 125
        lower[2] = 110
        upper[2] = 140

        vstart[3] = 10
        lower[3] = 2
        upper[3] = 25

        if len(vstart) > 5:
            vstart[5] = 125
            lower[5] = 110
            upper[5] = 140

            vstart[6] = 10
            lower[6] = 5
            upper[6] = 20

    if process == "z":
        vstart[2] = 90
        lower[2] = 70
        upper[2] = 110

        vstart[3] = 10
        lower[3] = 2
        upper[3] = 30

        if len(vstart) > 5:
            vstart[5] = 90
            lower[5] = 70
            upper[5] = 110

            vstart[6] = 10
            lower[6] = 2
            upper[6] = 30

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

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

    # 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(signalfunction.GetNumberFreeParameters()):
        signalfunction.SetParameter(p, fitval[p])
        print "fit uncert", fiterr_p[p]

    signalfunction.SetChisquare(fmin_p[0])
    print fmin_p[0]
    return fitval[partot - 1], fitval[partot - 2]
コード例 #12
0
class Minuit:
    '''
    A class for communicating with ROOT's function minimizer tool Minuit.
    '''

    def __init__(self, number_of_parameters, function_to_minimize,
                 parameter_names, start_parameters, parameter_errors,
                 quiet=True, verbose=False):
        '''
        Create a Minuit minimizer for a function `function_to_minimize`.
        Necessary arguments are the number of parameters and the function to be
        minimized `function_to_minimize`. The function `function_to_minimize`'s
        arguments must be numerical values. The same goes for its output.

        Another requirement is for every parameter of `function_to_minimize` to
        have a default value. These are then used to initialize Minuit.

        **number_of_parameters** : int
            The number of parameters of the function to minimize.

        **function_to_minimize** : function
            The function which `Minuit` should minimize. This must be a Python
            function with <``number_of_parameters``> arguments.

        **parameter_names** : tuple/list of strings
            The parameter names. These are used to keep track of the parameters
            in `Minuit`'s output.

        **start_parameters** : tuple/list of floats
            The start values of the parameters. It is important to have a good,
            if rough, estimate of the parameters at the minimum before starting
            the minimization. Wrong initial parameters can yield a local
            minimum instead of a global one.

        **parameter_errors** : tuple/list of floats
            An initial guess of the parameter errors. These errors are used to
            define the initial step size.

        *quiet* : boolean (optional, default: ``True``)
            If ``True``, suppresses all output from ``TMinuit``.

        *verbose* : boolean (optional, default: ``False``)
            If ``True``, sets ``TMinuit``'s print level to a high value, so
            that all output is logged.

        '''
        #: the name of this minimizer type
        self.name = "ROOT::TMinuit"

        #: the actual `FCN` called in ``FCN_wrapper``
        self.function_to_minimize = function_to_minimize

        #: number of parameters to minimize for
        self.number_of_parameters = number_of_parameters

        if not quiet:
            self.out_file = open(log_file("minuit.log"), 'a')
        else:
            self.out_file = null_file()

        # create a TMinuit instance for that number of parameters
        self.__gMinuit = TMinuit(self.number_of_parameters)

        # instruct Minuit to use this class's FCN_wrapper method as a FCN
        self.__gMinuit.SetFCN(self.FCN_wrapper)

        # set print level according to flag
        if quiet:
            self.set_print_level(-1000)  # suppress output
        elif verbose:
            self.set_print_level(10)     # detailed output
        else:
            self.set_print_level(0)      # frugal output

        # initialize minimizer
        self.set_err()
        self.set_strategy()
        self.set_parameter_values(start_parameters)
        self.set_parameter_errors(parameter_errors)
        self.set_parameter_names(parameter_names)

        #: maximum number of iterations until ``TMinuit`` gives up
        self.max_iterations = M_MAX_ITERATIONS

        #: ``TMinuit`` tolerance
        self.tolerance = M_TOLERANCE

    def update_parameter_data(self, show_warnings=False):
        """
        (Re-)Sets the parameter names, values and step size on the
        C++ side of Minuit.
        """
        error_code = Long(0)
        try:
            # Set up the starting fit parameters in TMinuit
            for i in range(0, self.number_of_parameters):
                self.__gMinuit.mnparm(i, self.parameter_names[i],
                                      self.current_parameters[i],
                                      0.1 * self.parameter_errors[i],
                                      0, 0, error_code)
                # use 10% of the par. 1-sigma errors as the initial step size
        except AttributeError as e:
            if show_warnings:
                logger.warning("Cannot update Minuit data on the C++ side. "
                            "AttributeError: %s" % (e, ))
        return error_code

    # Set methods
    ##############

    def set_print_level(self, print_level=P_DETAIL_LEVEL):
        '''Sets the print level for Minuit.

        *print_level* : int (optional, default: 1 (frugal output))
            Tells ``TMinuit`` how much output to generate. The higher this
            value, the more output it generates.
        '''
        self.__gMinuit.SetPrintLevel(print_level)  # set Minuit print level
        self.print_level = print_level

    def set_strategy(self, strategy_id=1):
        '''Sets the strategy Minuit.

        *strategy_id* : int (optional, default: 1 (optimized))
            Tells ``TMinuit`` to use a certain strategy. Refer to ``TMinuit``'s
            documentation for available strategies.
        '''
        error_code = Long(0)
        # execute SET STRATEGY command
        self.__gMinuit.mnexcm("SET STRATEGY",
                              arr('d', [strategy_id]), 1, error_code)

    def set_err(self, up_value=1.0):
        '''Sets the ``UP`` value for Minuit.

        *up_value* : float (optional, default: 1.0)
            This is the value by which `FCN` is expected to change.
        '''
        # Tell TMinuit to use an up-value of 1.0
        error_code = Long(0)
        # execute SET ERR command
        self.__gMinuit.mnexcm("SET ERR", arr('d', [up_value]), 1, error_code)

    def set_parameter_values(self, parameter_values):
        '''
        Sets the fit parameters. If parameter_values=`None`, tries to infer
          defaults from the function_to_minimize.
        '''
        if len(parameter_values) == self.number_of_parameters:
            self.current_parameters = parameter_values
        else:
            raise Exception("Cannot get default parameter values from the \
            FCN. Not all parameters have default values given.")

        self.update_parameter_data()

    def set_parameter_names(self, parameter_names):
        '''Sets the fit parameters. If parameter_values=`None`, tries to infer
        defaults from the function_to_minimize.'''
        if len(parameter_names) == self.number_of_parameters:
            self.parameter_names = parameter_names
        else:
            raise Exception("Cannot set param names. Tuple length mismatch.")

        self.update_parameter_data()

    def set_parameter_errors(self, parameter_errors=None):
        '''Sets the fit parameter errors. If parameter_values=`None`, sets the
        error to 10% of the parameter value.'''

        if parameter_errors is None:  # set to 0.1% of the parameter value
            if not self.current_parameters is None:
                self.parameter_errors = [max(0.1, 0.1 * par)
                                         for par in self.current_parameters]
            else:
                raise Exception("Cannot set parameter errors. No errors \
                                provided and no parameters initialized.")
        elif len(parameter_errors) != len(self.current_parameters):
            raise Exception("Cannot set parameter errors. \
                            Tuple length mismatch.")
        else:
            self.parameter_errors = parameter_errors

        self.update_parameter_data()

    # Get methods
    ##############

    def get_error_matrix(self):
        '''Retrieves the parameter error matrix from TMinuit.

        return : `numpy.matrix`
        '''

        # set up an array of type `double' to pass to TMinuit
        tmp_array = arr('d', [0.0]*(self.number_of_parameters**2))
        # get parameter covariance matrix from TMinuit
        self.__gMinuit.mnemat(tmp_array, self.number_of_parameters)
        # reshape into 2D array
        return np.asmatrix(
            np.reshape(
                tmp_array,
                (self.number_of_parameters, self.number_of_parameters)
            )
        )

    def get_parameter_values(self):
        '''Retrieves the parameter values from TMinuit.

        return : tuple
            Current `Minuit` parameter values
        '''

        result = []
        # retrieve fit parameters
        p, pe = Double(0), Double(0)

        for i in range(0, self.number_of_parameters):
            self.__gMinuit.GetParameter(i, p, pe)  # retrieve fitresult

            result.append(float(p))

        return tuple(result)

    def get_parameter_errors(self):
        '''Retrieves the parameter errors from TMinuit.

        return : tuple
            Current `Minuit` parameter errors
        '''

        result = []
        # retrieve fit parameters
        p, pe = Double(0), Double(0)

        for i in range(0, self.number_of_parameters):
            self.__gMinuit.GetParameter(i, p, pe)  # retrieve fitresult

            result.append(float(pe))

        return tuple(result)

    def get_parameter_info(self):
        '''Retrieves parameter information from TMinuit.

        return : list of tuples
            ``(parameter_name, parameter_val, parameter_error)``
        '''

        result = []
        # retrieve fit parameters
        p, pe = Double(0), Double(0)

        for i in range(0, self.number_of_parameters):
            self.__gMinuit.GetParameter(i, p, pe)  # retrieve fitresult
            result.append((self.get_parameter_name(i), float(p), float(pe)))

        return result

    def get_parameter_name(self, parameter_nr):
        '''Gets the name of parameter number ``parameter_nr``

        **parameter_nr** : int
            Number of the parameter whose name to get.
        '''

        return self.parameter_names[parameter_nr]

    def get_fit_info(self, info):
        '''Retrieves other info from `Minuit`.

        **info** : string
            Information about the fit to retrieve.
            This can be any of the following:

              - ``'fcn'``: `FCN` value at minimum,
              - ``'edm'``: estimated distance to minimum
              - ``'err_def'``: `Minuit` error matrix status code
              - ``'status_code'``: `Minuit` general status code

        '''

        # declare vars in which to retrieve other info
        fcn_at_min = Double(0)
        edm = Double(0)
        err_def = Double(0)
        n_var_param = Long(0)
        n_tot_param = Long(0)
        status_code = Long(0)

        # Tell TMinuit to update the variables declared above
        self.__gMinuit.mnstat(fcn_at_min,
                              edm,
                              err_def,
                              n_var_param,
                              n_tot_param,
                              status_code)

        if info == 'fcn':
            return fcn_at_min

        elif info == 'edm':
            return edm

        elif info == 'err_def':
            return err_def

        elif info == 'status_code':
            try:
                return D_MATRIX_ERROR[status_code]
            except:
                return status_code

    def get_chi2_probability(self, n_deg_of_freedom):
        '''
        Returns the probability that an observed :math:`\chi^2` exceeds
        the calculated value of :math:`\chi^2` for this fit by chance,
        even for a correct model. In other words, returns the probability that
        a worse fit of the model to the data exists. If this is a small value
        (typically <5%), this means the fit is pretty bad. For values below
        this threshold, the model very probably does not fit the data.

        n_def_of_freedom : int
            The number of degrees of freedom. This is typically
            :math:`n_\text{datapoints} - n_\text{parameters}`.
        '''
        chi2 = Double(self.get_fit_info('fcn'))
        ndf = Long(n_deg_of_freedom)
        return TMath.Prob(chi2, ndf)

    def get_contour(self, parameter1, parameter2, n_points=21):
        '''
        Returns a list of points (2-tuples) representing a sampling of
        the :math:`1\\sigma` contour of the TMinuit fit. The ``FCN`` has
        to be minimized before calling this.

        **parameter1** : int
            ID of the parameter to be displayed on the `x`-axis.

        **parameter2** : int
            ID of the parameter to be displayed on the `y`-axis.

        *n_points* : int (optional)
            number of points used to draw the contour. Default is 21.

        *returns* : 2-tuple of tuples
            a 2-tuple (x, y) containing ``n_points+1`` points sampled
            along the contour. The first point is repeated at the end
            of the list to generate a closed contour.
        '''

        self.out_file.write('\n')
        # entry in log-file
        self.out_file.write('\n')
        self.out_file.write('#'*(5+28))
        self.out_file.write('\n')
        self.out_file.write('# Contour for parameters %2d, %2d #\n'\
                            %(parameter1, parameter2) )
        self.out_file.write('#'*(5+28))
        self.out_file.write('\n\n')
        self.out_file.flush()
#
# first, make sure we are at minimum
        self.minimize(final_fit=True, log_print_level=0)

        # get the TGraph object from ROOT
        g = self.__gMinuit.Contour(n_points, parameter1, parameter2)

        # extract point data into buffers
        xbuf, ybuf = g.GetX(), g.GetY()
        N = g.GetN()

        # generate tuples from buffers
        x = np.frombuffer(xbuf, dtype=float, count=N)
        y = np.frombuffer(ybuf, dtype=float, count=N)

        #
        return (x, y)

    def get_profile(self, parid, n_points=21):
        '''
        Returns a list of points (2-tuples) the profile
        the :math:`\\chi^2`  of the TMinuit fit.


        **parid** : int
            ID of the parameter to be displayed on the `x`-axis.

        *n_points* : int (optional)
            number of points used for profile. Default is 21.

        *returns* : two arrays, par. values and corresp. :math:`\\chi^2`
            containing ``n_points`` sampled profile points.
        '''

        self.out_file.write('\n')
        # entry in log-file
        self.out_file.write('\n')
        self.out_file.write('#'*(2+26))
        self.out_file.write('\n')
        self.out_file.write("# Profile for parameter %2d #\n" % (parid))
        self.out_file.write('#'*(2+26))
        self.out_file.write('\n\n')
        self.out_file.flush()

        # redirect stdout stream
        _redirection_target = None
        ## -- disable redirection completely, for now
        ##if log_print_level >= 0:
        ##    _redirection_target = self.out_file

        with redirect_stdout_to(_redirection_target):
            pv = []
            chi2 = []
            error_code = Long(0)
            self.__gMinuit.mnexcm("SET PRINT",
                     arr('d', [0.0]), 1, error_code)  # no printout

            # first, make sure we are at minimum, i.e. re-minimize
            self.minimize(final_fit=True, log_print_level=0)
            minuit_id = Double(parid + 1) # Minuit parameter numbers start with 1

            # retrieve information about parameter with id=parid
            pmin = Double(0)
            perr = Double(0)
            self.__gMinuit.GetParameter(parid, pmin, perr)  # retrieve fitresult

            # fix parameter parid ...
            self.__gMinuit.mnexcm("FIX",
                                    arr('d', [minuit_id]),
                                    1, error_code)
            # ... and scan parameter values, minimizing at each point
            for v in np.linspace(pmin - 3.*perr, pmin + 3.*perr, n_points):
                pv.append(v)
                self.__gMinuit.mnexcm("SET PAR",
                     arr('d', [minuit_id, Double(v)]),
                                   2, error_code)
                self.__gMinuit.mnexcm("MIGRAD",
                     arr('d', [self.max_iterations, self.tolerance]),
                                   2, error_code)
                chi2.append(self.get_fit_info('fcn'))

            # release parameter to back to initial value and release
            self.__gMinuit.mnexcm("SET PAR",
                                  arr('d', [minuit_id, Double(pmin)]),
                                   2, error_code)
            self.__gMinuit.mnexcm("RELEASE",
                                    arr('d', [minuit_id]),
                                    1, error_code)

        return pv, chi2


    # Other methods
    ################

    def fix_parameter(self, parameter_number):
        '''
        Fix parameter number <`parameter_number`>.

        **parameter_number** : int
            Number of the parameter to fix.
        '''
        error_code = Long(0)
        logger.info("Fixing parameter %d in Minuit" % (parameter_number,))
        # execute FIX command
        self.__gMinuit.mnexcm("FIX",
                              arr('d', [parameter_number+1]), 1, error_code)

    def release_parameter(self, parameter_number):
        '''
        Release parameter number <`parameter_number`>.

        **parameter_number** : int
            Number of the parameter to release.
        '''
        error_code = Long(0)
        logger.info("Releasing parameter %d in Minuit" % (parameter_number,))
        # execute RELEASE command
        self.__gMinuit.mnexcm("RELEASE",
                              arr('d', [parameter_number+1]), 1, error_code)

    def reset(self):
        '''Execute TMinuit's `mnrset` method.'''
        self.__gMinuit.mnrset(0)  # reset TMinuit

    def FCN_wrapper(self, number_of_parameters, derivatives,
                    f, parameters, internal_flag):
        '''
        This is actually a function called in *ROOT* and acting as a C wrapper
        for our `FCN`, which is implemented in Python.

        This function is called by `Minuit` several times during a fit. It
        doesn't return anything but modifies one of its arguments (*f*).
        This is *ugly*, but it's how *ROOT*'s ``TMinuit`` works. Its argument
        structure is fixed and determined by `Minuit`:

        **number_of_parameters** : int
            The number of parameters of the current fit

        **derivatives** : C array
            If the user chooses to calculate the first derivative of the
            function inside the `FCN`, this value should be written here. This
            interface to `Minuit` ignores this derivative, however, so
            calculating this inside the `FCN` has no effect (yet).

        **f** : C array
            The desired function value is in f[0] after execution.

        **parameters** : C array
            A C array of parameters. Is cast to a Python list

        **internal_flag** : int
            A flag allowing for different behaviour of the function.
            Can be any integer from 1 (initial run) to 4(normal run). See
            `Minuit`'s specification.
        '''

        # Retrieve the parameters from the C side of ROOT and
        # store them in a Python list -- resource-intensive
        # for many calls, but can't be improved (yet?)
        parameter_list = np.frombuffer(parameters, dtype=float,
                                       count=self.number_of_parameters)

        # call the Python implementation of FCN.
        f[0] = self.function_to_minimize(*parameter_list)

    def minimize(self, final_fit=True, log_print_level=2):
        '''Do the minimization. This calls `Minuit`'s algorithms ``MIGRAD``
        for minimization and, if `final_fit` is `True`, also ``HESSE``
        for computing/checking the parameter error matrix.'''

        # Set the FCN again. This HAS to be done EVERY
        # time the minimize method is called because of
        # the implementation of SetFCN, which is not
        # object-oriented but sets a global pointer!!!
        logger.debug("Updating current FCN")
        self.__gMinuit.SetFCN(self.FCN_wrapper)

        # Run minimization algorithm (MIGRAD + HESSE)
        error_code = Long(0)

        prefix = "Minuit run on"  # set the timestamp prefix

        # insert timestamp
        self.out_file.write('\n')
        self.out_file.write('#'*(len(prefix)+4+20))
        self.out_file.write('\n')
        self.out_file.write("# %s " % (prefix,) +
                            strftime("%Y-%m-%d %H:%M:%S #\n", gmtime()))
        self.out_file.write('#'*(len(prefix)+4+20))
        self.out_file.write('\n\n')
        self.out_file.flush()

        # redirect stdout stream
        _redirection_target = None
        if log_print_level >= 0:
            _redirection_target = self.out_file

        with redirect_stdout_to(_redirection_target):
            self.__gMinuit.SetPrintLevel(log_print_level)  # set Minuit print level
            logger.debug("Running MIGRAD")
            self.__gMinuit.mnexcm("MIGRAD",
                                  arr('d', [self.max_iterations, self.tolerance]),
                                  2, error_code)
            if(final_fit):
                logger.debug("Running HESSE")
                self.__gMinuit.mnexcm("HESSE", arr('d', [self.max_iterations]), 1, error_code)
            # return to normal print level
            self.__gMinuit.SetPrintLevel(self.print_level)


    def minos_errors(self, log_print_level=1):
        '''
           Get (asymmetric) parameter uncertainties from MINOS
           algorithm. This calls `Minuit`'s algorithms ``MINOS``,
           which determines parameter uncertainties using profiling
           of the chi2 function.

           returns : tuple
             A tuple of [err+, err-, parabolic error, global correlation]
        '''

        # Set the FCN again. This HAS to be done EVERY
        # time the minimize method is called because of
        # the implementation of SetFCN, which is not
        # object-oriented but sets a global pointer!!!
        logger.debug("Updating current FCN")
        self.__gMinuit.SetFCN(self.FCN_wrapper)

        # redirect stdout stream
        _redirection_target = None
        if log_print_level >= 0:
            _redirection_target = self.out_file

        with redirect_stdout_to(_redirection_target):
            self.__gMinuit.SetPrintLevel(log_print_level)
            logger.debug("Running MINOS")
            error_code = Long(0)
            self.__gMinuit.mnexcm("MINOS", arr('d', [self.max_iterations]), 1, error_code)

            # return to normal print level
            self.__gMinuit.SetPrintLevel(self.print_level)


        output = []
        errpos=Double(0) # positive parameter error
        errneg=Double(0) # negative parameter error
        err=Double(0)    # parabolic error
        gcor=Double(0)   # global correlation coefficient

        for i in range(0, self.number_of_parameters):
            self.__gMinuit.mnerrs(i, errpos, errneg, err, gcor)
            output.append([float(errpos),float(errneg),float(err),float(gcor)])

        return output
コード例 #13
0
ファイル: minuit.py プロジェクト: dsavoiu/kafe
class Minuit:
    '''
    A class for communicating with ROOT's function minimizer tool Minuit.
    '''

    def __init__(self, number_of_parameters, function_to_minimize,
                 parameter_names, start_parameters, parameter_errors,
                 quiet=True, verbose=False):
        '''
        Create a Minuit minimizer for a function `function_to_minimize`.
        Necessary arguments are the number of parameters and the function to be
        minimized `function_to_minimize`. The function `function_to_minimize`'s
        arguments must be numerical values. The same goes for its output.

        Another requirement is for every parameter of `function_to_minimize` to
        have a default value. These are then used to initialize Minuit.

        **number_of_parameters** : int
            The number of parameters of the function to minimize.

        **function_to_minimize** : function
            The function which `Minuit` should minimize. This must be a Python
            function with <``number_of_parameters``> arguments.

        **parameter_names** : tuple/list of strings
            The parameter names. These are used to keep track of the parameters
            in `Minuit`'s output.

        **start_parameters** : tuple/list of floats
            The start values of the parameters. It is important to have a good,
            if rough, estimate of the parameters at the minimum before starting
            the minimization. Wrong initial parameters can yield a local
            minimum instead of a global one.

        **parameter_errors** : tuple/list of floats
            An initial guess of the parameter errors. These errors are used to
            define the initial step size.

        *quiet* : boolean (optional, default: ``True``)
            If ``True``, suppresses all output from ``TMinuit``.

        *verbose* : boolean (optional, default: ``False``)
            If ``True``, sets ``TMinuit``'s print level to a high value, so
            that all output is logged.

        '''
        #: the name of this minimizer type
        self.name = "ROOT::TMinuit"

        #: the actual `FCN` called in ``FCN_wrapper``
        self.function_to_minimize = function_to_minimize

        #: number of parameters to minimize for
        self.number_of_parameters = number_of_parameters

        if not quiet:
            self.out_file = open(log_file("minuit.log"), 'a')
        else:
            self.out_file = null_file()

        # create a TMinuit instance for that number of parameters
        self.__gMinuit = TMinuit(self.number_of_parameters)

        # instruct Minuit to use this class's FCN_wrapper method as a FCN
        self.__gMinuit.SetFCN(self.FCN_wrapper)

        # set print level according to flag
        if quiet:
            self.set_print_level(-1000)  # suppress output
        elif verbose:
            self.set_print_level(10)     # detailed output
        else:
            self.set_print_level(0)      # frugal output

        # initialize minimizer
        self.set_err()
        self.set_strategy()
        self.set_parameter_values(start_parameters)
        self.set_parameter_errors(parameter_errors)
        self.set_parameter_names(parameter_names)

        #: maximum number of iterations until ``TMinuit`` gives up
        self.max_iterations = M_MAX_ITERATIONS

        #: ``TMinuit`` tolerance
        self.tolerance = M_TOLERANCE

    def update_parameter_data(self, show_warnings=False):
        """
        (Re-)Sets the parameter names, values and step size on the
        C++ side of Minuit.
        """
        error_code = Long(0)
        try:
            # Set up the starting fit parameters in TMinuit
            for i in range(0, self.number_of_parameters):
                self.__gMinuit.mnparm(i, self.parameter_names[i],
                                      self.current_parameters[i],
                                      0.1 * self.parameter_errors[i],
                                      0, 0, error_code)
                # use 10% of the par. 1-sigma errors as the initial step size
        except AttributeError as e:
            if show_warnings:
                logger.warn("Cannot update Minuit data on the C++ side. "
                            "AttributeError: %s" % (e, ))
        return error_code

    # Set methods
    ##############

    def set_print_level(self, print_level=P_DETAIL_LEVEL):
        '''Sets the print level for Minuit.

        *print_level* : int (optional, default: 1 (frugal output))
            Tells ``TMinuit`` how much output to generate. The higher this
            value, the more output it generates.
        '''
        self.__gMinuit.SetPrintLevel(print_level)  # set Minuit print level
        self.print_level = print_level

    def set_strategy(self, strategy_id=1):
        '''Sets the strategy Minuit.

        *strategy_id* : int (optional, default: 1 (optimized))
            Tells ``TMinuit`` to use a certain strategy. Refer to ``TMinuit``'s
            documentation for available strategies.
        '''
        error_code = Long(0)
        # execute SET STRATEGY command
        self.__gMinuit.mnexcm("SET STRATEGY",
                              arr('d', [strategy_id]), 1, error_code)

    def set_err(self, up_value=1.0):
        '''Sets the ``UP`` value for Minuit.

        *up_value* : float (optional, default: 1.0)
            This is the value by which `FCN` is expected to change.
        '''
        # Tell TMinuit to use an up-value of 1.0
        error_code = Long(0)
        # execute SET ERR command
        self.__gMinuit.mnexcm("SET ERR", arr('d', [up_value]), 1, error_code)

    def set_parameter_values(self, parameter_values):
        '''
        Sets the fit parameters. If parameter_values=`None`, tries to infer
          defaults from the function_to_minimize.
        '''
        if len(parameter_values) == self.number_of_parameters:
            self.current_parameters = parameter_values
        else:
            raise Exception("Cannot get default parameter values from the \
            FCN. Not all parameters have default values given.")

        self.update_parameter_data()

    def set_parameter_names(self, parameter_names):
        '''Sets the fit parameters. If parameter_values=`None`, tries to infer
        defaults from the function_to_minimize.'''
        if len(parameter_names) == self.number_of_parameters:
            self.parameter_names = parameter_names
        else:
            raise Exception("Cannot set param names. Tuple length mismatch.")

        self.update_parameter_data()

    def set_parameter_errors(self, parameter_errors=None):
        '''Sets the fit parameter errors. If parameter_values=`None`, sets the
        error to 10% of the parameter value.'''

        if parameter_errors is None:  # set to 0.1% of the parameter value
            if not self.current_parameters is None:
                self.parameter_errors = [max(0.1, 0.1 * par)
                                         for par in self.current_parameters]
            else:
                raise Exception("Cannot set parameter errors. No errors \
                                provided and no parameters initialized.")
        elif len(parameter_errors) != len(self.current_parameters):
            raise Exception("Cannot set parameter errors. \
                            Tuple length mismatch.")
        else:
            self.parameter_errors = parameter_errors

        self.update_parameter_data()

    # Get methods
    ##############

    def get_error_matrix(self):
        '''Retrieves the parameter error matrix from TMinuit.

        return : `numpy.matrix`
        '''

        # set up an array of type `double' to pass to TMinuit
        tmp_array = arr('d', [0.0]*(self.number_of_parameters**2))
        # get parameter covariance matrix from TMinuit
        self.__gMinuit.mnemat(tmp_array, self.number_of_parameters)
        # reshape into 2D array
        return np.asmatrix(
            np.reshape(
                tmp_array,
                (self.number_of_parameters, self.number_of_parameters)
            )
        )

    def get_parameter_values(self):
        '''Retrieves the parameter values from TMinuit.

        return : tuple
            Current `Minuit` parameter values
        '''

        result = []
        # retrieve fit parameters
        p, pe = Double(0), Double(0)

        for i in range(0, self.number_of_parameters):
            self.__gMinuit.GetParameter(i, p, pe)  # retrieve fitresult

            result.append(float(p))

        return tuple(result)

    def get_parameter_errors(self):
        '''Retrieves the parameter errors from TMinuit.

        return : tuple
            Current `Minuit` parameter errors
        '''

        result = []
        # retrieve fit parameters
        p, pe = Double(0), Double(0)

        for i in range(0, self.number_of_parameters):
            self.__gMinuit.GetParameter(i, p, pe)  # retrieve fitresult

            result.append(float(pe))

        return tuple(result)

    def get_parameter_info(self):
        '''Retrieves parameter information from TMinuit.

        return : list of tuples
            ``(parameter_name, parameter_val, parameter_error)``
        '''

        result = []
        # retrieve fit parameters
        p, pe = Double(0), Double(0)

        for i in range(0, self.number_of_parameters):
            self.__gMinuit.GetParameter(i, p, pe)  # retrieve fitresult
            result.append((self.get_parameter_name(i), float(p), float(pe)))

        return result

    def get_parameter_name(self, parameter_nr):
        '''Gets the name of parameter number ``parameter_nr``

        **parameter_nr** : int
            Number of the parameter whose name to get.
        '''

        return self.parameter_names[parameter_nr]

    def get_fit_info(self, info):
        '''Retrieves other info from `Minuit`.

        **info** : string
            Information about the fit to retrieve.
            This can be any of the following:

              - ``'fcn'``: `FCN` value at minimum,
              - ``'edm'``: estimated distance to minimum
              - ``'err_def'``: `Minuit` error matrix status code
              - ``'status_code'``: `Minuit` general status code

        '''

        # declare vars in which to retrieve other info
        fcn_at_min = Double(0)
        edm = Double(0)
        err_def = Double(0)
        n_var_param = Long(0)
        n_tot_param = Long(0)
        status_code = Long(0)

        # Tell TMinuit to update the variables declared above
        self.__gMinuit.mnstat(fcn_at_min,
                              edm,
                              err_def,
                              n_var_param,
                              n_tot_param,
                              status_code)

        if info == 'fcn':
            return fcn_at_min

        elif info == 'edm':
            return edm

        elif info == 'err_def':
            return err_def

        elif info == 'status_code':
            try:
                return D_MATRIX_ERROR[status_code]
            except:
                return status_code

    def get_chi2_probability(self, n_deg_of_freedom):
        '''
        Returns the probability that an observed :math:`\chi^2` exceeds
        the calculated value of :math:`\chi^2` for this fit by chance,
        even for a correct model. In other words, returns the probability that
        a worse fit of the model to the data exists. If this is a small value
        (typically <5%), this means the fit is pretty bad. For values below
        this threshold, the model very probably does not fit the data.

        n_def_of_freedom : int
            The number of degrees of freedom. This is typically
            :math:`n_\text{datapoints} - n_\text{parameters}`.
        '''
        chi2 = Double(self.get_fit_info('fcn'))
        ndf = Long(n_deg_of_freedom)
        return TMath.Prob(chi2, ndf)

    def get_contour(self, parameter1, parameter2, n_points=21):
        '''
        Returns a list of points (2-tuples) representing a sampling of
        the :math:`1\\sigma` contour of the TMinuit fit. The ``FCN`` has
        to be minimized before calling this.

        **parameter1** : int
            ID of the parameter to be displayed on the `x`-axis.

        **parameter2** : int
            ID of the parameter to be displayed on the `y`-axis.

        *n_points* : int (optional)
            number of points used to draw the contour. Default is 21.

        *returns* : 2-tuple of tuples
            a 2-tuple (x, y) containing ``n_points+1`` points sampled
            along the contour. The first point is repeated at the end
            of the list to generate a closed contour.
        '''

        self.out_file.write('\n')
        # entry in log-file
        self.out_file.write('\n')
        self.out_file.write('#'*(5+28))
        self.out_file.write('\n')
        self.out_file.write('# Contour for parameters %2d, %2d #\n'\
                            %(parameter1, parameter2) )
        self.out_file.write('#'*(5+28))
        self.out_file.write('\n\n')
        self.out_file.flush()
#
# first, make sure we are at minimum
        self.minimize(final_fit=True, log_print_level=0)

        # get the TGraph object from ROOT
        g = self.__gMinuit.Contour(n_points, parameter1, parameter2)

        # extract point data into buffers
        xbuf, ybuf = g.GetX(), g.GetY()
        N = g.GetN()

        # generate tuples from buffers
        x = np.frombuffer(xbuf, dtype=float, count=N)
        y = np.frombuffer(ybuf, dtype=float, count=N)

        #
        return (x, y)

    def get_profile(self, parid, n_points=21):
        '''
        Returns a list of points (2-tuples) the profile
        the :math:`\\chi^2`  of the TMinuit fit.


        **parid** : int
            ID of the parameter to be displayed on the `x`-axis.

        *n_points* : int (optional)
            number of points used for profile. Default is 21.

        *returns* : two arrays, par. values and corresp. :math:`\\chi^2`
            containing ``n_points`` sampled profile points.
        '''

        self.out_file.write('\n')
        # entry in log-file
        self.out_file.write('\n')
        self.out_file.write('#'*(2+26))
        self.out_file.write('\n')
        self.out_file.write("# Profile for parameter %2d #\n" % (parid))
        self.out_file.write('#'*(2+26))
        self.out_file.write('\n\n')
        self.out_file.flush()

        # redirect stdout stream
        _redirection_target = None
        ## -- disable redirection completely, for now
        ##if log_print_level >= 0:
        ##    _redirection_target = self.out_file

        with redirect_stdout_to(_redirection_target):
            pv = []
            chi2 = []
            error_code = Long(0)
            self.__gMinuit.mnexcm("SET PRINT",
                     arr('d', [0.0]), 1, error_code)  # no printout

            # first, make sure we are at minimum, i.e. re-minimize
            self.minimize(final_fit=True, log_print_level=0)
            minuit_id = Double(parid + 1) # Minuit parameter numbers start with 1

            # retrieve information about parameter with id=parid
            pmin = Double(0)
            perr = Double(0)
            self.__gMinuit.GetParameter(parid, pmin, perr)  # retrieve fitresult

            # fix parameter parid ...
            self.__gMinuit.mnexcm("FIX",
                                    arr('d', [minuit_id]),
                                    1, error_code)
            # ... and scan parameter values, minimizing at each point
            for v in np.linspace(pmin - 3.*perr, pmin + 3.*perr, n_points):
                pv.append(v)
                self.__gMinuit.mnexcm("SET PAR",
                     arr('d', [minuit_id, Double(v)]),
                                   2, error_code)
                self.__gMinuit.mnexcm("MIGRAD",
                     arr('d', [self.max_iterations, self.tolerance]),
                                   2, error_code)
                chi2.append(self.get_fit_info('fcn'))

            # release parameter to back to initial value and release
            self.__gMinuit.mnexcm("SET PAR",
                                  arr('d', [minuit_id, Double(pmin)]),
                                   2, error_code)
            self.__gMinuit.mnexcm("RELEASE",
                                    arr('d', [minuit_id]),
                                    1, error_code)

        return pv, chi2


    # Other methods
    ################

    def fix_parameter(self, parameter_number):
        '''
        Fix parameter number <`parameter_number`>.

        **parameter_number** : int
            Number of the parameter to fix.
        '''
        error_code = Long(0)
        logger.info("Fixing parameter %d in Minuit" % (parameter_number,))
        # execute FIX command
        self.__gMinuit.mnexcm("FIX",
                              arr('d', [parameter_number+1]), 1, error_code)

    def release_parameter(self, parameter_number):
        '''
        Release parameter number <`parameter_number`>.

        **parameter_number** : int
            Number of the parameter to release.
        '''
        error_code = Long(0)
        logger.info("Releasing parameter %d in Minuit" % (parameter_number,))
        # execute RELEASE command
        self.__gMinuit.mnexcm("RELEASE",
                              arr('d', [parameter_number+1]), 1, error_code)

    def reset(self):
        '''Execute TMinuit's `mnrset` method.'''
        self.__gMinuit.mnrset(0)  # reset TMinuit

    def FCN_wrapper(self, number_of_parameters, derivatives,
                    f, parameters, internal_flag):
        '''
        This is actually a function called in *ROOT* and acting as a C wrapper
        for our `FCN`, which is implemented in Python.

        This function is called by `Minuit` several times during a fit. It
        doesn't return anything but modifies one of its arguments (*f*).
        This is *ugly*, but it's how *ROOT*'s ``TMinuit`` works. Its argument
        structure is fixed and determined by `Minuit`:

        **number_of_parameters** : int
            The number of parameters of the current fit

        **derivatives** : C array
            If the user chooses to calculate the first derivative of the
            function inside the `FCN`, this value should be written here. This
            interface to `Minuit` ignores this derivative, however, so
            calculating this inside the `FCN` has no effect (yet).

        **f** : C array
            The desired function value is in f[0] after execution.

        **parameters** : C array
            A C array of parameters. Is cast to a Python list

        **internal_flag** : int
            A flag allowing for different behaviour of the function.
            Can be any integer from 1 (initial run) to 4(normal run). See
            `Minuit`'s specification.
        '''

        # Retrieve the parameters from the C side of ROOT and
        # store them in a Python list -- resource-intensive
        # for many calls, but can't be improved (yet?)
        parameter_list = np.frombuffer(parameters, dtype=float,
                                       count=self.number_of_parameters)

        # call the Python implementation of FCN.
        f[0] = self.function_to_minimize(*parameter_list)

    def minimize(self, final_fit=True, log_print_level=2):
        '''Do the minimization. This calls `Minuit`'s algorithms ``MIGRAD``
        for minimization and, if `final_fit` is `True`, also ``HESSE``
        for computing/checking the parameter error matrix.'''

        # Set the FCN again. This HAS to be done EVERY
        # time the minimize method is called because of
        # the implementation of SetFCN, which is not
        # object-oriented but sets a global pointer!!!
        logger.debug("Updating current FCN")
        self.__gMinuit.SetFCN(self.FCN_wrapper)

        # Run minimization algorithm (MIGRAD + HESSE)
        error_code = Long(0)

        prefix = "Minuit run on"  # set the timestamp prefix

        # insert timestamp
        self.out_file.write('\n')
        self.out_file.write('#'*(len(prefix)+4+20))
        self.out_file.write('\n')
        self.out_file.write("# %s " % (prefix,) +
                            strftime("%Y-%m-%d %H:%M:%S #\n", gmtime()))
        self.out_file.write('#'*(len(prefix)+4+20))
        self.out_file.write('\n\n')
        self.out_file.flush()

        # redirect stdout stream
        _redirection_target = None
        if log_print_level >= 0:
            _redirection_target = self.out_file

        with redirect_stdout_to(_redirection_target):
            self.__gMinuit.SetPrintLevel(log_print_level)  # set Minuit print level
            logger.debug("Running MIGRAD")
            self.__gMinuit.mnexcm("MIGRAD",
                                  arr('d', [self.max_iterations, self.tolerance]),
                                  2, error_code)
            if(final_fit):
                logger.debug("Running HESSE")
                self.__gMinuit.mnexcm("HESSE", arr('d', [self.max_iterations]), 1, error_code)
            # return to normal print level
            self.__gMinuit.SetPrintLevel(self.print_level)


    def minos_errors(self, log_print_level=1):
        '''
           Get (asymmetric) parameter uncertainties from MINOS
           algorithm. This calls `Minuit`'s algorithms ``MINOS``,
           which determines parameter uncertainties using profiling
           of the chi2 function.

           returns : tuple
             A tuple of [err+, err-, parabolic error, global correlation]
        '''

        # Set the FCN again. This HAS to be done EVERY
        # time the minimize method is called because of
        # the implementation of SetFCN, which is not
        # object-oriented but sets a global pointer!!!
        logger.debug("Updating current FCN")
        self.__gMinuit.SetFCN(self.FCN_wrapper)

        # redirect stdout stream
        _redirection_target = None
        if log_print_level >= 0:
            _redirection_target = self.out_file

        with redirect_stdout_to(_redirection_target):
            self.__gMinuit.SetPrintLevel(log_print_level)
            logger.debug("Running MINOS")
            error_code = Long(0)
            self.__gMinuit.mnexcm("MINOS", arr('d', [self.max_iterations]), 1, error_code)

            # return to normal print level
            self.__gMinuit.SetPrintLevel(self.print_level)


        output = []
        errpos=Double(0) # positive parameter error
        errneg=Double(0) # negative parameter error
        err=Double(0)    # parabolic error
        gcor=Double(0)   # global correlation coefficient

        for i in range(0, self.number_of_parameters):
            self.__gMinuit.mnerrs(i, errpos, errneg, err, gcor)
            output.append([float(errpos),float(errneg),float(err),float(gcor)])

        return output
コード例 #14
0
    def fit(self):
        numberOfParameters = len(self.samples)
        gMinuit = TMinuit(numberOfParameters)
        if self.method == "logLikelihood":  # set function for minimisation
            gMinuit.SetFCN(self.logLikelihood)

        gMinuit.SetMaxIterations(1000000000000)

        # set Minuit print level
        # printlevel  = -1  quiet (also suppress all warnings)
        #            =  0  normal
        #            =  1  verbose
        #            =  2  additional output giving intermediate results.
        #            =  3  maximum output, showing progress of minimizations.
        gMinuit.SetPrintLevel(-1)

        # Error definition: 1 for chi-squared, 0.5 for negative log likelihood
        # SETERRDEF<up>: Sets the value of UP (default value= 1.), defining parameter errors.
        # Minuit defines parameter errors as the change in parameter value required to change the function value by UP.
        # Normally, for chisquared fits UP=1, and for negative log likelihood, UP=0.5.
        gMinuit.SetErrorDef(0.5)

        # error flag for functions passed as reference.set to as 0 is no error
        errorFlag = Long(2)

        N_min = 0
        N_max = self.fit_data_collection.max_n_data() * 2

        param_index = 0

        # MNPARM
        # Implements one parameter definition:
        # mnparm(k, cnamj, uk, wk, a, b, ierflg)
        #     K     (external) parameter number
        #     CNAMK parameter name
        #     UK    starting value
        #     WK    starting step size or uncertainty
        #     A, B  lower and upper physical parameter limits
        # and sets up (updates) the parameter lists.
        # Output: IERFLG  =0 if no problems
        #                >0 if MNPARM unable to implement definition
        for sample in self.samples:  # all samples but data
            if self.n_distributions > 1:
                gMinuit.mnparm(
                    param_index,
                    sample,
                    self.normalisation[self.distributions[0]][sample],
                    10.0,
                    N_min,
                    N_max,
                    errorFlag,
                )
            else:
                gMinuit.mnparm(param_index, sample, self.normalisation[sample], 10.0, N_min, N_max, errorFlag)
            param_index += 1

        arglist = array("d", 10 * [0.0])

        # minimisation strategy: 1 standard, 2 try to improve minimum (a bit slower)
        arglist[0] = 2

        # minimisation itself
        # SET STRategy<level>: Sets the strategy to be used in calculating first and second derivatives and in certain minimization methods.
        # In general, low values of <level> mean fewer function calls and high values mean more reliable minimization.
        # Currently allowed values are 0, 1 (default), and 2.
        gMinuit.mnexcm("SET STR", arglist, 1, errorFlag)

        gMinuit.Migrad()
        gMinuit.mnscan()  # class for minimization using a scan method to find the minimum; allows for user interaction: set/change parameters, do minimization, change parameters, re-do minimization etc.

        gMinuit.mnmatu(1)  # prints correlation matrix (always needed)

        self.module = gMinuit
        self.performedFit = True

        if not self.module:
            raise Exception("No fit results available. Please run fit method first")

        results = {}
        param_index = 0
        for sample in self.samples:
            temp_par = Double(0)
            temp_err = Double(0)
            self.module.GetParameter(param_index, temp_par, temp_err)
            if math.isnan(temp_err):
                self.logger.warning("Template fit error is NAN, setting to sqrt(N).")
                temp_err = math.sqrt(temp_par)

            #             gMinuit.Command("SCAn %i %i %i %i" % ( param_index, 100, N_min, N_total ) );
            #             scan = gMinuit.GetPlot()
            #             results[sample] = ( temp_par, temp_err, scan )
            results[sample] = (temp_par, temp_err)
            param_index += 1

        # #         gMinuit.Command("CONtour 1 2 3 50")
        #         gMinuit.SetErrorDef(1)
        #         results['contour'] = [gMinuit.Contour(100, 0, 1)]
        #         gMinuit.SetErrorDef(4)
        #         results['contour'].append(gMinuit.Contour(100, 0, 1))

        self.results = results
コード例 #15
0
        npar:   # of parameters
        deriv:  array of derivatives df/dp_i(x), optional
        f:      value of function to be minimised (typically chi2 or negLogL)
        apar:   the array of parameters
        iflag:  internal flag: 1 at first call, 3 at the last, 4 during
        minimisation 
    """
    f[0] = calcChi2(npar, apar)

# --> set up MINUIT
myMinuit = TMinuit(npar)    # initialize TMinuit with maximum of npar parameters
myMinuit.setFCN(fcn)        # set func to minimize
arglist = arr('d', 2*[0.01])# set error definition
ieflg = Long(0)
arglist[0] = 1.             # 1 sigma is Delta chi^2 = 1
myMinuit.mnexcm("SET ERR", arglist, 1, ierflg)



#−−>Set starting values and step sizes for parameters
for i in range(0, npar):
#Define the parameters for the fit
    myMinuit.mnparm(i, name[i], vstart[i], step[i], 0, 0, ierflg)

arglist[0] = 6000   # Number of calls to FCN before giving up.
arglist[1] = 0.3    # Tolerance
myMinuit.mnexcm("MIGRAD", arglist, 2, ierflg)   # execute the minimisation

#−−> check TMinuit status
amin, edm, errdef = Double(0.), Double(0.), Double(0.)
nvpar, nparx, icstat = Long(0), Long(0), Long(0)
コード例 #16
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
コード例 #17
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]
コード例 #18
0
    def fit_model(self, country, time_range):
        s_data = self.data_sir["susceptible"]
        i_data = self.data_sir["infected"]
        r_data = self.data_sir["recovered"]

        def fcn(nPar, gin, f, par, flag):
            tr = par[0]
            rec = par[1]
            chi2 = 0.
            n_bins = s_data.GetNbinsX()
            s_model, i_model, r_model = solve_SIR(tr, rec, time_range)
            for i in range(1, n_bins + 1):
                dif = (i_data.GetBinContent(i) -
                       i_model.GetBinContent(i)) / i_data.GetBinError(i)
                chi2 += dif**2
                dif = (r_data.GetBinContent(i) -
                       r_model.GetBinContent(i)) / r_data.GetBinError(i)
                chi2 += dif**2
            f[0] = chi2
            return

        minuit = TMinuit(3)
        minuit.SetFCN(fcn)

        vstep = [1e-10, 1e-10]
        vinit = [1e-10, 1e-10]
        # vinit = [1e-3, 1e-3]
        vmin = [1e-15, 1e-15]
        vmax = [1e0, 1e0]

        from ctypes import c_int, c_double
        import array as c_arr

        arglist = c_arr.array('d', 10 * [0.])
        ierflag = 0

        arglist[0] = 1
        minuit.mnexcm("SET ERR", arglist, 1, c_int(ierflag))

        minuit.mnparm(0, "transition rate", vinit[0], vstep[0], vmin[0],
                      vmax[0], c_int(ierflag))
        minuit.mnparm(1, "recovery rate", vinit[1], vstep[1], vmin[1], vmax[1],
                      c_int(ierflag))

        # minuit.SetErrorDef(1.)

        # minuit.SetMaxIteration(500)
        # minuit.Migrad()
        arglist[0] = 500
        arglist[1] = 1.
        # minuit.mnexcm( "MIGRAD", arglist, 2, c_int(ierflag) )

        res_trans = c_double(0.)
        res_rec = c_double(0.)
        err_trans = c_double(0.)
        err_rec = c_double(0.)

        minuit.GetParameter(0, res_trans, err_trans)
        minuit.GetParameter(1, res_rec, err_rec)

        # return res_trans.value, res_rec.value

        hists = self.solve_SIR(res_trans.value, res_rec.value, time_range)

        self.hists = {
            "susceptible": hists[0],
            "infected": hists[1],
            "recovered": hists[2]
        }

        self.draw()
コード例 #19
0
def make_renormalization_dict(name,alpha,epsilon,muRup,muRdown,muFup,muFdown,scup,scdown,pdfas,pdfasup,pdfasdown,topptrwhist) :
	global qq_global_hist_projection
	global gg_global_hist_projection
	returndict = {}
	#start with the simple values
	returndict['muRup']=muRup.GetMean() 
	returndict['muRdown']=muRdown.GetMean() 
	returndict['muFup']=muFup.GetMean() 
	returndict['muFdown']=muFdown.GetMean() 
	returndict['scup']=scup.GetMean() 
	returndict['scdown']=scdown.GetMean() 
	returndict['pdfas']=pdfas.GetMean() 
	returndict['pdfasup']=pdfasup.GetMean() 
	returndict['pdfasdown']=pdfasdown.GetMean() 
	returndict['topptrwmean']=topptrwhist.GetMean()
	printlines = []
	if alpha==1.0 and epsilon==1.0 and (name.find('_TT')!=-1 or name.find('_TTJets')!=-1) :
		#now we've got to do the fits for the "deweighting" alpha and epsilon values
		print 'fitting for alpha/epsilon values... '
		#Define the Minuit instance we'll use
		alpha_minuit = TMinuit(1); alpha_minuit.SetFCN(alpha_fcn)
		epsilon_minuit = TMinuit(1); epsilon_minuit.SetFCN(epsilon_fcn)
		#miscellaneous minuit stuff
		ierflag = Long(1); arglist = array('d',[-1])
		alpha_minuit.mnexcm('SET PRINT', arglist, 1,ierflag); alpha_minuit.mnexcm('SET NOWARNINGS',arglist,1,ierflag)
		epsilon_minuit.mnexcm('SET PRINT', arglist, 1,ierflag); epsilon_minuit.mnexcm('SET NOWARNINGS',arglist,1,ierflag)
		arglist[0]=100000.
		#for each bin in beta
		for i in range(1,csvb_qq_global_hist.GetXaxis().GetNbins()+1) :
			BETA[0] = csvb_qq_global_hist.GetXaxis().GetBinCenter(i)
			#qq_global_hist_projection = symmetrize(csvb_qq_global_hist.ProjectionY('qq_proj_'+str(i),i,i))
			qq_global_hist_projection = csvb_qq_global_hist.ProjectionY('qq_proj_'+str(i),i,i)
			#add parameter
			alpha_minuit.mnparm(0,'alpha',0.1,0.5,0.,0.,ierflag)
			#minimize
			alpha_minuit.mnexcm('MIGRAD',arglist,1,ierflag)
			#get back the fitted alpha value
			fitted_alpha=Double(0.0); fitted_alpha_err=Double(0.0)
			alpha_minuit.GetParameter(0,fitted_alpha,fitted_alpha_err)
			#print 'NEW NAME = alpha_'+str(csvb_qq_global_hist.GetXaxis().GetBinLowEdge(i))
			returndict['alpha_'+str(csvb_qq_global_hist.GetXaxis().GetBinLowEdge(i))]=fitted_alpha
			printlines.append('fitted alpha value in bin %d = %.4f +/- %.4f'%(i,fitted_alpha,fitted_alpha_err))
		#epsilon stuff
		for i in range(1,csvb_gg_global_hist.GetXaxis().GetNbins()+1) :
			BETA[0] = csvb_gg_global_hist.GetXaxis().GetBinCenter(i)
			#gg_global_hist_projection = symmetrize(csvb_gg_global_hist.ProjectionY('gg_proj_'+str(i),i,i))
			gg_global_hist_projection = csvb_gg_global_hist.ProjectionY('gg_proj_'+str(i),i,i)
			epsilon_minuit.mnparm(0,'epsilon',0.1,0.5,0.,0.,ierflag)
			epsilon_minuit.mnexcm('MIGRAD',arglist,1,ierflag)
			fitted_epsilon=Double(0.0); fitted_epsilon_err=Double(0.0)
			epsilon_minuit.GetParameter(0,fitted_epsilon,fitted_epsilon_err)
			returndict['epsilon_'+str(csvb_gg_global_hist.GetXaxis().GetBinLowEdge(i))]=fitted_epsilon
			printlines.append('fitted epsilon value in bin %d = %.4f +/- %.4f'%(i,fitted_epsilon,fitted_epsilon_err))
	else :
		returndict['alpha']=alpha; returndict['epsilon']=epsilon
		fitted_alpha_err = 1.0; fitted_epsilon_err = 1.0
	#print the values
	print 'muRup value = %.4f'%(returndict['muRup'])
	print 'muRdown value = %.4f'%(returndict['muRdown'])
	print 'muFup value = %.4f'%(returndict['muFup'])
	print 'muFdown value = %.4f'%(returndict['muFdown'])
	print 'scup value = %.4f'%(returndict['scup'])
	print 'scdown value = %.4f'%(returndict['scdown'])
	print 'pdfas value = %.4f'%(returndict['pdfas'])
	print 'pdfasup value = %.4f'%(returndict['pdfasup'])
	print 'pdfasdown value = %.4f'%(returndict['pdfasdown'])
	print 'top pT reweight (v1) mean value = %.4f'%(returndict['topptrwmean'])
	for line in printlines :
		print line
	#return the dictionary
	return returndict
コード例 #20
0
ファイル: mkflipsf.py プロジェクト: SiewYan/NanoFlipper
def fit( p , perr ):

     global val, err, nBins
     val = p
     err = perr
     nBins=len(val)

     #name=['q0','q1','q2','q3','q4']
     #name=['q0','q1','q2','q3']
     #name=['q0','q1','q2']
     name = [ 'q0' , 'q1' ]

     npar=len(name)
     # the initial values
     vstart = arr( 'd' , npar*[0.1] )
     # the initial step size
     step = arr( 'd' , npar*[0.000001] )

     # --> set up MINUIT
     gMinuit = TMinuit ( npar ) # initialize TMinuit with maximum of npar parameters
     gMinuit.SetFCN( fcn ) # set function to minimize
     arglist = arr( 'd' , npar*[0.01] ) # set error definition
     ierflg = c_int(0)

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

     # --> set starting values and step size for parameters
     # Define the parameters for the fit
     for i in range(0,npar): gMinuit.mnparm( i, name[i] , vstart[i] , step[i] , 0, 0, ierflg )
     # now ready for minimization step
     arglist [0] = 500 # Number of calls for FCN before giving up
     arglist [1] = 1. # Tolerance
     gMinuit.mnexcm("MIGRAD" , arglist , 2 , ierflg) # execute the minimisation

     # --> check TMinuit status
     amin , edm , errdef = c_double(0.) , c_double(0.) , c_double(0.)
     nvpar , nparx , icstat = c_int(0) , c_int(0) , c_int(0)
     gMinuit.mnstat (amin , edm , errdef , nvpar , nparx , icstat )
     gMinuit.mnprin(3,amin) # print-out by Minuit

     # meaning of parameters:
     #   amin:   value of fcn distance at minimum (=chi^2)
     #   edm:    estimated distance to minimum
     #   errdef: delta_fcn used to define 1 sigam errors
     #   nvpar:  total number of parameters
     #   icstat: status of error matrix:
     #           3 = accurate
     #           2 = forced pos. def
     #           1 = approximative
     #           0 = not calculated
     #

     # --> get results from MINUIT
     finalPar = []
     finalParErr = []
     p, pe = c_double(0.) , c_double(0.)
     for i in range(0,npar):
          gMinuit.GetParameter(i, p, pe) # retrieve parameters and errors
          finalPar.append( float(p.value) )
          finalParErr.append( float(pe.value) )
     # get covariance matrix
     buf = arr('d' , npar*npar*[0.])
     gMinuit.mnemat( buf , npar ) # retrieve error matrix
     emat = np.array( buf ).reshape( npar , npar )

     # --> provide formatted output of results
     print "\n"
     print "*==* MINUIT fit completed:"
     print'fcn@minimum = %.3g'%( amin.value ) , " error code =" , ierflg.value , " status =" , icstat.value , " (if its 3, mean accurate)"
     print " Results: \t value error corr. mat."
     for i in range(0,npar):
          print'%s: \t%10.3e +/- %.1e'%( name[i] , finalPar[i] , finalParErr[i] ) ,
          for j in range (0,i): print'%+.3g'%( emat[i][j]/np.sqrt(emat[i][i])/np.sqrt(emat[j][j]) ),
          print "\n"

     return [ [i,j]  for i,j in zip(finalPar , finalParErr) ]
コード例 #21
0
ファイル: myScript.py プロジェクト: JuhiRaj/InducedAsymmetry
def main():
    #The first part of the script is to input the root files#

    canvas = TCanvas("Canvas_d", "Canvas_d", 533, 76, 1383, 852)
    input_datafile = TFile(args["input_data"])
    EV_data = input_datafile.Get("EventCategorizer subtask 0 stats/ExpecValue")
    entries_data = EV_data.GetSize()
    print "# of Entries in Data file:", entries_data
    print "Experimental Data Inputed"
    data_arr = []

    canvas = TCanvas("Canvas_mc", "Canvas_mc", 533, 76, 1383, 852)
    input_mcfile = TFile(args["input_mc"])
    EV_mc = input_mcfile.Get(
        "EventCategorizer subtask 0 stats/ExpecValue_Smeared")
    entries_mc = EV_mc.GetSize()
    print "# of Entries in MC file:", entries_mc
    print "MC Data Inputed"
    mc_arr = []
    bin_arr = []

    for x in range(entries_data):
        Data_i = EV_data.GetBinContent(x)
        MC_i = EV_mc.GetBinContent(x)
        data_arr.append(Data_i)
        mc_arr.append(MC_i)
        Bin_i = EV_data.GetBinCenter(x)
        bin_arr.append(Bin_i)
        #print Data_i
        #print MC_i

    #print data_arr
    #print mc_arr
    #print bin_arr

# --> Set parameters and function to f i t
    name = ["c", "d"]  #variable names
    vstart = arr('d', (1.0, 1.0))  #the initial values
    step = arr('d', (0.001, 0.001))  #the initial step size
    npar = len(name)

    # --> Defining the Chi-Square function to be minimized#

    def Chi_Induced(Data, MC, BinCenter, C, D):
        chi = 0.
        for i in range(0, entries_data):
            #num1 = Data[i]
            #num2 = D*((1-(C*BinCenter[i]))*MC[i])
            #num = (num1 - num2)**2
            #num = 0.
            #den1 = ((Data[i])**(1/2))**2
            #den2 = (D*((1-(C*BinCenter[i])))*((MC[i])**(1/2)))**2
            num = 2
            den = 2
            #den = den1 + den2
            chi = chi + num / den
        return chi


# --> set up MINUIT

    myMinuit = TMinuit(
        npar)  # initialize TMinuit with maximum of npar parameters
    myMinuit.SetFCN(Chi_Induced)  # set function to minimize
    ierflg = Long(0)
    arglist = arr('d', 2 * [0.01])  # set error definition
    arglist[0] = 6000  # Number of calls for FCN before gving up
    arglist[1] = 0.3  # Toleranceierflg = Long(0)
    myMinuit.mnexcm("SET ERR", arglist, 1, ierflg)
    for i in range(0, npar):
        myMinuit.mnparm(i, name[i], vstart[i], step[i], 0, 0, ierflg)
    myMinuit.mnexcm("MIGRAD", arglist, 1, ierflg)  # execute the minimisation
    # --> check TMinuit status
    amin, edm, errdef = Double(0.), Double(0.), Double(0.)
    nvpar, nparx, icstat = Long(0), Long(0), Long(0)
    myMinuit.mnstat(amin, edm, errdef, nvpar, nparx, icstat)
コード例 #22
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()
コード例 #23
0
    def fit(self):
        numberOfParameters = len(self.samples)
        gMinuit = TMinuit(numberOfParameters)
        if self.method == 'logLikelihood':  # set function for minimisation
            gMinuit.SetFCN(self.logLikelihood)

        gMinuit.SetMaxIterations(1000000000000)

        # set Minuit print level
        # printlevel  = -1  quiet (also suppress all warnings)
        #            =  0  normal
        #            =  1  verbose
        #            =  2  additional output giving intermediate results.
        #            =  3  maximum output, showing progress of minimizations.
        gMinuit.SetPrintLevel(-1)

        # Error definition: 1 for chi-squared, 0.5 for negative log likelihood
        # SETERRDEF<up>: Sets the value of UP (default value= 1.), defining parameter errors.
        # Minuit defines parameter errors as the change in parameter value required to change the function value by UP.
        # Normally, for chisquared fits UP=1, and for negative log likelihood, UP=0.5.
        gMinuit.SetErrorDef(0.5)

        # error flag for functions passed as reference.set to as 0 is no error
        errorFlag = Long(2)

        N_min = 0
        N_max = self.fit_data_collection.max_n_data() * 2

        param_index = 0

        # MNPARM
        # Implements one parameter definition:
        # mnparm(k, cnamj, uk, wk, a, b, ierflg)
        #     K     (external) parameter number
        #     CNAMK parameter name
        #     UK    starting value
        #     WK    starting step size or uncertainty
        #     A, B  lower and upper physical parameter limits
        # and sets up (updates) the parameter lists.
        # Output: IERFLG  =0 if no problems
        #                >0 if MNPARM unable to implement definition
        for sample in self.samples:  # all samples but data
            if self.n_distributions > 1:
                gMinuit.mnparm(
                    param_index, sample,
                    self.normalisation[self.distributions[0]][sample], 10.0,
                    N_min, N_max, errorFlag)
            else:
                gMinuit.mnparm(param_index, sample, self.normalisation[sample],
                               10.0, N_min, N_max, errorFlag)
            param_index += 1

        arglist = array('d', 10 * [0.])

        # minimisation strategy: 1 standard, 2 try to improve minimum (a bit slower)
        arglist[0] = 2

        # minimisation itself
        # SET STRategy<level>: Sets the strategy to be used in calculating first and second derivatives and in certain minimization methods.
        # In general, low values of <level> mean fewer function calls and high values mean more reliable minimization.
        # Currently allowed values are 0, 1 (default), and 2.
        gMinuit.mnexcm("SET STR", arglist, 1, errorFlag)

        gMinuit.Migrad()
        gMinuit.mnscan(
        )  # class for minimization using a scan method to find the minimum; allows for user interaction: set/change parameters, do minimization, change parameters, re-do minimization etc.

        gMinuit.mnmatu(1)  # prints correlation matrix (always needed)

        self.module = gMinuit
        self.performedFit = True

        if not self.module:
            raise Exception(
                'No fit results available. Please run fit method first')

        results = {}
        param_index = 0
        for sample in self.samples:
            temp_par = Double(0)
            temp_err = Double(0)
            self.module.GetParameter(param_index, temp_par, temp_err)
            if (math.isnan(temp_err)):
                self.logger.warning(
                    'Template fit error is NAN, setting to sqrt(N).')
                temp_err = math.sqrt(temp_par)

#             gMinuit.Command("SCAn %i %i %i %i" % ( param_index, 100, N_min, N_total ) );
#             scan = gMinuit.GetPlot()
#             results[sample] = ( temp_par, temp_err, scan )
            results[sample] = (temp_par, temp_err)
            param_index += 1

# #         gMinuit.Command("CONtour 1 2 3 50")
#         gMinuit.SetErrorDef(1)
#         results['contour'] = [gMinuit.Contour(100, 0, 1)]
#         gMinuit.SetErrorDef(4)
#         results['contour'].append(gMinuit.Contour(100, 0, 1))

        self.results = results
コード例 #24
0
    def test1MinuitFit(self):
        """Test minuit callback and fit"""

        # setup minuit and callback
        gMinuit = TMinuit(5)
        gMinuit.SetPrintLevel(-1)  # quiet
        gMinuit.SetGraphicsMode(ROOT.kFALSE)
        gMinuit.SetFCN(fcn)

        arglist = array('d', 10 * [0.])
        if not exp_pyroot and sys.hexversion < 0x3000000:
            ierflg = ROOT.Long()
        else:
            ierflg = ctypes.c_int()

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

        # set starting values and step sizes for parameters
        vstart = array('d', [3, 1, 0.1, 0.01])
        step = array('d', [0.1, 0.1, 0.01, 0.001])
        gMinuit.mnparm(0, "a1", vstart[0], step[0], 0, 0, ierflg)
        gMinuit.mnparm(1, "a2", vstart[1], step[1], 0, 0, ierflg)
        gMinuit.mnparm(2, "a3", vstart[2], step[2], 0, 0, ierflg)
        gMinuit.mnparm(3, "a4", vstart[3], step[3], 0, 0, ierflg)

        # now ready for minimization step
        arglist[0] = 500
        arglist[1] = 1.
        gMinuit.mnexcm("MIGRAD", arglist, 2, ierflg)

        # verify results
        if exp_pyroot:
            Double = ctypes.c_double
        else:
            Double = ROOT.Double
        amin, edm, errdef = Double(), Double(), Double()
        if not exp_pyroot and sys.hexversion < 0x3000000:
            Long = ROOT.Long
            nvpar, nparx, icstat = Long(), Long(), Long()
        else:
            nvpar, nparx, icstat = ctypes.c_int(), ctypes.c_int(
            ), ctypes.c_int()
        gMinuit.mnstat(amin, edm, errdef, nvpar, nparx, icstat)
        # gMinuit.mnprin( 3, amin )

        if exp_pyroot or sys.hexversion >= 0x3000000:
            nvpar, nparx, icstat = map(lambda x: x.value,
                                       [nvpar, nparx, icstat])
        self.assertEqual(nvpar, 4)
        self.assertEqual(nparx, 4)

        # success means that full covariance matrix is available (icstat==3)
        self.assertEqual(icstat, 3)

        # check results (somewhat debatable ... )
        par, err = Double(), Double()

        if exp_pyroot:
            # ctypes.c_double requires the explicit retrieval of the inner value
            gMinuit.GetParameter(0, par, err)
            self.assertEqual(round(par.value - 2.15, 2), 0.)
            self.assertEqual(round(err.value - 0.10, 2), 0.)

            gMinuit.GetParameter(1, par, err)
            self.assertEqual(round(par.value - 0.81, 2), 0.)
            self.assertEqual(round(err.value - 0.25, 2), 0.)

            gMinuit.GetParameter(2, par, err)
            self.assertEqual(round(par.value - 0.17, 2), 0.)
            self.assertEqual(round(err.value - 0.40, 2), 0.)

            gMinuit.GetParameter(3, par, err)
            self.assertEqual(round(par.value - 0.10, 2), 0.)
            self.assertEqual(round(err.value - 0.16, 2), 0.)
        else:
            gMinuit.GetParameter(0, par, err)
            self.assertEqual(round(par - 2.15, 2), 0.)
            self.assertEqual(round(err - 0.10, 2), 0.)

            gMinuit.GetParameter(1, par, err)
            self.assertEqual(round(par - 0.81, 2), 0.)
            self.assertEqual(round(err - 0.25, 2), 0.)

            gMinuit.GetParameter(2, par, err)
            self.assertEqual(round(par - 0.17, 2), 0.)
            self.assertEqual(round(err - 0.40, 2), 0.)

            gMinuit.GetParameter(3, par, err)
            self.assertEqual(round(par - 0.10, 2), 0.)
            self.assertEqual(round(err - 0.16, 2), 0.)
コード例 #25
0
ファイル: ifit.py プロジェクト: degrutto/VHbbUF
def ifit():   
    gMinuit = TMinuit(npars)
    gMinuit.SetFCN(fcn)

    arglist = array('d', 10*[0.])
    ierflg = Long(1982)

    arglist[0] = 1  # 1 for chisquared fits, 0.5 for negative log likelihood
    gMinuit.mnexcm("SET ERR", arglist, 1, ierflg)

    arglist[0] = 0.00001  # floating point precision
    gMinuit.mnexcm("SET EPS", arglist, 1, ierflg)

    arglist[0] = 2 # 1 mean fewer function calls, 2 mean more reliable minimization
    gMinuit.mnexcm("SET STR", arglist, 1, ierflg)

    # Set starting values and step sizes for parameters
    vstart = array('d', npars*[1.0])
    #vstart = array('d', [0.909, 1.341, 0.942, 1.300, 1.003])
    step = array('d', npars*[0.001])
    gMinuit.mnparm(0, "ZjLF", vstart[0], step[0], 0, 0, ierflg)
    gMinuit.mnparm(1, "ZjHF", vstart[1], step[1], 0, 0, ierflg)
    gMinuit.mnparm(2, "WjLF", vstart[2], step[2], 0, 0, ierflg)
    gMinuit.mnparm(3, "WjHF", vstart[3], step[3], 1.3, 2.0, ierflg)
    gMinuit.mnparm(4, "TT"  , vstart[4], step[4], 0, 0, ierflg)

    # Fix parameter
    #arglist[0] = 1
    #gMinuit.mnexcm("FIX", arglist, 1, ierflg)
    #arglist[0] = 2
    #gMinuit.mnexcm("FIX", arglist, 1, ierflg)
    #arglist[0] = 3
    #gMinuit.mnexcm("FIX", arglist, 1, ierflg)
    #arglist[0] = 4
    #gMinuit.mnexcm("FIX", arglist, 1, ierflg)
    #arglist[0] = 5
    #gMinuit.mnexcm("FIX", arglist, 1, ierflg)

    # Scan for best parameter values
    #arglist[0] = 1
    #gMinuit.mnexcm("SCAN", arglist, 0, ierflg)

    # Now ready for minimization step
    arglist[0] = 500
    arglist[1] = 1.  # default: 0.1
    gMinuit.mnexcm("SIMPLEX", arglist, 2, ierflg)
    #gMinuit.mnexcm("MIGRAD", arglist, 2, ierflg)

    # Search for additional distinct local minima
    #arglist[0] = 10000 
    #gMinuit.mnexcm("IMP", arglist, 1, ierflg)

    # Do error analysis
    gMinuit.mnexcm("HESSE", arglist, 0, ierflg)
    #arglist[0] = 10000
    #gMinuit.mnexcm("MINOS", arglist, 1, ierflg)

    # Print results
    amin, edm, errdef = Double(0.18), Double(0.19), Double(0.20)  # passing doubles by reference is allowed, as long as on the python side doubles are unique (init them with different values, for example).
    nvpar, nparx, icstat = Long(1986), Long(1987), Long(1988)
    gMinuit.mnstat(amin, edm, errdef, nvpar, nparx, icstat)
    gMinuit.mnprin(5, amin)

    ndf = 0
    for i in xrange(len(data[0])):  # loop over all bins
        mc_ = [m[i] for m in mc]
        if sum(mc_) < tolerance:
            continue
        if data[0][i] < tolerance:
            continue
        ndf += 1

    print "chi^2 = ", amin, ", NDF = ", ndf, ", chi^2/NDF = ", amin/ndf, ", prob = ", TMath.Prob(amin,ndf)
    print "amin: ", amin, ", edm: ", edm, ", errdef: ", errdef, ", nvpar: ", nvpar, ", nparx: ", nparx, ", icstat: ", icstat
    print "c0: ", vstart[0], ", c1: ", vstart[1], ", c2: ", vstart[2], ", c3: ", vstart[3], ", c4: ", vstart[4]
コード例 #26
0
class MinimizerROOTTMinuit(MinimizerBase):
    def __init__(self,
                 parameter_names,
                 parameter_values,
                 parameter_errors,
                 function_to_minimize,
                 tolerance=1e-9,
                 errordef=MinimizerBase.ERRORDEF_CHI2,
                 strategy=1):
        self._strategy = strategy

        self._par_bounds = np.array([None] * len(parameter_names))
        self._par_fixed = np.array([False] * len(parameter_names))

        self.reset()  # sets self.__gMinuit and caches to None
        super(MinimizerROOTTMinuit,
              self).__init__(parameter_names=parameter_names,
                             parameter_values=parameter_values,
                             parameter_errors=parameter_errors,
                             function_to_minimize=function_to_minimize,
                             tolerance=tolerance,
                             errordef=errordef)

    # -- private methods

    def _save_state(self):
        if self._par_val is None:
            self._save_state_dict["par_val"] = self._par_val
        else:
            self._save_state_dict["par_val"] = np.array(self._par_val)
        if self._par_err is None:
            self._save_state_dict["par_err"] = self._par_err
        else:
            self._save_state_dict["par_err"] = np.array(self._par_err)
        self._save_state_dict['par_fixed'] = np.array(self._par_fixed)
        self._save_state_dict['gMinuit'] = self.__gMinuit
        super(MinimizerROOTTMinuit, self)._save_state()

    def _load_state(self):
        self.reset()
        self._par_val = self._save_state_dict["par_val"]
        if self._par_val is not None:
            self._par_val = np.array(self._par_val)
        self._par_err = self._save_state_dict["par_err"]
        if self._par_err is not None:
            self._par_err = np.array(self._par_err)
        self._par_fixed = np.array(self._save_state_dict['par_fixed'])
        self.__gMinuit = self._save_state_dict['gMinuit']
        # call the function to propagate the changes to the nexus:
        self._func_handle(*self.parameter_values)
        super(MinimizerROOTTMinuit, self)._load_state()

    def _recreate_gMinuit(self):
        self.__gMinuit = TMinuit(self.num_pars)
        self.__gMinuit.SetPrintLevel(-1)
        self.__gMinuit.mncomd("SET STRATEGY {}".format(self._strategy),
                              ctypes.c_int(0))
        self.__gMinuit.SetFCN(self._minuit_fcn)
        self.__gMinuit.SetErrorDef(self._err_def)

        # set gMinuit parameters
        error_code = ctypes.c_int(0)
        for _pid, (_pn, _pv, _pe) in enumerate(
                zip(self._par_names, self._par_val, self._par_err)):
            self.__gMinuit.mnparm(_pid, _pn, _pv, 0.1 * _pe, 0, 0, error_code)

        err_code = ctypes.c_int(0)
        # set fixed parameters
        for _par_id, _pf in enumerate(self._par_fixed):
            if _pf:
                self.__gMinuit.mnfixp(_par_id, err_code)

        # set parameter limits
        for _par_id, _pb in enumerate(self._par_bounds):
            if _pb is not None:
                _lo_lim, _up_lim = _pb
                self.__gMinuit.mnexcm(
                    "SET LIM", arr('d', [_par_id + 1, _lo_lim, _up_lim]), 3,
                    error_code)

    def _get_gMinuit(self):
        if self.__gMinuit is None:
            self._recreate_gMinuit()
        return self.__gMinuit

    def _migrad(self, max_calls=6000):
        # need to set the FCN explicitly before every call
        self._get_gMinuit().SetFCN(self._minuit_fcn)
        error_code = ctypes.c_int(0)
        self._get_gMinuit().mnexcm("MIGRAD",
                                   arr('d', [max_calls, self.tolerance]), 2,
                                   error_code)

    def _minuit_fcn(self, number_of_parameters, derivatives, f, parameters,
                    internal_flag):
        """
        This is actually a function called in *ROOT* and acting as a C wrapper
        for our `FCN`, which is implemented in Python.

        This function is called by `Minuit` several times during a fitters. It
        doesn't return anything but modifies one of its arguments (*f*).
        This is *ugly*, but it's how *ROOT*'s ``TMinuit`` works. Its argument
        structure is fixed and determined by `Minuit`:

        **number_of_parameters** : int
            The number of parameters of the current fitters

        **derivatives** : C array
            If the user chooses to calculate the first derivative of the
            function inside the `FCN`, this value should be written here. This
            interface to `Minuit` ignores this derivative, however, so
            calculating this inside the `FCN` has no effect (yet).

        **f** : C array
            The desired function value is in f[0] after execution.

        **parameters** : C array
            A C array of parameters. Is cast to a Python list

        **internal_flag** : int
            A flag allowing for different behaviour of the function.
            Can be any integer from 1 (initial run) to 4(normal run). See
            `Minuit`'s specification.
        """

        # Retrieve the parameters from the C side of ROOT and
        # store them in a Python list -- resource-intensive
        # for many calls, but can't be improved (yet?)
        parameter_list = np.frombuffer(parameters,
                                       dtype=float,
                                       count=self.num_pars)

        # call the Python implementation of FCN.
        f[0] = self._func_wrapper(*parameter_list)

    def _calculate_asymmetric_parameter_errors(self):
        self._get_gMinuit().mnmnos()
        _asymm_par_errs = np.zeros(shape=(self.num_pars, 2))
        for _n in range(self.num_pars):
            _number = Long(_n)
            _eplus = ctypes.c_double(0)
            _eminus = ctypes.c_double(0)
            _eparab = ctypes.c_double(0)
            _gcc = ctypes.c_double(0)
            self._get_gMinuit().mnerrs(_number, _eplus, _eminus, _eparab, _gcc)
            _asymm_par_errs[_n, 0] = _eminus.value
            _asymm_par_errs[_n, 1] = _eplus.value
        self.minimize()
        return _asymm_par_errs

    def _get_fit_info(self, info):
        '''Retrieves other info from `Minuit`.
        **info** : string
            Information about the fit to retrieve.
            This can be any of the following:
              - ``'fcn'``: `FCN` value at minimum,
              - ``'edm'``: estimated distance to minimum
              - ``'err_def'``: `Minuit` error matrix status code
              - ``'status_code'``: `Minuit` general status code
        '''

        # declare vars in which to retrieve other info
        fcn_at_min = ctypes.c_double(0)
        edm = ctypes.c_double(0)
        err_def = ctypes.c_double(0)
        n_var_param = ctypes.c_int(0)
        n_tot_param = ctypes.c_int(0)
        status_code = ctypes.c_int(0)

        # Tell TMinuit to update the variables declared above
        self.__gMinuit.mnstat(fcn_at_min, edm, err_def, n_var_param,
                              n_tot_param, status_code)

        if info == 'fcn':
            return fcn_at_min.value
        elif info == 'edm':
            return edm.value
        elif info == 'err_def':
            return err_def.value
        elif info == 'status_code':
            return status_code.value
        else:
            raise ValueError("Unknown fit info: %s" % info)

    # -- public properties

    @property
    def hessian(self):
        if not self.did_fit:
            return None
        if self._hessian is None:
            _submat = self._remove_zeroes_for_fixed(self.cov_mat)
            _submat_inv = 2.0 * self.errordef * np.linalg.inv(_submat)
            self._hessian = self._fill_in_zeroes_for_fixed(_submat_inv)
        return self._hessian.copy()

    @property
    def cov_mat(self):
        if not self.did_fit:
            return None
        if self._par_cov_mat is None:
            _n_pars_total = self.num_pars
            _tmp_mat_array = arr('d', [0.0] * (_n_pars_total**2))
            # get parameter covariance matrix from TMinuit
            self._get_gMinuit().mnemat(_tmp_mat_array, _n_pars_total)
            # reshape into 2D array
            _sub_cov_mat = np.asarray(np.reshape(
                _tmp_mat_array, (_n_pars_total, _n_pars_total)),
                                      dtype=np.float)
            _num_pars_free = np.sum(np.invert(self._par_fixed))
            _sub_cov_mat = _sub_cov_mat[:_num_pars_free, :_num_pars_free]
            self._par_cov_mat = self._fill_in_zeroes_for_fixed(_sub_cov_mat)
        return self._par_cov_mat.copy()

    @property
    def hessian_inv(self):
        if not self.did_fit:
            return None
        if self._hessian_inv is None:
            self._hessian_inv = self.cov_mat / (2.0 * self.errordef)
        return self._hessian_inv.copy()

    @property
    def parameter_values(self):
        return self._par_val.copy()

    @parameter_values.setter
    def parameter_values(self, new_values):
        self._par_val = np.array(new_values)
        self.reset()

    @property
    def parameter_errors(self):
        return self._par_err.copy()

    @parameter_errors.setter
    def parameter_errors(self, new_errors):
        _err_array = np.array(new_errors)
        if not np.all(_err_array > 0):
            raise ValueError("All parameter errors must be > 0! Received: %s" %
                             new_errors)
        self._par_err = _err_array
        self.reset()

    # -- private "properties"

    # -- public methods

    def reset(self):
        super(MinimizerROOTTMinuit, self).reset()
        self.__gMinuit = None

    def set(self, parameter_name, parameter_value):
        if parameter_name not in self._par_names:
            raise ValueError("No parameter named '%s'!" % (parameter_name, ))
        _par_id = self.parameter_names.index(parameter_name)
        self._par_val[_par_id] = parameter_value
        self.reset()

    def fix(self, parameter_name):
        # set local flag
        _par_id = self.parameter_names.index(parameter_name)
        if self._par_fixed[_par_id]:
            return  # par is already fixed
        self._par_fixed[_par_id] = True
        if self.__gMinuit is not None:
            # also update Minuit instance
            err_code = ctypes.c_int(0)
            self.__gMinuit.mnfixp(_par_id, err_code)
            # self.__gMinuit.mnexcm("FIX",
            #                   arr('d', [_par_id+1]), 1, error_code)
        self._invalidate_cache()

    def is_fixed(self, parameter_name):
        _par_id = self.parameter_names.index(parameter_name)
        return self._par_fixed[_par_id]

    def release(self, parameter_name):
        # set local flag
        _par_id = self.parameter_names.index(parameter_name)
        if not self._par_fixed[_par_id]:
            return  # par is already released
        self._par_fixed[_par_id] = False
        if self.__gMinuit is not None:
            # also update Minuit instance
            self.__gMinuit.mnfree(-_par_id - 1)
            # self.__gMinuit.mnexcm("RELEASE",
            #                   arr('d', [_par_id+1]), 1, error_code)
        self._invalidate_cache()

    def limit(self, parameter_name, parameter_bounds):
        assert len(parameter_bounds) == 2
        if parameter_bounds[0] is None or parameter_bounds[1] is None:
            raise MinimizerROOTTMinuitException(
                "Cannot define one-sided parameter limits when using the ROOT TMinuit Minimizer."
            )
        # set local flag
        _par_id = self.parameter_names.index(parameter_name)
        if self._par_bounds[_par_id] == parameter_bounds:
            return  # same limits already set
        if self._par_val[_par_id] < parameter_bounds[0]:
            self.set(parameter_name, parameter_bounds[0])
        elif self._par_val[_par_id] > parameter_bounds[1]:
            self.set(parameter_name, parameter_bounds[1])
        self._par_bounds[_par_id] = parameter_bounds
        if self.__gMinuit is not None:
            _lo_lim, _up_lim = self._par_bounds[_par_id]
            # also update Minuit instance
            error_code = ctypes.c_int(0)
            self.__gMinuit.mnexcm("SET LIM",
                                  arr('d', [_par_id + 1, _lo_lim, _up_lim]), 3,
                                  error_code)
            self._did_fit = False
        self._invalidate_cache()

    def unlimit(self, parameter_name):
        # set local flag
        _par_id = self.parameter_names.index(parameter_name)
        if self._par_bounds[_par_id] is None:
            return  # parameter is already unlimited
        self._par_bounds[_par_id] = None
        if self.__gMinuit is not None:
            # also update Minuit instance
            error_code = ctypes.c_int(0)
            self.__gMinuit.mnexcm("SET LIM", arr('d', [_par_id + 1]), 1,
                                  error_code)
            self._did_fit = False
        self._invalidate_cache()

    def minimize(self, max_calls=6000):
        if np.all(self._par_fixed):
            raise MinimizerROOTTMinuitException(
                "Cannot perform a fit if all parameters are fixed!")
        self._migrad(max_calls=max_calls)

        # retrieve fitters parameters
        self._par_val = np.zeros(self.num_pars)
        self._par_err = np.zeros(self.num_pars)
        _pv, _pe = ctypes.c_double(0), ctypes.c_double(0)
        for _par_id in six.moves.range(0, self.num_pars):
            self.__gMinuit.GetParameter(_par_id, _pv,
                                        _pe)  # retrieve fit result
            self._par_val[_par_id] = _pv.value
            self._par_err[_par_id] = _pe.value

        self._did_fit = True

    def contour(self,
                parameter_name_1,
                parameter_name_2,
                sigma=1.0,
                **minimizer_contour_kwargs):
        if not self.did_fit:
            raise MinimizerROOTTMinuitException(
                "Need to perform a fit before calling contour()!")
        _numpoints = minimizer_contour_kwargs.pop("numpoints", 100)
        if minimizer_contour_kwargs:
            raise MinimizerROOTTMinuitException(
                "Unknown parameters: {}".format(minimizer_contour_kwargs))
        _id_1 = self.parameter_names.index(parameter_name_1)
        _id_2 = self.parameter_names.index(parameter_name_2)
        self.__gMinuit.SetErrorDef(sigma**2)
        _t_graph = self.__gMinuit.Contour(_numpoints, _id_1, _id_2)
        self.__gMinuit.SetErrorDef(self._err_def)

        _x_buffer, _y_buffer = _t_graph.GetX(), _t_graph.GetY()
        _N = _t_graph.GetN()

        _x = np.frombuffer(_x_buffer, dtype=float, count=_N)
        _y = np.frombuffer(_y_buffer, dtype=float, count=_N)
        self._func_handle(*self.parameter_values)
        return ContourFactory.create_xy_contour((_x, _y), sigma)

    def profile(self,
                parameter_name,
                bins=21,
                bound=2,
                args=None,
                subtract_min=False):
        if not self.did_fit:
            raise MinimizerROOTTMinuitException(
                "Need to perform a fit before calling profile()!")

        MAX_ITERATIONS = 6000

        _error_code = ctypes.c_int(0)
        _minuit_id = Long(self.parameter_names.index(parameter_name) + 1)

        _par_min = ctypes.c_double(0)
        _par_err = ctypes.c_double(0)
        self.__gMinuit.GetParameter(_minuit_id - 1, _par_min, _par_err)
        _par_min = _par_min.value
        _par_err = _par_err.value

        _x = np.linspace(start=_par_min - bound * _par_err,
                         stop=_par_min + bound * _par_err,
                         num=bins,
                         endpoint=True)

        self.__gMinuit.mnexcm("FIX", arr('d', [_minuit_id]), 1, _error_code)

        _y = np.zeros(bins)
        for i in range(bins):
            self.__gMinuit.mnexcm("SET PAR",
                                  arr('d',
                                      [_minuit_id, Double(_x[i])]), 2,
                                  _error_code)
            self.__gMinuit.mnexcm("MIGRAD",
                                  arr('d', [MAX_ITERATIONS, self.tolerance]),
                                  2, _error_code)
            _y[i] = self._get_fit_info("fcn")

        self.__gMinuit.mnexcm("RELEASE", arr('d', [_minuit_id]), 1,
                              _error_code)
        self._migrad()
        self.__gMinuit.mnexcm("SET PAR",
                              arr('d',
                                  [_minuit_id, Double(_par_min)]), 2,
                              _error_code)

        if subtract_min:
            _y -= self.function_value

        return np.asarray((_x, _y))
コード例 #27
0
def Minuit(fun,
           x0,
           args=(),
           bounds=None,
           verbose=0,
           step_size=0.01,
           n_iterations=500,
           delta_one_sigma=0.5,
           **options):
    """
    Interface to ROOT Minuit
    @param bounds list of tuple with limits for each variable
    @param verbose -1 (silent) 0 (normal) 1 (verbose)
    @param step_size float or Sequence
    @param n_iterations maximum number of iterations
    @param delta_one_sigma delta in loss function which corresponds to one sigma errors
    """
    from ROOT import TMinuit, Double, Long
    n_parameters = len(x0)

    def to_minimize(npar, deriv, f, apar, iflag):
        f[0] = fun(np.array([apar[i] for i in range(n_parameters)]), *args)

    minuit = TMinuit(n_parameters)
    minuit.SetFCN(to_minimize)

    minuit.SetPrintLevel(verbose)

    ierflg = np.array(0, dtype=np.int32)
    minuit.mnexcm("SET ERR", np.array([delta_one_sigma]), 1, ierflg)

    if ierflg > 0:
        raise RuntimeError("Error during \"SET ERR\" call")

    for i in range(n_parameters):
        low, high = 0.0, 0.0  # Zero seems to mean no limit
        if bounds is not None:
            low, high = bounds[i]
        minuit.mnparm(
            i, 'Parameter_{}'.format(i), x0[i], step_size[i] if isinstance(
                step_size, collections.Sequence) else step_size, low, high,
            ierflg)
        if ierflg > 0:
            raise RuntimeError(
                "Error during \"nmparm\" call for parmameter {}".format(i))

    minuit.mnexcm("MIGRAD", np.array([n_iterations, 0.01], dtype=np.float64),
                  2, ierflg)

    if ierflg > 0:
        raise RuntimeError("Error during \"MIGRAD\" call")

    xbest = np.zeros(n_parameters)
    xbest_error = np.zeros(n_parameters)

    p, pe = Double(0), Double(0)
    for i in range(n_parameters):
        minuit.GetParameter(i, p, pe)
        xbest[i] = p
        xbest_error[i] = pe

    buf = array.array('d', [0.] * (n_parameters**2))
    minuit.mnemat(buf, n_parameters)  # retrieve error matrix
    hessian = np.array(buf).reshape(n_parameters, n_parameters)

    amin = Double(0.)  # value of fcn at minimum
    edm = Double(0.)  # estimated distance to mimimum
    errdef = Double(0.)  # delta_fcn used to define 1 sigma errors
    nvpar = np.array(0, dtype=np.int32)  # number of variable parameters
    nparx = np.array(0, dtype=np.int32)  # total number of parameters
    icstat = np.array(
        0, dtype=np.int32
    )  # status of error matrix: 3=accurate 2=forced pos. def 1= approximative 0=not calculated
    minuit.mnstat(amin, edm, errdef, nvpar, nparx, icstat)

    return scipy.optimize.OptimizeResult(x=xbest,
                                         fun=amin,
                                         hessian=hessian,
                                         success=(ierflg == 0),
                                         status=ierflg)
コード例 #28
0
class MinimizerROOTTMinuit(MinimizerBase):
    def __init__(self,
                 parameter_names, parameter_values, parameter_errors,
                 function_to_minimize, strategy = 1):
        self._par_names = parameter_names
        self._strategy = strategy

        self._func_handle = function_to_minimize
        self._err_def = 1.0
        self._tol = 0.001

        # initialize the minimizer parameter specification
        self._minimizer_param_dict = {}
        assert len(parameter_names) == len(parameter_values) == len(parameter_errors)
        self._par_val = []
        self._par_err = []
        self._par_fixed_mask = []
        self._par_limits = []
        for _pn, _pv, _pe in zip(parameter_names, parameter_values, parameter_errors):
            self._par_val.append(_pv)
            self._par_err.append(_pe)
            self._par_fixed_mask.append(False)
            self._par_limits.append(None)
            # TODO: limits/fixed parameters

        self.__gMinuit = None

        # cache for calculations
        self._hessian = None
        self._hessian_inv = None
        self._fval = None
        self._par_cov_mat = None
        self._par_cor_mat = None
        self._par_asymm_err = None
        self._fmin_struct = None
        self._pars_contour = None

        self._min_result_stale = True
        self._printed_inf_cost_warning = False

    # -- private methods

    # def _invalidate_cache(self):
    #     self._par_val = None
    #     self._par_err = None
    #     self._hessian = None
    #     self._hessian_inv = None
    #     self._fval = None
    #     self._par_cov_mat = None
    #     self._par_cor_mat = None
    #     self._par_asymm_err_dn = None
    #     self._par_asymm_err_up = None
    #     self._fmin_struct = None
    #     self._pars_contour = None

    def _recreate_gMinuit(self):
        self.__gMinuit = TMinuit(self.n_pars)
        self.__gMinuit.SetPrintLevel(-1)
        self.__gMinuit.mncomd("SET STRATEGY {}".format(self._strategy), Long(0))
        self.__gMinuit.SetFCN(self._minuit_fcn)
        self.__gMinuit.SetErrorDef(self._err_def)

        # set gMinuit parameters
        error_code = Long(0)
        for _pid, (_pn, _pv, _pe) in enumerate(zip(self._par_names, self._par_val, self._par_err)):
            self.__gMinuit.mnparm(_pid,
                                  _pn,
                                  _pv,
                                  0.1 * _pe,
                                  0, 0, error_code)

        err_code = Long(0)
        # set fixed parameters
        for _par_id, _pf in enumerate(self._par_fixed_mask):
            if _pf:
                self.__gMinuit.mnfixp(_par_id, err_code)

        # set parameter limits
        for _par_id, _pl in enumerate(self._par_limits):
            if _pl is not None:
                _lo_lim, _up_lim = _pl
                self.__gMinuit.mnexcm("SET LIM",
                                      arr('d', [_par_id + 1, _lo_lim, _up_lim]), 3, error_code)

    def _get_gMinuit(self):
        if self.__gMinuit is None:
            self._recreate_gMinuit()
        return self.__gMinuit

    def _migrad(self, max_calls=6000):
        # need to set the FCN explicitly before every call
        self._get_gMinuit().SetFCN(self._minuit_fcn)
        error_code = Long(0)
        self._get_gMinuit().mnexcm("MIGRAD",
                                    arr('d', [max_calls, self.tolerance]),
                                    2, error_code)

    def _hesse(self, max_calls=6000):
        # need to set the FCN explicitly before every call
        self._get_gMinuit().SetFCN(self._minuit_fcn)
        error_code = Long(0)
        self._get_gMinuit().mnexcm("HESSE", arr('d', [max_calls]), 1, error_code)

    def _minuit_fcn(self,
                    number_of_parameters, derivatives, f, parameters, internal_flag):
        """
        This is actually a function called in *ROOT* and acting as a C wrapper
        for our `FCN`, which is implemented in Python.

        This function is called by `Minuit` several times during a fitters. It
        doesn't return anything but modifies one of its arguments (*f*).
        This is *ugly*, but it's how *ROOT*'s ``TMinuit`` works. Its argument
        structure is fixed and determined by `Minuit`:

        **number_of_parameters** : int
            The number of parameters of the current fitters

        **derivatives** : C array
            If the user chooses to calculate the first derivative of the
            function inside the `FCN`, this value should be written here. This
            interface to `Minuit` ignores this derivative, however, so
            calculating this inside the `FCN` has no effect (yet).

        **f** : C array
            The desired function value is in f[0] after execution.

        **parameters** : C array
            A C array of parameters. Is cast to a Python list

        **internal_flag** : int
            A flag allowing for different behaviour of the function.
            Can be any integer from 1 (initial run) to 4(normal run). See
            `Minuit`'s specification.
        """

        # Retrieve the parameters from the C side of ROOT and
        # store them in a Python list -- resource-intensive
        # for many calls, but can't be improved (yet?)
        parameter_list = np.frombuffer(parameters,
                                       dtype=float,
                                       count=self.n_pars)

        # call the Python implementation of FCN.
        f[0] = self._func_wrapper(*parameter_list)

    def _insert_zeros_for_fixed(self, submatrix):
        """
        Takes the partial error matrix (submatrix) and adds
        rows and columns with 0.0 where the fixed
        parameters should go.
        """
        _mat = submatrix

        # reduce the matrix before inserting zeros
        _n_pars_free = self.n_pars_free
        _mat = _mat[0:_n_pars_free,0:_n_pars_free]

        _fparam_ids = [_par_id for _par_id, _p in enumerate(self._par_fixed_mask) if _p]
        for _id in _fparam_ids:
            _mat = np.insert(np.insert(_mat, _id, 0., axis=0), _id, 0., axis=1)

        return _mat

    # -- public properties

    def get_fit_info(self, info):
        '''Retrieves other info from `Minuit`.
        **info** : string
            Information about the fit to retrieve.
            This can be any of the following:
              - ``'fcn'``: `FCN` value at minimum,
              - ``'edm'``: estimated distance to minimum
              - ``'err_def'``: `Minuit` error matrix status code
              - ``'status_code'``: `Minuit` general status code
        '''

        # declare vars in which to retrieve other info
        fcn_at_min = Double(0)
        edm = Double(0)
        err_def = Double(0)
        n_var_param = Long(0)
        n_tot_param = Long(0)
        status_code = Long(0)

        # Tell TMinuit to update the variables declared above
        self.__gMinuit.mnstat(fcn_at_min,
                              edm,
                              err_def,
                              n_var_param,
                              n_tot_param,
                              status_code)

        if info == 'fcn':
            return fcn_at_min

        elif info == 'edm':
            return edm

        elif info == 'err_def':
            return err_def

        elif info == 'status_code':
            try:
                return D_MATRIX_ERROR[status_code]
            except:
                return status_code


    @property
    def n_pars(self):
        return len(self.parameter_names)

    @property
    def n_pars_free(self):
        return len([_p for _p in self._par_fixed_mask if not _p])

    @property
    def errordef(self):
        return self._err_def

    @errordef.setter
    def errordef(self, err_def):
        assert err_def > 0
        self._err_def = err_def
        if self.__gMinuit is not None:
            self.__gMinuit.set_errordef(err_def)
            self._min_result_stale = True

    @property
    def tolerance(self):
        return self._tol

    @tolerance.setter
    def tolerance(self, tolerance):
        assert tolerance > 0
        self._tol = tolerance
        self._min_result_stale = True

    @property
    def hessian(self):
        # TODO: cache this
        return 2.0 * self.errordef * np.linalg.inv(self.cov_mat)

    @property
    def cov_mat(self):
        if self._min_result_stale:
            raise MinimizerROOTTMinuitException("Cannot get cov_mat: Minimizer result is outdated.")
        if self._par_cov_mat is None:
            _n_pars_total = self.n_pars
            _n_pars_free = self.n_pars_free
            _tmp_mat_array = arr('d', [0.0]*(_n_pars_total**2))
            # get parameter covariance matrix from TMinuit
            self.__gMinuit.mnemat(_tmp_mat_array, _n_pars_total)
            # reshape into 2D array
            _sub_cov_mat = np.asarray(
                np.reshape(
                    _tmp_mat_array,
                    (_n_pars_total, _n_pars_total)
                )
            )
            self._par_cov_mat = self._insert_zeros_for_fixed(_sub_cov_mat)
        return self._par_cov_mat

    @property
    def cor_mat(self):
        if self._min_result_stale:
            raise MinimizerROOTTMinuitException("Cannot get cor_mat: Minimizer result is outdated.")
        if self._par_cor_mat is None:
            _cov_mat = self.cov_mat
            # TODO: use CovMat object!
            # Note: for zeros on cov_mat diagonals (which occur for fixed parameters) -> overwrite with 1.0
            _sqrt_diag = np.array([_err if _err>0 else 1.0 for _err in np.sqrt(np.diag(_cov_mat))])
            self._par_cor_mat = np.asarray(_cov_mat) / np.outer(_sqrt_diag, _sqrt_diag)
        return self._par_cor_mat

    @property
    def hessian_inv(self):
        return self.cov_mat / 2.0 / self.errordef

    @property
    def parameter_values(self):
        return self._par_val

    @property
    def parameter_errors(self):
        return self._par_err

    @property
    def parameter_names(self):
        return self._par_names

    # -- private "properties"


    # -- public methods

    def fix(self, parameter_name):
        # set local flag
        _par_id = self.parameter_names.index(parameter_name)
        if self._par_fixed_mask[_par_id]:
            return  # par is already fixed
        self._par_fixed_mask[_par_id] = True
        if self.__gMinuit is not None:
            # also update Minuit instance
            err_code = Long(0)
            self.__gMinuit.mnfixp(_par_id, err_code)
            # self.__gMinuit.mnexcm("FIX",
            #                   arr('d', [_par_id+1]), 1, error_code)
            self._min_result_stale = True

    def fix_several(self, parameter_names):
        for _pn in parameter_names:
            self.fix(_pn)

    def release(self, parameter_name):
        # set local flag
        _par_id = self.parameter_names.index(parameter_name)
        if not self._par_fixed_mask[_par_id]:
            return  # par is already released
        self._par_fixed_mask[_par_id] = False
        if self.__gMinuit is not None:
            # also update Minuit instance
            self.__gMinuit.mnfree(-_par_id-1)
            # self.__gMinuit.mnexcm("RELEASE",
            #                   arr('d', [_par_id+1]), 1, error_code)
            self._min_result_stale = True

    def release_several(self, parameter_names):
        for _pn in parameter_names:
            self.release(_pn)

    def limit(self, parameter_name, parameter_bounds):
        assert len(parameter_bounds) == 2
        # set local flag
        _par_id = self.parameter_names.index(parameter_name)
        if self._par_limits[_par_id] == parameter_bounds:
            return  # same limits already set
        self._par_limits[_par_id] = parameter_bounds
        if self.__gMinuit is not None:
            _lo_lim, _up_lim = self._par_limits[_par_id]
            # also update Minuit instance
            error_code = Long(0)
            self.__gMinuit.mnexcm("SET LIM",
                     arr('d', [_par_id+1, _lo_lim, _up_lim]), 3, error_code)
            self._min_result_stale = True

    def unlimit(self, parameter_name):
        # set local flag
        _par_id = self.parameter_names.index(parameter_name)
        if self._par_limits[_par_id] is None:
            return  # parameter is already unlimited
        self._par_limits[_par_id] = None
        if self.__gMinuit is not None:
            # also update Minuit instance
            error_code = Long(0)
            self.__gMinuit.mnexcm("SET LIM",
                     arr('d', [_par_id+1]), 1, error_code)
            self._min_result_stale = True

    def minimize(self, max_calls=6000):
        self._migrad(max_calls=max_calls)

        # retrieve fitters parameters
        self._par_val = []
        self._par_err = []
        _pv, _pe = Double(0), Double(0)
        for _par_id in six.moves.range(0, self.n_pars):
            self.__gMinuit.GetParameter(_par_id, _pv, _pe)  # retrieve fitresult
            self._par_val.append(float(_pv))
            self._par_err.append(float(_pe))

        self._min_result_stale = False
        
    def contour(self, parameter_name_1, parameter_name_2, sigma=1.0, **minimizer_contour_kwargs):
        if self.__gMinuit is None:
            raise MinimizerROOTTMinuitException("Need to perform a fit before calling contour()!")
        _numpoints = minimizer_contour_kwargs.pop("numpoints", 100)
        if minimizer_contour_kwargs:
            raise MinimizerROOTTMinuitException("Unknown parameters: {}".format(minimizer_contour_kwargs))
        _id_1 = self.parameter_names.index(parameter_name_1)
        _id_2 = self.parameter_names.index(parameter_name_2)
        self.__gMinuit.SetErrorDef(sigma ** 2)
        _t_graph = self.__gMinuit.Contour(_numpoints, _id_1, _id_2)
        self.__gMinuit.SetErrorDef(self._err_def)
        
        _x_buffer, _y_buffer = _t_graph.GetX(), _t_graph.GetY()
        _N = _t_graph.GetN()
        
        _x = np.frombuffer(_x_buffer, dtype=float, count=_N)
        _y = np.frombuffer(_y_buffer, dtype=float, count=_N)
        self._func_handle(*self.parameter_values)
        return ContourFactory.create_xy_contour((_x, _y), sigma)
    
    def profile(self, parameter_name, bins=21, bound=2, args=None, subtract_min=False):
        if self.__gMinuit is None:
            raise MinimizerROOTTMinuitException("Need to perform a fit before calling profile()!")
        
        MAX_ITERATIONS = 6000
        
        _error_code = Long(0)
        _minuit_id = Long(self.parameter_names.index(parameter_name) + 1)



        _par_min = Double(0)
        _par_err = Double(0)
        
        self.__gMinuit.GetParameter(_minuit_id - 1, _par_min, _par_err)

        _x = np.linspace(start=_par_min - bound * _par_err, stop=_par_min + bound * _par_err, num=bins, endpoint=True)

        self.__gMinuit.mnexcm("FIX", arr('d', [_minuit_id]), 1, _error_code)

        _y = np.zeros(bins)
        for i in range(bins):
            self.__gMinuit.mnexcm("SET PAR", arr('d', [_minuit_id, Double(_x[i])]), 2, _error_code)
            self.__gMinuit.mnexcm("MIGRAD", arr('d', [MAX_ITERATIONS, self.tolerance]), 2, _error_code)
            _y[i] = self.get_fit_info("fcn")

        self.__gMinuit.mnexcm("RELEASE", arr('d', [_minuit_id]), 1, _error_code)
        self._migrad()
        self.__gMinuit.mnexcm("SET PAR", arr('d', [_minuit_id, Double(_par_min)]), 2, _error_code)

        
        return np.asarray((_x, _y))