Esempio n. 1
0
    def __init__(self, mesh, layers):
        """Build an extruded mesh topology from an input mesh topology

        :arg mesh:           the unstructured base mesh topology
        :arg layers:         number of extruded cell layers in the "vertical"
                             direction.
        """
        from firedrake.citations import Citations
        Citations().register("McRae2014")
        # A cache of shared function space data on this mesh
        self._shared_data_cache = defaultdict(dict)

        mesh.init()
        self._base_mesh = mesh
        if layers < 1:
            raise RuntimeError("Must have at least one layer of extruded cells (not %d)" % layers)
        # All internal logic works with layers of base mesh (not layers of cells)
        self._layers = layers + 1
        self._ufl_cell = ufl.TensorProductCell(mesh.ufl_cell(), ufl.interval)

        # TODO: These attributes are copied so that FunctionSpaceBase can
        # access them directly.  Eventually we would want a better refactoring
        # of responsibilities between mesh and function space.
        self._plex = mesh._plex
        self._plex_renumbering = mesh._plex_renumbering
        self._entity_classes = mesh._entity_classes
Esempio n. 2
0
def _create_fiat_element(ufl_element):
    """Create FIAT element corresponding to given finite element."""

    # Get element data
    family = ufl_element.family()
    cell = ufl_element.cell()
    cellname = cell.cellname()
    degree = ufl_element.degree()

    # Check that FFC supports this element
    if family not in supported_families:
        raise RuntimeError("This element family (%s) is not supported by FFC." % family)

    # Create FIAT cell
    fiat_cell = reference_cell(cellname)

    # Handle the space of the constant
    if family == "Real":
        element = _create_fiat_element(ufl.FiniteElement("DG", cell, 0))
        element.__class__ = type('SpaceOfReals', (type(element), SpaceOfReals), {})
        return element

    if cellname == "quadrilateral":
        # Handle quadrilateral case by reconstructing the element with
        # cell TensorProductCell (interval x interval)
        quadrilateral_tpc = ufl.TensorProductCell(ufl.Cell("interval"), ufl.Cell("interval"))
        return FlattenedDimensions(
            _create_fiat_element(ufl_element.reconstruct(cell=quadrilateral_tpc)))
    elif cellname == "hexahedron":
        # Handle hexahedron case by reconstructing the element with cell
        # TensorProductCell (quadrilateral x interval). This creates
        # TensorProductElement(TensorProductElement(interval, interval),
        # interval) Therefore dof entities consists of nested tuples,
        # example: ((0, 1), 1)
        hexahedron_tpc = ufl.TensorProductCell(ufl.Cell("quadrilateral"), ufl.Cell("interval"))
        return FlattenedDimensions(
            _create_fiat_element(ufl_element.reconstruct(cell=hexahedron_tpc)))

    # FIXME: AL: Should this really be here?
    # Handle QuadratureElement
    if family == "Quadrature":
        # Compute number of points per axis from the degree of the element
        scheme = ufl_element.quadrature_scheme()
        assert degree is not None
        assert scheme is not None

        # Create quadrature (only interested in points)
        # TODO: KBO: What should we do about quadrature functions that live on ds, dS?
        # Get cell and facet names.
        points, weights = create_quadrature(cellname, degree, scheme)

        # Make element
        element = QuadratureElement(fiat_cell, points)
    else:
        # Check if finite element family is supported by FIAT
        if family not in FIAT.supported_elements:
            raise RuntimeError("Sorry, finite element of type \"%s\" are not supported by FIAT.",
                               family)

        ElementClass = FIAT.supported_elements[family]

        # Create tensor product FIAT finite element
        if isinstance(ufl_element, ufl.TensorProductElement):
            A = create_element(ufl_element.sub_elements()[0])
            B = create_element(ufl_element.sub_elements()[1])
            element = ElementClass(A, B)

        # Create normal FIAT finite element
        else:
            if degree is None:
                element = ElementClass(fiat_cell)
            else:
                element = ElementClass(fiat_cell, degree)

    if element.value_shape() != ufl_element.reference_value_shape():
        # Consistency check between UFL and FIAT elements.
        raise RuntimeError("Something went wrong in the construction of FIAT element from UFL element."
                           + "Shapes are {} and {}.".format(element.value_shape(),
                                                            ufl_element.reference_value_shape()))

    return element
