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 = RegridLandSea()(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_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 = RegridLandSea()(self.cube, 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 = RegridLandSea()(self.cube, self.target_grid, regridded_title=new_title) self.assertDictEqual(result.attributes, expected_attributes)
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 = RegridLandSea(regrid_mode="nearest-with-mask", landmask=landmask, landmask_vicinity=90000) msg = "Source landmask does not match input grid" with self.assertRaisesRegex(ValueError, msg): plugin(self.cube, self.target_grid)
def test_access_regrid_with_landmask(self): """Test the AdjustLandSeaPoints module is correctly called when using landmask arguments. Diagnosed by identifiable error.""" msg = "Distance of 1000m gives zero cell extent" with self.assertRaisesRegex(ValueError, msg): RegridLandSea( regrid_mode="nearest-with-mask", landmask=self.landmask, landmask_vicinity=1000, )(self.cube, self.target_grid)
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 = RegridLandSea( regrid_mode="nearest-with-mask", landmask=self.landmask, landmask_vicinity=90000, )(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_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 = RegridLandSea( regrid_mode="nearest-with-mask", landmask=self.landmask, landmask_vicinity=90000, )(self.cube, 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 process( cube: cli.inputcube, target_grid: cli.inputcube, land_sea_mask: cli.inputcube = None, *, regrid_mode="bilinear", extrapolation_mode="nanmask", land_sea_mask_vicinity: float = 25000, regridded_title: str = None, ): """Regrids source cube data onto a target grid. Optional land-sea awareness. Args: cube (iris.cube.Cube): Source cube to be regridded. target_grid (iris.cube.Cube): Cube defining the spatial grid onto which to regrid the source data. If also using land_sea_mask-aware regridding then this must be land_binary_mask data. land_sea_mask (iris.cube.Cube): Cube describing the land_binary_mask on the source grid if land-sea aware regridding is required, with land points set to one and sea points set to zero. regrid_mode (str): Selects which regridding techniques to use. Default uses iris.analysis.Linear(); "nearest" uses iris.analysis.Nearest(); "nearest-with-mask" uses Nearest() with land-sea awareness. 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. 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 RegridLandSea 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) return RegridLandSea( regrid_mode=regrid_mode, extrapolation_mode=extrapolation_mode, landmask=land_sea_mask, landmask_vicinity=land_sea_mask_vicinity, )(cube, target_grid, regridded_title=regridded_title)
def test_error_missing_landmask(self): """Test an error is thrown if no landmask is provided where required""" msg = "requires an input landmask cube" with self.assertRaisesRegex(ValueError, msg): RegridLandSea(regrid_mode="nearest-with-mask")
def test_error_unrecognised_regrid_mode(self): """Test error is thrown if regrid mode is not in expected values list""" msg = "Unrecognised regrid mode" with self.assertRaisesRegex(ValueError, msg): RegridLandSea(regrid_mode="kludge")
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 = RegridLandSea()(self.cube, self.target_grid) self.assertNotIn("mosg__grid_domain", result.attributes)