Example #1
0
    def test_variation(self):
        """Test that two cubes with slightly different coordinates return
        different hashes."""

        hash_input1 = set_up_variable_cube(np.zeros((3, 3)).astype(np.float32))
        hash_input2 = hash_input1.copy()
        latitude = hash_input2.coord("latitude")
        latitude_values = latitude.points * 1.001
        latitude = latitude.copy(points=latitude_values)
        hash_input2.remove_coord("latitude")
        hash_input2.add_dim_coord(latitude, 0)

        result1 = create_coordinate_hash(hash_input1)
        result2 = create_coordinate_hash(hash_input2)
        self.assertNotEqual(result1, result2)
Example #2
0
    def setUp(self):
        """Set up cubes for use in testing."""

        data = np.ones(9).reshape(3, 3).astype(np.float32)
        self.reference_cube = set_up_variable_cube(data,
                                                   spatial_grid="equalarea")
        self.cube1 = self.reference_cube.copy()
        self.cube2 = self.reference_cube.copy()
        self.unmatched_cube = set_up_variable_cube(data, spatial_grid="latlon")

        self.diagnostic_cube_hash = create_coordinate_hash(self.reference_cube)

        neighbours = np.array([[[0.0], [0.0], [0.0]]])
        altitudes = np.array([0])
        latitudes = np.array([0])
        longitudes = np.array([0])
        wmo_ids = np.array([0])
        grid_attributes = ["x_index", "y_index", "vertical_displacement"]
        neighbour_methods = ["nearest"]
        self.neighbour_cube = build_spotdata_cube(
            neighbours,
            "grid_neighbours",
            1,
            altitudes,
            latitudes,
            longitudes,
            wmo_ids,
            grid_attributes=grid_attributes,
            neighbour_methods=neighbour_methods,
        )
        self.neighbour_cube.attributes[
            "model_grid_hash"] = self.diagnostic_cube_hash
Example #3
0
    def test_basic(self):
        """Test the expected hash is returned for a given cube."""

        hash_input = set_up_variable_cube(np.zeros((3, 3)).astype(np.float32))
        result = create_coordinate_hash(hash_input)
        expected = "54812a6fed0f92fe75d180d63a6bd6c916407ea1e7e5fd32a5f20f86ea997fac"
        self.assertIsInstance(result, str)
        self.assertEqual(result, expected)
Example #4
0
    def test_basic(self):
        """Test the expected hash is returned for a given cube."""

        hash_input = set_up_variable_cube(np.zeros((3, 3)).astype(np.float32))
        result = create_coordinate_hash(hash_input)
        expected = "b26ca16d28f6e06ea4573fd745f55750c6dd93a06891f1b4ff0c6cd50585ac08"
        self.assertIsInstance(result, str)
        self.assertEqual(result, expected)
Example #5
0
    def test_global_attribute(self):
        """Test that a cube is returned with a model_grid_hash that matches
        that of the global input grids."""

        expected = create_coordinate_hash(self.global_orography)
        plugin = NeighbourSelection()
        result = plugin.process(self.global_sites, self.global_orography,
                                self.global_land_mask)

        self.assertIsInstance(result, iris.cube.Cube)
        self.assertEqual(result.attributes["model_grid_hash"], expected)
Example #6
0
    def test_region_attribute(self):
        """Test that a cube is returned with a model_grid_hash that matches
        that of the regional input grids."""

        expected = create_coordinate_hash(self.region_orography)
        plugin = NeighbourSelection(
            site_coordinate_system=self.region_projection.as_cartopy_crs(),
            site_x_coordinate='projection_x_coordinate',
            site_y_coordinate='projection_y_coordinate')
        result = plugin.process(self.region_sites, self.region_orography,
                                self.region_land_mask)

        self.assertIsInstance(result, iris.cube.Cube)
        self.assertEqual(result.attributes['model_grid_hash'], expected)
    def test_probability_cube(self):
        """Ensure that the plugin exits with value error if the spot data cube
        is in probability space. """

        diagnostic_cube_hash = create_coordinate_hash(self.lapse_rate_cube)
        data = np.ones((3, 3, 3), dtype=np.float32)
        threshold_points = np.array([276, 277, 278], dtype=np.float32)
        probability_cube = set_up_probability_cube(
            data, threshold_points, spp__relative_to_threshold="above")

        probability_cube.attributes["model_grid_hash"] = diagnostic_cube_hash

        plugin = SpotLapseRateAdjust()
        msg = ("Input cube has a probability coordinate which cannot be lapse "
               "rate adjusted. Input data should be in percentile or "
               "deterministic space only.")

        with self.assertRaisesRegex(ValueError, msg):
            plugin(probability_cube, self.neighbour_cube, self.lapse_rate_cube)
