def setUp(self):
        # Load a source cube, then generate an interpolator instance, calculate
        # the interpolation weights and set up a target grid.
        self.cube = stock.simple_2d()
        x_points = self.cube.coord('bar').points
        y_points = self.cube.coord('foo').points
        self.interpolator = _RegularGridInterpolator([x_points, y_points],
                                                     self.cube.data,
                                                     method='linear',
                                                     bounds_error=False,
                                                     fill_value=None)
        newx = x_points + 0.7
        newy = y_points + 0.7

        d_0 = self.cube.data[0, 0]
        d_1 = self.cube.data[0, 1]
        d_2 = self.cube.data[1, 0]
        d_3 = self.cube.data[1, 1]
        px_0, px_1 = x_points[0], x_points[1]
        py_0, py_1 = y_points[0], y_points[1]
        px_t = px_0 + 0.7
        py_t = py_0 + 0.7
        dyt_0 = self._interpolate_point(py_t, py_0, py_1, d_0, d_1)
        dyt_1 = self._interpolate_point(py_t, py_0, py_1, d_2, d_3)
        self.test_increment = self._interpolate_point(px_t, px_0, px_1,
                                                      dyt_0, dyt_1)

        xv, yv = np.meshgrid(newy, newx)
        self.tgrid = np.dstack((yv, xv))
        self.weights = self.interpolator.compute_interp_weights(self.tgrid)
예제 #2
0
    def setUp(self):
        # Load a source cube, then generate an interpolator instance, calculate
        # the interpolation weights and set up a target grid.
        self.cube = stock.simple_2d()
        x_points = self.cube.coord("bar").points
        y_points = self.cube.coord("foo").points
        self.interpolator = _RegularGridInterpolator(
            [x_points, y_points],
            self.cube.data,
            method="linear",
            bounds_error=False,
            fill_value=None,
        )
        newx = x_points + 0.7
        newy = y_points + 0.7

        d_0 = self.cube.data[0, 0]
        d_1 = self.cube.data[0, 1]
        d_2 = self.cube.data[1, 0]
        d_3 = self.cube.data[1, 1]
        px_0, px_1 = x_points[0], x_points[1]
        py_0, py_1 = y_points[0], y_points[1]
        px_t = px_0 + 0.7
        py_t = py_0 + 0.7
        dyt_0 = self._interpolate_point(py_t, py_0, py_1, d_0, d_1)
        dyt_1 = self._interpolate_point(py_t, py_0, py_1, d_2, d_3)
        self.test_increment = self._interpolate_point(
            px_t, px_0, px_1, dyt_0, dyt_1
        )

        xv, yv = np.meshgrid(newy, newx)
        self.tgrid = np.dstack((yv, xv))
        self.weights = self.interpolator.compute_interp_weights(self.tgrid)
예제 #3
0
    def _interpolate(self, data, interp_points):
        """
        Interpolate a data array over N dimensions.

        Create and cache the underlying interpolator instance before invoking
        it to perform interpolation over the data at the given coordinate point
        values.

        * data (ndarray):
            A data array, to be interpolated in its first 'N' dimensions.

        * interp_points (ndarray):
            An array of interpolation coordinate values.
            Its shape is (..., N) where N is the number of interpolation
            dimensions.
            "interp_points[..., i]" are interpolation point values for the i'th
            coordinate, which is mapped to the i'th data dimension.
            The other (leading) dimensions index over the different required
            sample points.

        Returns:

            A :class:`np.ndarray`.  Its shape is "points_shape + extra_shape",
            where "extra_shape" is the remaining non-interpolated dimensions of
            the data array (i.e. 'data.shape[N:]'), and "points_shape" is the
            leading dimensions of interp_points,
            (i.e. 'interp_points.shape[:-1]').

        """
        dtype = self._interpolated_dtype(data.dtype)
        if data.dtype != dtype:
            # Perform dtype promotion.
            data = data.astype(dtype)

        if self._interpolator is None:
            # Cache the interpolator instance.
            bounds_error, fill_value = _LINEAR_EXTRAPOLATION_MODES[self._mode]
            self._interpolator = _RegularGridInterpolator(self._src_points,
                                                          data,
                                                          bounds_error=False,
                                                          fill_value=None)
            # The constructor of the _RegularGridInterpolator class does
            # some unnecessary checks on these values, so we set them
            # afterwards instead. Sneaky. ;-)
            self._interpolator.bounds_error = bounds_error
            self._interpolator.fill_value = fill_value
        else:
            self._interpolator.values = data

        result = self._interpolator(interp_points)

        if result.dtype != data.dtype:
            # Cast the data dtype to be as expected. Note that, the dtype
            # of the interpolated result is influenced by the dtype of the
            # interpolation points.
            result = result.astype(data.dtype)

        return result
