Exemple #1
0
    def test_cube_dim(self):
        cube1_reverse0 = reverse(self.cube1, 0)
        cube1_reverse1 = reverse(self.cube1, 1)
        cube1_reverse_both = reverse(self.cube1, (0, 1))

        self.assertArrayEqual(self.cube1.data[::-1], cube1_reverse0.data)
        self.assertArrayEqual(
            self.cube2.coord("a").points,
            cube1_reverse0.coord("a").points)
        self.assertArrayEqual(
            self.cube1.coord("b").points,
            cube1_reverse0.coord("b").points)

        self.assertArrayEqual(self.cube1.data[:, ::-1], cube1_reverse1.data)
        self.assertArrayEqual(
            self.cube1.coord("a").points,
            cube1_reverse1.coord("a").points)
        self.assertArrayEqual(
            self.cube2.coord("b").points,
            cube1_reverse1.coord("b").points)

        self.assertArrayEqual(self.cube1.data[::-1, ::-1],
                              cube1_reverse_both.data)
        self.assertArrayEqual(
            self.cube2.coord("a").points,
            cube1_reverse_both.coord("a").points)
        self.assertArrayEqual(
            self.cube2.coord("b").points,
            cube1_reverse_both.coord("b").points)
Exemple #2
0
    def __init__(self, u, v, rsphere=6.3712e6):
        """Initialize a VectorWind instance.

        **Arguments:**

        *u*, *v*
            Zonal and meridional components of the vector wind
            respectively. Both components should be `~iris.cube.Cube`
            instances. The components must have the same dimension
            coordinates and contain no missing values.

        **Example:**

        Initialize a `VectorWind` instance with zonal and meridional
        components of the vector wind::

            from windspharm.iris import VectorWind
            w = VectorWind(u, v)

        """
        # Make sure inputs are Iris cubes.
        if type(u) is not Cube or type(v) is not Cube:
            raise TypeError('u and v must be iris cubes')
        # Get the coordinates of each component and make sure they are the
        # same.
        ucoords = u.dim_coords
        vcoords = v.dim_coords
        if ucoords != vcoords:
            raise ValueError('u and v must have the same dimensions')
        # Extract the latitude and longitude dimension coordinates.
        lat, lat_dim = _dim_coord_and_dim(u, 'latitude')
        lon, lon_dim = _dim_coord_and_dim(v, 'longitude')
        # Reverse the latitude dimension if necessary.
        if (lat.points[0] < lat.points[1]):
            # need to reverse latitude dimension
            u = reverse(u, lat_dim)
            v = reverse(v, lat_dim)
            lat, lat_dim = _dim_coord_and_dim(u, 'latitude')
        # Determine the grid type of the input.
        gridtype = inspect_gridtype(lat.points)
        # Determine the ordering list (input to transpose) which will put the
        # latitude and longitude dimensions at the front of the cube's
        # dimensions, and the ordering list which will reverse this process.
        apiorder, self._reorder = get_apiorder(u.ndim, lat_dim, lon_dim)
        # Re-order the inputs (in-place, so we take a copy first) so latiutude
        # and longitude are at the front.
        u = u.copy()
        v = v.copy()
        u.transpose(apiorder)
        v.transpose(apiorder)
        # Records the current shape and dimension coordinates of the inputs.
        self._ishape = u.shape
        self._coords = u.dim_coords
        # Reshape the inputs so they are compatible with pyspharm.
        u = u.data.reshape(u.shape[:2] + (np.prod(u.shape[2:]),))
        v = v.data.reshape(v.shape[:2] + (np.prod(v.shape[2:]),))
        # Create a base VectorWind instance to do the computations.
        self._api = standard.VectorWind(u, v, gridtype=gridtype,
                                        rsphere=rsphere)
