예제 #1
0
    def __init__(self, element):

        nodes = element.dual.nodes
        dim = element.ref_el.get_spatial_dimension()

        if dim == 2:
            ref_el = UFCQuadrilateral()
        elif dim == 3:
            ref_el = UFCHexahedron()
        else:
            raise ValueError("Illegal element dimension %s" % dim)

        entity_ids = element.dual.entity_ids

        flat_entity_ids = flatten_entities(entity_ids)
        dual = DualSet(nodes, ref_el, flat_entity_ids)
        super(FlattenedDimensions, self).__init__(ref_el, dual,
                                                  element.get_order(),
                                                  element.get_formdegree(),
                                                  element._mapping)
        self.element = element

        # Construct unflattening map for passing correct values to tabulate()
        self.unflattening_map = compute_unflattening_map(
            self.element.ref_el.get_topology())
예제 #2
0
def compute_pointwise_dual(el, pts):
    """Constructs a dual basis to the basis for el as a linear combination
    of a set of pointwise evaluations.  This is useful when the
    prescribed finite element isn't Ciarlet (e.g. the basis functions
    are provided explicitly as formulae).  Alternately, the element's
    given dual basis may involve differentiation, making run-time
    interpolation difficult in FIAT clients.  The pointwise dual,
    consisting only of pointwise evaluations, will effectively replace
    these derivatives with (automatically determined) finite
    differences.  This is exact on the polynomial space, but is an
    approximation if applied to functions outside the space.

    :param el: a :class:`FiniteElement`.
    :param pts: an iterable of points with the same length as el's
                dimension.  These points must be unisolvent for the
                polynomial space
    :returns: a :class `DualSet`
    """
    nbf = el.space_dimension()

    T = el.ref_el
    sd = T.get_spatial_dimension()

    assert np.asarray(pts).shape == (int(nbf / np.prod(el.value_shape())), sd)

    z = tuple([0] * sd)

    nds = []

    V = el.tabulate(0, pts)[z]

    # Make a square system, invert, and then put it back in the right
    # shape so we have (nbf, ..., npts) with more dimensions
    # for vector or tensor-valued elements.
    alphas = np.linalg.inv(V.reshape((nbf, -1)).T).reshape(V.shape)

    # Each row of alphas gives the coefficients of a functional,
    # represented, as elsewhere in FIAT, as a summation of
    # components of the input at particular points.

    # This logic picks out the points and components for which the
    # weights are actually nonzero to construct the functional.

    pts = np.asarray(pts)
    for coeffs in alphas:
        pt_dict = defaultdict(list)
        nonzero = np.where(np.abs(coeffs) > 1.e-12)
        *comp, pt_index = nonzero

        for pt, coeff_comp in zip(pts[pt_index],
                                  zip_longest(coeffs[nonzero],
                                              zip(*comp), fillvalue=())):
            pt_dict[tuple(pt)].append(coeff_comp)

        nds.append(Functional(T, el.value_shape(), dict(pt_dict), {}, "node"))

    return DualSet(nds, T, el.entity_dofs())
예제 #3
0
    def __init__(self, element, indices=None, restriction_domain=None):
        '''For sake of argument, indices overrides restriction_domain'''

        if not (indices or restriction_domain):
            raise RuntimeError(
                "Either indices or restriction_domain must be passed in")

        if not indices:
            indices = _get_indices(element, restriction_domain)

        if isinstance(indices, str):
            raise RuntimeError(
                "variable 'indices' was a string; did you forget to use a keyword?"
            )

        if len(indices) == 0:
            raise ValueError("No point in creating empty RestrictedElement.")

        self._element = element
        self._indices = indices

        # Fetch reference element
        ref_el = element.get_reference_element()

        # Restrict primal set
        poly_set = element.get_nodal_basis().take(indices)

        # Restrict dual set
        dof_counter = 0
        entity_ids = {}
        nodes = []
        nodes_old = element.dual_basis()
        for d, entities in element.entity_dofs().items():
            entity_ids[d] = {}
            for entity, dofs in entities.items():
                entity_ids[d][entity] = []
                for dof in dofs:
                    if dof not in indices:
                        continue
                    entity_ids[d][entity].append(dof_counter)
                    dof_counter += 1
                    nodes.append(nodes_old[dof])
        assert dof_counter == len(indices)
        dual = DualSet(nodes, ref_el, entity_ids)

        # Restrict mapping
        mapping_old = element.mapping()
        mapping_new = [mapping_old[dof] for dof in indices]
        assert all(e_mapping == mapping_new[0] for e_mapping in mapping_new)

        # Call constructor of CiarletElement
        super(RestrictedElement, self).__init__(poly_set, dual, 0,
                                                element.get_formdegree(),
                                                mapping_new[0])
