def _get_regrid_destination_(self): """ Prepare destination field for regridding. :rtype: :class:`~ocgis.SpatialDimension` """ # Spatially subset the regrid destination. ##################################################################### if self.subset_sdim is None: ocgis_lh(logger='regrid', msg='no spatial subsetting', level=logging.DEBUG) regrid_destination = self.field_dst else: if self.with_buffer: # Buffer the subset geometry by the resolution of the source field to improve chances of overlap between # source and destination extents. buffer_value = self.field_src.spatial.grid.resolution buffer_crs = self.field_src.spatial.crs else: buffer_value, buffer_crs = [None, None] ss = SpatialSubsetOperation(self.field_dst) regrid_destination = ss.get_spatial_subset('intersects', self.subset_sdim, use_spatial_index=env.USE_SPATIAL_INDEX, select_nearest=False, buffer_value=buffer_value, buffer_crs=buffer_crs) # Transform the coordinate system of the regrid destination. ################################################### # Update the coordinate system of the regrid destination if required. try: destination_sdim = regrid_destination.spatial except AttributeError: # Likely a spatial dimension object already. destination_sdim = regrid_destination # If switched to true, the regrid destination coordinate system must be updated to match the source. update_regrid_destination_crs = False if not isinstance(regrid_destination.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: ocgis_lh(logger='regrid', msg='updating regrid destination to spherical. regrid destination crs is: {}'.format( regrid_destination.crs), level=logging.DEBUG) destination_sdim.update_crs(Spherical()) else: destination_sdim.crs = Spherical() # Remove the mask from the destination field. ################################################################## new_mask = np.zeros(destination_sdim.shape, dtype=bool) destination_sdim.set_mask(new_mask) return destination_sdim
def test_get_spatial_subset_wrap(self): """Test subsetting with wrap set to a boolean value.""" subset_sdim = SpatialDimension.from_records([self.nebraska]) rd = self.test_data.get_rd('cancm4_tas') self.assertEqual(rd.get().spatial.wrapped_state, WrappableCoordinateReferenceSystem._flag_unwrapped) ss = SpatialSubsetOperation(rd, wrap=True) ret = ss.get_spatial_subset('intersects', subset_sdim) self.assertEqual(ret.spatial.wrapped_state, WrappableCoordinateReferenceSystem._flag_wrapped) self.assertAlmostEqual(ret.spatial.grid.value.data[1].mean(), -99.84375) # test with wrap false ss = SpatialSubsetOperation(rd, wrap=False) ret = ss.get_spatial_subset('intersects', subset_sdim) self.assertEqual(ret.spatial.wrapped_state, WrappableCoordinateReferenceSystem._flag_unwrapped) self.assertAlmostEqual(ret.spatial.grid.value.data[1].mean(), 260.15625)
def execute(self): """ Execute regridding operation. :rtype: :class:`~ocgis.Field` """ destination_sdim = self._get_regrid_destination_() self._update_regrid_source_coordinate_system_() # Regrid the input field. ocgis_lh(logger='regrid', msg='Creating regridded fields...', level=logging.INFO) regridded_source = list(iter_regridded_fields([self.field_src], destination_sdim, **self.regrid_options))[0] # Return the source field to its original coordinate system. if self._regrid_required_source_crs_update: ocgis_lh(logger='regrid', msg='Reverting source field to original coordinate system...', level=logging.INFO) regridded_source.spatial.update_crs(self._original_sfield_crs) else: regridded_source.spatial.crs = self._original_sfield_crs # Subset the output from the regrid operation as masked values may be introduced on the edges. if self.subset_sdim is not None: ss = SpatialSubsetOperation(regridded_source) regridded_source = ss.get_spatial_subset('intersects', self.subset_sdim, use_spatial_index=env.USE_SPATIAL_INDEX, select_nearest=False) return regridded_source
def test_get_spatial_subset_rotated_pole(self): """Test input has rotated pole with now output CRS.""" rd = self.rd_rotated_pole ss = SpatialSubsetOperation(rd) subset_sdim = SpatialDimension.from_records([self.germany]) ret = ss.get_spatial_subset('intersects', subset_sdim) self.assertEqual(ret.spatial.crs, rd.get().spatial.crs) self.assertAlmostEqual(ret.spatial.grid.value.data.mean(), -2.0600000000000009)
def test_get_spatial_subset_output_crs(self): """Test subsetting with an output CRS.""" # test with default crs converting to north american lambert proj4 = '+proj=aea +lat_1=20 +lat_2=60 +lat_0=40 +lon_0=-96 +x_0=0 +y_0=0 +ellps=GRS80 +datum=NAD83 +units=m +no_defs' output_crs = CoordinateReferenceSystem(proj4=proj4) subset_sdim = SpatialDimension.from_records([self.nebraska]) rd = self.test_data.get_rd('cancm4_tas') ss = SpatialSubsetOperation(rd, output_crs=output_crs) ret = ss.get_spatial_subset('intersects', subset_sdim) self.assertEqual(ret.spatial.crs, output_crs) self.assertAlmostEqual(ret.spatial.grid.value.mean(), -35065.750850951554) # test with an input rotated pole coordinate system rd = self.rd_rotated_pole ss = SpatialSubsetOperation(rd, output_crs=env.DEFAULT_COORDSYS) subset_sdim = SpatialDimension.from_records([self.germany]) ret = ss.get_spatial_subset('intersects', subset_sdim) self.assertEqual(ret.spatial.crs, env.DEFAULT_COORDSYS)
def test_get_spatial_subset_circular_geometries(self): """Test circular geometries. They were causing wrapping errors.""" geoms = TestGeom.get_geometry_dictionaries() rd = self.test_data.get_rd('cancm4_tas') ss = SpatialSubsetOperation(rd, wrap=True) buffered = [element['geom'].buffer(rd.get().spatial.grid.resolution*2) for element in geoms] for buff in buffered: record = [{'geom': buff, 'properties': {'UGID': 1}}] subset_sdim = SpatialDimension.from_records(record) ret = ss.get_spatial_subset('intersects', subset_sdim) self.assertTrue(np.all(ret.spatial.grid.extent > 0))
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