Skip to content

Commit 7db030b

Browse files
committed
restore FIAT back to main
1 parent 2b6cca3 commit 7db030b

1 file changed

Lines changed: 11 additions & 192 deletions

File tree

FIAT/reference_element.py

Lines changed: 11 additions & 192 deletions
Original file line numberDiff line numberDiff line change
@@ -613,56 +613,35 @@ def get_dimension(self):
613613
spatial dimension."""
614614
return self.get_spatial_dimension()
615615

616-
def compute_barycentric_coordinates(self, points, entity=None, rescale=False, facet_ordering=False):
616+
def compute_barycentric_coordinates(self, points, entity=None, rescale=False):
617617
"""Returns the barycentric coordinates of a list of points on the complex."""
618-
618+
if len(points) == 0:
619+
return points
619620
if entity is None:
620621
entity = (self.get_spatial_dimension(), 0)
621-
622622
entity_dim, entity_id = entity
623623
top = self.get_topology()
624624
sd = self.get_spatial_dimension()
625625

626-
# indices = slice(None)
627-
indices = list(range(sd+1))
628-
global_indices = top[entity_dim][entity_id] # indices of all vertices that form the sub-entity
629-
subcomplex = global_indices
630-
626+
# get a subcell containing the entity and the restriction indices of the entity
627+
indices = slice(None)
628+
subcomplex = top[entity_dim][entity_id]
631629
if entity_dim != sd:
632-
# get a sub-cell containing the sub-entity
633630
cell_id = self.connectivity[(entity_dim, sd)][entity_id][0]
634-
635-
# restrict indices to the chosen sub-cell
636631
indices = [i for i, v in enumerate(top[sd][cell_id]) if v in subcomplex]
637-
638-
# get the indices of all vertices that form the sub-cell
639632
subcomplex = top[sd][cell_id]
640633

641-
if facet_ordering:
642-
# Permute indices in facet order
643-
# i.e., for each vertex in turn, get the position of the facet that excludes it
644-
facet_ids = self.connectivity[(entity_dim, entity_dim-1)][entity_id]
645-
facets = [top[entity_dim-1][f] for f in facet_ids] # facet as a tuple of vertex indices that form it
646-
647-
perm = [facets.index(tuple(sorted(set(global_indices) - {v}))) for v in global_indices]
648-
indices = [indices[p] for p in perm]
649-
650-
cell_verts = self.get_vertices_of_subcomplex(subcomplex) # get vertex coordinates of the sub-cell
651-
ref_verts = numpy.eye(sd + 1) # get vertex coordinates of the standard reference cell
652-
A, b = make_affine_mapping(cell_verts, ref_verts)
653-
634+
cell_verts = self.get_vertices_of_subcomplex(subcomplex)
635+
ref_verts = numpy.eye(sd + 1)
636+
A, b = make_affine_mapping(cell_verts, ref_verts)
654637
A, b = A[indices], b[indices]
655638
if rescale:
656639
# rescale barycentric coordinates by the height wrt. to the facet
657640
h = 1 / numpy.linalg.norm(A, axis=1)
658641
b *= h
659642
A *= h[:, None]
660-
661-
# out = numpy.dot(points, A.T)
662-
out = points @ A.T
663-
664-
# return numpy.add(out, b)
665-
return out + b
643+
out = numpy.dot(points, A.T)
644+
return numpy.add(out, b, out=out)
666645

667646
def compute_bubble(self, points, entity=None):
668647
"""Returns the lowest-order bubble on an entity evaluated at the given
@@ -1427,58 +1406,6 @@ def extrinsic_orientation_permutation_map(self):
14271406
def is_macrocell(self):
14281407
return any(c.is_macrocell() for c in self.cells)
14291408

