Пример #1
0
def from_vertices_and_simplices(vertices, simplices, order=1, fix_orientation=False):
    """Imports a mesh from a numpy array of vertices and an array
    of simplices.

    :arg vertices:
        An array of vertex coordinates with shape
        *(ambient_dim, nvertices)*
    :arg simplices:
        An array *(nelements, nvertices)* of (mesh-wide)
        vertex indices.
    """
    from meshmode.mesh import Mesh
    from meshmode.mesh.generation import make_group_from_vertices

    grp = make_group_from_vertices(vertices, simplices, order)

    if fix_orientation:
        if grp.dim != vertices.shape[0]:
            raise ValueError("can only fix orientation of volume meshes")

        from meshmode.mesh.processing import (
                find_volume_mesh_element_group_orientation,
                flip_simplex_element_group)
        orient = find_volume_mesh_element_group_orientation(vertices, grp)
        grp = flip_simplex_element_group(vertices, grp, orient < 0)

    return Mesh(
            vertices=vertices, groups=[grp],
            is_conforming=True)
Пример #2
0
def from_vertices_and_simplices(vertices,
                                simplices,
                                order=1,
                                fix_orientation=False):
    """Imports a mesh from a numpy array of vertices and an array
    of simplices.

    :arg vertices:
        An array of vertex coordinates with shape
        *(ambient_dim, nvertices)*
    :arg simplices:
        An array *(nelements, nvertices)* of (mesh-wide)
        vertex indices.
    """
    from meshmode.mesh import Mesh
    from meshmode.mesh.generation import make_group_from_vertices

    grp = make_group_from_vertices(vertices, simplices, order)

    if fix_orientation:
        from meshmode.mesh.processing import (
            find_volume_mesh_element_group_orientation,
            flip_simplex_element_group)
        orient = find_volume_mesh_element_group_orientation(vertices, grp)
        grp = flip_simplex_element_group(vertices, grp, orient < 0)

    return Mesh(vertices=vertices,
                groups=[grp],
                nodal_adjacency=None,
                facial_adjacency_groups=None)
Пример #3
0
def from_vertices_and_simplices(vertices, simplices, order=1, fix_orientation=False):
    """Imports a mesh from a numpy array of vertices and an array
    of simplices.

    :arg vertices:
        An array of vertex coordinates with shape
        *(ambient_dim, nvertices)*
    :arg simplices:
        An array *(nelements, nvertices)* of (mesh-wide)
        vertex indices.
    """
    from meshmode.mesh import Mesh
    from meshmode.mesh.generation import make_group_from_vertices

    grp = make_group_from_vertices(vertices, simplices, order)

    if fix_orientation:
        if grp.dim != vertices.shape[0]:
            raise ValueError("can only fix orientation of volume meshes")

        from meshmode.mesh.processing import (
                find_volume_mesh_element_group_orientation,
                flip_simplex_element_group)
        orient = find_volume_mesh_element_group_orientation(vertices, grp)
        grp = flip_simplex_element_group(vertices, grp, orient < 0)

    return Mesh(
            vertices=vertices, groups=[grp],
            is_conforming=True)
Пример #4
0
def from_vertices_and_simplices(vertices, simplices, order=1, fix_orientation=False):
    """Imports a mesh from a numpy array of vertices and an array
    of simplices.

    :arg vertices:
        An array of vertex coordinates with shape
        *(ambient_dim, nvertices)*
    :arg simplices:
        An array *(nelements, nvertices)* of (mesh-wide)
        vertex indices.
    """
    from meshmode.mesh import Mesh
    from meshmode.mesh.generation import make_group_from_vertices

    grp = make_group_from_vertices(vertices, simplices, order)

    if fix_orientation:
        from meshmode.mesh.processing import (
                find_volume_mesh_element_group_orientation,
                flip_simplex_element_group)
        orient = find_volume_mesh_element_group_orientation(vertices, grp)
        grp = flip_simplex_element_group(vertices, grp, orient < 0)

    return Mesh(
            vertices=vertices, groups=[grp],
            nodal_adjacency=None,
            facial_adjacency_groups=None)
