Ejemplo n.º 1
0
def test_ply(mesh, binary):
    def writer(*args, **kwargs):
        return meshio.ply.write(*args, binary=binary, **kwargs)

    for k, c in enumerate(mesh.cells):
        mesh.cells[k] = meshio.CellBlock(c.type, c.data.astype(np.int32))

    helpers.write_read(writer, meshio.ply.read, mesh, 1.0e-12)
Ejemplo n.º 2
0
def test_obj(mesh):
    def writer(*args, **kwargs):
        return meshio.obj.write(*args, **kwargs)

    for k, c in enumerate(mesh.cells):
        mesh.cells[k] = meshio.CellBlock(c.type, c.data.astype(numpy.int32))

    helpers.write_read(writer, meshio.obj.read, mesh, 1.0e-12)
Ejemplo n.º 3
0
def export_domain(msh, dim, directory, prefix):
    """
    Export the domain XDMF file as well as the subdomains values.
    """
    # Set cell type
    if dim == 2:
        cell_type = "triangle"
    elif dim == 3:
        cell_type = "tetra"
    # Generate the cell block for the domain cells
    data_array = [arr for (t, arr) in msh.cells if t == cell_type]
    if len(data_array) == 0:
        print("WARNING: No domain physical group found.")
        return
    else:
        data = np.concatenate(data_array)
    cells = [
        meshio.CellBlock(
            type=cell_type,
            data=data,
        )
    ]
    # Generate the domain cells data (for the subdomains)
    try:
        cell_data = {
            "subdomains": [
                np.concatenate(
                    [
                        msh.cell_data["gmsh:physical"][i]
                        for i, cellBlock in enumerate(msh.cells)
                        if cellBlock.type == cell_type
                    ]
                )
            ]
        }
    except KeyError:
        raise ValueError(
            """
            No physical group found for the domain.
            Define the domain physical group.
                - if dim=2, the domain is a surface
                - if dim=3, the domain is a volume
            """
        )

    # Generate a meshio Mesh for the domain
    domain = meshio.Mesh(
        points=msh.points[:, :dim],
        cells=cells,
        cell_data=cell_data,
    )
    # Export the XDMF mesh of the domain
    meshio.write(
        "{}/{}_{}".format(directory, prefix, "domain.xdmf"),
        domain,
        file_format="xdmf"
    )
Ejemplo n.º 4
0
    def _export_1d(
        self, gs: Iterable[pp.Grid]
    ) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
        """
        Export the geometrical data (point coordinates) and connectivity
        information from the 1d PorePy grids to meshio.
        """
        gs = np.atleast_1d(gs)

        # in 1d we have only one cell type
        cell_type = "line"

        # cell connectivity information
        num_cells = np.sum([g.num_cells for g in gs])
        cell_to_nodes = {cell_type: np.empty((num_cells, 2))}
        # cell id map
        cell_id = {cell_type: np.empty(num_cells, dtype=np.int)}
        cell_pos = 0

        # points
        num_pts = np.sum([g.num_nodes for g in gs])
        meshio_pts = np.empty((num_pts, 3))
        pts_pos = 0

        # loop on all the 1d grids
        for g in gs:
            # save the points information
            sl = slice(pts_pos, pts_pos + g.num_nodes)
            meshio_pts[sl, :] = g.nodes.T

            # Cell-node relations
            g_cell_nodes = g.cell_nodes()
            g_nodes_cells, g_cells, _ = sps.find(g_cell_nodes)
            # Ensure ordering of the cells
            g_nodes_cells = g_nodes_cells[np.argsort(g_cells)]

            # loop on all the grid cells
            for c in np.arange(g.num_cells):
                loc = slice(g_cell_nodes.indptr[c], g_cell_nodes.indptr[c + 1])
                # get the local nodes and save them
                cell_to_nodes[cell_type][cell_pos, :] = g_nodes_cells[loc] + pts_pos
                cell_id[cell_type][cell_pos] = cell_pos
                cell_pos += 1

            pts_pos += g.num_nodes

        # construct the meshio data structure
        num_block = len(cell_to_nodes)
        meshio_cells = np.empty(num_block, dtype=np.object)
        meshio_cell_id = np.empty(num_block, dtype=np.object)

        for block, (cell_type, cell_block) in enumerate(cell_to_nodes.items()):
            meshio_cells[block] = meshio.CellBlock(cell_type, cell_block.astype(np.int))
            meshio_cell_id[block] = np.array(cell_id[cell_type])

        return meshio_pts, meshio_cells, meshio_cell_id
