Skip to content

Commit

Permalink
mass-decoupling variant
Browse files Browse the repository at this point in the history
  • Loading branch information
pbrubeck committed Nov 21, 2024
1 parent a2b02d1 commit f96b28c
Show file tree
Hide file tree
Showing 8 changed files with 52 additions and 24 deletions.
4 changes: 2 additions & 2 deletions FIAT/brezzi_douglas_marini.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,8 @@ def __init__(self, ref_el, degree, variant=None):

sd = ref_el.get_spatial_dimension()
poly_set = polynomial_set.ONPolynomialSet(ref_el, degree, (sd, ))
if variant == "demkowicz":
dual = demkowicz.DemkowiczDual(ref_el, degree, "HDiv")
if variant and variant.startswith("demkowicz"):
dual = demkowicz.DemkowiczDual(ref_el, degree, "HDiv", variant=variant)
elif variant == "fdm":
dual = demkowicz.FDMDual(ref_el, degree, "HDiv", type(self))
else:
Expand Down
8 changes: 3 additions & 5 deletions FIAT/check_format_variant.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,9 @@ def check_format_variant(variant, degree):
if variant is None:
variant = "integral"

match = re.match(r"^integral(?:\((\d+)\))?$", variant)
match = re.match(r"^(?:(\w+))?(?:\((\d+)\))?$", variant)
if match:
variant = "integral"
extra_degree, = match.groups()
variant, extra_degree = match.groups()
extra_degree = int(extra_degree) if extra_degree is not None else 0
interpolant_degree = degree + extra_degree
if interpolant_degree < degree:
Expand Down Expand Up @@ -61,7 +60,7 @@ def parse_lagrange_variant(variant, discontinuous=False, integral=False):

default = "integral" if integral else "spectral"
if integral:
supported_point_variants = {"integral": None, "fdm": "fdm", "demkowicz": "demkowicz"}
supported_point_variants = {"integral": None, "fdm": "fdm", "demkowicz": "demkowicz", "demkowicz-mass": "demkowicz-mass"}
elif discontinuous:
supported_point_variants = supported_dg_variants
else:
Expand All @@ -71,7 +70,6 @@ def parse_lagrange_variant(variant, discontinuous=False, integral=False):
splitting = None
splitting_args = tuple()
point_variant = supported_point_variants[default]

for pre_opt in options:
opt = pre_opt.lower()
if opt in supported_splits:
Expand Down
26 changes: 17 additions & 9 deletions FIAT/demkowicz.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ def map_duals(ref_el, dim, entity, mapping, Q_ref, Phis):

class DemkowiczDual(DualSet):

def __init__(self, ref_el, degree, sobolev_space, kind=None):
def __init__(self, ref_el, degree, sobolev_space, kind=None, variant=None):
nodes = []
entity_ids = {}
reduced_dofs = {}
Expand All @@ -76,6 +76,8 @@ def __init__(self, ref_el, degree, sobolev_space, kind=None):
dual_mapping = {"HCurl": "contravariant", "HDiv": "covariant"}.get(sobolev_space, None)
if kind is None:
kind = 1 if formdegree == 0 else 2
if variant is None:
variant = "demkowicz"

for dim in sorted(top):
entity_ids[dim] = {}
Expand All @@ -91,7 +93,7 @@ def __init__(self, ref_el, degree, sobolev_space, kind=None):
entity_ids[dim][entity] = list(range(cur, len(nodes)))
reduced_dofs[dim] = len(nodes)
else:
Q_ref, Phis, rdofs = self._reference_duals(dim, degree, formdegree, sobolev_space, kind)
Q_ref, Phis, rdofs = self._reference_duals(dim, degree, formdegree, sobolev_space, kind, variant)
reduced_dofs[dim] = rdofs
mapping = dual_mapping if dim == sd else trace
for entity in sorted(top[dim]):
Expand All @@ -101,9 +103,9 @@ def __init__(self, ref_el, degree, sobolev_space, kind=None):
entity_ids[dim][entity] = list(range(cur, len(nodes)))

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

def _reference_duals(self, dim, degree, formdegree, sobolev_space, kind):
def _reference_duals(self, dim, degree, formdegree, sobolev_space, kind, variant):
facet = symmetric_simplex(dim)
Q = create_quadrature(facet, 2 * degree)
Qpts, Qwts = Q.get_points(), Q.get_weights()
Expand All @@ -122,10 +124,15 @@ def _reference_duals(self, dim, degree, formdegree, sobolev_space, kind):
if formdegree >= dim:
K = inner(trial[:1], trial, Qwts)
else:
dtrial = exterior_derivative(P_at_qpts)
if dim == 2 and formdegree == 1 and sobolev_space == "HDiv":
dtrial = dtrial[:, None, :]
K = self._bubble_derivative_moments(facet, degree, formdegree, kind, Qpts, Qwts, dtrial)
if variant == "demkowicz":
deriv = True
dtrial = exterior_derivative(P_at_qpts)
if dim == 2 and formdegree == 1 and sobolev_space == "HDiv":
dtrial = dtrial[:, None, :]
else:
deriv = False
dtrial = trial
K = self._bubble_derivative_moments(facet, degree, formdegree, kind, Qpts, Qwts, dtrial, deriv=deriv)
reduced_dofs = K.shape[0]