Пример #5
0
    def group(self):
        if self._group is None:
            from meshmode.mesh import SimplexElementGroup
            from meshmode.mesh.processing import flip_simplex_element_group

            finat_element_a = self.coordinates_a.function_space_a().finat_element_a

            # IMPORTANT that set :attr:`_group` because
            # :meth:`orientations` may call :meth:`group`
            self._group = SimplexElementGroup(
                finat_element_a.analog().degree,
                self.vertex_indices(),
                self.nodes(),
                dim=self.cell_dimension(),
                unit_nodes=finat_element_a.unit_nodes())

            self._group = flip_simplex_element_group(self.vertices(), self._group,
                                                     self.orientations() < 0)

        return self._group
Пример #6
0
    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)
Пример #7
0
def import_firedrake_mesh(fdrake_mesh, cells_to_use=None,
                          normals=None, no_normals_warn=None):
    """
    Create a :class:`meshmode.mesh.Mesh`
    from a `firedrake.mesh.MeshGeometry`
    with the same cells/elements, vertices, nodes,
    mesh order, and facial adjacency.

    The vertex and node coordinates will be the same, as well
    as the cell/element ordering. However, :mod:`firedrake`
    does not require elements to be positively oriented,
    so any negative elements are flipped
    as in :func:`meshmode.mesh.processing.flip_simplex_element_group`.

    The flipped cells/elements are identified by the returned
    *firedrake_orient* array

    :arg fdrake_mesh: `firedrake.mesh.MeshGeometry`.
        This mesh **must** be in a space of ambient dimension
        1, 2, or 3 and have co-dimension of 0 or 1.
        It must use a simplex as a reference element.

        In the case of a 2-dimensional mesh embedded in 3-space,
        the method ``fdrake_mesh.init_cell_orientations`` must
        have been called.

        In the case of a 1-dimensional mesh embedded in 2-space,
        see parameters *normals* and *no_normals_warn*.

        Finally, the ``coordinates`` attribute must have a function
        space whose *finat_element* associates a degree
        of freedom with each vertex. In particular,
        this means that the vertices of the mesh must have well-defined
        coordinates.
        For those unfamiliar with :mod:`firedrake`, you can
        verify this by looking at

        .. code-block:: python

            coords_fspace = fdrake_mesh.coordinates.function_space()
            vertex_entity_dofs = coords_fspace.finat_element.entity_dofs()[0]
            for entity, dof_list in vertex_entity_dofs.items():
                assert len(dof_list) > 0

    :arg cells_to_use: *cells_to_use* is primarily intended for use
        internally by :func:`~meshmode.interop.firedrake.connection.\
build_connection_from_firedrake`.
        *cells_to_use* must be either

        1. *None*, in which case this argument is ignored, or
        2. a numpy array of unique firedrake cell indexes.

        In case (2.),
        only cells whose index appears in *cells_to_use* are included
        in the resultant mesh, and their index in *cells_to_use*
        becomes the element index in the resultant mesh element group.
        Any faces or vertices which do not touch a cell in
        *cells_to_use* are also ignored.
        Note that in this latter case, some faces that are not
        boundaries in *fdrake_mesh* may become boundaries in the
        returned mesh. These "induced" boundaries are marked with
        :class:`~meshmode.mesh.BTAG_INDUCED_BOUNDARY`
        instead of :class:`~meshmode.mesh.BTAG_ALL`.

    :arg normals: **Only** used if *fdrake_mesh* is a 1-surface
        embedded in 2-space. In this case,

            - If *None* then
              all elements are assumed to be positively oriented.
            - Else, should be a list/array whose *i*\\ th entry
              is the normal for the *i*\\ th element (*i*\\ th
              in *mesh.coordinate.function_space()*'s
              *cell_node_list*)

    :arg no_normals_warn: If *True* (the default), raises a warning
        if *fdrake_mesh* is a 1-surface embedded in 2-space
        and *normals* is *None*.

    :return: A tuple *(meshmode mesh, firedrake_orient)*.
         ``firedrake_orient < 0`` is *True* for any negatively
         oriented firedrake cell (which was flipped by meshmode)
         and False for any positively oriented firedrake cell
         (which was not flipped by meshmode).
    """
    # Type validation
    from firedrake.mesh import MeshGeometry
    if not isinstance(fdrake_mesh, MeshGeometry):
        raise TypeError("'fdrake_mesh_topology' must be an instance of "
                        "firedrake.mesh.MeshGeometry, "
                        "not '%s'." % type(fdrake_mesh))
    if cells_to_use is not None:
        if not isinstance(cells_to_use, np.ndarray):
            raise TypeError("'cells_to_use' must be a np.ndarray or "
                            "*None*")
        assert len(cells_to_use.shape) == 1
        assert np.size(np.unique(cells_to_use)) == np.size(cells_to_use), \
            ":arg:`cells_to_use` must have unique entries"
        assert np.all(np.logical_and(cells_to_use >= 0,
                                     cells_to_use < fdrake_mesh.num_cells()))
    assert fdrake_mesh.ufl_cell().is_simplex(), "Mesh must use simplex cells"
    gdim = fdrake_mesh.geometric_dimension()
    tdim = fdrake_mesh.topological_dimension()
    assert gdim in [1, 2, 3], "Mesh must be in space of ambient dim 1, 2, or 3"
    assert gdim - tdim in [0, 1], "Mesh co-dimension must be 0 or 1"
    # firedrake meshes are not guaranteed be fully instantiated until
    # the .init() method is called. In particular, the coordinates function
    # may not be accessible if we do not call init(). If the mesh has
    # already been initialized, nothing will change. For more details
    # on why we need a second initialization, see
    # this pull request:
    # https://github.com/firedrakeproject/firedrake/pull/627
    # which details how Firedrake implements a mesh's coordinates
    # as a function on that very same mesh
    fdrake_mesh.init()

    # Get all the nodal information we can from the topology
    bdy_tags = _get_firedrake_boundary_tags(
        fdrake_mesh, tag_induced_boundary=cells_to_use is not None)

    with ProcessLogger(logger, "Retrieving vertex indices and computing "
                       "NodalAdjacency from firedrake mesh"):
        vertex_indices, nodal_adjacency = \
            _get_firedrake_nodal_info(fdrake_mesh, cells_to_use=cells_to_use)

        # If only using some cells, vertices may need new indices as many
        # will be removed
        if cells_to_use is not None:
            vert_ndx_new2old = np.unique(vertex_indices.flatten())
            vert_ndx_old2new = dict(zip(vert_ndx_new2old,
                                        np.arange(np.size(vert_ndx_new2old),
                                                  dtype=vertex_indices.dtype)))
            vertex_indices = \
                np.vectorize(vert_ndx_old2new.__getitem__)(vertex_indices)

    with ProcessLogger(logger, "Building (possibly) unflipped "
                       "SimplexElementGroup from firedrake unit nodes/nodes"):

        # Grab the mesh reference element and cell dimension
        coord_finat_elt = fdrake_mesh.coordinates.function_space().finat_element
        cell_dim = fdrake_mesh.cell_dimension()

        # Get finat unit nodes and map them onto the meshmode reference simplex
        finat_unit_nodes = get_finat_element_unit_nodes(coord_finat_elt)
        fd_ref_to_mm = get_affine_reference_simplex_mapping(cell_dim, True)
        finat_unit_nodes = fd_ref_to_mm(finat_unit_nodes)

        # Now grab the nodes
        coords = fdrake_mesh.coordinates
        cell_node_list = coords.function_space().cell_node_list
        if cells_to_use is not None:
            cell_node_list = cell_node_list[cells_to_use]
        nodes = np.real(coords.dat.data[cell_node_list])
        # Add extra dim in 1D for shape (nelements, nunit_nodes, dim)
        if tdim == 1:
            nodes = np.reshape(nodes, nodes.shape + (1,))
        # Transpose nodes to have shape (dim, nelements, nunit_nodes)
        nodes = np.transpose(nodes, (2, 0, 1))

        # make a group (possibly with some elements that need to be flipped)
        unflipped_group = SimplexElementGroup(coord_finat_elt.degree,
                                              vertex_indices,
                                              nodes,
                                              dim=cell_dim,
                                              unit_nodes=finat_unit_nodes)

    # Next get the vertices (we'll need these for the orientations)
    with ProcessLogger(logger, "Obtaining vertex coordinates"):
        coord_finat = fdrake_mesh.coordinates.function_space().finat_element
        # unit_vertex_indices are the element-local indices of the nodes
        # which coincide with the vertices, i.e. for element *i*,
        # vertex 0's coordinates would be nodes[i][unit_vertex_indices[0]].
        # This assumes each vertex has some node which coincides with it...
        # which is normally fine to assume for firedrake meshes.
        unit_vertex_indices = []
        # iterate through the dofs associated to each vertex on the
        # reference element
        for _, dofs in sorted(coord_finat.entity_dofs()[0].items()):
            assert len(dofs) == 1, \
                "The function space of the mesh coordinates must have" \
                " exactly one degree of freedom associated with " \
                " each vertex in order to determine vertex coordinates"
            dof, = dofs
            unit_vertex_indices.append(dof)

        # Now get the vertex coordinates as *(dim, nvertices)*-shaped array
        if cells_to_use is not None:
            nvertices = np.size(vert_ndx_new2old)
        else:
            nvertices = fdrake_mesh.num_vertices()
        vertices = np.ndarray((gdim, nvertices), dtype=nodes.dtype)
        recorded_verts = set()
        for icell, cell_vertex_indices in enumerate(vertex_indices):
            for local_vert_id, global_vert_id in enumerate(cell_vertex_indices):
                if global_vert_id not in recorded_verts:
                    recorded_verts.add(global_vert_id)
                    local_node_nr = unit_vertex_indices[local_vert_id]
                    vertices[:, global_vert_id] = nodes[:, icell, local_node_nr]

    # Use the vertices to compute the orientations and flip the group
    with ProcessLogger(logger, "Computing cell orientations"):
        orient = _get_firedrake_orientations(fdrake_mesh,
                                             unflipped_group,
                                             vertices,
                                             cells_to_use=cells_to_use,
                                             normals=normals,
                                             no_normals_warn=no_normals_warn)

    with ProcessLogger(logger, "Flipping group"):
        from meshmode.mesh.processing import flip_simplex_element_group
        group = flip_simplex_element_group(vertices, unflipped_group, orient < 0)

    # Now, any flipped element had its 0 vertex and 1 vertex exchanged.
    # This changes the local facet nr, so we need to create and then
    # fix our facial adjacency groups. To do that, we need to figure
    # out which local facet numbers switched.
    face_vertex_indices = group.face_vertex_indices()
    # face indices of the faces not containing vertex 0 and not
    # containing vertex 1, respectively
    no_zero_face_ndx, no_one_face_ndx = None, None
    for iface, face in enumerate(face_vertex_indices):
        if 0 not in face:
            no_zero_face_ndx = iface
        elif 1 not in face:
            no_one_face_ndx = iface

    with ProcessLogger(logger, "Building (possibly) unflipped "
                       "FacialAdjacencyGroups"):
        unflipped_facial_adjacency_groups = \
            _get_firedrake_facial_adjacency_groups(fdrake_mesh,
                                                   cells_to_use=cells_to_use)

    # applied below to take elements and element_faces
    # (or neighbors and neighbor_faces) and flip in any faces that need to
    # be flipped.
    def flip_local_face_indices(faces, elements):
        faces = np.copy(faces)
        neg_elements = np.full(elements.shape, False)
        # To handle neighbor case, we only need to flip at elements
        # who have a neighbor, i.e. where neighbors is not a negative
        # bitmask of bdy tags
        neg_elements[elements >= 0] = (orient[elements[elements >= 0]] < 0)
        no_zero = np.logical_and(neg_elements, faces == no_zero_face_ndx)
        no_one = np.logical_and(neg_elements, faces == no_one_face_ndx)
        faces[no_zero], faces[no_one] = no_one_face_ndx, no_zero_face_ndx
        return faces

    # Create new facial adjacency groups that have been flipped
    with ProcessLogger(logger, "Flipping FacialAdjacencyGroups"):
        facial_adjacency_groups = []
        for igroup, fagrps in enumerate(unflipped_facial_adjacency_groups):
            facial_adjacency_groups.append({})
            for ineighbor_group, fagrp in fagrps.items():
                new_element_faces = flip_local_face_indices(fagrp.element_faces,
                                                            fagrp.elements)
                new_neighbor_faces = flip_local_face_indices(fagrp.neighbor_faces,
                                                             fagrp.neighbors)
                new_fagrp = FacialAdjacencyGroup(igroup=igroup,
                                                 ineighbor_group=ineighbor_group,
                                                 elements=fagrp.elements,
                                                 element_faces=new_element_faces,
                                                 neighbors=fagrp.neighbors,
                                                 neighbor_faces=new_neighbor_faces)
                facial_adjacency_groups[igroup][ineighbor_group] = new_fagrp

    return (Mesh(vertices, [group],
                 boundary_tags=bdy_tags,
                 nodal_adjacency=nodal_adjacency,
                 facial_adjacency_groups=facial_adjacency_groups),
            orient)