Example #8
0
 def _get_grid_hash(cube):
     try:
         cube_hash = cube.attributes["model_grid_hash"]
     except KeyError:
         cube_hash = create_coordinate_hash(cube)
     return cube_hash
Example #9
0
    def setUp(self):
        """
        Set up cubes and sitelists for use in testing SpotExtraction.
        The envisaged scenario is an island (1) surrounded by water (0).

          Land-sea       Orography      Diagnostic

          0 0 0 0 0      0 0 0 0 0       0  1  2  3  4
          0 1 1 1 0      0 1 2 1 0       5  6  7  8  9
          0 1 1 1 0      0 2 3 2 0      10 11 12 13 14
          0 1 1 1 0      0 1 2 1 0      15 16 17 18 19
          0 0 0 0 0      0 0 0 0 0      20 21 22 23 24

        """
        # Set up diagnostic data cube and neighbour cubes.
        diagnostic_data = np.arange(25).reshape(5, 5)

        # Grid attributes must be included in diagnostic cubes so their removal
        # can be tested
        attributes = {
            "mosg__grid_domain": "global",
            "mosg__grid_type": "standard"
        }

        self.cell_methods = (iris.coords.CellMethod("maximum",
                                                    coords="time",
                                                    intervals="1 hour"), )

        time = dt(2020, 6, 15, 12)
        frt = time - timedelta(hours=6)

        diagnostic_cube_yx = set_up_variable_cube(
            diagnostic_data.T,
            name="air_temperature",
            units="K",
            attributes=attributes,
            domain_corner=(0, 0),
            grid_spacing=10,
            time=time,
            frt=frt,
        )
        diagnostic_cube_yx.cell_methods = self.cell_methods

        diagnostic_cube_xy = diagnostic_cube_yx.copy()
        enforce_coordinate_ordering(
            diagnostic_cube_xy,
            [
                diagnostic_cube_xy.coord(axis="x").name(),
                diagnostic_cube_xy.coord(axis="y").name(),
            ],
            anchor_start=False,
        )

        times = np.array([time + timedelta(hours=i) for i in range(-3, 2)])

        # Create as int64 values
        time_points = np.array([_create_time_point(time) for time in times])
        bounds = np.array([[
            _create_time_point(time - timedelta(hours=1)),
            _create_time_point(time),
        ] for time in times])
        # Broadcast the times to a 2-dimensional grid that matches the diagnostic
        # data grid
        time_points = np.broadcast_to(time_points, (5, 5))
        bounds = np.broadcast_to(bounds, (5, 5, 2))
        # Create a 2-dimensional auxiliary time coordinate
        self.time_aux_coord = iris.coords.AuxCoord(
            time_points,
            "time",
            bounds=bounds,
            units=TIME_COORDS["time"].units)

        diagnostic_cube_2d_time = diagnostic_cube_yx.copy()
        diagnostic_cube_2d_time.coord("time").rename("time_in_local_timezone")
        diagnostic_cube_2d_time.add_aux_coord(self.time_aux_coord,
                                              data_dims=(0, 1))

        expected_indices = [[0, 0], [0, 0], [2, 2], [2, 2]]
        points = [
            self.time_aux_coord.points[y, x] for y, x in expected_indices
        ]
        bounds = [
            self.time_aux_coord.bounds[y, x] for y, x in expected_indices
        ]
        self.expected_spot_time_coord = self.time_aux_coord.copy(points=points,
                                                                 bounds=bounds)

        diagnostic_cube_hash = create_coordinate_hash(diagnostic_cube_yx)

        # neighbours, each group is for a point under two methods, e.g.
        # [ 0.  0.  0.] is the nearest point to the first spot site, whilst
        # [ 1.  1. -1.] is the nearest land point to the same site.
        neighbours = np.array([
            [[0.0, 0.0, 2.0, 2.0], [0.0, 0.0, 2.0, 2.0], [0.0, -1.0, 0.0,
                                                          1.0]],
            [[1.0, 1.0, 2.0, 2.0], [1.0, 1.0, 2.0, 2.0], [-1.0, 0.0, 0.0,
                                                          1.0]],
        ])

        self.altitudes = np.array([0, 1, 3, 2])
        self.latitudes = np.array([10, 10, 20, 20])
        self.longitudes = np.array([10, 10, 20, 20])
        self.wmo_ids = np.arange(4)
        self.unique_site_id = np.arange(4)
        self.unique_site_id_key = "met_office_site_id"
        grid_attributes = ["x_index", "y_index", "vertical_displacement"]
        neighbour_methods = ["nearest", "nearest_land"]
        neighbour_cube = build_spotdata_cube(
            neighbours,
            "grid_neighbours",
            1,
            self.altitudes,
            self.latitudes,
            self.longitudes,
            self.wmo_ids,
            unique_site_id=self.unique_site_id,
            unique_site_id_key=self.unique_site_id_key,
            grid_attributes=grid_attributes,
            neighbour_methods=neighbour_methods,
        )
        neighbour_cube.attributes["model_grid_hash"] = diagnostic_cube_hash

        coordinate_cube = neighbour_cube.extract(
            iris.Constraint(neighbour_selection_method_name="nearest")
            & iris.Constraint(grid_attributes_key=["x_index", "y_index"]))
        coordinate_cube.data = np.rint(coordinate_cube.data).astype(int)

        self.diagnostic_cube_xy = diagnostic_cube_xy
        self.diagnostic_cube_yx = diagnostic_cube_yx
        self.diagnostic_cube_2d_time = diagnostic_cube_2d_time
        self.neighbours = neighbours
        self.neighbour_cube = neighbour_cube
        self.coordinate_cube = coordinate_cube

        self.expected_attributes = self.diagnostic_cube_xy.attributes
        for attr in MOSG_GRID_ATTRIBUTES:
            self.expected_attributes.pop(attr, None)
        self.expected_attributes["title"] = "unknown"
        self.expected_attributes[
            "model_grid_hash"] = self.neighbour_cube.attributes[
                "model_grid_hash"]
    def setUp(self):
        """
        Set up cubes for use in testing SpotLapseRateAdjust. Inputs are
        envisaged as follows:

        Gridded

         Lapse rate  Orography  Temperatures (not used directly)
          (x DALR)

            A B C      A B C        A   B   C

        a   2 1 1      1 1 1       270 270 270
        b   1 2 1      1 4 1       270 280 270
        c   1 1 2      1 1 1       270 270 270

        Spot
        (note the neighbours are identified with the A-C, a-c indices above)

         Site  Temperature Altitude  Nearest    DZ   MinDZ      DZ
                                     neighbour       neighbour

          0        280        3      Ac         2    Bb         -1
          1        270        4      Bb         0    Bb          0
          2        280        0      Ca        -1    Ca         -1


        """
        # Set up lapse rate cube
        lapse_rate_data = np.ones(9).reshape(3, 3).astype(np.float32) * DALR
        lapse_rate_data[0, 2] = 2 * DALR
        lapse_rate_data[1, 1] = 2 * DALR
        lapse_rate_data[2, 0] = 2 * DALR
        self.lapse_rate_cube = set_up_variable_cube(lapse_rate_data,
                                                    name="lapse_rate",
                                                    units="K m-1",
                                                    spatial_grid="equalarea")
        diagnostic_cube_hash = create_coordinate_hash(self.lapse_rate_cube)

        # Set up neighbour and spot diagnostic cubes
        y_coord, x_coord = construct_xy_coords(3, 3, "equalarea")
        y_coord = y_coord.points
        x_coord = x_coord.points

        # neighbours, each group is for a point under two methods, e.g.
        # [ 0.  0.  0.] is the nearest point to the first spot site, whilst
        # [ 1.  1. -1.] is the nearest point with minimum height difference.
        neighbours = np.array([[[0., 0., 2.], [1., 1., -1.]],
                               [[1., 1., 0.], [1., 1., 0.]],
                               [[2., 2., -1.], [2., 2., -1.]]])
        altitudes = np.array([3, 4, 0])
        latitudes = np.array([y_coord[0], y_coord[1], y_coord[2]])
        longitudes = np.array([x_coord[0], x_coord[1], x_coord[2]])
        wmo_ids = np.arange(3)
        grid_attributes = ['x_index', 'y_index', 'vertical_displacement']
        neighbour_methods = ['nearest', 'nearest_minimum_dz']
        self.neighbour_cube = build_spotdata_cube(
            neighbours,
            'grid_neighbours',
            1,
            altitudes,
            latitudes,
            longitudes,
            wmo_ids,
            grid_attributes=grid_attributes,
            neighbour_methods=neighbour_methods)
        self.neighbour_cube.attributes['model_grid_hash'] = (
            diagnostic_cube_hash)

        time, = iris_time_to_datetime(self.lapse_rate_cube.coord("time"))
        frt, = iris_time_to_datetime(
            self.lapse_rate_cube.coord("forecast_reference_time"))
        time_bounds = None

        time_coords = construct_scalar_time_coords(time, time_bounds, frt)
        time_coords = [item[0] for item in time_coords]

        # This temperature cube is set up with the spot sites having obtained
        # their temperature values from the nearest grid sites.
        temperatures_nearest = np.array([280, 270, 280])
        self.spot_temperature_nearest = build_spotdata_cube(
            temperatures_nearest,
            'air_temperature',
            'K',
            altitudes,
            latitudes,
            longitudes,
            wmo_ids,
            scalar_coords=time_coords)
        self.spot_temperature_nearest.attributes['model_grid_hash'] = (
            diagnostic_cube_hash)

        # This temperature cube is set up with the spot sites having obtained
        # their temperature values from the nearest minimum vertical
        # displacment grid sites. The only difference here is for site 0, which
        # now gets its temperature from Bb (see doc-string above).
        temperatures_mindz = np.array([270, 270, 280])
        self.spot_temperature_mindz = build_spotdata_cube(
            temperatures_mindz,
            'air_temperature',
            'K',
            altitudes,
            latitudes,
            longitudes,
            wmo_ids,
            scalar_coords=time_coords)
        self.spot_temperature_mindz.attributes['model_grid_hash'] = (
            diagnostic_cube_hash)
