Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions FIAT/alfeld_sorokina.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,10 @@ class AlfeldSorokina(finite_element.CiarletElement):

This element belongs to a Stokes complex, and is paired with CG1(Alfeld).
"""
DEFAULT_DEGREE = 2

def __init__(self, ref_el, degree=2):
degree = self._parse_degree(degree)
dual = AlfeldSorokinaDualSet(ref_el, degree)
poly_set = AlfeldSorokinaSpace(ref_el, degree)
formdegree = ref_el.get_spatial_dimension() - 1 # (n-1)-form
Expand Down
3 changes: 2 additions & 1 deletion FIAT/argyris.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,10 @@ class Argyris(finite_element.CiarletElement):
"integral(q)" -> dofs are evaluated by quadrature rules with the minimum
degree required for unisolvence plus q.
"""
DEFAULT_DEGREE = 5

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

degree = self._parse_degree(degree)
splitting, variant, interpolant_deg = check_format_variant(variant, degree)
if splitting is not None:
raise NotImplementedError(f"{type(self).__name__} is not implemented as a macroelement.")
Expand Down
3 changes: 3 additions & 0 deletions FIAT/arnold_qin.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,10 @@ def ArnoldQinSpace(ref_el, degree, reduced=False):
class ArnoldQin(finite_element.CiarletElement):
"""The Arnold-Qin C0(Alfeld) quadratic macroelement with divergence in P0.
This element belongs to a Stokes complex, and is paired with unsplit DG0."""
DEFAULT_DEGREE = 2

def __init__(self, ref_el, degree=2, reduced=False):
degree = self._parse_degree(degree)
poly_set = ArnoldQinSpace(ref_el, degree)
if reduced:
order = 1
Expand Down
3 changes: 3 additions & 0 deletions FIAT/arnold_winther.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,10 @@ def __init__(self, ref_el, degree=3):
class ArnoldWinther(finite_element.CiarletElement):
"""The definition of the conforming Arnold-Winther element.
"""
DEFAULT_DEGREE = 3

def __init__(self, ref_el, degree=3):
degree = self._parse_degree(degree)
if ref_el.shape != TRIANGLE:
raise ValueError(f"{type(self).__name__} only defined on triangles")
Ps = polynomial_set.ONSymTensorPolynomialSet(ref_el, degree)
Expand Down
2 changes: 2 additions & 0 deletions FIAT/bell.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,12 @@ def __init__(self, ref_el, degree):

class Bell(finite_element.CiarletElement):
"""The Bell finite element."""
DEFAULT_DEGREE = 5

def __init__(self, ref_el, degree=5):
if ref_el.get_shape() != TRIANGLE:
raise ValueError(f"{type(self).__name__} only defined on triangles")
degree = self._parse_degree(degree)
if degree != 5:
raise ValueError(f"{type(self).__name__} only defined for degree = 5.")
poly_set = polynomial_set.ONPolynomialSet(ref_el, degree)
Expand Down
2 changes: 2 additions & 0 deletions FIAT/bernstein.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,10 @@ def __init__(self, ref_el, degree):

class Bernstein(FiniteElement):
"""A finite element with Bernstein polynomials as basis functions."""
DEFAULT_DEGREE = 1

def __init__(self, ref_el, degree):
degree = self._parse_degree(degree)
dual = BernsteinDualSet(ref_el, degree)
k = 0 # 0-form
super().__init__(ref_el, dual, degree, k)
Expand Down
5 changes: 2 additions & 3 deletions FIAT/brezzi_douglas_marini.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,16 +90,15 @@ class BrezziDouglasMarini(finite_element.CiarletElement):
exactly. This is important when you want to have (nearly) div-preserving
interpolation.
"""
DEFAULT_DEGREE = 1

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

splitting, variant, interpolant_deg = check_format_variant(variant, degree)
if splitting is not None:
ref_el = splitting(ref_el)

if degree < 1:
raise Exception("BDM_k elements only valid for k >= 1")

sd = ref_el.get_spatial_dimension()
if ref_el.is_macrocell():
base_element = type(self)(ref_el.get_parent(), degree)
Expand Down
6 changes: 6 additions & 0 deletions FIAT/c2_elements.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,10 @@ def __init__(self, ref_complex, degree, vorder=None, reduced=False, quad_scheme=

class BrambleZlamalC2(finite_element.CiarletElement):
"""The Bramble-Zlamal C2 element."""
DEFAULT_DEGREE = 9

def __init__(self, ref_el, degree=9, reduced=False, quad_scheme=None):
degree = self._parse_degree(degree)
poly_set = polynomial_set.ONPolynomialSet(ref_el, degree)
dual = C2DualSet(ref_el, degree, reduced=reduced, quad_scheme=quad_scheme)
super().__init__(poly_set, dual, degree, formdegree=0)
Expand All @@ -109,7 +112,10 @@ class AlfeldC2(finite_element.CiarletElement):
"""The Alfeld C^2 macroelement on a double barycentric split.
See Section 7.5 of Lai & Schumacher for the quintic C^2 spline.
"""
DEFAULT_DEGREE = 5

def __init__(self, ref_el, degree=5, reduced=False, quad_scheme=None):
degree = self._parse_degree(degree)
poly_set = AlfeldC2Space(ref_el, degree)
ref_complex = poly_set.get_reference_element()
dual = C2DualSet(ref_complex, degree, reduced=reduced, quad_scheme=quad_scheme)
Expand Down
2 changes: 2 additions & 0 deletions FIAT/crouzeix_raviart.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,10 @@ class CrouzeixRaviart(finite_element.CiarletElement):
Polynomial space: P_k
Dual basis: Evaluation at points or integral moments
"""
DEFAULT_DEGREE = 1

