From 94f5c62bf64ec42abbe0a5ac8465a6fffe049a47 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner <inform@tiker.net> Date: Thu, 27 Nov 2014 23:53:07 -0600 Subject: [PATCH] Add mesh merge and affine map --- meshmode/discretization/__init__.py | 8 ++- meshmode/mesh/processing.py | 80 +++++++++++++++++++++++++++++ setup.cfg | 2 +- test/test_meshmode.py | 34 +++++++++++- 4 files changed, 120 insertions(+), 4 deletions(-) diff --git a/meshmode/discretization/__init__.py b/meshmode/discretization/__init__.py index e7a09c2..6088753 100644 --- a/meshmode/discretization/__init__.py +++ b/meshmode/discretization/__init__.py @@ -241,10 +241,14 @@ class Discretization(object): result[d, k, i] = \ sum(j, resampling_mat[i, j] * nodes[d, k, j]) """, - name="nodes") + name="nodes", + default_offset=lp.auto) knl = lp.split_iname(knl, "i", 16, inner_tag="l.0") - return lp.tag_inames(knl, dict(k="g.0")) + knl = lp.tag_inames(knl, dict(k="g.0")) + knl = lp.tag_data_axes(knl, "result", + "stride:auto,stride:auto,stride:auto") + return knl result = self.empty(self.real_dtype, extra_dims=(self.ambient_dim,)) diff --git a/meshmode/mesh/processing.py b/meshmode/mesh/processing.py index dfa4607..94cd8b0 100644 --- a/meshmode/mesh/processing.py +++ b/meshmode/mesh/processing.py @@ -34,6 +34,8 @@ __doc__ = """ .. autofunction:: find_volume_mesh_element_orientations .. autofunction:: perform_flips .. autofunction:: find_bounding_box +.. autofunction:: merge_dijsoint_meshes +.. autofunction:: affine_map """ @@ -215,4 +217,82 @@ def find_bounding_box(mesh): # }}} + +# {{{ merging + +def merge_dijsoint_meshes(meshes, skip_tests=False): + if not meshes: + raise ValueError("must pass at least one mesh") + + from pytools import is_single_valued + if not is_single_valued(mesh.ambient_dim for mesh in meshes): + raise ValueError("all meshes must share the same ambient dimension") + + # {{{ assemble combined vertex array + + ambient_dim = meshes[0].ambient_dim + nvertices = sum( + mesh.vertices.shape[-1] + for mesh in meshes) + + vert_dtype = np.find_common_type( + [mesh.vertices.dtype for mesh in meshes], + []) + vertices = np.empty( + (ambient_dim, nvertices), vert_dtype) + + current_vert_base = 0 + vert_bases = [] + for mesh in meshes: + mesh_nvert = mesh.vertices.shape[-1] + vertices[:, current_vert_base:current_vert_base+mesh_nvert] = \ + mesh.vertices + + vert_bases.append(current_vert_base) + current_vert_base += mesh_nvert + + # }}} + + # {{{ assemble new groups list + + new_groups = [] + + for mesh, vert_base in zip(meshes, vert_bases): + for group in mesh.groups: + new_vertex_indices = group.vertex_indices + vert_base + new_group = group.copy(vertex_indices=new_vertex_indices) + new_groups.append(new_group) + + # }}} + + from meshmode.mesh import Mesh + return Mesh(vertices, new_groups, skip_tests=skip_tests) + +# }}} + + +# {{{ affine map + +def affine_map(mesh, A=None, b=None): + """Apply the affine map *f(x)=Ax+b* to the geometry of *mesh*.""" + + vertices = np.einsum("ij,jv->iv", A, mesh.vertices) + b[:, np.newaxis] + + # {{{ assemble new groups list + + new_groups = [] + + for group in mesh.groups: + nodes = ( + np.einsum("ij,jen->ien", A, group.nodes) + + b[:, np.newaxis, np.newaxis]) + new_groups.append(group.copy(nodes=nodes)) + + # }}} + + from meshmode.mesh import Mesh + return Mesh(vertices, new_groups, skip_tests=True) + +# }}} + # vim: foldmethod=marker diff --git a/setup.cfg b/setup.cfg index eca7b43..6faef2e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,3 +1,3 @@ [flake8] -ignore = E126,E127,E128,E123,E226,E241,E242 +ignore = E126,E127,E128,E123,E226,E241,E242,E265 max-line-length=85 diff --git a/test/test_meshmode.py b/test/test_meshmode.py index 3c8f20d..0a24243 100644 --- a/test/test_meshmode.py +++ b/test/test_meshmode.py @@ -117,6 +117,37 @@ def test_element_orientation(): assert ((mesh_orient < 0) == (flippy > 0)).all() +def test_merge_and_map(ctx_getter, visualize=False): + from meshmode.mesh.io import generate_gmsh, FileSource + + mesh_order = 3 + + mesh = generate_gmsh( + FileSource("blob-2d.step"), 2, order=mesh_order, + force_ambient_dim=2, + other_options=["-string", "Mesh.CharacteristicLengthMax = 0.02;"] + ) + + from meshmode.mesh.processing import merge_dijsoint_meshes, affine_map + mesh2 = affine_map(mesh, A=np.eye(2), b=np.array([5, 0])) + + mesh3 = merge_dijsoint_meshes((mesh2, mesh)) + + if visualize: + from meshmode.discretization import Discretization + from meshmode.discretization.poly_element import \ + PolynomialWarpAndBlendGroupFactory + cl_ctx = ctx_getter() + queue = cl.CommandQueue(cl_ctx) + + discr = Discretization(cl_ctx, mesh3, + PolynomialWarpAndBlendGroupFactory(3)) + + from meshmode.discretization.visualization import make_visualizer + vis = make_visualizer(queue, discr, 1) + vis.write_vtk_file("merged.vtu", []) + + @pytest.mark.parametrize("dim", [2, 3]) @pytest.mark.parametrize("order", [1, 3]) def test_sanity_single_element(ctx_getter, dim, order, visualize=False): @@ -242,7 +273,8 @@ def test_sanity_balls(ctx_getter, src_file, dim, mesh_order, from meshmode.discretization.connection import make_boundary_restriction bdry_mesh, bdry_discr, bdry_connection = make_boundary_restriction( - queue, vol_discr, InterpolatoryQuadratureSimplexGroupFactory(quad_order)) + queue, vol_discr, + InterpolatoryQuadratureSimplexGroupFactory(quad_order)) # }}} -- GitLab