示例#1
0
 def test_different_coord_systems(self):
     u, v = uv_cubes()
     v.coord("grid_latitude").coord_system = iris.coord_systems.GeogCS(1)
     with self.assertRaisesRegex(
         ValueError, "Coordinates differ between u and v cubes"
     ):
         rotate_winds(u, v, iris.coord_systems.OSGB())
示例#2
0
 def test_rotated_to_unrotated(self):
     # Check ability to use 2d coords as input.
     u, v = uv_cubes()
     ut, vt = rotate_winds(u, v, iris.coord_systems.GeogCS(6371229))
     # Remove  grid lat and lon, leaving 2d projection coords.
     ut.remove_coord('grid_latitude')
     vt.remove_coord('grid_latitude')
     ut.remove_coord('grid_longitude')
     vt.remove_coord('grid_longitude')
     # Change back.
     orig_cs = u.coord('grid_latitude').coord_system
     res_u, res_v = rotate_winds(ut, vt, orig_cs)
     # Check data values - limited accuracy due to numerical approx.
     self.assertArrayAlmostEqual(res_u.data, u.data, decimal=3)
     self.assertArrayAlmostEqual(res_v.data, v.data, decimal=3)
     # Check coords locations.
     x2d, y2d = np.meshgrid(u.coord('grid_longitude').points,
                            u.coord('grid_latitude').points)
     # Shift longitude from 0 to 360 -> -180 to 180.
     x2d = np.where(x2d > 180, x2d - 360, x2d)
     res_x = res_u.coord('projection_x_coordinate',
                         coord_system=orig_cs).points
     res_y = res_u.coord('projection_y_coordinate',
                         coord_system=orig_cs).points
     self.assertArrayAlmostEqual(res_x, x2d)
     self.assertArrayAlmostEqual(res_y, y2d)
     res_x = res_v.coord('projection_x_coordinate',
                         coord_system=orig_cs).points
     res_y = res_v.coord('projection_y_coordinate',
                         coord_system=orig_cs).points
     self.assertArrayAlmostEqual(res_x, x2d)
     self.assertArrayAlmostEqual(res_y, y2d)
示例#3
0
 def test_rotated_to_unrotated(self):
     # Check ability to use 2d coords as input.
     u, v = uv_cubes()
     ut, vt = rotate_winds(u, v, iris.coord_systems.GeogCS(6371229))
     # Remove  grid lat and lon, leaving 2d projection coords.
     ut.remove_coord("grid_latitude")
     vt.remove_coord("grid_latitude")
     ut.remove_coord("grid_longitude")
     vt.remove_coord("grid_longitude")
     # Change back.
     orig_cs = u.coord("grid_latitude").coord_system
     res_u, res_v = rotate_winds(ut, vt, orig_cs)
     # Check data values - limited accuracy due to numerical approx.
     self.assertArrayAlmostEqual(res_u.data, u.data, decimal=3)
     self.assertArrayAlmostEqual(res_v.data, v.data, decimal=3)
     # Check coords locations.
     x2d, y2d = np.meshgrid(
         u.coord("grid_longitude").points,
         u.coord("grid_latitude").points)
     # Shift longitude from 0 to 360 -> -180 to 180.
     x2d = np.where(x2d > 180, x2d - 360, x2d)
     res_x = res_u.coord("projection_x_coordinate",
                         coord_system=orig_cs).points
     res_y = res_u.coord("projection_y_coordinate",
                         coord_system=orig_cs).points
     self.assertArrayAlmostEqual(res_x, x2d)
     self.assertArrayAlmostEqual(res_y, y2d)
     res_x = res_v.coord("projection_x_coordinate",
                         coord_system=orig_cs).points
     res_y = res_v.coord("projection_y_coordinate",
                         coord_system=orig_cs).points
     self.assertArrayAlmostEqual(res_x, x2d)
     self.assertArrayAlmostEqual(res_y, y2d)
示例#4
0
 def test_dim_mapping(self):
     x = np.linspace(311.9, 391.1, 3)
     y = np.linspace(-23.6, 24.8, 3)
     u, v = uv_cubes(x, y)
     v.transpose()
     with self.assertRaisesRegex(ValueError, "Dimension mapping"):
         rotate_winds(u, v, iris.coord_systems.OSGB())
示例#5
0
 def test_dim_mapping(self):
     x = np.linspace(311.9, 391.1, 3)
     y = np.linspace(-23.6, 24.8, 3)
     u, v = uv_cubes(x, y)
     v.transpose()
     with self.assertRaisesRegexp(ValueError, 'Dimension mapping'):
         rotate_winds(u, v, iris.coord_systems.OSGB())
