示例#1
0
class Test_process(IrisTest):
    """Test the process method."""
    def setUp(self):
        """Set up data for testing."""
        self.plugin = GenerateTopographicZoneWeights()
        orography_data = np.array([[10.0, 25.0], [75.0, 100.0]])
        self.orography = set_up_orography_cube(orography_data)

        landmask_data = np.array([[0, 1], [1, 1]], dtype=np.float32)
        landmask = self.orography.copy(data=landmask_data)
        landmask.rename("land_binary_mask")
        landmask.units = Unit("1")
        self.landmask = landmask
        self.thresholds_dict = {"bounds": [[0, 50], [50, 200]], "units": "m"}

    def test_basic(self):
        """Test that the output is a cube with the expected format."""
        result = self.plugin.process(self.orography, self.thresholds_dict,
                                     self.landmask)
        self.assertIsInstance(result, iris.cube.Cube)
        self.assertEqual(result.name(), "topographic_zone_weights")
        self.assertEqual(result.units, Unit("1"))
        self.assertTrue(result.coord("topographic_zone"))
        self.assertEqual(result.coord("topographic_zone").units, Unit("m"))

    def test_invalid_orography(self):
        """Test that the appropriate exception is raised if the orography has
        more than two dimensions."""
        orography_data = np.array([[[0.0, 25.0], [75.0, 100.0]]])
        orography = set_up_orography_cube(orography_data)
        msg = "The input orography cube should be two-dimensional"
        with self.assertRaisesRegex(InvalidCubeError, msg):
            self.plugin.process(orography, self.thresholds_dict, self.landmask)

    def test_data(self):
        """Test that the result data and mask is as expected."""
        expected_weights_data = np.array(
            [[[1e20, 1.0], [0.33, 0.17]], [[1e20, 0.0], [0.67, 0.83]]],
            dtype=np.float32)
        expected_weights_mask = np.array([[[True, False], [False, False]],
                                          [[True, False], [False, False]]])
        result = self.plugin.process(self.orography, self.thresholds_dict,
                                     self.landmask)
        self.assertIsInstance(result, iris.cube.Cube)
        self.assertArrayAlmostEqual(result.data.data,
                                    expected_weights_data,
                                    decimal=2)
        self.assertArrayAlmostEqual(result.data.mask, expected_weights_mask)

    def test_data_no_mask(self):
        """Test that the result data is as expected, when none of the points
        are masked."""
        expected_weights_data = np.array(
            [[[1.0, 1.0], [0.33, 0.17]], [[0.0, 0.0], [0.67, 0.83]]],
            dtype=np.float32)
        landmask_data = np.array([[1, 1], [1, 1]])
        landmask = self.landmask.copy(landmask_data)
        result = self.plugin.process(self.orography, self.thresholds_dict,
                                     landmask)
        self.assertIsInstance(result, iris.cube.Cube)
        self.assertArrayAlmostEqual(result.data,
                                    expected_weights_data,
                                    decimal=2)

    def test_data_no_mask_input(self):
        """Test that the result data is as expected, when no landsea
           mask is input."""
        expected_weights_data = np.array(
            [[[1.0, 1.0], [0.33, 0.17]], [[0.0, 0.0], [0.67, 0.83]]],
            dtype=np.float32)
        result = self.plugin.process(self.orography, self.thresholds_dict)
        self.assertIsInstance(result, iris.cube.Cube)
        self.assertArrayAlmostEqual(result.data,
                                    expected_weights_data,
                                    decimal=2)

    def test_data_no_mask_input_metatdata(self):
        """Test that the result metadata is as expected, when no landsea
           mask is input."""
        result = self.plugin.process(self.orography, self.thresholds_dict)
        self.assertIsInstance(result, iris.cube.Cube)
        self.assertEqual(
            result.attributes["topographic_zones_include_seapoints"], "True")

    def test_data_no_mask_three_bands(self):
        """Test that the result data is as expected, when none of the points
        are masked and there are three bands defined."""
        orography_data = np.array([[10.0, 40.0, 45.0], [70.0, 80.0, 95.0],
                                   [115.0, 135.0, 145.0]])
        orography = set_up_orography_cube(orography_data)

        landmask_data = np.array([[1, 1, 1], [1, 1, 1], [1, 1, 1]])
        landmask = orography.copy(data=landmask_data)
        landmask.rename("land_binary_mask")
        landmask.units = Unit("1")

        thresholds_dict = {
            "bounds": [[0, 50], [50, 100], [100, 150]],
            "units": "m"
        }
        expected_weights_data = np.array([
            [[1.0, 0.7, 0.6], [0.1, 0.0, 0.0], [0.0, 0.0, 0.0]],
            [[0.0, 0.3, 0.4], [0.9, 0.9, 0.6], [0.2, 0.0, 0.0]],
            [[0.0, 0.0, 0.0], [0.0, 0.1, 0.4], [0.8, 1.0, 1.0]],
        ])
        result = self.plugin.process(orography, thresholds_dict, landmask)
        self.assertIsInstance(result, iris.cube.Cube)
        self.assertArrayAlmostEqual(result.data,
                                    expected_weights_data,
                                    decimal=2)

    def test_different_band_units(self):
        """Test for if the thresholds are specified in a different unit to
        the orography. The thresholds are converted to match the units of the
        orography."""
        expected_weights_data = np.array(
            [[[1e20, 1.0], [0.333, 0.167]], [[1e20, 0.0], [0.67, 0.83]]],
            dtype=np.float32,
        )
        expected_weights_mask = np.array([[[True, False], [False, False]],
                                          [[True, False], [False, False]]])
        thresholds_dict = {"bounds": [[0, 0.05], [0.05, 0.2]], "units": "km"}
        result = self.plugin.process(self.orography, thresholds_dict,
                                     self.landmask)
        self.assertIsInstance(result, iris.cube.Cube)
        self.assertArrayAlmostEqual(result.data.data,
                                    expected_weights_data,
                                    decimal=2)
        self.assertArrayAlmostEqual(result.data.mask, expected_weights_mask)

    def test_one_band_with_orography_in_band(self):
        """Test that if only one band is specified, the results are as
        expected."""
        expected_weights_data = np.array([[1e20, 1.0], [1.0, 1.0]],
                                         dtype=np.float32)
        expected_weights_mask = np.array([[True, False], [False, False]])
        orography_data = np.array([[10.0, 20.0], [30.0, 40.0]],
                                  dtype=np.float32)
        orography = self.orography.copy(data=orography_data)
        thresholds_dict = {"bounds": [[0, 50]], "units": "m"}
        result = self.plugin.process(orography, thresholds_dict, self.landmask)
        self.assertIsInstance(result, iris.cube.Cube)
        self.assertArrayAlmostEqual(result.data.data,
                                    expected_weights_data,
                                    decimal=2)
        self.assertArrayAlmostEqual(result.data.mask, expected_weights_mask)

    @ManageWarnings(record=True)
    def test_warning_if_orography_above_bands(self, warning_list=None):
        """Test that a warning is raised if the orography is greater than the
        maximum band."""
        orography_data = np.array([[60.0, 70.0], [80.0, 90.0]])
        orography = self.orography.copy(data=orography_data)
        thresholds_dict = {"bounds": [[0, 50]], "units": "m"}
        msg = "The maximum orography is greater than the uppermost band"
        self.plugin.process(orography, thresholds_dict, self.landmask)
        self.assertTrue(
            any(item.category == UserWarning for item in warning_list))
        self.assertTrue(any(msg in str(item) for item in warning_list))

    @ManageWarnings(record=True)
    def test_warning_if_orography_below_bands(self, warning_list=None):
        """Test that a warning is raised if the orography is lower than the
        minimum band."""
        orography_data = np.array([[60.0, 70.0], [80.0, 90.0]])
        orography = self.orography.copy(data=orography_data)
        thresholds_dict = {"bounds": [[100, 150]], "units": "m"}
        msg = "The minimum orography is lower than the lowest band"
        self.plugin.process(orography, thresholds_dict, self.landmask)
        self.assertTrue(
            any(item.category == UserWarning for item in warning_list))
        self.assertTrue(any(msg in str(item) for item in warning_list))