예제 #4
0
    def __init__(self, *elements):

        # Test elements are nodal
        if not all(e.is_nodal() for e in elements):
            raise ValueError("Not all elements given for construction "
                             "of NodalEnrichedElement are nodal")

        # Extract common data
        ref_el = elements[0].get_reference_element()
        expansion_set = elements[0].get_nodal_basis().get_expansion_set()
        degree = min(e.get_nodal_basis().get_degree() for e in elements)
        embedded_degree = max(e.get_nodal_basis().get_embedded_degree()
                              for e in elements)
        order = max(e.get_order() for e in elements)
        mapping = elements[0].mapping()[0]
        formdegree = None if any(e.get_formdegree() is None for e in elements) \
            else max(e.get_formdegree() for e in elements)
        value_shape = elements[0].value_shape()

        # Sanity check
        assert all(e.get_nodal_basis().get_reference_element() == ref_el
                   for e in elements)
        assert all(
            type(e.get_nodal_basis().get_expansion_set()) == type(
                expansion_set) for e in elements)
        assert all(e_mapping == mapping for e in elements
                   for e_mapping in e.mapping())
        assert all(e.value_shape() == value_shape for e in elements)

        # Merge polynomial sets
        coeffs = _merge_coeffs([e.get_coeffs() for e in elements])
        dmats = _merge_dmats([e.dmats() for e in elements])
        poly_set = PolynomialSet(ref_el, degree, embedded_degree,
                                 expansion_set, coeffs, dmats)

        # Renumber dof numbers
        offsets = np.cumsum([0] + [e.space_dimension() for e in elements[:-1]])
        entity_ids = _merge_entity_ids((e.entity_dofs() for e in elements),
                                       offsets)

        # Merge dual bases
        nodes = [node for e in elements for node in e.dual_basis()]
        dual_set = DualSet(nodes, ref_el, entity_ids)

        # CiarletElement constructor adjusts poly_set coefficients s.t.
        # dual_set is really dual to poly_set
        super(NodalEnrichedElement, self).__init__(poly_set,
                                                   dual_set,
                                                   order,
                                                   formdegree=formdegree,
                                                   mapping=mapping)
예제 #5
0
    def __init__(self, ref_el, points):
        # Create entity dofs.
        entity_dofs = {dim: {entity: [] for entity in entities}
                       for dim, entities in ref_el.get_topology().items()}
        entity_dofs[ref_el.get_dimension()] = {0: list(range(len(points)))}

        # The dual nodes are PointEvaluations at the quadrature points.
        # FIXME: KBO: Check if this gives expected results for code like evaluate_dof.
        nodes = [PointEvaluation(ref_el, tuple(point)) for point in points]

        # Construct the dual set
        dual = DualSet(nodes, ref_el, entity_dofs)

        super(QuadratureElement, self).__init__(ref_el, dual, order=None)
        self._points = points  # save the quadrature points
예제 #6
0
    def __init__(self, element):
        self._element = element
        new_entity_ids = {}
        topology = element.get_reference_element().get_topology()
        for dim in sorted(topology):
            new_entity_ids[dim] = {}
            for ent in sorted(topology[dim]):
                new_entity_ids[dim][ent] = []

        new_entity_ids[dim][0] = list(range(element.space_dimension()))
        # re-initialise the dual, so entity_closure_dofs is recalculated
        self.dual = DualSet(element.dual_basis(), element.get_reference_element(), new_entity_ids)

        # fully discontinuous
        self.formdegree = element.get_reference_element().get_spatial_dimension()