Example #11
0
    def setUp(self):
        """
        Set up cubes and sitelists for use in testing SpotExtraction.
        The envisaged scenario is an island (1) surrounded by water (0).

          Land-sea       Orography      Diagnostic

          0 0 0 0 0      0 0 0 0 0       0  1  2  3  4
          0 1 1 1 0      0 1 2 1 0       5  6  7  8  9
          0 1 1 1 0      0 2 3 2 0      10 11 12 13 14
          0 1 1 1 0      0 1 2 1 0      15 16 17 18 19
          0 0 0 0 0      0 0 0 0 0      20 21 22 23 24

        """
        # Set up diagnostic data cube and neighbour cubes.
        diagnostic_data = np.arange(25).reshape(5, 5)

        xcoord = iris.coords.DimCoord(np.linspace(0, 40, 5),
                                      standard_name="longitude",
                                      units="degrees")
        ycoord = iris.coords.DimCoord(np.linspace(0, 40, 5),
                                      standard_name="latitude",
                                      units="degrees")

        # Grid attributes must be included in diagnostic cubes so their removal
        # can be tested
        attributes = {
            "mosg__grid_domain": "global",
            "mosg__grid_type": "standard"
        }

        self.cell_methods = (iris.coords.CellMethod("maximum",
                                                    coords="time",
                                                    intervals="1 hour"), )

        diagnostic_cube_xy = iris.cube.Cube(
            diagnostic_data,
            standard_name="air_temperature",
            units="K",
            dim_coords_and_dims=[(ycoord, 1), (xcoord, 0)],
            attributes=attributes,
            cell_methods=self.cell_methods,
        )
        diagnostic_cube_yx = iris.cube.Cube(
            diagnostic_data.T,
            standard_name="air_temperature",
            units="K",
            dim_coords_and_dims=[(ycoord, 0), (xcoord, 1)],
            attributes=attributes,
            cell_methods=self.cell_methods,
        )

        diagnostic_cube_hash = create_coordinate_hash(diagnostic_cube_yx)

        # neighbours, each group is for a point under two methods, e.g.
        # [ 0.  0.  0.] is the nearest point to the first spot site, whilst
        # [ 1.  1. -1.] is the nearest land point to the same site.
        neighbours = np.array([
            [[0.0, 0.0, 2.0, 2.0], [0.0, 0.0, 2.0, 2.0], [0.0, -1.0, 0.0,
                                                          1.0]],
            [[1.0, 1.0, 2.0, 2.0], [1.0, 1.0, 2.0, 2.0], [-1.0, 0.0, 0.0,
                                                          1.0]],
        ])

        self.altitudes = np.array([0, 1, 3, 2])
        self.latitudes = np.array([10, 10, 20, 20])
        self.longitudes = np.array([10, 10, 20, 20])
        self.wmo_ids = np.arange(4)
        self.unique_site_id = np.arange(4)
        self.unique_site_id_key = "met_office_site_id"
        grid_attributes = ["x_index", "y_index", "vertical_displacement"]
        neighbour_methods = ["nearest", "nearest_land"]
        neighbour_cube = build_spotdata_cube(
            neighbours,
            "grid_neighbours",
            1,
            self.altitudes,
            self.latitudes,
            self.longitudes,
            self.wmo_ids,
            unique_site_id=self.unique_site_id,
            unique_site_id_key=self.unique_site_id_key,
            grid_attributes=grid_attributes,
            neighbour_methods=neighbour_methods,
        )
        neighbour_cube.attributes["model_grid_hash"] = diagnostic_cube_hash

        coordinate_cube = neighbour_cube.extract(
            iris.Constraint(neighbour_selection_method_name="nearest")
            & iris.Constraint(grid_attributes_key=["x_index", "y_index"]))
        coordinate_cube.data = np.rint(coordinate_cube.data).astype(int)

        self.diagnostic_cube_xy = diagnostic_cube_xy
        self.diagnostic_cube_yx = diagnostic_cube_yx
        self.neighbours = neighbours
        self.neighbour_cube = neighbour_cube
        self.coordinate_cube = coordinate_cube

        self.expected_attributes = self.diagnostic_cube_xy.attributes
        for attr in MOSG_GRID_ATTRIBUTES:
            self.expected_attributes.pop(attr, None)
        self.expected_attributes["title"] = "unknown"
        self.expected_attributes[
            "model_grid_hash"] = self.neighbour_cube.attributes[
                "model_grid_hash"]