예제 #4
0
    def _interpolate(self, data, interp_points):
        """
        Interpolate a data array over N dimensions.

        Create and cache the underlying interpolator instance before invoking
        it to perform interpolation over the data at the given coordinate point
        values.

        * data (ndarray):
            A data array, to be interpolated in its first 'N' dimensions.

        * interp_points (ndarray):
            An array of interpolation coordinate values.
            Its shape is (..., N) where N is the number of interpolation
            dimensions.
            "interp_points[..., i]" are interpolation point values for the i'th
            coordinate, which is mapped to the i'th data dimension.
            The other (leading) dimensions index over the different required
            sample points.

        Returns:

            A :class:`np.ndarray`.  Its shape is "points_shape + extra_shape",
            where "extra_shape" is the remaining non-interpolated dimensions of
            the data array (i.e. 'data.shape[N:]'), and "points_shape" is the
            leading dimensions of interp_points,
            (i.e. 'interp_points.shape[:-1]').

        """
        dtype = self._interpolated_dtype(data.dtype)
        if data.dtype != dtype:
            # Perform dtype promotion.
            data = data.astype(dtype)

        if self._interpolator is None:
            # Cache the interpolator instance.
            self._interpolator = _RegularGridInterpolator(self._src_points,
                                                          data,
                                                          bounds_error=False,
                                                          fill_value=None)
            # The constructor of the _RegularGridInterpolator class does
            # some unnecessary checks on these values, so we set them
            # afterwards instead. Sneaky. ;-)
            bounds_error, fill_value = _LINEAR_EXTRAPOLATION_MODES[self._mode]
            self._interpolator.bounds_error = bounds_error
            self._interpolator.fill_value = fill_value
        else:
            self._interpolator.values = data

        result = self._interpolator(interp_points)

        if result.dtype != data.dtype:
            # Cast the data dtype to be as expected. Note that, the dtype
            # of the interpolated result is influenced by the dtype of the
            # interpolation points.
            result = result.astype(data.dtype)

        return result