示例#6
0
 def test_different_shape(self):
     x = np.linspace(311.9, 391.1, 6)
     y = np.linspace(-23.6, 24.8, 5)
     u, _ = uv_cubes(x, y)
     _, v = uv_cubes(x[:-1], y)
     with self.assertRaisesRegexp(ValueError, 'same shape'):
         rotate_winds(u, v, iris.coord_systems.OSGB())
示例#7
0
 def test_different_shape(self):
     x = np.linspace(311.9, 391.1, 6)
     y = np.linspace(-23.6, 24.8, 5)
     u, _ = uv_cubes(x, y)
     _, v = uv_cubes(x[:-1], y)
     with self.assertRaisesRegex(ValueError, "same shape"):
         rotate_winds(u, v, iris.coord_systems.OSGB())
 def test_different_xy_coord_systems(self):
     u, v = uv_cubes()
     u.coord('grid_latitude').coord_system = iris.coord_systems.GeogCS(1)
     v.coord('grid_latitude').coord_system = iris.coord_systems.GeogCS(1)
     with self.assertRaisesRegexp(
             ValueError,
             'Coordinate systems of x and y coordinates differ'):
         rotate_winds(u, v, iris.coord_systems.OSGB())
示例#9
0
 def test_different_xy_coord_systems(self):
     u, v = uv_cubes()
     u.coord('grid_latitude').coord_system = iris.coord_systems.GeogCS(1)
     v.coord('grid_latitude').coord_system = iris.coord_systems.GeogCS(1)
     with self.assertRaisesRegexp(
             ValueError,
             'Coordinate systems of x and y coordinates differ'):
         rotate_winds(u, v, iris.coord_systems.OSGB())
示例#10
0
    def test_new_coords(self):
        u, v = self._uv_cubes_limited_extent()
        x = u.coord('grid_longitude').points
        y = u.coord('grid_latitude').points
        x2d, y2d = np.meshgrid(x, y)
        src_crs = ccrs.RotatedPole(pole_longitude=177.5, pole_latitude=37.5)
        tgt_crs = ccrs.OSGB()
        xyz_tran = tgt_crs.transform_points(src_crs, x2d, y2d)

        ut, vt = rotate_winds(u, v, iris.coord_systems.OSGB())

        points = xyz_tran[..., 0].reshape(x2d.shape)
        expected_x = AuxCoord(points,
                              standard_name='projection_x_coordinate',
                              units='m',
                              coord_system=iris.coord_systems.OSGB())
        self.assertEqual(ut.coord('projection_x_coordinate'), expected_x)
        self.assertEqual(vt.coord('projection_x_coordinate'), expected_x)

        points = xyz_tran[..., 1].reshape(y2d.shape)
        expected_y = AuxCoord(points,
                              standard_name='projection_y_coordinate',
                              units='m',
                              coord_system=iris.coord_systems.OSGB())
        self.assertEqual(ut.coord('projection_y_coordinate'), expected_y)
        self.assertEqual(vt.coord('projection_y_coordinate'), expected_y)
示例#11
0
    def test_rotated_to_osgb(self):
        # Rotated Pole data with large extent.
        x = np.linspace(311.9, 391.1, 10)
        y = np.linspace(-23.6, 24.8, 8)
        u, v = uv_cubes(x, y)
        ut, vt = rotate_winds(u, v, iris.coord_systems.OSGB())

        # Ensure cells with discrepancies in magnitude are masked.
        self.assertTrue(ma.isMaskedArray(ut.data))
        self.assertTrue(ma.isMaskedArray(vt.data))

        # Snapshot of mask with fixed tolerance of atol=2e-3
        expected_mask = np.array([[1, 1, 1, 0, 0, 0, 0, 0, 0, 1],
                                  [1, 1, 1, 0, 0, 0, 0, 0, 0, 1],
                                  [1, 1, 1, 1, 0, 0, 0, 0, 1, 1],
                                  [1, 1, 1, 1, 0, 0, 0, 0, 1, 1],
                                  [1, 1, 1, 1, 0, 0, 0, 0, 1, 1],
                                  [1, 1, 1, 1, 1, 0, 0, 1, 1, 1],
                                  [1, 1, 1, 1, 1, 0, 0, 1, 1, 1],
                                  [1, 1, 1, 1, 1, 0, 0, 1, 1, 1]], np.bool)
        self.assertArrayEqual(expected_mask, ut.data.mask)
        self.assertArrayEqual(expected_mask, vt.data.mask)

        # Check unmasked values have sufficiently small error in mag.
        expected_mag = np.sqrt(u.data**2 + v.data**2)
        # Use underlying data to ignore mask in calculation.
        res_mag = np.sqrt(ut.data.data**2 + vt.data.data**2)
        # Calculate percentage error (note there are no zero magnitudes
        # so we can divide safely).
        anom = 100.0 * np.abs(res_mag - expected_mag) / expected_mag
        self.assertTrue(anom[~ut.data.mask].max() < 0.1)
