class Test_process(IrisTest):
    """Tests the process method"""

    def setUp(self):
        """Create dummy cubes for tests"""
        self.plugin = ResolveWindComponents()
        wind_speed_data = np.array(
            [[6, 5, 4, 3], [8, 6, 4, 4], [12, 8, 6, 5]], dtype=np.float32
        )
        self.wind_speed_cube = set_up_cube(wind_speed_data, "wind_speed", "knots")

        wind_direction_data = np.array(
            [[138, 142, 141, 141], [141, 143, 140, 142], [142, 146, 141, 142]],
            dtype=np.float32,
        )
        self.wind_direction_cube = set_up_cube(
            wind_direction_data, "wind_to_direction", "degrees"
        )

        self.expected_u = np.array(
            [
                [3.804214, 2.917800, 2.410297, 1.822455],
                [4.711193, 3.395639, 2.454748, 2.365005],
                [6.844465, 4.144803, 3.580219, 2.943424],
            ],
            dtype=np.float32,
        )

        self.expected_v = np.array(
            [
                [-4.639823, -4.060351, -3.1922507, -2.382994],
                [-6.465651, -4.946681, -3.1581972, -3.225949],
                [-9.856638, -6.842559, -4.8147717, -4.041813],
            ],
            dtype=np.float32,
        )

    def test_basic(self):
        """Test plugin creates two output cubes with the correct metadata"""
        ucube, vcube = self.plugin.process(
            self.wind_speed_cube, self.wind_direction_cube
        )
        for cube in ucube, vcube:
            self.assertIsInstance(cube, iris.cube.Cube)
            self.assertEqual(cube.units, self.wind_speed_cube.units)
        self.assertEqual(ucube.name(), "grid_eastward_wind")
        self.assertEqual(vcube.name(), "grid_northward_wind")

    def test_values(self):
        """Test plugin generates expected wind values"""
        ucube, vcube = self.plugin.process(
            self.wind_speed_cube, self.wind_direction_cube
        )
        self.assertArrayAlmostEqual(ucube.data, self.expected_u, decimal=5)
        self.assertArrayAlmostEqual(vcube.data, self.expected_v, decimal=5)

    def test_coordinate_value_mismatch(self):
        """Test an error is raised if coordinate values are different for wind
        speed and direction cubes"""
        self.wind_direction_cube.coord(axis="y").convert_units("km")
        msg = "Wind speed and direction cubes have unmatched coordinates"
        with self.assertRaisesRegex(ValueError, msg):
            _, _ = self.plugin.process(self.wind_speed_cube, self.wind_direction_cube)

    def test_projection_mismatch(self):
        """Test an error is raised if coordinate names are different for wind
        speed and direction cubes"""
        self.wind_speed_cube.coord(axis="x").rename("longitude")
        self.wind_speed_cube.coord(axis="y").rename("latitude")
        msg = "Wind speed and direction cubes have unmatched coordinates"
        with self.assertRaisesRegex(ValueError, msg):
            _, _ = self.plugin.process(self.wind_speed_cube, self.wind_direction_cube)

    def test_height_levels(self):
        """Test a cube on more than one height level is correctly processed"""
        wind_speed_3d = add_new_dimension(self.wind_speed_cube, 3, "height", "km")
        wind_direction_3d = add_new_dimension(
            self.wind_direction_cube, 3, "height", "km"
        )
        ucube, vcube = self.plugin.process(wind_speed_3d, wind_direction_3d)
        self.assertSequenceEqual(ucube.shape, (3, 3, 4))
        self.assertArrayAlmostEqual(ucube[1].data, self.expected_u, decimal=5)
        self.assertArrayAlmostEqual(vcube[2].data, self.expected_v, decimal=5)

    def test_wind_from_direction(self):
        """Test correct behaviour when wind direction is 'from' not 'to'.
        We do not get perfect direction inversion to the 7th decimal place here
        because we ignore imprecision in the iris rotate_winds calcuation near
        the corners of the domain, and regrid the available data linearly to
        fill the gap.  The output wind speeds (in m s-1) compare equal to the
        5th decimal place.
        """
        expected_u = -1.0 * self.expected_u
        expected_v = -1.0 * self.expected_v
        self.wind_direction_cube.rename("wind_from_direction")
        ucube, vcube = self.plugin.process(
            self.wind_speed_cube, self.wind_direction_cube
        )
        self.assertArrayAllClose(ucube.data, expected_u, atol=1e-5)
        self.assertArrayAllClose(vcube.data, expected_v, atol=1e-5)
