Skip to content

Commit

Permalink
merge master
Browse files Browse the repository at this point in the history
  • Loading branch information
indiamai committed Nov 18, 2024
2 parents 21f1bf1 + d167922 commit 3eb0d1a
Show file tree
Hide file tree
Showing 67 changed files with 2,027 additions and 930 deletions.
18 changes: 9 additions & 9 deletions .github/workflows/pythonapp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,30 +12,30 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
python-version: [3.8, 3.9]
python-version: ['3.9', '3.10', '3.11', '3.12']

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v2
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Lint with flake8
run: |
pip install flake8
flake8 --statistics .
python -m pip install flake8
python -m flake8 --statistics .
- name: Check documentation style
run: |
pip install pydocstyle
python -m pip install pydocstyle
python -m pydocstyle .
- name: Install FIAT
run: pip install .
- name: Test with pytest
run: |
pip install coveralls pytest pytest-cov pytest-xdist
DATA_REPO_GIT="" pytest --cov=FIAT/ test/
python -m pip install coveralls pytest pytest-cov pytest-xdist
DATA_REPO_GIT="" python -m pytest --cov=FIAT/ test/
- name: Coveralls
if: ${{ github.repository == 'FEniCS/fiat' && github.head_ref == '' && matrix.os == 'ubuntu-latest' && matrix.python-version == '3.8' }}
if: ${{ github.repository == 'FEniCS/fiat' && github.head_ref == '' && matrix.os == 'ubuntu-latest' && matrix.python-version == '3.11' }}
env:
COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }}
run: coveralls
4 changes: 2 additions & 2 deletions FIAT/P0.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def __init__(self, ref_el):
entity_ids[dim][entity] = [entity] if dim == sd else []
entity_permutations[dim][entity] = perms

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


class P0(finite_element.CiarletElement):
Expand All @@ -49,4 +49,4 @@ def __init__(self, ref_el):
dual = P0Dual(ref_el)
degree = 0
formdegree = ref_el.get_spatial_dimension() # n-form
super(P0, self).__init__(poly_set, dual, degree, formdegree)
super().__init__(poly_set, dual, degree, formdegree)
6 changes: 3 additions & 3 deletions FIAT/Sminus.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ def tabulate(self, order, points, entity=None):

entity_dim, entity_id = entity
transform = self.ref_el.get_entity_transform(entity_dim, entity_id)
points = list(map(transform, points))
points = transform(points)

phivals = {}

Expand Down Expand Up @@ -497,7 +497,7 @@ def __init__(self, ref_el, degree):
self.basis = {(0, 0): Array(Sminus_list)}
else:
self.basis = {(0, 0, 0): Array(Sminus_list)}
super(TrimmedSerendipityEdge, self).__init__(ref_el=ref_el, degree=degree, mapping="covariant piola")
super().__init__(ref_el=ref_el, degree=degree, mapping="covariant piola")


class TrimmedSerendipityFace(TrimmedSerendipity):
Expand Down Expand Up @@ -526,4 +526,4 @@ def __init__(self, ref_el, degree):
Sminus_list = EL + FL
Sminus_list = [[-a[1], a[0]] for a in Sminus_list]
self.basis = {(0, 0): Array(Sminus_list)}
super(TrimmedSerendipityFace, self).__init__(ref_el=ref_el, degree=degree, mapping="contravariant piola")
super().__init__(ref_el=ref_el, degree=degree, mapping="contravariant piola")
14 changes: 7 additions & 7 deletions FIAT/SminusCurl.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,11 @@ def __init__(self, ref_el, degree, mapping):

entity_closure_ids = make_entity_closure_ids(flat_el, entity_ids)

super(TrimmedSerendipity, self).__init__(ref_el=ref_el,
dual=None,
order=degree,
formdegree=formdegree,
mapping=mapping)
super().__init__(ref_el=ref_el,
dual=None,
order=degree,
formdegree=formdegree,
mapping=mapping)

topology = ref_el.get_topology()
unflattening_map = compute_unflattening_map(topology)
Expand Down Expand Up @@ -131,7 +131,7 @@ def tabulate(self, order, points, entity=None):

entity_dim, entity_id = entity
transform = self.ref_el.get_entity_transform(entity_dim, entity_id)
points = list(map(transform, points))
points = transform(points)

phivals = {}