1430-
def compute_factor_barycentric_coordinates(self, points, entity=None, rescale=False):
1431-
"""Compute barycentric coordinates on each axis (factor) of a tensor-product cell.
1432-
1433-
Parameters
1434-
----------
1435-
points: numpy.ndarray or GEM.Node
1436-
The reference coordinates of the points.
1437-
1438-
Returns
1439-
-------
1440-
numpy.ndarray
1441-
A flattened array of shape ``(total_bary_coords, )`` and dtype object if points are GEM nodes,
1442-
otherwise dtype numeric. The i-th entry contains the barycentric coordinates
1443-
on the i-th factor cell. If factor i is a simplex of dimension d, this will
1444-
have shape ``(npoints, d+1)``. If factor i is a hypercube of dimension d,
1445-
this will have shape ``(npoints, 2*d)``.
1446-
"""
1447-
import gem
1448-
1449-
1450-
axis_dims = [c.get_spatial_dimension() for c in self.cells]
1451-
point_slices = TensorProductCell._split_slices(axis_dims)
1452-
1453-
# NOTE: entity is a tuple key of the tensor product cell's topology. It should be decomposed into per-factor sub-entities
1454-
# before being passed to factor.compute_barycentric_coordinates
1455-
if entity is not None:
1456-
raise NotImplementedError("Tensor-product sub-entity decomposition is not implemented yet.")
1457-
1458-
result = []
1459-
for factor, s in zip(self.cells, point_slices):
1460-
factor_sd = factor.get_spatial_dimension()
1461-
if factor_sd == 1:
1462-
factor_bary_coords = factor.compute_barycentric_coordinates(points[..., s], entity, rescale, facet_ordering=True)
1463-
else:
1464-
# For higher dimensional simplicies: vertex ordering is already guaranteed.
1465-
# NOTE: But what if we want to compute barycentric coordinates on a sub-entity and still want facet ordering?
1466-
# Then we need to pass facet_ordering=True even when factor_sd > 1
1467-
factor_bary_coords = factor.compute_barycentric_coordinates(points[..., s], entity, rescale)
1468-
result.append(factor_bary_coords)
1469-
1470-
if isinstance(points, gem.Node):
1471-
# Flatten the array
1472-
# We cannot construct the flat array directly since we may not know upfront the total number
1473-
# of barycentric coordinates (e.g., in a simplex it is d+1, in a hypercube it is 2*d)
1474-
flat_result = numpy.array([bary[j] for bary in result for j in range(bary.shape[0])])
1475-
# returns a ListTensor wrapping the scalar GEM expr. of bary coords.
1476-
flat_result = gem.as_gem(flat_result)
1477-
else:
1478-
flat_result = numpy.concatenate(result)
1479-
1480-
return flat_result
1481-
14821409

14831410
class Hypercube(Cell):
14841411
"""Abstract class for a reference hypercube"""
@@ -1496,8 +1423,6 @@ def __init__(self, dimension, product):
14961423
self.product = product
14971424
self.unflattening_map = compute_unflattening_map(pt)
14981425

1499-
# self.facet_perm = compute_facet_permutation(self.unflattening_map, self.product)
1500-
15011426
def get_dimension(self):
15021427
"""Returns the subelement dimension of the cell. Same as the
15031428
spatial dimension."""
@@ -1596,28 +1521,6 @@ def __ge__(self, other):
15961521
def __le__(self, other):
15971522
return self.product <= other
15981523

1599-
def compute_barycentric_coordinates(self, points, entity=None, rescale=False):
1600-
"""Returns the barycentric coordinates of a list of points on the hypercube.
1601-
1602-
Parameters
1603-
----------
1604-
points: numpy.ndarray or GEM.Node
1605-
The reference coordinates of the points.
1606-
1607-
Returns
1608-
-------
1609-
List of numpy.ndarray or GEM.ComponentTensor
1610-
Returns a list of barycentric coordinates in local facet order such that for any point
1611-
lying on local facet `lf` of the cell, the barycentric coordinate at index `lf` vanishes.
1612-
"""
1613-
if isinstance(points, numpy.ndarray) and len(points) == 0:
1614-
return points
1615-
1616-
tp_bary_coords = self.product.compute_factor_barycentric_coordinates(points, entity, rescale)
1617-
1618-
# return tp_bary_coords[self.facet_perm]
1619-
return tp_bary_coords
1620-
16211524

