def __init__(self, mesh_el_group, order, index, *, unit_nodes): basis = mp.orthonormal_basis_for_space(mp.QN(mesh_el_group.dim, order), mp.Hypercube(mesh_el_group.dim)) super().__init__(mesh_el_group, order, index, basis=basis, unit_nodes=unit_nodes)
def test_hypercube_submesh(dims, order=3): shape = mp.Hypercube(dims) space = mp.space_for_shape(shape, order) node_tuples = mp.node_tuples_for_space(space) for i, nt in enumerate(node_tuples): logger.info("[%4d] nodes %s", i, nt) assert len(node_tuples) == (order + 1)**dims elements = mp.submesh_for_shape(shape, node_tuples) for e in elements: logger.info("element: %s", e) assert len(elements) == order**dims
@pytest.mark.parametrize( ("order", "ebound"), [ (1, 2e-15), (2, 5e-15), (3, 1e-14), # (4, 3e-14), # (7, 3e-14), # (9, 2e-13), ]) @pytest.mark.parametrize("shape", [ mp.Simplex(2), mp.Simplex(3), mp.Hypercube(2), mp.Hypercube(3), ]) def test_orthogonality(shape, order, ebound): """Test orthogonality of ONBs using cubature.""" qspace = mp.space_for_shape(shape, 2 * order) cub = mp.quadrature_for_space(qspace, shape) basis = mp.orthonormal_basis_for_space(mp.space_for_shape(shape, order), shape) maxerr = 0 for i, f in enumerate(basis.functions): for j, g in enumerate(basis.functions): if i == j: true_result = 1
def make_group_from_vertices(vertices, vertex_indices, order, group_cls=None, unit_nodes=None): # shape: (ambient_dim, nelements, nvertices) ambient_dim = vertices.shape[0] el_vertices = vertices[:, vertex_indices] from meshmode.mesh import SimplexElementGroup, TensorProductElementGroup if group_cls is None: group_cls = SimplexElementGroup if issubclass(group_cls, SimplexElementGroup): if order < 1: raise ValueError("can't represent simplices with mesh order < 1") el_origins = el_vertices[:, :, 0][:, :, np.newaxis] # ambient_dim, nelements, nspan_vectors spanning_vectors = (el_vertices[:, :, 1:] - el_origins) nspan_vectors = spanning_vectors.shape[-1] dim = nspan_vectors # dim, nunit_nodes if unit_nodes is None: shape = mp.Simplex(dim) space = mp.space_for_shape(shape, order) unit_nodes = mp.edge_clustered_nodes_for_space(space, shape) unit_nodes_01 = 0.5 + 0.5 * unit_nodes nodes = np.einsum("si,des->dei", unit_nodes_01, spanning_vectors) + el_origins elif issubclass(group_cls, TensorProductElementGroup): nelements, nvertices = vertex_indices.shape dim = nvertices.bit_length() - 1 if nvertices != 2**dim: raise ValueError("invalid number of vertices for tensor-product " "elements, must be power of two") shape = mp.Hypercube(dim) space = mp.space_for_shape(shape, order) if unit_nodes is None: unit_nodes = mp.edge_clustered_nodes_for_space(space, shape) # shape: (dim, nnodes) unit_nodes_01 = 0.5 + 0.5 * unit_nodes _, nnodes = unit_nodes.shape vertex_tuples = mp.node_tuples_for_space(type(space)(dim, 1)) assert len(vertex_tuples) == nvertices vdm = np.empty((nvertices, nvertices)) for i, vertex_tuple in enumerate(vertex_tuples): for j, func_tuple in enumerate(vertex_tuples): vertex_ref = np.array(vertex_tuple, dtype=np.float64) vdm[i, j] = np.prod(vertex_ref**func_tuple) # shape: (ambient_dim, nelements, nvertices) coeffs = np.empty((ambient_dim, nelements, nvertices)) for d in range(ambient_dim): coeffs[d] = la.solve(vdm, el_vertices[d].T).T vdm_nodes = np.zeros((nnodes, nvertices)) for j, func_tuple in enumerate(vertex_tuples): vdm_nodes[:, j] = np.prod(unit_nodes_01**np.array(func_tuple).reshape( -1, 1), axis=0) nodes = np.einsum("ij,dej->dei", vdm_nodes, coeffs) else: raise ValueError(f"unsupported value for 'group_cls': {group_cls}") # make contiguous nodes = nodes.copy() return group_cls(order, vertex_indices, nodes, unit_nodes=unit_nodes)
def get_mesh(self): el_type_hist = {} for el_type in self.element_types: el_type_hist[el_type] = el_type_hist.get(el_type, 0) + 1 if not el_type_hist: raise RuntimeError("empty mesh in gmsh input") groups = self.groups = [] ambient_dim = self.points.shape[-1] mesh_bulk_dim = max(el_type.dimensions for el_type in el_type_hist) # {{{ build vertex numbering # map set of face vertex indices to list of tags associated to face face_vertex_indices_to_tags = {} vertex_gmsh_index_to_mine = {} for element, el_vertices in enumerate(self.element_vertices): for gmsh_vertex_nr in el_vertices: if gmsh_vertex_nr not in vertex_gmsh_index_to_mine: vertex_gmsh_index_to_mine[gmsh_vertex_nr] = \ len(vertex_gmsh_index_to_mine) if self.tags: el_tag_indexes = [self.gmsh_tag_index_to_mine[t] for t in self.element_markers[element]] # record tags of boundary dimension el_tags = [self.tags[i][0] for i in el_tag_indexes if self.tags[i][1] == mesh_bulk_dim - 1] el_grp_verts = {vertex_gmsh_index_to_mine[e] for e in el_vertices} face_vertex_indices = frozenset(el_grp_verts) if face_vertex_indices not in face_vertex_indices_to_tags: face_vertex_indices_to_tags[face_vertex_indices] = [] face_vertex_indices_to_tags[face_vertex_indices] += el_tags # }}} # {{{ build vertex array gmsh_vertex_indices, my_vertex_indices = \ list(zip(*vertex_gmsh_index_to_mine.items())) vertices = np.empty( (ambient_dim, len(vertex_gmsh_index_to_mine)), dtype=np.float64) vertices[:, np.array(my_vertex_indices, np.intp)] = \ self.points[np.array(gmsh_vertex_indices, np.intp)].T # }}} from meshmode.mesh import (Mesh, SimplexElementGroup, TensorProductElementGroup) bulk_el_types = set() for group_el_type, ngroup_elements in el_type_hist.items(): if group_el_type.dimensions != mesh_bulk_dim: continue bulk_el_types.add(group_el_type) nodes = np.empty( (ambient_dim, ngroup_elements, group_el_type.node_count()), np.float64) el_vertex_count = group_el_type.vertex_count() vertex_indices = np.empty( (ngroup_elements, el_vertex_count), np.int32) i = 0 for el_vertices, el_nodes, el_type in zip( self.element_vertices, self.element_nodes, self.element_types): if el_type is not group_el_type: continue nodes[:, i] = self.points[el_nodes].T vertex_indices[i] = [ vertex_gmsh_index_to_mine[v_nr] for v_nr in el_vertices ] i += 1 import modepy as mp if isinstance(group_el_type, GmshSimplexElementBase): shape = mp.Simplex(group_el_type.dimensions) elif isinstance(group_el_type, GmshTensorProductElementBase): shape = mp.Hypercube(group_el_type.dimensions) else: raise NotImplementedError( f"gmsh element type: {type(group_el_type).__name__}") space = mp.space_for_shape(shape, group_el_type.order) unit_nodes = mp.equispaced_nodes_for_space(space, shape) if isinstance(group_el_type, GmshSimplexElementBase): group = SimplexElementGroup( group_el_type.order, vertex_indices, nodes, unit_nodes=unit_nodes ) if group.dim == 2: from meshmode.mesh.processing import flip_simplex_element_group group = flip_simplex_element_group(vertices, group, np.ones(ngroup_elements, bool)) elif isinstance(group_el_type, GmshTensorProductElementBase): vertex_shuffle = type(group_el_type)( order=1).get_lexicographic_gmsh_node_indices() group = TensorProductElementGroup( group_el_type.order, vertex_indices[:, vertex_shuffle], nodes, unit_nodes=unit_nodes ) else: # NOTE: already checked above raise AssertionError() groups.append(group) # FIXME: This is heuristic. if len(bulk_el_types) == 1: is_conforming = True else: is_conforming = mesh_bulk_dim < 3 # construct boundary tags for mesh from meshmode.mesh import BTAG_ALL, BTAG_REALLY_ALL boundary_tags = [BTAG_ALL, BTAG_REALLY_ALL] if self.tags: boundary_tags += [tag for tag, dim in self.tags if dim == mesh_bulk_dim-1] # compute facial adjacency for Mesh if there is tag information facial_adjacency_groups = None if is_conforming and self.tags: from meshmode.mesh import _compute_facial_adjacency_from_vertices facial_adjacency_groups = _compute_facial_adjacency_from_vertices( groups, boundary_tags, np.int32, np.int8, face_vertex_indices_to_tags) return Mesh( vertices, groups, is_conforming=is_conforming, facial_adjacency_groups=facial_adjacency_groups, boundary_tags=boundary_tags, **self.mesh_construction_kwargs)
def shape(self): return mp.Hypercube(self.dim)