예제 #5
0
파일: _regrid.py 프로젝트: Jozhogg/iris
    def _regrid(src_data, x_dim, y_dim,
                src_x_coord, src_y_coord,
                sample_grid_x, sample_grid_y,
                method='linear', extrapolation_mode='nanmask'):
        """
        Regrid the given data from the src grid to the sample grid.

        The result will be a MaskedArray if either/both of:
         - the source array is a MaskedArray,
         - the extrapolation_mode is 'mask' and the result requires
           extrapolation.

        If the result is a MaskedArray the mask for each element will be set
        if either/both of:
         - there is a non-zero contribution from masked items in the input data
         - the element requires extrapolation and the extrapolation_mode
           dictates a masked value.

        Args:

        * src_data:
            An N-dimensional NumPy array or MaskedArray.
        * x_dim:
            The X dimension within `src_data`.
        * y_dim:
            The Y dimension within `src_data`.
        * src_x_coord:
            The X :class:`iris.coords.DimCoord`.
        * src_y_coord:
            The Y :class:`iris.coords.DimCoord`.
        * sample_grid_x:
            A 2-dimensional array of sample X values.
        * sample_grid_y:
            A 2-dimensional array of sample Y values.

        Kwargs:

        * method:
            Either 'linear' or 'nearest'. The default method is 'linear'.
        * extrapolation_mode:
            Must be one of the following strings:

              * 'linear' - The extrapolation points will be calculated by
                extending the gradient of the closest two points.
              * 'nan' - The extrapolation points will be be set to NaN.
              * 'error' - A ValueError exception will be raised, notifying an
                attempt to extrapolate.
              * 'mask' - The extrapolation points will always be masked, even
                if the source data is not a MaskedArray.
              * 'nanmask' - If the source data is a MaskedArray the
                extrapolation points will be masked. Otherwise they will be
                set to NaN.

            The default mode of extrapolation is 'nanmask'.

        Returns:
            The regridded data as an N-dimensional NumPy array. The lengths
            of the X and Y dimensions will now match those of the sample
            grid.

        """
        #
        # XXX: At the moment requires to be a static method as used by
        # experimental regrid_area_weighted_rectilinear_src_and_grid
        #
        if sample_grid_x.shape != sample_grid_y.shape:
            raise ValueError('Inconsistent sample grid shapes.')
        if sample_grid_x.ndim != 2:
            raise ValueError('Sample grid must be 2-dimensional.')

        # Prepare the result data array
        shape = list(src_data.shape)
        assert shape[x_dim] == src_x_coord.shape[0]
        assert shape[y_dim] == src_y_coord.shape[0]

        shape[y_dim] = sample_grid_x.shape[0]
        shape[x_dim] = sample_grid_x.shape[1]

        # If we're given integer values, convert them to the smallest
        # possible float dtype that can accurately preserve the values.
        dtype = src_data.dtype
        if dtype.kind == 'i':
            dtype = np.promote_types(dtype, np.float16)

        if isinstance(src_data, ma.MaskedArray):
            data = ma.empty(shape, dtype=dtype)
            data.mask = np.zeros(data.shape, dtype=np.bool)
        else:
            data = np.empty(shape, dtype=dtype)

        # The interpolation class requires monotonically increasing
        # coordinates, so flip the coordinate(s) and data if the aren't.
        reverse_x = src_x_coord.points[0] > src_x_coord.points[1]
        reverse_y = src_y_coord.points[0] > src_y_coord.points[1]
        flip_index = [slice(None)] * src_data.ndim
        if reverse_x:
            src_x_coord = src_x_coord[::-1]
            flip_index[x_dim] = slice(None, None, -1)
        if reverse_y:
            src_y_coord = src_y_coord[::-1]
            flip_index[y_dim] = slice(None, None, -1)
        src_data = src_data[tuple(flip_index)]

        if src_x_coord.circular:
            x_points, src_data = extend_circular_coord_and_data(src_x_coord,
                                                                src_data,
                                                                x_dim)
        else:
            x_points = src_x_coord.points

        # Slice out the first full 2D piece of data for construction of the
        # interpolator.
        index = [0] * src_data.ndim
        index[x_dim] = index[y_dim] = slice(None)
        initial_data = src_data[tuple(index)]
        if y_dim < x_dim:
            initial_data = initial_data.T

        # Construct the interpolator, we will fill in any values out of bounds
        # manually.
        interpolator = _RegularGridInterpolator([x_points, src_y_coord.points],
                                                initial_data, method=method,
                                                bounds_error=False,
                                                fill_value=None)
        # The constructor of the _RegularGridInterpolator class does
        # some unnecessary checks on these values, so we set them
        # afterwards instead. Sneaky. ;-)
        try:
            mode = EXTRAPOLATION_MODES[extrapolation_mode]
        except KeyError:
            raise ValueError('Invalid extrapolation mode.')
        interpolator.bounds_error = mode.bounds_error
        interpolator.fill_value = mode.fill_value

        # Construct the target coordinate points array, suitable for passing to
        # the interpolator multiple times.
        interp_coords = [sample_grid_x.astype(np.float64)[..., np.newaxis],
                         sample_grid_y.astype(np.float64)[..., np.newaxis]]

        # Map all the requested values into the range of the source
        # data (centred over the centre of the source data to allow
        # extrapolation where required).
        min_x, max_x = x_points.min(), x_points.max()
        min_y, max_y = src_y_coord.points.min(), src_y_coord.points.max()
        if src_x_coord.units.modulus:
            modulus = src_x_coord.units.modulus
            offset = (max_x + min_x - modulus) * 0.5
            interp_coords[0] -= offset
            interp_coords[0] = (interp_coords[0] % modulus) + offset

        interp_coords = np.dstack(interp_coords)

        def interpolate(data):
            # Update the interpolator for this data slice.
            data = data.astype(interpolator.values.dtype)
            if y_dim < x_dim:
                data = data.T
            interpolator.values = data
            data = interpolator(interp_coords)
            if y_dim > x_dim:
                data = data.T
            return data

        # Build up a shape suitable for passing to ndindex, inside the loop we
        # will insert slice(None) on the data indices.
        iter_shape = list(shape)
        iter_shape[x_dim] = iter_shape[y_dim] = 1

        # Iterate through each 2d slice of the data, updating the interpolator
        # with the new data as we go.
        for index in np.ndindex(tuple(iter_shape)):
            index = list(index)
            index[x_dim] = index[y_dim] = slice(None)

            src_subset = src_data[tuple(index)]
            interpolator.fill_value = mode.fill_value
            data[tuple(index)] = interpolate(src_subset)

            if isinstance(data, ma.MaskedArray) or mode.force_mask:
                # NB. np.ma.getmaskarray returns an array of `False` if
                # `src_subset` is not a masked array.
                src_mask = np.ma.getmaskarray(src_subset)
                interpolator.fill_value = mode.mask_fill_value
                mask_fraction = interpolate(src_mask)
                new_mask = (mask_fraction > 0)

                if np.ma.isMaskedArray(data):
                    data.mask[tuple(index)] = new_mask
                elif np.any(new_mask):
                    # Set mask=False to ensure we have an expanded mask array.
                    data = np.ma.MaskedArray(data, mask=False)
                    data.mask[tuple(index)] = new_mask

        return data