16221525
class UFCHypercube(Hypercube):
16231526
"""Reference UFC Hypercube
@@ -1936,90 +1839,6 @@ def compute_unflattening_map(topology_dict):
19361839
return unflattening_map
19371840

19381841

1939-
def compute_facet_permutation(unflattening_map, product):
1940-
"""
1941-
Returns a permutation mapping each facet of a Hypercube to the index of the
1942-
barycentric coordinate that vanishes on it.
1943-
1944-
Let's take the example of a quad in 2D. Calling `compute_factor_barycentric_coordinates` returns
1945-
the barycentric coordinates on each of its 2 axes:
1946-
1947-
axis 0 (x): lambda_x_1, lambda_x_2
1948-
axis 1 (y): lambda_y_1, lambda_y_2
1949-
1950-
as a flat array bary_coords = [lambda_x_1, lambda_x_2, lambda_y_1, lambda_y_2]
1951-
1952-
A quad has 4 facets which are numbered in UFC order as:
1953-
1954-
facet 3
1955-
┌───────┐
1956-
│ │
1957-
facet 0 │ │ facet 1
1958-
│ │
1959-
│ │
1960-
└───────┘
1961-
facet 2
1962-
1963-
Since each axis is a UFCInterval (a simplex), with vertices at P1 = (0,) and P2 = (1,) its barycentric coordinates
1964-
are lambda_1 = 1 - t (vanishes at P2) and lambda_2 = t (vanishes at P1). This applies the rule for barycentric coordinates
1965-
on simplicies which is that lambda_i vanishes on the facet opposite vertex i.
1966-
1967-
Therefore:
1968-
1969-
- lambda_x_1 vanishes on facet 1 (x=1), lambda_x_2 vanishes on facet 0 (x=0)
1970-
- lambda_y_1 vanishes on facet 3 (y=1), lambda_y_2 vanishes on facet 2 (y=0)
1971-
1972-
The permutation computed in this function reorders the array of barycentric coordinates such that:
1973-
1974-
bary_coords[perm] = [lambda_x_2, lambda_x_1, lambda_y_2, lambda_y_1]
1975-
1976-
where the i-th entry corresponds to the barycentric coordinate vanishing on facet i.
1977-
"""
1978-
# First compute axis offsets into the flattened barycentric coordinate array.
1979-
axis_offsets = []
1980-
offset = 0
1981-
for axis_cell in product.cells:
1982-
axis_offsets.append(offset)
1983-
offset += axis_cell.get_dimension() + 1
1984-
1985-
# Initialise the integer permutation array
1986-
sd = len(product.cells)
1987-
num_facets = 2 * sd
1988-
perm = numpy.zeros(num_facets, dtype=int)
1989-
1990-
for f in range(num_facets):
1991-
# Recover the tensor-product representation of the facet as given by the unflattening map
1992-
dim_tuple, tp_entity = unflattening_map[(sd - 1, f)]
1993-
1994-
# Determine the axis that's orthogonal to the facet
1995-
# E.g., in a quad:
1996-
# if dim_tuple = (0,1) -> facet has dimension 0 on the first component -> fixed at x = 0 or x = 1
1997-
# if dim_tuple = (1,0) -> facet has dimension 0 on the second component -> fixed at y = 0 or y = 1
1998-
axis = next(
1999-
i for i, d in enumerate(dim_tuple)
2000-
if d == product.cells[i].get_dimension() - 1
2001-
)
2002-
2003-
# Determine the index of the endpoint that produces the facet
2004-
# which gives the local facet number in the axis space
2005-
entity_shape = tuple(
2006-
len(c.get_topology()[d])
2007-
for c, d in zip(product.cells, dim_tuple)
2008-
)
2009-
tuple_ei = numpy.unravel_index(tp_entity, entity_shape)
2010-
local_facet = tuple_ei[axis]
2011-
2012-
# For a simplex (UFCInterval, UFCTriangle), the barycentric coordinate that vanishes on local facet i
2013-
# corresponds to the ID of the vertex that doesn't belong to that facet
2014-
all_vertices = set(product.cells[axis].get_topology()[0].keys())
2015-
facet_vertices = set(product.cells[axis].get_topology()[0][local_facet])
2016-
bary_index = next(iter(all_vertices - facet_vertices))
2017-
2018-
perm[f] = axis_offsets[axis] + bary_index
2019-
2020-
return perm
2021-
2022-
20231842
def max_complex(complexes):
20241843
max_cell = max(complexes)
20251844
if all(max_cell >= b for b in complexes):

0 commit comments

Comments
 (0)