Ejemplo n.º 5
0
def extract_to_meshio():
    # extract point coords
    idx, points, _ = gmsh.model.mesh.getNodes()
    points = points.reshape(-1, 3)
    idx -= 1
    srt = numpy.argsort(idx)
    assert numpy.all(idx[srt] == numpy.arange(len(idx)))
    points = points[srt]

    # extract cells
    elem_types, elem_tags, node_tags = gmsh.model.mesh.getElements()
    cells = []
    for elem_type, node_tags in zip(elem_types, node_tags):
        # `elementName', `dim', `order', `numNodes', `localNodeCoord',
        # `numPrimaryNodes'
        num_nodes_per_cell = gmsh.model.mesh.getElementProperties(elem_type)[3]
        meshio.gmsh.gmsh_to_meshio_type
        cells.append(
            meshio.CellBlock(
                meshio.gmsh.gmsh_to_meshio_type[elem_type],
                node_tags.reshape(-1, num_nodes_per_cell) - 1,
            )
        )

    cell_sets = {}
    for dim, tag in gmsh.model.getPhysicalGroups():
        name = gmsh.model.getPhysicalName(dim, tag)
        cell_sets[name] = [[] for _ in range(len(cells))]
        for e in gmsh.model.getEntitiesForPhysicalGroup(dim, tag):
            # TODO node_tags?
            # elem_types, elem_tags, node_tags
            elem_types, elem_tags, _ = gmsh.model.mesh.getElements(dim, e)
            assert len(elem_types) == len(elem_tags)
            assert len(elem_types) == 1
            elem_type = elem_types[0]
            elem_tags = elem_tags[0]

            meshio_cell_type = meshio.gmsh.gmsh_to_meshio_type[elem_type]
            # make sure that the cell type appears only once in the cell list
            # -- for now
            idx = []
            for k, cell_block in enumerate(cells):
                if cell_block.type == meshio_cell_type:
                    idx.append(k)
            assert len(idx) == 1
            idx = idx[0]
            cell_sets[name][idx].append(elem_tags - 1)

        cell_sets[name] = [
            (None if len(idcs) == 0 else numpy.concatenate(idcs))
            for idcs in cell_sets[name]
        ]

    # make meshio mesh
    return meshio.Mesh(points, cells, cell_sets=cell_sets)
Ejemplo n.º 6
0
    def RequestData(self, request, inInfoVec, outInfoVec):
        mesh = dsa.WrapDataObject(vtkUnstructuredGrid.GetData(inInfoVec[0]))

        # Read points
        points = np.asarray(mesh.GetPoints())

        # Read cells
        # Adapted from test/legacy_reader.py
        cell_conn = mesh.GetCells()
        cell_offsets = mesh.GetCellLocations()
        cell_types = mesh.GetCellTypes()
        cells_dict = {}
        for vtk_cell_type in np.unique(cell_types):
            offsets = cell_offsets[cell_types == vtk_cell_type]
            ncells = len(offsets)
            npoints = cell_conn[offsets[0]]
            array = np.empty((ncells, npoints), dtype=int)
            for i in range(npoints):
                array[:, i] = cell_conn[offsets + i + 1]
            cells_dict[vtk_to_meshio_type[vtk_cell_type]] = array
        cells = [meshio.CellBlock(key, cells_dict[key]) for key in cells_dict]

        # Read point and field data
        # Adapted from test/legacy_reader.py
        def _read_data(data):
            out = {}
            for i in range(data.VTKObject.GetNumberOfArrays()):
                name = data.VTKObject.GetArrayName(i)
                array = np.asarray(data.GetArray(i))
                out[name] = array
            return out

        point_data = _read_data(mesh.GetPointData())
        field_data = _read_data(mesh.GetFieldData())

        # Read cell data
        cell_data_flattened = _read_data(mesh.GetCellData())
        cell_data = {}
        for name, array in cell_data_flattened.items():
            cell_data[name] = []
            for cell_type in cells_dict:
                vtk_cell_type = meshio_to_vtk_type[cell_type]
                mask_cell_type = cell_types == vtk_cell_type
                cell_data[name].append(array[mask_cell_type])

        # Use meshio to write mesh
        meshio.write_points_cells(
            self._filename,
            points,
            cells,
            point_data=point_data,
            cell_data=cell_data,
            field_data=field_data,
        )
        return 1
Ejemplo n.º 7
0
def test_obj(mesh, tmp_path):
    for k, c in enumerate(mesh.cells):
        mesh.cells[k] = meshio.CellBlock(c.type, c.data.astype(np.int32))

    helpers.write_read(
        tmp_path,
        meshio.obj.write,
        meshio.obj.read,
        mesh,
        1.0e-12,
        test_memory_file=True,
    )
