ChessAnalysisPipeline 0.0.12__py3-none-any.whl → 0.0.14__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/utils/fit.py CHANGED
@@ -862,9 +862,13 @@ class Fit:
862
862
  # Third party modules
863
863
  from asteval import Interpreter
864
864
 
865
+ # Local modules
866
+ from CHAP.utils.general import is_num_pair
867
+
865
868
  if centers_range is None:
866
869
  centers_range = (self._x[0], self._x[-1])
867
- elif not is_index_range(centers_range, ge=self._x[0], le=self._x[-1]):
870
+ elif (not is_num_pair(centers_range) or len(centers_range) != 2
871
+ or centers_range[0] >= centers_range[1]):
868
872
  raise ValueError(
869
873
  f'Invalid parameter centers_range ({centers_range})')
870
874
  if self._model is not None:
@@ -1021,9 +1025,8 @@ class Fit:
1021
1025
  {'name': par_name, 'min': min_value})
1022
1026
  elif len(index) == 1:
1023
1027
  parameter = parameters[index[0]]
1024
- _min = parameter.get('min', None)
1025
- if _min is None or _min < min_value:
1026
- parameter['min'] = min_value
1028
+ _min = parameter.get('min', min_value)
1029
+ parameter['min'] = max(_min, min_value)
1027
1030
  else:
1028
1031
  raise ValueError(
1029
1032
  'Invalid parameters value in '
@@ -1045,14 +1048,47 @@ class Fit:
1045
1048
  {'name': par_name, 'min': min_value})
1046
1049
  elif len(index) == 1:
1047
1050
  parameter = parameters[index[0]]
1048
- _min = parameter.get('min', None)
1049
- if _min is None or _min < min_value:
1050
- parameter['min'] = min_value
1051
+ _min = parameter.get('min', min_value)
1052
+ parameter['min'] = max(_min, min_value)
1051
1053
  else:
1052
1054
  raise ValueError(
1053
1055
  'Invalid parameters value in '
1054
1056
  f'background model {name} '
1055
1057
  f'({parameters})')
1058
+ if name == 'gaussian':
1059
+ if parameters is None:
1060
+ parameters = {
1061
+ 'name': 'center',
1062
+ 'value': 0.5 * (
1063
+ centers_range[0] + centers_range[1]),
1064
+ 'min': centers_range[0],
1065
+ 'min': centers_range[1],
1066
+ }
1067
+ else:
1068
+ index = [i for i, par in enumerate(parameters)
1069
+ if par['name'] == 'center']
1070
+ if not len(index):
1071
+ parameters.append({
1072
+ 'name': 'center',
1073
+ 'value': 0.5 * (
1074
+ centers_range[0] + centers_range[1]),
1075
+ 'min': centers_range[0],
1076
+ 'max': centers_range[1],
1077
+ })
1078
+ elif len(index) == 1:
1079
+ parameter = parameters[index[0]]
1080
+ if 'value' not in parameter:
1081
+ parameter['value'] = 0.5 * (
1082
+ centers_range[0]+centers_range[1])
1083
+ _min = parameter.get('min', centers_range[0])
1084
+ parameter['min'] = max(_min, centers_range[0])
1085
+ _max = parameter.get('max', centers_range[1])
1086
+ parameter['max'] = min(_max, centers_range[1])
1087
+ else:
1088
+ raise ValueError(
1089
+ 'Invalid parameters value in '
1090
+ f'background model {name} '
1091
+ f'({parameters})')
1056
1092
  self.add_model(
1057
1093
  name, prefix=prefix, parameters=parameters,
1058
1094
  **model)
@@ -1320,14 +1356,11 @@ class Fit:
1320
1356
  self._reset_par_at_boundary()
1321
1357
 
1322
1358
  # Perform the fit
1323
- fit_kws = None
1324
- # if 'Dfun' in kwargs:
1325
- # fit_kws = {'Dfun': kwargs.pop('Dfun')}
1326
- # self._result = self._model.fit(
1327
- # self._y_norm, self._parameters, x=self._x, fit_kws=fit_kws,
1328
- # **kwargs)
1359
+ fit_kws = {}
1329
1360
  if self._param_constraint:
1330
1361
  fit_kws = {'xtol': 1.e-5, 'ftol': 1.e-5, 'gtol': 1.e-5}
1362
+ # if 'Dfun' in kwargs:
1363
+ # fit_kws['Dfun'] = kwargs.pop('Dfun')
1331
1364
  if self._mask is None:
1332
1365
  self._result = self._model.fit(
1333
1366
  self._y_norm, self._parameters, x=self._x, fit_kws=fit_kws,
@@ -1866,6 +1899,7 @@ class Fit:
1866
1899
  self._result.residual *= self._norm[1]
1867
1900
 
1868
1901
  def _reset_par_at_boundary(self):
1902
+ fraction = 0.02
1869
1903
  for name, par in self._parameters.items():
1870
1904
  if par.vary:
1871
1905
  value = par.value
@@ -1874,26 +1908,26 @@ class Fit:
1874
1908
  if np.isinf(_min):
1875
1909
  if not np.isinf(_max):
1876
1910
  if self._parameter_norms.get(name, False):
1877
- upp = _max-0.1*self._y_range
1911
+ upp = _max - fraction*self._y_range
1878
1912
  elif _max == 0.0:
1879
- upp = _max-0.1
1913
+ upp = _max - fraction
1880
1914
  else:
1881
- upp = _max-0.1*abs(_max)
1915
+ upp = _max - fraction*abs(_max)
1882
1916
  if value >= upp:
1883
1917
  par.set(value=upp)
1884
1918
  else:
1885
1919
  if np.isinf(_max):
1886
1920
  if self._parameter_norms.get(name, False):
1887
- low = _min + 0.1*self._y_range
1921
+ low = _min + fraction*self._y_range
1888
1922
  elif _min == 0.0:
1889
- low = _min+0.1
1923
+ low = _min + fraction
1890
1924
  else:
1891
- low = _min + 0.1*abs(_min)
1925
+ low = _min + fraction*abs(_min)
1892
1926
  if value <= low:
1893
1927
  par.set(value=low)
1894
1928
  else:
1895
- low = 0.9*_min + 0.1*_max
1896
- upp = 0.1*_min + 0.9*_max
1929
+ low = (1.0-fraction)*_min + fraction*_max
1930
+ upp = fraction*_min + (1.0-fraction)*_max
1897
1931
  if value <= low:
1898
1932
  par.set(value=low)
1899
1933
  if value >= upp:
@@ -1917,6 +1951,7 @@ class FitMap(Fit):
1917
1951
  self._max_nfev = None
1918
1952
  self._memfolder = None
1919
1953
  self._new_parameters = None
1954
+ self._num_func_eval = None
1920
1955
  self._out_of_bounds = None
1921
1956
  self._plot = False
1922
1957
  self._print_report = False
@@ -1932,6 +1967,7 @@ class FitMap(Fit):
1932
1967
  # map dimensions
1933
1968
  if isinstance(ymap, (tuple, list, np.ndarray)):
1934
1969
  self._x = np.asarray(x)
1970
+ ymap = np.asarray(ymap)
1935
1971
  elif HAVE_XARRAY and isinstance(ymap, xr.DataArray):
1936
1972
  if x is not None:
1937
1973
  logger.warning('Ignoring superfluous input x ({x})')
@@ -2149,7 +2185,8 @@ class FitMap(Fit):
2149
2185
  @property
2150
2186
  def max_nfev(self):
2151
2187
  """
2152
- Return the maximum number of function evaluations for each fit.
2188
+ Return if the maximum number of function evaluations is reached
2189
+ for each fit.
2153
2190
  """
2154
2191
  return self._max_nfev
2155
2192
 
@@ -2158,7 +2195,7 @@ class FitMap(Fit):
2158
2195
  """
2159
2196
  Return the number of function evaluations for each best fit.
2160
2197
  """
2161
- logger.warning('Undefined property num_func_eval')
2198
+ return self._num_func_eval
2162
2199
 
2163
2200
  @property
2164
2201
  def out_of_bounds(self):
@@ -2466,6 +2503,7 @@ class FitMap(Fit):
2466
2503
  if self._result is not None:
2467
2504
  self._out_of_bounds = None
2468
2505
  self._max_nfev = None
2506
+ self._num_func_eval = None
2469
2507
  self._redchi = None
2470
2508
  self._success = None
2471
2509
  self._best_fit = None
@@ -2508,6 +2546,7 @@ class FitMap(Fit):
2508
2546
  if num_proc == 1:
2509
2547
  self._out_of_bounds_flat = np.zeros(self._map_dim, dtype=bool)
2510
2548
  self._max_nfev_flat = np.zeros(self._map_dim, dtype=bool)
2549
+ self._num_func_eval_flat = np.zeros(self._map_dim, dtype=np.intc)
2511
2550
  self._redchi_flat = np.zeros(self._map_dim, dtype=np.float64)
2512
2551
  self._success_flat = np.zeros(self._map_dim, dtype=bool)
2513
2552
  self._best_fit_flat = np.zeros(
@@ -2537,6 +2576,11 @@ class FitMap(Fit):
2537
2576
  filename_memmap = path.join(self._memfolder, 'max_nfev_memmap')
2538
2577
  self._max_nfev_flat = np.memmap(
2539
2578
  filename_memmap, dtype=bool, shape=(self._map_dim), mode='w+')
2579
+ filename_memmap = path.join(
2580
+ self._memfolder, 'num_func_eval_memmap')
2581
+ self._num_func_eval_flat = np.memmap(
2582
+ filename_memmap, dtype=np.intc, shape=(self._map_dim),
2583
+ mode='w+')
2540
2584
  filename_memmap = path.join(self._memfolder, 'redchi_memmap')
2541
2585
  self._redchi_flat = np.memmap(
2542
2586
  filename_memmap, dtype=np.float64, shape=(self._map_dim),
@@ -2598,29 +2642,32 @@ class FitMap(Fit):
2598
2642
  except AttributeError:
2599
2643
  pass
2600
2644
 
2601
- if num_proc == 1:
2602
- # Perform the remaining fits serially
2603
- for n in range(1, self._map_dim):
2604
- self._fit(n, current_best_values, **kwargs)
2605
- else:
2606
- # Perform the remaining fits in parallel
2607
- num_fit = self._map_dim-1
2608
- if num_proc > num_fit:
2609
- logger.warning(
2610
- f'The requested number of processors ({num_proc}) exceeds '
2611
- f'the number of fits, num_proc reduced to {num_fit}')
2612
- num_proc = num_fit
2613
- num_fit_per_proc = 1
2645
+ if self._map_dim > 1:
2646
+ if num_proc == 1:
2647
+ # Perform the remaining fits serially
2648
+ for n in range(1, self._map_dim):
2649
+ self._fit(n, current_best_values, **kwargs)
2614
2650
  else:
2615
- num_fit_per_proc = round((num_fit)/num_proc)
2616
- if num_proc*num_fit_per_proc < num_fit:
2617
- num_fit_per_proc += 1
2618
- num_fit_batch = min(num_fit_per_proc, 40)
2619
- with Parallel(n_jobs=num_proc) as parallel:
2620
- parallel(
2621
- delayed(self._fit_parallel)
2622
- (current_best_values, num_fit_batch, n_start, **kwargs)
2623
- for n_start in range(1, self._map_dim, num_fit_batch))
2651
+ # Perform the remaining fits in parallel
2652
+ num_fit = self._map_dim-1
2653
+ if num_proc > num_fit:
2654
+ logger.warning(
2655
+ f'The requested number of processors ({num_proc}) '
2656
+ 'exceeds the number of fits, num_proc reduced to '
2657
+ f'{num_fit}')
2658
+ num_proc = num_fit
2659
+ num_fit_per_proc = 1
2660
+ else:
2661
+ num_fit_per_proc = round((num_fit)/num_proc)
2662
+ if num_proc*num_fit_per_proc < num_fit:
2663
+ num_fit_per_proc += 1
2664
+ num_fit_batch = min(num_fit_per_proc, 40)
2665
+ with Parallel(n_jobs=num_proc) as parallel:
2666
+ parallel(
2667
+ delayed(self._fit_parallel)
2668
+ (current_best_values, num_fit_batch, n_start,
2669
+ **kwargs)
2670
+ for n_start in range(1, self._map_dim, num_fit_batch))
2624
2671
 
2625
2672
  # Renormalize the initial parameters for external use
2626
2673
  if self._norm is not None and self._normalized:
@@ -2649,6 +2696,8 @@ class FitMap(Fit):
2649
2696
  self._out_of_bounds_flat, self._map_shape))
2650
2697
  self._max_nfev = np.copy(np.reshape(
2651
2698
  self._max_nfev_flat, self._map_shape))
2699
+ self._num_func_eval = np.copy(np.reshape(
2700
+ self._num_func_eval_flat, self._map_shape))
2652
2701
  self._redchi = np.copy(np.reshape(self._redchi_flat, self._map_shape))
2653
2702
  self._success = np.copy(np.reshape(
2654
2703
  self._success_flat, self._map_shape))
@@ -2662,6 +2711,8 @@ class FitMap(Fit):
2662
2711
  self._out_of_bounds = np.transpose(
2663
2712
  self._out_of_bounds, self._inv_transpose)
2664
2713
  self._max_nfev = np.transpose(self._max_nfev, self._inv_transpose)
2714
+ self._num_func_eval = np.transpose(
2715
+ self._num_func_eval, self._inv_transpose)
2665
2716
  self._redchi = np.transpose(self._redchi, self._inv_transpose)
2666
2717
  self._success = np.transpose(self._success, self._inv_transpose)
2667
2718
  self._best_fit = np.transpose(
@@ -2673,6 +2724,7 @@ class FitMap(Fit):
2673
2724
  self._best_errors, [0] + [i+1 for i in self._inv_transpose])
2674
2725
  del self._out_of_bounds_flat
2675
2726
  del self._max_nfev_flat
2727
+ del self._num_func_eval_flat
2676
2728
  del self._redchi_flat
2677
2729
  del self._success_flat
2678
2730
  del self._best_fit_flat
@@ -2761,6 +2813,7 @@ class FitMap(Fit):
2761
2813
 
2762
2814
  if result.redchi >= self._redchi_cutoff:
2763
2815
  result.success = False
2816
+ self._num_func_eval_flat[n] = result.nfev
2764
2817
  if result.nfev == result.max_nfev:
2765
2818
  if result.redchi < self._redchi_cutoff:
2766
2819
  result.success = True