Exemple #3
0
    def __init__(self, u, v):
        """Initialize a VectorWind instance.

        **Arguments:**

        *u*, *v*
            Zonal and meridional components of the vector wind
            respectively. Both components should be `~iris.cube.Cube`
            instances. The components must have the same dimension
            coordinates and contain no missing values.

        **Example:**

        Initialize a `VectorWind` instance with zonal and meridional
        components of the vector wind::

            from windspharm.iris import VectorWind
            w = VectorWind(u, v)

        """
        # Make sure inputs are Iris cubes.
        if type(u) is not Cube or type(v) is not Cube:
            raise TypeError('u and v must be iris cubes')
        # Get the coordinates of each component and make sure they are the
        # same.
        ucoords = u.dim_coords
        vcoords = v.dim_coords
        if ucoords != vcoords:
            raise ValueError('u and v must have the same dimensions')
        # Extract the latitude and longitude dimension coordinates.
        lat, lat_dim = _dim_coord_and_dim(u, 'latitude')
        lon, lon_dim = _dim_coord_and_dim(v, 'longitude')
        # Reverse the latitude dimension if necessary.
        if (lat.points[0] < lat.points[1]):
            # need to reverse latitude dimension
            u = reverse(u, lat_dim)
            v = reverse(v, lat_dim)
            lat, lat_dim = _dim_coord_and_dim(u, 'latitude')
        # Determine the grid type of the input.
        gridtype = self._gridtype(lat.points)
        # Determine the ordering list (input to transpose) which will put the
        # latitude and longitude dimensions at the front of the cube's
        # dimensions, and the ordering list which will reverse this process.
        apiorder, self._reorder = self._get_apiorder_reorder(
            u, lat_dim, lon_dim)
        # Re-order the inputs (in-place, so we take a copy first) so latiutude
        # and longitude are at the front.
        u = u.copy()
        v = v.copy()
        u.transpose(apiorder)
        v.transpose(apiorder)
        # Records the current shape and dimension coordinates of the inputs.
        self._ishape = u.shape
        self._coords = u.dim_coords
        # Reshape the inputs so they are compatible with pyspharm.
        u = u.data.reshape(u.shape[:2] + (np.prod(u.shape[2:]), ))
        v = v.data.reshape(v.shape[:2] + (np.prod(v.shape[2:]), ))
        # Create a base VectorWind instance to do the computations.
        self._api = standard.VectorWind(u, v, gridtype=gridtype)
Exemple #4
0
    def truncate(self, field, truncation=None):
        """Apply spectral truncation to a scalar field.

        This is useful to represent other fields in a way consistent
        with the output of other `VectorWind` methods.

        **Argument:**

        *field*
            A scalar field. It must be a `~iris.cube.Cube`
            with the same latitude and longitude dimensions as the
            vector wind components that initialized the `VectorWind`
            instance.

        **Optional argument:**

        *truncation*
            Truncation limit (triangular truncation) for the spherical
            harmonic computation. If not specified it will default to
            *nlats - 1* where *nlats* is the number of latitudes.

        **Returns:**

        *truncated_field*
            The field with spectral truncation applied.

        **Examples:**

        Truncate a scalar field to the computational resolution of the
        `VectorWind` instance::

            scalar_field_truncated = w.truncate(scalar_field)

        Truncate a scalar field to T21::

            scalar_field_T21 = w.truncate(scalar_field, truncation=21)

        """
        if type(field) is not Cube:
            raise TypeError('scalar field must be an iris cube')
        lat, lat_dim = _dim_coord_and_dim(field, 'latitude')
        lon, lon_dim = _dim_coord_and_dim(field, 'longitude')
        if (lat.points[0] < lat.points[1]):
            # need to reverse latitude dimension
            field = reverse(field, lat_dim)
            lat, lat_dim = _dim_coord_and_dim(field, 'latitude')
        apiorder, reorder = get_apiorder(field.ndim, lat_dim, lon_dim)
        field = field.copy()
        field.transpose(apiorder)
        ishape = field.shape
        coords = field.dim_coords
        fielddata = field.data.reshape(
            field.shape[:2] + (np.prod(field.shape[2:]),))
        fieldtrunc = self._api.truncate(fielddata, truncation=truncation)
        field.data = fieldtrunc.reshape(ishape)
        field.transpose(reorder)
        return field
