def test_inverse_order_false(self): """ Test setting of inverse_order flag using percentiles_cube. In this case the flag should be false as the values associated with the percentiles increase in the same direction as the percentiles.""" plugin_instance = ProbabilitiesFromPercentiles2D( self.test_cube, 'new_name') self.assertFalse(plugin_instance.inverse_ordering)
def setUp(self): """ Set up class instance and orography cube """ percentiles_cube = set_up_percentiles_cube() self.plugin_instance = ProbabilitiesFromPercentiles2D( percentiles_cube, 'new_name') self.reference_cube = percentiles_cube[0] self.orography_cube = set_up_threshold_cube()
def process(percentiles_cube, threshold_cube, output_diagnostic_name): """Calculates probability from a percentiled field. Plugin generates probabilities at a fixed threshold (height) from a set of (height) percentiles. Args: percentiles_cube (iris.cube.Cube): The percentiled field from which probabilities will be obtained using the input cube. This cube should contain a percentiles dimension, with fields of values that correspond to these percentiles. The cube passed to the process method will contain values of the same diagnostic. threshold_cube (iris.cube.Cube): A cube of values that effectively behave as thresholds, for which it is desired to obtain probability values from a percentiled reference cube. output_diagnostic_name (str): The name of the cube being created, e.g 'probability_of_snow_falling_level_below_ground_level' Returns: iris.cube.Cube: A cube of probabilities obtained by interpolating between percentile values at the "threshold" level. """ result = ProbabilitiesFromPercentiles2D(percentiles_cube, output_diagnostic_name) probability_cube = result.process(threshold_cube) return probability_cube
def test_preservation_of_dimensions(self): """Test that if the pecentiles_cube has other dimension coordinates over which slicing is performed, that these dimensions are properly restored in the resulting probability cube.""" percentiles_cube = set_up_percentiles_cube() test_data = np.array([percentiles_cube.data, percentiles_cube.data]) percentiles = percentiles_cube.coord('percentiles') grid_x = percentiles_cube.coord('projection_x_coordinate') grid_y = percentiles_cube.coord('projection_y_coordinate') new_model_coord = build_coordinate([0, 1], long_name='leading_coord', coord_type=DimCoord, data_type=int) input_cube = iris.cube.Cube( test_data, long_name="snow_level", units="m", dim_coords_and_dims=[(new_model_coord, 0), (percentiles, 1), (grid_y, 2), (grid_x, 3)]) plugin_instance = ProbabilitiesFromPercentiles2D( input_cube, 'new_name') probability_cube = plugin_instance.process(self.orography_cube) self.assertEqual(input_cube.coords(dim_coords=True)[0], probability_cube.coords(dim_coords=True)[0])
def test_inverse_order_true(self): """ Test setting of inverse_order flag using percentiles_cube. In this case the flag should be true as the values associated with the percentiles increase in the opposite direction to the percentiles.""" percentiles_cube = self.test_cube.copy(data=np.flipud(self.test_cube.data)) plugin_instance = ProbabilitiesFromPercentiles2D(percentiles_cube, "new_name") self.assertTrue(plugin_instance.inverse_ordering)
def test_single_percentile(self): """Test for sensible behaviour when a percentiles_cube containing a single percentile is passed into the plugin.""" percentiles_cube = set_up_percentiles_cube() percentiles_cube = percentiles_cube[0] msg = "Percentile coordinate has only one value. Interpolation" with self.assertRaisesRegex(ValueError, msg): ProbabilitiesFromPercentiles2D(percentiles_cube, 'new_name')
def test_values(self): """Test that interpolated probabilities at given topography heights are sensible. Includes out-of-range values (P=0 and P=1).""" expected = set_reference_probabilities() probability_cube = ProbabilitiesFromPercentiles2D( self.percentiles_cube, 'new_name').percentile_interpolation( self.orography_cube, self.percentiles_cube) self.assertArrayAlmostEqual(probability_cube.data, expected)
def test_attributes_inverse_ordering(self): """Test relative_to_threshold attribute is suitable for the inverse_ordering case, when it should be 'above'.""" self.percentiles_cube.data = np.flipud(self.percentiles_cube.data) plugin_instance = ProbabilitiesFromPercentiles2D(self.percentiles_cube, self.new_name) result = plugin_instance.create_probability_cube(self.percentiles_cube, self.orography_cube) self.assertEqual(result.attributes['relative_to_threshold'], 'above')
def setUp(self): """ Set up a percentiles cube, plugin instance and orography cube """ self.percentiles_cube = set_up_percentiles_cube() self.percentile_coordinate = find_percentile_coordinate( self.percentiles_cube) self.new_name = "probability" self.plugin_instance = ProbabilitiesFromPercentiles2D( self.percentiles_cube, self.new_name) self.orography_cube = set_up_threshold_cube()
def test_basic(self): """ Compare __repr__ string with expectation """ new_name = "probability_of_snowfall" test_cube = set_up_percentiles_cube() inverse_ordering = False expected = ("<ProbabilitiesFromPercentiles2D: percentiles_" "cube: {}, output_name: {}, inverse_ordering: {}".format( test_cube, new_name, inverse_ordering)) result = str(ProbabilitiesFromPercentiles2D(test_cube, new_name)) self.assertEqual(result, expected)
def process( percentiles_cube: cli.inputcube, threshold_cube: cli.inputcube, *, output_diagnostic_name, ): r"""Probability from a percentiled field at a 2D threshold level. Probabilities are generated at a fixed threshold (height) from a set of (height) percentiles. E.g. for 2D percentile levels at different heights, calculate probability that height is at ground level, where the threshold cube contains a 2D topography field. Example:: Snow-fall level: Reference field: Percentiled snow fall level (m ASL) Other field: Orography (m ASL) 300m ----------------- 30th Percentile snow fall level 200m ----_------------ 20th Percentile snow fall level 100m ---/-\----------- 10th Percentile snow fall level 000m --/---\---------- 0th Percentile snow fall level ______/ \_________ Orogaphy The orography heights are compared against the heights that correspond with percentile values to find the band in which they fall, then interpolated linearly to obtain a probability at / below the ground surface. Args: percentiles_cube (iris.cube.Cube): The percentiled field from which probabilities will be obtained using the input cube. This cube should contain a percentiles dimension, with fields of values that correspond to these percentiles. The cube passed to the process method will contain values of the same diagnostic. threshold_cube (iris.cube.Cube): A cube of values that effectively behave as thresholds, for which it is desired to obtain probability values from a percentiled reference cube. output_diagnostic_name (str): The name of the cube being created, e.g 'probability_of_snow_falling_level_below_ground_level' Returns: iris.cube.Cube: A cube of probabilities obtained by interpolating between percentile values at the "threshold" level. """ from improver.utilities.statistical_operations import ProbabilitiesFromPercentiles2D probability_cube = ProbabilitiesFromPercentiles2D( percentiles_cube, output_diagnostic_name)(threshold_cube) return probability_cube
def test_equal_percentiles(self): """Test for sensible behaviour when some percentile levels are equal.""" self.percentiles_cube.data[0, :, :].fill(300.) expected = set_reference_probabilities() expected[np.where(expected < 0.25)] = 0. probability_cube = ProbabilitiesFromPercentiles2D( self.percentiles_cube, 'new_name').percentile_interpolation( self.orography_cube, self.percentiles_cube) self.assertArrayAlmostEqual(probability_cube.data, expected)
def main(argv=None): r""" Load arguments and run ProbabilitiesFromPercentiles plugin. Plugin generates probabilities at a fixed threshold (height) from a set of (height) percentiles. Example: Snow-fall level:: Reference field: Percentiled snow fall level (m ASL) Other field: Orography (m ASL) 300m ----------------- 30th Percentile snow fall level 200m ----_------------ 20th Percentile snow fall level 100m ---/-\----------- 10th Percentile snow fall level 000m --/---\---------- 0th Percentile snow fall level ______/ \_________ Orogaphy The orography heights are compared against the heights that correspond with percentile values to find the band in which they fall, then interpolated linearly to obtain a probability of snow level at / below the ground surface. """ parser = ArgParser( description="Calculate probability from a percentiled field at a " "2D threshold level. Eg for 2D percentile levels at different " "heights, calculate probability that height is at ground level, where" " the threshold file contains a 2D topography field.") parser.add_argument("percentiles_filepath", metavar="PERCENTILES_FILE", help="A path to an input NetCDF file containing a " "percentiled field") parser.add_argument("threshold_filepath", metavar="THRESHOLD_FILE", help="A path to an input NetCDF file containing a " "threshold value at which probabilities should be " "calculated.") parser.add_argument("output_filepath", metavar="OUTPUT_FILE", help="The output path for the processed NetCDF") parser.add_argument("output_diagnostic_name", metavar="OUTPUT_DIAGNOSTIC_NAME", type=str, help="Name for data in output file e.g. " "probability_of_snow_falling_level_below_ground_level") args = parser.parse_args(args=argv) threshold_cube = load_cube(args.threshold_filepath) percentiles_cube = load_cube(args.percentiles_filepath) result = ProbabilitiesFromPercentiles2D(percentiles_cube, args.output_diagnostic_name) probability_cube = result.process(threshold_cube) save_netcdf(probability_cube, args.output_filepath)
def test_all_equal_percentiles(self): """Test for sensible behaviour when all percentile levels are equal at some points.""" self.percentiles_cube.data[:, :, 0:2].fill(300.) expected = set_reference_probabilities() expected[0:2, 0:2] = 0 expected[2:, 0:2] = 1 probability_cube = ProbabilitiesFromPercentiles2D( self.percentiles_cube, 'new_name').percentile_interpolation( self.orography_cube, self.percentiles_cube) self.assertArrayAlmostEqual(probability_cube.data, expected)
def test_equal_percentiles_inverse_ordering(self): """Test for sensible behaviour when some percentile levels are equal in the case of inverse ordering (as described above).""" self.percentiles_cube.data[0, :, :].fill(300.) # Invert the values associated with the percentiles. self.percentiles_cube.data = np.flipud(self.percentiles_cube.data) expected = set_reference_probabilities() expected[np.where(expected <= 0.25)] = 0. expected = 1.0 - expected probability_cube = ProbabilitiesFromPercentiles2D( self.percentiles_cube, 'new_name').percentile_interpolation( self.orography_cube, self.percentiles_cube) self.assertArrayAlmostEqual(probability_cube.data, expected)
def test_preservation_of_single_valued_dimension(self): """Test that if the pecentiles_cube has a single value dimension coordinate over which slicing is performed, that this coordinate is restored as a dimension coordinate in the resulting probability cube.""" percentiles_cube = set_up_percentiles_cube() new_model_coord = DimCoord([0], units="1", long_name="leading_coord") percentiles_cube.add_aux_coord(new_model_coord) percentiles_cube = iris.util.new_axis(percentiles_cube, scalar_coord="leading_coord") plugin_instance = ProbabilitiesFromPercentiles2D( percentiles_cube, "new_name") probability_cube = plugin_instance.process(self.orography_cube) self.assertEqual( percentiles_cube.coords(dim_coords=True)[0], probability_cube.coords(dim_coords=True)[0], )
def test_values_inverse_ordering(self): """Test that interpolated probabilities at given topography heights are sensible when we use the inverse_ordering set to True. This is for situations in which the values associated with the percentiles increase in the opposite direction, e.g. 0 % = 100m, 20% = 50m, etc. In this situation we expect the lowest points to have a probability of 1, and the highest points to have probabilities of 0. The probabilities between should be the inverse of what is found in the usual case.""" # Invert the values associated with the percentiles. self.percentiles_cube.data = np.flipud(self.percentiles_cube.data) expected = set_reference_probabilities() expected = 1.0 - expected probability_cube = ProbabilitiesFromPercentiles2D( self.percentiles_cube, 'new_name').percentile_interpolation( self.orography_cube, self.percentiles_cube) self.assertArrayAlmostEqual(probability_cube.data, expected)
def test_basic(self): """ Test setting of a custom name """ plugin_instance = ProbabilitiesFromPercentiles2D(self.test_cube, self.new_name) self.assertEqual(plugin_instance.output_name, self.new_name)
def test_naming(self): """ Test default naming """ plugin_instance = ProbabilitiesFromPercentiles2D(self.test_cube) self.assertEqual(plugin_instance.output_name, "probability_of_{}".format(self.test_cube.name()))