Expand Down Expand Up @@ -231,7 +231,7 @@ def __init__(self, ref_el, degree):

Sminus_list = EL + FL
self.basis = {(0, 0): Array(Sminus_list)}
super(TrimmedSerendipityCurl, self).__init__(ref_el=ref_el, degree=degree, mapping="contravariant piola")
super().__init__(ref_el=ref_el, degree=degree, mapping="contravariant piola")


def e_lambda_1_3d(deg, dx, dy, dz, x_mid, y_mid, z_mid):
Expand Down
16 changes: 8 additions & 8 deletions FIAT/SminusDiv.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,11 @@ def __init__(self, ref_el, degree, mapping):

entity_closure_ids = make_entity_closure_ids(flat_el, entity_ids)

super(TrimmedSerendipity, self).__init__(ref_el=ref_el,
dual=None,
order=degree,
formdegree=formdegree,
mapping=mapping)
super().__init__(ref_el=ref_el,
dual=None,
order=degree,
formdegree=formdegree,
mapping=mapping)

topology = ref_el.get_topology()
unflattening_map = compute_unflattening_map(topology)
Expand Down Expand Up @@ -121,7 +121,7 @@ def tabulate(self, order, points, entity=None):

entity_dim, entity_id = entity
transform = self.ref_el.get_entity_transform(entity_dim, entity_id)
points = list(map(transform, points))
points = transform(points)

phivals = {}

Expand Down Expand Up @@ -198,7 +198,7 @@ def __init__(self, ref_el, degree):
IL = ()
Sminus_list = FL + IL
self.basis = {(0, 0, 0): Array(Sminus_list)}
super(TrimmedSerendipityDiv, self).__init__(ref_el=ref_el, degree=degree, mapping="contravariant piola")
super().__init__(ref_el=ref_el, degree=degree, mapping="contravariant piola")

else:
# Put all 2 dimensional stuff here.
Expand All @@ -213,7 +213,7 @@ def __init__(self, ref_el, degree):
Sminus_list = EL + FL
Sminus_list = [[-a[1], a[0]] for a in Sminus_list]
self.basis = {(0, 0): Array(Sminus_list)}
super(TrimmedSerendipityDiv, self).__init__(ref_el=ref_el, degree=degree, mapping="contravariant piola")
super().__init__(ref_el=ref_el, degree=degree, mapping="contravariant piola")


