Skip to content

Commit 20105d8

Browse files
committed
Merge branch 'pbrubeck/hcurldiv' of github.com:firedrakeproject/fiat into pbrubeck/hcurldiv
2 parents 8112271 + 887e01f commit 20105d8

File tree

1 file changed

+63
-114
lines changed

1 file changed

+63
-114
lines changed

FIAT/mardal_tai_winther.py

Lines changed: 63 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -17,140 +17,89 @@
1717
from FIAT.quadrature_schemes import create_quadrature
1818

1919

20-
def DivergenceDubinerMoments(cell, start_deg, stop_deg, comp_deg):
21-
sd = cell.get_spatial_dimension()
22-
P = polynomial_set.ONPolynomialSet(cell, stop_deg)
23-
Q = create_quadrature(cell, comp_deg + stop_deg)
20+
def DivergenceDubinerMoments(ref_el, start_deg, stop_deg, comp_deg):
21+
sd = ref_el.get_spatial_dimension()
22+
P = polynomial_set.ONPolynomialSet(ref_el, stop_deg)
23+
Q = create_quadrature(ref_el, comp_deg + stop_deg)
2424

25-
dim0 = expansions.polynomial_dimension(cell, start_deg-1)
26-
dim1 = expansions.polynomial_dimension(cell, stop_deg)
25+
dim0 = expansions.polynomial_dimension(ref_el, start_deg-1)
26+
dim1 = expansions.polynomial_dimension(ref_el, stop_deg)
2727
indices = list(range(dim0, dim1))
2828
phis = P.take(indices).tabulate(Q.get_points())[(0,)*sd]
29-
return [IntegralMomentOfDivergence(cell, Q, phi) for phi in phis]
29+
for phi in phis:
30+
yield IntegralMomentOfDivergence(ref_el, Q, phi)
3031

3132

3233
class MardalTaiWintherDual(dual_set.DualSet):
3334
"""Degrees of freedom for Mardal-Tai-Winther elements."""
34-
def __init__(self, cell, degree):
35-
dim = cell.get_spatial_dimension()
36-
if not dim == 2:
37-
raise ValueError("Mardal-Tai-Winther elements are only"
38-
"defined in dimension 2.")
39-
40-
if not degree == 3:
41-
raise ValueError("Mardal-Tai-Winther elements are only defined"
42-
"for degree 3.")
43-
44-
# construct the degrees of freedoms
45-
dofs = [] # list of functionals
46-
47-
# dof_ids[i][j] contains the indices of dofs that are associated with
48-
# entity j in dim i
49-
dof_ids = {}
50-
51-
# no vertex dof
52-
dof_ids[0] = {i: [] for i in range(dim + 1)}
53-
54-
# edge dofs
55-
(_dofs, _dof_ids) = self._generate_edge_dofs(cell, degree)
56-
dofs.extend(_dofs)
57-
dof_ids[1] = _dof_ids
58-
59-
# no cell dofs
60-
dof_ids[2] = {}
61-
dof_ids[2][0] = []
62-
63-
# extra dofs for enforcing div(v) constant over the cell and
64-
# v.n linear on edges
65-
(_dofs, _edge_dof_ids, _cell_dof_ids) = self._generate_constraint_dofs(cell, degree, len(dofs))
66-
dofs.extend(_dofs)
67-
68-
for entity_id in range(3):
69-
dof_ids[1][entity_id].extend(_edge_dof_ids[entity_id])
70-
71-
dof_ids[2][0].extend(_cell_dof_ids)
72-
73-
super(MardalTaiWintherDual, self).__init__(dofs, cell, dof_ids)
74-
75-
@staticmethod
76-
def _generate_edge_dofs(cell, degree):
77-
"""Generate dofs on edges.
78-
On each edge, let n be its normal. We need to integrate
79-
u.n and u.t against the first Legendre polynomial (constant)
80-
and u.n against the second (linear).
81-
"""
82-
dofs = []
83-
dof_ids = {}
84-
offset = 0
85-
sd = 2
86-
87-
facet = cell.get_facet_element()
88-
# Facet nodes are \int_F v\cdot n p ds where p \in P_{q-1}
35+
def __init__(self, ref_el, degree):
36+
sd = ref_el.get_spatial_dimension()
37+
top = ref_el.get_topology()
38+
39+
if sd != 2:
40+
raise ValueError("Mardal-Tai-Winther elements are only defined in dimension 2.")
41+
42+
if degree != 3:
43+
raise ValueError("Mardal-Tai-Winther elements are only defined for degree 3.")
44+
45+
entity_ids = {dim: {entity: [] for entity in top[dim]} for dim in top}
46+
nodes = []
47+
48+
# no vertex dofs
49+
50+
# On each facet, let n be its normal. We need to integrate
51+
# u.n and u.t against the first Legendre polynomial (constant)
52+
# and u.n against the second (linear).
53+
facet = ref_el.get_facet_element()
54+
# Facet nodes are \int_F v.n p ds where p \in P_{q-1}
8955
# degree is q - 1
9056
Q = create_quadrature(facet, degree+1)
9157
Pq = polynomial_set.ONPolynomialSet(facet, 1)
9258
phis = Pq.tabulate(Q.get_points())[(0,)*(sd - 1)]
93-
for f in range(3):
94-
dofs.append(IntegralMomentOfNormalEvaluation(cell, Q, phis[0], f))
95-
dofs.append(IntegralMomentOfTangentialEvaluation(cell, Q, phis[0], f))
96-
dofs.append(IntegralMomentOfNormalEvaluation(cell, Q, phis[1], f))
97-
98-
num_new_dofs = 3
99-
dof_ids[f] = list(range(offset, offset + num_new_dofs))
100-
offset += num_new_dofs
101-
102-
return (dofs, dof_ids)
103-
104-
@staticmethod
105-
def _generate_constraint_dofs(cell, degree, offset):
106-
"""
107-
Generate constraint dofs on the cell and edges
108-
* div(v) must be constant on the cell. Since v is a cubic and
109-
div(v) is quadratic, we need the integral of div(v) against the
110-
linear and quadratic Dubiner polynomials to vanish.
111-
There are two linear and three quadratics, so these are five
112-
constraints
113-
* v.n must be linear on each edge. Since v.n is cubic, we need
114-
the integral of v.n against the cubic and quadratic Legendre
115-
polynomial to vanish on each edge.
116-
117-
So we introduce functionals whose kernel describes this property,
118-
as described in the FIAT paper.
119-
"""
120-
dofs = []
121-
edge_dof_ids = {}
122-
59+
for f in sorted(top[sd-1]):
60+
cur = len(nodes)
61+
nodes.append(IntegralMomentOfNormalEvaluation(ref_el, Q, phis[0], f))
62+
nodes.append(IntegralMomentOfTangentialEvaluation(ref_el, Q, phis[0], f))
63+
nodes.append(IntegralMomentOfNormalEvaluation(ref_el, Q, phis[1], f))
64+
entity_ids[sd-1][f].extend(range(cur, len(nodes)))
65+
66+
# Generate constraint nodes on the cell and facets
67+
# * div(v) must be constant on the cell. Since v is a cubic and
68+
# div(v) is quadratic, we need the integral of div(v) against the
69+
# linear and quadratic Dubiner polynomials to vanish.
70+
# There are two linear and three quadratics, so these are five
71+
# constraints
72+
# * v.n must be linear on each facet. Since v.n is cubic, we need
73+
# the integral of v.n against the cubic and quadratic Legendre
74+
# polynomial to vanish on each facet.
75+
76+
# So we introduce functionals whose kernel describes this property,
77+
# as described in the FIAT paper.
12378
start_order = 2
12479
stop_order = 3
12580
qdegree = degree + stop_order
126-
for entity_id in range(3):
127-
cur = len(dofs)
128-
dofs.extend(IntegralLegendreNormalMoment(cell, entity_id, order, qdegree)
129-
for order in range(start_order, stop_order+1))
130-
131-
edge_dof_ids[entity_id] = list(range(offset+cur, offset+len(dofs)))
81+
for f in sorted(top[sd-1]):
82+
cur = len(nodes)
83+
nodes.extend(IntegralLegendreNormalMoment(ref_el, f, order, qdegree)
84+
for order in range(start_order, stop_order+1))
85+
entity_ids[sd-1][f].extend(range(cur, len(nodes)))
13286

