Skip to content

Commit

Permalink
Merged in cyruscycheng21/fiat/cyrus-serendipity-bitbucket (pull request
Browse files Browse the repository at this point in the history
#58)

dPc and Serendipity elements

Approved-by: David Ham <[email protected]>
  • Loading branch information
cyruscycheng21 authored and wence- committed Jul 12, 2019
2 parents 3e213bc + 0c9ea60 commit dd99c9e
Show file tree
Hide file tree
Showing 10 changed files with 481 additions and 4 deletions.
3 changes: 3 additions & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,6 @@ Contributors:

Ivan Yashchuk
email: [email protected]

Cyrus Cheng
email: [email protected]
3 changes: 1 addition & 2 deletions FIAT/P0.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,13 @@ def __init__(self, ref_el):

nodes = [functional.PointEvaluation(ref_el, bary)]
entity_ids = {}
sd = ref_el.get_spatial_dimension()
top = ref_el.get_topology()
for dim in sorted(top):
entity_ids[dim] = {}
for entity in sorted(top[dim]):
entity_ids[dim][entity] = []

entity_ids[sd] = {0: [0]}
entity_ids[dim] = {0: [0]}

super(P0Dual, self).__init__(nodes, ref_el, entity_ids)

Expand Down
4 changes: 4 additions & 0 deletions FIAT/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
from FIAT.discontinuous_lagrange import DiscontinuousLagrange
from FIAT.discontinuous_taylor import DiscontinuousTaylor
from FIAT.discontinuous_raviart_thomas import DiscontinuousRaviartThomas
from FIAT.serendipity import Serendipity
from FIAT.discontinuous_pc import DPC
from FIAT.hermite import CubicHermite
from FIAT.lagrange import Lagrange
from FIAT.gauss_lobatto_legendre import GaussLobattoLegendre
Expand Down Expand Up @@ -55,6 +57,8 @@
"FacetBubble": FacetBubble,
"Crouzeix-Raviart": CrouzeixRaviart,
"Discontinuous Lagrange": DiscontinuousLagrange,
"S": Serendipity,
"DPC": DPC,
"Discontinuous Taylor": DiscontinuousTaylor,
"Discontinuous Raviart-Thomas": DiscontinuousRaviartThomas,
"Hermite": CubicHermite,
Expand Down
124 changes: 124 additions & 0 deletions FIAT/discontinuous_pc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
# Copyright (C) 2018 Cyrus Cheng (Imperial College London)
#
# This file is part of FIAT.
#
# FIAT is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# FIAT is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with FIAT. If not, see <http://www.gnu.org/licenses/>.
#
# Modified by David A. Ham ([email protected]), 2018

from FIAT import finite_element, polynomial_set, dual_set, functional
from FIAT.reference_element import (Point,
DefaultLine,
UFCInterval,
UFCQuadrilateral,
UFCHexahedron,
UFCTriangle,
UFCTetrahedron,
make_affine_mapping,
flatten_reference_cube)
from FIAT.P0 import P0Dual
import numpy as np

hypercube_simplex_map = {Point(): Point(),
DefaultLine(): DefaultLine(),
UFCInterval(): UFCInterval(),
UFCQuadrilateral(): UFCTriangle(),
UFCHexahedron(): UFCTetrahedron()}


class DPC0(finite_element.CiarletElement):
def __init__(self, ref_el):
flat_el = flatten_reference_cube(ref_el)
poly_set = polynomial_set.ONPolynomialSet(hypercube_simplex_map[flat_el], 0)
dual = P0Dual(ref_el)
degree = 0
formdegree = ref_el.get_spatial_dimension() # n-form
super(DPC0, self).__init__(poly_set=poly_set,
dual=dual,
order=degree,
ref_el=ref_el,
formdegree=formdegree)


class DPCDualSet(dual_set.DualSet):
"""The dual basis for DPC elements. This class works for
hypercubes of any dimension. Nodes are point evaluation at
equispaced points. This is the discontinuous version where
all nodes are topologically associated with the cell itself"""

def __init__(self, ref_el, flat_el, degree):
entity_ids = {}
nodes = []

# Change coordinates here.
# Vertices of the simplex corresponding to the reference element.
v_simplex = hypercube_simplex_map[flat_el].get_vertices()
# Vertices of the reference element.
v_hypercube = flat_el.get_vertices()
# For the mapping, first two vertices are unchanged in all dimensions.
v_ = [v_hypercube[0], v_hypercube[int(-0.5*len(v_hypercube))]]

# For dimension 1 upwards,
# take the next vertex and map it to the midpoint of the edge/face it belongs to, and shares
# with no other points.
for d in range(1, flat_el.get_dimension()):
v_.append(tuple(np.asarray(v_hypercube[flat_el.get_dimension() - d] +
np.average(np.asarray(v_hypercube[::2]), axis=0))))
A, b = make_affine_mapping(v_simplex, tuple(v_)) # Make affine mapping to be used later.

# make nodes by getting points
# need to do this dimension-by-dimension, facet-by-facet
top = hypercube_simplex_map[flat_el].get_topology()

cur = 0
for dim in sorted(top):
for entity in sorted(top[dim]):
pts_cur = hypercube_simplex_map[flat_el].make_points(dim, entity, degree)
pts_cur = [tuple(np.matmul(A, np.array(x)) + b) for x in pts_cur]
nodes_cur = [functional.PointEvaluation(flat_el, x)
for x in pts_cur]
nnodes_cur = len(nodes_cur)
nodes += nodes_cur
cur += nnodes_cur

cube_topology = ref_el.get_topology()
for dim in sorted(cube_topology):
entity_ids[dim] = {}
for entity in sorted(cube_topology[dim]):
entity_ids[dim][entity] = []

entity_ids[dim][0] = list(range(len(nodes)))
super(DPCDualSet, self).__init__(nodes, ref_el, entity_ids)


class HigherOrderDPC(finite_element.CiarletElement):
"""The DPC finite element. It is what it is."""

def __init__(self, ref_el, degree):
flat_el = flatten_reference_cube(ref_el)
poly_set = polynomial_set.ONPolynomialSet(hypercube_simplex_map[flat_el], degree)
dual = DPCDualSet(ref_el, flat_el, degree)
formdegree = flat_el.get_spatial_dimension() # n-form
super(HigherOrderDPC, self).__init__(poly_set=poly_set,
dual=dual,
order=degree,
ref_el=ref_el,
formdegree=formdegree)


def DPC(ref_el, degree):
if degree == 0:
return DPC0(ref_el)
else:
return HigherOrderDPC(ref_el, degree)
16 changes: 16 additions & 0 deletions FIAT/dual_set.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,19 @@ def to_riesz(self, poly_set):
self.mat[i][:] = self.nodes[i].to_riesz(poly_set)

return self.mat


def make_entity_closure_ids(ref_el, entity_ids):
entity_closure_ids = {}
for dim, entities in ref_el.sub_entities.items():
entity_closure_ids[dim] = {}

for e, sub_entities in entities.items():
ids = []

for d, se in sub_entities:
ids += entity_ids[d][se]
ids.sort()
entity_closure_ids[d][e] = ids

return entity_closure_ids
4 changes: 2 additions & 2 deletions FIAT/finite_element.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,8 @@ class CiarletElement(FiniteElement):
basis generated from polynomials encoded in a `PolynomialSet`.
"""

def __init__(self, poly_set, dual, order, formdegree=None, mapping="affine"):
ref_el = poly_set.get_reference_element()
def __init__(self, poly_set, dual, order, formdegree=None, mapping="affine", ref_el=None):
ref_el = ref_el or poly_set.get_reference_element()
super(CiarletElement, self).__init__(ref_el, dual, order, formdegree, mapping)

# build generalized Vandermonde matrix
Expand Down
8 changes: 8 additions & 0 deletions FIAT/quadrature.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,14 @@ def make_quadrature(ref_el, m):
return CollapsedQuadratureTriangleRule(ref_el, m)
elif ref_el.get_shape() == reference_element.TETRAHEDRON:
return CollapsedQuadratureTetrahedronRule(ref_el, m)
elif ref_el.get_shape() == reference_element.QUADRILATERAL:
line_rule = GaussJacobiQuadratureLineRule(ref_el.construct_subelement(1), m)
return make_tensor_product_quadrature(line_rule, line_rule)
elif ref_el.get_shape() == reference_element.HEXAHEDRON:
line_rule = GaussJacobiQuadratureLineRule(ref_el.construct_subelement(1), m)
return make_tensor_product_quadrature(line_rule, line_rule, line_rule)
else:
raise ValueError("Unable to make quadrature for cell: %s" % ref_el)


def make_tensor_product_quadrature(*quad_rules):
Expand Down
24 changes: 24 additions & 0 deletions FIAT/reference_element.py
Original file line number Diff line number Diff line change
Expand Up @@ -1025,6 +1025,30 @@ def tuple_sum(tree):
return tree


def is_hypercube(cell):
if isinstance(cell, (DefaultLine, UFCInterval, UFCQuadrilateral, UFCHexahedron)):
return True
elif isinstance(cell, TensorProductCell):
return reduce(lambda a, b: a and b, [is_hypercube(c) for c in cell.cells])
else:
return False


def flatten_reference_cube(ref_el):
"""This function flattens a Tensor Product hypercube to the corresponding UFC hypercube"""
flattened_cube = {2: UFCQuadrilateral(), 3: UFCHexahedron()}
if numpy.sum(ref_el.get_dimension()) <= 1:
# Just return point/interval cell arguments
return ref_el
else:
# Handle cases where cell is a quad/cube constructed from a tensor product or
# an already flattened element
if is_hypercube(ref_el):
return flattened_cube[numpy.sum(ref_el.get_dimension())]
else:
raise TypeError('Invalid cell type')


def flatten_entities(topology_dict):
"""This function flattens topology dict of TensorProductCell and entity_dofs dict of TensorProductElement"""

Expand Down
Loading

0 comments on commit dd99c9e

Please sign in to comment.