示例#12
0
    def _check_rotated_to_true(self, u_rot, v_rot, target_cs, **kwds):
        # Run test calculation (numeric).
        u_true, v_true = rotate_winds(u_rot, v_rot, target_cs)

        # Perform same calculation via the reference method (equations).
        cs_rot = u_rot.coord("grid_longitude").coord_system
        pole_lat = cs_rot.grid_north_pole_latitude
        pole_lon = cs_rot.grid_north_pole_longitude
        rotated_lons = u_rot.coord("grid_longitude").points
        rotated_lats = u_rot.coord("grid_latitude").points
        rotated_lons_2d, rotated_lats_2d = np.meshgrid(rotated_lons,
                                                       rotated_lats)
        rotated_u, rotated_v = u_rot.data, v_rot.data
        u_ref, v_ref = self._unrotate_equation(
            rotated_lons_2d,
            rotated_lats_2d,
            rotated_u,
            rotated_v,
            pole_lon,
            pole_lat,
        )

        # Check that all the numerical results are within given tolerances.
        self.assertArrayAllClose(u_true.data, u_ref, **kwds)
        self.assertArrayAllClose(v_true.data, v_ref, **kwds)
示例#13
0
 def test_name(self):
     u, v = self._uv_cubes_limited_extent()
     u.rename("bob")
     v.rename("alice")
     ut, vt = rotate_winds(u, v, iris.coord_systems.OSGB())
     self.assertEqual(ut.name(), "transformed_" + u.name())
     self.assertEqual(vt.name(), "transformed_" + v.name())
示例#14
0
    def test_new_coords(self):
        u, v = self._uv_cubes_limited_extent()
        x = u.coord("grid_longitude").points
        y = u.coord("grid_latitude").points
        x2d, y2d = np.meshgrid(x, y)
        src_crs = ccrs.RotatedPole(pole_longitude=177.5, pole_latitude=37.5)
        tgt_crs = ccrs.OSGB()
        xyz_tran = tgt_crs.transform_points(src_crs, x2d, y2d)

        ut, vt = rotate_winds(u, v, iris.coord_systems.OSGB())

        points = xyz_tran[..., 0].reshape(x2d.shape)
        expected_x = AuxCoord(
            points,
            standard_name="projection_x_coordinate",
            units="m",
            coord_system=iris.coord_systems.OSGB(),
        )
        self.assertEqual(ut.coord("projection_x_coordinate"), expected_x)
        self.assertEqual(vt.coord("projection_x_coordinate"), expected_x)

        points = xyz_tran[..., 1].reshape(y2d.shape)
        expected_y = AuxCoord(
            points,
            standard_name="projection_y_coordinate",
            units="m",
            coord_system=iris.coord_systems.OSGB(),
        )
        self.assertEqual(ut.coord("projection_y_coordinate"), expected_y)
        self.assertEqual(vt.coord("projection_y_coordinate"), expected_y)
示例#15
0
 def test_orig_coords(self):
     u, v = self._uv_cubes_limited_extent()
     ut, vt = rotate_winds(u, v, iris.coord_systems.OSGB())
     self.assertEqual(u.coord('grid_latitude'), ut.coord('grid_latitude'))
     self.assertEqual(v.coord('grid_latitude'), vt.coord('grid_latitude'))
     self.assertEqual(u.coord('grid_longitude'), ut.coord('grid_longitude'))
     self.assertEqual(v.coord('grid_longitude'), vt.coord('grid_longitude'))
示例#16
0
 def test_name(self):
     u, v = self._uv_cubes_limited_extent()
     u.rename('bob')
     v.rename('alice')
     ut, vt = rotate_winds(u, v, iris.coord_systems.OSGB())
     self.assertEqual(ut.name(), 'transformed_' + u.name())
     self.assertEqual(vt.name(), 'transformed_' + v.name())
