def test_iter_regridded_field_with_corners(self): """Test with_corners as True and False when regridding Fields.""" ofield = self.get_ofield() ofield.spatial.crs = Spherical() ofield2 = deepcopy(ofield) sources = [ofield, ofield2] destination_field = deepcopy(ofield) self.assertIsNotNone(destination_field.spatial.geom.polygon) for regridded in iter_regridded_fields(sources, destination_field, with_corners=False): self.assertIsNone(regridded.spatial.grid.row.bounds) self.assertIsNone(regridded.spatial.grid.col.bounds) self.assertIsNone(regridded.spatial.grid.corners) self.assertIsNone(regridded.spatial.geom.polygon) # Check that the destination grid is not modified. self.assertIsNotNone(destination_field.spatial.grid.row.bounds) # Remove corners from the destination and make sure that this is caught when with_corners is True. dest = deepcopy(destination_field).spatial dest.grid.row.remove_bounds() dest.grid.col.remove_bounds() dest.grid._corners = None self.assertIsNone(dest.grid.corners) with self.assertRaises(CornersInconsistentError): list(iter_regridded_fields(sources, dest, with_corners=True)) # If this is now false, then there should be no problem as only centroids are used. list(iter_regridded_fields(sources, dest, with_corners=False)) # This is also the case with 'auto'. list(iter_regridded_fields(sources, dest, with_corners="auto"))
def test_iter_regridded_fields(self): """Test with equivalent input and output expectations. The shapes of the grids are equal.""" ofield = self.get_ofield() ofield.spatial.crs = Spherical() ofield2 = deepcopy(ofield) sources = [ofield, ofield2] destination_field = deepcopy(ofield) keywords = dict(use_sdim=[True, False], split=[False, True]) for k in itr_products_keywords(keywords, as_namedtuple=True): if k.use_sdim: destination = destination_field.spatial sdim = destination else: destination = destination_field sdim = destination.spatial self.assertIsNotNone(sdim.grid.row) self.assertIsNotNone(sdim.grid.col) for ctr, regridded in enumerate( iter_regridded_fields(sources, destination, with_corners="auto", value_mask=None, split=k.split) ): self.assertIsInstance(regridded, Field) self.assertNumpyAll(regridded.spatial.grid.value, sdim.grid.value) self.assertEqual(regridded.spatial.crs, sdim.crs) self.assertNumpyAll(regridded.spatial.grid.row.value, sdim.grid.row.value) self.assertNumpyAll(regridded.spatial.grid.row.bounds, sdim.grid.row.bounds) self.assertNumpyAll(regridded.spatial.grid.col.value, sdim.grid.col.value) self.assertNumpyAll(regridded.spatial.grid.col.bounds, sdim.grid.col.bounds) for variable in regridded.variables.itervalues(): self.assertGreater(variable.value.mean(), 2.0) self.assertNumpyAll(variable.value, sources[ctr].variables[variable.alias].value) self.assertFalse(np.may_share_memory(variable.value, sources[ctr].variables[variable.alias].value)) self.assertEqual(ctr, 1)
def test_iter_regridded_fields_problem_bounds(self): """Test a dataset with crap bounds will work when with_corners is False.""" dst = self.test_data.get_rd("cancm4_tas").get()[:, :, :, 20:25, 30:35] dst.spatial.crs = Spherical() src = deepcopy(dst[0, 0, 0, :, :]) egrid_dst = get_esmf_grid_from_sdim(dst.spatial) egrid_src = get_esmf_grid_from_sdim(src.spatial) self.assertEqual(egrid_dst.mask[0].sum(), 25) self.assertEqual(egrid_src.mask[0].sum(), 25) self.assertNumpyAll(egrid_dst.coords[0][0], egrid_src.coords[0][0]) self.assertNumpyAll(egrid_dst.coords[0][1], egrid_src.coords[0][1]) ret = list(iter_esmf_fields(src)) self.assertEqual(len(ret), 1) variable_alias, efield, tidx = ret[0] self.assertNumpyAll(efield.grid.coords[0][0], dst.spatial.grid.value.data[1]) self.assertNumpyAll(efield.grid.coords[0][1], dst.spatial.grid.value.data[0]) ret = list(iter_regridded_fields([src], dst, with_corners=False))[0] actual = dst[0, 0, 0, :, :].variables.first().value to_test = ret.variables.first().value self.assertFalse(to_test.mask.any()) self.assertNumpyAllClose(to_test.data, actual.data) self.assertNumpyAll(to_test.mask, actual.mask)
def test_iter_regridded_fields_differing_crs(self): """Test exception raised when source and destination CRS values are not equal.""" ofield = self.get_ofield() ofield2 = deepcopy(ofield) sources = [ofield, ofield2] destination_field = deepcopy(ofield) sources[1].spatial.crs = CoordinateReferenceSystem(epsg=2136) with self.assertRaises(RegriddingError): list(iter_regridded_fields(sources, destination_field))
def test_iter_regridded_fields_value_mask(self): """Test with a value mask on the destination.""" ofield = self.get_ofield() ofield.spatial.crs = Spherical() ofield2 = deepcopy(ofield) sources = [ofield, ofield2] destination_field = deepcopy(ofield) value_mask = np.zeros(destination_field.spatial.shape, dtype=bool) value_mask[1, 1] = True for regridded in iter_regridded_fields(sources, destination_field, value_mask=value_mask): self.assertTrue(np.all(regridded.variables.first().value.mask[:, :, :, 1, 1]))
def test_iter_regridded_fields_partial_extents(self): """Test regridding with fields that partially overlap.""" rd = self.test_data.get_rd("cancm4_tas") # california and nevada coll = ocgis.OcgOperations( dataset=rd, geom="state_boundaries", select_ugid=[23, 25], snippet=True, vector_wrap=False ).execute() source = coll[25]["tas"] destination = coll[23]["tas"] source.spatial.crs = Spherical() destination.spatial.crs = Spherical() res = list(iter_regridded_fields([source], destination)) self.assertEqual(res[0].variables["tas"].value.mask.sum(), 6)
def test_iter_regridded_fields_nonoverlapping_extents(self): """Test regridding with fields that do not spatially overlap.""" rd = self.test_data.get_rd("cancm4_tas") # nebraska and california coll = ocgis.OcgOperations( dataset=rd, geom="state_boundaries", select_ugid=[16, 25], snippet=True, vector_wrap=False ).execute() source = coll[25]["tas"] destination = coll[16]["tas"] source.spatial.crs = Spherical() destination.spatial.crs = Spherical() with self.assertRaises(RegriddingError): list(iter_regridded_fields([source], destination))
def test_iter_regridded_fields_different_grid_shapes(self): """Test regridding a downscaled dataset to GCM output. The input and output grids have different shapes.""" downscaled = self.test_data.get_rd("maurer_2010_tas") downscaled.time_region = {"month": [2], "year": [1990]} downscaled = downscaled.get() poly = make_poly([37, 43], [-104, -94]) downscaled = downscaled.get_intersects(poly) downscaled.spatial.unwrap() downscaled.spatial.crs = Spherical() gcm = self.test_data.get_rd("cancm4_tas") gcm = gcm.get() poly = make_poly([37, 43], [-104 + 360, -94 + 360]) gcm = gcm.get_intersects(poly) gcm.spatial.crs = Spherical() # add masked values to the source and destination self.assertFalse(downscaled.spatial.get_mask().any()) self.assertFalse(gcm.spatial.get_mask().any()) mask = gcm.spatial.get_mask() mask[1, 3] = True gcm.spatial.set_mask(mask) desired = { "std": 3.1385237308556095, "trace": -11.13192056119442, "min": -11.858446, "max": 9.8645229, "shape": (1, 28, 1, 3, 5), "mean": 0.047387103645169008, } for regridded in iter_regridded_fields([downscaled], gcm): self.assertEqual(regridded.shape, (1, 28, 1, 3, 5)) self.assertEqual(regridded.variables.keys(), ["tas"]) self.assertDescriptivesAlmostEqual(desired, regridded.variables["tas"].value) self.assertNumpyAll(gcm.spatial.get_mask(), mask) for variable in regridded.variables.itervalues(): vmask = variable.value.mask self.assertTrue(vmask[:, :, :, 1, 3].all()) self.assertEqual(vmask.sum(), 28)
def test_iter_regridded_fields_different_grid_shapes(self): """Test regridding a downscaled dataset to GCM output. The input and output grids have different shapes.""" downscaled = self.test_data.get_rd("maurer_2010_tas") downscaled.time_region = {"month": [2], "year": [1990]} downscaled = downscaled.get() poly = make_poly([37, 43], [-104, -94]) downscaled = downscaled.get_intersects(poly) downscaled.spatial.unwrap() downscaled.spatial.crs = Spherical() gcm = self.test_data.get_rd("cancm4_tas") gcm = gcm.get() poly = make_poly([37, 43], [-104 + 360, -94 + 360]) gcm = gcm.get_intersects(poly) gcm.spatial.crs = Spherical() # add masked values to the source and destination self.assertFalse(downscaled.spatial.get_mask().any()) self.assertFalse(gcm.spatial.get_mask().any()) mask = gcm.spatial.get_mask() mask[1, 3] = True gcm.spatial.set_mask(mask) dmask = downscaled.spatial.get_mask() dmask[:] = True downscaled.spatial.set_mask(dmask) downscaled.variables.first().value.mask[:] = True for regridded in iter_regridded_fields([downscaled], gcm): self.assertEqual(regridded.shape, (1, 28, 1, 3, 5)) self.assertEqual(regridded.variables.keys(), ["tas"]) self.assertAlmostEqual(regridded.variables["tas"].value.data.mean(), 0.057409391) self.assertNumpyAll(gcm.spatial.get_mask(), mask) for variable in regridded.variables.itervalues(): vmask = variable.value.mask self.assertTrue(vmask[:, :, :, 1, 3].all()) self.assertEqual(vmask.sum(), 28)
def _get_regridded_field_with_subset_(self, sfield, subset_sdim_for_regridding=None, with_buffer=True): """ Regrid ``sfield`` subsetting the regrid destination in the process. :param sfield: The input field to regrid. :type sfield: :class:`ocgis.interface.base.field.Field` :param subset_sdim_for_regridding: The original, unaltered spatial dimension to use for subsetting. :type subset_sdim_for_regridding: :class:`ocgis.interface.base.dimension.spatial.SpatialDimension` :param bool with_buffer: If ``True``, buffer the geometry used to subset the destination grid. """ # todo: cache spatial operations on regrid destination field from ocgis.regrid.base import iter_regridded_fields from ocgis.util.spatial.spatial_subset import SpatialSubsetOperation if subset_sdim_for_regridding is None: regrid_destination = self.ops.regrid_destination else: if with_buffer: # buffer the subset geometry by the resolution of the source field to give extents a chance to be # compatible buffer_value = sfield.spatial.grid.resolution buffer_crs = sfield.spatial.crs else: buffer_value, buffer_crs = [None, None] ss = SpatialSubsetOperation(self.ops.regrid_destination) regrid_destination = ss.get_spatial_subset('intersects', subset_sdim_for_regridding, use_spatial_index=env.USE_SPATIAL_INDEX, select_nearest=False, buffer_value=buffer_value, buffer_crs=buffer_crs) original_sfield_crs = sfield.spatial.crs # check crs on the source field regrid_required_update_crs = False if not isinstance(sfield.spatial.crs, Spherical): # this as _assigned_ a WGS84 crs hence we cannot assume the default crs if isinstance(sfield.spatial.crs, WGS84) and sfield._has_assigned_coordinate_system: regrid_required_update_crs = True # the data has a coordinate system that is not WGS84 elif not isinstance(sfield.spatial.crs, WGS84): regrid_required_update_crs = True if regrid_required_update_crs: # need to load values as source indices will disappear during crs update for variable in sfield.variables.itervalues(): variable.value sfield.spatial.update_crs(Spherical()) else: sfield.spatial.crs = Spherical() # update the coordinate system of the regrid destination if required try: destination_sdim = regrid_destination.spatial except AttributeError: # likely a spatial dimension object destination_sdim = regrid_destination update_regrid_destination_crs = False if not isinstance(destination_sdim.crs, Spherical): if isinstance(regrid_destination, Field): if isinstance(destination_sdim.crs, WGS84) and regrid_destination._has_assigned_coordinate_system: update_regrid_destination_crs = True elif isinstance(destination_sdim.crs, WGS84) and not regrid_destination._has_assigned_coordinate_system: pass else: update_regrid_destination_crs = True else: if not isinstance(destination_sdim.crs, Spherical): update_regrid_destination_crs = True if update_regrid_destination_crs: destination_sdim.update_crs(Spherical()) else: destination_sdim.crs = Spherical() # check that wrapping is equivalent if destination_sdim.wrapped_state == WrappableCoordinateReferenceSystem._flag_unwrapped: if sfield.spatial.wrapped_state == WrappableCoordinateReferenceSystem._flag_wrapped: sfield.spatial = deepcopy(sfield.spatial) sfield.spatial.unwrap() if destination_sdim.wrapped_state == WrappableCoordinateReferenceSystem._flag_wrapped: if sfield.spatial.wrapped_state == WrappableCoordinateReferenceSystem._flag_unwrapped: sfield.spatial = deepcopy(sfield.spatial) sfield.spatial.wrap() # remove the mask from the destination field. new_mask = np.zeros(destination_sdim.shape, dtype=bool) destination_sdim.set_mask(new_mask) # regrid the input fields. sfield = list(iter_regridded_fields([sfield], destination_sdim, **self.ops.regrid_options))[0] if regrid_required_update_crs: sfield.spatial.update_crs(original_sfield_crs) else: sfield.spatial.crs = original_sfield_crs # subset the output from the regrid operation as masked values may be introduced on the edges if subset_sdim_for_regridding is not None: ss = SpatialSubsetOperation(sfield) sfield = ss.get_spatial_subset('intersects', subset_sdim_for_regridding, use_spatial_index=env.USE_SPATIAL_INDEX, select_nearest=False) return sfield