Ejemplo n.º 8
0
def main(argv=None):
    parser = _get_parser()
    args = parser.parse_args(argv)

    if not (args.max_num_steps < math.inf or args.tolerance > 0.0):
        parser.error(
            "At least one of --max-num-steps or --tolerance required.")

    mesh = meshio.read(args.input_file)

    # Remove all points which do not belong to the highest-order simplex. Those would
    # lead to singular equations systems further down the line.
    mesh.cells = [
        meshio.CellBlock("triangle", mesh.get_cells_type("triangle"))
    ]
    prune(mesh)

    if args.subdomain_field_name:
        field = mesh.cell_data["triangle"][args.subdomain_field_name]
        subdomain_idx = np.unique(field)
        cell_sets = [idx == field for idx in subdomain_idx]
    else:
        cell_sets = [
            np.ones(mesh.get_cells_type("triangle").shape[0], dtype=bool)
        ]

    cells = mesh.get_cells_type("triangle")

    for cell_idx in cell_sets:
        X, cls = optimize_points_cells(
            mesh.points,
            cells[cell_idx],
            args.method,
            args.tolerance,
            args.max_num_steps,
            omega=args.omega,
            verbose=~args.quiet,
            step_filename_format=args.step_filename_format,
        )

        cells[cell_idx] = cls

    q = meshplex.MeshTri(X, cls).q_radius_ratio
    meshio.write_points_cells(
        args.output_file,
        X,
        [("triangle", cells)],
        cell_data={"cell_quality": [q]},
    )
Ejemplo n.º 9
0
def test_ply(mesh, binary, tmp_path):
    def writer(*args, **kwargs):
        return meshio.ply.write(*args, binary=binary, **kwargs)

    for k, c in enumerate(mesh.cells):
        mesh.cells[k] = meshio.CellBlock(c.type, c.data.astype(np.int32))

    helpers.write_read(
        tmp_path,
        writer,
        meshio.ply.read,
        mesh,
        1.0e-12,
        memory_file_is_binary=True,
        test_memory_file=True,
    )
Ejemplo n.º 10
0
def export_boundaries(msh, dim, directory, prefix):
    """
    Export the boundaries XDMF file.
    """
    # Set the cell type
    if dim == 2:
        cell_type = "line"
    elif dim == 3:
        cell_type = "triangle"
    # Generate the cell block for the boundaries cells
    data_array = [arr for (t, arr) in msh.cells if t == cell_type]
    if len(data_array) == 0:
        print("WARNING: No boundary physical group found.")
        return
    else:
        data = np.concatenate(data_array)
    boundaries_cells = [
        meshio.CellBlock(
            type=cell_type,
            data=data,
        )
    ]
    # Generate the boundaries cells data
    cell_data = {
        "boundaries": [
            np.concatenate(
                [
                    msh.cell_data["gmsh:physical"][i]
                    for i, cellBlock in enumerate(msh.cells)
                    if cellBlock.type == cell_type
                ]
            )
        ]
    }
    # Generate the meshio Mesh for the boundaries physical groups
    boundaries = meshio.Mesh(
        points=msh.points[:, :dim],
        cells=boundaries_cells,
        cell_data=cell_data,
    )
    # Export the XDMF mesh of the lines boundaries
    meshio.write(
        "{}/{}_{}".format(directory, prefix, "boundaries.xdmf"),
        boundaries,
        file_format="xdmf"
    )
Ejemplo n.º 11
0
    def to_file(self,
                file_name: str,
                data: Dict[str, np.ndarray] = None,
                **kwargs) -> None:
        """
        Export the fracture network to file.

        The file format is given as an kwarg, by default vtu will be used. The writing is
        outsourced to meshio, thus the file format should be supported by that package.

        The fractures are treated as lines, with no special treatment
        of intersections.

        Fracture numbers are always exported (1-offset). In addition, it is
        possible to export additional data, as specified by the
        keyword-argument data.

        Parameters:
            file_name (str): Name of the target file.
            data (dictionary, optional): Data associated with the fractures.
                The values in the dictionary should be numpy arrays. 1d and 3d
                data is supported. Fracture numbers are always exported.

        Optional arguments in kwargs:
            binary (boolean): Use binary export format. Default to
                True.
            fracture_offset (int): Use to define the offset for a
                fracture id. Default to 1.
            folder_name (string): Path to save the file. Default to "./".
            extension (string): File extension. Default to ".vtu".

        """
        if data is None:
            data = {}

        binary: bool = kwargs.pop("binary", True)
        fracture_offset: int = kwargs.pop("fracture_offset", 1)
        extension: str = kwargs.pop("extension", ".vtu")
        folder_name: str = kwargs.pop("folder_name", "")

        if kwargs:
            msg = "Got unexpected keyword argument '{}'"
            raise TypeError(msg.format(kwargs.popitem()[0]))

        if not file_name.endswith(extension):
            file_name += extension

        # in 1d we have only one cell type
        cell_type = "line"

        # cell connectivity information
        meshio_cells = np.empty(1, dtype=np.object)
        meshio_cells[0] = meshio.CellBlock(cell_type, self.edges.T)

        # prepare the points
        meshio_pts = self.pts.T
        # make points 3d
        if meshio_pts.shape[1] == 2:
            meshio_pts = np.hstack(
                (meshio_pts, np.zeros((meshio_pts.shape[0], 1))))

        # Cell-data to be exported is at least the fracture numbers
        meshio_cell_data = {}
        meshio_cell_data["fracture_number"] = [
            fracture_offset + np.arange(self.edges.shape[1])
        ]

        # process the
        for key, val in data.items():
            if val.ndim == 1:
                meshio_cell_data[key] = [val]
            elif val.ndim == 2:
                meshio_cell_data[key] = [val.T]

        meshio_grid_to_export = meshio.Mesh(meshio_pts,
                                            meshio_cells,
                                            cell_data=meshio_cell_data)
        meshio.write(folder_name + file_name,
                     meshio_grid_to_export,
                     binary=binary)