Example #12
0
    def process(
        self, sites: List[Dict[str, Any]], orography: Cube, land_mask: Cube
    ) -> Cube:
        """
        Using the constraints provided, find the nearest grid point neighbours
        to the given spot sites for the model/grid given by the input cubes.
        Returned is a cube that contains the defining characteristics of the
        spot sites (e.g. x coordinate, y coordinate, altitude) and the indices
        of the selected grid point neighbour.

        Args:
            sites:
                A list of dictionaries defining the spot sites for which
                neighbours are to be found. e.g.:

                   [{'altitude': 11.0, 'latitude': 57.867000579833984,
                    'longitude': -5.632999897003174, 'wmo_id': 3034}]

            orography:
                A cube of orography, used to obtain the grid point altitudes.
            land_mask:
                A land mask cube for the model/grid from which grid point
                neighbours are being selected, with land points set to one and
                sea points set to zero.

        Returns:
            A cube containing both the spot site information and for each
            the grid point indices of its nearest neighbour as per the
            imposed constraints.
        """
        # Check if we are dealing with a global grid.
        self.global_coordinate_system = orography.coord(axis="x").circular

        # Exclude regional grids with spatial dimensions other than metres.
        if not self.global_coordinate_system:
            if not orography.coord(axis="x").units == "metres":
                msg = (
                    "Cube spatial coordinates for regional grids must be"
                    "in metres to match the defined search_radius."
                )
                raise ValueError(msg)

        # Ensure land_mask and orography are on the same grid.
        if not orography.dim_coords == land_mask.dim_coords:
            msg = "Orography and land_mask cubes are not on the same " "grid."
            raise ValueError(msg)

        # Enforce x-y coordinate order for input cubes.
        enforce_coordinate_ordering(
            orography,
            [orography.coord(axis="x").name(), orography.coord(axis="y").name()],
        )
        enforce_coordinate_ordering(
            land_mask,
            [land_mask.coord(axis="x").name(), land_mask.coord(axis="y").name()],
        )

        # Remap site coordinates on to coordinate system of the model grid.
        site_x_coords = np.array([site[self.site_x_coordinate] for site in sites])
        site_y_coords = np.array([site[self.site_y_coordinate] for site in sites])
        site_coords = self._transform_sites_coordinate_system(
            site_x_coords, site_y_coords, orography.coord_system().as_cartopy_crs()
        )

        # Exclude any sites falling outside the domain given by the cube and
        # notify the user.
        (
            sites,
            site_coords,
            site_x_coords,
            site_y_coords,
        ) = self.check_sites_are_within_domain(
            sites, site_coords, site_x_coords, site_y_coords, orography
        )

        # Find nearest neighbour point using quick iris method.
        nearest_indices = self.get_nearest_indices(site_coords, orography)

        # Create an array containing site altitudes, using the nearest point
        # orography height for any that are unset.
        site_altitudes = np.array(
            [site.get(self.site_altitude, None) for site in sites]
        )
        site_altitudes = np.where(
            np.isnan(site_altitudes.astype(float)),
            orography.data[tuple(nearest_indices.T)],
            site_altitudes,
        )

        # If further constraints are being applied, build a KD Tree which
        # includes points filtered by constraint.
        if self.land_constraint or self.minimum_dz:
            # Build the KDTree, an internal test for the land_constraint checks
            # whether to exclude sea points from the tree.
            tree, index_nodes = self.build_KDTree(land_mask)

            # Site coordinates made cartesian for global coordinate system
            if self.global_coordinate_system:
                site_coords = self.geocentric_cartesian(
                    orography, site_coords[:, 0], site_coords[:, 1]
                )

            if not self.minimum_dz:
                # Query the tree for the nearest neighbour, in this case a land
                # neighbour is returned along with the distance to it.
                distances, node_indices = tree.query([site_coords])
                # Look up the grid coordinates that correspond to the tree node
                (land_neighbour_indices,) = index_nodes[node_indices]
                # Use the found land neighbour if it is within the
                # search_radius, otherwise use the nearest neighbour.
                distances = np.array([distances[0], distances[0]]).T
                nearest_indices = np.where(
                    distances < self.search_radius,
                    land_neighbour_indices,
                    nearest_indices,
                )
            else:
                # Query the tree for self.node_limit nearby neighbours.
                distances, node_indices = tree.query(
                    [site_coords],
                    distance_upper_bound=self.search_radius,
                    k=self.node_limit,
                )
                # Loop over the sites and for each choose the returned
                # neighbour with the minimum vertical displacement.
                for index, (distance, indices) in enumerate(
                    zip(distances[0], node_indices[0])
                ):
                    grid_point = self.select_minimum_dz(
                        orography, site_altitudes[index], index_nodes, distance, indices
                    )
                    # None is returned if the tree query returned no neighbours
                    # within the search radius.
                    if grid_point is not None:
                        nearest_indices[index] = grid_point

        # Calculate the vertical displacements between the chosen grid point
        # and the spot site.
        vertical_displacements = (
            site_altitudes - orography.data[tuple(nearest_indices.T)]
        )

        # Create a list of WMO IDs if available. These are stored as strings
        # to accommodate the use of 'None' for unset IDs.
        wmo_ids = [str(site.get("wmo_id", None)) for site in sites]

        # Construct a name to describe the neighbour finding method employed
        method_name = self.neighbour_finding_method_name()

        # Create an array of indices and displacements to return
        data = np.stack(
            (nearest_indices[:, 0], nearest_indices[:, 1], vertical_displacements),
            axis=0,
        )
        data = np.expand_dims(data, 0).astype(np.float32)

        # Regardless of input sitelist coordinate system, the site coordinates
        # are stored as latitudes and longitudes in the neighbour cube.
        if self.site_coordinate_system != ccrs.PlateCarree():
            lon_lats = self._transform_sites_coordinate_system(
                site_x_coords, site_y_coords, ccrs.PlateCarree()
            )
            longitudes = lon_lats[:, 0]
            latitudes = lon_lats[:, 1]
        else:
            longitudes = site_x_coords
            latitudes = site_y_coords

        # Create a cube of neighbours
        neighbour_cube = build_spotdata_cube(
            data,
            "grid_neighbours",
            1,
            site_altitudes.astype(np.float32),
            latitudes.astype(np.float32),
            longitudes.astype(np.float32),
            wmo_ids,
            neighbour_methods=[method_name],
            grid_attributes=["x_index", "y_index", "vertical_displacement"],
        )

        # Add a hash attribute based on the model grid to ensure the neighbour
        # cube is only used with a compatible grid.
        grid_hash = create_coordinate_hash(orography)
        neighbour_cube.attributes["model_grid_hash"] = grid_hash

        return neighbour_cube
