def test_incorrect_grid_attributes_removed(self):
     """Test grid attributes not present on the target cube are removed
     after regridding"""
     self.target_grid.attributes.pop("mosg__grid_domain")
     result = StandardiseGridAndMetadata().process(
         self.cube, target_grid=self.target_grid)
     self.assertNotIn("mosg__grid_domain", result.attributes)
 def test_default(self):
     """Test initialisation with default options"""
     plugin = StandardiseGridAndMetadata()
     self.assertEqual(plugin.regrid_mode, 'bilinear')
     self.assertEqual(plugin.extrapolation_mode, 'nanmask')
     self.assertIsNone(plugin.landmask_source_grid)
     self.assertIsNone(plugin.landmask_vicinity)
     self.assertEqual(plugin.landmask_name, 'land_binary_mask')
 def test_error_regrid_with_incorrect_landmask(self):
     """Test an error is thrown if a landmask is provided that does not
     match the source grid"""
     landmask = self.target_grid.copy()
     plugin = StandardiseGridAndMetadata(regrid_mode='nearest-with-mask',
                                         landmask=landmask,
                                         landmask_vicinity=90000)
     msg = "Source landmask does not match input grid"
     with self.assertRaisesRegex(ValueError, msg):
         plugin.process(self.cube, target_grid=self.target_grid)
 def test_access_regrid_with_landmask(self):
     """Test the RegridLandAndSea module is correctly called when using
     landmask arguments. Diagnosed by identifiable error."""
     msg = "Distance of 10000m gives zero cell extent"
     with self.assertRaisesRegex(ValueError, msg):
         StandardiseGridAndMetadata(regrid_mode='nearest-with-mask',
                                    landmask=self.landmask,
                                    landmask_vicinity=10000).process(
                                        self.cube,
                                        target_grid=self.target_grid)
 def setUp(self):
     """Set up input cube"""
     self.cube = set_up_variable_cube(
         282 * np.ones((5, 5), dtype=np.float32),
         spatial_grid='latlon',
         standard_grid_metadata='gl_det',
         time=datetime(2019, 10, 11),
         time_bounds=[datetime(2019, 10, 10, 23),
                      datetime(2019, 10, 11)],
         frt=datetime(2019, 10, 10, 18))
     self.plugin = StandardiseGridAndMetadata()
 def test_attribute_changes_with_regridding(self):
     """Test attributes inherited on regridding"""
     expected_attributes = self.cube.attributes
     expected_attributes["title"] = MANDATORY_ATTRIBUTE_DEFAULTS["title"]
     for attr in [
             "mosg__grid_domain", "mosg__grid_type", "mosg__grid_version"
     ]:
         expected_attributes[attr] = self.target_grid.attributes[attr]
     result = StandardiseGridAndMetadata().process(
         self.cube, target_grid=self.target_grid)
     self.assertDictEqual(result.attributes, expected_attributes)
 def test_new_title(self):
     """Test new title can be set on regridding"""
     new_title = "Global Model Forecast on UK 2km Standard Grid"
     expected_attributes = self.cube.attributes
     expected_attributes["title"] = new_title
     for attr in [
             "mosg__grid_domain", "mosg__grid_type", "mosg__grid_version"
     ]:
         expected_attributes[attr] = self.target_grid.attributes[attr]
     result = StandardiseGridAndMetadata().process(
         self.cube, target_grid=self.target_grid, regridded_title=new_title)
     self.assertDictEqual(result.attributes, expected_attributes)
 def test_warning_source_not_landmask(self, warning_list=None):
     """Test warning is raised if landmask_source_grid is not a landmask"""
     expected_data = 282 * np.ones((12, 12), dtype=np.float32)
     self.landmask.rename("not_a_landmask")
     result = StandardiseGridAndMetadata(regrid_mode='nearest-with-mask',
                                         landmask=self.landmask,
                                         landmask_vicinity=90000).process(
                                             self.cube,
                                             target_grid=self.target_grid)
     msg = "Expected land_binary_mask in input_landmask cube"
     self.assertTrue(any([msg in str(warning) for warning in warning_list]))
     self.assertTrue(
         any(item.category == UserWarning for item in warning_list))
     self.assertArrayAlmostEqual(result.data, expected_data)
 def test_attribute_changes_after_regridding(self):
     """Test attributes can be manually updated after regridding"""
     attribute_changes = {
         "institution": "Met Office",
         "mosg__grid_version": "remove"
     }
     expected_attributes = {
         "mosg__grid_domain": "uk_extended",
         "mosg__grid_type": "standard",
         "mosg__model_configuration": "gl_det",
         "institution": "Met Office",
         "title": MANDATORY_ATTRIBUTE_DEFAULTS["title"]
     }
     result = StandardiseGridAndMetadata().process(
         self.cube,
         target_grid=self.target_grid,
         attributes_dict=attribute_changes)
     self.assertDictEqual(result.attributes, expected_attributes)
 def test_basic_regrid(self):
     """Test default regridding arguments return expected dimensionality
     and updated grid-defining attributes"""
     expected_data = 282 * np.ones((12, 12), dtype=np.float32)
     expected_attributes = {
         "mosg__model_configuration": "gl_det",
         "title": MANDATORY_ATTRIBUTE_DEFAULTS["title"]
     }
     for attr in [
             "mosg__grid_domain", "mosg__grid_type", "mosg__grid_version"
     ]:
         expected_attributes[attr] = self.target_grid.attributes[attr]
     result = StandardiseGridAndMetadata().process(self.cube,
                                                   self.target_grid.copy())
     self.assertArrayAlmostEqual(result.data, expected_data)
     for axis in ['x', 'y']:
         self.assertEqual(result.coord(axis=axis),
                          self.target_grid.coord(axis=axis))
     self.assertDictEqual(result.attributes, expected_attributes)
 def test_run_regrid_with_landmask(self):
     """Test masked regridding (same expected values as basic, since input
     points are all equal)"""
     expected_data = 282 * np.ones((12, 12), dtype=np.float32)
     expected_attributes = {
         "mosg__model_configuration": "gl_det",
         "title": MANDATORY_ATTRIBUTE_DEFAULTS["title"]
     }
     for attr in [
             "mosg__grid_domain", "mosg__grid_type", "mosg__grid_version"
     ]:
         expected_attributes[attr] = self.target_grid.attributes[attr]
     result = StandardiseGridAndMetadata(
         regrid_mode='nearest-with-mask',
         landmask=self.landmask,
         landmask_vicinity=90000).process(
             self.cube, target_grid=self.target_grid.copy())
     self.assertArrayAlmostEqual(result.data, expected_data)
     for axis in ['x', 'y']:
         self.assertEqual(result.coord(axis=axis),
                          self.target_grid.coord(axis=axis))
     self.assertDictEqual(result.attributes, expected_attributes)
