diff --git a/meshmode/mesh/processing.py b/meshmode/mesh/processing.py index 90fa2e8ba1db5d777c4b49c6a99e4f9e6d46a65e..a61349da9d136f5b778119845a6aab4b316148bf 100644 --- a/meshmode/mesh/processing.py +++ b/meshmode/mesh/processing.py @@ -56,6 +56,8 @@ __doc__ = """ .. autofunction:: map_mesh .. autofunction:: affine_map .. autofunction:: rotate_mesh_around_axis + +.. autofunction:: remove_unused_vertices """ @@ -1594,4 +1596,36 @@ def make_mesh_grid( # }}} + +# {{{ remove_unused_vertices + +def remove_unused_vertices(mesh: Mesh) -> Mesh: + if mesh.vertices is None: + raise ValueError("mesh must have vertices") + + def not_none(vi: Optional[np.ndarray]) -> np.ndarray: + if vi is None: + raise ValueError("mesh element groups must have vertex indices") + return vi + + used_vertices = np.unique(np.sort(np.concatenate([ + not_none(grp.vertex_indices).reshape(-1) + for grp in mesh.groups + ]))) + + used_flags: np.ndarray = np.zeros(mesh.nvertices, dtype=np.bool_) + used_flags[used_vertices] = 1 + new_vertex_indices = np.cumsum(used_flags, dtype=mesh.vertex_id_dtype) - 1 + new_vertex_indices[~used_flags] = -1 + + return replace( + mesh, + vertices=mesh.vertices[:, used_flags], + groups=tuple( + replace(grp, vertex_indices=new_vertex_indices[grp.vertex_indices]) + for grp in mesh.groups + )) + +# }}} + # vim: foldmethod=marker diff --git a/test/test_firedrake_interop.py b/test/test_firedrake_interop.py index b9458d80b2abb6e3e93c3926c3d7c7141cba42ad..d32419b1cf7075872d7f34466eb9b2183bda4c62 100644 --- a/test/test_firedrake_interop.py +++ b/test/test_firedrake_interop.py @@ -78,7 +78,8 @@ def fspace_degree(request): def make_mm_mesh(name: str) -> Mesh: from meshmode.mesh.io import read_gmsh - return read_gmsh(name) + from meshmode.mesh.processing import remove_unused_vertices + return remove_unused_vertices(read_gmsh(name)) def make_firedrake_mesh(name: str): diff --git a/test/test_mesh.py b/test/test_mesh.py index 2d54fafaf8c80b522217cb8c20230a34781f63e4..22cd615e2560bd9961dd974e3862c0eb562ad2cd 100644 --- a/test/test_mesh.py +++ b/test/test_mesh.py @@ -256,6 +256,30 @@ def test_mesh_copy(): mesh.copy() +def test_remove_unused_vertices(): + mesh = mgen.generate_box_mesh(3*(np.linspace(0, 1, 5),)) + + assert mesh.vertices is not None + + mesh2 = replace( + mesh, + vertices=np.concatenate([np.zeros((3, 1)), mesh.vertices], axis=1), + groups=tuple( + replace( + grp, + vertex_indices=grp.vertex_indices + 1 + ) + for grp in mesh.groups + )) + + mesh3 = mproc.remove_unused_vertices(mesh2) + + assert np.array_equal(mesh3.vertices, mesh.vertices) + assert np.array_equal( + mesh3.groups[0].vertex_indices, + mesh.groups[0].vertex_indices) + + # {{{ as_python stringification def test_mesh_as_python():