Skip to content

Commit 74ccf80

Browse files
committed
MacroPolynomialSet
1 parent 013c5f8 commit 74ccf80

File tree

3 files changed

+98
-53
lines changed

3 files changed

+98
-53
lines changed

FIAT/brezzi_douglas_marini.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ def __init__(self, ref_el, degree, variant=None):
105105
sd = ref_el.get_spatial_dimension()
106106
if ref_el.is_macrocell():
107107
poly_set = macro.HDivPolynomialSet(ref_el, degree)
108+
# base_element = BrezziDouglasMarini(ref_el.get_parent(), degree)
109+
# poly_set = macro.MacroPolynomialSet(ref_el, base_element)
108110
else:
109111
poly_set = polynomial_set.ONPolynomialSet(ref_el, degree, (sd, ))
110112
dual = BDMDualSet(ref_el, degree, variant, interpolant_deg)

FIAT/expansions.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -274,11 +274,18 @@ def __init__(self, ref_el, scale=None, variant=None):
274274
if scale is None:
275275
scale = math.sqrt(1.0 / base_ref_el.volume())
276276
self.scale = scale
277+
self.variant = variant
277278
self.continuity = "C0" if variant == "bubble" else None
278279
self.recurrence_order = 2
279280
self._dmats_cache = {}
280281
self._cell_node_map_cache = {}
281282

283+
def reconstruct(self, ref_el=None, scale=None, variant=None):
284+
"""Reconstructs this ExpansionSet with modified arguments."""
285+
return ExpansionSet(ref_el or self.ref_el,
286+
scale=scale or self.scale,
287+
variant=variant or self.variant)
288+
282289
def get_scale(self, n, cell=0):
283290
scale = self.scale
284291
sd = self.ref_el.get_spatial_dimension()
@@ -378,13 +385,11 @@ def _tabulate(self, n, pts, order=0):
378385
base_phi = tuple(phis.values())[0]
379386
for alpha in base_phi:
380387
dtype = base_phi[alpha].dtype
381-
phi_shape = (num_phis,) + base_phi[alpha].shape[1:-1]
382-
shape_idx = tuple(range(i) for i in phi_shape[1:])
383-
result[alpha] = numpy.zeros(phi_shape + pts.shape[:-1], dtype=dtype)
388+
result[alpha] = numpy.zeros((num_phis, *pts.shape[:-1]), dtype=dtype)
384389
for cell in cell_point_map:
385390
ibfs = cell_node_map[cell]
386391
ipts = cell_point_map[cell]
387-
result[alpha][idx(ibfs, *shape_idx, ipts)] += phis[cell][alpha]
392+
result[alpha][idx(ibfs, ipts)] += phis[cell][alpha]
388393
return result
389394

390395
def tabulate_normal_jumps(self, n, ref_pts, facet, order=0):

FIAT/macro.py

Lines changed: 87 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -556,82 +556,120 @@ def __init__(self, ref_el, degree, order=0, **kwargs):
556556
super().__init__(ref_el, degree, degree, U.expansion_set, coeffs)
557557

558558