Exemple #5
0
    def truncate(self, field, truncation=None):
        """Apply spectral truncation to a scalar field.

        This is useful to represent other fields in a way consistent
        with the output of other `VectorWind` methods.

        **Argument:**

        *field*
            A scalar field. It must be a `~iris.cube.Cube`
            with the same latitude and longitude dimensions as the
            vector wind components that initialized the `VectorWind`
            instance.

        **Optional argument:**

        *truncation*
            Truncation limit (triangular truncation) for the spherical
            harmonic computation. If not specified it will default to
            *nlats - 1* where *nlats* is the number of latitudes.

        **Returns:**

        *truncated_field*
            The field with spectral truncation applied.

        **Examples:**

        Truncate a scalar field to the computational resolution of the
        `VectorWind` instance::

            scalar_field_truncated = w.truncate(scalar_field)

        Truncate a scalar field to T21::

            scalar_field_T21 = w.truncate(scalar_field, truncation=21)

        """
        if type(field) is not Cube:
            raise TypeError('scalar field must be an iris cube')
        lat, lat_dim = _dim_coord_and_dim(field, 'latitude')
        lon, lon_dim = _dim_coord_and_dim(field, 'longitude')
        if (lat.points[0] < lat.points[1]):
            # need to reverse latitude dimension
            field = reverse(field, lat_dim)
            lat, lat_dim = _dim_coord_and_dim(field, 'latitude')
        apiorder, reorder = get_apiorder(field.ndim, lat_dim, lon_dim)
        field = field.copy()
        field.transpose(apiorder)
        ishape = field.shape
        coords = field.dim_coords
        fielddata = field.data.reshape(field.shape[:2] +
                                       (np.prod(field.shape[2:]), ))
        fieldtrunc = self._api.truncate(fielddata, truncation=truncation)
        field.data = fieldtrunc.reshape(ishape)
        field.transpose(reorder)
        return field
def meridional_mass_streamfunction(cubelist, z_coord=UM_HGT):
    v = cubelist.extract_strict("y_wind")
    const = v.attributes["planet_conf"]
    if v.coord(z_coord).units.is_convertible("m"):
        rho = cubelist.extract_strict("air_density")
        rho.coord(z_coord).bounds = None
        v.coord(z_coord).bounds = None
        integrand = zonal_mean(v * rho)
        integrand = reverse(integrand, z_coord)
        res = -1 * vertical_cumsum(integrand, coord=z_coord)
        res = reverse(res, z_coord)
    elif v.coord(z_coord).units.is_convertible("Pa"):
        # pres = cubelist.extract_strict("air_pressure")
        # mmstreamf_const /= const.gravity.asc
        raise NotImplementedError()
    coslat = apply_ufunc(np.cos, apply_ufunc(np.deg2rad, coord_to_cube(res, UM_LATLON[0])))
    coslat.units = "1"
    mmstreamf_const = 2 * np.pi * coslat * const.radius.asc
    res = res * mmstreamf_const
    res.rename("meridional_mass_streamfunction")
    res.convert_units("kg s^-1")
    return res
Exemple #7
0
    def gradient(self, chi, truncation=None):
        """Computes the vector gradient of a scalar field on the sphere.

        **Argument:**

        *chi*
            A scalar field. It must be a `~iris.cube.Cube`
            with the same latitude and longitude dimensions as the
            vector wind components that initialized the `VectorWind`
            instance.

        **Optional argument:**

        *truncation*
            Truncation limit (triangular truncation) for the spherical
            harmonic computation.

        **Returns:**

        *uchi*, *vchi*
            The zonal and meridional components of the vector gradient
            respectively.

        **Examples:**

        Compute the vector gradient of absolute vorticity::

            avrt = w.absolutevorticity()
            avrt_zonal, avrt_meridional = w.gradient(avrt)

        Compute the vector gradient of absolute vorticity and apply
        spectral truncation at triangular T13::

            avrt = w.absolutevorticity()
            avrt_zonalT13, avrt_meridionalT13 = w.gradient(avrt, truncation=13)

        """
        if type(chi) is not Cube:
            raise TypeError('scalar field must be an iris cube')
        name = chi.name()
        lat, lat_dim = _dim_coord_and_dim(chi, 'latitude')
        lon, lon_dim = _dim_coord_and_dim(chi, 'longitude')
        if (lat.points[0] < lat.points[1]):
            # need to reverse latitude dimension
            chi = reverse(chi, lat_dim)
            lat, lat_dim = _dim_coord_and_dim(chi, 'latitude')
        apiorder, reorder = get_apiorder(chi.ndim, lat_dim, lon_dim)
        chi = chi.copy()
        chi.transpose(apiorder)
        ishape = chi.shape
        coords = chi.dim_coords
        chi = chi.data.reshape(chi.shape[:2] + (np.prod(chi.shape[2:]),))
        uchi, vchi = self._api.gradient(chi, truncation=truncation)
        uchi = uchi.reshape(ishape)
        vchi = vchi.reshape(ishape)
        uchi = Cube(
            uchi,
            dim_coords_and_dims=list(zip(coords, range(uchi.ndim))))
        vchi = Cube(
            vchi,
            dim_coords_and_dims=list(zip(coords, range(vchi.ndim))))
        uchi.transpose(reorder)
        vchi.transpose(reorder)
        uchi.long_name = 'zonal_gradient_of_{!s}'.format(name)
        vchi.long_name = 'meridional_gradient_of_{!s}'.format(name)
        return uchi, vchi