Esempio n. 3
0
    elements = []

    def rec(eles):
        for ele in eles:
            if isinstance(ele, ufl.MixedElement):
                rec(ele.sub_elements())
            else:
                elements.append(ele)

    rec(element.sub_elements())
    fiat_elements = map(
        partial(create_element, vector_is_mixed=vector_is_mixed), elements)
    return FIAT.MixedElement(fiat_elements)


quad_tpc = ufl.TensorProductCell(ufl.Cell("interval"), ufl.Cell("interval"))
_cache = weakref.WeakKeyDictionary()


def create_element(element, vector_is_mixed=True):
    """Create a FIAT element (suitable for tabulating with) given a UFL element.

    :arg element: The UFL element to create a FIAT element from.

    :arg vector_is_mixed: indicate whether VectorElement (or
         TensorElement) should be treated as a MixedElement.  Maybe
         useful if you want a FIAT element that tells you how many
         "nodes" the finite element has.
    """
    try:
        cache = _cache[element]
Esempio n. 4
0
    finat_elem, deps = _create_element(element._element, **kwargs)
    return finat.HCurlElement(finat_elem), deps


@convert.register(ufl.RestrictedElement)
def convert_restrictedelement(element, **kwargs):
    # Fall back on FIAT
    return fiat_compat(element), set()


@convert.register(ufl.NodalEnrichedElement)
def convert_nodalenrichedelement(element, **kwargs):
    return fiat_compat(element), set()


hexahedron_tpc = ufl.TensorProductCell(ufl.quadrilateral, ufl.interval)
quadrilateral_tpc = ufl.TensorProductCell(ufl.interval, ufl.interval)
_cache = weakref.WeakKeyDictionary()


def create_element(ufl_element, shape_innermost=True):
    """Create a FInAT element (suitable for tabulating with) given a UFL element.

    :arg ufl_element: The UFL element to create a FInAT element from.
    :arg shape_innermost: Vector/tensor indices come after basis function indices
    """
    finat_element, deps = _create_element(ufl_element,
                                          shape_innermost=shape_innermost)
    return finat_element

Esempio n. 5
0
VTK_INTERVAL = 3
VTK_TRIANGLE = 5
VTK_QUADRILATERAL = 9
VTK_TETRAHEDRON = 10
VTK_HEXAHEDRON = 12
VTK_WEDGE = 13

cells = {
    ufl.Cell("interval"):
    VTK_INTERVAL,
    ufl.Cell("triangle"):
    VTK_TRIANGLE,
    ufl.Cell("quadrilateral"):
    VTK_QUADRILATERAL,
    ufl.TensorProductCell(ufl.Cell("interval"), ufl.Cell("interval")):
    VTK_QUADRILATERAL,
    ufl.Cell("tetrahedron"):
    VTK_TETRAHEDRON,
    ufl.TensorProductCell(ufl.Cell("triangle"), ufl.Cell("interval")):
    VTK_WEDGE,
    ufl.TensorProductCell(ufl.Cell("quadrilateral"), ufl.Cell("interval")):
    VTK_HEXAHEDRON
}

OFunction = collections.namedtuple("OFunction", ["array", "name", "function"])


