Skip to content

Commit

Permalink
Reduced Demkowicz elements
Browse files Browse the repository at this point in the history
  • Loading branch information
pbrubeck committed Aug 12, 2024
1 parent ee8a8b9 commit 2936ff1
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 2 deletions.
31 changes: 29 additions & 2 deletions FIAT/demkowicz.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import scipy

from FIAT.dual_set import DualSet
from FIAT.restricted import RestrictedDualSet
from FIAT.functional import PointEvaluation, FrobeniusIntegralMoment
from FIAT.polynomial_set import make_bubbles, ONPolynomialSet, PolynomialSet
from FIAT.quadrature import FacetQuadratureRule
Expand Down Expand Up @@ -68,6 +69,7 @@ class DemkowiczDual(DualSet):
def __init__(self, ref_el, degree, sobolev_space, kind=2):
nodes = []
entity_ids = {}
reduced_dofs = {}
top = ref_el.get_topology()
sd = ref_el.get_spatial_dimension()
formdegree = {"H1": 0, "HCurl": 1, "HDiv": sd-1, "L2": sd}[sobolev_space]
Expand All @@ -79,21 +81,25 @@ def __init__(self, ref_el, degree, sobolev_space, kind=2):
if dim < formdegree or degree <= dim - formdegree:
for entity in top[dim]:
entity_ids[dim][entity] = []
reduced_dofs[dim] = 0
elif dim == 0 and formdegree == 0:
for entity in sorted(top[dim]):
cur = len(nodes)
pts = ref_el.make_points(dim, entity, degree)
nodes.extend(PointEvaluation(ref_el, pt) for pt in pts)
entity_ids[dim][entity] = list(range(cur, len(nodes)))
reduced_dofs[dim] = len(nodes)
else:
Q_ref, Phis = self._reference_duals(dim, degree, formdegree, sobolev_space, kind)
Q_ref, Phis, rdofs = self._reference_duals(dim, degree, formdegree, sobolev_space, kind)
reduced_dofs[dim] = rdofs
mapping = dual_mapping if dim == sd else trace
for entity in sorted(top[dim]):
cur = len(nodes)
Q, phis = map_duals(ref_el, dim, entity, mapping, Q_ref, Phis)
nodes.extend(FrobeniusIntegralMoment(ref_el, Q, phi) for phi in phis)
entity_ids[dim][entity] = list(range(cur, len(nodes)))

self._reduced_dofs = reduced_dofs
super(DemkowiczDual, self).__init__(nodes, ref_el, entity_ids)

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

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

duals = numpy.tensordot(K, P_at_qpts[(0,) * dim], axes=(1, 0))
return Q, duals
return Q, duals, reduced_dofs

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

def get_indices(self, restriction_domain, take_closure=True):
"""Return the list of dofs with support on the given restriction domain.
Allows for reduced Demkowicz elements, excluding the exterior
derivative of the previous space in the de Rham complex.
:arg restriction_domain: can be 'reduced', 'interior', 'vertex',
'edge', 'face' or 'facet'
:kwarg take_closure: Are we taking the closure of the restriction domain?
"""
if restriction_domain == "reduced":
indices = []
entity_ids = self.get_entity_ids()
for dim in entity_ids:
reduced_dofs = self._reduced_dofs[dim]
for entity, ids in entity_ids[dim].items():
indices.extend(ids[:reduced_dofs])
return indices
else:
return super(DemkowiczDual, self).get_indices(restriction_domain, take_closure=take_closure)


class FDMDual(DualSet):

Expand Down
4 changes: 4 additions & 0 deletions FIAT/restricted.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ def get_indices(self, restriction_domain, take_closure=True):
# Call get_indices on the parent class to support multiple restriction domains
return type(self._dual).get_indices(self, restriction_domain, take_closure=take_closure)

def __getattr__(self, name):
val = getattr(self._dual, name)
return val


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

0 comments on commit 2936ff1

Please sign in to comment.