예제 #7
0
파일: enriched.py 프로젝트: vsujeesh/fiat
    def __init__(self, *elements):
        # Firstly, check it makes sense to enrich.  Elements must have:
        # - same reference element
        # - same mapping
        # - same value shape
        if len(set(e.get_reference_element() for e in elements)) > 1:
            raise ValueError(
                "Elements must be defined on the same reference element")
        if len(set(m for e in elements for m in e.mapping())) > 1:
            raise ValueError("Elements must have same mapping")
        if len(set(e.value_shape() for e in elements)) > 1:
            raise ValueError("Elements must have the same value shape")

        # order is at least max, possibly more, though getting this
        # right isn't important AFAIK
        order = max(e.get_order() for e in elements)
        # form degree is essentially max (not true for Hdiv/Hcurl,
        # but this will raise an error above anyway).
        # E.g. an H^1 function enriched with an L^2 is now just L^2.
        if any(e.get_formdegree() is None for e in elements):
            formdegree = None
        else:
            formdegree = max(e.get_formdegree() for e in elements)

        # set up reference element and mapping, following checks above
        ref_el, = set(e.get_reference_element() for e in elements)
        mapping, = set(m for e in elements for m in e.mapping())

        # set up entity_ids - for each geometric entity, just concatenate
        # the entities of the constituent elements
        entity_ids = concatenate_entity_dofs(ref_el, elements)

        # set up dual basis - just concatenation
        nodes = list(chain.from_iterable(e.dual_basis() for e in elements))
        dual = DualSet(nodes, ref_el, entity_ids)

        super(EnrichedElement, self).__init__(ref_el, dual, order, formdegree,
                                              mapping)

        # required degree (for quadrature) is definitely max
        self.polydegree = max(e.degree() for e in elements)

        # Store subelements
        self._elements = elements
예제 #8
0
파일: mixed.py 프로젝트: strekalloff/mpm
    def __init__(self, elements, ref_el=None):
        elements = tuple(elements)

        cells = set(e.get_reference_element() for e in elements)
        if ref_el is not None:
            cells.add(ref_el)
        ref_el, = cells

        # These functionals are absolutely wrong, they all map from
        # functions of the wrong shape, and potentially of different
        # shapes.  However, they are wrong precisely as FFC hacks
        # expect them to be. :(
        nodes = [L for e in elements for L in e.dual_basis()]

        entity_dofs = concatenate_entity_dofs(ref_el, elements)

        dual = DualSet(nodes, ref_el, entity_dofs)
        super(MixedElement, self).__init__(ref_el, dual, None, mapping=None)
        self._elements = elements
예제 #9
0
    def __init__(self, element):
        """ Constructs a FlattenToQuad element.

        :arg element: a fiat element
        """
        nodes = element.dual.nodes
        ref_el = FiredrakeQuadrilateral()
        entity_ids = element.dual.entity_ids

        flat_entity_ids = {}
        flat_entity_ids[0] = entity_ids[(0, 0)]
        flat_entity_ids[1] = dict(
            enumerate([v for k, v in sorted(entity_ids[(0, 1)].items())] +
                      [v for k, v in sorted(entity_ids[(1, 0)].items())]))
        flat_entity_ids[2] = entity_ids[(1, 1)]
        dual = DualSet(nodes, ref_el, flat_entity_ids)
        super(FlattenToQuad, self).__init__(ref_el, dual, element.get_order(),
                                            element.get_formdegree(),
                                            element._mapping)
        self.element = element
