Exemple #1
0
    def basis_evaluation(self, order, ps, entity=None):
        r"""Produce the recipe for basis function evaluation at a set of points :math:`q`:

        .. math::
            \boldsymbol\phi_{(\gamma \epsilon) (i \alpha \beta) q} = \delta_{\alpha \gamma}\delta{\beta \epsilon}\phi_{i q}

            \nabla\boldsymbol\phi_{(\epsilon \gamma \zeta) (i \alpha \beta) q} = \delta_{\alpha \epsilon} \deta{\beta \gamma}\nabla\phi_{\zeta i q}
        """
        # Old basis function and value indices
        scalar_i = self._base_element.get_indices()
        scalar_vi = self._base_element.get_value_indices()

        # New basis function and value indices
        tensor_i = tuple(gem.Index(extent=d) for d in self._shape)
        tensor_vi = tuple(gem.Index(extent=d) for d in self._shape)

        # Couple new basis function and value indices
        deltas = reduce(gem.Product,
                        (gem.Delta(j, k) for j, k in zip(tensor_i, tensor_vi)))

        scalar_result = self._base_element.basis_evaluation(order, ps, entity)
        result = {}
        for alpha, expr in iteritems(scalar_result):
            result[alpha] = gem.ComponentTensor(
                gem.Product(deltas, gem.Indexed(expr, scalar_i + scalar_vi)),
                scalar_i + tensor_i + scalar_vi + tensor_vi)
        return result
Exemple #2
0
    def basis_evaluation(self,
                         order,
                         ps,
                         entity=None,
                         coordinate_mapping=None):
        '''Return code for evaluating the element at known points on the
        reference element.

        :param order: return derivatives up to this order.
        :param ps: the point set.
        :param entity: the cell entity on which to tabulate.
        '''

        result = super(GaussLegendre, self).basis_evaluation(order, ps, entity)
        cell_dimension = self.cell.get_dimension()
        if entity is None or entity == (cell_dimension, 0):  # on cell interior
            space_dim = self.space_dimension()
            if isinstance(ps, GaussLegendrePointSet) and len(
                    ps.points) == space_dim:
                # Bingo: evaluation points match node locations!
                spatial_dim = self.cell.get_spatial_dimension()
                q, = ps.indices
                r, = self.get_indices()
                result[(0, ) * spatial_dim] = gem.ComponentTensor(
                    gem.Delta(q, r), (r, ))
        return result
Exemple #3
0
    def basis_evaluation(self,
                         order,
                         ps,
                         entity=None,
                         coordinate_mapping=None):
        '''Return code for evaluating the element at known points on the
        reference element.

        :param order: return derivatives up to this order.
        :param ps: the point set object.
        :param entity: the cell entity on which to tabulate.
        '''
        if entity is not None and entity != (self.cell.get_dimension(), 0):
            raise ValueError(
                'QuadratureElement does not "tabulate" on subentities.')

        if order:
            raise ValueError(
                "Derivatives are not defined on a QuadratureElement.")

        if not self._rule.point_set.almost_equal(ps):
            raise ValueError("Mismatch of quadrature points!")

        # Return an outer product of identity matrices
        multiindex = self.get_indices()
        product = reduce(
            gem.Product,
            [gem.Delta(q, r) for q, r in zip(ps.indices, multiindex)])

        dim = self.cell.get_spatial_dimension()
        return {(0, ) * dim: gem.ComponentTensor(product, multiindex)}
Exemple #4
0
    def _tensorise(self, scalar_evaluation):
        # Old basis function and value indices
        scalar_i = self._base_element.get_indices()
        scalar_vi = self._base_element.get_value_indices()

        # New basis function and value indices
        tensor_i = tuple(gem.Index(extent=d) for d in self._shape)
        tensor_vi = tuple(gem.Index(extent=d) for d in self._shape)

        # Couple new basis function and value indices
        deltas = reduce(gem.Product, (gem.Delta(j, k)
                                      for j, k in zip(tensor_i, tensor_vi)))

        if self._transpose:
            index_ordering = tensor_i + scalar_i + tensor_vi + scalar_vi
        else:
            index_ordering = scalar_i + tensor_i + tensor_vi + scalar_vi

        result = {}
        for alpha, expr in scalar_evaluation.items():
            result[alpha] = gem.ComponentTensor(
                gem.Product(deltas, gem.Indexed(expr, scalar_i + scalar_vi)),
                index_ordering
            )
        return result