def is_cg(V):
    """Is the provided space continuous?
Esempio n. 6
0
VTK_INTERVAL = 3
VTK_TRIANGLE = 5
VTK_QUADRILATERAL = 9
VTK_TETRAHEDRON = 10
VTK_HEXAHEDRON = 12
VTK_WEDGE = 13
#  Lagrange VTK cells:
VTK_LAGRANGE_CURVE = 68
VTK_LAGRANGE_TRIANGLE = 69
VTK_LAGRANGE_QUADRILATERAL = 70
VTK_LAGRANGE_TETRAHEDRON = 71
VTK_LAGRANGE_HEXAHEDRON = 72
VTK_LAGRANGE_WEDGE = 73


ufl_quad = ufl.TensorProductCell(ufl.Cell("interval"),
                                 ufl.Cell("interval"))
ufl_wedge = ufl.TensorProductCell(ufl.Cell("triangle"),
                                  ufl.Cell("interval"))
ufl_hex = ufl.TensorProductCell(ufl.Cell("quadrilateral"),
                                ufl.Cell("interval"))
cells = {
    (ufl.Cell("interval"), False): VTK_INTERVAL,
    (ufl.Cell("interval"), True): VTK_LAGRANGE_CURVE,
    (ufl.Cell("triangle"), False): VTK_TRIANGLE,
    (ufl.Cell("triangle"), True): VTK_LAGRANGE_TRIANGLE,
    (ufl.Cell("quadrilateral"), False): VTK_QUADRILATERAL,
    (ufl.Cell("quadrilateral"), True): VTK_LAGRANGE_QUADRILATERAL,
    (ufl_quad, True): VTK_LAGRANGE_QUADRILATERAL,
    (ufl_quad, False): VTK_QUADRILATERAL,
    (ufl.Cell("tetrahedron"), False): VTK_TETRAHEDRON,
    (ufl.Cell("tetrahedron"), True): VTK_LAGRANGE_TETRAHEDRON,
Esempio n. 7
0
logger = logging.getLogger("ffcx")

# Element families supported by FFCX
supported_families = ("Brezzi-Douglas-Marini", "Brezzi-Douglas-Fortin-Marini",
                      "Crouzeix-Raviart", "Discontinuous Lagrange",
                      "Discontinuous Raviart-Thomas", "HDiv Trace", "Lagrange",
                      "Lobatto", "Nedelec 1st kind H(curl)",
                      "Nedelec 2nd kind H(curl)", "Radau", "Raviart-Thomas",
                      "Real", "Bubble", "Quadrature", "Regge",
                      "Hellan-Herrmann-Johnson", "Q", "DQ",
                      "TensorProductElement", "Gauss-Lobatto-Legendre")

# Cache for computed elements
_cache = {}

_tpc_quadrilateral = ufl.TensorProductCell(ufl.interval, ufl.interval)
_tpc_hexahedron = ufl.TensorProductCell(ufl.quadrilateral, ufl.interval)


class SpaceOfReals(object):
    """Constant over the entire domain, rather than just cellwise."""


def reference_cell_vertices(cellname):
    """Return dict of coordinates of reference cell vertices for this 'cellname'."""
    return FIAT.ufc_cell(cellname).get_vertices()


@functools.singledispatch
def _create_element(element):
    raise ValueError("Element type is not supported.")
Esempio n. 8
0
__all__ = ("File", )


VTK_INTERVAL = 3
VTK_TRIANGLE = 5
VTK_QUADRILATERAL = 9
VTK_TETRAHEDRON = 10
VTK_HEXAHEDRON = 12
VTK_WEDGE = 13

cells = {
    ufl.Cell("interval"): VTK_INTERVAL,
    ufl.Cell("triangle"): VTK_TRIANGLE,
    ufl.Cell("quadrilateral"): VTK_QUADRILATERAL,
    ufl.TensorProductCell(ufl.Cell("interval"),
                          ufl.Cell("interval")): VTK_QUADRILATERAL,
    ufl.Cell("tetrahedron"): VTK_TETRAHEDRON,
    ufl.TensorProductCell(ufl.Cell("triangle"),
                          ufl.Cell("interval")): VTK_WEDGE,
    ufl.TensorProductCell(ufl.Cell("quadrilateral"),
                          ufl.Cell("interval")): VTK_HEXAHEDRON
}


OFunction = collections.namedtuple("OFunction", ["array", "name", "function"])


def is_cg(V):
    """Is the provided space continuous?

    :arg V: A FunctionSpace.
Esempio n. 9
0
    return finat.HDivElement(finat_elem), deps


@convert.register(ufl.HCurlElement)
def convert_hcurlelement(element, **kwargs):
    finat_elem, deps = _create_element(element._element, **kwargs)
    return finat.HCurlElement(finat_elem), deps


@convert.register(ufl.RestrictedElement)
def convert_restrictedelement(element, **kwargs):
    # Fall back on FIAT
    return fiat_compat(element), set()


quad_tpc = ufl.TensorProductCell(ufl.interval, ufl.interval)
_cache = weakref.WeakKeyDictionary()


def create_element(ufl_element, shape_innermost=True):
    """Create a FInAT element (suitable for tabulating with) given a UFL element.

    :arg ufl_element: The UFL element to create a FInAT element from.
    :arg shape_innermost: Vector/tensor indices come after basis function indices
    """
    finat_element, deps = _create_element(ufl_element,
                                          shape_innermost=shape_innermost)
    return finat_element