예제 #6
0
파일: _linear.py 프로젝트: ckmo/iris
    def _interpolate(self, data, interp_points):
        """
        Interpolate a data array over N dimensions.

        Create and cache the underlying interpolator instance before invoking
        it to perform interpolation over the data at the given coordinate point
        values.

        * data (ndarray):
            A data array, to be interpolated in its first 'N' dimensions.

        * interp_points (ndarray):
            An array of interpolation coordinate values.
            Its shape is (..., N) where N is the number of interpolation
            dimensions.
            "interp_points[..., i]" are interpolation point values for the i'th
            coordinate, which is mapped to the i'th data dimension.
            The other (leading) dimensions index over the different required
            sample points.

        Returns:

            A :class:`np.ndarray`.  Its shape is "points_shape + extra_shape",
            where "extra_shape" is the remaining non-interpolated dimensions of
            the data array (i.e. 'data.shape[N:]'), and "points_shape" is the
            leading dimensions of interp_points,
            (i.e. 'interp_points.shape[:-1]').

        """
        dtype = self._interpolated_dtype(data.dtype)
        if data.dtype != dtype:
            # Perform dtype promotion.
            data = data.astype(dtype)

        mode = _LINEAR_EXTRAPOLATION_MODES[self._mode]
        if self._interpolator is None:
            # Cache the interpolator instance.
            # NB. The constructor of the _RegularGridInterpolator class does
            # some unnecessary checks on the fill_value parameter,
            # so we set it afterwards instead. Sneaky. ;-)
            self._interpolator = _RegularGridInterpolator(
                self._src_points, data, bounds_error=mode.bounds_error,
                fill_value=None)
        else:
            self._interpolator.values = data

        # We may be re-using a cached interpolator, so ensure the fill
        # value is set appropriately for extrapolating data values.
        self._interpolator.fill_value = mode.fill_value
        result = self._interpolator(interp_points)

        if result.dtype != data.dtype:
            # Cast the data dtype to be as expected. Note that, the dtype
            # of the interpolated result is influenced by the dtype of the
            # interpolation points.
            result = result.astype(data.dtype)

        if np.ma.isMaskedArray(data) or mode.force_mask:
            # NB. np.ma.getmaskarray returns an array of `False` if
            # `data` is not a masked array.
            src_mask = np.ma.getmaskarray(data)
            # Switch the extrapolation to work with mask values.
            self._interpolator.fill_value = mode.mask_fill_value
            self._interpolator.values = src_mask
            mask_fraction = self._interpolator(interp_points)
            new_mask = (mask_fraction > 0)
            if isinstance(data, ma.MaskedArray) or np.any(new_mask):
                result = np.ma.MaskedArray(result, new_mask)

        return result