示例#17
0
    def test_xy_dimensionality(self):
        u, v = uv_cubes()
        # Replace 1d lat with 2d lat.
        x = u.coord('grid_longitude').points
        y = u.coord('grid_latitude').points
        x2d, y2d = np.meshgrid(x, y)
        lat_2d = AuxCoord(y2d, 'grid_latitude', units='degrees',
                          coord_system=u.coord('grid_latitude').coord_system)
        for cube in (u, v):
            cube.remove_coord('grid_latitude')
            cube.add_aux_coord(lat_2d.copy(), (0, 1))

        with self.assertRaisesRegexp(
                ValueError,
                'x and y coordinates must have the same number of dimensions'):
            rotate_winds(u, v, iris.coord_systems.OSGB())
示例#18
0
    def test_xy_dimensionality(self):
        u, v = uv_cubes()
        # Replace 1d lat with 2d lat.
        x = u.coord('grid_longitude').points
        y = u.coord('grid_latitude').points
        x2d, y2d = np.meshgrid(x, y)
        lat_2d = AuxCoord(y2d, 'grid_latitude', units='degrees',
                          coord_system=u.coord('grid_latitude').coord_system)
        for cube in (u, v):
            cube.remove_coord('grid_latitude')
            cube.add_aux_coord(lat_2d.copy(), (0, 1))

        with self.assertRaisesRegex(
                ValueError,
                'x and y coordinates must have the same number of dimensions'):
            rotate_winds(u, v, iris.coord_systems.OSGB())
    def test_rotated_to_osgb(self):
        # Rotated Pole data with large extent.
        x = np.linspace(311.9, 391.1, 10)
        y = np.linspace(-23.6, 24.8, 8)
        u, v = uv_cubes(x, y)
        ut, vt = rotate_winds(u, v, iris.coord_systems.OSGB())

        # Ensure cells with discrepancies in magnitude are masked.
        self.assertTrue(ma.isMaskedArray(ut.data))
        self.assertTrue(ma.isMaskedArray(vt.data))

        # Snapshot of mask with fixed tolerance of atol=2e-3
        expected_mask = np.array(
            [[1, 1, 1, 0, 0, 0, 0, 0, 0, 1], [1, 1, 1, 0, 0, 0, 0, 0, 0, 1],
             [1, 1, 1, 1, 0, 0, 0, 0, 1, 1], [1, 1, 1, 1, 0, 0, 0, 0, 1, 1],
             [1, 1, 1, 1, 0, 0, 0, 0, 1, 1], [1, 1, 1, 1, 1, 0, 0, 1, 1, 1],
             [1, 1, 1, 1, 1, 0, 0, 1, 1, 1], [1, 1, 1, 1, 1, 0, 0, 1, 1, 1]],
            np.bool)
        self.assertArrayEqual(expected_mask, ut.data.mask)
        self.assertArrayEqual(expected_mask, vt.data.mask)

        # Check unmasked values have sufficiently small error in mag.
        expected_mag = np.sqrt(u.data**2 + v.data**2)
        # Use underlying data to ignore mask in calculation.
        res_mag = np.sqrt(ut.data.data**2 + vt.data.data**2)
        # Calculate percentage error (note there are no zero magnitudes
        # so we can divide safely).
        anom = 100.0 * np.abs(res_mag - expected_mag) / expected_mag
        self.assertTrue(anom[~ut.data.mask].max() < 0.1)
示例#20
0
 def test_orig_coords(self):
     u, v = self._uv_cubes_limited_extent()
     ut, vt = rotate_winds(u, v, iris.coord_systems.OSGB())
     self.assertEqual(u.coord("grid_latitude"), ut.coord("grid_latitude"))
     self.assertEqual(v.coord("grid_latitude"), vt.coord("grid_latitude"))
     self.assertEqual(u.coord("grid_longitude"), ut.coord("grid_longitude"))
     self.assertEqual(v.coord("grid_longitude"), vt.coord("grid_longitude"))
示例#21
0
def unrotate_uv(u, v, target_cs=None, remove_aux_xy=True):
    """
    Rotate u- and v-winds to a given CS (Geog by default) and remove
    auxiliary coordinates created automatically by `rotate_winds()` function
    """
    if target_cs is None:
        target_cs = iris.coord_systems.GeogCS(EARTH_RADIUS)
    uv = rotate_winds(u, v, target_cs)
    if remove_aux_xy:
        [cube.remove_coord(i) for i in ('projection_x_coordinate',
                                        'projection_y_coordinate')
         for cube in uv]
    return uv