def __init__(self, ref_el, degree, variant=None, quad_scheme=None):
degree = self._parse_degree(degree)
if degree % 2 != 1:
raise ValueError("Crouzeix-Raviart only defined for odd degree")

Expand Down
5 changes: 5 additions & 0 deletions FIAT/discontinuous_lagrange.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,9 @@ class DiscontinuousLagrange(finite_element.CiarletElement):
variant='Alfeld' can be used to obtain a barycentrically refined
macroelement for Scott-Vogelius.
"""

DEFAULT_DEGREE = 0

def __new__(cls, ref_el, degree, variant="equispaced"):
if degree == 0:
Comment thread
pbrubeck marked this conversation as resolved.
Outdated
Comment thread
pbrubeck marked this conversation as resolved.
Outdated
Comment thread
pbrubeck marked this conversation as resolved.
Outdated
Comment thread
pbrubeck marked this conversation as resolved.
Outdated
splitting, _ = parse_lagrange_variant(variant, discontinuous=True)
Expand All @@ -223,6 +226,8 @@ def __new__(cls, ref_el, degree, variant="equispaced"):
return super().__new__(cls)

def __init__(self, ref_el, degree, variant="equispaced"):
degree = self._parse_degree(degree)

splitting, point_variant = parse_lagrange_variant(variant, discontinuous=True)
if splitting is not None:
ref_el = splitting(ref_el)
Expand Down
14 changes: 13 additions & 1 deletion FIAT/finite_element.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,18 @@
from FIAT.quadrature_schemes import create_quadrature


class FiniteElement(object):
class FiniteElement:
"""Class implementing a basic abstraction template for general
finite element families. Finite elements which inherit from
this class are non-nodal unless they are CiarletElement subclasses.
"""

@property
def DEFAULT_DEGREE(self):
raise NotImplementedError(f"{type(self).__name__} does not specify a "
"default degree, please pass one explicitly "
"instead")

def __init__(self, ref_el, dual, order, formdegree=None, mapping="affine", ref_complex=None):
# Relevant attributes that do not necessarily depend on a PolynomialSet object:
# The order (degree) of the polynomial basis
Expand Down Expand Up @@ -120,6 +126,12 @@ def is_nodal():
def is_macroelement(self):
return self.ref_el is not self.ref_complex

def _parse_degree(self, degree):
degree = self.DEFAULT_DEGREE if degree is None else degree
if degree < self.DEFAULT_DEGREE:
raise ValueError(f"{type(self).__name__} is only defined for degree >= {self.DEFAULT_DEGREE}.")
return degree


class CiarletElement(FiniteElement):
"""Class implementing Ciarlet's abstraction of a finite element
Expand Down
5 changes: 5 additions & 0 deletions FIAT/gopalakrishnan_lederer_schoberl.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,10 @@ class GopalakrishnanLedererSchoberlSecondKind(finite_element.CiarletElement):
the weak symmetry constraint.