Exemple #2
0
class Test_process(IrisTest):
    """Tests the process method"""
    def setUp(self):
        """Create dummy cubes for tests"""
        self.plugin = ResolveWindComponents()
        wind_speed_data = np.array([[6, 5, 4, 3], [8, 6, 4, 4], [12, 8, 6, 5]],
                                   dtype=np.float32)
        self.wind_speed_cube = set_up_cube(wind_speed_data, "wind_speed",
                                           "knots")

        wind_direction_data = np.array(
            [[138, 142, 141, 141], [141, 143, 140, 142], [142, 146, 141, 142]],
            dtype=np.float32)
        self.wind_direction_cube = set_up_cube(wind_direction_data,
                                               "wind_to_direction", "degrees")

        self.expected_u = np.array([[3.774919, 2.902824, 2.406847, 1.826062],
                                    [4.683339, 3.386423, 2.456537, 2.374629],
                                    [6.829466, 4.149148, 3.593584, 2.963243]],
                                   dtype=np.float32)

        self.expected_v = np.array(
            [[-4.663688, -4.071071, -3.194854, -2.380230],
             [-6.485857, -4.952993, -3.156806, -3.218872],
             [-9.867035, -6.839924, -4.804805, -4.027306]],
            dtype=np.float32)

    def test_basic(self):
        """Test plugin creates two output cubes with the correct metadata"""
        ucube, vcube = self.plugin.process(self.wind_speed_cube,
                                           self.wind_direction_cube)
        for cube in ucube, vcube:
            self.assertIsInstance(cube, iris.cube.Cube)
            self.assertEqual(cube.units, self.wind_speed_cube.units)
        self.assertEqual(ucube.name(), "grid_eastward_wind")
        self.assertEqual(vcube.name(), "grid_northward_wind")

    def test_values(self):
        """Test plugin generates expected wind values"""
        ucube, vcube = self.plugin.process(self.wind_speed_cube,
                                           self.wind_direction_cube)
        self.assertArrayAlmostEqual(ucube.data, self.expected_u)
        self.assertArrayAlmostEqual(vcube.data, self.expected_v)

    def test_coordinate_value_mismatch(self):
        """Test an error is raised if coordinate values are different for wind
        speed and direction cubes"""
        self.wind_direction_cube.coord(axis='y').convert_units("km")
        msg = 'Wind speed and direction cubes have unmatched coordinates'
        with self.assertRaisesRegex(ValueError, msg):
            _, _ = self.plugin.process(self.wind_speed_cube,
                                       self.wind_direction_cube)

    def test_projection_mismatch(self):
        """Test an error is raised if coordinate names are different for wind
        speed and direction cubes"""
        self.wind_speed_cube.coord(axis='x').rename('longitude')
        self.wind_speed_cube.coord(axis='y').rename('latitude')
        msg = 'Wind speed and direction cubes have unmatched coordinates'
        with self.assertRaisesRegex(ValueError, msg):
            _, _ = self.plugin.process(self.wind_speed_cube,
                                       self.wind_direction_cube)

    def test_height_levels(self):
        """Test a cube on more than one height level is correctly processed"""
        wind_speed_3d = add_new_dimension(self.wind_speed_cube, 3, "height",
                                          "km")
        wind_direction_3d = add_new_dimension(self.wind_direction_cube, 3,
                                              "height", "km")
        ucube, vcube = self.plugin.process(wind_speed_3d, wind_direction_3d)
        self.assertSequenceEqual(ucube.shape, (3, 3, 4))
        self.assertArrayAlmostEqual(ucube[1].data, self.expected_u)
        self.assertArrayAlmostEqual(vcube[2].data, self.expected_v)

    def test_wind_from_direction(self):
        """Test correct behaviour when wind direction is 'from' not 'to'.
        We do not get perfect direction inversion to the 7th decimal place here
        because we ignore imprecision in the iris rotate_winds calcuation near
        the corners of the domain, and regrid the available data linearly to
        fill the gap.  The output wind speeds (in m s-1) compare equal to the
        5th decimal place.
        """
        expected_u = -1. * self.expected_u
        expected_v = -1. * self.expected_v
        self.wind_direction_cube.rename("wind_from_direction")
        ucube, vcube = self.plugin.process(self.wind_speed_cube,
                                           self.wind_direction_cube)
        self.assertTrue(np.allclose(ucube.data, expected_u, atol=1e-6))
        self.assertTrue(np.allclose(vcube.data, expected_v, atol=1e-6))