示例#22
0
    def test_new_coords_transposed(self):
        u, v = self._uv_cubes_limited_extent()
        # Transpose cubes so that cube is in xy order rather than the
        # typical yx order of meshgrid.
        u.transpose()
        v.transpose()
        x = u.coord("grid_longitude").points
        y = u.coord("grid_latitude").points
        x2d, y2d = np.meshgrid(x, y)
        src_crs = ccrs.RotatedPole(pole_longitude=177.5, pole_latitude=37.5)
        tgt_crs = ccrs.OSGB()
        xyz_tran = tgt_crs.transform_points(src_crs, x2d, y2d)

        ut, vt = rotate_winds(u, v, iris.coord_systems.OSGB())

        points = xyz_tran[..., 0].reshape(x2d.shape)
        expected_x = AuxCoord(
            points,
            standard_name="projection_x_coordinate",
            units="m",
            coord_system=iris.coord_systems.OSGB(),
        )
        self.assertEqual(ut.coord("projection_x_coordinate"), expected_x)
        self.assertEqual(vt.coord("projection_x_coordinate"), expected_x)

        points = xyz_tran[..., 1].reshape(y2d.shape)
        expected_y = AuxCoord(
            points,
            standard_name="projection_y_coordinate",
            units="m",
            coord_system=iris.coord_systems.OSGB(),
        )
        self.assertEqual(ut.coord("projection_y_coordinate"), expected_y)
        self.assertEqual(vt.coord("projection_y_coordinate"), expected_y)
        # Check dim mapping for 2d coords is yx.
        expected_dims = u.coord_dims("grid_latitude") + u.coord_dims(
            "grid_longitude"
        )
        self.assertEqual(
            ut.coord_dims("projection_x_coordinate"), expected_dims
        )
        self.assertEqual(
            ut.coord_dims("projection_y_coordinate"), expected_dims
        )
        self.assertEqual(
            vt.coord_dims("projection_x_coordinate"), expected_dims
        )
        self.assertEqual(
            vt.coord_dims("projection_y_coordinate"), expected_dims
        )
示例#23
0
 def test_data_values(self):
     u, v = self._uv_cubes_limited_extent()
     # Slice out 4 points that lie in and outside OSGB extent.
     u = u[1:3, 3:5]
     v = v[1:3, 3:5]
     ut, vt = rotate_winds(u, v, iris.coord_systems.OSGB())
     # Values precalculated and checked.
     expected_ut_data = np.array([[0.16285514, 0.35323639],
                                  [1.82650698, 2.62455840]])
     expected_vt_data = np.array([[19.88979966, 19.01921346],
                                  [19.88018847, 19.01424281]])
     # Compare u and v data values against previously calculated values.
     self.assertArrayAllClose(ut.data, expected_ut_data, rtol=1e-5)
     self.assertArrayAllClose(vt.data, expected_vt_data, rtol=1e-5)
示例#24
0
 def test_data_values(self):
     u, v = self._uv_cubes_limited_extent()
     # Slice out 4 points that lie in and outside OSGB extent.
     u = u[1:3, 3:5]
     v = v[1:3, 3:5]
     ut, vt = rotate_winds(u, v, iris.coord_systems.OSGB())
     # Values precalculated and checked.
     expected_ut_data = np.array([[0.16285514,  0.35323639],
                                  [1.82650698,  2.62455840]])
     expected_vt_data = np.array([[19.88979966,  19.01921346],
                                  [19.88018847,  19.01424281]])
     # Compare u and v data values against previously calculated values.
     self.assertArrayAllClose(ut.data, expected_ut_data, rtol=1e-5)
     self.assertArrayAllClose(vt.data, expected_vt_data, rtol=1e-5)