def f_lambda_2_3d(degree, dx, dy, dz, x_mid, y_mid, z_mid):
Expand Down
17 changes: 14 additions & 3 deletions FIAT/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,14 @@
# Import finite element classes
from FIAT.finite_element import FiniteElement, CiarletElement # noqa: F401
from FIAT.argyris import Argyris
from FIAT.bernardi_raugel import BernardiRaugel
from FIAT.bernstein import Bernstein
from FIAT.bell import Bell
from FIAT.hct import HsiehCloughTocher
from FIAT.alfeld_sorokina import AlfeldSorokina
from FIAT.arnold_qin import ArnoldQin
from FIAT.guzman_neilan import GuzmanNeilanFirstKindH1, GuzmanNeilanSecondKindH1, GuzmanNeilanH1div
from FIAT.christiansen_hu import ChristiansenHu
from FIAT.johnson_mercier import JohnsonMercier
from FIAT.brezzi_douglas_marini import BrezziDouglasMarini
from FIAT.Sminus import TrimmedSerendipityEdge # noqa: F401
Expand All @@ -31,8 +36,7 @@
from FIAT.morley import Morley
from FIAT.nedelec import Nedelec
from FIAT.nedelec_second_kind import NedelecSecondKind
from FIAT.powell_sabin import QuadraticPowellSabin6
from FIAT.powell_sabin import QuadraticPowellSabin12
from FIAT.powell_sabin import QuadraticPowellSabin6, QuadraticPowellSabin12
from FIAT.hierarchical import Legendre, IntegratedLegendre
from FIAT.P0 import P0
from FIAT.raviart_thomas import RaviartThomas
Expand Down Expand Up @@ -65,6 +69,7 @@
# List of supported elements and mapping to element classes
supported_elements = {"Argyris": Argyris,
"Bell": Bell,
"Bernardi-Raugel": BernardiRaugel,
"Bernstein": Bernstein,
"Brezzi-Douglas-Marini": BrezziDouglasMarini,
"Brezzi-Douglas-Fortin-Marini": BrezziDouglasFortinMarini,
Expand All @@ -79,7 +84,13 @@
"Discontinuous Taylor": DiscontinuousTaylor,
"Discontinuous Raviart-Thomas": DiscontinuousRaviartThomas,
"Hermite": CubicHermite,
"HsiehCloughTocher": HsiehCloughTocher,
"Hsieh-Clough-Tocher": HsiehCloughTocher,
"Alfeld-Sorokina": AlfeldSorokina,
"Arnold-Qin": ArnoldQin,
"Christiansen-Hu": ChristiansenHu,
"Guzman-Neilan 1st kind H1": GuzmanNeilanFirstKindH1,
"Guzman-Neilan 2nd kind H1": GuzmanNeilanSecondKindH1,
"Guzman-Neilan H1(div)": GuzmanNeilanH1div,
"Johnson-Mercier": JohnsonMercier,
"Lagrange": Lagrange,
"Kong-Mulder-Veldhuizen": KongMulderVeldhuizen,
Expand Down
84 changes: 84 additions & 0 deletions FIAT/alfeld_sorokina.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Copyright (C) 2024 Pablo D. Brubeck
#
# This file is part of FIAT (https://www.fenicsproject.org)
#
# SPDX-License-Identifier: LGPL-3.0-or-later
#
# Written by Pablo D. Brubeck ([email protected]), 2024

from FIAT import finite_element, dual_set, polynomial_set
from FIAT.functional import ComponentPointEvaluation, PointDivergence
from FIAT.quadrature_schemes import create_quadrature
from FIAT.macro import CkPolynomialSet, AlfeldSplit

import numpy


def AlfeldSorokinaSpace(ref_el, degree):
"""Return a vector-valued C0 PolynomialSet on an Alfeld split with C0
divergence. This works on any simplex and for all polynomial degrees."""
ref_complex = AlfeldSplit(ref_el)
sd = ref_complex.get_spatial_dimension()
C0 = CkPolynomialSet(ref_complex, degree, order=0, shape=(sd,), variant="bubble")
expansion_set = C0.get_expansion_set()
num_members = C0.get_num_members()
coeffs = C0.get_coeffs()

facet_el = ref_complex.construct_subelement(sd-1)
phi = polynomial_set.ONPolynomialSet(facet_el, 0 if sd == 1 else degree-1)
Q = create_quadrature(facet_el, 2 * phi.degree)
qpts, qwts = Q.get_points(), Q.get_weights()
phi_at_qpts = phi.tabulate(qpts)[(0,) * (sd-1)]
weights = numpy.multiply(phi_at_qpts, qwts)

rows = []
for facet in ref_complex.get_interior_facets(sd-1):
n = ref_complex.compute_normal(facet)
jumps = expansion_set.tabulate_normal_jumps(degree, qpts, facet, order=1)
div_jump = n[:, None, None] * jumps[1][None, ...]
r = numpy.tensordot(div_jump, weights, axes=(-1, -1))
rows.append(r.reshape(num_members, -1).T)

if len(rows) > 0:
dual_mat = numpy.vstack(rows)
nsp = polynomial_set.spanning_basis(dual_mat, nullspace=True)
coeffs = numpy.tensordot(nsp, coeffs, axes=(-1, 0))
return polynomial_set.PolynomialSet(ref_complex, degree, degree, expansion_set, coeffs)


class AlfeldSorokinaDualSet(dual_set.DualSet):
def __init__(self, ref_el, degree):
if degree != 2:
raise NotImplementedError(f"{type(self).__name__} only defined for degree = 2")

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

nodes = []
for dim in sorted(top):
for entity in sorted(top[dim]):
cur = len(nodes)

dpts = ref_el.make_points(dim, entity, degree-1)
nodes.extend(PointDivergence(ref_el, pt) for pt in dpts)

pts = ref_el.make_points(dim, entity, degree)
nodes.extend(ComponentPointEvaluation(ref_el, k, (sd,), pt)
for pt in pts for k in range(sd))
entity_ids[dim][entity].extend(range(cur, len(nodes)))

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


class AlfeldSorokina(finite_element.CiarletElement):
"""The Alfeld-Sorokina C0 quadratic macroelement with C0 divergence.
This element belongs to a Stokes complex, and is paired with CG1(Alfeld).
"""
def __init__(self, ref_el, degree=2):
dual = AlfeldSorokinaDualSet(ref_el, degree)
poly_set = AlfeldSorokinaSpace(ref_el, degree)
formdegree = ref_el.get_spatial_dimension() - 1 # (n-1)-form
super().__init__(poly_set, dual, degree, formdegree,
mapping="contravariant piola")
4 changes: 2 additions & 2 deletions FIAT/argyris.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ def __init__(self, ref_el, degree, variant, interpolant_deg):
entity_ids[2][0] = list(range(cur, len(nodes)))
else:
raise ValueError("Invalid variant for Argyris")
super(ArgyrisDualSet, self).__init__(nodes, ref_el, entity_ids)
super().__init__(nodes, ref_el, entity_ids)


class Argyris(finite_element.CiarletElement):
Expand All @@ -107,4 +107,4 @@ def __init__(self, ref_el, degree=5, variant=None):

poly_set = polynomial_set.ONPolynomialSet(ref_el, degree, variant="bubble")
dual = ArgyrisDualSet(ref_el, degree, variant, interpolant_deg)
super(Argyris, self).__init__(poly_set, dual, degree)
super().__init__(poly_set, dual, degree)
71 changes: 71 additions & 0 deletions FIAT/arnold_qin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# This file is part of FIAT (https://www.fenicsproject.org)
#
# SPDX-License-Identifier: LGPL-3.0-or-later
#
# Written by Pablo D. Brubeck ([email protected]), 2024

from FIAT import finite_element, polynomial_set
from FIAT.bernardi_raugel import BernardiRaugelDualSet
from FIAT.quadrature_schemes import create_quadrature
from FIAT.reference_element import TRIANGLE
from FIAT.macro import CkPolynomialSet
from FIAT.hct import HsiehCloughTocher

import numpy


def ArnoldQinSpace(ref_el, degree, reduced=False):
"""Return a basis for the Arnold-Qin space
curl(HCT-red) + P0 x if reduced = True, and
curl(HCT) + P0 x if reduced = False."""
if ref_el.get_shape() != TRIANGLE:
raise ValueError("Arnold-Qin only defined on triangles")
if degree != 2:
raise ValueError("Arnold-Qin only defined for degree = 2")
sd = ref_el.get_spatial_dimension()
HCT = HsiehCloughTocher(ref_el, degree+1, reduced=True)
ref_complex = HCT.get_reference_complex()
Q = create_quadrature(ref_complex, 2 * degree)
qpts, qwts = Q.get_points(), Q.get_weights()

x = qpts.T
bary = numpy.asarray(ref_el.make_points(sd, 0, sd+1))
P0x_at_qpts = x[None, :, :] - bary[:, :, None]

tab = HCT.tabulate(1, qpts)
curl_at_qpts = numpy.stack([tab[(0, 1)], -tab[(1, 0)]], axis=1)
if reduced:
curl_at_qpts = curl_at_qpts[:9]

C0 = CkPolynomialSet(ref_complex, degree, order=0, scale=1, variant="bubble")
C0_at_qpts = C0.tabulate(qpts)[(0,) * sd]
duals = numpy.multiply(C0_at_qpts, qwts)
M = numpy.dot(duals, C0_at_qpts.T)
duals = numpy.linalg.solve(M, duals)

# Remove the constant nullspace
ids = [0, 3, 6]
A = numpy.asarray([[1, 1, 1], [1, -1, 0], [0, -1, 1]])
phis = curl_at_qpts
phis[ids] = numpy.tensordot(A, phis[ids], axes=(-1, 0))
# Replace the constant nullspace with P_0 x
phis[0] = P0x_at_qpts
coeffs = numpy.tensordot(phis, duals, axes=(-1, -1))
return polynomial_set.PolynomialSet(ref_complex, degree, degree,
C0.get_expansion_set(), coeffs)


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."""
def __init__(self, ref_el, degree=2, reduced=False):
poly_set = ArnoldQinSpace(ref_el, degree)
if reduced:
order = 1
mapping = "contravariant piola"
else:
order = degree
mapping = "affine"
dual = BernardiRaugelDualSet(ref_el, order, degree=degree)
formdegree = ref_el.get_spatial_dimension() - 1 # (n-1)-form
super().__init__(poly_set, dual, degree, formdegree, mapping=mapping)
Loading

0 comments on commit 3eb0d1a

Please sign in to comment.