def test_basic(self): """Test that the __repr__ returns the expected string.""" result = str(FallingSnowLevel()) msg = ('<FallingSnowLevel: ' 'precision:0.005, falling_level_threshold:90.0,' ' grid_point_radius: 2>') self.assertEqual(result, msg)
def test_basic(self): """Test we find the correct gradient and intercepts for simple case""" plugin = FallingSnowLevel() gradients, intercepts = plugin.linear_wet_bulb_fit( self.wet_bulb_temperature, self.heights, self.sea_points) self.assertArrayAlmostEqual(self.expected_gradients, gradients) self.assertArrayAlmostEqual(self.expected_intercepts, intercepts)
def test_basic(self): """Test it fills in the points it's meant to.""" plugin = FallingSnowLevel() plugin.fill_in_sea_points(self.snow_falling_level, self.land_sea, self.max_wb_integral, self.wet_bulb_temperature, self.heights) self.assertArrayAlmostEqual(self.snow_falling_level.data, self.expected_snow_falling_level)
def test_basic(self): """Test method returns an array with correct data""" plugin = FallingSnowLevel() expected = np.array([[10.0, 7.5], [25.0, 20.5]]) result = plugin.find_falling_level(self.wb_int_data, self.orog_data, self.height_points) self.assertIsInstance(result, np.ndarray) self.assertArrayEqual(result, expected)
def test_outside_range(self): """Test method returns an nan if data outside range""" plugin = FallingSnowLevel() wb_int_data = self.wb_int_data wb_int_data[2, 1, 1] = 70.0 result = plugin.find_falling_level(wb_int_data, self.orog_data, self.height_points) self.assertTrue(np.isnan(result[1, 1]))
def test_land_points(self): """Test it returns arrays of zeros if points are land.""" plugin = FallingSnowLevel() sea_points = np.ones((3, 3)) * False gradients, intercepts = plugin.linear_wet_bulb_fit( self.wet_bulb_temperature, self.heights, sea_points) self.assertArrayAlmostEqual(np.zeros((3, 3)), gradients) self.assertArrayAlmostEqual(np.zeros((3, 3)), intercepts)
def test_no_sea(self): """Test it only fills in sea points, and ignores a land point""" plugin = FallingSnowLevel() expected = np.ones((3, 3)) * np.nan land_sea = np.ones((3, 3)) plugin.fill_in_sea_points(self.snow_falling_level, land_sea, self.max_wb_integral, self.wet_bulb_temperature, self.heights) self.assertArrayAlmostEqual(self.snow_falling_level.data, expected)
def setUp(self): """ Set up arrays for testing.""" self.snow_level_data = np.array([[1.0, 1.0, 2.0], [1.0, np.nan, 2.0], [1.0, 2.0, 2.0]]) self.orog_data = np.array([[6.0, 6.0, 6.0], [6.0, 7.0, 6.0], [6.0, 6.0, 6.0]]) self.max_in_nbhood_orog = np.array([[7.0, 7.0, 7.0], [7.0, 7.0, 7.0], [7.0, 7.0, 7.0]]) self.plugin = FallingSnowLevel()
def test_basic(self): """Test we fill in the correct snow falling levels for a simple case""" plugin = FallingSnowLevel() plugin.find_extrapolated_falling_level( self.max_wb_integral, self.gradients, self.intercepts, self.snow_falling_level, self.sea_points) self.assertArrayAlmostEqual(self.expected_snow_falling_level, self.snow_falling_level)
def test_basic(self): """Test fills in missing data with orography + highest height""" plugin = FallingSnowLevel() self.highest_wb_int[1, 1] = 100.0 expected = np.array([[1.0, 1.0, 2.0], [1.0, 301.0, 2.0], [1.0, 2.0, 2.0]]) plugin.fill_in_high_snow_falling_levels(self.snow_level_data, self.orog, self.highest_wb_int, self.highest_height) self.assertArrayEqual(self.snow_level_data, expected)
def test_basic(self): """Test that process returns a cube with the right name and units.""" result = FallingSnowLevel().process( self.temperature_cube, self.relative_humidity_cube, self.pressure_cube, self.orog) expected = np.ones((2, 3, 3)) * 66.88732723 self.assertIsInstance(result, iris.cube.Cube) self.assertEqual(result.name(), "falling_snow_level_asl") self.assertEqual(result.units, Unit('m')) self.assertArrayAlmostEqual(result.data, expected)
def test_gradients_zero(self): """Test we do nothing if all gradients are zero""" plugin = FallingSnowLevel() gradients = np.zeros((3, 3)) plugin.find_extrapolated_falling_level( self.max_wb_integral, gradients, self.intercepts, self.snow_falling_level, self.sea_points) expected_snow_falling_level = np.ones((3, 3))*np.nan self.assertArrayAlmostEqual(expected_snow_falling_level, self.snow_falling_level)
def test_no_fill_if_conditions_not_met(self): """Test it doesn't fill in NaN if the heighest wet bulb integral value is less than the threshold.""" plugin = FallingSnowLevel() expected = np.array([[1.0, 1.0, 2.0], [1.0, np.nan, 2.0], [1.0, 2.0, 2.0]]) plugin.fill_in_high_snow_falling_levels(self.snow_level_data, self.orog, self.highest_wb_int, self.highest_height) self.assertArrayEqual(self.snow_level_data, expected)
def test_basic(self): """Test method returns an array with correct data""" plugin = FallingSnowLevel() expected = np.array([[1.0, 1.0, 2.0], [1.0, 1.5, 2.0], [1.0, 2.0, 2.0]]) result = plugin.fill_in_missing_data(self.snow_level_data, self.orog, self.highest_wb_int, self.highest_height) self.assertIsInstance(result, np.ndarray) self.assertArrayEqual(result, expected)
def test_all_above_threshold(self): """Test it doesn't change points that are all above the threshold""" plugin = FallingSnowLevel() self.max_wb_integral[0, 1] = 100 self.snow_falling_level[0, 1] = 100 self.expected_snow_falling_level[0, 1] = 100 plugin.fill_in_sea_points(self.snow_falling_level, self.land_sea, self.max_wb_integral, self.wet_bulb_temperature, self.heights) self.assertArrayAlmostEqual(self.snow_falling_level.data, self.expected_snow_falling_level)
def test_freezing_points(self): """Test with integral below threshold sets snow level to missing_value where the data can not be interpolated from other points and points are not a sea-level points.""" plugin = FallingSnowLevel() expected = np.array([[-300.0, -300.0, -300.0], [1.0, 1.5, 2.0], [1.0, 2.0, -300.0]]) result = plugin.fill_in_missing_data(self.snow_data_no_interp, self.orog, self.highest_wb_int, self.highest_height) self.assertIsInstance(result, np.ndarray) self.assertArrayEqual(result, expected)
def test_data(self): """Test that the falling snow level process returns a cube containing the expected data when points at sea-level.""" expected = np.ones((2, 3, 3)) * 65.88732723 expected[:, 1, 1] = 0.0 orog = self.orog orog.data = orog.data * 0.0 result = FallingSnowLevel().process( self.temperature_cube, self.relative_humidity_cube, self.pressure_cube, self.orog) self.assertIsInstance(result, iris.cube.Cube) self.assertArrayAlmostEqual(result.data, expected)
def test_freezing_sealevel_point(self): """Test sea point with integral below threshold sets snow level to 0""" plugin = FallingSnowLevel() orog = self.orog orog[1, 1] = 0.0 expected = np.array([[1.0, 1.0, 2.0], [1.0, 0.0, 2.0], [1.0, 2.0, 2.0]]) result = plugin.fill_in_missing_data(self.snow_level_data, orog, self.highest_wb_int, self.highest_height) self.assertIsInstance(result, np.ndarray) self.assertArrayEqual(result, expected)
def process(temperature, relative_humidity, pressure, orog, land_sea, precision=0.005, falling_level_threshold=90.0): """Module to calculate continuous snow falling level. Calculate the wet-bulb temperature integral by firstly calculating the wet-bulb temperature from the inputs provided and then calculating the vertical integral of the wet-bulb temperature. Find the falling_snow_level by finding the height above sea level corresponding to the falling_level_threshold in the integral data. Args: temperature (iris.cube.Cube): Cube of air temperature at heights (m) at the points for which the continuous falling snow level is being calculated. relative_humidity (iris.cube.Cube): Cube of relative humidities at heights (m) at the points for which the continuous falling snow level is being calculated. pressure (iris.cube.Cube): Cube of air pressure at heights (m) at the points for which the continuous falling snow level is being calculated. orog (iris.cube.Cube): Cube of the orography height in m of the terrain over which the continuous falling snow level is being calculated. land_sea (iris.cube.Cube): Cube containing the binary land-sea mask for the points for which the continuous falling snow level is being calculated. Land points are set to 1, sea points are set to 0. precision (float): Precision to which the wet-bulb temperature is required: This is used by the Newton iteration. Default is 0.005. falling_level_threshold (float): Cutoff threshold for the wet-bulb integral used to calculate the falling snow level. This threshold indicates the level at which falling snow is deemed to have melted to become rain. Default is 90.0. Returns: iris.cube.Cube: Processed Cube of falling snow level above sea level. """ result = FallingSnowLevel( precision=precision, falling_level_threshold=falling_level_threshold).process( temperature, relative_humidity, pressure, orog, land_sea) return result
def test_nonfreezing_points(self): """Test with integral above threshold sets snow level to highest_level plus orograpy where the data can not be interpolated from other points and points are not sea-level points.""" plugin = FallingSnowLevel() highest_wb_int = self.highest_wb_int * 100.0 expected = np.array([[301.0, 301.0, 301.0], [1.0, 1.5, 2.0], [1.0, 2.0, 301.0]]) result = plugin.fill_in_missing_data(self.snow_data_no_interp, self.orog, highest_wb_int, self.highest_height) self.assertIsInstance(result, np.ndarray) self.assertArrayEqual(result, expected)
def test_data(self): """Test that the falling snow level process returns a cube containing the expected data when points at sea-level.""" expected = np.ones((2, 3, 3), dtype=np.float32) * 65.88566 orog = self.orog orog.data = orog.data * 0.0 orog.data[1, 1] = 100.0 land_sea = self.land_sea land_sea = land_sea * 0.0 result = FallingSnowLevel().process(self.temperature_cube, self.relative_humidity_cube, self.pressure_cube, orog, land_sea) self.assertIsInstance(result, iris.cube.Cube) self.assertArrayAlmostEqual(result.data, expected)
def main(argv=None): """Load in arguments and get going.""" parser = ArgParser( description="Calculate the continuous falling snow level ") parser.add_argument("temperature", metavar="TEMPERATURE", help="Path to a NetCDF file of air temperatures at" " heights (m) at the points for which the continuous " "falling snow level is being calculated.") parser.add_argument("relative_humidity", metavar="RELATIVE_HUMIDITY", help="Path to a NetCDF file of relative_humidities at" " heights (m) at the points for which the continuous " "falling snow level is being calculated.") parser.add_argument("pressure", metavar="PRESSURE", help="Path to a NetCDF file of air pressures at" " heights (m) at the points for which the continuous " "falling snow level is being calculated.") parser.add_argument("orography", metavar="OROGRAPHY", help="Path to a NetCDF file containing " "the orography height in m of the terrain " "over which the continuous falling snow level is " "being calculated.") parser.add_argument("land_sea_mask", metavar="LAND_SEA_MASK", help="Path to a NetCDF file containing " "the binary land-sea mask for the points " "for which the continuous falling snow level is " "being calculated. Land points are set to 1, sea " "points are set to 0.") parser.add_argument("output_filepath", metavar="OUTPUT_FILE", help="The output path for the processed NetCDF") parser.add_argument("--precision", metavar="NEWTON_PRECISION", default=0.005, type=float, help="Precision to which the wet bulb temperature " "is required: This is used by the Newton iteration " "default value is 0.005") parser.add_argument("--falling_level_threshold", metavar="FALLING_LEVEL_THRESHOLD", default=90.0, type=float, help=("Cutoff threshold for the wet-bulb integral used" " to calculate the falling snow level. This " "threshold indicates the level at which falling " "snow is deemed to have melted to become rain. " "The default value is 90.0, an empirically " "derived value.")) args = parser.parse_args(args=argv) temperature = load_cube(args.temperature, no_lazy_load=True) relative_humidity = load_cube(args.relative_humidity, no_lazy_load=True) pressure = load_cube(args.pressure, no_lazy_load=True) orog = load_cube(args.orography, no_lazy_load=True) land_sea = load_cube(args.land_sea_mask, no_lazy_load=True) result = FallingSnowLevel( precision=args.precision, falling_level_threshold=args.falling_level_threshold).process( temperature, relative_humidity, pressure, orog, land_sea) save_netcdf(result, args.output_filepath)
def test_basic(self): """Test the function does what it's meant to in a simple case.""" plugin = FallingSnowLevel(grid_point_radius=1) result = plugin.find_max_in_nbhood_orography(self.cube) self.assertArrayAlmostEqual(result.data, self.expected_data)