88
99import numpy
1010
11- from FIAT import finite_element , dual_set , functional , P0
11+ from FIAT import finite_element , dual_set , functional
1212from FIAT .reference_element import symmetric_simplex
13- from FIAT .orientation_utils import make_entity_permutations_simplex
1413from FIAT .quadrature import FacetQuadratureRule
1514from FIAT .quadrature_schemes import create_quadrature
1615from FIAT .polynomial_set import ONPolynomialSet , make_bubbles
17- from FIAT .check_format_variant import parse_lagrange_variant
16+ from FIAT .check_format_variant import check_format_variant
17+ from FIAT .P0 import P0
1818
1919
2020def make_dual_bubbles (ref_el , degree , codim = 0 , interpolant_deg = None ):
2121 """Tabulate the L2-duals of the hierarchical C0 basis."""
22+ if ref_el .get_spatial_dimension () == 0 :
23+ degree = 0
2224 if interpolant_deg is None :
2325 interpolant_deg = degree
2426 Q = create_quadrature (ref_el , degree + interpolant_deg )
@@ -32,105 +34,86 @@ def make_dual_bubbles(ref_el, degree, codim=0, interpolant_deg=None):
3234
3335class LegendreDual (dual_set .DualSet ):
3436 """The dual basis for Legendre elements."""
35- def __init__ (self , ref_el , degree , codim = 0 ):
36- nodes = []
37- entity_ids = {}
38- entity_permutations = {}
39-
37+ def __init__ (self , ref_el , degree , codim = 0 , interpolant_deg = None ):
38+ if interpolant_deg is None :
39+ interpolant_deg = degree
4040 sd = ref_el .get_spatial_dimension ()
4141 top = ref_el .get_topology ()
42- for dim in sorted (top ):
43- npoints = degree + 1 if dim == sd - codim else 0
44- perms = make_entity_permutations_simplex (dim , npoints )
45- entity_permutations [dim ] = {}
46- entity_ids [dim ] = {}
47- if npoints == 0 :
48- for entity in sorted (top [dim ]):
49- entity_ids [dim ][entity ] = []
50- entity_permutations [dim ][entity ] = perms
51- continue
42+ entity_ids = {dim : {entity : [] for entity in top [dim ]} for dim in top }
43+ nodes = []
5244
53- ref_facet = ref_el .construct_subelement (dim )
54- poly_set = ONPolynomialSet (ref_facet , degree )
55- Q_ref = create_quadrature (ref_facet , 2 * degree )
56- phis = poly_set .tabulate (Q_ref .get_points ())[(0 ,) * dim ]
57- for entity in sorted (top [dim ]):
58- cur = len (nodes )
59- Q_facet = FacetQuadratureRule (ref_el , dim , entity , Q_ref )
60- nodes .extend (functional .IntegralMoment (ref_el , Q_facet , phi ) for phi in phis )
61- entity_ids [dim ][entity ] = list (range (cur , len (nodes )))
62- entity_permutations [dim ][entity ] = perms
45+ dim = sd - codim
46+ ref_facet = ref_el .construct_subelement (dim )
47+ poly_set = ONPolynomialSet (ref_facet , degree , scale = "L2 piola" )
48+ Q_ref = create_quadrature (ref_facet , degree + interpolant_deg )
49+ Phis = poly_set .tabulate (Q_ref .get_points ())[(0 ,) * dim ]
50+ for entity in sorted (top [dim ]):
51+ cur = len (nodes )
52+ Q_facet = FacetQuadratureRule (ref_el , dim , entity , Q_ref )
53+ # phis must transform like a d-form to undo the measure transformation
54+ scale = 1 / Q_facet .jacobian_determinant ()
55+ phis = scale * Phis
56+ nodes .extend (functional .IntegralMoment (ref_el , Q_facet , phi ) for phi in phis )
57+ entity_ids [dim ][entity ].extend (range (cur , len (nodes )))
6358
64- super ().__init__ (nodes , ref_el , entity_ids , entity_permutations )
59+ super ().__init__ (nodes , ref_el , entity_ids )
6560
6661
6762class Legendre (finite_element .CiarletElement ):
6863 """Simplicial discontinuous element with Legendre polynomials."""
6964 def __new__ (cls , ref_el , degree , variant = None ):
7065 if degree == 0 :
71- splitting , _ = parse_lagrange_variant (variant , integral = True )
72- if splitting is None :
66+ splitting , variant , interpolant_deg = check_format_variant (variant , degree )
67+ if splitting is None and interpolant_deg == 0 :
7368 # FIXME P0 on the split requires implementing SplitSimplicialComplex.symmetry_group_size()
74- return P0 . P0 (ref_el )
69+ return P0 (ref_el )
7570 return super ().__new__ (cls )
7671
7772 def __init__ (self , ref_el , degree , variant = None ):
78- splitting , _ = parse_lagrange_variant (variant , integral = True )
73+ splitting , variant , interpolant_deg = check_format_variant (variant , degree )
7974 if splitting is not None :
8075 ref_el = splitting (ref_el )
8176 poly_set = ONPolynomialSet (ref_el , degree )
82- dual = LegendreDual (ref_el , degree )
77+ dual = LegendreDual (ref_el , degree , interpolant_deg = interpolant_deg )
8378 formdegree = ref_el .get_spatial_dimension () # n-form
8479 super ().__init__ (poly_set , dual , degree , formdegree )
8580
8681
8782class IntegratedLegendreDual (dual_set .DualSet ):
8883 """The dual basis for integrated Legendre elements."""
89- def __init__ (self , ref_el , degree ):
84+ def __init__ (self , ref_el , degree , interpolant_deg = None ):
85+ if interpolant_deg is None :
86+ interpolant_deg = degree
87+ top = ref_el .get_topology ()
88+ entity_ids = {dim : {entity : [] for entity in top [dim ]} for dim in top }
9089 nodes = []
91- entity_ids = {}
92- entity_permutations = {}
9390
94- top = ref_el .get_topology ()
9591 for dim in sorted (top ):
96- perms = make_entity_permutations_simplex (dim , degree - dim )
97- entity_ids [dim ] = {}
98- entity_permutations [dim ] = {}
99- if dim == 0 or degree <= dim :
100- for entity in sorted (top [dim ]):
101- cur = len (nodes )
102- pts = ref_el .make_points (dim , entity , degree )
103- nodes .extend (functional .PointEvaluation (ref_el , pt ) for pt in pts )
104- entity_ids [dim ][entity ] = list (range (cur , len (nodes )))
105- entity_permutations [dim ][entity ] = perms
92+ if degree <= dim :
10693 continue
107-
10894 ref_facet = symmetric_simplex (dim )
109- Q_ref , phis = make_dual_bubbles (ref_facet , degree )
95+ Q_ref , Phis = make_dual_bubbles (ref_facet , degree , interpolant_deg = interpolant_deg )
11096 for entity in sorted (top [dim ]):
11197 cur = len (nodes )
11298 Q_facet = FacetQuadratureRule (ref_el , dim , entity , Q_ref )
113-
11499 # phis must transform like a d-form to undo the measure transformation
115100 scale = 1 / Q_facet .jacobian_determinant ()
116- Jphis = scale * phis
117-
118- nodes .extend (functional .IntegralMoment (ref_el , Q_facet , phi ) for phi in Jphis )
119- entity_ids [dim ][entity ] = list (range (cur , len (nodes )))
120- entity_permutations [dim ][entity ] = perms
101+ phis = scale * Phis
102+ nodes .extend (functional .IntegralMoment (ref_el , Q_facet , phi ) for phi in phis )
103+ entity_ids [dim ][entity ].extend (range (cur , len (nodes )))
121104
122- super ().__init__ (nodes , ref_el , entity_ids , entity_permutations )
105+ super ().__init__ (nodes , ref_el , entity_ids )
123106
124107
125108class IntegratedLegendre (finite_element .CiarletElement ):
126109 """Simplicial continuous element with integrated Legendre polynomials."""
127110 def __init__ (self , ref_el , degree , variant = None ):
128- splitting , _ = parse_lagrange_variant (variant , integral = True )
111+ splitting , variant , interpolant_deg = check_format_variant (variant , degree )
129112 if splitting is not None :
130113 ref_el = splitting (ref_el )
131114 if degree < 1 :
132115 raise ValueError (f"{ type (self ).__name__ } elements only valid for k >= 1" )
133116 poly_set = ONPolynomialSet (ref_el , degree , variant = "bubble" )
134- dual = IntegratedLegendreDual (ref_el , degree )
117+ dual = IntegratedLegendreDual (ref_el , degree , interpolant_deg = interpolant_deg )
135118 formdegree = 0 # 0-form
136119 super ().__init__ (poly_set , dual , degree , formdegree )
0 commit comments