Source code for FIAT.crouzeix_raviart

# Copyright (C) 2010 Marie E. Rognes
#
# This file is part of FIAT (https://www.fenicsproject.org)
#
# SPDX-License-Identifier:    LGPL-3.0-or-later
#
# Written by Marie E. Rognes <meg@simula.no> based on original
# implementation by Robert C. Kirby.
#
# Last changed: 2010-01-28

import numpy
from FIAT import finite_element, polynomial_set, dual_set, functional
from FIAT.check_format_variant import check_format_variant
from FIAT.quadrature_schemes import create_quadrature
from FIAT.quadrature import FacetQuadratureRule


[docs] class CrouzeixRaviartDualSet(dual_set.DualSet): def __init__(self, ref_el, degree, variant, interpolant_deg): # Get topology dictionary sd = ref_el.get_spatial_dimension() top = ref_el.get_topology() if degree > 1 and sd != 2: raise NotImplementedError("High-order Crouzeix-Raviart is only implemented on triangles.") # Initialize empty nodes and entity_ids entity_ids = {dim: {entity: [] for entity in top[dim]} for dim in top} nodes = [] # Construct nodes and entity_ids if variant == "integral": for dim in sorted(top): if dim == 0 and dim != sd-1: # Skip vertex dofs continue facet = ref_el.construct_subelement(dim) if dim == 0: Q_facet = create_quadrature(facet, degree + interpolant_deg-1) Phis = numpy.ones((1, len(Q_facet.pts))) else: k = degree - 1 if dim == sd-1 else degree - (1+dim) if k < 0: continue Q_facet = create_quadrature(facet, k + interpolant_deg) poly_set = polynomial_set.ONPolynomialSet(facet, k) Phis = poly_set.tabulate(Q_facet.get_points())[(0,) * dim] for i in sorted(top[dim]): cur = len(nodes) Q = FacetQuadratureRule(ref_el, dim, i, Q_facet) scale = 1 / Q.jacobian_determinant() phis = scale * Phis nodes.extend(functional.IntegralMoment(ref_el, Q, phi) for phi in phis) entity_ids[dim][i].extend(range(cur, len(nodes))) else: for dim in sorted(top): if dim == 0 and dim != sd-1: # Skip vertex dofs continue for i in sorted(top[dim]): cur = len(nodes) if dim == sd-1 and dim != 0: pts = ref_el.make_points(dim, i, degree-1, variant="gl", interior=0) else: pts = ref_el.make_points(dim, i, degree, variant="gll") nodes.extend(functional.PointEvaluation(ref_el, x) for x in pts) entity_ids[dim][i].extend(range(cur, len(nodes))) super().__init__(nodes, ref_el, entity_ids)
[docs] class CrouzeixRaviart(finite_element.CiarletElement): """The Crouzeix-Raviart finite element: K: Triangle/Tetrahedron Polynomial space: P_k Dual basis: Evaluation at points or integral moments """ def __init__(self, ref_el, degree, variant=None): variant, interpolant_deg = check_format_variant(variant, degree) if degree % 2 != 1: raise ValueError("Crouzeix-Raviart only defined for odd degree") space = polynomial_set.ONPolynomialSet(ref_el, degree, variant="bubble") dual = CrouzeixRaviartDualSet(ref_el, degree, variant, interpolant_deg) super().__init__(space, dual, degree)