예제 #7
0
파일: _regrid.py 프로젝트: cpelley/iris
    def _regrid(src_data,
                x_dim,
                y_dim,
                src_x_coord,
                src_y_coord,
                sample_grid_x,
                sample_grid_y,
                method='linear',
                extrapolation_mode='nanmask'):
        """
        Regrid the given data from the src grid to the sample grid.

        The result will be a MaskedArray if either/both of:
         - the source array is a MaskedArray,
         - the extrapolation_mode is 'mask' and the result requires
           extrapolation.

        If the result is a MaskedArray the mask for each element will be set
        if either/both of:
         - there is a non-zero contribution from masked items in the input data
         - the element requires extrapolation and the extrapolation_mode
           dictates a masked value.

        Args:

        * src_data:
            An N-dimensional NumPy array or MaskedArray.
        * x_dim:
            The X dimension within `src_data`.
        * y_dim:
            The Y dimension within `src_data`.
        * src_x_coord:
            The X :class:`iris.coords.DimCoord`.
        * src_y_coord:
            The Y :class:`iris.coords.DimCoord`.
        * sample_grid_x:
            A 2-dimensional array of sample X values.
        * sample_grid_y:
            A 2-dimensional array of sample Y values.

        Kwargs:

        * method:
            Either 'linear' or 'nearest'. The default method is 'linear'.
        * extrapolation_mode:
            Must be one of the following strings:

              * 'linear' - The extrapolation points will be calculated by
                extending the gradient of the closest two points.
              * 'nan' - The extrapolation points will be be set to NaN.
              * 'error' - A ValueError exception will be raised, notifying an
                attempt to extrapolate.
              * 'mask' - The extrapolation points will always be masked, even
                if the source data is not a MaskedArray.
              * 'nanmask' - If the source data is a MaskedArray the
                extrapolation points will be masked. Otherwise they will be
                set to NaN.

            The default mode of extrapolation is 'nanmask'.

        Returns:
            The regridded data as an N-dimensional NumPy array. The lengths
            of the X and Y dimensions will now match those of the sample
            grid.

        """
        #
        # XXX: At the moment requires to be a static method as used by
        # experimental regrid_area_weighted_rectilinear_src_and_grid
        #
        if sample_grid_x.shape != sample_grid_y.shape:
            raise ValueError('Inconsistent sample grid shapes.')
        if sample_grid_x.ndim != 2:
            raise ValueError('Sample grid must be 2-dimensional.')

        # Prepare the result data array
        shape = list(src_data.shape)
        assert shape[x_dim] == src_x_coord.shape[0]
        assert shape[y_dim] == src_y_coord.shape[0]

        shape[y_dim] = sample_grid_x.shape[0]
        shape[x_dim] = sample_grid_x.shape[1]

        dtype = src_data.dtype
        if method == 'linear':
            # If we're given integer values, convert them to the smallest
            # possible float dtype that can accurately preserve the values.
            if dtype.kind == 'i':
                dtype = np.promote_types(dtype, np.float16)

        if ma.isMaskedArray(src_data):
            data = ma.empty(shape, dtype=dtype)
            data.mask = np.zeros(data.shape, dtype=np.bool)
        else:
            data = np.empty(shape, dtype=dtype)

        # The interpolation class requires monotonically increasing
        # coordinates, so flip the coordinate(s) and data if the aren't.
        reverse_x = src_x_coord.points[0] > src_x_coord.points[1]
        reverse_y = src_y_coord.points[0] > src_y_coord.points[1]
        flip_index = [slice(None)] * src_data.ndim
        if reverse_x:
            src_x_coord = src_x_coord[::-1]
            flip_index[x_dim] = slice(None, None, -1)
        if reverse_y:
            src_y_coord = src_y_coord[::-1]
            flip_index[y_dim] = slice(None, None, -1)
        src_data = src_data[tuple(flip_index)]

        if src_x_coord.circular:
            x_points, src_data = extend_circular_coord_and_data(
                src_x_coord, src_data, x_dim)
        else:
            x_points = src_x_coord.points

        # Slice out the first full 2D piece of data for construction of the
        # interpolator.
        index = [0] * src_data.ndim
        index[x_dim] = index[y_dim] = slice(None)
        initial_data = src_data[tuple(index)]
        if y_dim < x_dim:
            initial_data = initial_data.T

        # Construct the interpolator, we will fill in any values out of bounds
        # manually.
        interpolator = _RegularGridInterpolator([x_points, src_y_coord.points],
                                                initial_data,
                                                method=method,
                                                bounds_error=False,
                                                fill_value=None)
        # The constructor of the _RegularGridInterpolator class does
        # some unnecessary checks on these values, so we set them
        # afterwards instead. Sneaky. ;-)
        try:
            mode = EXTRAPOLATION_MODES[extrapolation_mode]
        except KeyError:
            raise ValueError('Invalid extrapolation mode.')
        interpolator.bounds_error = mode.bounds_error
        interpolator.fill_value = mode.fill_value

        # Construct the target coordinate points array, suitable for passing to
        # the interpolator multiple times.
        interp_coords = [
            sample_grid_x.astype(np.float64)[..., np.newaxis],
            sample_grid_y.astype(np.float64)[..., np.newaxis]
        ]

        # Map all the requested values into the range of the source
        # data (centred over the centre of the source data to allow
        # extrapolation where required).
        min_x, max_x = x_points.min(), x_points.max()
        min_y, max_y = src_y_coord.points.min(), src_y_coord.points.max()
        if src_x_coord.units.modulus:
            modulus = src_x_coord.units.modulus
            offset = (max_x + min_x - modulus) * 0.5
            interp_coords[0] -= offset
            interp_coords[0] = (interp_coords[0] % modulus) + offset

        interp_coords = np.dstack(interp_coords)

        weights = interpolator.compute_interp_weights(interp_coords)

        def interpolate(data):
            # Update the interpolator for this data slice.
            data = data.astype(interpolator.values.dtype)
            if y_dim < x_dim:
                data = data.T
            interpolator.values = data
            data = interpolator.interp_using_pre_computed_weights(weights)
            if y_dim > x_dim:
                data = data.T
            return data

        # Build up a shape suitable for passing to ndindex, inside the loop we
        # will insert slice(None) on the data indices.
        iter_shape = list(shape)
        iter_shape[x_dim] = iter_shape[y_dim] = 1

        # Iterate through each 2d slice of the data, updating the interpolator
        # with the new data as we go.
        for index in np.ndindex(tuple(iter_shape)):
            index = list(index)
            index[x_dim] = index[y_dim] = slice(None)

            src_subset = src_data[tuple(index)]
            interpolator.fill_value = mode.fill_value
            data[tuple(index)] = interpolate(src_subset)

            if ma.isMaskedArray(data) or mode.force_mask:
                # NB. np.ma.getmaskarray returns an array of `False` if
                # `src_subset` is not a masked array.
                src_mask = np.ma.getmaskarray(src_subset)
                interpolator.fill_value = mode.mask_fill_value
                mask_fraction = interpolate(src_mask)
                new_mask = (mask_fraction > 0)

                if np.ma.isMaskedArray(data):
                    data.mask[tuple(index)] = new_mask
                elif np.any(new_mask):
                    # Set mask=False to ensure we have an expanded mask array.
                    data = np.ma.MaskedArray(data, mask=False)
                    data.mask[tuple(index)] = new_mask

        return data
     def _regrid_iris_coastline_correction_deprecated(
            self, input_cubes, algorithm='linear'):
        """
        Use iris.analysis._interpolate for coastline correction and
        then combine with Iris.regrid;
        For 'area-weighted', use '_regrid_iris_two_stage' for 'cc'.
         ------
        Args:
            input_cubes: the source input cubes
            algorithm: a string descrbing the regridding scheme used,
                       i.e. only "linear" and "nearest"
        Returns:
            The interpolated cube with coastline correction.
        """
        # kafka_log, full_log = getLoggers()
        # If the input is only a param_cube, turn it into CubeList
        if not isinstance(input_cubes, iris.cube.CubeList):
            input_cube_list = iris.cube.CubeList([])
            input_cube_list.append(input_cubes)
            input_cubes = input_cube_list

        regridded_cubes = iris.cube.CubeList([])

        if self.lsm_src is None or self.lsm_tgt is None:
            raise ValueError("Need land/sea mask to initialize MdsRegridder!")

        for cube in input_cubes:
            full_log.info("Processing " + cube.name())
            # Need check if the input cube has the same shape of grid
            if cube.shape != self.lsm_src.shape:
                cube = cube.regrid(self.lsm_src, iris.analysis.Linear())
            # Separate land/sea data
            cube_src_land_data = np.where(
                (self.lsm_src.data != 0), cube.data, np.nan)
            cube_src_sea_data = np.where(
                (self.lsm_src.data == 0), cube.data, np.nan)

            # Prepare the interpolator
            # We need to extropolate the points outside bounds
            # So set bounds_error=False, fill_value=None
            interpolator_land = _RegularGridInterpolator(
                (self.lat_src, self.lon_src), cube_src_land_data,
                method=algorithm, bounds_error=False, fill_value=None)
            interpolator_sea = _RegularGridInterpolator(
                (self.lat_src, self.lon_src), cube_src_sea_data,
                method=algorithm, bounds_error=False, fill_value=None)

            # Interpolate separately by land/sea
            output_data_land = self._interp_masked_grid(
                interpolator_land, self.grid_tgt)
            output_data_sea = self._interp_masked_grid(
                interpolator_sea, self.grid_tgt)
            # Combine the data
            combined_data = np.where(
                (self.lsm_tgt.data == 0), output_data_sea, output_data_land)

            # Since the combined_data has 'nan', where it is a point
            # along the coastline. Find it and do correction
            coast_pnt_bool = np.isnan(combined_data)
            
            # Now retrieving the points being both coastline and land
            coast_pnt_bool_land = np.logical_and(
                coast_pnt_bool, self.lsm_land_bool_tgt)
            coast_points_land = self.grid_tgt[coast_pnt_bool_land]
            # The way to pass an array of coast points to
            # 'latlons' is much faster.
            out_value_land = self._regrid_coastline_pnt(
                cube, self.grid_src, coast_points_land,
                self.lsm_land_bool_src, algorithm)

            # Do the same with sea
            coast_pnt_bool_sea = np.logical_and(
                coast_pnt_bool, self.lsm_sea_bool_tgt)
            coast_points_sea = self.grid_tgt[coast_pnt_bool_sea]
            # More works (using Cython) need to optimize the function
            out_value_sea = self._regrid_coastline_pnt(
                cube, self.grid_src, coast_points_sea,
                self.lsm_sea_bool_src, algorithm)

            # Now need to replace those coastline points with value nan
            combined_data[coast_pnt_bool_land] = out_value_land
            combined_data[coast_pnt_bool_sea] = out_value_sea
            
            drv_cube = cube.regrid(self.topo_tgt, iris.analysis.Linear())
            drv_cube.data = combined_data

            regridded_cubes.append(drv_cube)

        return regridded_cubes