예제 #10
0
파일: hdiv_trace.py 프로젝트: vsujeesh/fiat
    def __init__(self, ref_el, degree):
        """Constructor for the HDivTrace element.

        :arg ref_el: A reference element, which may be a tensor product
                     cell.
        :arg degree: The degree of approximation. If on a tensor product
                     cell, then provide a tuple of degrees if you want
                     varying degrees.
        """
        sd = ref_el.get_spatial_dimension()
        if sd in (0, 1):
            raise ValueError("Cannot take the trace of a %d-dim cell." % sd)

        # Store the degrees if on a tensor product cell
        if ref_el.get_shape() == TENSORPRODUCT:
            try:
                degree = tuple(degree)
            except TypeError:
                degree = (degree,) * len(ref_el.cells)

            assert len(ref_el.cells) == len(degree), (
                "Number of specified degrees must be equal to the number of cells."
            )
        else:
            if ref_el.get_shape() not in [TRIANGLE, TETRAHEDRON, QUADRILATERAL]:
                raise NotImplementedError(
                    "Trace element on a %s not implemented" % type(ref_el)
                )
            # Cannot have varying degrees for these reference cells
            if isinstance(degree, tuple):
                raise ValueError("Must have a tensor product cell if providing multiple degrees")

        # Initialize entity dofs and construct the DG elements
        # for the facets
        facet_sd = sd - 1
        dg_elements = {}
        entity_dofs = {}
        topology = ref_el.get_topology()
        for top_dim, entities in topology.items():
            cell = ref_el.construct_subelement(top_dim)
            entity_dofs[top_dim] = {}

            # We have a facet entity!
            if cell.get_spatial_dimension() == facet_sd:
                dg_elements[top_dim] = construct_dg_element(cell, degree)
            # Initialize
            for entity in entities:
                entity_dofs[top_dim][entity] = []

        # Compute the dof numbering for all facet entities
        # and extract nodes
        offset = 0
        pts = []
        for facet_dim in sorted(dg_elements):
            element = dg_elements[facet_dim]
            nf = element.space_dimension()
            num_facets = len(topology[facet_dim])

            for i in range(num_facets):
                entity_dofs[facet_dim][i] = list(range(offset, offset + nf))
                offset += nf

                # Run over nodes and collect the points for point evaluations
                for dof in element.dual_basis():
                    facet_pt, = dof.get_point_dict()
                    transform = ref_el.get_entity_transform(facet_dim, i)
                    pts.append(tuple(transform(facet_pt)))

        # Setting up dual basis - only point evaluations
        nodes = [PointEvaluation(ref_el, pt) for pt in pts]
        dual = DualSet(nodes, ref_el, entity_dofs)

        # Degree of the element
        deg = max([e.degree() for e in dg_elements.values()])

        super(HDivTrace, self).__init__(ref_el, dual, order=deg,
                                        formdegree=facet_sd,
                                        mapping="affine")

        # Set up facet elements
        self.dg_elements = dg_elements

        # Degree for quadrature rule
        self.polydegree = deg
예제 #11
0
def create_actual_fiat_element(ufl_element):
    fiat_element = None

    # Check if finite element family is supported by FIAT
    family = ufl_element.family()
    if not family in FIAT.supported_elements:
        # We support RTCE and RTCF elements on quadrilaterals,
        # even though they are not supported by FIAT.
        if ufl_element.cell().cellname() == "quadrilateral":
            fiat_element = create_actual_fiat_element(
                reconstruct_element(ufl_element, ufl_element.family(),
                                    _quad_opc, ufl_element.degree()))
        else:
            if family in ("FacetElement", "InteriorElement"):
                # rescue these
                pass
            else:
                error(
                    "Sorry, finite element of type \"%s\" are not supported by FIAT.",
                    family)

    # Skip all cases if FIAT element is ready already
    if fiat_element is not None:
        pass
    # HDiv and HCurl elements have family "OuterProductElement",
    # so get matching FIAT element directly rather than via lookup
    elif isinstance(ufl_element, ufl.HDivElement):
        fiat_element = FIAT.Hdiv(create_element(ufl_element._element))
    elif isinstance(ufl_element, ufl.HCurlElement):
        fiat_element = FIAT.Hcurl(create_element(ufl_element._element))
    elif isinstance(ufl_element, ufl.FacetElement):
        fiat_element = FIAT.RestrictedElement(create_element(
            ufl_element._element),
                                              restriction_domain="facet")
    elif isinstance(ufl_element, ufl.InteriorElement):
        fiat_element = FIAT.RestrictedElement(create_element(
            ufl_element._element),
                                              restriction_domain="interior")
    else:
        # Look up FIAT element
        ElementClass = FIAT.supported_elements[family]

        if isinstance(ufl_element, ufl.EnrichedElement):
            A = create_element(ufl_element._elements[0])
            B = create_element(ufl_element._elements[1])
            fiat_element = ElementClass(A, B)
        # OPVE is only here to satisfy calls from Firedrake
        elif isinstance(
                ufl_element,
            (ufl.OuterProductElement, ufl.OuterProductVectorElement,
             ufl.OuterProductTensorElement)):
            cell = ufl_element.cell()
            if not isinstance(cell, ufl.OuterProductCell):
                error(
                    "An OuterProductElement must have an OuterProductCell as domain, sorry."
                )

            A = create_element(ufl_element._A)
            B = create_element(ufl_element._B)
            fiat_element = ElementClass(A, B)
        elif isinstance(ufl_element, (ufl.BrokenElement, ufl.TraceElement)):
            fiat_element = ElementClass(create_element(ufl_element._element))
        elif ufl_element.cell().cellname() == "quadrilateral":
            fiat_element = create_actual_fiat_element(
                ufl_element.reconstruct(domain=_quad_opc))
        else:
            # "Normal element" case
            cell = ufl_element.cell()
            degree = ufl_element.degree()
            fiat_cell = reference_cell(cell)
            fiat_element = ElementClass(fiat_cell, degree)

    if fiat_element is None:
        raise Exception(
            "Something strange happened: reached end of function without returning an element"
        )

    if ufl_element.cell().cellname() == "quadrilateral" and \
            isinstance(fiat_element.get_reference_element(),
                       FIAT.reference_element.two_product_cell):
        # Flatten tensor product element

        from FIAT.reference_element import FiredrakeQuadrilateral
        from FIAT.dual_set import DualSet

        nodes = fiat_element.dual.nodes
        ref_el = FiredrakeQuadrilateral()

        entity_ids = fiat_element.dual.entity_ids
        flat_entity_ids = {}
        flat_entity_ids[0] = entity_ids[(0, 0)]
        flat_entity_ids[1] = dict(
            enumerate(entity_ids[(0, 1)].values() +
                      entity_ids[(1, 0)].values()))
        flat_entity_ids[2] = entity_ids[(1, 1)]

        fiat_element.dual = DualSet(nodes, ref_el, flat_entity_ids)
        fiat_element.ref_el = ref_el

    return fiat_element