133-
cur = len(dofs)
134-
dofs.extend(DivergenceDubinerMoments(cell, start_order-1, stop_order-1, degree))
135-
cell_dof_ids = list(range(offset+cur, offset+len(dofs)))
87+
cur = len(nodes)
88+
nodes.extend(DivergenceDubinerMoments(ref_el, start_order-1, stop_order-1, degree))
89+
entity_ids[sd][0].extend(range(cur, len(nodes)))
13690

137-
return (dofs, edge_dof_ids, cell_dof_ids)
91+
super().__init__(nodes, ref_el, entity_ids)
13892

13993

14094
class MardalTaiWinther(finite_element.CiarletElement):
14195
"""The definition of the Mardal-Tai-Winther element.
14296
"""
143-
def __init__(self, cell, degree=3):
97+
def __init__(self, ref_el, degree=3):
98+
sd = ref_el.get_spatial_dimension()
14499
assert degree == 3, "Only defined for degree 3"
145-
assert cell.get_spatial_dimension() == 2, "Only defined for dimension 2"
146-
# polynomial space
147-
Ps = polynomial_set.ONPolynomialSet(cell, degree, (2,))
148-
149-
# degrees of freedom
150-
Ls = MardalTaiWintherDual(cell, degree)
151-
152-
# mapping under affine transformation
100+
assert sd == 2, "Only defined for dimension 2"
101+
poly_set = polynomial_set.ONPolynomialSet(ref_el, degree, (sd,))
102+
dual = MardalTaiWintherDual(ref_el, degree)
103+
formdegree = sd-1
153104
mapping = "contravariant piola"
154-
155-
super(MardalTaiWinther, self).__init__(Ps, Ls, degree,
156-
mapping=mapping)
105+
super().__init__(poly_set, dual, degree, formdegree, mapping=mapping)

0 commit comments

Comments
 (0)