def test_barycentric_coordinate_map(dims): from random import Random rng = Random(17) n = 5 unit = np.empty((dims, n)) from modepy.tools import ( pick_random_simplex_unit_coordinate, unit_to_barycentric, barycentric_to_unit, barycentric_to_equilateral, equilateral_to_unit,) for i in range(n): unit[:, i] = pick_random_simplex_unit_coordinate(rng, dims) bary = unit_to_barycentric(unit) assert (np.abs(np.sum(bary, axis=0) - 1) < 1e-15).all() assert (bary >= 0).all() unit2 = barycentric_to_unit(bary) assert la.norm(unit-unit2) < 1e-14 equi = barycentric_to_equilateral(bary) unit3 = equilateral_to_unit(equi) assert la.norm(unit-unit3) < 1e-14
def get_simplex_element_flip_matrix(order, unit_nodes, permutation=None): """ Generate a resampling matrix that corresponds to a permutation of the barycentric coordinates being applied. The default permutation is to swap the first two barycentric coordinates. :param order: The order of the function space on the simplex, (see second argument in :fun:`modepy.simplex_best_available_basis`) :param unit_nodes: A np array of unit nodes with shape *(dim, nunit_nodes)* :param permutation: Either *None*, or a tuple of shape storing a permutation: the *i*th barycentric coordinate gets mapped to the *permutation[i]*th coordinate. :return: A numpy array of shape *(nunit_nodes, nunit_nodes)* which, when its transpose is right-applied to the matrix of nodes (shaped *(dim, nunit_nodes)*), corresponds to the permutation being applied """ from modepy.tools import barycentric_to_unit, unit_to_barycentric bary_unit_nodes = unit_to_barycentric(unit_nodes) flipped_bary_unit_nodes = bary_unit_nodes.copy() if permutation is None: flipped_bary_unit_nodes[0, :] = bary_unit_nodes[1, :] flipped_bary_unit_nodes[1, :] = bary_unit_nodes[0, :] else: flipped_bary_unit_nodes[permutation, :] = bary_unit_nodes flipped_unit_nodes = barycentric_to_unit(flipped_bary_unit_nodes) dim = unit_nodes.shape[0] shape = mp.Simplex(dim) space = mp.PN(dim, order) basis = mp.basis_for_space(space, shape) flip_matrix = mp.resampling_matrix(basis.functions, flipped_unit_nodes, unit_nodes) flip_matrix[np.abs(flip_matrix) < 1e-15] = 0 # Flipping twice should be the identity if permutation is None: assert la.norm( np.dot(flip_matrix, flip_matrix) - np.eye(len(flip_matrix))) < 1e-13 return flip_matrix
def flip_simplex_element_group(vertices, grp, grp_flip_flags): from modepy.tools import barycentric_to_unit, unit_to_barycentric from meshmode.mesh import SimplexElementGroup if not isinstance(grp, SimplexElementGroup): raise NotImplementedError( "flips only supported on " "exclusively SimplexElementGroup-based meshes") # Swap the first two vertices on elements to be flipped. new_vertex_indices = grp.vertex_indices.copy() new_vertex_indices[grp_flip_flags, 0] \ = grp.vertex_indices[grp_flip_flags, 1] new_vertex_indices[grp_flip_flags, 1] \ = grp.vertex_indices[grp_flip_flags, 0] # Generate a resampling matrix that corresponds to the # first two barycentric coordinates being swapped. bary_unit_nodes = unit_to_barycentric(grp.unit_nodes) flipped_bary_unit_nodes = bary_unit_nodes.copy() flipped_bary_unit_nodes[0, :] = bary_unit_nodes[1, :] flipped_bary_unit_nodes[1, :] = bary_unit_nodes[0, :] flipped_unit_nodes = barycentric_to_unit(flipped_bary_unit_nodes) flip_matrix = mp.resampling_matrix( mp.simplex_best_available_basis(grp.dim, grp.order), flipped_unit_nodes, grp.unit_nodes) flip_matrix[np.abs(flip_matrix) < 1e-15] = 0 # Flipping twice should be the identity assert la.norm( np.dot(flip_matrix, flip_matrix) - np.eye(len(flip_matrix))) < 1e-13 # Apply the flip matrix to the nodes. new_nodes = grp.nodes.copy() new_nodes[:, grp_flip_flags] = np.einsum("ij,dej->dei", flip_matrix, grp.nodes[:, grp_flip_flags]) return SimplexElementGroup(grp.order, new_vertex_indices, new_nodes, unit_nodes=grp.unit_nodes)
def flip_simplex_element_group(vertices, grp, grp_flip_flags): from modepy.tools import barycentric_to_unit, unit_to_barycentric from meshmode.mesh import SimplexElementGroup if not isinstance(grp, SimplexElementGroup): raise NotImplementedError("flips only supported on " "exclusively SimplexElementGroup-based meshes") # Swap the first two vertices on elements to be flipped. new_vertex_indices = grp.vertex_indices.copy() new_vertex_indices[grp_flip_flags, 0] \ = grp.vertex_indices[grp_flip_flags, 1] new_vertex_indices[grp_flip_flags, 1] \ = grp.vertex_indices[grp_flip_flags, 0] # Generate a resampling matrix that corresponds to the # first two barycentric coordinates being swapped. bary_unit_nodes = unit_to_barycentric(grp.unit_nodes) flipped_bary_unit_nodes = bary_unit_nodes.copy() flipped_bary_unit_nodes[0, :] = bary_unit_nodes[1, :] flipped_bary_unit_nodes[1, :] = bary_unit_nodes[0, :] flipped_unit_nodes = barycentric_to_unit(flipped_bary_unit_nodes) flip_matrix = mp.resampling_matrix( mp.simplex_best_available_basis(grp.dim, grp.order), flipped_unit_nodes, grp.unit_nodes) flip_matrix[np.abs(flip_matrix) < 1e-15] = 0 # Flipping twice should be the identity assert la.norm( np.dot(flip_matrix, flip_matrix) - np.eye(len(flip_matrix))) < 1e-13 # Apply the flip matrix to the nodes. new_nodes = grp.nodes.copy() new_nodes[:, grp_flip_flags] = np.einsum( "ij,dej->dei", flip_matrix, grp.nodes[:, grp_flip_flags]) return SimplexElementGroup( grp.order, new_vertex_indices, new_nodes, unit_nodes=grp.unit_nodes)
def flip_matrix(self): """ :return: The matrix which should be applied to the *(dim, nunitnodes)*-shaped array of nodes corresponding to an element in order to change orientation - <-> +. The matrix will be *(dim, dim)* and orthogonal with *np.float64* type entries. """ if self._flip_matrix is None: # This is very similar to :mod:`meshmode` in processing.py # the function :function:`from_simplex_element_group`, but # we needed to use firedrake nodes from modepy.tools import barycentric_to_unit, unit_to_barycentric # Generate a resampling matrix that corresponds to the # first two barycentric coordinates being swapped. bary_unit_nodes = unit_to_barycentric(self.unit_nodes()) flipped_bary_unit_nodes = bary_unit_nodes.copy() flipped_bary_unit_nodes[0, :] = bary_unit_nodes[1, :] flipped_bary_unit_nodes[1, :] = bary_unit_nodes[0, :] flipped_unit_nodes = barycentric_to_unit(flipped_bary_unit_nodes) from modepy import resampling_matrix, simplex_best_available_basis flip_matrix = resampling_matrix( simplex_best_available_basis(self.dim(), self.analog().degree), flipped_unit_nodes, self.unit_nodes()) flip_matrix[np.abs(flip_matrix) < 1e-15] = 0 # Flipping twice should be the identity assert la.norm( np.dot(flip_matrix, flip_matrix) - np.eye(len(flip_matrix))) < 1e-13 self._flip_matrix = flip_matrix return self._flip_matrix
def test_barycentric_coordinate_map(dims): n = 100 from modepy.tools import ( unit_to_barycentric, barycentric_to_unit, barycentric_to_equilateral, equilateral_to_unit, ) rng = np.random.Generator(np.random.PCG64(17)) unit = nd.random_nodes_for_shape(shp.Simplex(dims), n, rng=rng) bary = unit_to_barycentric(unit) assert (np.abs(np.sum(bary, axis=0) - 1) < 1e-15).all() assert (bary >= 0).all() unit2 = barycentric_to_unit(bary) assert la.norm(unit - unit2) < 1e-14 equi = barycentric_to_equilateral(bary) unit3 = equilateral_to_unit(equi) assert la.norm(unit - unit3) < 1e-14