Пример #8
0
    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 six.iterkeys(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, el_type) in enumerate(zip(
                self.element_vertices, self.element_types)):
            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(*six.iteritems(vertex_gmsh_index_to_mine)))
        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 six.iteritems(el_type_hist):
            if group_el_type.dimensions != mesh_bulk_dim:
                continue

            bulk_el_types.add(group_el_type)

            nodes = np.empty((ambient_dim, ngroup_elements, 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 element, (el_vertices, el_nodes, el_type) in enumerate(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

            unit_nodes = (np.array(group_el_type.lexicographic_node_tuples(),
                    dtype=np.float64).T/group_el_type.order)*2 - 1

            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, np.bool))

            elif isinstance(group_el_type, GmshTensorProductElementBase):
                gmsh_vertex_tuples = type(group_el_type)(order=1).gmsh_node_tuples()
                gmsh_vertex_tuples_loc_dict = dict(
                        (gvt, i)
                        for i, gvt in enumerate(gmsh_vertex_tuples))

                from pytools import (
                        generate_nonnegative_integer_tuples_below as gnitb)
                vertex_shuffle = np.array([
                    gmsh_vertex_tuples_loc_dict[vt]
                    for vt in gnitb(2, group_el_type.dimensions)])

                group = TensorProductElementGroup(
                    group_el_type.order,
                    vertex_indices[:, vertex_shuffle],
                    nodes,
                    unit_nodes=unit_nodes
                    )
            else:
                raise NotImplementedError("gmsh element type: %s"
                        % type(group_el_type).__name__)

            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]
        boundary_tags = tuple(boundary_tags)

        # 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)
