def test_threshold_below_fuzzy_miss(self): """Test not meeting the threshold in fuzzy below-threshold-mode.""" plugin = Threshold(2.0, fuzzy_factor=self.fuzzy_factor, comparison_operator="<") result = plugin(self.cube) expected_result_array = np.ones_like(self.cube.data).reshape( (1, 1, 5, 5)) self.assertArrayAlmostEqual(result.data, expected_result_array)
def test_threshold_asymmetric_bounds_upper_below(self): """Test when a point is in upper asymmetric fuzzy threshold area and below-threshold is requested.""" bounds = (0.0, 0.6) plugin = Threshold(0.4, fuzzy_bounds=bounds, comparison_operator="<") result = plugin(self.cube) expected_result_array = np.ones_like(self.cube.data) expected_result_array[2][2] = 0.25 self.assertArrayAlmostEqual(result.data, expected_result_array)
def test_cell_method_updates(self): """Test plugin adds correct information to cell methods""" self.cube.add_cell_method(CellMethod("max", coords="time")) plugin = Threshold(2.0, comparison_operator=">") result = plugin(self.cube) (cell_method, ) = result.cell_methods self.assertEqual(cell_method.method, "max") self.assertEqual(cell_method.coord_names, ("time", )) self.assertEqual(cell_method.comments, ("of precipitation_amount", ))
def test_threshold_negative(self): """Test a point when the threshold is negative.""" plugin = Threshold(-1.0, fuzzy_factor=self.fuzzy_factor, below_thresh_ok=True) result = plugin.process(self.cube) expected_result_array = np.ones_like(self.cube.data).reshape( 1, 1, 5, 5) self.assertArrayAlmostEqual(result.data, expected_result_array)
def test_threshold_asymmetric_bounds_middle(self): """Test when a point is on the threshold with asymmetric fuzzy bounds.""" bounds = (0.4, 0.9) plugin = Threshold(0.5, fuzzy_bounds=bounds) result = plugin(self.cube) expected_result_array = np.zeros_like(self.cube.data) expected_result_array[2][2] = 0.5 self.assertArrayAlmostEqual(result.data, expected_result_array)
def test_threshold_below_fuzzy(self): """Test a point in fuzzy threshold in below-threshold-mode.""" plugin = Threshold( 0.6, fuzzy_factor=self.fuzzy_factor, comparison_operator='<') result = plugin(self.cube) expected_result_array = np.ones_like(self.cube.data).reshape(( 1, 1, 5, 5)) expected_result_array[0][0][2][2] = 2.0/3.0 self.assertArrayAlmostEqual(result.data, expected_result_array)
def test_threshold_asymmetric_bounds_above(self): """Test when a point is above asymmetric fuzzy threshold area.""" bounds = (0.0, 0.45) plugin = Threshold(0.4, fuzzy_bounds=bounds) result = plugin(self.cube) expected_result_array = np.zeros_like(self.cube.data).reshape(( 1, 1, 5, 5)) expected_result_array[0][0][2][2] = 1. self.assertArrayAlmostEqual(result.data, expected_result_array)
def test_threshold_boundingzero_above(self): """Test fuzzy threshold of zero where data are above upper-bound.""" bounds = (-0.1, 0.1) plugin = Threshold(0.0, fuzzy_bounds=bounds) result = plugin(self.cube) expected_result_array = np.full_like( self.cube.data, fill_value=0.5).reshape((1, 1, 5, 5)) expected_result_array[0][0][2][2] = 1. self.assertArrayAlmostEqual(result.data, expected_result_array)
def test_threshold_boundingbelowzero(self): """Test fuzzy threshold of below-zero.""" bounds = (-1.0, 1.0) plugin = Threshold(0.0, fuzzy_bounds=bounds, comparison_operator='<') result = plugin(self.cube) expected_result_array = np.full_like( self.cube.data, fill_value=0.5).reshape((1, 1, 5, 5)) expected_result_array[0][0][2][2] = 0.25 self.assertArrayAlmostEqual(result.data, expected_result_array)
def test_above_threshold_without_fuzzy_factor(self): """Test if the fixed threshold is below the value in the data.""" # Copy the cube as the cube.data is used as the basis for comparison. cube = self.cube.copy() plugin = Threshold(0.1) result = plugin(cube) expected_result_array = self.cube.data.reshape((1, 1, 5, 5)) expected_result_array[0][0][2][2] = 1.0 self.assertArrayAlmostEqual(result.data, expected_result_array)
def test_threshold_fuzzybounds(self): """Test when a point is in the fuzzy threshold area.""" bounds = (0.6 * self.fuzzy_factor, 0.6 * (2. - self.fuzzy_factor)) plugin = Threshold(0.6, fuzzy_bounds=bounds) result = plugin(self.cube) expected_result_array = np.zeros_like(self.cube.data).reshape(( 1, 1, 5, 5)) expected_result_array[0][0][2][2] = 1.0/3.0 self.assertArrayAlmostEqual(result.data, expected_result_array)
def test_threshold_point_nan(self): """Test behaviour for a single NaN grid cell.""" # Need to copy the cube as we're adjusting the data. self.cube.data[0][2][2] = np.NAN msg = "NaN detected in input cube data" plugin = Threshold( 2.0, fuzzy_factor=self.fuzzy_factor, comparison_operator='<') with self.assertRaisesRegex(ValueError, msg): plugin(self.cube)
def test_invalid_lower_bound(self): """Test when fuzzy_bounds do not bound threshold (invalid).""" threshold = 0.6 fuzzy_bounds = (0.7, 0.8) # Note that back-slashes are necessary to make regexp literal. msg = "Threshold must be within bounds: " r"\!\( {} <= {} <= {} \)".format( fuzzy_bounds[0], threshold, fuzzy_bounds[1]) with self.assertRaisesRegex(ValueError, msg): Threshold(threshold, fuzzy_bounds=fuzzy_bounds)
def test_invalid_bounds_toomany(self): """Test when fuzzy_bounds contains three values (invalid).""" threshold = 0.6 fuzzy_bounds = (0.4, 0.8, 1.2) # Regexp matches .* with any string. msg = ("Invalid bounds for one threshold: .*. " "Expected 2 floats.") with self.assertRaisesRegex(ValueError, msg): Threshold(threshold, fuzzy_bounds=fuzzy_bounds)
def test_threshold_below_fuzzy_miss(self): """Test not meeting the threshold in fuzzy below-threshold-mode.""" plugin = Threshold(2.0, fuzzy_factor=self.fuzzy_factor, below_thresh_ok=True) result = plugin.process(self.cube) expected_result_array = np.ones_like(self.cube.data).reshape( 1, 1, 5, 5) self.assertArrayAlmostEqual(result.data, expected_result_array)
def test_masked_array(self): """Test masked array are handled correctly. Masked values are preserved following thresholding.""" plugin = Threshold(0.1) result = plugin(self.masked_cube) expected_result_array = np.zeros_like(self.masked_cube.data) expected_result_array[2][2] = 1.0 self.assertArrayAlmostEqual(result.data.data, expected_result_array) self.assertArrayEqual(result.data.mask, self.masked_cube.data.mask)
def test_threshold_asymmetric_bounds_upper(self): """Test when a point is in upper asymmetric fuzzy threshold area.""" bounds = (0.0, 0.6) plugin = Threshold(0.4, fuzzy_bounds=bounds) result = plugin.process(self.cube) expected_result_array = np.zeros_like(self.cube.data).reshape( 1, 1, 5, 5) expected_result_array[0][0][2][2] = 0.75 self.assertArrayAlmostEqual(result.data, expected_result_array)
def test_threshold_below_fuzzy(self): """Test a point in fuzzy threshold in below-threshold-mode.""" plugin = Threshold( 0.6, fuzzy_factor=self.fuzzy_factor, below_thresh_ok=True) result = plugin.process(self.cube) expected_result_array = np.ones_like(self.cube.data).reshape( 1, 1, 5, 5) expected_result_array[0][0][2][2] = 2.0/3.0 self.assertArrayAlmostEqual(result.data, expected_result_array)
def test_threshold_boundingbelowzero(self): """Test fuzzy threshold of below-zero.""" bounds = (-1.0, 1.0) plugin = Threshold(0.0, fuzzy_bounds=bounds, below_thresh_ok=True) result = plugin.process(self.cube) expected_result_array = np.full_like( self.cube.data, fill_value=0.5).reshape(1, 1, 5, 5) expected_result_array[0][0][2][2] = 0.25 self.assertArrayAlmostEqual(result.data, expected_result_array)
def test_fuzzy_factor_and_fuzzy_bounds(self): """Test when fuzzy_factor and fuzzy_bounds both set (ambiguous).""" fuzzy_factor = 2.0 fuzzy_bounds = (0.4, 0.8) msg = ("Invalid combination of keywords. Cannot specify " "fuzzy_factor and fuzzy_bounds together") with self.assertRaisesRegex(ValueError, msg): Threshold(0.6, fuzzy_factor=fuzzy_factor, fuzzy_bounds=fuzzy_bounds)
def test_below_fuzzy_threshold(self): """Test that the __repr__ returns the expected string.""" threshold = [0.6] fuzzy_factor = 0.2 below_thresh_ok = True result = str(Threshold(threshold, fuzzy_factor, below_thresh_ok)) msg = ('<BasicThreshold: thresholds {}, fuzzy factor {}, ' 'below_thresh_ok: {}>'.format(threshold, fuzzy_factor, below_thresh_ok)) self.assertEqual(result, msg)
def test_threshold_negative(self): """Test a point when the threshold is negative.""" self.cube.data[0][2][2] = -0.75 plugin = Threshold( -1.0, fuzzy_factor=self.fuzzy_factor, comparison_operator='<') result = plugin(self.cube) expected_result_array = np.zeros_like(self.cube.data).reshape(( 1, 1, 5, 5)) expected_result_array[0][0][2][2] = 0.25 self.assertArrayAlmostEqual(result.data, expected_result_array)
def test_invalid_comparison_operator(self): """Test plugin throws a ValueError when comparison_operator is bad""" comparison_operator = "invalid" threshold = 0.6 msg = ( 'String "{}" does not match any known comparison_operator ' "method".format(comparison_operator) ) with self.assertRaisesRegex(ValueError, msg): Threshold(threshold, comparison_operator=comparison_operator)
def test_multiple_thresholds(self): """Test that the __repr__ returns the expected string.""" threshold = [0.6, 0.8] fuzzy_factor = None below_thresh_ok = False result = str(Threshold(threshold, fuzzy_factor, below_thresh_ok)) msg = ('<BasicThreshold: thresholds {}, fuzzy factor {}, ' 'below_thresh_ok: {}>'.format(threshold, fuzzy_factor, below_thresh_ok)) self.assertEqual(result, msg)
def test_threshold_asymmetric_bounds_upper_below(self): """Test when a point is in upper asymmetric fuzzy threshold area and below-threshold is requested.""" bounds = (0.0, 0.6) plugin = Threshold(0.4, fuzzy_bounds=bounds, below_thresh_ok=True) result = plugin.process(self.cube) expected_result_array = np.ones_like(self.cube.data).reshape( 1, 1, 5, 5) expected_result_array[0][0][2][2] = 0.25 self.assertArrayAlmostEqual(result.data, expected_result_array)
def setUp(self): """Set up a cube and plugin for testing.""" self.cube = set_up_variable_cube(np.ones((3, 3), dtype=np.float32)) self.plugin = Threshold(latitude_to_threshold) self.plugin.threshold_coord_name = self.cube.name() self.thresholds = np.array( latitude_to_threshold( self.cube.coord("latitude").points, midlatitude=1.0, tropics=3.0 ) )
def test_threshold(self): """Test the basic threshold functionality.""" # Copy the cube as the cube.data is used as the basis for comparison. cube = self.cube.copy() fuzzy_factor = 0.95 plugin = Threshold(0.1, fuzzy_factor=fuzzy_factor) result = plugin.process(cube) # The single 0.5-valued point => 1.0, so cheat by * 2.0 vs orig data. expected_result_array = (self.cube.data * 2.0).reshape(1, 1, 5, 5) self.assertArrayAlmostEqual(result.data, expected_result_array)
def test_each_threshold_func(self): """Test user supplied func is applied on each threshold cube.""" # Need to copy the cube as we're adjusting the data. new_attr = {"new_attribute": "narwhal"} plugin = Threshold( 2.0, each_threshold_func=lambda cube: cube.attributes.update(new_attr) or cube, ) result = plugin(self.cube) self.assertTrue("new_attribute" in result.attributes)
def test_threshold_unit_conversion(self): """Test data are correctly thresholded when the threshold is given in units different from that of the input cube. In this test two thresholds (of 4 and 6 mm/h) are used on a 5x5 cube where the central data point value is 1.39e-6 m/s (~ 5 mm/h).""" expected_result_array = np.zeros((2, 5, 5)) expected_result_array[0][2][2] = 1. plugin = Threshold([4.0, 6.0], threshold_units='mm h-1') result = plugin.process(self.rate_cube) self.assertArrayAlmostEqual(result.data, expected_result_array)
def test_threshold_negative(self): """Repeat the test with negative numbers when the threshold is negative.""" expected_result_array = np.zeros_like(self.cube.data) expected_result_array[2:-2][:] = 1 self.cube.data = 0 - self.cube.data plugin = Threshold( lambda lat: latitude_to_threshold(lat, midlatitude=-1e-6, tropics=-1.0) ) result = plugin(self.cube) self.assertArrayAlmostEqual(result.data, expected_result_array)