def _create_element(ufl_element, **kwargs):
Esempio n. 10
0
    def init_cell_orientations(self, expr):
        """Compute and initialise :attr:`cell_orientations` relative to a specified orientation.

        :arg expr: an :class:`.Expression` evaluated to produce a
             reference normal direction.

        """
        import firedrake.function as function
        import firedrake.functionspace as functionspace

        if expr.value_shape()[0] != 3:
            raise NotImplementedError('Only implemented for 3-vectors')
        if self.ufl_cell() not in (ufl.Cell('triangle', 3),
                                   ufl.Cell("quadrilateral", 3),
                                   ufl.TensorProductCell(ufl.Cell('interval'), ufl.Cell('interval'),
                                                         geometric_dimension=3)):
            raise NotImplementedError('Only implemented for triangles and quadrilaterals embedded in 3d')

        if hasattr(self.topology, '_cell_orientations'):
            raise RuntimeError("init_cell_orientations already called, did you mean to do so again?")

        v0 = lambda x: ast.Symbol("v0", (x,))
        v1 = lambda x: ast.Symbol("v1", (x,))
        n = lambda x: ast.Symbol("n", (x,))
        x = lambda x: ast.Symbol("x", (x,))
        coords = lambda x, y: ast.Symbol("coords", (x, y))

        body = []
        body += [ast.Decl("double", v(3)) for v in [v0, v1, n, x]]
        body.append(ast.Decl("double", "dot"))
        body.append(ast.Assign("dot", 0.0))
        body.append(ast.Decl("int", "i"))

        # if triangle, use v0 = x1 - x0, v1 = x2 - x0
        # otherwise, for the various quads, use v0 = x2 - x0, v1 = x1 - x0
        # recall reference element ordering:
        # triangle: 2        quad: 1 3
        #           0 1            0 2
        if self.ufl_cell() == ufl.Cell('triangle', 3):
            body.append(ast.For(ast.Assign("i", 0), ast.Less("i", 3), ast.Incr("i", 1),
                                [ast.Assign(v0("i"), ast.Sub(coords(1, "i"), coords(0, "i"))),
                                 ast.Assign(v1("i"), ast.Sub(coords(2, "i"), coords(0, "i"))),
                                 ast.Assign(x("i"), 0.0)]))
        else:
            body.append(ast.For(ast.Assign("i", 0), ast.Less("i", 3), ast.Incr("i", 1),
                                [ast.Assign(v0("i"), ast.Sub(coords(2, "i"), coords(0, "i"))),
                                 ast.Assign(v1("i"), ast.Sub(coords(1, "i"), coords(0, "i"))),
                                 ast.Assign(x("i"), 0.0)]))

        # n = v0 x v1
        body.append(ast.Assign(n(0), ast.Sub(ast.Prod(v0(1), v1(2)), ast.Prod(v0(2), v1(1)))))
        body.append(ast.Assign(n(1), ast.Sub(ast.Prod(v0(2), v1(0)), ast.Prod(v0(0), v1(2)))))
        body.append(ast.Assign(n(2), ast.Sub(ast.Prod(v0(0), v1(1)), ast.Prod(v0(1), v1(0)))))

        body.append(ast.For(ast.Assign("i", 0), ast.Less("i", 3), ast.Incr("i", 1),
                            [ast.Incr(x(j), coords("i", j)) for j in range(3)]))

        body.extend([ast.FlatBlock("dot += (%(x)s) * n[%(i)d];\n" % {"x": x_, "i": i})
                     for i, x_ in enumerate(expr.code)])
        body.append(ast.Assign("orientation[0][0]", ast.Ternary(ast.Less("dot", 0), 1, 0)))

        kernel = op2.Kernel(ast.FunDecl("void", "cell_orientations",
                                        [ast.Decl("int**", "orientation"),
                                         ast.Decl("double**", "coords")],
                                        ast.Block(body)),
                            "cell_orientations")

        # Build the cell orientations as a DG0 field (so that we can
        # pass it in for facet integrals and the like)
        fs = functionspace.FunctionSpace(self, 'DG', 0)
        cell_orientations = function.Function(fs, name="cell_orientations", dtype=np.int32)
        op2.par_loop(kernel, self.cell_set,
                     cell_orientations.dat(op2.WRITE, cell_orientations.cell_node_map()),
                     self.coordinates.dat(op2.READ, self.coordinates.cell_node_map()))
        self.topology._cell_orientations = cell_orientations