Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add hierarchical and FDM elements #34

Merged
merged 35 commits into from
Feb 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
8f4adbe
Add two FDM discontinuous elements
pbrubeck Apr 5, 2022
093e9d9
flake8
pbrubeck Apr 5, 2022
e1606e1
rename DG FDM elements
pbrubeck Apr 13, 2022
d6a3dcc
Add support for HDiv Trace on the interval
pbrubeck May 6, 2022
ab21234
cathegorize FDM elements by BCs and formdegree
pbrubeck May 12, 2022
f896c02
style
pbrubeck May 15, 2022
5bb511f
Merge branch 'master' into pbrubeck/fdm-discontinuous
pbrubeck Jun 16, 2022
3dfce06
Revert "style"
pbrubeck Jul 4, 2022
d450716
Merge remote-tracking branch 'origin/master' into pbrubeck/fdm-discon…
pbrubeck Jul 4, 2022
9a8b6de
add FDMQuadrature element
pbrubeck Jul 11, 2022
58b050f
Use eigendecomposition instead Cholesky
pbrubeck Jul 13, 2022
bb64e13
fix typo in quadrature interval
pbrubeck Aug 7, 2022
d6d8f0b
Use Galerkin projection to construct differentiation matrix
pbrubeck Oct 21, 2022
4df51a7
cleanup
pbrubeck Oct 21, 2022
5620318
add hierarchical high-order elements
pbrubeck Oct 23, 2022
b7e6921
add FIAT.Legendre and FIAT.IntegratedLegendre
pbrubeck Oct 24, 2022
3ba4fe7
implement barycentric interpolation as a PolynomialSet
pbrubeck Oct 24, 2022
bdec8b7
use simpy to simplify tabulation on sympy objects
pbrubeck Oct 31, 2022
63d95c9
consider alternative DOFs for linear vertex modes
pbrubeck Dec 12, 2022
98de791
Merge remote-tracking branch 'origin/master' into pbrubeck/fdm-discon…
pbrubeck Dec 28, 2022
9829d30
remove whitespace
pbrubeck Jan 6, 2023
b004fde
fix typo
pbrubeck Jan 23, 2023
5e7b712
add tests
pbrubeck Jan 23, 2023
d380cb3
refactoring hierarchical and FDM elements
pbrubeck Jan 31, 2023
d303d73
clean up
pbrubeck Feb 1, 2023
ccf9036
flake8
pbrubeck Feb 6, 2023
ff7062f
build docs
pbrubeck Feb 6, 2023
0716471
import index_iterator
pbrubeck Feb 6, 2023
cf21d92
fix merge conflict
pbrubeck Feb 6, 2023
4abeccb
discard 1D H(div) trace element
pbrubeck Feb 6, 2023
aa32968
drop dmat changes
pbrubeck Feb 7, 2023
59121f6
drop changes in finite_element.py
pbrubeck Feb 7, 2023
afd9198
remove dead code, clean up
pbrubeck Feb 7, 2023
0ef69a4
flake8
pbrubeck Feb 7, 2023
4a631f3
test sparsity for CG/DG variants
pbrubeck Feb 8, 2023
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: 2 additions & 1 deletion FIAT/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@
from FIAT.restricted import RestrictedElement # noqa: F401
from FIAT.quadrature_element import QuadratureElement # noqa: F401
from FIAT.kong_mulder_veldhuizen import KongMulderVeldhuizen # noqa: F401
from FIAT.fdm_element import FDMLagrange, FDMHermite # noqa: F401
from FIAT.hierarchical import Legendre, IntegratedLegendre # noqa: F401
from FIAT.fdm_element import FDMLagrange, FDMDiscontinuousLagrange, FDMQuadrature, FDMBrokenH1, FDMBrokenL2, FDMHermite # noqa: F401

# Important functionality
from FIAT.quadrature import make_quadrature # noqa: F401
Expand Down
113 changes: 83 additions & 30 deletions FIAT/barycentric_interpolation.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,39 +7,92 @@
# Written by Pablo D. Brubeck (brubeck@protonmail.com), 2021

import numpy
from FIAT import reference_element, expansions, polynomial_set
from FIAT.functional import index_iterator