"""
DEFAULT_DEGREE = 0

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

splitting, variant, interpolant_deg = check_format_variant(variant, degree)
assert variant == "integral"
Expand Down Expand Up @@ -81,6 +84,8 @@ def GopalakrishnanLedererSchoberlFirstKind(ref_el, degree, variant=None, quad_sc

Reference: https://doi.org/10.1093/imanum/drz022
"""
if degree < 1:
raise ValueError("GopalakrishnanLedererSchoberlFirstKind is only defined for degree >= 1.")
fe = GopalakrishnanLedererSchoberlSecondKind(ref_el, degree, variant=variant, quad_scheme=quad_scheme)
entity_dofs = fe.entity_dofs()
sd = ref_el.get_spatial_dimension()
Expand Down
3 changes: 3 additions & 0 deletions FIAT/hct.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,10 @@ class HsiehCloughTocher(finite_element.CiarletElement):
super-smooth C^1 space from Groselj and Knez (2022) on a barycentric split,
although there the basis functions are positive on an incenter split.
"""
DEFAULT_DEGREE = 3

def __init__(self, ref_el, degree=3, reduced=False, quad_scheme=None):
degree = self._parse_degree(degree)
ref_complex = macro.AlfeldSplit(ref_el)
dual = HCTDualSet(ref_complex, degree, reduced=reduced, quad_scheme=quad_scheme)
poly_set = macro.CkPolynomialSet(ref_complex, degree, order=1, vorder=degree-1, variant="bubble")
Expand Down
7 changes: 4 additions & 3 deletions FIAT/hellan_herrmann_johnson.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,10 @@ class HellanHerrmannJohnson(finite_element.CiarletElement):
HHJ(k) is the space of symmetric-matrix-valued polynomials of degree k
or less with normal-normal continuity.
"""
def __init__(self, ref_el, degree=0, variant=None, quad_scheme=None):
if degree < 0:
raise ValueError(f"{type(self).__name__} only defined for degree >= 0")
DEFAULT_DEGREE = 0

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

splitting, variant, qdegree = check_format_variant(variant, degree)
if splitting is not None:
Expand Down
10 changes: 6 additions & 4 deletions FIAT/hermite.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,12 @@ def __init__(self, ref_el):

class CubicHermite(finite_element.CiarletElement):
"""The cubic Hermite finite element. It is what it is."""
DEFAULT_DEGREE = 3

def __init__(self, ref_el, deg=3):
assert deg == 3
poly_set = polynomial_set.ONPolynomialSet(ref_el, 3)
def __init__(self, ref_el, degree=3):
degree = self._parse_degree(degree)
assert degree == 3
poly_set = polynomial_set.ONPolynomialSet(ref_el, degree)
dual = CubicHermiteDualSet(ref_el)

