Skip to content

Commit 2d802c9

Browse files
committed
LagrangeExpansionSet on 1D manifolds
1 parent a129b96 commit 2d802c9

4 files changed

Lines changed: 40 additions & 18 deletions

File tree

FIAT/barycentric_interpolation.py

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ def barycentric_interpolation(nodes, wts, dmat, pts, order=0):
3030
sp_simplify = numpy.vectorize(simplify)
3131
else:
3232
sp_simplify = lambda x: x
33-
phi = numpy.add.outer(-nodes, pts.flatten())
33+
phi = numpy.add.outer(-nodes.flatten(), pts.flatten())
3434
with numpy.errstate(divide='ignore', invalid='ignore'):
3535
numpy.reciprocal(phi, out=phi)
3636
numpy.multiply(phi, wts[:, None], out=phi)
@@ -49,7 +49,7 @@ def barycentric_interpolation(nodes, wts, dmat, pts, order=0):
4949
def make_dmat(x):
5050
"""Returns Lagrange differentiation matrix and barycentric weights
5151
associated with x[j]."""
52-
dmat = numpy.add.outer(-x, x)
52+
dmat = numpy.add.outer(-x.flatten(), x.flatten())
5353
numpy.fill_diagonal(dmat, 1.0)
5454
wts = numpy.prod(dmat, axis=0)
5555
numpy.reciprocal(wts, out=wts)
@@ -59,22 +59,38 @@ def make_dmat(x):
5959

6060

6161
class LagrangeLineExpansionSet(expansions.LineExpansionSet):
62-
"""Lagrange polynomial expansion set for given points the line."""
62+
"""Lagrange polynomial expansion set for given points on the line."""
6363
def __init__(self, ref_el, pts):
64+
if ref_el.get_spatial_dimension() != 1:
65+
raise Exception("Must have a line")
66+
pts = numpy.asarray(pts)
6467
self.points = pts
65-
self.x = numpy.array(pts, dtype="d").flatten()
68+
6669
self.cell_node_map = expansions.compute_cell_point_map(ref_el, pts, unique=False)
6770
self.dmats = [None for _ in self.cell_node_map]
6871
self.weights = [None for _ in self.cell_node_map]
6972
self.nodes = [None for _ in self.cell_node_map]
73+
self.affine_mappings = {}
7074
for cell, ibfs in self.cell_node_map.items():
71-
self.nodes[cell] = self.x[ibfs]
72-
self.dmats[cell], self.weights[cell] = make_dmat(self.nodes[cell])
75+
x = pts[ibfs]
76+
if ref_el.is_trace():
77+
verts = ref_el.get_vertices_of_subcomplex(ref_el.topology[1][cell])
78+
A = numpy.diff(verts, axis=0)[0]/2
79+
A /= numpy.linalg.norm(A)
80+
b = -numpy.dot(numpy.sum(verts, axis=0)/2, A.T)
81+
self.affine_mappings[cell] = (A, b)
82+
x = numpy.add(numpy.dot(x, A.T), b)
83+
self.nodes[cell] = x
84+
self.dmats[cell], self.weights[cell] = make_dmat(x)
7385

7486
self.degree = max(len(wts) for wts in self.weights)-1
7587
self.recurrence_order = self.degree + 1
76-
super().__init__(ref_el)
77-
self.continuity = None if len(self.x) == sum(len(xk) for xk in self.nodes) else "C0"
88+
self.ref_el = ref_el
89+
self.variant = None
90+
self.scale = 1
91+
self.continuity = None if len(pts) == sum(len(xk) for xk in self.nodes) else "C0"
92+
self._dmats_cache = {}
93+
self._cell_node_map_cache = {}
7894

7995
def get_num_members(self, n):
8096
return len(self.points)
@@ -89,6 +105,12 @@ def get_dmats(self, degree, cell=0):
89105
return [self.dmats[cell].T]
90106

91107
def _tabulate_on_cell(self, n, pts, order=0, cell=0, direction=None):
108+
try:
109+
A, b = self.affine_mappings[cell]
110+
ref_pts = numpy.add(numpy.dot(pts.reshape(-1, A.shape[-1]), A.T), b)
111+
pts = ref_pts.reshape(*pts.shape[:-1], -1)
112+
except KeyError:
113+
pass
92114
return barycentric_interpolation(self.nodes[cell], self.weights[cell], self.dmats[cell], pts, order=order)
93115

94116

FIAT/discontinuous_lagrange.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ def __init__(self, ref_el, degree, variant="equispaced"):
233233
dual = BrokenLagrangeDualSet(ref_el, degree, point_variant=point_variant)
234234
else:
235235
dual = DiscontinuousLagrangeDualSet(ref_el, degree, point_variant=point_variant)
236-
if ref_el.shape == LINE and not ref_el.is_trace():
236+
if ref_el.shape == LINE:
237237
# In 1D we can use the primal basis as the expansion set,
238238
# avoiding any round-off coming from a basis transformation
239239
points = get_lagrange_points(dual)

FIAT/expansions.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,7 @@ def _tabulate(self, n, pts, order=0):
371371
if tdim == 0 and len(phis) == 0:
372372
# Hack for TensorProduct HDivTrace: do not raise TraceError on the interval
373373
for cell in parent.topology[gdim]:
374-
phis[cell] = {(0,)*gdim: numpy.zeros((1, 1))}
374+
phis[cell] = {(0,)*gdim: numpy.zeros(())}
375375
elif sum(len(cell_point_map[cell]) for cell in cell_point_map) < len(pts):
376376
# Raise TraceError when interior points fail to be binned on facets
377377
for cell in parent.topology[gdim]:
@@ -626,14 +626,14 @@ def get_affine_mapping(xs, ys):
626626
"""
627627
X = numpy.asarray(xs)
628628
Y = numpy.asarray(ys)
629-
A = X[1:] - X[:1]
630-
B = Y[1:] - Y[:1]
631-
if A.shape[0] == A.shape[1]:
632-
C = numpy.linalg.solve(A, B)
629+
DX = X[1:] - X[:1]
630+
DY = Y[1:] - Y[:1]
631+
if DX.shape[0] == DX.shape[1]:
632+
AT = numpy.linalg.solve(DX, DY)
633633
else:
634-
C, *_ = numpy.linalg.lstsq(A, B)
635-
b = Y[0] - numpy.dot(X[0], C)
636-
return C.T, b
634+
AT, *_ = numpy.linalg.lstsq(DX, DY)
635+
b = Y[0] - numpy.dot(X[0], AT)
636+
return AT.T, b
637637

638638

639639
def polynomial_dimension(ref_el, n, continuity=None):

finat/element_factory.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ def convert_finiteelement(element, **kwargs):
169169
# Handle quadrilateral short names like RTCE/F and NCE/F.
170170
try:
171171
tpc = supported_tensor_product_cells[element.cell.cellname()]
172-
except ValueError:
172+
except KeyError:
173173
raise ValueError("%s is supported, but handled incorrectly" %
174174
element.family())
175175
element = element.reconstruct(cell=tpc)

0 commit comments

Comments
 (0)