From 70657ca9e56c3fea77d3efd3b336797e8cd91ad2 Mon Sep 17 00:00:00 2001 From: Ben Sepanski <ben_sepanski@baylor.edu> Date: Thu, 28 May 2020 11:41:52 -0500 Subject: [PATCH] Added an importer for FIAT's simplex cell --- meshmode/interop/fiat/simplex_cell.py | 123 ++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 meshmode/interop/fiat/simplex_cell.py diff --git a/meshmode/interop/fiat/simplex_cell.py b/meshmode/interop/fiat/simplex_cell.py new file mode 100644 index 00000000..51c61a04 --- /dev/null +++ b/meshmode/interop/fiat/simplex_cell.py @@ -0,0 +1,123 @@ +from warnings import warn # noqa +import numpy as np +import numpy.linalg as la + +from meshmode.mesh.interop import ExternalImporter + + +__doc__ = """ +Interoperators +-------------- +.. autoclass:: SimplexCellAnalog + :members: +""" + +# {{{ Compute an affine mapping from given input/outputs + +def get_affine_mapping(reference_vects, vects): + r""" + Returns (mat, shift), + a matrix *mat* and vector *shift* which maps the + *i*th vector in *reference_vects* to the *i*th vector in *vects by + + ..math:: + + A ri + b -> vi, \qquad A = mat, b = shift + + :arg reference_vects: An np.array of *n* vectors of dimension *ref_dim* + :arg vects: An np.array of *n* vectors of dimension *dim*, with + *ref_dim* <= *dim*. + + NOTE : Should be shape *(ref_dim, nvectors)*, *(dim, nvectors)* respectively. + + *mat* will have shape *(dim, ref_dim)*, *shift* will have shape *(dim,)* + """ + # Make sure both have same number of vectors + ref_dim, num_vects = reference_vects.shape + assert num_vects == vects.shape[1] + + # Make sure d1 <= d2 (see docstring) + dim = vects.shape[0] + assert ref_dim <= dim + + # If there is only one vector, set M = I, b = vect - reference + if num_vects == 1: + mat = np.eye(dim, ref_dim) + shift = vects[:, 0] - np.matmul(mat, reference_vects[:, 0]) + else: + ref_span_vects = reference_vects[:, 1:] - reference_vects[:, 0, np.newaxis] + span_vects = vects[:, 1:] - vects[:, 0, np.newaxis] + mat = la.solve(ref_span_vects, span_vects) + shift = -np.matmul(mat, reference_vects[:, 0]) + vects[:, 0] + + return mat, shift + +# }}} + + +# {{{ Interoperator for FIAT's reference_element.Simplex + +class FIATSimplexCellImporter(ExternalImporter): + """ + Importer for a :mod:`FIAT` simplex cell. + There is no data created from the :attr:`from_data`. Instead, + the data is simply used to obtain FIAT's reference + nodes according to :mod:`modepy`'s reference coordinates + using :meth:`make_modepy_points`. + + .. attribute:: from_data + + An instance of :class:`fiat.FIAT.reference_element.Simplex`. + + .. attribute:: to_data + + :raises ValueError: If accessed. + """ + def __init__(self, cell): + """ + :arg cell: a :class:`fiat.FIAT.reference_element.Simplex`. + """ + # Ensure this cell is actually a simplex + from FIAT.reference_element import Simplex + assert isinstance(cell, Simplex) + + super(SimplexCellInteroperator, self).__init__(cell) + + # Stored as (dim, nunit_vertices) + from modepy.tools import unit_vertices + self._unit_vertices = unit_vertices(cell.get_dimension()).T + + # Maps FIAT reference vertices to :mod:`meshmode` + # unit vertices by x -> Ax + b, where A is :attr:`_mat` + # and b is :attr:`_shift` + reference_vertices = np.array(cell.vertices).T + self._mat, self._shift = get_affine_mapping(reference_vertices, + self._unit_vertices) + + def make_modepy_points(self, dim, entity_id, order): + """ + Constructs a lattice of points on the *entity_id*th facet + of dimension *dim*. + + Args are exactly as in + :meth:`fiat.FIAT.reference_element.Cell.make_points` + (see `FIAT docs <fiat.FIAT.reference_element.Cell.make_points>`_), + but the unit nodes are (affinely) mapped to :mod:`modepy` + `unit coordinates <https://documen.tician.de/modepy/nodes.html>`_. + + :arg dim: Dimension of the facet we are constructing points on. + :arg entity_id: identifier to determine which facet of + dimension *dim* to construct the points on. + :arg order: Number of points to include in each direction. + + :return: an *np.array* of shape *(dim, npoints)* holding the + coordinates of each of the ver + """ + points = self.from_data.make_points(dim, entity_id, order) + if not points: + return points + points = np.array(points) + # Points is (npoints, dim) so have to transpose + return (np.matmul(self._mat, points.T) + self._shift[:, np.newaxis]).T + +# }}} -- GitLab