-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfit_functions.py
More file actions
221 lines (204 loc) · 9.78 KB
/
fit_functions.py
File metadata and controls
221 lines (204 loc) · 9.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
import ROOT as r
import numpy as np
background_npar = {'pol3pol2' : 6,
'pol3': 4,
'ratioPol2' : 6,
'pol2' : 3,
'exp' : 2}
def signal(x: np.ndarray, par: np.ndarray) -> float:
mass = x[0]
# integral = par[0]
return (par[0] / (par[2] * np.sqrt(2 * np.pi))) * np.exp(-0.5 * ((mass - par[1]) / par[2])**2)
def dscb(x: np.ndarray, par: np.ndarray) -> float:
# Double sided crystal ball for fitting Jpsi->mumu
N = par[0]
m0 = par[1]
sigma = par[2]
alphaL = par[3]
nL = par[4]
alphaR = par[5]
nR = par[6]
AL = (nL/np.abs(alphaL))**nL * np.exp(-(np.abs(alphaL)**2)/2)
AR = (nR/np.abs(alphaR))**nR * np.exp(-(np.abs(alphaR)**2)/2)
BL = nL/np.abs(alphaL) - np.abs(alphaL)
BR = nR/np.abs(alphaR) - np.abs(alphaR)
t = (x[0] - m0) / sigma
result = 0
if (-alphaL <= t and alphaR >= t):
result = np.exp(-(t**2)/2)
elif (t < -alphaL):
result = AL*(BL-t)**(-nL)
elif (t > alphaR):
result = AR*(BR+t)**(-nR)
return N*result
def reflected_background(x: np.ndarray, par: np.ndarray) -> float:
mass = x[0]
"""
par[0] = integral
par[1] = relative normalization of the two Gaussians
par[2] = Gaussian 1 mu
par[3] = Gaussian 1 sigma
par[4] = Gaussian 2 mu
par[5] = Gaussian 2 sigma
"""
return par[0] * ( (par[1] / (par[3] * np.sqrt(2 * np.pi))) * np.exp(-0.5 * ((mass - par[2]) / par[3])**2)
+ ((1 - par[1]) / (par[5] * np.sqrt(2 * np.pi))) * np.exp(-0.5 * ((mass - par[4]) / par[5])**2))
def pol3pol2(x: np.ndarray, par: np.ndarray) -> float:
# pol3 / pol2
mass = x[0]
return (par[0] * mass**3 + par[1] * mass**2 + par[2] * mass + par[3]) / (par[4] * mass**2 + par[5] * mass + 1)
# return par[0] * (1.0 + par[1] * mass + par[2] * mass**2 + par[3] * mass**3) / (1.0 + par[4] * mass + par[5] * mass**2)
# Parameterized in terms of positions of local minimum and maximum for the numerator
# return (par[0] * (mass**3/3 - (par[1]+par[2])*mass**2/2 + par[1]*par[2]*mass) + par[3]) / (1.0 + par[4] * mass + par[5] * mass**2)
def pol3(x: np.ndarray, par: np.ndarray) -> float:
# pol3
mass = x[0]
# Parameterized in terms of positions of local minimum and maximum for the numerator
# return par[0] * (mass**3/3 - (par[1]+par[2])*mass**2/2 + par[1]*par[2]*mass) + par[3]
return par[0] * mass**3 + par[1] * mass**2 + par[2] * mass + par[3]
def ratioPol2(x: np.ndarray, par: np.ndarray) -> float:
# pol2 / pol2
mass = x[0]
return (par[0] + par[1]*mass + par[2]*mass**2)/(par[3] + par[4]*mass + par[5]*mass**2)
def pol2(x: np.ndarray, par: np.ndarray) -> float:
mass = x[0]
return (par[0]*mass**2 + par[1]*mass + par[2])
def exp(x: np.ndarray, par: np.ndarray) -> float:
mass = x[0]
return par[0]*np.exp(par[1]*mass)
def simple_fit_model(x: np.ndarray, par: np.ndarray) -> float:
mass = x[0]
signalVal = (par[0] / (par[2] * np.sqrt(2 * np.pi))) * np.exp(-0.5 * ((mass - par[1]) / par[2])**2)
backgroundVal = par[3] + par[4] * mass
return signalVal + backgroundVal
def template_shape(x: np.ndarray, par: np.ndarray, hist=None) -> float:
# par[0] is the normalization, shape is fixed
if hist is not None:
return par[0] * hist.Interpolate(x)
else:
return 0.0
def make_fit_model(backgroundFunc, backgroundNPar, xmin, xmax):
# Composite callable that TF1 will call
def fit_model(x: np.ndarray, par: np.ndarray) -> float:
# First 3 parameters are S, mu, sigma for the signal Gaussian
signalVal = signal(x, [par[0], par[1], par[2]])
# Next 6 parameters are for the reflected background
# par[3] is the reflected/signal ratio, so it must be multiplied by S=par[0] before being passed
reflVal = reflected_background(x, [par[0]*par[3], par[4], par[5], par[6], par[7], par[8]])
# Next backgroundNPar parameters are for the combinatorial background
backgroundPars = []
for i in range(backgroundNPar):
backgroundPars.append(par[3 + 6 + i])
backgroundVal = backgroundFunc(x, backgroundPars)
return signalVal + reflVal + backgroundVal
totalFunc = r.TF1("fit_model", fit_model, xmin, xmax, 3 + 6 + backgroundNPar)
totalFunc.SetParName(0, "S")
totalFunc.SetParName(1, "Mean")
totalFunc.SetParName(2, "Sigma")
totalFunc.SetParName(3, "reflToSignalRatio")
totalFunc.SetParName(4, "reflRelNorm")
totalFunc.SetParName(5, "reflMu1")
totalFunc.SetParName(6, "reflSigma1")
totalFunc.SetParName(7, "reflMu2")
totalFunc.SetParName(8, "reflSigma2")
return totalFunc
def make_fit_model_with_corr_bkg(backgroundFunc, backgroundNPar, xmin, xmax, histCorrBkg=None):
# Composite callable that TF1 will call
def fit_model(x: np.ndarray, par: np.ndarray) -> float:
# First 3 parameters are S, mu, sigma for the signal Gaussian
signalVal = signal(x, [par[0], par[1], par[2]])
# Next 6 parameters are for the reflected background
# par[3] is the reflected/signal ratio, so it must be multiplied by S=par[0] before being passed
reflVal = reflected_background(x, [par[0]*par[3], par[4], par[5], par[6], par[7], par[8]])
# Next backgroundNPar parameters are for the combinatorial background
backgroundPars = []
for i in range(backgroundNPar):
backgroundPars.append(par[3 + 6 + i])
backgroundVal = backgroundFunc(x, backgroundPars)
# Lastly, add the template value for the correlated background from D0 -> K- pi+ pi0 if requested
corrBkgVal = 0
if histCorrBkg is not None:
# corrBkgVal = template_shape(x, [par[-1]])
corrBkgVal = par[3 + 6 + backgroundNPar] * histCorrBkg.Interpolate(x[0])
return signalVal + reflVal + backgroundVal + corrBkgVal
totalFunc = r.TF1("fit_model", fit_model, xmin, xmax, 3 + 6 + backgroundNPar + 1)
totalFunc.SetParName(0, "S")
totalFunc.SetParName(1, "Mean")
totalFunc.SetParName(2, "Sigma")
totalFunc.SetParName(3, "reflToSignalRatio")
totalFunc.SetParName(4, "reflRelNorm")
totalFunc.SetParName(5, "reflMu1")
totalFunc.SetParName(6, "reflSigma1")
totalFunc.SetParName(7, "reflMu2")
totalFunc.SetParName(8, "reflSigma2")
if histCorrBkg is not None:
# totalFunc._templateHist = histCorrBkg
totalFunc.SetParName(3 + 6 + backgroundNPar, "nCorr")
return totalFunc
def make_correlated_background_model(xmin, xmax, histCorrBkg):
def corr_bkg_model(x: np.ndarray, par: np.ndarray) -> float:
return par[0] * histCorrBkg.Interpolate(x[0])
func = r.TF1("correlated_bkg_model", corr_bkg_model, xmin, xmax, 1)
# func._templateHist = histCorrBkg
return func
def make_jpsi_fit_model(backgroundFunc, backgroundNPar, xmin, xmax):
# Composite callable that TF1 will call
def fit_model(x: np.ndarray, par: np.ndarray) -> float:
# First 3 parameters are S, mu, sigma for the signal Gaussian
signalVal = dscb(x, [par[0], par[1], par[2], par[3], par[4], par[5], par[6]])
# Last backgroundNPar parameters are for the combinatorial background
backgroundPars = []
for i in range(backgroundNPar):
backgroundPars.append(par[7 + i])
backgroundVal = backgroundFunc(x, backgroundPars)
return signalVal + backgroundVal
totalFunc = r.TF1("fit_model", fit_model, xmin, xmax, 7 + backgroundNPar)
totalFunc.SetParName(0, "N")
totalFunc.SetParName(1, "m0")
totalFunc.SetParName(2, "sigma")
totalFunc.SetParName(3, "alphaL")
totalFunc.SetParName(4, "nL")
totalFunc.SetParName(5, "alphaR")
totalFunc.SetParName(6, "nR")
return totalFunc
def make_background_model(backgroundFunc, backgroundNPar, xmin, xmax):
# Composite callable that TF1 will call
def background_model(x: np.ndarray, par: np.ndarray) -> float:
# First 6 parameters are for the reflected background
reflVal = reflected_background(x, [par[0], par[1], par[2], par[3], par[4], par[5]])
# Last backgroundNPar parameters are for the combinatorial background
backgroundPars = []
for i in range(backgroundNPar):
backgroundPars.append(par[6 + i])
backgroundVal = backgroundFunc(x, backgroundPars)
return reflVal + backgroundVal
totalFunc = r.TF1("background_model", background_model, xmin, xmax, 6 + backgroundNPar)
totalFunc.SetParName(0, "reflN")
totalFunc.SetParName(1, "reflRelNorm")
totalFunc.SetParName(2, "reflMu1")
totalFunc.SetParName(3, "reflSigma1")
totalFunc.SetParName(4, "reflMu2")
totalFunc.SetParName(5, "reflSigma2")
return totalFunc
def make_background_model_with_corr_bkg(backgroundFunc, backgroundNPar, xmin, xmax, histCorrBkg):
# Composite callable that TF1 will call
def background_model(x: np.ndarray, par: np.ndarray) -> float:
# First 6 parameters are for the reflected background
reflVal = reflected_background(x, [par[0], par[1], par[2], par[3], par[4], par[5]])
# Last backgroundNPar parameters are for the combinatorial background
backgroundPars = []
for i in range(backgroundNPar):
backgroundPars.append(par[6 + i])
backgroundVal = backgroundFunc(x, backgroundPars)
corrBkgVal = par[3 + 6 + backgroundNPar] * histCorrBkg.Interpolate(x[0])
return reflVal + backgroundVal + corrBkgVal
totalFunc = r.TF1("background_model", background_model, xmin, xmax, 6 + backgroundNPar + 1)
totalFunc.SetParName(0, "reflN")
totalFunc.SetParName(1, "reflRelNorm")
totalFunc.SetParName(2, "reflMu1")
totalFunc.SetParName(3, "reflSigma1")
totalFunc.SetParName(4, "reflMu2")
totalFunc.SetParName(5, "reflSigma2")
# totalFunc._templateHist = histCorrBkg
totalFunc.SetParName(3 + 6 + backgroundNPar, "nCorr")
return totalFunc