From cd697b376d7875fc174f2a978de9ea7cf7280c98 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner <inform@tiker.net> Date: Sat, 21 Jun 2014 13:40:50 -0500 Subject: [PATCH] Boundary finding appears to work --- meshmode/discretization/connection.py | 119 ++++++++++++++++++++++- meshmode/discretization/visualization.py | 17 +++- meshmode/mesh/__init__.py | 46 ++++++++- meshmode/mesh/io.py | 2 +- 4 files changed, 179 insertions(+), 5 deletions(-) diff --git a/meshmode/discretization/connection.py b/meshmode/discretization/connection.py index b20b267..4c251aa 100644 --- a/meshmode/discretization/connection.py +++ b/meshmode/discretization/connection.py @@ -23,6 +23,7 @@ THE SOFTWARE. """ import numpy as np +import modepy as mp import pyopencl as cl import pyopencl.array # noqa from pytools import memoize_method, memoize_method_nested @@ -188,11 +189,127 @@ def make_same_mesh_connection(queue, to_discr, from_discr): from_discr, to_discr, groups) -def make_boundary_extractor(queue, discr): +def make_boundary_extractor(queue, discr, group_factory): """ :return: a tuple ``(bdry_mesh, bdry_discr, connection)`` """ + # {{{ build face_map + + # maps (igrp, el_grp, face_id) to a frozenset of vertex IDs + face_map = {} + + for igrp, mgrp in enumerate(discr.mesh.groups): + grp_face_vertex_indices = mgrp.face_vertex_indices() + for iel_grp in xrange(mgrp.nelements): + for fid, loc_face_vertices in enumerate(grp_face_vertex_indices): + face_vertices = frozenset( + mgrp.vertex_indices[iel_grp, fvi] + for fvi in loc_face_vertices + ) + face_map.setdefault(face_vertices, []).append( + (igrp, iel_grp, fid)) + + del face_vertices + + # }}} + + boundary_faces = [ + face_ids[0] + for face_vertices, face_ids in face_map.iteritems() + if len(face_ids) == 1] + + from pytools import flatten + bdry_vertex_vol_nrs = sorted(set(flatten(face_map.iterkeys()))) + + vol_to_bdry_vertices = np.empty( + discr.mesh.vertices.shape[-1], + discr.mesh.vertices.dtype) + vol_to_bdry_vertices.fill(-1) + vol_to_bdry_vertices[bdry_vertex_vol_nrs] = np.arange( + len(bdry_vertex_vol_nrs)) + + bdry_vertices = discr.mesh.vertices[:, bdry_vertex_vol_nrs] + + from meshmode.mesh import Mesh, SimplexElementGroup + bdry_mesh_groups = [] + for igrp, grp in enumerate(discr.groups): + mgrp = grp.mesh_el_group + group_boundary_faces = [ + (ibface_group, ibface_el, ibface_face) + for ibface_group, ibface_el, ibface_face in boundary_faces + if ibface_group == igrp] + + if not isinstance(mgrp, SimplexElementGroup): + raise NotImplementedError("can only take boundary of " + "SimplexElementGroup-based meshes") + + # {{{ Preallocate arrays for mesh group + + ngroup_bdry_elements = len(group_boundary_faces) + vertex_indices = np.empty( + (ngroup_bdry_elements, mgrp.dim+1-1), + mgrp.vertex_indices.dtype) + + bdry_unit_nodes = mp.warp_and_blend_nodes(mgrp.dim-1, mgrp.order) + bdry_unit_nodes_01 = (bdry_unit_nodes + 1)*0.5 + + vol_basis = mp.simplex_onb(mgrp.dim, mgrp.order) + nbdry_unit_nodes = bdry_unit_nodes_01.shape[-1] + nodes = np.empty( + (discr.ambient_dim, ngroup_bdry_elements, nbdry_unit_nodes), + dtype=np.float64) + + # }}} + + grp_face_vertex_indices = mgrp.face_vertex_indices() + grp_vertex_unit_coordinates = mgrp.vertex_unit_coordinates() + + for ibdry_el, (ibface_group, ibface_el, ibface_face) in enumerate( + group_boundary_faces): + + # Find boundary vertex indices + loc_face_vertices = list(grp_face_vertex_indices[ibface_face]) + glob_face_vertices = mgrp.vertex_indices[ibface_el, loc_face_vertices] + vertex_indices[ibdry_el] = vol_to_bdry_vertices[glob_face_vertices] + + # Find unit nodes for boundary element + face_vertex_unit_coordinates = \ + grp_vertex_unit_coordinates[loc_face_vertices] + + # Find A, b such that A [e_1 e_2] + b = [r_1 r_2] + # (Notation assumes that the volume is 3D and the face is 2D.) + b = face_vertex_unit_coordinates[0] + A = ( + face_vertex_unit_coordinates[1:] + - face_vertex_unit_coordinates[0]).T + + face_unit_nodes = (np.dot(A, bdry_unit_nodes_01).T + b).T + + resampling_mat = mp.resampling_matrix( + vol_basis, + face_unit_nodes, mgrp.unit_nodes) + + nodes[:, ibdry_el, :] = np.einsum( + "ij,dj->di", + resampling_mat, + mgrp.nodes[:, ibface_el, :]) + + bdry_mesh_group = SimplexElementGroup( + mgrp.order, vertex_indices, nodes, unit_nodes=bdry_unit_nodes) + bdry_mesh_groups.append(bdry_mesh_group) + + bdry_mesh = Mesh(bdry_vertices, bdry_mesh_groups) + + from meshmode.discretization import Discretization + bdry_discr = Discretization( + discr.cl_context, bdry_mesh, group_factory) + + # FIXME + connection = None + + return bdry_mesh, bdry_discr, connection + # }}} # vim: foldmethod=marker diff --git a/meshmode/discretization/visualization.py b/meshmode/discretization/visualization.py index 9bdf0e0..815df95 100644 --- a/meshmode/discretization/visualization.py +++ b/meshmode/discretization/visualization.py @@ -131,7 +131,22 @@ class Visualizer(object): vis_connectivity = self._vis_connectivity() - if self.vis_discr.dim == 2: + if self.vis_discr.dim == 1: + nodes = list(nodes) + # pad to 3D with zeros + while len(nodes) < 3: + nodes.append(0*nodes[0]) + assert len(nodes) == 3 + + args = tuple(nodes) + (field,) + + # http://docs.enthought.com/mayavi/mayavi/auto/example_plotting_many_lines.html # noqa + src = mlab.pipeline.scalar_scatter(*args) + src.mlab_source.dataset.lines = vis_connectivity.reshape(-1, 2) + lines = mlab.pipeline.stripper(src) + mlab.pipeline.surface(lines, **kwargs) + + elif self.vis_discr.dim == 2: nodes = list(nodes) # pad to 3D with zeros while len(nodes) < 3: diff --git a/meshmode/mesh/__init__.py b/meshmode/mesh/__init__.py index 3ff935a..91f3a7b 100644 --- a/meshmode/mesh/__init__.py +++ b/meshmode/mesh/__init__.py @@ -22,8 +22,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ - -#import numpy as np +import numpy as np import modepy as mp #import numpy.linalg as la from pytools import Record @@ -130,6 +129,9 @@ class SimplexElementGroup(MeshElementGroup): automatically assigned. """ + if not issubclass(vertex_indices.dtype.type, np.integer): + raise TypeError("vertex_indices must be integral") + if unit_nodes is None: if dim is None: raise TypeError("'dim' must be passed " @@ -147,6 +149,46 @@ class SimplexElementGroup(MeshElementGroup): MeshElementGroup.__init__(self, order, vertex_indices, nodes, element_nr_base, node_nr_base, unit_nodes, dim) + def face_vertex_indices(self): + if self.dim == 1: + return ((0, 1)) + elif self.dim == 2: + return ( + (0, 1), + (1, 2), + (0, 2), + ) + elif self.dim == 3: + return ( + (0, 1, 2), + (0, 1, 3), + (0, 2, 3), + (1, 2, 3) + ) + else: + raise NotImplementedError("dim=%d" % self.dim) + + def vertex_unit_coordinates(self): + if self.dim == 1: + return np.array([ + [-1], [1] + ], dtype=np.float64) + elif self.dim == 2: + return np.array([ + [-1, -1], + [1, -1], + [-1, 1], + ], dtype=np.float64) + elif self.dim == 3: + return np.array([ + [-1, -1, -1], + [1, -1, -1], + [-1, 1, -1], + [-1, -1, 1], + ], dtype=np.float64) + else: + raise NotImplementedError("dim=%d" % self.dim) + # }}} diff --git a/meshmode/mesh/io.py b/meshmode/mesh/io.py index 160153c..af83e49 100644 --- a/meshmode/mesh/io.py +++ b/meshmode/mesh/io.py @@ -133,7 +133,7 @@ class GmshMeshReceiver(GmshMeshReceiverBase): el_vertex_count = group_el_type.vertex_count() vertex_indices = np.empty( (ngroup_elements, el_vertex_count), - np.float64) + np.int32) i = 0 for el_vertices, el_nodes, el_type in zip( -- GitLab