Skip to content

Commit 2936ff1

Browse files
committed
Reduced Demkowicz elements
1 parent ee8a8b9 commit 2936ff1

File tree

2 files changed

+33
-2
lines changed

2 files changed

+33
-2
lines changed

FIAT/demkowicz.py

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import scipy
99

1010
from FIAT.dual_set import DualSet
11+
from FIAT.restricted import RestrictedDualSet
1112
from FIAT.functional import PointEvaluation, FrobeniusIntegralMoment
1213
from FIAT.polynomial_set import make_bubbles, ONPolynomialSet, PolynomialSet
1314
from FIAT.quadrature import FacetQuadratureRule
@@ -68,6 +69,7 @@ class DemkowiczDual(DualSet):
6869
def __init__(self, ref_el, degree, sobolev_space, kind=2):
6970
nodes = []
7071
entity_ids = {}
72+
reduced_dofs = {}
7173
top = ref_el.get_topology()
7274
sd = ref_el.get_spatial_dimension()
7375
formdegree = {"H1": 0, "HCurl": 1, "HDiv": sd-1, "L2": sd}[sobolev_space]
@@ -79,21 +81,25 @@ def __init__(self, ref_el, degree, sobolev_space, kind=2):
7981
if dim < formdegree or degree <= dim - formdegree:
8082
for entity in top[dim]:
8183
entity_ids[dim][entity] = []
84+
reduced_dofs[dim] = 0
8285
elif dim == 0 and formdegree == 0:
8386
for entity in sorted(top[dim]):
8487
cur = len(nodes)
8588
pts = ref_el.make_points(dim, entity, degree)
8689
nodes.extend(PointEvaluation(ref_el, pt) for pt in pts)
8790
entity_ids[dim][entity] = list(range(cur, len(nodes)))
91+
reduced_dofs[dim] = len(nodes)
8892
else:
89-
Q_ref, Phis = self._reference_duals(dim, degree, formdegree, sobolev_space, kind)
93+
Q_ref, Phis, rdofs = self._reference_duals(dim, degree, formdegree, sobolev_space, kind)
94+
reduced_dofs[dim] = rdofs
9095
mapping = dual_mapping if dim == sd else trace
9196
for entity in sorted(top[dim]):
9297
cur = len(nodes)
9398
Q, phis = map_duals(ref_el, dim, entity, mapping, Q_ref, Phis)
9499
nodes.extend(FrobeniusIntegralMoment(ref_el, Q, phi) for phi in phis)
95100
entity_ids[dim][entity] = list(range(cur, len(nodes)))
96101

102+
self._reduced_dofs = reduced_dofs
97103
super(DemkowiczDual, self).__init__(nodes, ref_el, entity_ids)
98104

99105
def _reference_duals(self, dim, degree, formdegree, sobolev_space, kind):
@@ -117,6 +123,7 @@ def _reference_duals(self, dim, degree, formdegree, sobolev_space, kind):
117123
dtrial = dtrial[:, None, :]
118124
K = self._bubble_derivative_moments(facet, degree, formdegree, kind, Qpts, Qwts, dtrial)
119125

126+
reduced_dofs = K.shape[0]
120127
if formdegree > 0:
121128
if dim == 2 and formdegree == 1 and sobolev_space == "HDiv":
122129
trial = perp(trial)
@@ -125,7 +132,7 @@ def _reference_duals(self, dim, degree, formdegree, sobolev_space, kind):
125132
K = numpy.vstack((K, M))
126133

127134
duals = numpy.tensordot(K, P_at_qpts[(0,) * dim], axes=(1, 0))
128-
return Q, duals
135+
return Q, duals, reduced_dofs
129136

130137
def _bubble_derivative_moments(self, facet, degree, formdegree, kind, Qpts, Qwts, trial):
131138
"""Integrate trial expressions against an orthonormal basis for
@@ -164,6 +171,26 @@ def _bubble_derivative_moments(self, facet, degree, formdegree, kind, Qpts, Qwts
164171
dtest = numpy.tensordot(S.T, dtest, axes=(1, 0))
165172
return inner(dtest, trial, Qwts)
166173

174+
def get_indices(self, restriction_domain, take_closure=True):
175+
"""Return the list of dofs with support on the given restriction domain.
176+
Allows for reduced Demkowicz elements, excluding the exterior
177+
derivative of the previous space in the de Rham complex.
178+
179+
:arg restriction_domain: can be 'reduced', 'interior', 'vertex',
180+
'edge', 'face' or 'facet'
181+
:kwarg take_closure: Are we taking the closure of the restriction domain?
182+
"""
183+
if restriction_domain == "reduced":
184+
indices = []
185+
entity_ids = self.get_entity_ids()
186+
for dim in entity_ids:
187+
reduced_dofs = self._reduced_dofs[dim]
188+
for entity, ids in entity_ids[dim].items():
189+
indices.extend(ids[:reduced_dofs])
190+
return indices
191+
else:
192+
return super(DemkowiczDual, self).get_indices(restriction_domain, take_closure=take_closure)
193+
167194

168195
class FDMDual(DualSet):
169196

FIAT/restricted.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ def get_indices(self, restriction_domain, take_closure=True):
4040
# Call get_indices on the parent class to support multiple restriction domains
4141
return type(self._dual).get_indices(self, restriction_domain, take_closure=take_closure)
4242

43+
def __getattr__(self, name):
44+
val = getattr(self._dual, name)
45+
return val
46+
4347

4448
class RestrictedElement(CiarletElement):
4549
"""Restrict the given element to the specified list of dofs."""

0 commit comments

Comments
 (0)