Esempio n. 1
0
    def _interpolate(self, xi):
        """
        Interpolate at the sample coordinates.

        This method is called from OpenMDAO, and is not meant for standalone use.

        Parameters
        ----------
        xi : ndarray of shape (..., ndim)
            The coordinates to sample the gridded data.

        Returns
        -------
        ndarray
            Value of interpolant at all sample points.
        """
        # cache latest evaluation point for gradient method's use later
        self._xi = xi

        if not self.extrapolate:
            for i, p in enumerate(xi.T):
                if np.isnan(p).any():
                    raise OutOfBoundsError("One of the requested xi contains a NaN",
                                           i, np.NaN, self.grid[i][0], self.grid[i][-1])

                eps = 1e-14 * self.grid[i][-1]
                if not np.logical_and(np.all(self.grid[i][0] <= p + eps),
                                      np.all(p - eps <= self.grid[i][-1])):
                    p1 = np.where(self.grid[i][0] > p)[0]
                    p2 = np.where(p > self.grid[i][-1])[0]
                    # First violating entry is enough to direct the user.
                    violated_idx = set(p1).union(p2).pop()
                    value = p[violated_idx]
                    raise OutOfBoundsError("One of the requested xi is out of bounds",
                                           i, value, self.grid[i][0], self.grid[i][-1])

        if self._compute_d_dvalues:
            # If the table grid or values are component inputs, then we need to create a new table
            # each iteration.
            interp = self._interp
            self.table = interp(self.grid, self.values, interp, **self._interp_options)
            self.table._compute_d_dvalues = True

        table = self.table
        if table._vectorized:
            result, derivs_x, derivs_val, derivs_grid = table.evaluate_vectorized(xi)

        else:
            xi = np.atleast_2d(xi)
            n_nodes, nx = xi.shape
            result = np.empty((n_nodes, ), dtype=xi.dtype)
            derivs_x = np.empty((n_nodes, nx), dtype=xi.dtype)
            derivs_val = None

            # TODO: it might be possible to vectorize over n_nodes.
            for j in range(n_nodes):
                val, d_x, d_values, d_grid = table.evaluate(xi[j, :])
                result[j] = val
                derivs_x[j, :] = d_x.flatten()
                if d_values is not None:
                    if derivs_val is None:
                        dv_shape = [n_nodes]
                        dv_shape.extend(self.values.shape)
                        derivs_val = np.zeros(dv_shape, dtype=xi.dtype)
                    in_slice = table._full_slice
                    full_slice = [slice(j, j + 1)]
                    full_slice.extend(in_slice)
                    shape = derivs_val[tuple(full_slice)].shape
                    derivs_val[tuple(full_slice)] = d_values.reshape(shape)

        # Cache derivatives
        self._d_dx = derivs_x
        self._d_dvalues = derivs_val

        return result
Esempio n. 2
0
    def bracket(self, x):
        """
        Locate the interval of the new independent.

        Uses the following algorithm:
           1. Determine if the value is above or below the value at last_index
           2. Bracket the value between last_index and last_index +- inc, where
              inc has an increasing value of 1,2,4,8, etc.
           3. Once the value is bracketed, use bisection method within that bracket.

        The grid is assumed to increase in a monotonic fashion.

        Parameters
        ----------
        x : float
            Value of new independent to interpolate.

        Returns
        -------
        integer
            Grid interval index that contains x.
        integer
            Extrapolation flag, -1 if the bracket is below the first table element, 1 if the
            bracket is above the last table element, 0 for normal interpolation.
        """
        grid = self.grid
        last_index = self.last_index
        high = last_index + 1
        highbound = len(grid) - 1
        inc = 1

        while x < grid[last_index]:
            high = last_index
            last_index -= inc
            if last_index < 0:
                last_index = 0

                # Check if we're off of the bottom end.
                if x < grid[0]:
                    if not self.extrapolate:
                        msg = f"Extrapolation while evaluation dimension {self.idim}."
                        raise OutOfBoundsError(msg, self.idim, x, grid[0], grid[-1])

                    return last_index, -1
                break

            inc += inc

        if high > highbound:
            high = highbound

        while x > grid[high]:
            last_index = high
            high += inc
            if high >= highbound:

                # Check if we're off of the top end
                if x > grid[highbound]:
                    if not self.extrapolate:
                        msg = f"Extrapolation while evaluation dimension {self.idim}."
                        raise OutOfBoundsError(msg, self.idim, x, grid[0], grid[-1])

                    last_index = highbound
                    return last_index, 1

                high = highbound
                break
            inc += inc

        # Bisection
        while high - last_index > 1:
            low = (high + last_index) // 2
            if x < grid[low]:
                high = low
            else:
                last_index = low

        return last_index, 0
Esempio n. 3
0
    def _interpolate(self, xi):
        """
        Interpolate at the sample coordinates.

        This method is called from OpenMDAO, and is not meant for standalone use.

        Parameters
        ----------
        xi : ndarray of shape (..., ndim)
            The coordinates to sample the gridded data.

        Returns
        -------
        ndarray
            Value of interpolant at all sample points.
        """
        # cache latest evaluation point for gradient method's use later
        self._xi = xi

        if not self.extrapolate:
            for i, p in enumerate(xi.T):
                if np.isnan(p).any():
                    raise OutOfBoundsError(
                        "One of the requested xi contains a NaN", i, np.NaN,
                        self.grid[i][0], self.grid[i][-1])

        if self._compute_d_dvalues:
            # If the table grid or values are component inputs, then we need to create a new table
            # each iteration.
            interp = self._interp
            self.table = interp(self.grid,
                                self.values,
                                interp,
                                extrapolate=self.extrapolate,
                                compute_d_dvalues=True,
                                **self._interp_options)

        table = self.table

        xi = np.atleast_2d(xi)
        n_nodes, nx = xi.shape
        result = np.empty((n_nodes, ), dtype=xi.dtype)
        derivs_x = np.empty((n_nodes, nx), dtype=xi.dtype)
        if self._compute_d_dvalues:
            derivs_val = np.zeros((n_nodes, len(self.values)), dtype=xi.dtype)

        # Loop over n_nodes because there isn't a way to vectorize.
        for j in range(n_nodes):
            val, d_x, d_values_tuple, extrapolate = table.interpolate(xi[j, :])
            result[j] = val
            derivs_x[j, :] = d_x.ravel()
            if self._compute_d_dvalues:
                d_values, idx = d_values_tuple
                derivs_val[j, idx] = d_values.ravel()

        # Cache derivatives
        self._d_dx = derivs_x
        if self._compute_d_dvalues:
            self._d_dvalues = derivs_val

        return result