def test_returns_correct_cube_and_coord(self): """Test it returns the correct Cube and Coord.""" plugin = WindGustDiagnostic(self.wg_perc, self.ws_perc) result, perc_coord = (plugin.extract_percentile_data( self.cube_wg, self.wg_perc, "wind_speed_of_gust")) self.assertEqual(perc_coord.name(), "percentile") self.assertEqual(result.coord("percentile").points, [self.wg_perc])
def test_updated_metadata(self): """Test that the metadata is set as expected """ plugin = WindGustDiagnostic(50.0, 80.0) result = plugin.update_metadata_after_max(self.cube, self.perc_coord) msg = 'Expected to find exactly 1 .* coordinate, but found none.' with self.assertRaisesRegex(CoordinateNotFoundError, msg): result.coord(self.perc_coord)
def test_fails_if_req_percentile_not_in_cube(self): """Test it raises a Value Error if req_perc not in cube.""" plugin = WindGustDiagnostic(self.wg_perc, self.ws_perc) msg = ('Could not find required percentile') with self.assertRaisesRegex(ValueError, msg): plugin.extract_percentile_data(self.cube_wg, 20.0, "wind_speed_of_gust")
def test_metadata(self): """Test that the metadata is set as expected """ plugin = WindGustDiagnostic(50.0, 80.0) result = plugin.add_metadata(self.cube_wg) self.assertEqual(result.standard_name, "wind_speed_of_gust") msg = "<WindGustDiagnostic: wind-gust perc=50.0, " "wind-speed perc=80.0>" self.assertEqual(result.attributes["wind_gust_diagnostic"], msg)
def test_basic(self): """Test that the function returns a Cube and Coord.""" plugin = WindGustDiagnostic(self.wg_perc, self.ws_perc) result, perc_coord = (plugin.extract_percentile_data( self.cube_wg, self.wg_perc, "wind_speed_of_gust")) self.assertIsInstance(result, Cube) self.assertIsInstance(perc_coord, iris.coords.Coord)
def test_raises_error_points_mismatch_and_no_bounds(self): """Test raises Value Error if points mismatch and no bounds """ cube_wg = self.cube_wg cube_wg.coord('time').points = [402192.5, 402194.5] plugin = WindGustDiagnostic(self.wg_perc, self.ws_perc) msg = ('Could not match time coordinate') with self.assertRaisesRegex(ValueError, msg): plugin.process(cube_wg, self.cube_ws)
def test_fails_if_data_is_not_cube(self): """Test it raises a Type Error if cube is not a cube.""" plugin = WindGustDiagnostic(self.wg_perc, self.ws_perc) msg = ('Expecting wind_speed_of_gust data to be an instance of ' 'iris.cube.Cube but is' ' {0}.'.format(type(self.wg_perc))) with self.assertRaisesRegex(TypeError, msg): plugin.extract_percentile_data(self.wg_perc, self.wg_perc, "wind_speed_of_gust")
def test_raises_error_for_no_time_coord(self): """Test raises Value Error if cubes have no time coordinate """ cube_wg = self.cube_wg[:, 0, ::] cube_ws = self.cube_ws[:, 0, ::] cube_wg.remove_coord('time') cube_wg = iris.util.squeeze(cube_wg) plugin = WindGustDiagnostic(self.wg_perc, self.ws_perc) msg = ('Could not match time coordinate') with self.assertRaisesRegex(ValueError, msg): plugin.process(cube_wg, cube_ws)
def test_raises_error_points_mismatch_and_bounds(self): """Test raises Value Error if both points and bounds mismatch """ cube_wg = self.cube_wg cube_wg.coord('time').points = [402192.0, 402193.0] cube_wg.coord('time').bounds = [[402191.0, 402192.0], [402192.0, 402193.0]] plugin = WindGustDiagnostic(self.wg_perc, self.ws_perc) msg = ('Could not match time coordinate') with self.assertRaisesRegex(ValueError, msg): plugin.process(cube_wg, self.cube_ws)
def test_no_raises_error_if_ws_point_in_bounds(self): """Test raises no Value Error if wind-speed point in bounds """ cube_wg = self.cube_wg cube_wg.coord('time').points = [402192.0, 402193.0] cube_wg.coord('time').bounds = [[402191.5, 402192.5], [402192.5, 402193.5]] plugin = WindGustDiagnostic(self.wg_perc, self.ws_perc) result = plugin.process(cube_wg, self.cube_ws) self.assertIsInstance(result, Cube)
def test_returns_wind_gust_diagnostic(self): """Test that the plugin returns a Cube. """ plugin = WindGustDiagnostic(self.wg_perc, self.ws_perc) result = plugin.process(self.cube_wg, self.cube_ws) expected_data = np.zeros((2, 2, 2)) expected_data[0, :, :] = 3.0 expected_data[1, :, :] = 2.0 self.assertArrayAlmostEqual(result.data, expected_data) self.assertEqual(result.attributes['wind_gust_diagnostic'], 'Typical gusts')
def test_warning_if_standard_names_do_not_match(self, warning_list=None): """Test it raises a warning if standard names do not match.""" plugin = WindGustDiagnostic(self.wg_perc, self.ws_perc) warning_msg = ('Warning mismatching name for data expecting') result, perc_coord = (plugin.extract_percentile_data( self.cube_wg, self.wg_perc, "wind_speed")) self.assertTrue( any(item.category == UserWarning for item in warning_list)) self.assertTrue(any(warning_msg in str(item) for item in warning_list)) self.assertIsInstance(result, Cube) self.assertIsInstance(perc_coord, iris.coords.Coord)
def process( wind_gust: cli.inputcube, wind_speed: cli.inputcube, *, wind_gust_percentile: float = 50.0, wind_speed_percentile: float = 95.0, ): """Create a cube containing the wind_gust diagnostic. Calculate revised wind-gust data using a specified percentile of wind-gust data and a specified percentile of wind-speed data through the WindGustDiagnostic plugin. The wind-gust diagnostic will be the max of the specified percentile data. Args: wind_gust (iris.cube.Cube): Cube containing one or more percentiles of wind_gust data. wind_speed (iris.cube.Cube): Cube containing one or more percentiles of wind_speed data. wind_gust_percentile (float): Percentile value required from wind-gust cube. wind_speed_percentile (float): Percentile value required from wind-speed cube. Returns: iris.cube.Cube: Cube containing the wind-gust diagnostic data. """ from improver.wind_calculations.wind_gust_diagnostic import WindGustDiagnostic result = WindGustDiagnostic(wind_gust_percentile, wind_speed_percentile)(wind_gust, wind_speed) return result
def process(gust_cube, speed_cube, percentile_gust, percentile_speed): """Create a cube containing the wind_gust diagnostic. Calculate revised wind-gust data using a specified percentiles of wind-gust data and a specified percentile of wind-speed data through the WindGustDiagnostic plugin. The wind-gust diagnostic will be the max of the specified percentile data. Args: gust_cube (iris.cube.Cube): Cube containing one or more percentiles of wind_gust data. speed_cube (iris.cube.Cube): Cube containing one or more percentiles of wind_speed data. percentile_gust (float): Percentile value required from wind-gust cube. percentile_speed (float): Percentile value required from wind-speed cube. Returns: result (iris.cube.Cube): Cube containing the wind-gust diagnostic data. """ result = (WindGustDiagnostic(percentile_gust, percentile_speed).process( gust_cube, speed_cube)) return result
def test_raises_error_for_mismatching_perc_coords(self): """Test raises an error for mismatching perc coords. """ plugin = WindGustDiagnostic(self.wg_perc, self.ws_perc) data_wg = np.zeros((1, 2, 2, 2)) data_wg[0, 0, :, :] = 3.0 data_wg[0, 1, :, :] = 1.5 gust = "wind_speed_of_gust" cube_wg = (create_cube_with_percentile_coord( data=data_wg, perc_values=[self.wg_perc], standard_name=gust, perc_name='percentile_dummy')) msg = ('Percentile coord of wind-gust data' 'does not match coord of wind-speed data') with self.assertRaisesRegex(ValueError, msg): plugin.process(cube_wg, self.cube_ws)
def test_raises_error_for_mismatching_perc_coords(self): """Test raises an error for mismatching perc coords. """ plugin = WindGustDiagnostic(self.wg_perc, self.ws_perc) self.cube_wg.coord("percentile").rename("percentile_dummy") msg = ("Percentile coord of wind-gust data" "does not match coord of wind-speed data") with self.assertRaisesRegex(ValueError, msg): plugin(self.cube_wg, self.cube_ws)
def test_raises_error_points_mismatch_and_no_bounds(self): """Test raises Value Error if points mismatch and no bounds """ # offset times by half an hour (in seconds) self.cube_wg.coord("time").points = self.cube_wg.coord("time").points + 30 * 60 plugin = WindGustDiagnostic(self.wg_perc, self.ws_perc) msg = "Could not match time coordinate" with self.assertRaisesRegex(ValueError, msg): plugin(self.cube_wg, self.cube_ws)
def main(argv=None): """Load in arguments for wind-gust diagnostic. Wind-gust and Wind-speed data should be supplied along with the required percentile value. The wind-gust diagnostic will be the Max of the specified percentile data. Currently * Typical gusts is MAX(wind-gust(50th percentile),wind-speed(95th percentile)) * Extreme gust is MAX(wind-gust(95th percentile),wind-speed(100th percentile)) If no percentile values are supplied the code defaults to values for Typical gusts. """ parser = ArgParser( description="Calculate revised wind-gust data using a specified " "percentile of wind-gust data and a specified percentile " "of wind-speed data through the WindGustDiagnostic plugin. " "The wind-gust diagnostic will be the Max of the specified " "percentile data." "Currently Typical gusts is " "MAX(wind-gust(50th percentile),wind-speed(95th percentile))" "and Extreme gust is " "MAX(wind-gust(95th percentile),wind-speed(100th percentile)). " "If no percentile values are supplied the code defaults " "to values for Typical gusts.") parser.add_argument("input_filegust", metavar="INPUT_FILE_GUST", help="A path to an input Wind Gust Percentile" " NetCDF file") parser.add_argument("input_filews", metavar="INPUT_FILE_WINDSPEED", help="A path to an input Wind Speed Percentile" " NetCDF file") parser.add_argument("output_filepath", metavar="OUTPUT_FILE", help="The output path for the processed NetCDF") parser.add_argument("--percentile_gust", metavar="PERCENTILE_GUST", default="50.0", help="Percentile of wind-gust required." " Default=50.0", type=float) parser.add_argument("--percentile_ws", metavar="PERCENTILE_WIND_SPEED", default="95.0", help="Percentile of wind-speed required." " Default=95.0", type=float) args = parser.parse_args(args=argv) cube_wg = load_cube(args.input_filegust) cube_ws = load_cube(args.input_filews) result = (WindGustDiagnostic(args.percentile_gust, args.percentile_ws).process(cube_wg, cube_ws)) save_netcdf(result, args.output_filepath)
def test_no_error_if_ws_point_in_bounds(self): """Test raises no Value Error if wind-speed point in bounds """ self.cube_wg.coord("time").points = self.cube_wg.coord("time").points + 30 * 60 times = self.cube_wg.coord("time").points self.cube_wg.coord("time").bounds = [ [times[0] - 3600, times[0]], [times[1] - 3600, times[1]], ] plugin = WindGustDiagnostic(self.wg_perc, self.ws_perc) result = plugin(self.cube_wg, self.cube_ws) self.assertIsInstance(result, Cube)
def test_raises_error_points_mismatch_and_bounds(self): """Test raises Value Error if both points and bounds mismatch """ # offset by 4 hours (in seconds) self.cube_wg.coord("time").points = ( self.cube_wg.coord("time").points + 4 * 60 * 60) times = self.cube_wg.coord("time").points self.cube_wg.coord("time").bounds = [ [times[0] - 3600, times[0]], [times[1] - 3600, times[1]], ] plugin = WindGustDiagnostic(self.wg_perc, self.ws_perc) msg = "Could not match time coordinate" with self.assertRaisesRegex(ValueError, msg): plugin(self.cube_wg, self.cube_ws)
def test_basic(self): """Test that the __repr__ returns the expected string.""" result = str(WindGustDiagnostic(50.0, 95.0)) msg = ('<WindGustDiagnostic: wind-gust perc=50.0, ' 'wind-speed perc=95.0>') self.assertEqual(result, msg)
def test_basic(self): """Test that the __init__ sets things up correctly""" plugin = (WindGustDiagnostic(50.0, 95.0)) self.assertEqual(plugin.percentile_gust, 50.0) self.assertEqual(plugin.percentile_windspeed, 95.0)
def test_basic(self): """Test that the function returns a Cube. """ plugin = WindGustDiagnostic(50.0, 95.0) result = plugin.add_metadata(self.cube_wg) self.assertIsInstance(result, Cube)
def test_basic(self): """Test that the plugin returns a Cube. """ plugin = WindGustDiagnostic(self.wg_perc, self.ws_perc) result = plugin.process(self.cube_wg, self.cube_ws) self.assertIsInstance(result, Cube)
def test_diagnostic_typical_txt(self): """Test that the attribute is set as expected for typical gusts""" plugin = WindGustDiagnostic(50.0, 95.0) result = plugin.add_metadata(self.cube_wg) msg = 'Typical gusts' self.assertEqual(result.attributes['wind_gust_diagnostic'], msg)
def test_diagnostic_extreme_txt(self): """Test that the attribute is set as expected for extreme gusts""" plugin = WindGustDiagnostic(95.0, 100.0) result = plugin.add_metadata(self.cube_wg) msg = 'Extreme gusts' self.assertEqual(result.attributes['wind_gust_diagnostic'], msg)
def test_basic(self): """Test that the function returns a Cube. """ plugin = WindGustDiagnostic(50.0, 95.0) result = plugin.update_metadata_after_max(self.cube, self.perc_coord) self.assertIsInstance(result, Cube)