Ejemplo n.º 12
0
def generate_mesh(  # noqa: C901
    geo_object,
    verbose=True,
    dim=3,
    prune_vertices=True,
    prune_z_0=False,
    remove_lower_dim_cells=False,
    gmsh_path=None,
    extra_gmsh_arguments=None,
    # for debugging purposes:
    geo_filename=None,
    msh_filename=None,
    mesh_file_type="msh",
):
    """Return a meshio.Mesh, storing the mesh points, cells, and data, generated by Gmsh
    from the `geo_object`, written to a temporary file, and reread by `meshio`.

    Gmsh's native "msh" format is ill-suited to fast I/O.  This can greatly reduce the
    performance of pygmsh.  As alternatives, try `mesh_file_type=`:

    - "vtk"`, though Gmsh doesn't write the physical tags to VTK
      <https://gitlab.onelab.info/gmsh/gmsh/issues/389> or

    - `"mesh"`, though this only supports a few basic elements - "line", "triangle",
      "quad", "tetra", "hexahedron" - and doesn't preserve the `$PhysicalNames`, just
      the `int` tags.
    """
    if extra_gmsh_arguments is None:
        extra_gmsh_arguments = []

    # For format "mesh", ask Gmsh to save the physical tags
    # http://gmsh.info/doc/texinfo/gmsh.html#index-Mesh_002eSaveElementTagType
    if mesh_file_type == "mesh":
        extra_gmsh_arguments += ["-string", "Mesh.SaveElementTagType=2;"]

    preserve_geo = geo_filename is not None
    if geo_filename is None:
        with tempfile.NamedTemporaryFile(suffix=".geo") as f:
            geo_filename = f.name

    with open(geo_filename, "w") as f:
        f.write(geo_object.get_code())

    # As of Gmsh 4.1.3, the mesh format options are
    # ```
    # auto, msh1, msh2, msh3, msh4, msh, unv, vtk, wrl, mail, stl, p3d, mesh, bdf, cgns,
    # med, diff, ir3, inp, ply2, celum, su2, x3d, dat, neu, m, key
    # ```
    # Pick the correct filename suffix.
    filename_suffix = "msh" if mesh_file_type[:3] == "msh" else mesh_file_type

    preserve_msh = msh_filename is not None
    if msh_filename is None:
        with tempfile.NamedTemporaryFile(suffix="." +
                                         filename_suffix) as handle:
            msh_filename = handle.name

    gmsh_executable = gmsh_path if gmsh_path is not None else _get_gmsh_exe()

    args = [
        f"-{dim}",
        geo_filename,
        "-format",
        mesh_file_type,
        "-bin",
        "-o",
        msh_filename,
    ] + extra_gmsh_arguments

    # https://stackoverflow.com/a/803421/353337
    try:
        p = subprocess.Popen([gmsh_executable] + args,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.STDOUT)
    except FileNotFoundError:
        print("Is gmsh installed?")
        raise

    if verbose:
        while True:
            line = p.stdout.readline()
            if not line:
                break
            print(line.decode("utf-8"), end="")

    p.communicate()
    assert p.returncode == 0, "Gmsh exited with error (return code {}).".format(
        p.returncode)

    mesh = meshio.read(msh_filename)

    if remove_lower_dim_cells:
        # Only keep the cells of highest topological dimension; discard faces and such.
        cells_2d = {"triangle", "quad"}
        cells_3d = {
            "tetra",
            "hexahedron",
            "wedge",
            "pyramid",
            "penta_prism",
            "hexa_prism",
        }
        if any(c.type in cells_3d for c in mesh.cells):
            keep_types = cells_3d
        elif any(c.type in cells_2d for c in mesh.cells):
            keep_types = cells_2d
        else:
            keep_types = set(cell_type for cell_type, _ in mesh.cells)

        for name, val in mesh.cell_data.items():
            mesh.cell_data[name] = [
                d for d, c in zip(val, mesh.cells) if c[0] in keep_types
            ]
        mesh.cells = [c for c in mesh.cells if c[0] in keep_types]

    if prune_vertices:
        # Make sure to include only those vertices which belong to a cell.
        ncells = numpy.concatenate(
            [numpy.concatenate(c) for _, c in mesh.cells])
        uvertices, uidx = numpy.unique(ncells, return_inverse=True)

        k = 0
        cells = []
        for key, cellblock in mesh.cells:
            n = numpy.prod(cellblock.shape)
            cells.append(
                meshio.CellBlock(key, uidx[k:k + n].reshape(cellblock.shape)))
            k += n
        mesh.cells = cells

        mesh.points = mesh.points[uvertices]
        for key in mesh.point_data:
            mesh.point_data[key] = mesh.point_data[key][uvertices]

    # clean up
    if preserve_msh:
        print(f"\nmsh file: {msh_filename}")
    else:
        Path(msh_filename).unlink()
    if preserve_geo:
        print(f"\ngeo file: {geo_filename}")
    else:
        Path(geo_filename).unlink()

    if (prune_z_0 and mesh.points.shape[1] == 3
            and numpy.all(numpy.abs(mesh.points[:, 2]) < 1.0e-13)):
        mesh.points = mesh.points[:, :2]

    return mesh
