forked from FEniCS/fiat
-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathcrouzeix_raviart.py
More file actions
97 lines (81 loc) · 3.88 KB
/
Copy pathcrouzeix_raviart.py
File metadata and controls
97 lines (81 loc) · 3.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# 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, macro
from FIAT.check_format_variant import check_format_variant, parse_quadrature_scheme
from FIAT.quadrature import FacetQuadratureRule
class CrouzeixRaviartDualSet(dual_set.DualSet):
def __init__(self, ref_el, degree, variant, interpolant_deg, quad_scheme):
# 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 = parse_quadrature_scheme(facet, degree + interpolant_deg-1, quad_scheme)
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 = parse_quadrature_scheme(facet, k + interpolant_deg, quad_scheme)
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, avg=True)
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)
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
"""
DEFAULT_DEGREE = 1
def __init__(self, ref_el, degree, variant=None, quad_scheme=None):
degree = self._parse_degree(degree)
if degree % 2 != 1:
raise ValueError("Crouzeix-Raviart only defined for odd degree")
splitting, variant, interpolant_deg = check_format_variant(variant, degree)
if splitting is not None:
ref_el = splitting(ref_el)
if ref_el.is_macrocell():
base_element = type(self)(ref_el.get_parent(), degree)
poly_set = macro.MacroPolynomialSet(ref_el, base_element)
else:
poly_set = polynomial_set.ONPolynomialSet(ref_el, degree)
dual = CrouzeixRaviartDualSet(ref_el, degree, variant, interpolant_deg, quad_scheme)
super().__init__(poly_set, dual, degree)