예제 #9
0
    def _interpolate(self, data, interp_points):
        """
        Interpolate a data array over N dimensions.

        Create and cache the underlying interpolator instance before invoking
        it to perform interpolation over the data at the given coordinate point
        values.

        * data (ndarray):
            A data array, to be interpolated in its first 'N' dimensions.

        * interp_points (ndarray):
            An array of interpolation coordinate values.
            Its shape is (..., N) where N is the number of interpolation
            dimensions.
            "interp_points[..., i]" are interpolation point values for the i'th
            coordinate, which is mapped to the i'th data dimension.
            The other (leading) dimensions index over the different required
            sample points.

        Returns:

            A :class:`np.ndarray`.  Its shape is "points_shape + extra_shape",
            where "extra_shape" is the remaining non-interpolated dimensions of
            the data array (i.e. 'data.shape[N:]'), and "points_shape" is the
            leading dimensions of interp_points,
            (i.e. 'interp_points.shape[:-1]').

        """
        dtype = self._interpolated_dtype(data.dtype)
        if data.dtype != dtype:
            # Perform dtype promotion.
            data = data.astype(dtype)

        mode = EXTRAPOLATION_MODES[self._mode]
        if self._interpolator is None:
            # Cache the interpolator instance.
            # NB. The constructor of the _RegularGridInterpolator class does
            # some unnecessary checks on the fill_value parameter,
            # so we set it afterwards instead. Sneaky. ;-)
            self._interpolator = _RegularGridInterpolator(
                self._src_points,
                data,
                method=self.method,
                bounds_error=mode.bounds_error,
                fill_value=None)
        else:
            self._interpolator.values = data

        # We may be re-using a cached interpolator, so ensure the fill
        # value is set appropriately for extrapolating data values.
        self._interpolator.fill_value = mode.fill_value
        result = self._interpolator(interp_points)

        if result.dtype != data.dtype:
            # Cast the data dtype to be as expected. Note that, the dtype
            # of the interpolated result is influenced by the dtype of the
            # interpolation points.
            result = result.astype(data.dtype)

        if np.ma.isMaskedArray(data) or mode.force_mask:
            # NB. np.ma.getmaskarray returns an array of `False` if
            # `data` is not a masked array.
            src_mask = np.ma.getmaskarray(data)
            # Switch the extrapolation to work with mask values.
            self._interpolator.fill_value = mode.mask_fill_value
            self._interpolator.values = src_mask
            mask_fraction = self._interpolator(interp_points)
            new_mask = (mask_fraction > 0)
            if ma.isMaskedArray(data) or np.any(new_mask):
                result = np.ma.MaskedArray(result, new_mask)

        return result