super().__init__(poly_set, dual, 3)
super().__init__(poly_set, dual, degree)
10 changes: 7 additions & 3 deletions FIAT/hierarchical.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,18 @@ def __init__(self, ref_el, degree, codim=0, interpolant_deg=None, quad_scheme=No

class Legendre(finite_element.CiarletElement):
"""Simplicial discontinuous element with Legendre polynomials."""
DEFAULT_DEGREE = 0

def __new__(cls, ref_el, degree, variant=None):
if degree == 0:
if degree is None or degree == 0:
splitting, variant, interpolant_deg = check_format_variant(variant, degree)
if splitting is None and interpolant_deg == 0:
# FIXME P0 on the split requires implementing SplitSimplicialComplex.symmetry_group_size()
return P0(ref_el)
return super().__new__(cls)

def __init__(self, ref_el, degree, variant=None, quad_scheme=None):
degree = self._parse_degree(degree)
splitting, variant, interpolant_deg = check_format_variant(variant, degree)
if splitting is not None:
ref_el = splitting(ref_el)
Expand Down Expand Up @@ -102,12 +105,13 @@ def __init__(self, ref_el, degree, interpolant_deg=None, quad_scheme=None):

class IntegratedLegendre(finite_element.CiarletElement):
"""Simplicial continuous element with integrated Legendre polynomials."""
DEFAULT_DEGREE = 1

def __init__(self, ref_el, degree, variant=None, quad_scheme=None):
degree = self._parse_degree(degree)
splitting, variant, interpolant_deg = check_format_variant(variant, degree)
if splitting is not None:
ref_el = splitting(ref_el)
if degree < 1:
raise ValueError(f"{type(self).__name__} elements only valid for k >= 1")
poly_set = ONPolynomialSet(ref_el, degree, variant="bubble")
dual = IntegratedLegendreDual(ref_el, degree, interpolant_deg=interpolant_deg, quad_scheme=quad_scheme)
formdegree = 0 # 0-form
Expand Down
3 changes: 3 additions & 0 deletions FIAT/histopolation.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,10 @@ def __init__(self, ref_el, degree):

class Histopolation(finite_element.CiarletElement):
"""1D discontinuous element with integral DOFs on GLL subgrid."""
DEFAULT_DEGREE = 0

def __init__(self, ref_el, degree):
degree = self._parse_degree(degree)
if ref_el.shape != LINE:
raise ValueError("Histopolation elements are only defined in one dimension.")

Expand Down
5 changes: 3 additions & 2 deletions FIAT/hu_zhang.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,10 @@ def __init__(self, ref_el, degree, variant, qdegree, quad_scheme):

class HuZhang(finite_element.CiarletElement):
"""The definition of the Hu-Zhang element."""
DEFAULT_DEGREE = 3

def __init__(self, ref_el, degree=3, variant=None, quad_scheme=None):
if degree < 3:
raise ValueError(f"{type(self).__name__} only defined for degree >= 3")
degree = self._parse_degree(degree)
if ref_el.shape != TRIANGLE:
raise ValueError(f"{type(self).__name__} only defined on triangles")
splitting, variant, qdegree = check_format_variant(variant, degree)
Expand Down
2 changes: 2 additions & 0 deletions FIAT/johnson_mercier.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,10 @@ def __init__(self, ref_complex, degree, variant=None, quad_scheme=None):

class JohnsonMercier(finite_element.CiarletElement):
"""The Johnson-Mercier finite element."""
DEFAULT_DEGREE = 1

def __init__(self, ref_el, degree=1, variant=None, quad_scheme=None):
degree = self._parse_degree(degree)
ref_complex = macro.AlfeldSplit(ref_el)
poly_set = macro.HDivSymPolynomialSet(ref_complex, degree)
dual = JohnsonMercierDualSet(ref_complex, degree, variant=variant, quad_scheme=quad_scheme)
Expand Down
2 changes: 2 additions & 0 deletions FIAT/kong_mulder_veldhuizen.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,10 @@ class KongMulderVeldhuizen(finite_element.CiarletElement):
W. A. MULDER

"""
DEFAULT_DEGREE = 1

def __init__(self, ref_el, degree, variant=None):
degree = self._parse_degree(degree)
splitting, variant = parse_lagrange_variant(variant)
if splitting:
ref_el = splitting(ref_el)
Expand Down
4 changes: 4 additions & 0 deletions FIAT/lagrange.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,11 @@ class Lagrange(finite_element.CiarletElement):
entity id. The DOFs are always sorted by the entity ordering
and then lexicographically by lattice multiindex.
"""
DEFAULT_DEGREE = 1

def __init__(self, ref_el, degree, variant="equispaced", sort_entities=False):
degree = self._parse_degree(degree)

Comment thread
pbrubeck marked this conversation as resolved.
Outdated
splitting, point_variant = parse_lagrange_variant(variant)
if splitting is not None:
ref_el = splitting(ref_el)
Expand Down
3 changes: 3 additions & 0 deletions FIAT/mixed.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ class MixedElement(FiniteElement):

This object offers tabulation of the concatenated basis function
tables along with an entity_dofs dict."""

DEFAULT_DEGREE = None

def __init__(self, elements, ref_el=None):
elements = tuple(elements)

Expand Down
2 changes: 2 additions & 0 deletions FIAT/morley.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,12 @@ def duals(ref_el, dim, degree):

class Morley(finite_element.CiarletElement):
"""The Morley finite element."""
DEFAULT_DEGREE = 2

def __init__(self, ref_el, degree=2):
if ref_el.get_shape() not in {TRIANGLE, TETRAHEDRON}:
raise ValueError("Morley only defined on simplices of dimension >= 2")
degree = self._parse_degree(degree)
if degree != 2:
raise ValueError("{type(self).__name__} only defined for degree == 2")
poly_set = polynomial_set.ONPolynomialSet(ref_el, degree)
Expand Down
3 changes: 3 additions & 0 deletions FIAT/nedelec.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,8 +197,11 @@ class Nedelec(finite_element.CiarletElement):
exactly. This is important when you want to have (nearly) curl-preserving
interpolation.
"""
DEFAULT_DEGREE = 1

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

Comment thread
pbrubeck marked this conversation as resolved.
Outdated
splitting, variant, interpolant_deg = check_format_variant(variant, degree)
if splitting is not None:
ref_el = splitting(ref_el)
Expand Down
6 changes: 3 additions & 3 deletions FIAT/nedelec_second_kind.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,15 +190,15 @@ class NedelecSecondKind(CiarletElement):
exactly. This is important when you want to have (nearly) curl-preserving
interpolation.
"""
DEFAULT_DEGREE = 1

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

Comment thread
pbrubeck marked this conversation as resolved.
Outdated
splitting, variant, interpolant_deg = check_format_variant(variant, degree)
if splitting is not None:
ref_el = splitting(ref_el)

# Check degree
assert degree >= 1, "Second kind Nedelecs start at 1!"

# Get dimension
d = ref_el.get_spatial_dimension()

Expand Down
Loading
Loading