Пример #12
0
def process(cube: cli.inputcube,
            target_grid: cli.inputcube = None,
            land_sea_mask: cli.inputcube = None,
            *,
            regrid_mode='bilinear',
            extrapolation_mode='nanmask',
            land_sea_mask_vicinity: float = 25000,
            regridded_title: str = None,
            attributes_config: cli.inputjson = None,
            coords_to_remove: cli.comma_separated_list = None,
            new_name: str = None,
            new_units: str = None,
            fix_float64=False):
    """Standardises a cube by one or more of regridding, updating meta-data etc

    Standardise a source cube. Available options are regridding (bi-linear or
    nearest-neighbour, optionally with land-mask awareness), renaming,
    converting units, updating attributes and / or converting float64 data to
    float32.

    Args:
        cube (iris.cube.Cube):
            Source cube to be standardised
        target_grid (iris.cube.Cube):
            If specified, then regridding of the source against the target
            grid is enabled. If also using land_sea_mask-aware regridding then
            this must be land_binary_mask data.
        land_sea_mask (iris.cube.Cube):
            A cube describing the land_binary_mask on the source-grid if
            coastline-aware regridding is required.
        regrid_mode (str):
            Selects which regridding techniques to use. Default uses
            iris.analysis.Linear(); "nearest" uses Nearest() (for less
            continuous fields, e.g precipitation); "nearest-with-mask"
            ensures that target data are sources from points with the same
            mask value (for coast-line-dependant variables like temperature).
        extrapolation_mode (str):
            Mode to use for extrapolating data into regions beyond the limits
            of the input cube domain. Refer to online documentation for
            iris.analysis.
            Modes are -
            extrapolate - extrapolated points will take their values from the
            nearest source point
            nan - extrapolated points will be set to NaN
            error - a ValueError will be raised notifying an attempt to
            extrapolate
            mask - extrapolated points will always be masked, even if
            the source data is not a MaskedArray
            nanmask - if the source data is a MaskedArray extrapolated points
            will be masked; otherwise they will be set to NaN
        land_sea_mask_vicinity (float):
            Radius of vicinity to search for a coastline, in metres.
        regridded_title (str):
            New "title" attribute to be set if the field is being regridded
            (since "title" may contain grid information). If None, a default
            value is used.
        attributes_config (dict):
            Dictionary containing required changes that will be applied to
            the attributes.
        coords_to_remove (list):
            List of names of scalar coordinates to remove.
        new_name (str):
            Name of output cube.
        new_units (str):
            Units to convert to.
        fix_float64 (bool):
            If True, checks and fixes cube for float64 data. Without this
            option an exception will be raised if float64 data is found but no
            fix applied.

    Returns:
        iris.cube.Cube:
            Processed cube.

    Raises:
        ValueError:
            If source land_sea_mask is supplied but regrid mode is not
            "nearest-with-mask".
        ValueError:
            If regrid_mode is "nearest-with-mask" but no source land_sea_mask
            is provided (from plugin).
    """
    from improver.standardise import StandardiseGridAndMetadata

    if (land_sea_mask and
            "nearest-with-mask" not in regrid_mode):
        msg = ("Land-mask file supplied without appropriate regrid-mode. "
               "Use --regrid-mode nearest-with-mask.")
        raise ValueError(msg)

    plugin = StandardiseGridAndMetadata(
        regrid_mode=regrid_mode, extrapolation_mode=extrapolation_mode,
        landmask=land_sea_mask,
        landmask_vicinity=land_sea_mask_vicinity)
    output_data = plugin.process(
        cube, target_grid, new_name=new_name, new_units=new_units,
        regridded_title=regridded_title, coords_to_remove=coords_to_remove,
        attributes_dict=attributes_config, fix_float64=fix_float64)

    return output_data
 def test_error_missing_landmask(self):
     """Test an error is thrown if no mask is provided for masked
     regridding"""
     msg = "requires an input landmask cube"
     with self.assertRaisesRegex(ValueError, msg):
         StandardiseGridAndMetadata(regrid_mode='nearest-with-mask')