示例#25
0
def get_geographic_coordinates(u, v, x, y, cs):
    """Convert winds and positions from a rotated grid to an unrotated grid

    Args:
        u, v (np.Array): Wind fields on rotated grid
        x, y (np.Array): Trajectory longitude and latitude positions on
            rotated grid
        cs (iris.coord_systems.CoordSystem): The coordinate system of the
            rotated longitude/latitude grid

    Returns
        u_wind, v_wind (np.Array): Wind fields on unrotated grid
        lon, lat (np.Array): Trajectory positions
    """
    # Place input information in to iris cubes to perform to rotation
    rlon = AuxCoord(x, standard_name='grid_longitude', units='degrees',
                    coord_system=cs)
    rlat = AuxCoord(y, standard_name='grid_latitude', units='degrees',
                    coord_system=cs)
    u_array, v_array = [], []
    for n in range(len(u)):
        u_array.append(u)
        v_array.append(v)
    u = np.array(u_array)
    v = np.array(v_array)
    u = Cube(u, standard_name='x_wind', units='m s-1',
             aux_coords_and_dims=[(rlon, 0), (rlat, 1)])
    v = Cube(v, standard_name='y_wind', units='m s-1',
             aux_coords_and_dims=[(rlon, 0), (rlat, 1)])

    # Calculate unrotated winds and postitions
    u, v = rotate_winds(u, v, GeogCS(a))

    # Extract information from the unrotated cubes
    u_wind, v_wind, lon, lat = [], [], [], []
    lons = u.coord('projection_x_coordinate').points
    lats = u.coord('projection_y_coordinate').points
    for n in range(len(x)):
        u_wind.append(u.data[n,n])
        v_wind.append(v.data[n,n])
        lon.append(lons[n, n])
        lat.append(lats[n, n])

    u_wind = np.array(u_wind)
    v_wind = np.array(v_wind)
    lon = np.array(lon)
    lat = np.array(lat)

    return u_wind, v_wind, lon, lat
示例#26
0
 def test_nd_data(self):
     u2d, y2d = self._uv_cubes_limited_extent()
     u, v = uv_cubes_3d(u2d)
     u = u[:, 1:3, 3:5]
     v = v[:, 1:3, 3:5]
     ut, vt = rotate_winds(u, v, iris.coord_systems.OSGB())
     # Values precalculated and checked (as test_data_values above),
     # then scaled by factor [1, 2, 3] along 0th dim (see uv_cubes_3d()).
     expected_ut_data = np.array([[0.16285514, 0.35323639],
                                  [1.82650698, 2.62455840]])
     expected_vt_data = np.array([[19.88979966, 19.01921346],
                                  [19.88018847, 19.01424281]])
     factor = np.array([1, 2, 3]).reshape(3, 1, 1)
     expected_ut_data = factor * expected_ut_data
     expected_vt_data = factor * expected_vt_data
     # Compare u and v data values against previously calculated values.
     self.assertArrayAlmostEqual(ut.data, expected_ut_data)
     self.assertArrayAlmostEqual(vt.data, expected_vt_data)
示例#27
0
 def test_nd_data(self):
     u2d, y2d = self._uv_cubes_limited_extent()
     u, v = uv_cubes_3d(u2d)
     u = u[:, 1:3, 3:5]
     v = v[:, 1:3, 3:5]
     ut, vt = rotate_winds(u, v, iris.coord_systems.OSGB())
     # Values precalculated and checked (as test_data_values above),
     # then scaled by factor [1, 2, 3] along 0th dim (see uv_cubes_3d()).
     expected_ut_data = np.array([[0.16285514,  0.35323639],
                                  [1.82650698,  2.62455840]])
     expected_vt_data = np.array([[19.88979966,  19.01921346],
                                  [19.88018847,  19.01424281]])
     factor = np.array([1, 2, 3]).reshape(3, 1, 1)
     expected_ut_data = factor * expected_ut_data
     expected_vt_data = factor * expected_vt_data
     # Compare u and v data values against previously calculated values.
     self.assertArrayAlmostEqual(ut.data, expected_ut_data)
     self.assertArrayAlmostEqual(vt.data, expected_vt_data)
示例#28
0
    def test_new_coords_transposed(self):
        u, v = self._uv_cubes_limited_extent()
        # Transpose cubes so that cube is in xy order rather than the
        # typical yx order of meshgrid.
        u.transpose()
        v.transpose()
        x = u.coord('grid_longitude').points
        y = u.coord('grid_latitude').points
        x2d, y2d = np.meshgrid(x, y)
        src_crs = ccrs.RotatedPole(pole_longitude=177.5, pole_latitude=37.5)
        tgt_crs = ccrs.OSGB()
        xyz_tran = tgt_crs.transform_points(src_crs, x2d, y2d)

        ut, vt = rotate_winds(u, v, iris.coord_systems.OSGB())

        points = xyz_tran[..., 0].reshape(x2d.shape)
        expected_x = AuxCoord(points,
                              standard_name='projection_x_coordinate',
                              units='m',
                              coord_system=iris.coord_systems.OSGB())
        self.assertEqual(ut.coord('projection_x_coordinate'), expected_x)
        self.assertEqual(vt.coord('projection_x_coordinate'), expected_x)

        points = xyz_tran[..., 1].reshape(y2d.shape)
        expected_y = AuxCoord(points,
                              standard_name='projection_y_coordinate',
                              units='m',
                              coord_system=iris.coord_systems.OSGB())
        self.assertEqual(ut.coord('projection_y_coordinate'), expected_y)
        self.assertEqual(vt.coord('projection_y_coordinate'), expected_y)
        # Check dim mapping for 2d coords is yx.
        expected_dims = (u.coord_dims('grid_latitude') +
                         u.coord_dims('grid_longitude'))
        self.assertEqual(ut.coord_dims('projection_x_coordinate'),
                         expected_dims)
        self.assertEqual(ut.coord_dims('projection_y_coordinate'),
                         expected_dims)
        self.assertEqual(vt.coord_dims('projection_x_coordinate'),
                         expected_dims)
        self.assertEqual(vt.coord_dims('projection_y_coordinate'),
                         expected_dims)