Example #13
0
    def setUp(self):
        """
        Set up cubes and sitelists for use in testing SpotExtraction.
        The envisaged scenario is an island (1) surrounded by water (0).

          Land-sea       Orography      Diagnostic

          0 0 0 0 0      0 0 0 0 0       0  1  2  3  4
          0 1 1 1 0      0 1 2 1 0       5  6  7  8  9
          0 1 1 1 0      0 2 3 2 0      10 11 12 13 14
          0 1 1 1 0      0 1 2 1 0      15 16 17 18 19
          0 0 0 0 0      0 0 0 0 0      20 21 22 23 24

        """
        # Set up diagnostic data cube and neighbour cubes.
        diagnostic_data = np.arange(25).reshape(5, 5)

        xcoord = iris.coords.DimCoord(np.linspace(0, 40, 5),
                                      standard_name='longitude',
                                      units='degrees')
        ycoord = iris.coords.DimCoord(np.linspace(0, 40, 5),
                                      standard_name='latitude',
                                      units='degrees')

        # Grid attributes must be included in diagnostic cubes so their removal
        # can be tested
        attributes = {
            'mosg__grid_domain': 'global',
            'mosg__grid_type': 'standard'
        }

        diagnostic_cube_xy = iris.cube.Cube(diagnostic_data,
                                            standard_name="air_temperature",
                                            units='K',
                                            dim_coords_and_dims=[(ycoord, 1),
                                                                 (xcoord, 0)],
                                            attributes=attributes)
        diagnostic_cube_yx = iris.cube.Cube(diagnostic_data.T,
                                            standard_name="air_temperature",
                                            units='K',
                                            dim_coords_and_dims=[(ycoord, 0),
                                                                 (xcoord, 1)],
                                            attributes=attributes)

        diagnostic_cube_hash = create_coordinate_hash(diagnostic_cube_yx)

        # neighbours, each group is for a point under two methods, e.g.
        # [ 0.  0.  0.] is the nearest point to the first spot site, whilst
        # [ 1.  1. -1.] is the nearest land point to the same site.
        neighbours = np.array([[[0., 0., 0.], [1., 1., -1.]],
                               [[0., 0., -1.], [1., 1., 0.]],
                               [[2., 2., 0.], [2., 2., 0.]],
                               [[2., 2., 1.], [2., 2., 1.]]])
        altitudes = np.array([0, 1, 3, 2])
        latitudes = np.array([10, 10, 20, 20])
        longitudes = np.array([10, 10, 20, 20])
        wmo_ids = np.arange(4)
        grid_attributes = ['x_index', 'y_index', 'vertical_displacement']
        neighbour_methods = ['nearest', 'nearest_land']
        neighbour_cube = build_spotdata_cube(
            neighbours,
            'grid_neighbours',
            1,
            altitudes,
            latitudes,
            longitudes,
            wmo_ids,
            grid_attributes=grid_attributes,
            neighbour_methods=neighbour_methods)
        neighbour_cube.attributes['model_grid_hash'] = diagnostic_cube_hash

        coordinate_cube = neighbour_cube.extract(
            iris.Constraint(neighbour_selection_method_name='nearest')
            & iris.Constraint(grid_attributes_key=['x_index', 'y_index']))
        coordinate_cube.data = np.rint(coordinate_cube.data).astype(int)

        self.latitudes = latitudes
        self.longitudes = longitudes
        self.diagnostic_cube_xy = diagnostic_cube_xy
        self.diagnostic_cube_yx = diagnostic_cube_yx
        self.neighbours = neighbours
        self.neighbour_cube = neighbour_cube
        self.coordinate_cube = coordinate_cube

        self.expected_attributes = self.diagnostic_cube_xy.attributes
        for attr in MOSG_GRID_ATTRIBUTES:
            self.expected_attributes.pop(attr, None)
        self.expected_attributes["title"] = "unknown"
        self.expected_attributes["model_grid_hash"] = (
            self.neighbour_cube.attributes['model_grid_hash'])