data-manipulation-utilities 0.2.5__py3-none-any.whl → 0.2.7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {data_manipulation_utilities-0.2.5.dist-info → data_manipulation_utilities-0.2.7.dist-info}/METADATA +179 -10
- {data_manipulation_utilities-0.2.5.dist-info → data_manipulation_utilities-0.2.7.dist-info}/RECORD +31 -19
- {data_manipulation_utilities-0.2.5.dist-info → data_manipulation_utilities-0.2.7.dist-info}/WHEEL +1 -1
- dmu/generic/hashing.py +44 -0
- dmu/generic/utilities.py +14 -1
- dmu/generic/version_management.py +3 -5
- dmu/ml/cv_diagnostics.py +221 -0
- dmu/ml/train_mva.py +143 -46
- dmu/pdataframe/utilities.py +36 -3
- dmu/plotting/fwhm.py +64 -0
- dmu/plotting/plotter.py +2 -0
- dmu/plotting/plotter_1d.py +87 -6
- dmu/stats/fitter.py +1 -1
- dmu/stats/minimizers.py +40 -11
- dmu/stats/model_factory.py +248 -44
- dmu/stats/zfit_models.py +68 -0
- dmu/stats/zfit_plotter.py +29 -21
- dmu/testing/utilities.py +31 -4
- dmu_data/ml/tests/diagnostics_from_file.yaml +13 -0
- dmu_data/ml/tests/diagnostics_from_model.yaml +10 -0
- dmu_data/ml/tests/diagnostics_multiple_methods.yaml +10 -0
- dmu_data/ml/tests/diagnostics_overlay.yaml +33 -0
- dmu_data/ml/tests/train_mva.yaml +19 -10
- dmu_data/ml/tests/train_mva_with_diagnostics.yaml +82 -0
- dmu_data/plotting/tests/plug_fwhm.yaml +24 -0
- dmu_data/plotting/tests/plug_stats.yaml +19 -0
- dmu_data/plotting/tests/simple.yaml +4 -3
- dmu_data/plotting/tests/styling.yaml +11 -0
- {data_manipulation_utilities-0.2.5.data → data_manipulation_utilities-0.2.7.data}/scripts/publish +0 -0
- {data_manipulation_utilities-0.2.5.dist-info → data_manipulation_utilities-0.2.7.dist-info}/entry_points.txt +0 -0
- {data_manipulation_utilities-0.2.5.dist-info → data_manipulation_utilities-0.2.7.dist-info}/top_level.txt +0 -0
dmu/stats/minimizers.py
CHANGED
@@ -1,12 +1,16 @@
|
|
1
1
|
'''
|
2
2
|
Module containing derived classes from ZFit minimizer
|
3
3
|
'''
|
4
|
+
from typing import Union
|
4
5
|
import numpy
|
5
6
|
|
6
7
|
import zfit
|
8
|
+
import matplotlib.pyplot as plt
|
9
|
+
|
7
10
|
from zfit.result import FitResult
|
8
11
|
from zfit.core.basepdf import BasePDF as zpdf
|
9
12
|
from zfit.minimizers.baseminimizer import FailMinimizeNaN
|
13
|
+
from dmu.stats.utilities import print_pdf
|
10
14
|
from dmu.stats.gof_calculator import GofCalculator
|
11
15
|
from dmu.logging.log_store import LogStore
|
12
16
|
|
@@ -29,6 +33,7 @@ class AnealingMinimizer(zfit.minimize.Minuit):
|
|
29
33
|
self._chi2ndof = chi2ndof
|
30
34
|
|
31
35
|
self._check_thresholds()
|
36
|
+
self._l_bad_fit_res : list[FitResult] = []
|
32
37
|
|
33
38
|
super().__init__()
|
34
39
|
# ------------------------
|
@@ -66,19 +71,24 @@ class AnealingMinimizer(zfit.minimize.Minuit):
|
|
66
71
|
return is_good
|
67
72
|
# ------------------------
|
68
73
|
def _is_good_fit(self, res : FitResult) -> bool:
|
74
|
+
good_fit = True
|
75
|
+
|
69
76
|
if not res.valid:
|
70
|
-
log.
|
71
|
-
|
77
|
+
log.debug('Skipping invalid fit')
|
78
|
+
good_fit = False
|
72
79
|
|
73
80
|
if res.status != 0:
|
74
|
-
log.
|
75
|
-
|
81
|
+
log.debug('Skipping fit with bad status')
|
82
|
+
good_fit = False
|
76
83
|
|
77
84
|
if not res.converged:
|
78
|
-
log.
|
79
|
-
|
85
|
+
log.debug('Skipping non-converging fit')
|
86
|
+
good_fit = False
|
80
87
|
|
81
|
-
|
88
|
+
if not good_fit:
|
89
|
+
self._l_bad_fit_res.append(res)
|
90
|
+
|
91
|
+
return good_fit
|
82
92
|
# ------------------------
|
83
93
|
def _get_gof(self, nll) -> tuple[float, float]:
|
84
94
|
log.debug('Checking GOF')
|
@@ -108,10 +118,11 @@ class AnealingMinimizer(zfit.minimize.Minuit):
|
|
108
118
|
par.set_value(fval)
|
109
119
|
log.debug(f'{par.name:<20}{ival:<15.3f}{"->":<10}{fval:<15.3f}{"in":<5}{par.lower:<15.3e}{par.upper:<15.3e}')
|
110
120
|
# ------------------------
|
111
|
-
def _pick_best_fit(self, d_chi2_res : dict) -> FitResult:
|
121
|
+
def _pick_best_fit(self, d_chi2_res : dict) -> Union[FitResult,None]:
|
112
122
|
nres = len(d_chi2_res)
|
113
123
|
if nres == 0:
|
114
|
-
|
124
|
+
log.error('No fits found')
|
125
|
+
return None
|
115
126
|
|
116
127
|
l_chi2_res= list(d_chi2_res.items())
|
117
128
|
l_chi2_res.sort()
|
@@ -149,6 +160,15 @@ class AnealingMinimizer(zfit.minimize.Minuit):
|
|
149
160
|
|
150
161
|
return l_model[0]
|
151
162
|
# ------------------------
|
163
|
+
def _print_failed_fit_diagnostics(self, nll) -> None:
|
164
|
+
for res in self._l_bad_fit_res:
|
165
|
+
print(res)
|
166
|
+
|
167
|
+
arr_mass = nll.data[0].numpy()
|
168
|
+
|
169
|
+
plt.hist(arr_mass, bins=60)
|
170
|
+
plt.show()
|
171
|
+
# ------------------------
|
152
172
|
def minimize(self, nll, **kwargs) -> FitResult:
|
153
173
|
'''
|
154
174
|
Will run minimization and return FitResult object
|
@@ -156,18 +176,20 @@ class AnealingMinimizer(zfit.minimize.Minuit):
|
|
156
176
|
|
157
177
|
d_chi2_res : dict[float,FitResult] = {}
|
158
178
|
for i_try in range(self._ntries):
|
159
|
-
log.info(f'try {i_try:02}/{self._ntries:02}')
|
160
179
|
try:
|
161
180
|
res = super().minimize(nll, **kwargs)
|
162
181
|
except (FailMinimizeNaN, ValueError, RuntimeError) as exc:
|
163
|
-
log.
|
182
|
+
log.error(f'{i_try:02}/{self._ntries:02}{"Failed":>20}')
|
183
|
+
log.debug(exc)
|
164
184
|
self._randomize_parameters(nll)
|
165
185
|
continue
|
166
186
|
|
167
187
|
if not self._is_good_fit(res):
|
188
|
+
log.warning(f'{i_try:02}/{self._ntries:02}{"Bad fit":>20}')
|
168
189
|
continue
|
169
190
|
|
170
191
|
chi2, pvl = self._get_gof(nll)
|
192
|
+
log.info(f'{i_try:02}/{self._ntries:02}{chi2:>20.3f}')
|
171
193
|
d_chi2_res[chi2] = res
|
172
194
|
|
173
195
|
if self._is_good_gof(chi2, pvl):
|
@@ -176,6 +198,13 @@ class AnealingMinimizer(zfit.minimize.Minuit):
|
|
176
198
|
self._randomize_parameters(nll)
|
177
199
|
|
178
200
|
res = self._pick_best_fit(d_chi2_res)
|
201
|
+
if res is None:
|
202
|
+
self._print_failed_fit_diagnostics(nll)
|
203
|
+
pdf = nll.model[0]
|
204
|
+
print_pdf(pdf)
|
205
|
+
|
206
|
+
raise ValueError('Fit failed')
|
207
|
+
|
179
208
|
pdf = self._pdf_from_nll(nll)
|
180
209
|
self._set_pdf_pars(res, pdf)
|
181
210
|
|
dmu/stats/model_factory.py
CHANGED
@@ -6,9 +6,12 @@ Module storing ZModel class
|
|
6
6
|
from typing import Callable, Union
|
7
7
|
|
8
8
|
import zfit
|
9
|
+
|
9
10
|
from zfit.core.interfaces import ZfitSpace as zobs
|
10
11
|
from zfit.core.basepdf import BasePDF as zpdf
|
11
12
|
from zfit.core.parameter import Parameter as zpar
|
13
|
+
from dmu.stats.zfit_models import HypExp
|
14
|
+
from dmu.stats.zfit_models import ModExp
|
12
15
|
from dmu.logging.log_store import LogStore
|
13
16
|
|
14
17
|
log=LogStore.add_logger('dmu:stats:model_factory')
|
@@ -37,7 +40,23 @@ class MethodRegistry:
|
|
37
40
|
'''
|
38
41
|
Will return method in charge of building PDF, for an input nickname
|
39
42
|
'''
|
40
|
-
|
43
|
+
method = cls._d_method.get(nickname, None)
|
44
|
+
|
45
|
+
if method is not None:
|
46
|
+
return method
|
47
|
+
|
48
|
+
log.warning('Available PDFs:')
|
49
|
+
for value in cls._d_method:
|
50
|
+
log.info(f' {value}')
|
51
|
+
|
52
|
+
return method
|
53
|
+
|
54
|
+
@classmethod
|
55
|
+
def get_pdf_names(cls) -> list[str]:
|
56
|
+
'''
|
57
|
+
Returns list of PDFs that are registered/supported
|
58
|
+
'''
|
59
|
+
return list(cls._d_method)
|
41
60
|
#-----------------------------------------
|
42
61
|
class ModelFactory:
|
43
62
|
'''
|
@@ -48,67 +67,172 @@ class ModelFactory:
|
|
48
67
|
|
49
68
|
l_pdf = ['dscb', 'gauss']
|
50
69
|
l_shr = ['mu']
|
51
|
-
|
70
|
+
l_flt = ['mu', 'sg']
|
71
|
+
d_rep = {'mu' : 'scale', 'sg' : 'reso'}
|
72
|
+
mod = ModelFactory(preffix = 'signal', obs = obs, l_pdf = l_pdf, l_shared = l_shr, d_rep = d_rep)
|
52
73
|
pdf = mod.get_pdf()
|
53
74
|
```
|
54
75
|
|
55
|
-
where one can specify which parameters
|
76
|
+
where one can specify which parameters
|
77
|
+
|
78
|
+
- Can be shared among the PDFs
|
79
|
+
- Are meant to float if this fit is done to MC, in order to fix parameters in data.
|
80
|
+
- Are scales or resolutions that need reparametrizations
|
56
81
|
'''
|
57
82
|
#-----------------------------------------
|
58
|
-
def __init__(self,
|
83
|
+
def __init__(self,
|
84
|
+
preffix : str,
|
85
|
+
obs : zobs,
|
86
|
+
l_pdf : list[str],
|
87
|
+
l_shared : list[str],
|
88
|
+
l_float : list[str],
|
89
|
+
d_fix : dict[str:float] = None,
|
90
|
+
d_rep : dict[str:str] = None):
|
59
91
|
'''
|
92
|
+
preffix: used to identify PDF, will be used to name every parameter
|
60
93
|
obs: zfit obserbable
|
61
94
|
l_pdf: List of PDF nicknames which are registered below
|
62
95
|
l_shared: List of parameter names that are shared
|
96
|
+
l_float: List of parameter names to allow to float
|
97
|
+
d_fix: Dictionary with keys as the beginning of the name of a parameter and value as the number
|
98
|
+
to which it has to be fixed. If not one and only one parameter is found, ValueError is raised
|
99
|
+
d_rep: Dictionary with keys as variables that will be reparametrized
|
63
100
|
'''
|
64
101
|
|
102
|
+
self._preffix = preffix
|
65
103
|
self._l_pdf = l_pdf
|
66
104
|
self._l_shr = l_shared
|
67
|
-
self.
|
105
|
+
self._l_flt = l_float
|
106
|
+
self._d_fix = d_fix
|
107
|
+
self._d_rep = d_rep
|
68
108
|
self._obs = obs
|
69
109
|
|
70
110
|
self._d_par : dict[str,zpar] = {}
|
111
|
+
|
112
|
+
self._check_reparametrization()
|
113
|
+
#-----------------------------------------
|
114
|
+
def _check_reparametrization(self) -> None:
|
115
|
+
if self._d_rep is None:
|
116
|
+
return
|
117
|
+
|
118
|
+
s_par_1 = set(self._d_rep)
|
119
|
+
s_par_2 = set(self._l_flt)
|
120
|
+
|
121
|
+
if not s_par_1.isdisjoint(s_par_2):
|
122
|
+
raise ValueError('Non empty intersection between floating and reparametrization parameters')
|
123
|
+
|
124
|
+
s_kind = set(self._d_rep.values())
|
125
|
+
if not s_kind.issubset({'scale', 'reso'}):
|
126
|
+
raise ValueError(f'Only scales and resolution reparametrizations allowed, found: {s_kind}')
|
127
|
+
#-----------------------------------------
|
128
|
+
def _split_name(self, name : str) -> tuple[str,str]:
|
129
|
+
l_part = name.split('_')
|
130
|
+
pname = l_part[0]
|
131
|
+
xname = '_'.join(l_part[1:])
|
132
|
+
|
133
|
+
return pname, xname
|
71
134
|
#-----------------------------------------
|
72
|
-
def
|
73
|
-
|
135
|
+
def _get_parameter_name(self, name : str, suffix : str) -> str:
|
136
|
+
pname, xname = self._split_name(name)
|
137
|
+
|
138
|
+
log.debug(f'Using physical name: {pname}')
|
139
|
+
|
140
|
+
if pname in self._l_shr:
|
141
|
+
name = f'{pname}_{self._preffix}'
|
142
|
+
else:
|
143
|
+
name = f'{pname}_{xname}_{self._preffix}{suffix}'
|
144
|
+
|
145
|
+
if pname in self._l_flt:
|
74
146
|
return f'{name}_flt'
|
75
147
|
|
76
148
|
return name
|
77
149
|
#-----------------------------------------
|
78
|
-
def
|
79
|
-
|
80
|
-
|
81
|
-
|
150
|
+
def _get_parameter(
|
151
|
+
self,
|
152
|
+
name : str,
|
153
|
+
suffix : str,
|
154
|
+
val : float,
|
155
|
+
low : float,
|
156
|
+
high : float) -> zpar:
|
157
|
+
|
158
|
+
par_name = self._get_parameter_name(name, suffix)
|
159
|
+
log.debug(f'Assigning name: {par_name}')
|
160
|
+
|
161
|
+
if par_name in self._d_par:
|
162
|
+
return self._d_par[par_name]
|
163
|
+
|
164
|
+
is_reparametrized = self._is_reparametrized(name)
|
165
|
+
|
166
|
+
if is_reparametrized:
|
167
|
+
init_name, _ = self._split_name(par_name)
|
168
|
+
par = self._get_reparametrization(par_name, init_name, val, low, high)
|
169
|
+
else:
|
170
|
+
par = zfit.param.Parameter(par_name, val, low, high)
|
82
171
|
|
83
|
-
|
172
|
+
self._d_par[par_name] = par
|
173
|
+
|
174
|
+
return par
|
84
175
|
#-----------------------------------------
|
85
|
-
def
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
if name in self._d_par:
|
93
|
-
return self._d_par[name]
|
176
|
+
def _is_reparametrized(self, name : str) -> bool:
|
177
|
+
if self._d_rep is None:
|
178
|
+
return False
|
179
|
+
|
180
|
+
root_name, _ = self._split_name(name)
|
181
|
+
|
182
|
+
is_rep = root_name in self._d_rep
|
94
183
|
|
95
|
-
|
184
|
+
log.debug(f'Reparametrizing {name}: {is_rep}')
|
96
185
|
|
97
|
-
|
186
|
+
return is_rep
|
187
|
+
#-----------------------------------------
|
188
|
+
def _get_reparametrization(self, par_name : str, init_name : str, value : float, low : float, high : float) -> zpar:
|
189
|
+
log.debug(f'Reparametrizing {par_name}')
|
190
|
+
par_const = zfit.Parameter(par_name, value, low, high)
|
191
|
+
par_const.floating = False
|
192
|
+
|
193
|
+
kind = self._d_rep[init_name]
|
194
|
+
if kind == 'reso':
|
195
|
+
par_reso = zfit.Parameter(f'{par_name}_reso_flt' , 1.0, 0.20, 5.0)
|
196
|
+
par = zfit.ComposedParameter(f'{par_name}_cmp', lambda d_par : d_par['par_const'] * d_par['reso' ], params={'par_const' : par_const, 'reso' : par_reso } )
|
197
|
+
elif kind == 'scale':
|
198
|
+
par_scale = zfit.Parameter(f'{par_name}_scale_flt', 0.0, -100, 100)
|
199
|
+
par = zfit.ComposedParameter(f'{par_name}_cmp', lambda d_par : d_par['par_const'] + d_par['scale'], params={'par_const' : par_const, 'scale' : par_scale} )
|
200
|
+
else:
|
201
|
+
raise ValueError(f'Invalid kind: {kind}')
|
98
202
|
|
99
203
|
return par
|
100
204
|
#-----------------------------------------
|
101
205
|
@MethodRegistry.register('exp')
|
102
206
|
def _get_exponential(self, suffix : str = '') -> zpdf:
|
103
|
-
c = self._get_parameter('c_exp', suffix, -0.
|
104
|
-
pdf = zfit.pdf.Exponential(c, self._obs)
|
207
|
+
c = self._get_parameter('c_exp', suffix, -0.010, -0.020, -0.0001)
|
208
|
+
pdf = zfit.pdf.Exponential(c, self._obs, name=f'exp{suffix}')
|
209
|
+
|
210
|
+
return pdf
|
211
|
+
# ---------------------------------------------
|
212
|
+
@MethodRegistry.register('hypexp')
|
213
|
+
def _get_hypexp(self, suffix : str = '') -> zpdf:
|
214
|
+
mu = zfit.Parameter('mu_hypexp', 5000, 4000, 6000)
|
215
|
+
ap = zfit.Parameter('ap_hypexp', 0.020, 0, 0.10)
|
216
|
+
bt = zfit.Parameter('bt_hypexp', 0.002, 0.0001, 0.003)
|
217
|
+
|
218
|
+
pdf= HypExp(obs=self._obs, mu=mu, alpha=ap, beta=bt, name=f'hypexp{suffix}')
|
219
|
+
|
220
|
+
return pdf
|
221
|
+
# ---------------------------------------------
|
222
|
+
@MethodRegistry.register('modexp')
|
223
|
+
def _get_modexp(self, suffix : str = '') -> zpdf:
|
224
|
+
mu = zfit.Parameter('mu_modexp', 4250, 4250, 4500)
|
225
|
+
ap = zfit.Parameter('ap_modexp', 0.002, 0.002, 0.026)
|
226
|
+
bt = zfit.Parameter('bt_modexp', 0.002, 0.002, 0.020)
|
227
|
+
|
228
|
+
pdf= ModExp(obs=self._obs, mu=mu, alpha=ap, beta=bt, name=f'modexp{suffix}')
|
105
229
|
|
106
230
|
return pdf
|
107
231
|
#-----------------------------------------
|
108
232
|
@MethodRegistry.register('pol1')
|
109
233
|
def _get_pol1(self, suffix : str = '') -> zpdf:
|
110
234
|
a = self._get_parameter('a_pol1', suffix, -0.005, -0.95, 0.00)
|
111
|
-
pdf = zfit.pdf.Chebyshev(obs=self._obs, coeffs=[a])
|
235
|
+
pdf = zfit.pdf.Chebyshev(obs=self._obs, coeffs=[a], name=f'pol1{suffix}')
|
112
236
|
|
113
237
|
return pdf
|
114
238
|
#-----------------------------------------
|
@@ -116,51 +240,100 @@ class ModelFactory:
|
|
116
240
|
def _get_pol2(self, suffix : str = '') -> zpdf:
|
117
241
|
a = self._get_parameter('a_pol2', suffix, -0.005, -0.95, 0.00)
|
118
242
|
b = self._get_parameter('b_pol2', suffix, 0.000, -0.95, 0.95)
|
119
|
-
pdf = zfit.pdf.Chebyshev(obs=self._obs, coeffs=[a, b])
|
243
|
+
pdf = zfit.pdf.Chebyshev(obs=self._obs, coeffs=[a, b ], name=f'pol2{suffix}')
|
244
|
+
|
245
|
+
return pdf
|
246
|
+
# ---------------------------------------------
|
247
|
+
@MethodRegistry.register('pol3')
|
248
|
+
def _get_pol3(self, suffix : str = '') -> zpdf:
|
249
|
+
a = zfit.Parameter('a_pol3', -0.005, -0.95, 0.00)
|
250
|
+
b = zfit.Parameter('b_pol3', 0.000, -0.95, 0.95)
|
251
|
+
c = zfit.Parameter('c_pol3', 0.000, -0.95, 0.95)
|
252
|
+
pdf = zfit.pdf.Chebyshev(obs=self._obs, coeffs=[a, b, c], name=f'pol3{suffix}')
|
120
253
|
|
121
254
|
return pdf
|
122
255
|
#-----------------------------------------
|
123
256
|
@MethodRegistry.register('cbr')
|
124
257
|
def _get_cbr(self, suffix : str = '') -> zpdf:
|
125
|
-
mu = self._get_parameter('mu_cbr', suffix, 5300,
|
258
|
+
mu = self._get_parameter('mu_cbr', suffix, 5300, 5100, 5500)
|
126
259
|
sg = self._get_parameter('sg_cbr', suffix, 10, 2, 300)
|
127
|
-
ar = self._get_parameter('ac_cbr', suffix, -2,
|
128
|
-
nr = self._get_parameter('nc_cbr', suffix, 1, 0.5,
|
260
|
+
ar = self._get_parameter('ac_cbr', suffix, -2, -14., -0.1)
|
261
|
+
nr = self._get_parameter('nc_cbr', suffix, 1, 0.5, 150)
|
262
|
+
|
263
|
+
pdf = zfit.pdf.CrystalBall(mu, sg, ar, nr, self._obs, name=f'cbr{suffix}')
|
264
|
+
|
265
|
+
return pdf
|
266
|
+
#-----------------------------------------
|
267
|
+
@MethodRegistry.register('suj')
|
268
|
+
def _get_suj(self, suffix : str = '') -> zpdf:
|
269
|
+
mu = self._get_parameter('mu_suj', suffix, 5300, 5000, 6000)
|
270
|
+
sg = self._get_parameter('sg_suj', suffix, 10, 2, 5000)
|
271
|
+
gm = self._get_parameter('gm_suj', suffix, 1, -10, 10)
|
272
|
+
dl = self._get_parameter('dl_suj', suffix, 1, 0.1, 40)
|
129
273
|
|
130
|
-
pdf = zfit.pdf.
|
274
|
+
pdf = zfit.pdf.JohnsonSU(mu, sg, gm, dl, self._obs, name=f'suj{suffix}')
|
131
275
|
|
132
276
|
return pdf
|
133
277
|
#-----------------------------------------
|
134
278
|
@MethodRegistry.register('cbl')
|
135
279
|
def _get_cbl(self, suffix : str = '') -> zpdf:
|
136
|
-
mu = self._get_parameter('mu_cbl', suffix, 5300,
|
280
|
+
mu = self._get_parameter('mu_cbl', suffix, 5300, 5100, 5500)
|
137
281
|
sg = self._get_parameter('sg_cbl', suffix, 10, 2, 300)
|
138
|
-
al = self._get_parameter('ac_cbl', suffix, 2,
|
139
|
-
nl = self._get_parameter('nc_cbl', suffix, 1, 0.5,
|
282
|
+
al = self._get_parameter('ac_cbl', suffix, 2, 0.0, 14.)
|
283
|
+
nl = self._get_parameter('nc_cbl', suffix, 1, 0.5, 150)
|
140
284
|
|
141
|
-
pdf = zfit.pdf.CrystalBall(mu, sg, al, nl, self._obs)
|
285
|
+
pdf = zfit.pdf.CrystalBall(mu, sg, al, nl, self._obs, name=f'cbl{suffix}')
|
142
286
|
|
143
287
|
return pdf
|
144
288
|
#-----------------------------------------
|
145
289
|
@MethodRegistry.register('gauss')
|
146
290
|
def _get_gauss(self, suffix : str = '') -> zpdf:
|
147
|
-
mu = self._get_parameter('mu_gauss', suffix, 5300,
|
291
|
+
mu = self._get_parameter('mu_gauss', suffix, 5300, 5100, 5500)
|
148
292
|
sg = self._get_parameter('sg_gauss', suffix, 10, 2, 300)
|
149
293
|
|
150
|
-
pdf = zfit.pdf.Gauss(mu, sg, self._obs)
|
294
|
+
pdf = zfit.pdf.Gauss(mu, sg, self._obs, name=f'gauss{suffix}')
|
151
295
|
|
152
296
|
return pdf
|
153
297
|
#-----------------------------------------
|
154
298
|
@MethodRegistry.register('dscb')
|
155
299
|
def _get_dscb(self, suffix : str = '') -> zpdf:
|
156
|
-
mu = self._get_parameter('mu_dscb', suffix, 5300,
|
157
|
-
sg = self._get_parameter('sg_dscb', suffix, 10, 2,
|
300
|
+
mu = self._get_parameter('mu_dscb', suffix, 5300, 5000, 5400)
|
301
|
+
sg = self._get_parameter('sg_dscb', suffix, 10, 2, 500)
|
158
302
|
ar = self._get_parameter('ar_dscb', suffix, 1, 0, 5)
|
159
303
|
al = self._get_parameter('al_dscb', suffix, 1, 0, 5)
|
160
|
-
nr = self._get_parameter('nr_dscb', suffix, 2, 1,
|
161
|
-
nl = self._get_parameter('nl_dscb', suffix, 2, 0,
|
304
|
+
nr = self._get_parameter('nr_dscb', suffix, 2, 1, 150)
|
305
|
+
nl = self._get_parameter('nl_dscb', suffix, 2, 0, 150)
|
306
|
+
|
307
|
+
pdf = zfit.pdf.DoubleCB(mu, sg, al, nl, ar, nr, self._obs, name=f'dscb{suffix}')
|
308
|
+
|
309
|
+
return pdf
|
310
|
+
#-----------------------------------------
|
311
|
+
@MethodRegistry.register('voigt')
|
312
|
+
def _get_voigt(self, suffix : str = '') -> zpdf:
|
313
|
+
mu = zfit.Parameter('mu_voigt', 5280, 5040, 5500)
|
314
|
+
sg = zfit.Parameter('sg_voigt', 20, 10, 400)
|
315
|
+
gm = zfit.Parameter('gm_voigt', 4, 0.1, 100)
|
162
316
|
|
163
|
-
pdf = zfit.pdf.
|
317
|
+
pdf = zfit.pdf.Voigt(m=mu, sigma=sg, gamma=gm, obs=self._obs, name=f'voigt{suffix}')
|
318
|
+
|
319
|
+
return pdf
|
320
|
+
#-----------------------------------------
|
321
|
+
@MethodRegistry.register('qgauss')
|
322
|
+
def _get_qgauss(self, suffix : str = '') -> zpdf:
|
323
|
+
mu = zfit.Parameter('mu_qgauss', 5280, 5040, 5500)
|
324
|
+
sg = zfit.Parameter('sg_qgauss', 20, 10, 400)
|
325
|
+
q = zfit.Parameter( 'q_qgauss', 1, 1, 3)
|
326
|
+
|
327
|
+
pdf = zfit.pdf.QGauss(q=q, mu=mu, sigma=sg, obs=self._obs, name =f'qgauss{suffix}')
|
328
|
+
|
329
|
+
return pdf
|
330
|
+
#-----------------------------------------
|
331
|
+
@MethodRegistry.register('cauchy')
|
332
|
+
def _get_cauchy(self, suffix : str = '') -> zpdf:
|
333
|
+
mu = zfit.Parameter('mu', 5280, 5040, 5500)
|
334
|
+
gm = zfit.Parameter('gm', 150, 50, 500)
|
335
|
+
|
336
|
+
pdf = zfit.pdf.Cauchy(obs=self._obs, m=mu, gamma=gm, name=f'cauchy{suffix}')
|
164
337
|
|
165
338
|
return pdf
|
166
339
|
#-----------------------------------------
|
@@ -194,9 +367,39 @@ class ModelFactory:
|
|
194
367
|
log.debug('Requested only one PDF, skipping sum')
|
195
368
|
return l_pdf[0]
|
196
369
|
|
197
|
-
l_frc= [ zfit.param.Parameter(f'frc_{ifrc + 1}', 0.5, 0, 1) for ifrc in range(nfrc - 1) ]
|
370
|
+
l_frc= [ zfit.param.Parameter(f'frc_{self._preffix}_{ifrc + 1}', 0.5, 0, 1) for ifrc in range(nfrc - 1) ]
|
371
|
+
|
372
|
+
pdf = zfit.pdf.SumPDF(l_pdf, name=self._preffix, fracs=l_frc)
|
373
|
+
|
374
|
+
return pdf
|
375
|
+
#-----------------------------------------
|
376
|
+
def _find_par(self, s_par : set[zpar], name_start : str) -> zpar:
|
377
|
+
l_par_match = [ par for par in s_par if par.name.startswith(name_start) ]
|
378
|
+
|
379
|
+
if len(l_par_match) != 1:
|
380
|
+
for par in s_par:
|
381
|
+
log.info(par.name)
|
382
|
+
|
383
|
+
raise ValueError(f'Not found one and only one parameter starting with: {name_start}')
|
384
|
+
|
385
|
+
return l_par_match[0]
|
386
|
+
#-----------------------------------------
|
387
|
+
def _fix_parameters(self, pdf : zpdf) -> zpdf:
|
388
|
+
if self._d_fix is None:
|
389
|
+
log.debug('Not fixing any parameter')
|
390
|
+
return pdf
|
391
|
+
|
392
|
+
s_par = pdf.get_params()
|
393
|
+
|
394
|
+
log.info('-' * 30)
|
395
|
+
log.info('Fixing parameters')
|
396
|
+
log.info('-' * 30)
|
397
|
+
for name_start, value in self._d_fix.items():
|
398
|
+
par = self._find_par(s_par, name_start)
|
399
|
+
par.set_value(value)
|
198
400
|
|
199
|
-
|
401
|
+
log.info(f'{name_start:<20}{value:<20.3f}')
|
402
|
+
par.floating = False
|
200
403
|
|
201
404
|
return pdf
|
202
405
|
#-----------------------------------------
|
@@ -208,6 +411,7 @@ class ModelFactory:
|
|
208
411
|
l_type= self._get_pdf_types()
|
209
412
|
l_pdf = [ self._get_pdf(kind, preffix) for kind, preffix in l_type ]
|
210
413
|
pdf = self._add_pdf(l_pdf)
|
414
|
+
pdf = self._fix_parameters(pdf)
|
211
415
|
|
212
416
|
return pdf
|
213
417
|
#-----------------------------------------
|
dmu/stats/zfit_models.py
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
'''
|
2
|
+
Module meant to hold classes defining PDFs that can be used by ZFIT
|
3
|
+
'''
|
4
|
+
|
5
|
+
import zfit
|
6
|
+
from zfit import z
|
7
|
+
|
8
|
+
#-------------------------------------------------------------------
|
9
|
+
class HypExp(zfit.pdf.ZPDF):
|
10
|
+
_N_OBS = 1
|
11
|
+
_PARAMS = ['mu', 'alpha', 'beta']
|
12
|
+
|
13
|
+
def _unnormalized_pdf(self, x):
|
14
|
+
x = z.unstack_x(x)
|
15
|
+
mu = self.params['mu']
|
16
|
+
ap = self.params['alpha']
|
17
|
+
bt = self.params['beta']
|
18
|
+
|
19
|
+
u = (x - mu)
|
20
|
+
val = z.exp(-bt * x) / (1 + z.exp(-ap * u))
|
21
|
+
|
22
|
+
return val
|
23
|
+
#-------------------------------------------------------------------
|
24
|
+
class ModExp(zfit.pdf.ZPDF):
|
25
|
+
_N_OBS = 1
|
26
|
+
_PARAMS = ['mu', 'alpha', 'beta']
|
27
|
+
|
28
|
+
def _unnormalized_pdf(self, x):
|
29
|
+
x = z.unstack_x(x)
|
30
|
+
mu = self.params['mu']
|
31
|
+
ap = self.params['alpha']
|
32
|
+
bt = self.params['beta']
|
33
|
+
|
34
|
+
u = x - mu
|
35
|
+
val = (1 - z.exp(-ap * u)) * z.exp(-bt * u)
|
36
|
+
|
37
|
+
return val
|
38
|
+
#-------------------------------------------------------------------
|
39
|
+
class GenExp(zfit.pdf.ZPDF):
|
40
|
+
_N_OBS = 1
|
41
|
+
_PARAMS = ['mu', 'sg', 'alpha', 'beta']
|
42
|
+
|
43
|
+
def _unnormalized_pdf(self, x):
|
44
|
+
x = z.unstack_x(x)
|
45
|
+
mu = self.params['mu']
|
46
|
+
sg = self.params['sg']
|
47
|
+
ap = self.params['alpha']
|
48
|
+
bt = self.params['beta']
|
49
|
+
|
50
|
+
u = (x - mu) / sg
|
51
|
+
val = (1 - z.exp(-ap * u)) * z.exp(-bt * u)
|
52
|
+
|
53
|
+
return val
|
54
|
+
#-------------------------------------------------------------------
|
55
|
+
class FermiDirac(zfit.pdf.ZPDF):
|
56
|
+
_N_OBS = 1
|
57
|
+
_PARAMS = ['mu', 'ap']
|
58
|
+
|
59
|
+
def _unnormalized_pdf(self, x):
|
60
|
+
x = z.unstack_x(x)
|
61
|
+
mu = self.params['mu']
|
62
|
+
ap = self.params['ap']
|
63
|
+
|
64
|
+
exp = (x - mu) / ap
|
65
|
+
den = 1 + z.exp(exp)
|
66
|
+
|
67
|
+
return 1. / den
|
68
|
+
#-------------------------------------------------------------------
|