Source code for ufl.finiteelement.enrichedelement

# -*- coding: utf-8 -*-
"This module defines the UFL finite element classes."

# Copyright (C) 2008-2016 Martin Sandve Alnæs
#
# This file is part of UFL (https://www.fenicsproject.org)
#
# SPDX-License-Identifier:    LGPL-3.0-or-later
#
# Modified by Kristian B. Oelgaard
# Modified by Marie E. Rognes 2010, 2012
# Modified by Massimiliano Leoni, 2016

from ufl.log import error
from ufl.finiteelement.finiteelementbase import FiniteElementBase


[docs]class EnrichedElementBase(FiniteElementBase): """The vector sum of several finite element spaces: .. math:: \\textrm{EnrichedElement}(V, Q) = \\{v + q | v \\in V, q \\in Q\\}. """ def __init__(self, *elements): self._elements = elements cell = elements[0].cell() if not all(e.cell() == cell for e in elements[1:]): error("Cell mismatch for sub elements of enriched element.") if isinstance(elements[0].degree(), int): degrees = {e.degree() for e in elements} - {None} degree = max(degrees) if degrees else None else: degree = tuple(map(max, zip(*[e.degree() for e in elements]))) # We can allow the scheme not to be defined, but all defined # should be equal quad_schemes = [e.quadrature_scheme() for e in elements] quad_schemes = [qs for qs in quad_schemes if qs is not None] quad_scheme = quad_schemes[0] if quad_schemes else None if not all(qs == quad_scheme for qs in quad_schemes): error("Quadrature scheme mismatch.") value_shape = elements[0].value_shape() if not all(e.value_shape() == value_shape for e in elements[1:]): error("Element value shape mismatch.") reference_value_shape = elements[0].reference_value_shape() if not all(e.reference_value_shape() == reference_value_shape for e in elements[1:]): error("Element reference value shape mismatch.") # mapping = elements[0].mapping() # FIXME: This fails for a mixed subelement here. # if not all(e.mapping() == mapping for e in elements[1:]): # error("Element mapping mismatch.") # Get name of subclass: EnrichedElement or NodalEnrichedElement class_name = self.__class__.__name__ # Initialize element data FiniteElementBase.__init__(self, class_name, cell, degree, quad_scheme, value_shape, reference_value_shape) # Cache repr string self._repr = "%s(%s)" % (class_name, ", ".join(repr(e) for e in self._elements))
[docs] def mapping(self): return self._elements[0].mapping()
[docs] def sobolev_space(self): "Return the underlying Sobolev space." elements = [e for e in self._elements] if all(e.sobolev_space() == elements[0].sobolev_space() for e in elements): return elements[0].sobolev_space() else: # Find smallest shared Sobolev space over all sub elements spaces = [e.sobolev_space() for e in elements] superspaces = [{s} | set(s.parents) for s in spaces] intersect = set.intersection(*superspaces) for s in intersect.copy(): for parent in s.parents: intersect.discard(parent) sobolev_space, = intersect return sobolev_space
[docs] def reconstruct(self, **kwargs): return type(self)(*[e.reconstruct(**kwargs) for e in self._elements])
[docs]class EnrichedElement(EnrichedElementBase): """The vector sum of several finite element spaces: .. math:: \\textrm{EnrichedElement}(V, Q) = \\{v + q | v \\in V, q \\in Q\\}. Dual basis is a concatenation of subelements dual bases; primal basis is a concatenation of subelements primal bases; resulting element is not nodal even when subelements are. Structured basis may be exploited in form compilers. """
[docs] def is_cellwise_constant(self): """Return whether the basis functions of this element is spatially constant over each cell.""" return all(e.is_cellwise_constant() for e in self._elements)
def __str__(self): "Format as string for pretty printing." return "<%s>" % " + ".join(str(e) for e in self._elements)
[docs] def shortstr(self): "Format as string for pretty printing." return "<%s>" % " + ".join(e.shortstr() for e in self._elements)
[docs]class NodalEnrichedElement(EnrichedElementBase): """The vector sum of several finite element spaces: .. math:: \\textrm{EnrichedElement}(V, Q) = \\{v + q | v \\in V, q \\in Q\\}. Primal basis is reorthogonalized to dual basis which is a concatenation of subelements dual bases; resulting element is nodal. """
[docs] def is_cellwise_constant(self): """Return whether the basis functions of this element is spatially constant over each cell.""" return False
def __str__(self): "Format as string for pretty printing." return "<Nodal enriched element(%s)>" % ", ".join(str(e) for e in self._elements)
[docs] def shortstr(self): "Format as string for pretty printing." return "NodalEnriched(%s)" % ", ".join(e.shortstr() for e in self._elements)