예제 #12
0
파일: enriched.py 프로젝트: wei-pan/fiat
    def __init__(self, *elements):
        assert len(
            elements
        ) == 2, "EnrichedElement only implemented for two subelements"
        A, B = elements

        # Firstly, check it makes sense to enrich.  Elements must have:
        # - same reference element
        # - same mapping
        # - same value shape
        if not A.get_reference_element() == B.get_reference_element():
            raise ValueError(
                "Elements must be defined on the same reference element")
        if not A.mapping()[0] == B.mapping()[0]:
            raise ValueError("Elements must have same mapping")
        if not A.value_shape() == B.value_shape():
            raise ValueError("Elements must have the same value shape")

        # order is at least max, possibly more, though getting this
        # right isn't important AFAIK
        order = max(A.get_order(), B.get_order())
        # form degree is essentially max (not true for Hdiv/Hcurl,
        # but this will raise an error above anyway).
        # E.g. an H^1 function enriched with an L^2 is now just L^2.
        if A.get_formdegree() is None or B.get_formdegree() is None:
            formdegree = None
        else:
            formdegree = max(A.get_formdegree(), B.get_formdegree())

        # set up reference element and mapping, following checks above
        ref_el = A.get_reference_element()
        mapping = A.mapping()[0]

        # set up entity_ids - for each geometric entity, just concatenate
        # the entities of the constituent elements
        Adofs = A.entity_dofs()
        Bdofs = B.entity_dofs()
        offset = A.space_dimension()  # number of entities belonging to A
        entity_ids = {}

        for ent_dim in Adofs:
            entity_ids[ent_dim] = {}
            for ent_dim_index in Adofs[ent_dim]:
                entlist = copy(Adofs[ent_dim][ent_dim_index])
                entlist += [c + offset for c in Bdofs[ent_dim][ent_dim_index]]
                entity_ids[ent_dim][ent_dim_index] = entlist

        # set up dual basis - just concatenation
        nodes = A.dual_basis() + B.dual_basis()
        dual = DualSet(nodes, ref_el, entity_ids)

        super(EnrichedElement, self).__init__(ref_el, dual, order, formdegree,
                                              mapping)

        # Set up constituent elements
        self.A = A
        self.B = B

        # required degree (for quadrature) is definitely max
        self.polydegree = max(A.degree(), B.degree())

        # Store subelements
        self._elements = elements