def barycentric_interpolation(xsrc, xdst, order=0):
"""Return tabulations of a 1D Lagrange nodal basis via the second barycentric interpolation formula
def make_dmat(x):
"""Returns Lagrange differentiation matrix and barycentric weights
associated with x[j]."""
dmat = numpy.add.outer(-x, x)
numpy.fill_diagonal(dmat, 1.0)
wts = numpy.prod(dmat, axis=0)
numpy.reciprocal(wts, out=wts)
numpy.divide(numpy.divide.outer(wts, wts), dmat, out=dmat)
numpy.fill_diagonal(dmat, dmat.diagonal() - numpy.sum(dmat, axis=0))
return dmat, wts

See Berrut and Trefethen (2004) https://doi.org/10.1137/S0036144502417715 Eq. (4.2) & (9.4)

:arg xsrc: a :class:`numpy.array` with the nodes defining the Lagrange polynomial basis
:arg xdst: a :class:`numpy.array` with the interpolation points
:arg order: the integer order of differentiation
:returns: dict of tabulations up to the given order (in the same format as :meth:`~.CiarletElement.tabulate`)
class LagrangeLineExpansionSet(expansions.LineExpansionSet):
"""Evaluates a Lagrange basis on a line reference element
via the second barycentric interpolation formula. See Berrut and Trefethen (2004)
https://doi.org/10.1137/S0036144502417715 Eq. (4.2) & (9.4)
"""

# w = barycentric weights
# D = spectral differentiation matrix (D.T : u(xsrc) -> u'(xsrc))
# I = barycentric interpolation matrix (I.T : u(xsrc) -> u(xdst))

D = numpy.add.outer(-xsrc, xsrc)
numpy.fill_diagonal(D, 1.0E0)
w = 1.0E0 / numpy.prod(D, axis=0)
D = numpy.divide.outer(w, w) / D
numpy.fill_diagonal(D, numpy.diag(D) - numpy.sum(D, axis=0))

I = numpy.add.outer(-xsrc, xdst)
idx = numpy.argwhere(numpy.isclose(I, 0.0E0, 0.0E0))
I[idx[:, 0], idx[:, 1]] = 1.0E0
I = 1.0E0 / I
I *= w[:, None]
I[:, idx[:, 1]] = 0.0E0
I[idx[:, 0], idx[:, 1]] = 1.0E0
I = (1.0E0 / numpy.sum(I, axis=0)) * I

tabulation = {(0,): I}
for k in range(order):
tabulation[(k+1,)] = numpy.dot(D, tabulation[(k,)])
return tabulation
def __init__(self, ref_el, pts):
self.nodes = numpy.array(pts).flatten()
self.dmat, self.weights = make_dmat(self.nodes)
super(LagrangeLineExpansionSet, self).__init__(ref_el)

def get_num_members(self, n):
return len(self.nodes)

def tabulate(self, n, pts):
assert n == len(self.nodes)-1
results = numpy.add.outer(-self.nodes, numpy.array(pts).flatten())
with numpy.errstate(divide='ignore', invalid='ignore'):
numpy.reciprocal(results, out=results)
numpy.multiply(results, self.weights[:, None], out=results)
numpy.multiply(1.0 / numpy.sum(results, axis=0), results, out=results)

results[results != results] = 1.0
if results.dtype == object:
from sympy import simplify
results = numpy.array(list(map(simplify, results)))
return results

def tabulate_derivatives(self, n, pts):
return numpy.dot(self.dmat, self.tabulate(n, pts))


class LagrangePolynomialSet(polynomial_set.PolynomialSet):

def __init__(self, ref_el, pts, shape=tuple()):
degree = len(pts) - 1
if shape == tuple():
num_components = 1
else:
flat_shape = numpy.ravel(shape)
num_components = numpy.prod(flat_shape)
num_exp_functions = expansions.polynomial_dimension(ref_el, degree)
num_members = num_components * num_exp_functions
embedded_degree = degree
expansion_set = get_expansion_set(ref_el, pts)

# set up coefficients
if shape == tuple():
coeffs = numpy.eye(num_members)
else:
coeffs_shape = tuple([num_members] + list(shape) + [num_exp_functions])
coeffs = numpy.zeros(coeffs_shape, "d")
# use functional's index_iterator function
cur_bf = 0
for idx in index_iterator(shape):
n = expansions.polynomial_dimension(ref_el, embedded_degree)
for exp_bf in range(n):
cur_idx = tuple([cur_bf] + list(idx) + [exp_bf])
coeffs[cur_idx] = 1.0
cur_bf += 1

dmats = [numpy.transpose(expansion_set.dmat)]
super(LagrangePolynomialSet, self).__init__(ref_el, degree, embedded_degree,
expansion_set, coeffs, dmats)


def get_expansion_set(ref_el, pts):
"""Returns an ExpansionSet instance appopriate for the given
reference element."""
if ref_el.get_shape() == reference_element.LINE:
return LagrangeLineExpansionSet(ref_el, pts)
else:
raise Exception("Unknown reference element type.")
Loading