Example #1
0
    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
Example #2
0
    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
Example #3
0
    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)
Example #4
0
    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))
Example #5
0
    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)
Example #6
0
    def test_get_buffered_subset_sdim(self):
        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'
        buffer_crs_list = [None, CoordinateReferenceSystem(proj4=proj4)]
        poly = make_poly((36, 44), (-104, -95))

        for buffer_crs in buffer_crs_list:
            subset_sdim = SpatialDimension.from_records([{'geom': poly, 'properties': {'UGID': 1}}], crs=CFWGS84())
            self.assertEqual(subset_sdim.crs, CFWGS84())
            if buffer_crs is None:
                buffer_value = 1
            else:
                buffer_value = 10

            ret = SpatialSubsetOperation._get_buffered_subset_sdim_(subset_sdim, buffer_value, buffer_crs=buffer_crs)
            ref = ret.geom.polygon.value[0, 0]

            if buffer_crs is None:
                self.assertEqual(ref.bounds, (-105.0, 35.0, -94.0, 45.0))
            else:
                self.assertNumpyAllClose(np.array(ref.bounds), np.array((-104.00013263459613, 35.9999147913708, -94.99986736540386, 44.00008450528758)))
            self.assertEqual(subset_sdim.crs, ret.crs)

            # check deepcopy
            ret.geom.polygon.value[0, 0] = make_poly((1, 2), (3, 4))
            ref_buffered = ret.geom.polygon.value[0, 0]
            ref_original = subset_sdim.geom.polygon.value[0, 0]
            with self.assertRaises(AssertionError):
                self.assertNumpyAllClose(np.array(ref_buffered.bounds), np.array(ref_original.bounds))
Example #7
0
    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)
Example #8
0
    def test_prepare_subset_sdim(self):
        for subset_sdim in self.get_subset_sdim():
            for ss, k in self:
                try:
                    prepared = ss._prepare_subset_sdim_(subset_sdim)
                    # check that a deepcopy has occurred
                    self.assertFalse(np.may_share_memory(prepared.uid, subset_sdim.uid))
                except KeyError:
                    # the target has a rotated pole coordinate system. transformations to rotated pole for the subset
                    # geometry is not supported.
                    if isinstance(ss.sdim.crs, CFRotatedPole):
                        continue
                    else:
                        raise
                self.assertEqual(prepared.crs, ss.sdim.crs)

        # test nebraska against an unwrapped dataset specifically
        nebraska = SpatialDimension.from_records([self.nebraska])
        field = self.test_data.get_rd('cancm4_tas').get()
        ss = SpatialSubsetOperation(field)
        prepared = ss._prepare_subset_sdim_(nebraska)
        self.assertEqual(prepared.wrapped_state, WrappableCoordinateReferenceSystem._flag_unwrapped)
Example #9
0
    def test_get_should_wrap(self):
        # a 360 dataset
        field_360 = self.test_data.get_rd('cancm4_tas').get()
        ss = SpatialSubsetOperation(field_360, wrap=True)
        self.assertTrue(ss._get_should_wrap_(ss.target))
        ss = SpatialSubsetOperation(field_360, wrap=False)
        self.assertFalse(ss._get_should_wrap_(ss.target))
        ss = SpatialSubsetOperation(field_360, wrap=None)
        self.assertFalse(ss._get_should_wrap_(ss.target))

        # wrapped dataset
        field_360.spatial.wrap()
        ss = SpatialSubsetOperation(field_360, wrap=True)
        self.assertFalse(ss._get_should_wrap_(ss.target))
        ss = SpatialSubsetOperation(field_360, wrap=False)
        self.assertFalse(ss._get_should_wrap_(ss.target))
        ss = SpatialSubsetOperation(field_360, wrap=None)
        self.assertFalse(ss._get_should_wrap_(ss.target))
Example #10
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