Skip to content

Commit eb34beb

Browse files
authored
Merge pull request #75 from firedrakeproject/pbrubeck/fix/gll-ordering
GLL: ensure natural ordering of the DOFs
2 parents ab32c8d + 3d6db42 commit eb34beb

File tree

4 files changed

+34
-22
lines changed

4 files changed

+34
-22
lines changed

FIAT/gauss_lobatto_legendre.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,4 @@
1414
class GaussLobattoLegendre(lagrange.Lagrange):
1515
"""Simplicial continuous element with nodes at the (recursive) Gauss-Lobatto-Legendre points."""
1616
def __init__(self, ref_el, degree):
17-
super(GaussLobattoLegendre, self).__init__(ref_el, degree, variant="gll")
17+
super(GaussLobattoLegendre, self).__init__(ref_el, degree, variant="gll", sort_entities=True)

FIAT/lagrange.py

+30-17
Original file line numberDiff line numberDiff line change
@@ -14,33 +14,42 @@
1414

1515
class LagrangeDualSet(dual_set.DualSet):
1616
"""The dual basis for Lagrange elements. This class works for
17-
simplices of any dimension. Nodes are point evaluation at
17+
simplicial complexes of any dimension. Nodes are point evaluation at
1818
recursively-defined points.
19+
20+
:arg ref_el: The simplicial complex.
21+
:arg degree: The polynomial degree.
22+
:arg point_variant: The point distribution variant passed on to recursivenodes.
23+
:arg sort_entities: A flag to sort entities by support vertex ids.
24+
If false then entities are sorted first by dimension and then by
25+
entity id. The DOFs are always sorted by the entity ordering
26+
and then lexicographically by lattice multiindex.
1927
"""
20-
def __init__(self, ref_el, degree, point_variant="equispaced"):
21-
entity_ids = {}
28+
def __init__(self, ref_el, degree, point_variant="equispaced", sort_entities=False):
2229
nodes = []
30+
entity_ids = {}
2331
entity_permutations = {}
24-
25-
# make nodes by getting points
26-
# need to do this dimension-by-dimension, facet-by-facet
2732
top = ref_el.get_topology()
28-
29-
cur = 0
3033
for dim in sorted(top):
3134
entity_ids[dim] = {}
3235
entity_permutations[dim] = {}
3336
perms = {0: [0]} if dim == 0 else make_entity_permutations_simplex(dim, degree - dim)
3437
for entity in sorted(top[dim]):
35-
pts_cur = ref_el.make_points(dim, entity, degree, variant=point_variant)
36-
nodes_cur = [functional.PointEvaluation(ref_el, x)
37-
for x in pts_cur]
38-
nnodes_cur = len(nodes_cur)
39-
nodes += nodes_cur
40-
entity_ids[dim][entity] = list(range(cur, cur + nnodes_cur))
41-
cur += nnodes_cur
4238
entity_permutations[dim][entity] = perms
4339

40+
entities = [(dim, entity) for dim in sorted(top) for entity in sorted(top[dim])]
41+
if sort_entities:
42+
# sort the entities by support vertex ids
43+
support = [top[dim][entity] for dim, entity in entities]
44+
entities = [entity for verts, entity in sorted(zip(support, entities))]
45+
46+
# make nodes by getting points
47+
# need to do this entity-by-entity
48+
for dim, entity in entities:
49+
cur = len(nodes)
50+
pts_cur = ref_el.make_points(dim, entity, degree, variant=point_variant)
51+
nodes.extend(functional.PointEvaluation(ref_el, x) for x in pts_cur)
52+
entity_ids[dim][entity] = list(range(cur, len(nodes)))
4453
super(LagrangeDualSet, self).__init__(nodes, ref_el, entity_ids, entity_permutations)
4554

4655

@@ -58,12 +67,16 @@ class Lagrange(finite_element.CiarletElement):
5867
variant='equispaced,Iso(2)' with degree=1 gives the P2:P1 iso element.
5968
variant='Alfeld' can be used to obtain a barycentrically refined
6069
macroelement for Scott-Vogelius.
70+
:arg sort_entities: A flag to sort entities by support vertex ids.
71+
If false then entities are sorted first by dimension and then by
72+
entity id. The DOFs are always sorted by the entity ordering
73+
and then lexicographically by lattice multiindex.
6174
"""
62-
def __init__(self, ref_el, degree, variant="equispaced"):
75+
def __init__(self, ref_el, degree, variant="equispaced", sort_entities=False):
6376
splitting, point_variant = parse_lagrange_variant(variant)
6477
if splitting is not None:
6578
ref_el = splitting(ref_el)
66-
dual = LagrangeDualSet(ref_el, degree, point_variant=point_variant)
79+
dual = LagrangeDualSet(ref_el, degree, point_variant=point_variant, sort_entities=sort_entities)
6780
if ref_el.shape == LINE:
6881
# In 1D we can use the primal basis as the expansion set,
6982
# avoiding any round-off coming from a basis transformation

test/unit/test_fiat.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -394,8 +394,8 @@ def test_empty_bubble():
394394

395395
@pytest.mark.parametrize('elements', [
396396
(Lagrange(I, 2), Lagrange(I, 1), Bubble(I, 2)),
397-
(GaussLobattoLegendre(I, 3), Lagrange(I, 1),
398-
RestrictedElement(GaussLobattoLegendre(I, 3), restriction_domain="interior")),
397+
(Lagrange(I, 3, variant="gll"), Lagrange(I, 1),
398+
RestrictedElement(Lagrange(I, 3, variant="gll"), restriction_domain="interior")),
399399
(RaviartThomas(T, 2),
400400
RestrictedElement(RaviartThomas(T, 2), restriction_domain='facet'),
401401
RestrictedElement(RaviartThomas(T, 2), restriction_domain='interior')),

test/unit/test_gauss_lobatto_legendre.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,7 @@ def test_edge_dofs(dim, degree):
5959
# Test that edge DOFs are located at the GLL quadrature points
6060
line = s if dim == 1 else s.construct_subelement(1)
6161
lr = quadrature.GaussLobattoLegendreQuadratureLineRule(line, degree + 1)
62-
# Edge DOFs are ordered with the two vertex DOFs followed by the interior DOFs
63-
quadrature_points = lr.pts[::degree] + lr.pts[1:-1]
62+
quadrature_points = lr.get_points()
6463

6564
entity_dofs = fe.entity_closure_dofs()
6665
edge_dofs = entity_dofs[1]

0 commit comments

Comments
 (0)