559-
class MacroExpansionSet(expansions.ExpansionSet):
560-
559+
def pullback(mapping, Jinv, phi):
560+
try:
561+
formdegree = {
562+
"affine": (0,),
563+
"covariant piola": (1,),
564+
"contravariant piola": (2,),
565+
"double covariant piola": (1, 1),
566+
"double contravariant piola": (2, 2),
567+
"covariant contravariant piola": (1, 2),
568+
"contravariant covariant piola": (2, 1), }[mapping]
569+
except KeyError:
570+
raise ValueError(f"Unrecognized mapping {mapping}")
571+
572+
F1 = Jinv.T
573+
F2 = numpy.linalg.inv(Jinv) * numpy.linalg.det(Jinv)
574+
575+
perm = [*range(1, phi.ndim-1), 0, -1]
576+
phi = phi.transpose(perm)
577+
578+
for i, k in enumerate(formdegree):
579+
if k == 0:
580+
continue
581+
F = F1 if k == 1 else F2
582+
phi = numpy.tensordot(F, phi, (1, i))
583+
584+
perm = [-2, *range(phi.ndim-2), -1]
585+
phi = phi.transpose(perm)
586+
return phi
587+
588+
589+
class MacroPolynomialSet(polynomial_set.PolynomialSet):
590+
"""Constructs a PolynomialSet by tiling a CiarletElement on a
591+
SimplicialComplex.
592+
593+
:arg ref_el: The SimplicialComplex.
594+
:arg element: The CiarletElement.
595+
"""
561596
def __init__(self, ref_el, element):
562-
self.element = element
563-
self.ref_el = ref_el
564-
self.variant = None
565-
sd = ref_el.get_spatial_dimension()
566597
top = ref_el.get_topology()
567-
base_ref_el = element.ref_el
568-
base_verts = base_ref_el.get_vertices()
569-
570-
self.affine_mappings = [reference_element.make_affine_mapping(
571-
ref_el.get_vertices_of_subcomplex(top[sd][cell]),
572-
base_verts) for cell in top[sd]]
573-
self.scale = 1
574-
self.continuity = element.entity_dofs()
575-
self.recurrence_order = element.degree
576-
self._dmats_cache = {}
577-
self._cell_node_map_cache = {}
578-
579-
def _tabulate_on_cell(self, n, pts, order=0, cell=0, direction=None):
580-
A, b = self.affine_mappings[cell]
581-
ref_pts = numpy.add(numpy.dot(pts, A.T), b)
582-
Jinv = A if direction is None else numpy.dot(A, direction)[:, None]
583-
phis = self.element.tabulate(order, ref_pts)
584-
for alpha in phis:
585-
phis[alpha] = self.pullback(Jinv, phis[alpha])
586-
return phis
587-
588-
def pullback(self, Jinv, phi):
589-
mapping = self.element.mapping()[0]
590-
if mapping == "covariant piola":
591-
phi = numpy.tensordot(Jinv.T, phi, (1, 1)).transpose((1, 0, 2))
592-
elif mapping == "contravariant piola":
593-
J = numpy.linalg.inv(Jinv)
594-
Jdet = abs(numpy.linalg.det(J))
595-
phi = numpy.tensordot(J/Jdet, phi, (1, 1)).transpose((1, 0, 2))
596-
elif mapping != "identity":
597-
raise ValueError(f"Unrecognized mapping {mapping}")
598-
599-
return phi
598+
sd = ref_el.get_spatial_dimension()
599+
600+
mapping, = set(element.mapping())
601+
base_ref_el = element.get_reference_element()
602+
base_entity_ids = element.entity_dofs()
603+
n = element.degree()
604+
605+
base_expansion_set = element.get_nodal_basis().get_expansion_set()
606+
expansion_set = base_expansion_set.reconstruct(ref_el=ref_el)
607+
608+
base_entity_ids = expansions.polynomial_entity_ids(base_ref_el, n, base_entity_ids)
609+
entity_ids = expansions.polynomial_entity_ids(ref_el, n, base_entity_ids)
610+
611+
shp = element.value_shape()
612+
num_bfs = expansions.polynomial_dimension(ref_el, n, entity_ids)
613+
num_members = expansion_set.get_num_members(n)
614+
coeffs = numpy.zeros((num_bfs, *shp, num_members))
615+
base_coeffs = element.get_coeffs()
616+
617+
rmap = expansions.polynomial_cell_node_map(ref_el, n, base_entity_ids)
618+
cmap = expansion_set.get_cell_node_map(n)
619+
for cell in sorted(top):
620+
cell_verts = ref_el.get_vertices_of_subcomplex(top[sd][cell])
621+
A, b = reference_element.make_affine_mapping(cell_verts, base_ref_el.vertices)
622+
623+
indices = numpy.ix_(rmap[cell], *map(range, shp), cmap[cell])
624+
coeffs[indices] = pullback(mapping, A, base_coeffs)
625+
626+
super().__init__(ref_el, element.degree(), element.degree(), expansion_set, coeffs)
600627

601628

602629
if __name__ == "__main__":
603-
from FIAT import RaviartThomas
630+
from FIAT import Lagrange, Nedelec, RaviartThomas, Regge
604631
from FIAT.reference_element import symmetric_simplex
605632

633+
degree = 1
606634
dim = 3
607635
K = symmetric_simplex(dim)
608-
A = IsoSplit(K)
636+
A = AlfeldSplit(K)
609637

610-
degree = 1
638+
fe = Lagrange(K, degree)
639+
fe = Nedelec(K, degree)
611640
fe = RaviartThomas(K, degree)
612-
# fe = Nedelec(K, degree)
613-
614-
U = MacroExpansionSet(A, fe)
641+
fe = Regge(K, 0)
615642

616643
mapping = fe.mapping()[0]
617644
fdim = fe.formdegree
645+
if isinstance(fdim, tuple):
646+
fdim, = set(fdim)
618647
comps = []
619648
pts = []
620649
for entity in A.topology[fdim]:
621650
pts_cur = A.make_points(fdim, entity, degree+fdim)
622651
pts.extend(pts_cur)
623-
if mapping == "covariant piola":
652+
if mapping == "affine":
653+
comp = numpy.ones(())
654+
elif mapping.endswith("covariant piola"):
624655
comp = A.compute_edge_tangent(entity)
625-
elif mapping == "contravariant piola":
656+
elif mapping.endswith("contravariant piola"):
626657
comp = A.compute_scaled_normal(entity)
658+
if mapping.startswith("double"):
659+
comp = numpy.outer(comp, comp)
627660
comps.extend([comp] * len(pts_cur))
628661

629-
phis = U._tabulate(degree, pts)
662+
P = MacroPolynomialSet(A, fe)
663+
phis = P.tabulate(pts)
664+
630665
for alpha in phis:
631666
shape = phis[alpha].shape
667+
shp = shape[1:-1]
632668
result = numpy.zeros((shape[0], shape[-1]))
669+
670+
ax = (tuple(range(-len(shp), 0)), )*2
633671
for i, comp in enumerate(comps):
634-
result[..., i] = numpy.dot(phis[alpha][..., i], comp)
672+
result[..., i] = numpy.tensordot(phis[alpha][..., i], comp, ax)
635673
result[abs(result) < 1E-14] = 0
636674
phis[alpha] = result
637675

0 commit comments

Comments
 (0)