Ejemplo n.º 13
0
def main(argv=None):
    parser = _get_parser()
    args = parser.parse_args(argv)

    if not (args.max_num_steps < math.inf or args.tolerance > 0.0):
        parser.error(
            "At least one of --max-num-steps or --tolerance required.")

    mesh = meshio.read(args.input_file)

    # Remove all nodes which do not belong to the highest-order simplex. Those would
    # lead to singular equations systems further down the line.
    mesh.cells = [
        meshio.CellBlock("triangle", mesh.get_cells_type("triangle"))
    ]
    prune(mesh)

    if args.subdomain_field_name:
        field = mesh.cell_data["triangle"][args.subdomain_field_name]
        subdomain_idx = numpy.unique(field)
        cell_sets = [idx == field for idx in subdomain_idx]
    else:
        cell_sets = [
            numpy.ones(mesh.get_cells_type("triangle").shape[0], dtype=bool)
        ]

    method = {
        "laplace": laplace.fixed_point,
        #
        "cpt-dp": cpt.linear_solve_density_preserving,
        "cpt-uniform-fp": cpt.fixed_point_uniform,
        "cpt-uniform-qn": cpt.quasi_newton_uniform,
        #
        "lloyd": cvt.quasi_newton_uniform_lloyd,
        "cvt-uniform-fp": cvt.quasi_newton_uniform_lloyd,
        "cvt-uniform-qnb": cvt.quasi_newton_uniform_blocks,
        "cvt-uniform-qnf": cvt.quasi_newton_uniform_full,
        #
        "odt-dp-fp": odt.fixed_point_density_preserving,
        "odt-uniform-fp": odt.fixed_point_uniform,
        "odt-uniform-bfgs": odt.nonlinear_optimization_uniform,
    }[args.method]

    cells = mesh.get_cells_type("triangle")

    for cell_idx in cell_sets:
        if args.method in ["odt-uniform-bfgs"]:
            # no relaxation parameter omega
            X, cls = method(
                mesh.points,
                cells[cell_idx],
                args.tolerance,
                args.max_num_steps,
                verbose=~args.quiet,
                step_filename_format=args.step_filename_format,
            )
        else:
            X, cls = method(
                mesh.points,
                cells[cell_idx],
                args.tolerance,
                args.max_num_steps,
                omega=args.omega,
                verbose=~args.quiet,
                step_filename_format=args.step_filename_format,
            )

        cells[cell_idx] = cls

    q = meshplex.MeshTri(X, cls).cell_quality
    meshio.write_points_cells(
        args.output_file,
        X,
        [("triangle", cells)],
        cell_data={"cell_quality": [q]},
    )