示例#29
0
    def _check_rotated_to_true(self, u_rot, v_rot, target_cs, **kwds):
        # Run test calculation (numeric).
        u_true, v_true = rotate_winds(u_rot, v_rot, target_cs)

        # Perform same calculation via the reference method (equations).
        cs_rot = u_rot.coord('grid_longitude').coord_system
        pole_lat = cs_rot.grid_north_pole_latitude
        pole_lon = cs_rot.grid_north_pole_longitude
        rotated_lons = u_rot.coord('grid_longitude').points
        rotated_lats = u_rot.coord('grid_latitude').points
        rotated_lons_2d, rotated_lats_2d = np.meshgrid(
            rotated_lons, rotated_lats)
        rotated_u, rotated_v = u_rot.data, v_rot.data
        u_ref, v_ref = self._unrotate_equation(rotated_lons_2d,
                                               rotated_lats_2d,
                                               rotated_u, rotated_v,
                                               pole_lon, pole_lat)

        # Check that all the numerical results are within given tolerances.
        self.assertArrayAllClose(u_true.data, u_ref, **kwds)
        self.assertArrayAllClose(v_true.data, v_ref, **kwds)
示例#30
0
    def calc_true_north_offset(reference_cube: Cube) -> ndarray:
        """
        Calculate the angles between grid North and true North, as a
        matrix of values on the grid of the input reference cube.

        Args:
            reference_cube:
                2D cube on grid for which "north" is required.  Provides both
                coordinate system (reference_cube.coord_system()) and template
                spatial grid on which the angle adjustments should be provided.

        Returns:
            Angle in radians by which wind direction wrt true North at
            each point must be rotated to be relative to grid North.
        """
        reference_x_coord = reference_cube.coord(axis="x")
        reference_y_coord = reference_cube.coord(axis="y")

        # find corners of reference_cube grid in lat / lon coordinates
        latlon = [
            GLOBAL_CRS.as_cartopy_crs().transform_point(
                reference_x_coord.points[i],
                reference_y_coord.points[j],
                reference_cube.coord_system().as_cartopy_crs(),
            )
            for i in [0, -1]
            for j in [0, -1]
        ]
        latlon = np.array(latlon).T.tolist()

        # define lat / lon coordinates to cover the reference_cube grid at an
        # equivalent resolution
        lat_points = np.linspace(
            np.floor(min(latlon[1])),
            np.ceil(max(latlon[1])),
            len(reference_y_coord.points),
        )
        lon_points = np.linspace(
            np.floor(min(latlon[0])),
            np.ceil(max(latlon[0])),
            len(reference_x_coord.points),
        )

        lat_coord = DimCoord(
            lat_points, "latitude", units="degrees", coord_system=GLOBAL_CRS
        )
        lon_coord = DimCoord(
            lon_points, "longitude", units="degrees", coord_system=GLOBAL_CRS
        )

        # define a unit vector wind towards true North over the lat / lon grid
        udata = np.zeros(reference_cube.shape, dtype=np.float32)
        vdata = np.ones(reference_cube.shape, dtype=np.float32)

        ucube_truenorth = Cube(
            udata,
            "grid_eastward_wind",
            dim_coords_and_dims=[(lat_coord, 0), (lon_coord, 1)],
        )
        vcube_truenorth = Cube(
            vdata,
            "grid_northward_wind",
            dim_coords_and_dims=[(lat_coord, 0), (lon_coord, 1)],
        )

        # rotate unit vector onto reference_cube coordinate system
        ucube, vcube = rotate_winds(
            ucube_truenorth, vcube_truenorth, reference_cube.coord_system()
        )

        # unmask and regrid rotated winds onto reference_cube grid
        ucube.data = ucube.data.data
        ucube = ucube.regrid(reference_cube, Linear())
        vcube.data = vcube.data.data
        vcube = vcube.regrid(reference_cube, Linear())

        # ratio of u to v winds is the tangent of the angle which is the
        # true North to grid North rotation
        angle_adjustment = np.arctan2(ucube.data, vcube.data)

        return angle_adjustment