Exemple #8
0
    def gradient(self, chi, truncation=None):
        """Computes the vector gradient of a scalar field on the sphere.

        **Argument:**

        *chi*
            A scalar field. It must be a `~iris.cube.Cube`
            with the same latitude and longitude dimensions as the
            vector wind components that initialized the `VectorWind`
            instance.

        **Optional argument:**

        *truncation*
            Truncation limit (triangular truncation) for the spherical
            harmonic computation.

        **Returns:**

        *uchi*, *vchi*
            The zonal and meridional components of the vector gradient
            respectively.

        **Examples:**

        Compute the vector gradient of absolute vorticity::

            avrt = w.absolutevorticity()
            avrt_zonal, avrt_meridional = w.gradient(avrt)

        Compute the vector gradient of absolute vorticity and apply
        spectral truncation at triangular T13::

            avrt = w.absolutevorticity()
            avrt_zonalT13, avrt_meridionalT13 = w.gradient(avrt, truncation=13)

        """
        if type(chi) is not Cube:
            raise TypeError('scalar field must be an iris cube')
        name = chi.name()
        lat, lat_dim = _dim_coord_and_dim(chi, 'latitude')
        lon, lon_dim = _dim_coord_and_dim(chi, 'longitude')
        if (lat.points[0] < lat.points[1]):
            # need to reverse latitude dimension
            chi = reverse(chi, lat_dim)
            lat, lat_dim = _dim_coord_and_dim(chi, 'latitude')
        apiorder, reorder = get_apiorder(chi.ndim, lat_dim, lon_dim)
        chi = chi.copy()
        chi.transpose(apiorder)
        ishape = chi.shape
        coords = chi.dim_coords
        chi = chi.data.reshape(chi.shape[:2] + (np.prod(chi.shape[2:]), ))
        uchi, vchi = self._api.gradient(chi, truncation=truncation)
        uchi = uchi.reshape(ishape)
        vchi = vchi.reshape(ishape)
        uchi = Cube(uchi,
                    dim_coords_and_dims=list(zip(coords, range(uchi.ndim))))
        vchi = Cube(vchi,
                    dim_coords_and_dims=list(zip(coords, range(vchi.ndim))))
        uchi.transpose(reorder)
        vchi.transpose(reorder)
        uchi.long_name = 'zonal_gradient_of_{!s}'.format(name)
        vchi.long_name = 'meridional_gradient_of_{!s}'.format(name)
        return uchi, vchi
Exemple #9
0
    def test_single_array(self):
        a = np.arange(36).reshape(3, 4, 3)
        self.assertArrayEqual(a[::-1], reverse(a, 0))
        self.assertArrayEqual(a[::-1, ::-1], reverse(a, [0, 1]))
        self.assertArrayEqual(a[:, ::-1, ::-1], reverse(a, [1, 2]))
        self.assertArrayEqual(a[..., ::-1], reverse(a, 2))

        msg = "Reverse was expecting a single axis or a 1d array *"
        with self.assertRaisesRegex(ValueError, msg):
            reverse(a, [])

        msg = "An axis value out of range for the number of dimensions *"
        with self.assertRaisesRegex(ValueError, msg):
            reverse(a, -1)
        with self.assertRaisesRegex(ValueError, msg):
            reverse(a, 10)
        with self.assertRaisesRegex(ValueError, msg):
            reverse(a, [-1])
        with self.assertRaisesRegex(ValueError, msg):
            reverse(a, [0, -1])

        with self.assertRaisesRegex(TypeError,
                                    "To reverse an array, provide an int *"):
            reverse(a, "latitude")