# Evaluate type-II degrees of freedom on P
Expand Down Expand Up @@ -220,7 +227,7 @@ def __init__(self, ref_el, degree, sobolev_space, element):
self.Q = Q
self.V0 = phis[(0,) * sd]
self.V1 = exterior_derivative(phis)
super(FDMDual, self).__init__(ref_el, degree, sobolev_space, kind=None)
super().__init__(ref_el, degree, sobolev_space, kind=None)

def _reference_duals(self, dim, degree, formdegree, sobolev_space, kind):
entity_dofs = self.fe.entity_dofs()
Expand Down Expand Up @@ -286,6 +293,7 @@ def _reference_duals(self, dim, degree, formdegree, sobolev_space, kind):
kind = 1
variant = "fdm"
variant = "demkowicz"
variant = "demkowicz-mass"
# variant = None
space_dict = {"H1": (CG, grad),
"HCurl": (N1Curl if kind == 1 else N2Curl, curl),
Expand Down
4 changes: 2 additions & 2 deletions FIAT/hierarchical.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ def __init__(self, ref_el, degree, variant=None):
if splitting is not None:
ref_el = splitting(ref_el)
poly_set = ONPolynomialSet(ref_el, degree)
if variant == "demkowicz":
if variant and variant.startswith("demkowicz"):
dual = demkowicz.DemkowiczDual(ref_el, degree, "L2")
elif variant == "fdm":
dual = demkowicz.FDMDual(ref_el, degree, "L2", type(self))
Expand Down Expand Up @@ -135,7 +135,7 @@ def __init__(self, ref_el, degree, variant=None):
if degree < 1:
raise ValueError(f"{type(self).__name__} elements only valid for k >= 1")
poly_set = ONPolynomialSet(ref_el, degree, variant="bubble")
if variant == "demkowicz":
if variant and variant.startswith("demkowicz"):
dual = demkowicz.DemkowiczDual(ref_el, degree, "H1")
elif variant == "fdm":
dual = demkowicz.FDMDual(ref_el, degree, "H1", type(self))
Expand Down
4 changes: 2 additions & 2 deletions FIAT/nedelec.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,8 +196,8 @@ class Nedelec(finite_element.CiarletElement):

def __init__(self, ref_el, degree, variant=None):

if variant == "demkowicz":
dual = demkowicz.DemkowiczDual(ref_el, degree, "HCurl", kind=1)
if variant and variant.startswith("demkowicz"):
dual = demkowicz.DemkowiczDual(ref_el, degree, "HCurl", kind=1, variant=variant)
elif variant == "fdm":
dual = demkowicz.FDMDual(ref_el, degree, "HCurl", type(self))
else:
Expand Down
4 changes: 2 additions & 2 deletions FIAT/nedelec_second_kind.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,8 +198,8 @@ def __init__(self, ref_el, degree, variant=None):

sd = ref_el.get_spatial_dimension()
poly_set = ONPolynomialSet(ref_el, degree, (sd, ), variant="bubble")
if variant == "demkowicz":
dual = demkowicz.DemkowiczDual(ref_el, degree, "HCurl")
if variant and variant.startswith("demkowicz"):
dual = demkowicz.DemkowiczDual(ref_el, degree, "HCurl", variant=variant)
elif variant == "fdm":
dual = demkowicz.FDMDual(ref_el, degree, "HCurl", type(self))
else:
Expand Down
4 changes: 2 additions & 2 deletions FIAT/raviart_thomas.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,8 @@ class RaviartThomas(finite_element.CiarletElement):

def __init__(self, ref_el, degree, variant=None):

if variant == "demkowicz":
dual = demkowicz.DemkowiczDual(ref_el, degree, "HDiv", kind=1)
if variant and variant.startswith("demkowicz"):
dual = demkowicz.DemkowiczDual(ref_el, degree, "HDiv", kind=1, variant=variant)
elif variant == "fdm":
dual = demkowicz.FDMDual(ref_el, degree, "HDiv", type(self))
else:
Expand Down
22 changes: 22 additions & 0 deletions test/unit/test_hct.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
from FIAT.reference_element import ufc_simplex
from FIAT.functional import PointEvaluation
from FIAT.macro import CkPolynomialSet
from FIAT.quadrature_schemes import create_quadrature
from FIAT.jacobi import eval_jacobi


@pytest.fixture
Expand Down Expand Up @@ -74,3 +76,23 @@ def test_full_polynomials(cell, reduced):
C1 = CkPolynomialSet(ref_complex, degree, order=1, variant="bubble")
C1_tab = C1.tabulate(pts)[(0, 0)]
assert span_greater_equal(tab, C1_tab)


def test_reduced_normal_derivative(cell):
fe = HCT(cell, reduced=True)

ref_line = cell.construct_subelement(1)
Q = create_quadrature(ref_line, fe.degree()+2)
qpts, qwts = Q.get_points(), Q.get_weights()

bary = ref_line.compute_barycentric_coordinates(qpts)
leg2 = eval_jacobi(0, 0, 2, bary[:, 1] - bary[:, 0])
wts = numpy.multiply(leg2, qwts)
top = cell.get_topology()
for e in top[1]:
n = cell.compute_normal(e)
vals = fe.tabulate(1, qpts, entity=(1, e))
fn = vals[(1, 0)] * n[0] + vals[(0, 1)] * n[1]

fn = fn[:-3]
assert numpy.allclose(numpy.dot(fn, wts), 0)

0 comments on commit f96b28c

Please sign in to comment.