Ejemplo n.º 14
0
    def generate_mesh(  # noqa: C901
        self,
        dim=3,
        order=None,
        # http://gmsh.info/doc/texinfo/gmsh.html#index-Mesh_002eAlgorithm
        algorithm=None,
    ):
        """Return a meshio.Mesh, storing the mesh points, cells, and data, generated by
        Gmsh from the `self`.
        """
        self.synchronize()

        for item in self._AFTER_SYNC_QUEUE:
            item.exec()

        for item, host in self._EMBED_QUEUE:
            gmsh.model.mesh.embed(item.dim, [item._ID], host.dim, host._ID)

        # set compound entities after sync
        for c in self._COMPOUND_ENTITIES:
            gmsh.model.mesh.setCompound(*c)

        for s in self._RECOMBINE_ENTITIES:
            gmsh.model.mesh.setRecombine(*s)

        for t in self._TRANSFINITE_CURVE_QUEUE:
            gmsh.model.mesh.setTransfiniteCurve(*t)

        for t in self._TRANSFINITE_SURFACE_QUEUE:
            gmsh.model.mesh.setTransfiniteSurface(*t)

        for e in self._TRANSFINITE_VOLUME_QUEUE:
            gmsh.model.mesh.setTransfiniteVolume(*e)

        for item, size in self._SIZE_QUEUE:
            gmsh.model.mesh.setSize(
                gmsh.model.getBoundary(item.dim_tags, False, False, True), size
            )

        for entities, label in self._PHYSICAL_QUEUE:
            tag = gmsh.model.addPhysicalGroup(dim, [e._ID for e in entities])
            if label is not None:
                gmsh.model.setPhysicalName(dim, tag, label)

        if order is not None:
            gmsh.model.mesh.setOrder(order)

        # set algorithm
        # http://gmsh.info/doc/texinfo/gmsh.html#index-Mesh_002eAlgorithm
        if algorithm:
            gmsh.option.setNumber("Mesh.Algorithm", algorithm)

        gmsh.model.mesh.generate(dim)

        # extract point coords
        idx, points, _ = gmsh.model.mesh.getNodes()
        points = points.reshape(-1, 3)
        idx -= 1
        srt = numpy.argsort(idx)
        assert numpy.all(idx[srt] == numpy.arange(len(idx)))
        points = points[srt]

        # extract cells
        elem_types, elem_tags, node_tags = gmsh.model.mesh.getElements()
        cells = []
        for elem_type, node_tags in zip(elem_types, node_tags):
            # `elementName', `dim', `order', `numNodes', `localNodeCoord',
            # `numPrimaryNodes'
            num_nodes_per_cell = gmsh.model.mesh.getElementProperties(elem_type)[3]
            meshio.gmsh.gmsh_to_meshio_type
            cells.append(
                meshio.CellBlock(
                    meshio.gmsh.gmsh_to_meshio_type[elem_type],
                    node_tags.reshape(-1, num_nodes_per_cell) - 1,
                )
            )

        cell_sets = {}
        for dim, tag in gmsh.model.getPhysicalGroups():
            name = gmsh.model.getPhysicalName(dim, tag)
            cell_sets[name] = [[] for _ in range(len(cells))]
            for e in gmsh.model.getEntitiesForPhysicalGroup(dim, tag):
                # TODO node_tags?
                # elem_types, elem_tags, node_tags
                elem_types, elem_tags, _ = gmsh.model.mesh.getElements(dim, e)
                assert len(elem_types) == len(elem_tags)
                assert len(elem_types) == 1
                elem_type = elem_types[0]
                elem_tags = elem_tags[0]

                meshio_cell_type = meshio.gmsh.gmsh_to_meshio_type[elem_type]
                # make sure that the cell type appears only once in the cell list
                # -- for now
                idx = []
                for k, cell_block in enumerate(cells):
                    if cell_block.type == meshio_cell_type:
                        idx.append(k)
                assert len(idx) == 1
                idx = idx[0]
                cell_sets[name][idx].append(elem_tags - 1)

            cell_sets[name] = [
                (None if len(idcs) == 0 else numpy.concatenate(idcs))
                for idcs in cell_sets[name]
            ]

        # make meshio mesh
        return meshio.Mesh(points, cells, cell_sets=cell_sets)
Ejemplo n.º 15
0
    def _export_2d(
        self, gs: Iterable[pp.Grid]
    ) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
        """
        Export the geometrical data (point coordinates) and connectivity
        information from the 2d PorePy grids to meshio.
        """

        # use standard name for simple object type
        polygon_map = {"polygon3": "triangle", "polygon4": "quad"}

        # cell->nodes connectivity information
        cell_to_nodes: Dict[str, np.ndarray] = {}
        # cell id map
        cell_id: Dict[str, List[int]] = {}

        # points
        num_pts = np.sum([g.num_nodes for g in gs])
        meshio_pts = np.empty((num_pts, 3))  # type: ignore
        pts_pos = 0
        cell_pos = 0

        # loop on all the 2d grids
        for g in gs:
            # save the points information
            sl = slice(pts_pos, pts_pos + g.num_nodes)
            meshio_pts[sl, :] = g.nodes.T

            # Cell-face and face-node relations
            g_faces_cells, g_cells, _ = sps.find(g.cell_faces)
            # Ensure ordering of the cells
            g_faces_cells = g_faces_cells[np.argsort(g_cells)]
            g_nodes_faces, _, _ = sps.find(g.face_nodes)

            # loop on all the grid cells
            for c in np.arange(g.num_cells):
                loc = slice(g.cell_faces.indptr[c], g.cell_faces.indptr[c + 1])
                # get the nodes for the current cell
                nodes = np.array(
                    [
                        g_nodes_faces[
                            g.face_nodes.indptr[f] : g.face_nodes.indptr[f + 1]
                        ]
                        for f in g_faces_cells[loc]
                    ]
                ).T
                # sort the nodes
                nodes_loc, *_ = pp.utils.sort_points.sort_point_pairs(nodes)

                # define the type of cell we are currently saving
                cell_type = "polygon" + str(nodes_loc.shape[1])
                cell_type = polygon_map.get(cell_type, cell_type)

                # if the cell type is not present, then add it
                if cell_type not in cell_to_nodes:
                    cell_to_nodes[cell_type] = np.atleast_2d(nodes_loc[0] + pts_pos)
                    cell_id[cell_type] = [cell_pos]
                else:
                    cell_to_nodes[cell_type] = np.vstack(
                        (cell_to_nodes[cell_type], nodes_loc[0] + pts_pos)
                    )
                    cell_id[cell_type] += [cell_pos]
                cell_pos += 1

            pts_pos += g.num_nodes

        # construct the meshio data structure
        num_block = len(cell_to_nodes)
        meshio_cells = np.empty(num_block, dtype=object)
        meshio_cell_id = np.empty(num_block, dtype=object)

        for block, (cell_type, cell_block) in enumerate(cell_to_nodes.items()):
            meshio_cells[block] = meshio.CellBlock(cell_type, cell_block.astype(int))
            meshio_cell_id[block] = np.array(cell_id[cell_type])

        return meshio_pts, meshio_cells, meshio_cell_id