Exemple #5
0
 def dual_basis(self):
     ps = self._rule.point_set
     multiindex = self.get_indices()
     # Evaluation matrix is just an outer product of identity
     # matrices, evaluation points are just the quadrature points.
     Q = reduce(gem.Product,
                (gem.Delta(q, r) for q, r in zip(ps.indices, multiindex)))
     Q = gem.ComponentTensor(Q, multiindex)
     return Q, ps
Exemple #6
0
    def dual_basis(self):
        base = self.base_element
        Q, points = base.dual_basis

        # Suppose the tensor element has shape (2, 4)
        # These identity matrices may have difference sizes depending the shapes
        # tQ = Q ⊗ 𝟙₂ ⊗ 𝟙₄
        scalar_i = self.base_element.get_indices()
        scalar_vi = self.base_element.get_value_indices()
        tensor_i = tuple(gem.Index(extent=d) for d in self._shape)
        tensor_vi = tuple(gem.Index(extent=d) for d in self._shape)
        # Couple new basis function and value indices
        deltas = reduce(gem.Product, (gem.Delta(j, k)
                                      for j, k in zip(tensor_i, tensor_vi)))
        if self._transpose:
            index_ordering = tensor_i + scalar_i + tensor_vi + scalar_vi
        else:
            index_ordering = scalar_i + tensor_i + tensor_vi + scalar_vi

        Qi = Q[scalar_i + scalar_vi]
        tQ = gem.ComponentTensor(Qi*deltas, index_ordering)
        return tQ, points
Exemple #7
0
 def _dual_basis(self):
     # Return the numerical part of the dual basis, this split is
     # needed because the dual_basis itself can't produce the same
     # point set over and over in case it is used multiple times
     # (in for example a tensorproductelement).
     fiat_dual_basis = self._element.dual_basis()
     seen = dict()
     allpts = []
     # Find the unique points to evaluate at.
     # We might be able to make this a smaller set by treating each
     # point one by one, but most of the redundancy comes from
     # multiple functionals using the same quadrature rule.
     for dual in fiat_dual_basis:
         if len(dual.deriv_dict) != 0:
             raise NotImplementedError(
                 "FIAT dual bases with derivative nodes represented via a ``Functional.deriv_dict`` property do not currently have a FInAT dual basis"
             )
         pts = dual.get_point_dict().keys()
         pts = tuple(sorted(pts))  # need this for determinism
         if pts not in seen:
             # k are indices into Q (see below) for the seen points
             kstart = len(allpts)
             kend = kstart + len(pts)
             seen[pts] = kstart, kend
             allpts.extend(pts)
     # Build Q.
     # Q is a tensor of weights (of total rank R) to contract with a unique
     # vector of points to evaluate at, giving a tensor (of total rank R-1)
     # where the first indices (rows) correspond to a basis functional
     # (node).
     # Q is a DOK Sparse matrix in (row, col, higher,..)=>value pairs (to
     # become a gem.SparseLiteral when implemented).
     # Rows (i) are number of nodes/dual functionals.
     # Columns (k) are unique points to evaluate.
     # Higher indices (*cmp) are tensor indices of the weights when weights
     # are tensor valued.
     Q = {}
     for i, dual in enumerate(fiat_dual_basis):
         point_dict = dual.get_point_dict()
         pts = tuple(sorted(point_dict.keys()))
         kstart, kend = seen[pts]
         for p, k in zip(pts, range(kstart, kend)):
             for weight, cmp in point_dict[p]:
                 Q[(i, k, *cmp)] = weight
     if all(
             len(set(key)) == 1 and np.isclose(weight, 1) and len(key) == 2
             for key, weight in Q.items()):
         # Identity matrix Q can be expressed symbolically
         extents = tuple(map(max, zip(*Q.keys())))
         js = tuple(gem.Index(extent=e + 1) for e in extents)
         assert len(js) == 2
         Q = gem.ComponentTensor(gem.Delta(*js), js)
     else:
         # temporary until sparse literals are implemented in GEM which will
         # automatically convert a dictionary of keys internally.
         # TODO the below is unnecessarily slow and would be sped up
         # significantly by building Q in a COO format rather than DOK (i.e.
         # storing coords and associated data in (nonzeros, entries) shaped
         # numpy arrays) to take advantage of numpy multiindexing
         Qshape = tuple(s + 1 for s in map(max, *Q))
         Qdense = np.zeros(Qshape, dtype=np.float64)
         for idx, value in Q.items():
             Qdense[idx] = value
         Q = gem.Literal(Qdense)
     return Q, np.asarray(allpts)