示例#31
0
 def test_rotated_to_unrotated(self):
     # Suffiently accurate so that no mask is introduced.
     u, v = uv_cubes()
     ut, vt = rotate_winds(u, v, iris.coord_systems.GeogCS(6371229))
     self.assertFalse(ma.isMaskedArray(ut.data))
     self.assertFalse(ma.isMaskedArray(vt.data))
示例#32
0
 def test_magnitude_preservation(self):
     u, v = self._uv_cubes_limited_extent()
     ut, vt = rotate_winds(u, v, iris.coord_systems.OSGB())
     orig_sq_mag = u.data**2 + v.data**2
     res_sq_mag = ut.data**2 + vt.data**2
     self.assertArrayAllClose(orig_sq_mag, res_sq_mag, rtol=5e-4)
示例#33
0
 def test_magnitude_preservation(self):
     u, v = self._uv_cubes_limited_extent()
     ut, vt = rotate_winds(u, v, iris.coord_systems.OSGB())
     orig_sq_mag = u.data**2 + v.data**2
     res_sq_mag = ut.data**2 + vt.data**2
     self.assertArrayAllClose(orig_sq_mag, res_sq_mag, rtol=5e-4)
示例#34
0
 def test_rotated_to_unrotated(self):
     # Suffiently accurate so that no mask is introduced.
     u, v = uv_cubes()
     ut, vt = rotate_winds(u, v, iris.coord_systems.GeogCS(6371229))
     self.assertFalse(ma.isMaskedArray(ut.data))
     self.assertFalse(ma.isMaskedArray(vt.data))
示例#35
0
    def _regrid_and_populate(self, temperature, humidity, pressure, uwind,
                             vwind, topography):
        """
        Regrids input variables onto the high resolution orography field, then
        populates the class instance with regridded variables before converting
        to SI units.  Also calculates V.gradZ as a class member.

        Args:
            temperature (iris.cube.Cube):
                Temperature at top of boundary layer
            humidity (iris.cube.Cube):
                Relative humidity at top of boundary layer
            pressure (iris.cube.Cube):
                Pressure at top of boundary layer
            uwind (iris.cube.Cube):
                Positive eastward wind vector component at top of boundary
                layer
            vwind (iris.cube.Cube):
                Positive northward wind vector component at top of boundary
                layer
            topography (iris.cube.Cube):
                Height of topography above sea level on 1 km UKPP domain grid
        """
        # convert topography grid, datatype and units
        for axis in ['x', 'y']:
            topography = sort_coord_in_cube(topography,
                                            topography.coord(axis=axis))
        topography = enforce_coordinate_ordering(topography, [
            topography.coord(axis='y').name(),
            topography.coord(axis='x').name()
        ])
        self.topography = topography.copy(
            data=topography.data.astype(np.float32))
        self.topography.convert_units('m')

        # rotate winds
        try:
            uwind, vwind = rotate_winds(uwind, vwind,
                                        topography.coord_system())
        except ValueError as err:
            if 'Duplicate coordinates are not permitted' in str(err):
                # ignore error raised if uwind and vwind do not need rotating
                pass
            else:
                raise ValueError(str(err))
        else:
            # remove auxiliary spatial coordinates from rotated winds
            for cube in [uwind, vwind]:
                for axis in ['x', 'y']:
                    cube.remove_coord(cube.coord(axis=axis, dim_coords=False))

        # regrid and convert input variables
        self.temperature = self._regrid_variable(temperature, 'kelvin')
        self.humidity = self._regrid_variable(humidity, '1')
        self.pressure = self._regrid_variable(pressure, 'Pa')
        self.uwind = self._regrid_variable(uwind, 'm s-1')
        self.vwind = self._regrid_variable(vwind, 'm s-1')

        # calculate orography gradients
        gradx, grady = self._orography_gradients()

        # calculate v.gradZ
        self.vgradz = (np.multiply(gradx.data, self.uwind.data) +
                       np.multiply(grady.data, self.vwind.data))