Ejemplo n.º 16
0
    def _export_3d(
        self, gs: Iterable[pp.Grid]
    ) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
        """
        Export the geometrical data (point coordinates) and connectivity
        information from the 3d PorePy grids to meshio.
        """

        # use standard name for simple object type
        # NOTE: this part is not developed
        # polygon_map  = {"polyhedron4": "tetra", "polyhedron8": "hexahedron"}

        # cell-faces and cell nodes connectivity information
        cell_to_faces: Dict[str, List[List[int]]] = {}
        cell_to_nodes: Dict[str, np.ndarray] = {}
        # cell id map
        cell_id: Dict[str, List[int]] = {}

        # points
        num_pts = np.sum([g.num_nodes for g in gs])
        meshio_pts = np.empty((num_pts, 3))  # type: ignore
        pts_pos = 0
        cell_pos = 0

        # loop on all the 3d grids
        for g in gs:
            # save the points information
            sl = slice(pts_pos, pts_pos + g.num_nodes)
            meshio_pts[sl, :] = g.nodes.T

            # Cell-face and face-node relations
            g_faces_cells, g_cells, _ = sps.find(g.cell_faces)
            # Ensure ordering of the cells
            g_faces_cells = g_faces_cells[np.argsort(g_cells)]

            g_nodes_faces, _, _ = sps.find(g.face_nodes)

            cptr = g.cell_faces.indptr
            fptr = g.face_nodes.indptr
            face_per_cell = np.diff(cptr)
            nodes_per_face = np.diff(fptr)

            # Total number of nodes to be written in the face-node relation
            num_cell_nodes = np.array([nodes_per_face[i] for i in g.cell_faces.indices])

            n = g.nodes
            fc = g.face_centers
            normal_vec = g.face_normals / g.face_areas

            # Use numba if available, unless the problem is very small, in which
            # case the pure python version probably is faster than combined compile
            # and runtime for numba
            # The number 1000 here is somewhat random.
            if self.has_numba and g.num_cells > 1000:
                logger.info("Construct 3d grid information using numba")
                cell_nodes = self._point_ind_numba(
                    cptr,
                    fptr,
                    g_faces_cells,
                    g_nodes_faces,
                    n,
                    fc,
                    normal_vec,
                    num_cell_nodes,
                )
            else:
                logger.info("Construct 3d grid information using pure python")
                cell_nodes = self._point_ind(
                    cptr,
                    fptr,
                    g_faces_cells,
                    g_nodes_faces,
                    n,
                    fc,
                    normal_vec,
                    num_cell_nodes,
                )

            # implementation note: I did not even try feeding this to numba, my
            # guess is that it will not like the vtk specific stuff.
            nc = 0
            f_counter = 0

            # loop on all the grid cells
            for c in np.arange(g.num_cells):
                faces_loc: List[int] = []
                # loop on all the cell faces
                for _ in np.arange(face_per_cell[c]):
                    fi = g.cell_faces.indices[f_counter]
                    faces_loc += [cell_nodes[nc : (nc + nodes_per_face[fi])]]
                    nc += nodes_per_face[fi]
                    f_counter += 1

                # collect all the nodes for the cell
                nodes_loc = np.unique(faces_loc).astype(int)

                # define the type of cell we are currently saving
                cell_type = "polyhedron" + str(nodes_loc.size)
                # cell_type = polygon_map.get(cell_type, cell_type)

                # if the cell type is not present, then add it
                if cell_type not in cell_to_nodes:
                    cell_to_nodes[cell_type] = np.atleast_2d(nodes_loc + pts_pos)
                    cell_to_faces[cell_type] = [faces_loc]
                    cell_id[cell_type] = [cell_pos]
                else:
                    cell_to_nodes[cell_type] = np.vstack(
                        (cell_to_nodes[cell_type], nodes_loc + pts_pos)
                    )
                    cell_to_faces[cell_type] += [faces_loc]
                    cell_id[cell_type] += [cell_pos]
                cell_pos += 1

            pts_pos += g.num_nodes

        # NOTE: only cell->faces relation will be kept, so far we export only polyhedron
        # otherwise in the next lines we should consider also the cell->nodes map

        # construct the meshio data structure
        num_block = len(cell_to_nodes)
        meshio_cells = np.empty(num_block, dtype=object)
        meshio_cell_id = np.empty(num_block, dtype=object)

        for block, (cell_type, cell_block) in enumerate(cell_to_faces.items()):
            meshio_cells[block] = meshio.CellBlock(cell_type, cell_block)
            meshio_cell_id[block] = np.array(cell_id[cell_type])

        return meshio_pts, meshio_cells, meshio_cell_id