Exemple #10
0
    def test_cube_coord(self):
        cube1_reverse0 = reverse(self.cube1, self.a1)
        cube1_reverse1 = reverse(self.cube1, "b")
        cube1_reverse_both = reverse(self.cube1, (self.a1, self.b1))
        cube1_reverse_spanning = reverse(self.cube1, "spanning")

        self.assertArrayEqual(self.cube1.data[::-1], cube1_reverse0.data)
        self.assertArrayEqual(
            self.cube2.coord("a").points,
            cube1_reverse0.coord("a").points)
        self.assertArrayEqual(
            self.cube1.coord("b").points,
            cube1_reverse0.coord("b").points)

        self.assertArrayEqual(self.cube1.data[:, ::-1], cube1_reverse1.data)
        self.assertArrayEqual(
            self.cube1.coord("a").points,
            cube1_reverse1.coord("a").points)
        self.assertArrayEqual(
            self.cube2.coord("b").points,
            cube1_reverse1.coord("b").points)

        self.assertArrayEqual(self.cube1.data[::-1, ::-1],
                              cube1_reverse_both.data)
        self.assertArrayEqual(
            self.cube2.coord("a").points,
            cube1_reverse_both.coord("a").points)
        self.assertArrayEqual(
            self.cube2.coord("b").points,
            cube1_reverse_both.coord("b").points)

        self.assertArrayEqual(self.cube1.data[::-1, ::-1],
                              cube1_reverse_spanning.data)
        self.assertArrayEqual(
            self.cube2.coord("a").points,
            cube1_reverse_spanning.coord("a").points,
        )
        self.assertArrayEqual(
            self.cube2.coord("b").points,
            cube1_reverse_spanning.coord("b").points,
        )
        self.assertArrayEqual(
            self.span.points[::-1, ::-1],
            cube1_reverse_spanning.coord("spanning").points,
        )

        msg = (
            "Expected to find exactly 1 'latitude' coordinate, but found none."
        )
        with self.assertRaisesRegex(iris.exceptions.CoordinateNotFoundError,
                                    msg):
            reverse(self.cube1, "latitude")

        msg = "Reverse was expecting a single axis or a 1d array *"
        with self.assertRaisesRegex(ValueError, msg):
            reverse(self.cube1, [])

        msg = ("coords_or_dims must be int, str, coordinate or sequence of "
               "these.  Got cube.")
        with self.assertRaisesRegex(TypeError, msg):
            reverse(self.cube1, self.cube1)

        msg = ("coords_or_dims must be int, str, coordinate or sequence of "
               "these.")
        with self.assertRaisesRegex(TypeError, msg):
            reverse(self.cube1, 3.0)
Exemple #11
0
    def __init__(self, u, v, rsphere=6.3712e6, legfunc='stored'):
        """Initialize a VectorWind instance.

        **Arguments:**

        *u*, *v*
            Zonal and meridional components of the vector wind
            respectively. Both components should be `~iris.cube.Cube`
            instances. The components must have the same dimension
            coordinates and contain no missing values.

        **Optional argument:**

        *rsphere*
            The radius in metres of the sphere used in the spherical
            harmonic computations. Default is 6371200 m, the approximate
            mean spherical Earth radius.

        *legfunc*
            'stored' (default) or 'computed'.  If 'stored', associated legendre
            functions are precomputed and stored when the class instance is
            created.  This uses O(nlat**3) memory, but speeds up the spectral
            transforms.  If 'computed', associated legendre functions are
            computed on the fly when transforms are requested.  This uses
            O(nlat**2) memory, but slows down the spectral transforms a bit.

        **Example:**

        Initialize a `VectorWind` instance with zonal and meridional
        components of the vector wind::

            from windspharm.iris import VectorWind
            w = VectorWind(u, v)

        """
        # Make sure inputs are Iris cubes.
        if type(u) is not Cube or type(v) is not Cube:
            raise TypeError('u and v must be iris cubes')
        # Get the coordinates of each component and make sure they are the
        # same.
        ucoords = u.dim_coords
        vcoords = v.dim_coords
        if ucoords != vcoords:
            raise ValueError('u and v must have the same dimensions')
        # Extract the latitude and longitude dimension coordinates.
        lat, lat_dim = _dim_coord_and_dim(u, 'latitude')
        lon, lon_dim = _dim_coord_and_dim(v, 'longitude')
        # Reverse the latitude dimension if necessary.
        if (lat.points[0] < lat.points[1]):
            # need to reverse latitude dimension
            u = reverse(u, lat_dim)
            v = reverse(v, lat_dim)
            lat, lat_dim = _dim_coord_and_dim(u, 'latitude')
        # Determine the grid type of the input.
        gridtype = inspect_gridtype(lat.points)
        # Determine the ordering list (input to transpose) which will put the
        # latitude and longitude dimensions at the front of the cube's
        # dimensions, and the ordering list which will reverse this process.
        apiorder, self._reorder = get_apiorder(u.ndim, lat_dim, lon_dim)
        # Re-order the inputs (in-place, so we take a copy first) so latiutude
        # and longitude are at the front.
        u = u.copy()
        v = v.copy()
        u.transpose(apiorder)
        v.transpose(apiorder)
        # Records the current shape and dimension coordinates of the inputs.
        self._ishape = u.shape
        self._coords = u.dim_coords
        # Reshape the inputs so they are compatible with pyspharm.
        u = to3d(u.data)
        v = to3d(v.data)
        # Create a base VectorWind instance to do the computations.
        self._api = standard.VectorWind(u,
                                        v,
                                        gridtype=gridtype,
                                        rsphere=rsphere,
                                        legfunc=legfunc)
