Write a program that fits the events saved in the file
dati.txt.
Take care to determine the range and binning of the histogram used for the fit
based on the events themselves,
writing appropriate algorithms to determine the minimum and maximum of the sample
and a reasonable estimate of the number of bins to use.
Determine the initial values of the fit parameters
using the techniques described in the lesson.
Print the fit result on the screen.
Plot the histogram with the fitted model overlaid.
Which parameters are correlated, and which are anti-correlated with each other?
importnumpyasnpfrommathimportfloor,ceilfrommatplotlibimportpyplotasplt# read the filewithopen('dati.txt')asf:sample=[float(x)forxinf.readlines()]# show its content in a histogramsample_mean=np.mean(sample)sample_sigma=np.std(sample)# first guess of x_axis range, before looking at the histogram# x_min = sample_mean - 3 * sample_sigma # x_max = sample_mean + 3 * sample_sigmax_min=floor(min(sample))x_max=ceil(max(sample))x_range=(x_min,x_max)N_bins=floor(len(sample)/100)# build a numpy histogram containing the data counts in each binbin_content,bin_edges=np.histogram(sample,bins=N_bins,range=x_range)fig,ax=plt.subplots()ax.set_title('dati.txt',size=14)ax.set_xlabel('variable')ax.set_ylabel('events in bin')ax.hist(sample,bins=bin_edges,color='orange',)plt.show()
fromiminuitimportMinuitfromscipy.statsimportexpon,normfromiminuit.costimportExtendedBinnedNLL# the fitting functiondefmod_total(bin_edges,N_signal,mu,sigma,N_background,tau):returnN_signal*norm.cdf(bin_edges,mu,sigma)+ \
N_background*expon.cdf(bin_edges,0,tau)N_events=sum(bin_content)# the cost function for the fitmy_cost_func=ExtendedBinnedNLL(bin_content,bin_edges,mod_total)# the fitting algoritmmy_minuit=Minuit(my_cost_func,N_signal=N_events,mu=sample_mean,sigma=sample_sigma,# signal input parametersN_background=N_events,tau=1.)# background input parameters# bounds the following parameters to being positivemy_minuit.limits['N_signal','N_background','sigma','tau']=(0,None)
to determine the background parameters to be used as starting point for the final fit
# fixing the following parameters,# setting the signal to zero for a first background-only preliminary fitmy_minuit.values["N_signal"]=0my_minuit.fixed["N_signal","mu","sigma"]=True# we temporarily mask out the signalbin_centres=0.5*(bin_edges[1:]+bin_edges[:-1])my_cost_func.mask=(bin_centres<5)|(15<bin_centres)my_minuit.migrad()my_minuit.minos()print(my_minuit.valid)display(my_minuit)
to estimate the signal parameters to be used as starting point for the final fit
my_cost_func.mask=None# remove maskmy_minuit.fixed=False# release all parametersmy_minuit.fixed["N_background","tau"]=True# fix background amplitudemy_minuit.values["N_signal"]=N_events-my_minuit.values["N_background"]# do not start at the limitmy_minuit.migrad()my_minuit.minos()print(my_minuit.valid)display(my_minuit)
True
Migrad
FCN = 88.68 (χ²/ndof = 0.9)
Nfcn = 406
EDM = 8.41e-08 (Goal: 0.0002)
Valid Minimum
Below EDM threshold (goal x 10)
No parameters at limit
Below call limit
Hesse ok
Covariance accurate
Name
Value
Hesse Error
Minos Error-
Minos Error+
Limit-
Limit+
Fixed
0
N_signal
2.23e3
0.07e3
-0.07e3
0.07e3
0
1
mu
9.99
0.08
-0.08
0.08
2
sigma
2.04
0.06
-0.06
0.07
0
3
N_background
7.98e3
0.13e3
-0.13e3
0.13e3
0
yes
4
tau
5.2
0.1
-0.1
0.1
0
yes
N_background
tau
N_signal
mu
sigma
Error
-0.13e3
0.13e3
-0.1
0.1
-70
70
-0.08
0.08
-0.06
0.07
Valid
True
True
True
True
True
True
True
True
True
True
At Limit
False
False
False
False
False
False
False
False
False
False
Max FCN
False
False
False
False
False
False
False
False
False
False
New Min
False
False
False
False
False
False
False
False
False
False
N_signal
mu
sigma
N_background
tau
N_signal
4.9e+03
-1.390 (-0.263)
1.744 (0.384)
0e3
0e3
mu
-1.390 (-0.263)
0.00572
-0.001 (-0.293)
0.000
0.000
sigma
1.744 (0.384)
-0.001 (-0.293)
0.00421
0.000
0.000
N_background
0e3
0.000
0.000
0
0
tau
0e3
0.000
0.000
0
0
12.8.4. final fit over the full range, with the full model#
my_minuit.fixed=False# release all parametersmy_minuit.migrad()my_minuit.minos()print(my_minuit.valid)display(my_minuit)