diff --git a/Troubled_Cell_Detector.py b/Troubled_Cell_Detector.py index 058f52432221abb516dbac358680a3bfeb7ccefd..ce4cecfde141ced7ef274284d05b66abca9c291c 100644 --- a/Troubled_Cell_Detector.py +++ b/Troubled_Cell_Detector.py @@ -5,7 +5,7 @@ TODO: Vectorize _get_cells() in Boxplot method -> Done TODO: Restructure Boxplot method -> Done TODO: Introduce lower/upper extreme outliers in Boxplot - (each cell is also checked for neighboring domains if existing) + (each cell is also checked for neighboring domains if existing) -> Done TODO: Determine max_value for Theoretical only over highest degree TODO: Check if indexing in wavelets is correct TODO: Add ThresholdDetector @@ -340,13 +340,15 @@ class Boxplot(WaveletDetector): Length of Boxplot whiskers. adjust_outer_fences : bool Flag whether outer fences should be adjusted using global mean. + extreme_outlier_only : bool + Flag whether outliers also have to be detected in neighbouring folds. folds : ndarray Array with indices for elements of each fold (including overlaps). """ def _reset(self, config): - """Resets instance variables. + """Reset instance variables. Parameters ---------- @@ -360,6 +362,7 @@ class Boxplot(WaveletDetector): self._fold_len = config.pop('fold_len', 16) self._whisker_len = config.pop('whisker_len', 3) self._adjust_outer_fences = config.pop('adjust_outer_fences', True) + self._extreme_outlier_only = config.pop('extreme_outlier_only', True) if self._mesh.num_grid_cells < self._fold_len: self._fold_len = self._mesh.num_grid_cells @@ -400,7 +403,7 @@ class Boxplot(WaveletDetector): boundary_index = self._fold_len//4 balance_factor = self._fold_len/4.0 - boundary_index - # Determine bounds based on first and third quartiles of a boxplot + # Determine first and third quartiles first_quartiles = (1-balance_factor) \ * folds[:, boundary_index-1] \ + balance_factor * folds[:, boundary_index] @@ -408,11 +411,21 @@ class Boxplot(WaveletDetector): * folds[:, 3*boundary_index-1]\ + balance_factor * folds[:, 3*boundary_index] - lower_bounds = first_quartiles - self._whisker_len * ( + # Determine bounds based on quartiles of a boxplot + lower_bounds = np.zeros(len(first_quartiles) + 2) + upper_bounds = np.zeros(len(first_quartiles) + 2) + + lower_bounds[1:-1] = first_quartiles - self._whisker_len * ( third_quartiles-first_quartiles) - upper_bounds = third_quartiles + self._whisker_len * ( + upper_bounds[1:-1] = third_quartiles + self._whisker_len * ( third_quartiles-first_quartiles) + # Adjust bounds to capture periodic boundary + lower_bounds[0] = lower_bounds[-2] + lower_bounds[-1] = lower_bounds[1] + upper_bounds[0] = upper_bounds[-2] + upper_bounds[-1] = upper_bounds[1] + # Adjust outer fences if flag is set if self._adjust_outer_fences: global_mean = np.mean(abs(coeffs)) @@ -420,9 +433,20 @@ class Boxplot(WaveletDetector): upper_bounds[upper_bounds < global_mean] = global_mean # Select outliers as troubled cells - troubled_cells = np.flatnonzero(np.logical_or( - coeffs < np.repeat(lower_bounds, self._fold_len), - coeffs > np.repeat(upper_bounds, self._fold_len))).tolist() + lower_outlier = coeffs < np.repeat(lower_bounds[1:-1], self._fold_len) + upper_outlier = coeffs > np.repeat(upper_bounds[1:-1], self._fold_len) + + # Adjust for extreme outliers if flag is set + if self._extreme_outlier_only: + lower_outlier = np.logical_and(lower_outlier, np.logical_and( + coeffs < np.repeat(lower_bounds[:-2], self._fold_len), + coeffs < np.repeat(lower_bounds[2:], self._fold_len))) + upper_outlier = np.logical_and(upper_outlier, np.logical_and( + coeffs > np.repeat(upper_bounds[:-2], self._fold_len), + coeffs > np.repeat(upper_bounds[2:], self._fold_len))) + + troubled_cells = np.flatnonzero(np.logical_or(lower_outlier, + upper_outlier)).tolist() return troubled_cells