ChessAnalysisPipeline 0.0.11__py3-none-any.whl → 0.0.13__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.
Potentially problematic release.
This version of ChessAnalysisPipeline might be problematic. Click here for more details.
- CHAP/__init__.py +2 -0
- CHAP/common/__init__.py +6 -2
- CHAP/common/models/map.py +217 -70
- CHAP/common/processor.py +249 -155
- CHAP/common/reader.py +175 -130
- CHAP/common/writer.py +150 -94
- CHAP/edd/models.py +458 -262
- CHAP/edd/processor.py +614 -354
- CHAP/edd/utils.py +746 -235
- CHAP/tomo/models.py +22 -18
- CHAP/tomo/processor.py +1215 -892
- CHAP/utils/fit.py +211 -127
- CHAP/utils/general.py +789 -610
- CHAP/utils/parfile.py +1 -9
- CHAP/utils/scanparsers.py +101 -52
- {ChessAnalysisPipeline-0.0.11.dist-info → ChessAnalysisPipeline-0.0.13.dist-info}/METADATA +1 -1
- {ChessAnalysisPipeline-0.0.11.dist-info → ChessAnalysisPipeline-0.0.13.dist-info}/RECORD +21 -21
- {ChessAnalysisPipeline-0.0.11.dist-info → ChessAnalysisPipeline-0.0.13.dist-info}/WHEEL +1 -1
- {ChessAnalysisPipeline-0.0.11.dist-info → ChessAnalysisPipeline-0.0.13.dist-info}/LICENSE +0 -0
- {ChessAnalysisPipeline-0.0.11.dist-info → ChessAnalysisPipeline-0.0.13.dist-info}/entry_points.txt +0 -0
- {ChessAnalysisPipeline-0.0.11.dist-info → ChessAnalysisPipeline-0.0.13.dist-info}/top_level.txt +0 -0
CHAP/utils/fit.py
CHANGED
|
@@ -118,7 +118,9 @@ class Fit:
|
|
|
118
118
|
self._result = None
|
|
119
119
|
self._try_linear_fit = True
|
|
120
120
|
self._param_constraint = None
|
|
121
|
+
self._fwhm_min = None
|
|
121
122
|
self._fwhm_max = None
|
|
123
|
+
self._sigma_min = None
|
|
122
124
|
self._sigma_max = None
|
|
123
125
|
self._y = None
|
|
124
126
|
self._y_norm = None
|
|
@@ -851,12 +853,20 @@ class Fit:
|
|
|
851
853
|
|
|
852
854
|
def create_multipeak_model(
|
|
853
855
|
self, centers=None, fit_type=None, peak_models=None,
|
|
854
|
-
center_exprs=None, background=None, param_constraint=
|
|
855
|
-
fwhm_max=None):
|
|
856
|
+
center_exprs=None, background=None, param_constraint=True,
|
|
857
|
+
fwhm_min=None, fwhm_max=None, centers_range=None):
|
|
856
858
|
"""Create a multipeak model."""
|
|
857
859
|
# System modules
|
|
858
860
|
from re import search as re_search
|
|
859
861
|
|
|
862
|
+
# Third party modules
|
|
863
|
+
from asteval import Interpreter
|
|
864
|
+
|
|
865
|
+
if centers_range is None:
|
|
866
|
+
centers_range = (self._x[0], self._x[-1])
|
|
867
|
+
elif not is_index_range(centers_range, ge=self._x[0], le=self._x[-1]):
|
|
868
|
+
raise ValueError(
|
|
869
|
+
f'Invalid parameter centers_range ({centers_range})')
|
|
860
870
|
if self._model is not None:
|
|
861
871
|
if self._fit_type == 'uniform' and fit_type != 'uniform':
|
|
862
872
|
logger.info('Use the existing multipeak model to refit a '
|
|
@@ -872,10 +882,12 @@ class Fit:
|
|
|
872
882
|
self._best_errors, scale_factor_index, 0)
|
|
873
883
|
for name, par in self._parameters.items():
|
|
874
884
|
if re_search('peak\d+_center', name) is not None:
|
|
875
|
-
par.set(
|
|
885
|
+
par.set(
|
|
886
|
+
min=centers_range[0], max=centers_range[1],
|
|
887
|
+
vary=True, expr=None)
|
|
876
888
|
self._parameter_bounds[name] = {
|
|
877
|
-
'min':
|
|
878
|
-
'max':
|
|
889
|
+
'min': centers_range[0],
|
|
890
|
+
'max': centers_range[1],
|
|
879
891
|
}
|
|
880
892
|
else:
|
|
881
893
|
for name, par in self._parameters.items():
|
|
@@ -942,11 +954,15 @@ class Fit:
|
|
|
942
954
|
raise ValueError(
|
|
943
955
|
f'Invalid parameter fit_type ({fit_type})')
|
|
944
956
|
self._fit_type = fit_type
|
|
957
|
+
self._fwhm_min = fwhm_min
|
|
945
958
|
self._fwhm_max = fwhm_max
|
|
959
|
+
self._sigma_min = None
|
|
946
960
|
self._sigma_max = None
|
|
947
961
|
if param_constraint:
|
|
948
962
|
self._param_constraint = True
|
|
949
963
|
min_value = FLOAT_MIN
|
|
964
|
+
if self._fwhm_min is not None:
|
|
965
|
+
self._sigma_min = np.zeros(num_peaks)
|
|
950
966
|
if self._fwhm_max is not None:
|
|
951
967
|
self._sigma_max = np.zeros(num_peaks)
|
|
952
968
|
else:
|
|
@@ -1045,7 +1061,13 @@ class Fit:
|
|
|
1045
1061
|
f'Invalid parameter background ({background})')
|
|
1046
1062
|
|
|
1047
1063
|
# Add peaks and set initial fit parameters
|
|
1064
|
+
ast = Interpreter()
|
|
1048
1065
|
if num_peaks == 1:
|
|
1066
|
+
sig_min = None
|
|
1067
|
+
if self._sigma_min is not None:
|
|
1068
|
+
ast(f'fwhm = {self._fwhm_min}')
|
|
1069
|
+
sig_min = ast(fwhm_factor[peak_models[0]])
|
|
1070
|
+
self._sigma_min[0] = sig_min
|
|
1049
1071
|
sig_max = None
|
|
1050
1072
|
if self._sigma_max is not None:
|
|
1051
1073
|
ast(f'fwhm = {self._fwhm_max}')
|
|
@@ -1055,14 +1077,20 @@ class Fit:
|
|
|
1055
1077
|
peak_models[0],
|
|
1056
1078
|
parameters=(
|
|
1057
1079
|
{'name': 'amplitude', 'min': min_value},
|
|
1058
|
-
{'name': 'center', 'value': centers[0],
|
|
1059
|
-
|
|
1080
|
+
{'name': 'center', 'value': centers[0],
|
|
1081
|
+
'min': centers_range[0], 'max': centers_range[1]},
|
|
1082
|
+
{'name': 'sigma', 'min': sig_min, 'max': sig_max},
|
|
1060
1083
|
))
|
|
1061
1084
|
else:
|
|
1062
1085
|
if fit_type == 'uniform':
|
|
1063
1086
|
self.add_parameter(
|
|
1064
1087
|
name='scale_factor', value=1.0, min=min_value)
|
|
1065
1088
|
for i in range(num_peaks):
|
|
1089
|
+
sig_min = None
|
|
1090
|
+
if self._sigma_min is not None:
|
|
1091
|
+
ast(f'fwhm = {self._fwhm_min}')
|
|
1092
|
+
sig_min = ast(fwhm_factor[peak_models[i]])
|
|
1093
|
+
self._sigma_min[i] = sig_min
|
|
1066
1094
|
sig_max = None
|
|
1067
1095
|
if self._sigma_max is not None:
|
|
1068
1096
|
ast(f'fwhm = {self._fwhm_max}')
|
|
@@ -1074,8 +1102,7 @@ class Fit:
|
|
|
1074
1102
|
parameters=(
|
|
1075
1103
|
{'name': 'amplitude', 'min': min_value},
|
|
1076
1104
|
{'name': 'center', 'expr': center_exprs[i]},
|
|
1077
|
-
{'name': 'sigma', 'min':
|
|
1078
|
-
'max': sig_max},
|
|
1105
|
+
{'name': 'sigma', 'min': sig_min, 'max': sig_max},
|
|
1079
1106
|
))
|
|
1080
1107
|
else:
|
|
1081
1108
|
self.add_model(
|
|
@@ -1084,7 +1111,7 @@ class Fit:
|
|
|
1084
1111
|
parameters=(
|
|
1085
1112
|
{'name': 'amplitude', 'min': min_value},
|
|
1086
1113
|
{'name': 'center', 'value': centers[i],
|
|
1087
|
-
'min':
|
|
1114
|
+
'min': centers_range[0], 'max': centers_range[1]},
|
|
1088
1115
|
{'name': 'sigma', 'min': min_value,
|
|
1089
1116
|
'max': sig_max},
|
|
1090
1117
|
))
|
|
@@ -1102,7 +1129,7 @@ class Fit:
|
|
|
1102
1129
|
# Third party modules
|
|
1103
1130
|
from asteval import Interpreter
|
|
1104
1131
|
|
|
1105
|
-
# Check
|
|
1132
|
+
# Check input parameters
|
|
1106
1133
|
if self._model is None:
|
|
1107
1134
|
logger.error('Undefined fit model')
|
|
1108
1135
|
return None
|
|
@@ -1121,6 +1148,11 @@ class Fit:
|
|
|
1121
1148
|
f'Invalid value of keyword argument guess ({guess})')
|
|
1122
1149
|
else:
|
|
1123
1150
|
guess = False
|
|
1151
|
+
if self._result is not None:
|
|
1152
|
+
if guess:
|
|
1153
|
+
logger.warning(
|
|
1154
|
+
'Ignoring input parameter guess during refitting')
|
|
1155
|
+
guess = False
|
|
1124
1156
|
if 'try_linear_fit' in kwargs:
|
|
1125
1157
|
try_linear_fit = kwargs.pop('try_linear_fit')
|
|
1126
1158
|
if not isinstance(try_linear_fit, bool):
|
|
@@ -1133,16 +1165,6 @@ class Fit:
|
|
|
1133
1165
|
'(not yet supported for callable models)')
|
|
1134
1166
|
else:
|
|
1135
1167
|
self._try_linear_fit = try_linear_fit
|
|
1136
|
-
if self._result is not None:
|
|
1137
|
-
if guess:
|
|
1138
|
-
logger.warning(
|
|
1139
|
-
'Ignoring input parameter guess during refitting')
|
|
1140
|
-
guess = False
|
|
1141
|
-
|
|
1142
|
-
# Check for circular expressions
|
|
1143
|
-
# RV
|
|
1144
|
-
# for name1, par1 in self._parameters.items():
|
|
1145
|
-
# if par1.expr is not None:
|
|
1146
1168
|
|
|
1147
1169
|
# Apply mask if supplied:
|
|
1148
1170
|
if 'mask' in kwargs:
|
|
@@ -1171,14 +1193,17 @@ class Fit:
|
|
|
1171
1193
|
# Should work for other peak-like models,
|
|
1172
1194
|
# but will need tests first
|
|
1173
1195
|
for component in self._model.components:
|
|
1174
|
-
if component
|
|
1196
|
+
if isinstance(component, GaussianModel):
|
|
1175
1197
|
center = self._parameters[
|
|
1176
1198
|
f"{component.prefix}center"].value
|
|
1177
1199
|
height_init, cen_init, fwhm_init = \
|
|
1178
1200
|
self.guess_init_peak(
|
|
1179
1201
|
xx, yy, center_guess=center,
|
|
1180
1202
|
use_max_for_center=False)
|
|
1181
|
-
if (self.
|
|
1203
|
+
if (self._fwhm_min is not None
|
|
1204
|
+
and fwhm_init < self._fwhm_min):
|
|
1205
|
+
fwhm_init = self._fwhm_min
|
|
1206
|
+
elif (self._fwhm_max is not None
|
|
1182
1207
|
and fwhm_init > self._fwhm_max):
|
|
1183
1208
|
fwhm_init = self._fwhm_max
|
|
1184
1209
|
ast(f'fwhm = {fwhm_init}')
|
|
@@ -1292,9 +1317,7 @@ class Fit:
|
|
|
1292
1317
|
self._parameter_bounds = {
|
|
1293
1318
|
name:{'min': par.min, 'max': par.max}
|
|
1294
1319
|
for name, par in self._parameters.items() if par.vary}
|
|
1295
|
-
|
|
1296
|
-
if par.vary:
|
|
1297
|
-
par.set(value=self._reset_par_at_boundary(par, par.value))
|
|
1320
|
+
self._reset_par_at_boundary()
|
|
1298
1321
|
|
|
1299
1322
|
# Perform the fit
|
|
1300
1323
|
fit_kws = None
|
|
@@ -1842,39 +1865,39 @@ class Fit:
|
|
|
1842
1865
|
if self._result.residual is not None:
|
|
1843
1866
|
self._result.residual *= self._norm[1]
|
|
1844
1867
|
|
|
1845
|
-
def _reset_par_at_boundary(self
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
if np.isinf(_max):
|
|
1862
|
-
if self._parameter_norms.get(name, False):
|
|
1863
|
-
low = _min + 0.1*self._y_range
|
|
1864
|
-
elif _min == 0.0:
|
|
1865
|
-
low = _min+0.1
|
|
1868
|
+
def _reset_par_at_boundary(self):
|
|
1869
|
+
for name, par in self._parameters.items():
|
|
1870
|
+
if par.vary:
|
|
1871
|
+
value = par.value
|
|
1872
|
+
_min = self._parameter_bounds[name]['min']
|
|
1873
|
+
_max = self._parameter_bounds[name]['max']
|
|
1874
|
+
if np.isinf(_min):
|
|
1875
|
+
if not np.isinf(_max):
|
|
1876
|
+
if self._parameter_norms.get(name, False):
|
|
1877
|
+
upp = _max-0.1*self._y_range
|
|
1878
|
+
elif _max == 0.0:
|
|
1879
|
+
upp = _max-0.1
|
|
1880
|
+
else:
|
|
1881
|
+
upp = _max-0.1*abs(_max)
|
|
1882
|
+
if value >= upp:
|
|
1883
|
+
par.set(value=upp)
|
|
1866
1884
|
else:
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1885
|
+
if np.isinf(_max):
|
|
1886
|
+
if self._parameter_norms.get(name, False):
|
|
1887
|
+
low = _min + 0.1*self._y_range
|
|
1888
|
+
elif _min == 0.0:
|
|
1889
|
+
low = _min+0.1
|
|
1890
|
+
else:
|
|
1891
|
+
low = _min + 0.1*abs(_min)
|
|
1892
|
+
if value <= low:
|
|
1893
|
+
par.set(value=low)
|
|
1894
|
+
else:
|
|
1895
|
+
low = 0.9*_min + 0.1*_max
|
|
1896
|
+
upp = 0.1*_min + 0.9*_max
|
|
1897
|
+
if value <= low:
|
|
1898
|
+
par.set(value=low)
|
|
1899
|
+
if value >= upp:
|
|
1900
|
+
par.set(value=upp)
|
|
1878
1901
|
|
|
1879
1902
|
|
|
1880
1903
|
class FitMap(Fit):
|
|
@@ -1917,7 +1940,7 @@ class FitMap(Fit):
|
|
|
1917
1940
|
raise ValueError('Invalid parameter ymap ({ymap})')
|
|
1918
1941
|
self._ymap = ymap
|
|
1919
1942
|
|
|
1920
|
-
#
|
|
1943
|
+
# Check input parameters
|
|
1921
1944
|
if self._x.ndim != 1:
|
|
1922
1945
|
raise ValueError(f'Invalid dimension for input x {self._x.ndim}')
|
|
1923
1946
|
if self._ymap.ndim < 2:
|
|
@@ -2314,7 +2337,7 @@ class FitMap(Fit):
|
|
|
2314
2337
|
logger.warning(
|
|
2315
2338
|
f'The requested number of processors ({num_proc}) exceeds the '
|
|
2316
2339
|
'maximum number of processors, num_proc reduced to '
|
|
2317
|
-
f'
|
|
2340
|
+
f'{cpu_count()}')
|
|
2318
2341
|
num_proc = cpu_count()
|
|
2319
2342
|
if 'try_no_bounds' in kwargs:
|
|
2320
2343
|
self._try_no_bounds = kwargs.pop('try_no_bounds')
|
|
@@ -2469,9 +2492,7 @@ class FitMap(Fit):
|
|
|
2469
2492
|
self._parameter_bounds = {
|
|
2470
2493
|
name:{'min': par.min, 'max': par.max}
|
|
2471
2494
|
for name, par in self._parameters.items() if par.vary}
|
|
2472
|
-
|
|
2473
|
-
if par.vary:
|
|
2474
|
-
par.set(value=self._reset_par_at_boundary(par, par.value))
|
|
2495
|
+
self._reset_par_at_boundary()
|
|
2475
2496
|
|
|
2476
2497
|
# Set parameter bounds to unbound
|
|
2477
2498
|
# (only use bounds when fit fails)
|
|
@@ -2587,7 +2608,7 @@ class FitMap(Fit):
|
|
|
2587
2608
|
if num_proc > num_fit:
|
|
2588
2609
|
logger.warning(
|
|
2589
2610
|
f'The requested number of processors ({num_proc}) exceeds '
|
|
2590
|
-
f'the number of fits, num_proc reduced to
|
|
2611
|
+
f'the number of fits, num_proc reduced to {num_fit}')
|
|
2591
2612
|
num_proc = num_fit
|
|
2592
2613
|
num_fit_per_proc = 1
|
|
2593
2614
|
else:
|
|
@@ -2684,23 +2705,112 @@ class FitMap(Fit):
|
|
|
2684
2705
|
self._fit(n_start+n, current_best_values, **kwargs)
|
|
2685
2706
|
|
|
2686
2707
|
def _fit(self, n, current_best_values, return_result=False, **kwargs):
|
|
2708
|
+
# Check input parameters
|
|
2709
|
+
if 'rel_amplitude_cutoff' in kwargs:
|
|
2710
|
+
rel_amplitude_cutoff = kwargs.pop('rel_amplitude_cutoff')
|
|
2711
|
+
if (rel_amplitude_cutoff is not None
|
|
2712
|
+
and not is_num(rel_amplitude_cutoff, gt=0.0, lt=1.0)):
|
|
2713
|
+
logger.warning(
|
|
2714
|
+
'Ignoring invalid parameter rel_amplitude_cutoff '
|
|
2715
|
+
f'in FitMap._fit() ({rel_amplitude_cutoff})')
|
|
2716
|
+
rel_amplitude_cutoff = None
|
|
2717
|
+
else:
|
|
2718
|
+
rel_amplitude_cutoff = None
|
|
2719
|
+
|
|
2720
|
+
# Regular full fit
|
|
2721
|
+
result = self._fit_with_bounds_check(n, current_best_values, **kwargs)
|
|
2722
|
+
|
|
2723
|
+
if rel_amplitude_cutoff is not None:
|
|
2724
|
+
# Third party modules
|
|
2725
|
+
from lmfit.models import (
|
|
2726
|
+
GaussianModel,
|
|
2727
|
+
LorentzianModel,
|
|
2728
|
+
)
|
|
2729
|
+
|
|
2730
|
+
# Check for low amplitude peaks and refit without them
|
|
2731
|
+
amplitudes = []
|
|
2732
|
+
names = []
|
|
2733
|
+
for component in result.components:
|
|
2734
|
+
if isinstance(component, (GaussianModel, LorentzianModel)):
|
|
2735
|
+
for name in component.param_names:
|
|
2736
|
+
if 'amplitude' in name:
|
|
2737
|
+
amplitudes.append(result.params[name].value)
|
|
2738
|
+
names.append(name)
|
|
2739
|
+
if amplitudes:
|
|
2740
|
+
refit = False
|
|
2741
|
+
amplitudes = np.asarray(amplitudes)/sum(amplitudes)
|
|
2742
|
+
parameters_save = deepcopy(self._parameters)
|
|
2743
|
+
for i, (name, amp) in enumerate(zip(names, amplitudes)):
|
|
2744
|
+
if abs(amp) < rel_amplitude_cutoff:
|
|
2745
|
+
self._parameters[name].set(
|
|
2746
|
+
value=0.0, min=0.0, vary=False)
|
|
2747
|
+
self._parameters[
|
|
2748
|
+
name.replace('amplitude', 'center')].set(
|
|
2749
|
+
vary=False)
|
|
2750
|
+
self._parameters[
|
|
2751
|
+
name.replace('amplitude', 'sigma')].set(
|
|
2752
|
+
value=0.0, min=0.0, vary=False)
|
|
2753
|
+
refit = True
|
|
2754
|
+
if refit:
|
|
2755
|
+
result = self._fit_with_bounds_check(
|
|
2756
|
+
n, current_best_values, **kwargs)
|
|
2757
|
+
# for name in names:
|
|
2758
|
+
# result.params[name].error = 0.0
|
|
2759
|
+
# Reset fixed amplitudes back to default
|
|
2760
|
+
self._parameters = deepcopy(parameters_save)
|
|
2761
|
+
|
|
2762
|
+
if result.redchi >= self._redchi_cutoff:
|
|
2763
|
+
result.success = False
|
|
2764
|
+
if result.nfev == result.max_nfev:
|
|
2765
|
+
if result.redchi < self._redchi_cutoff:
|
|
2766
|
+
result.success = True
|
|
2767
|
+
self._max_nfev_flat[n] = True
|
|
2768
|
+
if result.success:
|
|
2769
|
+
assert all(
|
|
2770
|
+
True for par in current_best_values
|
|
2771
|
+
if par in result.params.values())
|
|
2772
|
+
for par in result.params.values():
|
|
2773
|
+
if par.vary:
|
|
2774
|
+
current_best_values[par.name] = par.value
|
|
2775
|
+
else:
|
|
2776
|
+
logger.warning(f'Fit for n = {n} failed: {result.lmdif_message}')
|
|
2777
|
+
# Renormalize the data and results
|
|
2778
|
+
self._renormalize(n, result)
|
|
2779
|
+
if self._print_report:
|
|
2780
|
+
print(result.fit_report(show_correl=False))
|
|
2781
|
+
if self._plot:
|
|
2782
|
+
dims = np.unravel_index(n, self._map_shape)
|
|
2783
|
+
if self._inv_transpose is not None:
|
|
2784
|
+
dims = tuple(
|
|
2785
|
+
dims[self._inv_transpose[i]] for i in range(len(dims)))
|
|
2786
|
+
super().plot(
|
|
2787
|
+
result=result, y=np.asarray(self._ymap[dims]),
|
|
2788
|
+
plot_comp_legends=True, skip_init=self._skip_init,
|
|
2789
|
+
title=str(dims))
|
|
2790
|
+
if return_result:
|
|
2791
|
+
return result
|
|
2792
|
+
return None
|
|
2793
|
+
|
|
2794
|
+
def _fit_with_bounds_check(self, n, current_best_values, **kwargs):
|
|
2687
2795
|
# Set parameters to current best values, but prevent them from
|
|
2688
2796
|
# sitting at boundaries
|
|
2689
2797
|
if self._new_parameters is None:
|
|
2690
2798
|
# Initial fit
|
|
2691
2799
|
for name, value in current_best_values.items():
|
|
2692
2800
|
par = self._parameters[name]
|
|
2693
|
-
par.
|
|
2801
|
+
if par.vary:
|
|
2802
|
+
par.set(value=value)
|
|
2694
2803
|
else:
|
|
2695
2804
|
# Refit
|
|
2696
2805
|
for i, name in enumerate(self._best_parameters):
|
|
2697
2806
|
par = self._parameters[name]
|
|
2698
|
-
if
|
|
2699
|
-
if name in
|
|
2700
|
-
|
|
2701
|
-
par
|
|
2702
|
-
|
|
2703
|
-
|
|
2807
|
+
if par.vary:
|
|
2808
|
+
if name in self._new_parameters:
|
|
2809
|
+
if name in current_best_values:
|
|
2810
|
+
par.set(value=current_best_values[name])
|
|
2811
|
+
elif par.expr is None:
|
|
2812
|
+
par.set(value=self._best_values[i][n])
|
|
2813
|
+
self._reset_par_at_boundary()
|
|
2704
2814
|
if self._mask is None:
|
|
2705
2815
|
result = self._model.fit(
|
|
2706
2816
|
self._ymap_norm[n], self._parameters, x=self._x, **kwargs)
|
|
@@ -2710,35 +2820,39 @@ class FitMap(Fit):
|
|
|
2710
2820
|
x=self._x[~self._mask], **kwargs)
|
|
2711
2821
|
out_of_bounds = False
|
|
2712
2822
|
for name, par in self._parameter_bounds.items():
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2823
|
+
if self._parameters[name].vary:
|
|
2824
|
+
value = result.params[name].value
|
|
2825
|
+
if not np.isinf(par['min']) and value < par['min']:
|
|
2826
|
+
out_of_bounds = True
|
|
2827
|
+
break
|
|
2828
|
+
if not np.isinf(par['max']) and value > par['max']:
|
|
2829
|
+
out_of_bounds = True
|
|
2830
|
+
break
|
|
2720
2831
|
self._out_of_bounds_flat[n] = out_of_bounds
|
|
2721
2832
|
if self._try_no_bounds and out_of_bounds:
|
|
2722
2833
|
# Rerun fit with parameter bounds in place
|
|
2723
2834
|
for name, par in self._parameter_bounds.items():
|
|
2724
|
-
self._parameters[name].
|
|
2835
|
+
if self._parameters[name].vary:
|
|
2836
|
+
self._parameters[name].set(min=par['min'], max=par['max'])
|
|
2725
2837
|
# Set parameters to current best values, but prevent them
|
|
2726
2838
|
# from sitting at boundaries
|
|
2727
2839
|
if self._new_parameters is None:
|
|
2728
2840
|
# Initial fit
|
|
2729
2841
|
for name, value in current_best_values.items():
|
|
2730
2842
|
par = self._parameters[name]
|
|
2731
|
-
par.
|
|
2843
|
+
if par.vary:
|
|
2844
|
+
par.set(value=value)
|
|
2732
2845
|
else:
|
|
2733
2846
|
# Refit
|
|
2734
2847
|
for i, name in enumerate(self._best_parameters):
|
|
2735
2848
|
par = self._parameters[name]
|
|
2736
|
-
if
|
|
2737
|
-
if name in
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2849
|
+
if par.vary:
|
|
2850
|
+
if name in self._new_parameters:
|
|
2851
|
+
if name in current_best_values:
|
|
2852
|
+
par.set(value=current_best_values[name])
|
|
2853
|
+
elif par.expr is None:
|
|
2854
|
+
par.set(value=self._best_values[i][n])
|
|
2855
|
+
self._reset_par_at_boundary()
|
|
2742
2856
|
if self._mask is None:
|
|
2743
2857
|
result = self._model.fit(
|
|
2744
2858
|
self._ymap_norm[n], self._parameters, x=self._x, **kwargs)
|
|
@@ -2748,48 +2862,18 @@ class FitMap(Fit):
|
|
|
2748
2862
|
x=self._x[~self._mask], **kwargs)
|
|
2749
2863
|
out_of_bounds = False
|
|
2750
2864
|
for name, par in self._parameter_bounds.items():
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2865
|
+
if self._parameters[name].vary:
|
|
2866
|
+
value = result.params[name].value
|
|
2867
|
+
if not np.isinf(par['min']) and value < par['min']:
|
|
2868
|
+
out_of_bounds = True
|
|
2869
|
+
break
|
|
2870
|
+
if not np.isinf(par['max']) and value > par['max']:
|
|
2871
|
+
out_of_bounds = True
|
|
2872
|
+
break
|
|
2873
|
+
# Reset parameters back to unbound
|
|
2874
|
+
self._parameters[name].set(min=-np.inf, max=np.inf)
|
|
2761
2875
|
assert not out_of_bounds
|
|
2762
|
-
|
|
2763
|
-
result.success = False
|
|
2764
|
-
if result.nfev == result.max_nfev:
|
|
2765
|
-
if result.redchi < self._redchi_cutoff:
|
|
2766
|
-
result.success = True
|
|
2767
|
-
self._max_nfev_flat[n] = True
|
|
2768
|
-
if result.success:
|
|
2769
|
-
assert all(
|
|
2770
|
-
True for par in current_best_values
|
|
2771
|
-
if par in result.params.values())
|
|
2772
|
-
for par in result.params.values():
|
|
2773
|
-
if par.vary:
|
|
2774
|
-
current_best_values[par.name] = par.value
|
|
2775
|
-
else:
|
|
2776
|
-
logger.warning(f'Fit for n = {n} failed: {result.lmdif_message}')
|
|
2777
|
-
# Renormalize the data and results
|
|
2778
|
-
self._renormalize(n, result)
|
|
2779
|
-
if self._print_report:
|
|
2780
|
-
print(result.fit_report(show_correl=False))
|
|
2781
|
-
if self._plot:
|
|
2782
|
-
dims = np.unravel_index(n, self._map_shape)
|
|
2783
|
-
if self._inv_transpose is not None:
|
|
2784
|
-
dims = tuple(
|
|
2785
|
-
dims[self._inv_transpose[i]] for i in range(len(dims)))
|
|
2786
|
-
super().plot(
|
|
2787
|
-
result=result, y=np.asarray(self._ymap[dims]),
|
|
2788
|
-
plot_comp_legends=True, skip_init=self._skip_init,
|
|
2789
|
-
title=str(dims))
|
|
2790
|
-
if return_result:
|
|
2791
|
-
return result
|
|
2792
|
-
return None
|
|
2876
|
+
return result
|
|
2793
2877
|
|
|
2794
2878
|
def _renormalize(self, n, result):
|
|
2795
2879
|
self._redchi_flat[n] = np.float64(result.redchi)
|