class Test_process(IrisTest):
    """Test the process method."""
    def setUp(self):
        """Set up data for testing."""
        self.plugin = GenerateTopographicZoneWeights()
        orography_data = np.array([[[[10., 25.], [75., 100.]]]])
        orography = set_up_cube(orography_data,
                                "altitude",
                                "m",
                                realizations=np.array([0]),
                                y_dimension_length=2,
                                x_dimension_length=2)
        orography = orography[0, 0, ...]
        orography.remove_coord("realization")
        orography.remove_coord("time")
        self.orography = orography

        landmask_data = np.array([[0, 1], [1, 1]])
        landmask = orography.copy(data=landmask_data)
        landmask.rename("land_binary_mask")
        landmask.units = Unit("1")
        self.landmask = landmask
        self.thresholds_dict = {
            'land': {
                'bounds': [[0, 50], [50, 200]],
                'units': 'm'
            }
        }

    def test_basic(self):
        """Test that the output is a cube with the expected format."""
        result = self.plugin.process(self.orography, self.landmask,
                                     self.thresholds_dict)
        self.assertIsInstance(result, iris.cube.Cube)
        self.assertEqual(result.name(), "topographic_zone_weights")
        self.assertEqual(result.units, Unit("1"))
        self.assertTrue(result.coord("topographic_zone"))
        self.assertEqual(result.coord("topographic_zone").units, Unit("m"))

    def test_invalid_orography(self):
        """Test that the appropriate exception is raised if the orography has
        more than two dimensions."""
        orography_data = np.array([[[[0., 25.], [75., 100.]]]])
        orography = set_up_cube(orography_data,
                                "altitude",
                                "m",
                                realizations=np.array([0]),
                                y_dimension_length=2,
                                x_dimension_length=2)
        msg = "The input orography cube should be two-dimensional"
        with self.assertRaisesRegexp(InvalidCubeError, msg):
            self.plugin.process(orography, self.landmask, self.thresholds_dict)

    def test_invalid_bands(self):
        """Test for if the thresholds_dict has an invalid key."""
        thresholds_dict = {
            'invalid': {
                'bounds': [[0, 50], [50, 200]],
                'units': 'm'
            }
        }
        msg = "'land'"
        with self.assertRaisesRegexp(KeyError, msg):
            self.plugin.process(self.orography, self.landmask, thresholds_dict)

    def test_data(self):
        """Test that the result data and mask is as expected."""
        expected_weights_data = np.array([[[1e20, 1.0], [0.33, 0.17]],
                                          [[1e20, 0.0], [0.67, 0.83]]])
        expected_weights_mask = np.array([[[True, False], [False, False]],
                                          [[True, False], [False, False]]])
        result = self.plugin.process(self.orography, self.landmask,
                                     self.thresholds_dict)
        self.assertIsInstance(result, iris.cube.Cube)
        self.assertArrayAlmostEqual(result.data.data,
                                    expected_weights_data,
                                    decimal=2)
        self.assertArrayAlmostEqual(result.data.mask, expected_weights_mask)

    def test_data_no_mask(self):
        """Test that the result data is as expected, when none of the points
        are masked."""
        expected_weights_data = np.array([[[1.0, 1.0], [0.33, 0.17]],
                                          [[0.0, 0.0], [0.67, 0.83]]])
        landmask_data = np.array([[1, 1], [1, 1]])
        landmask = self.landmask.copy(landmask_data)
        result = self.plugin.process(self.orography, landmask,
                                     self.thresholds_dict)
        self.assertIsInstance(result, iris.cube.Cube)
        self.assertArrayAlmostEqual(result.data,
                                    expected_weights_data,
                                    decimal=2)

    def test_data_no_mask_three_bands(self):
        """Test that the result data is as expected, when none of the points
        are masked and there are three bands defined."""
        orography_data = np.array([[[[10., 40., 45.], [70., 80., 95.],
                                     [115., 135., 145.]]]])
        orography = set_up_cube(orography_data,
                                "altitude",
                                "m",
                                realizations=np.array([0]),
                                y_dimension_length=3,
                                x_dimension_length=3)
        orography = orography[0, 0, ...]
        orography.remove_coord("realization")
        orography.remove_coord("time")

        landmask_data = np.array([[1, 1, 1], [1, 1, 1], [1, 1, 1]])
        landmask = orography.copy(data=landmask_data)
        landmask.rename("land_binary_mask")
        landmask.units = Unit("1")

        thresholds_dict = {
            'land': {
                'bounds': [[0, 50], [50, 100], [100, 150]],
                'units': 'm'
            }
        }
        expected_weights_data = np.array([[[1.0, 0.7, 0.6], [0.1, 0.0, 0.0],
                                           [0.0, 0.0, 0.0]],
                                          [[0.0, 0.3, 0.4], [0.9, 0.9, 0.6],
                                           [0.2, 0.0, 0.0]],
                                          [[0.0, 0.0, 0.0], [0.0, 0.1, 0.4],
                                           [0.8, 1.0, 1.0]]])
        result = self.plugin.process(orography, landmask, thresholds_dict)
        self.assertIsInstance(result, iris.cube.Cube)
        self.assertArrayAlmostEqual(result.data,
                                    expected_weights_data,
                                    decimal=2)

    def test_different_band_units(self):
        """Test for if the thresholds are specified in a different unit to
        the orography. The thresholds are converted to match the units of the
        orography."""
        expected_weights_data = np.array([[[1e20, 1.0], [0.33, 0.17]],
                                          [[1e20, 0.0], [0.67, 0.83]]])
        expected_weights_mask = np.array([[[True, False], [False, False]],
                                          [[True, False], [False, False]]])
        thresholds_dict = {
            'land': {
                'bounds': [[0, 0.05], [0.05, 0.2]],
                'units': 'km'
            }
        }
        result = self.plugin.process(self.orography, self.landmask,
                                     thresholds_dict)
        self.assertIsInstance(result, iris.cube.Cube)
        self.assertArrayAlmostEqual(result.data.data,
                                    expected_weights_data,
                                    decimal=2)
        self.assertArrayAlmostEqual(result.data.mask, expected_weights_mask)

    def test_one_band_with_orography_in_band(self):
        """Test that if only one band is specified, the results are as
        expected."""
        expected_weights_data = np.array([[1e20, 1.0], [1.0, 1.0]])
        expected_weights_mask = np.array([[True, False], [False, False]])
        orography_data = np.array([[10., 20.], [30., 40.]])
        orography = self.orography.copy(data=orography_data)
        thresholds_dict = {'land': {'bounds': [[0, 50]], 'units': 'm'}}
        result = self.plugin.process(orography, self.landmask, thresholds_dict)
        self.assertIsInstance(result, iris.cube.Cube)
        self.assertArrayAlmostEqual(result.data.data,
                                    expected_weights_data,
                                    decimal=2)
        self.assertArrayAlmostEqual(result.data.mask, expected_weights_mask)

    def test_warning_if_orography_above_bands(self):
        """Test that a warning is raised if the orography is greater than the
        maximum band."""
        orography_data = np.array([[60., 70.], [80., 90.]])
        orography = self.orography.copy(data=orography_data)
        thresholds_dict = {'land': {'bounds': [[0, 50]], 'units': 'm'}}
        msg = "The maximum orography is greater than the uppermost band"
        with warnings.catch_warnings(record=True) as warning_list:
            self.plugin.process(orography, self.landmask, thresholds_dict)
            self.assertTrue(
                any(item.category == UserWarning for item in warning_list))
            self.assertTrue(any(msg in str(item) for item in warning_list))

    def test_warning_if_orography_below_bands(self):
        """Test that a warning is raised if the orography is lower than the
        minimum band."""
        orography_data = np.array([[60., 70.], [80., 90.]])
        orography = self.orography.copy(data=orography_data)
        thresholds_dict = {'land': {'bounds': [[100, 150]], 'units': 'm'}}
        msg = "The minimum orography is lower than the lowest band"
        with warnings.catch_warnings(record=True) as warning_list:
            self.plugin.process(orography, self.landmask, thresholds_dict)
            self.assertTrue(
                any(item.category == UserWarning for item in warning_list))
            self.assertTrue(any(msg in str(item) for item in warning_list))