Exemple #12
0
    def test_simple_array(self):
        a = np.arange(12).reshape(3, 4)
        self.assertArrayEqual(a[::-1], reverse(a, 0))
        self.assertArrayEqual(a[::-1, ::-1], reverse(a, [0, 1]))
        self.assertArrayEqual(a[:, ::-1], reverse(a, 1))
        self.assertArrayEqual(a[:, ::-1], reverse(a, [1]))

        msg = 'Reverse was expecting a single axis or a 1d array *'
        with self.assertRaisesRegex(ValueError, msg):
            reverse(a, [])

        msg = 'An axis value out of range for the number of dimensions *'
        with self.assertRaisesRegex(ValueError, msg):
            reverse(a, -1)
        with self.assertRaisesRegex(ValueError, msg):
            reverse(a, 10)
        with self.assertRaisesRegex(ValueError, msg):
            reverse(a, [-1])
        with self.assertRaisesRegex(ValueError, msg):
            reverse(a, [0, -1])

        msg = 'To reverse an array, provide an int *'
        with self.assertRaisesRegex(TypeError, msg):
            reverse(a, 'latitude')
Exemple #13
0
    def test_cube_coord(self):
        cube1_reverse0 = reverse(self.cube1, self.a1)
        cube1_reverse1 = reverse(self.cube1, 'b')
        cube1_reverse_both = reverse(self.cube1, (self.a1, self.b1))
        cube1_reverse_spanning = reverse(self.cube1, 'spanning')

        self.assertArrayEqual(self.cube1.data[::-1], cube1_reverse0.data)
        self.assertArrayEqual(
            self.cube2.coord('a').points,
            cube1_reverse0.coord('a').points)
        self.assertArrayEqual(
            self.cube1.coord('b').points,
            cube1_reverse0.coord('b').points)

        self.assertArrayEqual(self.cube1.data[:, ::-1], cube1_reverse1.data)
        self.assertArrayEqual(
            self.cube1.coord('a').points,
            cube1_reverse1.coord('a').points)
        self.assertArrayEqual(
            self.cube2.coord('b').points,
            cube1_reverse1.coord('b').points)

        self.assertArrayEqual(self.cube1.data[::-1, ::-1],
                              cube1_reverse_both.data)
        self.assertArrayEqual(
            self.cube2.coord('a').points,
            cube1_reverse_both.coord('a').points)
        self.assertArrayEqual(
            self.cube2.coord('b').points,
            cube1_reverse_both.coord('b').points)

        self.assertArrayEqual(self.cube1.data[::-1, ::-1],
                              cube1_reverse_spanning.data)
        self.assertArrayEqual(
            self.cube2.coord('a').points,
            cube1_reverse_spanning.coord('a').points)
        self.assertArrayEqual(
            self.cube2.coord('b').points,
            cube1_reverse_spanning.coord('b').points)
        self.assertArrayEqual(self.span.points[::-1, ::-1],
                              cube1_reverse_spanning.coord('spanning').points)

        msg = 'Expected to find exactly 1 latitude coordinate, but found none.'
        with self.assertRaisesRegex(iris.exceptions.CoordinateNotFoundError,
                                    msg):
            reverse(self.cube1, 'latitude')

        msg = 'Reverse was expecting a single axis or a 1d array *'
        with self.assertRaisesRegex(ValueError, msg):
            reverse(self.cube1, [])

        msg = ('coords_or_dims must be int, str, coordinate or sequence of '
               'these.  Got cube.')
        with self.assertRaisesRegex(TypeError, msg):
            reverse(self.cube1, self.cube1)

        msg = ('coords_or_dims must be int, str, coordinate or sequence of '
               'these.')
        with self.assertRaisesRegex(TypeError, msg):
            reverse(self.cube1, 3.)