11from FIAT import finite_element , dual_set , polynomial_set , expansions
2+ from FIAT .check_format_variant import check_format_variant
23from FIAT .functional import TensorBidirectionalIntegralMoment as BidirectionalMoment
34from FIAT .quadrature_schemes import create_quadrature
45from FIAT .quadrature import FacetQuadratureRule
@@ -12,34 +13,29 @@ def __init__(self, ref_el, degree):
1213 nodes = []
1314 entity_ids = {dim : {entity : [] for entity in sorted (top [dim ])} for dim in sorted (top )}
1415
15- # Face dofs: moments of normal-tangential components against a basis for Pk
16- ref_facet = ref_el .construct_subelement (sd - 1 )
17- Qref = create_quadrature (ref_facet , 2 * degree )
18- P = polynomial_set .ONPolynomialSet (ref_facet , degree )
19- phis = P .tabulate (Qref .get_points ())[(0 ,) * (sd - 1 )]
20- for f in sorted (top [sd - 1 ]):
21- cur = len (nodes )
22- Q = FacetQuadratureRule (ref_el , sd - 1 , f , Qref )
23- Jdet = Q .jacobian_determinant ()
24- normal = ref_el .compute_scaled_normal (f )
25- tangents = ref_el .compute_tangents (sd - 1 , f )
26- n = normal / Jdet
27- nodes .extend (BidirectionalMoment (ref_el , t , n , Q , phi )
28- for phi in phis for t in tangents )
29- entity_ids [sd - 1 ][f ].extend (range (cur , len (nodes )))
30-
16+ # Face dofs: moments of normal-tangential components against a basis for P_k
3117 # Interior dofs: moments of normal-tangential components against a basis for P_{k-1}
32- if degree > 0 :
33- cur = len (nodes )
34- Q = create_quadrature (ref_el , 2 * degree - 1 )
35- P = polynomial_set .ONPolynomialSet (ref_el , degree - 1 , scale = "L2 piola" )
36- phis = P .tabulate (Q .get_points ())[(0 ,) * sd ]
37- for f in sorted (top [sd - 1 ]):
38- n = ref_el .compute_scaled_normal (f )
39- tangents = ref_el .compute_tangents (sd - 1 , f )
40- nodes .extend (BidirectionalMoment (ref_el , t , n , Q , phi )
41- for phi in phis for t in tangents )
42- entity_ids [sd ][0 ].extend (range (cur , len (nodes )))
18+ for dim in (sd - 1 , sd ):
19+ q = degree + sd - 1 - dim
20+ if q < 0 :
21+ continue
22+
23+ ref_facet = ref_el .construct_subelement (dim )
24+ Q_ref = create_quadrature (ref_facet , degree + q )
25+ P = polynomial_set .ONPolynomialSet (ref_facet , q , scale = 1 )
26+ phis = P .tabulate (Q_ref .get_points ())[(0 ,) * dim ]
27+
28+ for entity in sorted (top [dim ]):
29+ cur = len (nodes )
30+ Q = FacetQuadratureRule (ref_el , dim , entity , Q_ref )
31+ Jdet = Q .jacobian_determinant ()
32+ for f in ref_el .get_connectivity ()[(dim , sd - 1 )][entity ]:
33+ normal = ref_el .compute_scaled_normal (f )
34+ tangents = ref_el .compute_tangents (sd - 1 , f )
35+ n = normal / Jdet
36+ nodes .extend (BidirectionalMoment (ref_el , t , n , Q , phi )
37+ for phi in phis for t in tangents )
38+ entity_ids [dim ][entity ].extend (range (cur , len (nodes )))
4339
4440 super ().__init__ (nodes , ref_el , entity_ids )
4541
@@ -59,7 +55,14 @@ class GopalakrishnanLedererSchoberlSecondKind(finite_element.CiarletElement):
5955 the weak symmetry constraint.
6056
6157 """
62- def __init__ (self , ref_el , degree ):
58+ def __init__ (self , ref_el , degree , variant = None ):
59+
60+ splitting , variant , interpolant_deg = check_format_variant (variant , degree )
61+ assert variant == "integral"
62+
63+ if splitting is not None :
64+ ref_el = splitting (ref_el )
65+
6366 poly_set = polynomial_set .TracelessTensorPolynomialSet (ref_el , degree )
6467 dual = GLSDual (ref_el , degree )
6568 sd = ref_el .get_spatial_dimension ()
@@ -68,7 +71,7 @@ def __init__(self, ref_el, degree):
6871 super ().__init__ (poly_set , dual , degree , formdegree , mapping = mapping )
6972
7073
71- def GopalakrishnanLedererSchoberlFirstKind (ref_el , degree ):
74+ def GopalakrishnanLedererSchoberlFirstKind (ref_el , degree , variant = None ):
7275 """The GLS element used for the Mass-Conserving mixed Stress (MCS)
7376 formulation for Stokes flow.
7477
@@ -77,12 +80,16 @@ def GopalakrishnanLedererSchoberlFirstKind(ref_el, degree):
7780
7881 Reference: https://doi.org/10.1093/imanum/drz022
7982 """
80- fe = GopalakrishnanLedererSchoberlSecondKind (ref_el , degree )
83+ fe = GopalakrishnanLedererSchoberlSecondKind (ref_el , degree , variant = variant )
8184 entity_dofs = fe .entity_dofs ()
8285 sd = ref_el .get_spatial_dimension ()
83- dimPkm1 = (sd - 1 )* expansions .polynomial_dimension (ref_el .construct_subelement (sd - 1 ), degree - 1 )
86+ facet = ref_el .construct_subelement (sd - 1 )
87+ dimPkm1 = (sd - 1 )* expansions .polynomial_dimension (facet , degree - 1 )
88+
8489 indices = []
85- for f in entity_dofs [sd - 1 ]:
90+ for f in sorted ( entity_dofs [sd - 1 ]) :
8691 indices .extend (entity_dofs [sd - 1 ][f ][:dimPkm1 ])
87- indices .extend (entity_dofs [sd ][0 ])
92+ for cell in sorted (entity_dofs [sd ]):
93+ indices .extend (entity_dofs [sd ][cell ])
94+
8895 return RestrictedElement (fe , indices = indices )
0 commit comments