Ejemplo n.º 1
0
def _new_operator1(shape, **kwargs):
    infield = DenseData(name='in', shape=shape, dtype=np.int32)
    infield.data[:] = np.arange(reduce(mul, shape),
                                dtype=np.int32).reshape(shape)

    outfield = DenseData(name='out', shape=shape, dtype=np.int32)

    stencil = Eq(outfield.indexify(),
                 outfield.indexify() + infield.indexify() * 3.0)

    # Run the operator
    Operator(stencil, **kwargs)(infield, outfield)

    return outfield
Ejemplo n.º 2
0
class PointData(CompositeData):
    """
    Data object for sparse point data that acts as a Function symbol

    :param name: Name of the resulting :class:`sympy.Function` symbol
    :param npoint: Number of points to sample
    :param nt: Size of the time dimension for point data
    :param ndim: Dimension of the coordinate data, eg. 2D or 3D
    :param coordinates: Optional coordinate data for the sparse points
    :param dtype: Data type of the buffered data
    """

    is_PointData = True

    def __init__(self, *args, **kwargs):
        if not self._cached():
            self.nt = kwargs.get('nt')
            self.npoint = kwargs.get('npoint')
            self.ndim = kwargs.get('ndim')
            kwargs['shape'] = (self.nt, self.npoint)
            super(PointData, self).__init__(self, *args, **kwargs)

            # Allocate and copy coordinate data
            self.coordinates = DenseData(name='%s_coords' % self.name,
                                         dimensions=[self.indices[1], d],
                                         shape=(self.npoint, self.ndim))
            self._children.append(self.coordinates)
            coordinates = kwargs.get('coordinates', None)
            if coordinates is not None:
                self.coordinates.data[:] = coordinates[:]

    def __new__(cls, *args, **kwargs):
        nt = kwargs.get('nt')
        npoint = kwargs.get('npoint')
        kwargs['shape'] = (nt, npoint)

        return DenseData.__new__(cls, *args, **kwargs)

    @classmethod
    def _indices(cls, **kwargs):
        """Return the default dimension indices for a given data shape

        :param shape: Shape of the spatial data
        :return: indices used for axis.
        """
        dimensions = kwargs.get('dimensions', None)
        return dimensions or [time, p]

    @property
    def coefficients(self):
        """Symbolic expression for the coefficients for sparse point
        interpolation according to:
        https://en.wikipedia.org/wiki/Bilinear_interpolation.

        :returns: List of coefficients, eg. [b_11, b_12, b_21, b_22]
        """
        # Grid indices corresponding to the corners of the cell
        x1, y1, z1, x2, y2, z2 = symbols('x1, y1, z1, x2, y2, z2')
        # Coordinate values of the sparse point
        px, py, pz = self.point_symbols
        if self.ndim == 2:
            A = Matrix([[1, x1, y1, x1 * y1], [1, x1, y2, x1 * y2],
                        [1, x2, y1, x2 * y1], [1, x2, y2, x2 * y2]])

            p = Matrix([[1], [px], [py], [px * py]])

        elif self.ndim == 3:
            A = Matrix(
                [[1, x1, y1, z1, x1 * y1, x1 * z1, y1 * z1, x1 * y1 * z1],
                 [1, x1, y2, z1, x1 * y2, x1 * z1, y2 * z1, x1 * y2 * z1],
                 [1, x2, y1, z1, x2 * y1, x2 * z1, y2 * z1, x2 * y1 * z1],
                 [1, x1, y1, z2, x1 * y1, x1 * z2, y1 * z2, x1 * y1 * z2],
                 [1, x2, y2, z1, x2 * y2, x2 * z1, y2 * z1, x2 * y2 * z1],
                 [1, x1, y2, z2, x1 * y2, x1 * z2, y2 * z2, x1 * y2 * z2],
                 [1, x2, y1, z2, x2 * y1, x2 * z2, y1 * z2, x2 * y1 * z2],
                 [1, x2, y2, z2, x2 * y2, x2 * z2, y2 * z2, x2 * y2 * z2]])

            p = Matrix([[1], [px], [py], [pz], [px * py], [px * pz], [py * pz],
                        [px * py * pz]])
        else:
            error('Point interpolation only supported for 2D and 3D')
            raise NotImplementedError('Interpolation coefficients not '
                                      'implemented for %d dimensions.' %
                                      self.ndim)

        # Map to reference cell
        reference_cell = {
            x1: 0,
            y1: 0,
            z1: 0,
            x2: x.spacing,
            y2: y.spacing,
            z2: z.spacing
        }
        A = A.subs(reference_cell)
        return A.inv().T.dot(p)

    @property
    def point_symbols(self):
        """Symbol for coordinate value in each dimension of the point"""
        return symbols('px, py, pz')

    @property
    def point_increments(self):
        """Index increments in each dimension for each point symbol"""
        if self.ndim == 2:
            return ((0, 0), (0, 1), (1, 0), (1, 1))
        elif self.ndim == 3:
            return ((0, 0, 0), (0, 1, 0), (1, 0, 0), (0, 0, 1), (1, 1, 0),
                    (0, 1, 1), (1, 0, 1), (1, 1, 1))
        else:
            error('Point interpolation only supported for 2D and 3D')
            raise NotImplementedError('Point increments not defined '
                                      'for %d dimensions.' % self.ndim)

    @property
    def coordinate_symbols(self):
        """Symbol representing the coordinate values in each dimension"""
        p_dim = self.indices[1]
        return tuple(
            [self.coordinates.indexify((p_dim, i)) for i in range(self.ndim)])

    @property
    def coordinate_indices(self):
        """Symbol for each grid index according to the coordinates"""
        indices = (x, y, z)
        return tuple([
            INT(Function('floor')(c / i.spacing))
            for c, i in zip(self.coordinate_symbols, indices[:self.ndim])
        ])

    @property
    def coordinate_bases(self):
        """Symbol for the base coordinates of the reference grid point"""
        indices = (x, y, z)
        return tuple([
            FLOAT(c - idx * i.spacing)
            for c, idx, i in zip(self.coordinate_symbols,
                                 self.coordinate_indices, indices[:self.ndim])
        ])

    def interpolate(self, expr, offset=0, **kwargs):
        """Creates a :class:`sympy.Eq` equation for the interpolation
        of an expression onto this sparse point collection.

        :param expr: The expression to interpolate.
        :param offset: Additional offset from the boundary for
                       absorbing boundary conditions.
        :param u_t: (Optional) time index to use for indexing into
                    field data in `expr`.
        :param p_t: (Optional) time index to use for indexing into
                    the sparse point data.
        """
        u_t = kwargs.get('u_t', None)
        p_t = kwargs.get('p_t', None)
        expr = indexify(expr)

        # Apply optional time symbol substitutions to expr
        if u_t is not None:
            expr = expr.subs(t, u_t).subs(time, u_t)

        variables = list(retrieve_indexed(expr))
        # List of indirection indices for all adjacent grid points
        index_matrix = [
            tuple(idx + ii + offset
                  for ii, idx in zip(inc, self.coordinate_indices))
            for inc in self.point_increments
        ]
        # Generate index substituions for all grid variables
        idx_subs = []
        for i, idx in enumerate(index_matrix):
            v_subs = [(v, v.base[v.indices[:-self.ndim] + idx])
                      for v in variables]
            idx_subs += [OrderedDict(v_subs)]
        # Substitute coordinate base symbols into the coefficients
        subs = OrderedDict(zip(self.point_symbols, self.coordinate_bases))
        rhs = sum([
            expr.subs(vsub) * b.subs(subs)
            for b, vsub in zip(self.coefficients, idx_subs)
        ])

        # Apply optional time symbol substitutions to lhs of assignment
        lhs = self if p_t is None else self.subs(self.indices[0], p_t)
        return [Eq(lhs, rhs)]

    def inject(self, field, expr, offset=0, **kwargs):
        """Symbol for injection of an expression onto a grid

        :param field: The grid field into which we inject.
        :param expr: The expression to inject.
        :param offset: Additional offset from the boundary for
                       absorbing boundary conditions.
        :param u_t: (Optional) time index to use for indexing into `field`.
        :param p_t: (Optional) time index to use for indexing into `expr`.
        """
        u_t = kwargs.get('u_t', None)
        p_t = kwargs.get('p_t', None)

        expr = indexify(expr)
        field = indexify(field)
        variables = list(retrieve_indexed(expr)) + [field]

        # Apply optional time symbol substitutions to field and expr
        if u_t is not None:
            field = field.subs(field.indices[0], u_t)
        if p_t is not None:
            expr = expr.subs(self.indices[0], p_t)

        # List of indirection indices for all adjacent grid points
        index_matrix = [
            tuple(idx + ii + offset
                  for ii, idx in zip(inc, self.coordinate_indices))
            for inc in self.point_increments
        ]

        # Generate index substituions for all grid variables except
        # the sparse `PointData` types
        idx_subs = []
        for i, idx in enumerate(index_matrix):
            v_subs = [(v, v.base[v.indices[:-self.ndim] + idx])
                      for v in variables if not v.base.function.is_PointData]
            idx_subs += [OrderedDict(v_subs)]

        # Substitute coordinate base symbols into the coefficients
        subs = OrderedDict(zip(self.point_symbols, self.coordinate_bases))
        return [
            Eq(field.subs(vsub),
               field.subs(vsub) + expr.subs(subs).subs(vsub) * b.subs(subs))
            for b, vsub in zip(self.coefficients, idx_subs)
        ]