Ejemplo n.º 17
0
    def generate_mesh(  # noqa: C901
        self,
        dim=3,
        order=None,
        prune_vertices=True,
        prune_z_0=False,
        remove_lower_dim_cells=False,
        # http://gmsh.info/doc/texinfo/gmsh.html#index-Mesh_002eAlgorithm
        algorithm=None,
    ):
        """Return a meshio.Mesh, storing the mesh points, cells, and data, generated by
        Gmsh from the `self`.
        """
        self.synchronize()

        for item in self._AFTER_SYNC_QUEUE:
            item.exec()

        for item, host in self._EMBED_QUEUE:
            gmsh.model.mesh.embed(item.dim, [item._ID], host.dim, host._ID)

        # set compound entities after sync
        for c in self._COMPOUND_ENTITIES:
            gmsh.model.mesh.setCompound(*c)

        for s in self._RECOMBINE_ENTITIES:
            gmsh.model.mesh.setRecombine(*s)

        for t in self._TRANSFINITE_CURVE_QUEUE:
            gmsh.model.mesh.setTransfiniteCurve(*t)

        for t in self._TRANSFINITE_SURFACE_QUEUE:
            gmsh.model.mesh.setTransfiniteSurface(*t)

        for e in self._TRANSFINITE_VOLUME_QUEUE:
            gmsh.model.mesh.setTransfiniteVolume(*e)

        for item, size in self._SIZE_QUEUE:
            gmsh.model.mesh.setSize(
                gmsh.model.getBoundary(item.dim_tags, False, False, True),
                size)

        if order is not None:
            gmsh.model.mesh.setOrder(order)

        # set algorithm
        # http://gmsh.info/doc/texinfo/gmsh.html#index-Mesh_002eAlgorithm
        if algorithm:
            gmsh.option.setNumber("Mesh.Algorithm", algorithm)

        gmsh.model.mesh.generate(dim)

        # extract point coords
        idx, points, _ = gmsh.model.mesh.getNodes()
        points = points.reshape(-1, 3)
        idx -= 1
        srt = numpy.argsort(idx)
        assert numpy.all(idx[srt] == numpy.arange(len(idx)))
        points = points[srt]
        if prune_z_0 and numpy.all(numpy.abs(points[:, 2]) < 1.0e-13):
            points = points[:, :2]

        # extract cells
        elem_types, elem_tags, node_tags = gmsh.model.mesh.getElements()
        cells = []
        for elem_type, node_tags in zip(elem_types, node_tags):
            # `elementName', `dim', `order', `numNodes', `localNodeCoord',
            # `numPrimaryNodes'
            num_nodes_per_cell = gmsh.model.mesh.getElementProperties(
                elem_type)[3]
            meshio.gmsh.gmsh_to_meshio_type
            cells.append(
                meshio.CellBlock(
                    meshio.gmsh.gmsh_to_meshio_type[elem_type],
                    node_tags.reshape(-1, num_nodes_per_cell) - 1,
                ))

        # print("a", gmsh.model.getEntities())
        # grps = gmsh.model.getPhysicalGroups()
        # print("a", grps)
        # for dim, tag in grps:
        #     print("a", gmsh.model.getPhysicalName(dim, tag))
        #     ent = gmsh.model.getEntitiesForPhysicalGroup(dim, tag)
        #     print("a", ent)
        #     assert len(ent) == 1
        #     print("a", gmsh.model.mesh.getElements(dim, ent[0]))

        # make meshio mesh
        mesh = meshio.Mesh(points, cells)

        if remove_lower_dim_cells:
            # Only keep the cells of highest topological dimension; discard faces and
            # such.
            cells_2d = {"triangle", "quad"}
            cells_3d = {
                "tetra",
                "hexahedron",
                "wedge",
                "pyramid",
                "penta_prism",
                "hexa_prism",
            }
            if any(c.type in cells_3d for c in mesh.cells):
                keep_types = cells_3d
            elif any(c.type in cells_2d for c in mesh.cells):
                keep_types = cells_2d
            else:
                keep_types = set(cell_type for cell_type, _ in mesh.cells)

            for name, val in mesh.cell_data.items():
                mesh.cell_data[name] = [
                    d for d, c in zip(val, mesh.cells) if c[0] in keep_types
                ]
            mesh.cells = [c for c in mesh.cells if c[0] in keep_types]

        if prune_vertices:
            # Make sure to include only those vertices which belong to a cell.
            ncells = numpy.concatenate(
                [numpy.concatenate(c) for _, c in mesh.cells])
            uvertices, uidx = numpy.unique(ncells, return_inverse=True)

            k = 0
            cells = []
            for key, cellblock in mesh.cells:
                n = numpy.prod(cellblock.shape)
                cells.append(
                    meshio.CellBlock(key,
                                     uidx[k:k + n].reshape(cellblock.shape)))
                k += n
            mesh.cells = cells

            mesh.points = mesh.points[uvertices]
            for key in mesh.point_data:
                mesh.point_data[key] = mesh.point_data[key][uvertices]

        return mesh