Пример #9
0
    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 six.iterkeys(el_type_hist))

        # {{{ build vertex numbering

        vertex_index_gmsh_to_mine = {}
        for el_vertices, el_type in zip(self.element_vertices,
                                        self.element_types):
            for gmsh_vertex_nr in el_vertices:
                if gmsh_vertex_nr not in vertex_index_gmsh_to_mine:
                    vertex_index_gmsh_to_mine[gmsh_vertex_nr] = \
                            len(vertex_index_gmsh_to_mine)

        # }}}

        # {{{ build vertex array

        gmsh_vertex_indices, my_vertex_indices = \
                list(zip(*six.iteritems(vertex_index_gmsh_to_mine)))
        vertices = np.empty((ambient_dim, len(vertex_index_gmsh_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)

        for group_el_type, ngroup_elements in six.iteritems(el_type_hist):
            if group_el_type.dimensions != mesh_bulk_dim:
                continue

            nodes = np.empty(
                (ambient_dim, ngroup_elements, 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_index_gmsh_to_mine[v_nr] for v_nr in el_vertices
                ]

                i += 1

            unit_nodes = (np.array(group_el_type.lexicographic_node_tuples(),
                                   dtype=np.float64).T /
                          group_el_type.order) * 2 - 1

            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, np.bool))

            elif isinstance(group_el_type, GmshTensorProductElementBase):
                gmsh_vertex_tuples = type(group_el_type)(
                    order=1).gmsh_node_tuples()
                gmsh_vertex_tuples_loc_dict = dict(
                    (gvt, i) for i, gvt in enumerate(gmsh_vertex_tuples))

                from pytools import (generate_nonnegative_integer_tuples_below
                                     as gnitb)
                vertex_shuffle = np.array([
                    gmsh_vertex_tuples_loc_dict[vt]
                    for vt in gnitb(2, group_el_type.dimensions)
                ])

                group = TensorProductElementGroup(
                    group_el_type.order,
                    vertex_indices[:, vertex_shuffle],
                    nodes,
                    unit_nodes=unit_nodes)
            else:
                raise NotImplementedError("gmsh element type: %s" %
                                          type(group_el_type).__name__)

            # Gmsh seems to produce elements in the opposite orientation
            # of what we like. Flip them all.

            groups.append(group)

        return Mesh(vertices,
                    groups,
                    nodal_adjacency=None,
                    facial_adjacency_groups=None)
Пример #10
0
    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 six.iterkeys(el_type_hist))

        # {{{ build vertex numbering

        vertex_index_gmsh_to_mine = {}
        for el_vertices, el_type in zip(
                self.element_vertices, self.element_types):
            for gmsh_vertex_nr in el_vertices:
                if gmsh_vertex_nr not in vertex_index_gmsh_to_mine:
                    vertex_index_gmsh_to_mine[gmsh_vertex_nr] = \
                            len(vertex_index_gmsh_to_mine)

        # }}}

        # {{{ build vertex array

        gmsh_vertex_indices, my_vertex_indices = \
                list(zip(*six.iteritems(vertex_index_gmsh_to_mine)))
        vertices = np.empty(
                (ambient_dim, len(vertex_index_gmsh_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)

        for group_el_type, ngroup_elements in six.iteritems(el_type_hist):
            if group_el_type.dimensions != mesh_bulk_dim:
                continue

            nodes = np.empty((ambient_dim, ngroup_elements, 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_index_gmsh_to_mine[v_nr]
                        for v_nr in el_vertices]

                i += 1

            unit_nodes = (np.array(group_el_type.lexicographic_node_tuples(),
                    dtype=np.float64).T/group_el_type.order)*2 - 1

            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, np.bool))

            elif isinstance(group_el_type, GmshTensorProductElementBase):
                group = TensorProductElementGroup(
                    group_el_type.order,
                    vertex_indices,
                    nodes,
                    unit_nodes=unit_nodes
                    )
            else:
                raise NotImplementedError("gmsh element type: %s"
                        % type(group_el_type).__name__)

            # Gmsh seems to produce elements in the opposite orientation
            # of what we like. Flip them all.

            groups.append(group)

        return Mesh(
                vertices, groups,
                nodal_adjacency=None,
                facial_adjacency_groups=None)