def xtest_read_write_p2_mesh(tempdir, encoding): pygmsh = pytest.importorskip("pygmsh") if MPI.COMM_WORLD.rank == 0: geom = pygmsh.opencascade.Geometry() geom.add_ball([0.0, 0.0, 0.0], 1.0, char_length=0.4) pygmsh_mesh = pygmsh.generate_mesh( geom, mesh_file_type="vtk", extra_gmsh_arguments=["-order", "2"]) cells, x = pygmsh_mesh.cells[-1].data, pygmsh_mesh.points pygmsh_cell = pygmsh_mesh.cells[-1].type cell_type, gdim, num_nodes = MPI.COMM_WORLD.bcast( [pygmsh_cell, x.shape[1], cells.shape[1]], root=0) else: cell_type, gdim, num_nodes = MPI.COMM_WORLD.bcast([None, None, None], root=0) cells, x = np.empty([0, num_nodes]), np.empty([0, gdim]) domain = ufl_mesh_from_gmsh(cell_type, gdim) cell_type = cpp.mesh.to_type(str(domain.ufl_cell())) cells = cells[:, perm_vtk(cell_type, cells.shape[1])] mesh = create_mesh(MPI.COMM_WORLD, cells, x, domain) filename = os.path.join(tempdir, "tet10_mesh.xdmf") with XDMFFile(mesh.mpi_comm(), filename, "w", encoding=encoding) as xdmf: xdmf.write_mesh(mesh) with XDMFFile(mesh.mpi_comm(), filename, "r", encoding=encoding) as xdmf: mesh2 = xdmf.read_mesh() assert mesh.topology.index_map(0).size_global == mesh2.topology.index_map( 0).size_global dim = mesh.topology.dim assert mesh.topology.index_map( dim).size_global == mesh2.topology.index_map(dim).size_global
def test_gmsh_input_3d(order, cell_type): try: import gmsh except ImportError: pytest.skip() if cell_type == CellType.hexahedron and order > 2: pytest.xfail("GMSH permutation for order > 2 hexahedra not implemented in DOLFINx.") res = 0.2 gmsh.initialize() if cell_type == CellType.hexahedron: gmsh.option.setNumber("Mesh.RecombinationAlgorithm", 2) gmsh.option.setNumber("Mesh.RecombineAll", 2) gmsh.option.setNumber("Mesh.CharacteristicLengthMin", res) gmsh.option.setNumber("Mesh.CharacteristicLengthMax", res) circle = gmsh.model.occ.addDisk(0, 0, 0, 1, 1) if cell_type == CellType.hexahedron: gmsh.model.occ.extrude([(2, circle)], 0, 0, 1, numElements=[5], recombine=True) else: gmsh.model.occ.extrude([(2, circle)], 0, 0, 1, numElements=[5]) gmsh.model.occ.synchronize() gmsh.model.mesh.generate(3) gmsh.model.mesh.setOrder(order) idx, points, _ = gmsh.model.mesh.getNodes() points = points.reshape(-1, 3) idx -= 1 srt = np.argsort(idx) assert np.all(idx[srt] == np.arange(len(idx))) x = points[srt] element_types, element_tags, node_tags = gmsh.model.mesh.getElements(dim=3) name, dim, order, num_nodes, local_coords, num_first_order_nodes = gmsh.model.mesh.getElementProperties( element_types[0]) cells = node_tags[0].reshape(-1, num_nodes) - 1 if cell_type == CellType.tetrahedron: gmsh_cell_id = MPI.COMM_WORLD.bcast(gmsh.model.mesh.getElementType("tetrahedron", order), root=0) elif cell_type == CellType.hexahedron: gmsh_cell_id = MPI.COMM_WORLD.bcast(gmsh.model.mesh.getElementType("hexahedron", order), root=0) gmsh.finalize() # Permute the mesh topology from GMSH ordering to DOLFINx ordering domain = ufl_mesh_from_gmsh(gmsh_cell_id, 3) cells = cells[:, perm_gmsh(cell_type, cells.shape[1])] mesh = create_mesh(MPI.COMM_WORLD, cells, x, domain) volume = assemble_scalar(form(1 * dx(mesh))) assert mesh.comm.allreduce(volume, op=MPI.SUM) == pytest.approx(np.pi, rel=10 ** (-1 - order))
def test_read_write_p2_mesh(tempdir, encoding): try: import gmsh except ImportError: pytest.skip() if MPI.COMM_WORLD.rank == 0: gmsh.initialize() gmsh.model.occ.addSphere(0, 0, 0, 1, tag=1) gmsh.option.setNumber("Mesh.CharacteristicLengthMin", 0.3) gmsh.option.setNumber("Mesh.CharacteristicLengthMax", 0.4) gmsh.model.occ.synchronize() gmsh.model.mesh.generate(3) gmsh.model.mesh.setOrder(2) idx, points, _ = gmsh.model.mesh.getNodes() points = points.reshape(-1, 3) idx -= 1 srt = np.argsort(idx) assert np.all(idx[srt] == np.arange(len(idx))) x = points[srt] element_types, element_tags, node_tags = gmsh.model.mesh.getElements( dim=3) name, dim, order, num_nodes, local_coords, num_first_order_nodes = gmsh.model.mesh.getElementProperties( element_types[0]) cells = node_tags[0].reshape(-1, num_nodes) - 1 num_nodes, gmsh_cell_id = MPI.COMM_WORLD.bcast( [cells.shape[1], gmsh.model.mesh.getElementType("tetrahedron", 2)], root=0) gmsh.finalize() else: num_nodes, gmsh_cell_id = MPI.COMM_WORLD.bcast([None, None], root=0) cells, x = np.empty([0, num_nodes]), np.empty([0, 3]) domain = ufl_mesh_from_gmsh(gmsh_cell_id, 3) cell_type = _cpp.mesh.to_type(str(domain.ufl_cell())) cells = cells[:, perm_gmsh(cell_type, cells.shape[1])] mesh = create_mesh(MPI.COMM_WORLD, cells, x, domain) filename = os.path.join(tempdir, "tet10_mesh.xdmf") with XDMFFile(mesh.comm, filename, "w", encoding=encoding) as xdmf: xdmf.write_mesh(mesh) with XDMFFile(mesh.comm, filename, "r", encoding=encoding) as xdmf: mesh2 = xdmf.read_mesh() assert mesh.topology.index_map(0).size_global == mesh2.topology.index_map( 0).size_global assert mesh.topology.index_map( mesh.topology.dim).size_global == mesh2.topology.index_map( mesh.topology.dim).size_global
def test_gmsh_input_2d(order, cell_type): try: import gmsh except ImportError: pytest.skip() res = 0.2 gmsh.initialize() gmsh.option.setNumber("Mesh.CharacteristicLengthMin", res) gmsh.option.setNumber("Mesh.CharacteristicLengthMax", res) if cell_type == CellType.quadrilateral: gmsh.option.setNumber("Mesh.Algorithm", 2 if order == 2 else 5) gmsh.model.occ.addSphere(0, 0, 0, 1, tag=1) gmsh.model.occ.synchronize() gmsh.model.mesh.generate(2) if cell_type == CellType.quadrilateral: gmsh.model.mesh.recombine() gmsh.model.mesh.setOrder(order) idx, points, _ = gmsh.model.mesh.getNodes() points = points.reshape(-1, 3) idx -= 1 srt = np.argsort(idx) assert np.all(idx[srt] == np.arange(len(idx))) x = points[srt] element_types, element_tags, node_tags = gmsh.model.mesh.getElements(dim=2) name, dim, order, num_nodes, local_coords, num_first_order_nodes = gmsh.model.mesh.getElementProperties( element_types[0]) cells = node_tags[0].reshape(-1, num_nodes) - 1 if cell_type == CellType.triangle: gmsh_cell_id = gmsh.model.mesh.getElementType("triangle", order) elif cell_type == CellType.quadrilateral: gmsh_cell_id = gmsh.model.mesh.getElementType("quadrangle", order) gmsh.finalize() cells = cells[:, perm_gmsh(cell_type, cells.shape[1])] mesh = create_mesh(MPI.COMM_WORLD, cells, x, ufl_mesh_from_gmsh(gmsh_cell_id, x.shape[1])) surface = assemble_scalar(1 * dx(mesh)) assert mesh.mpi_comm().allreduce(surface, op=MPI.SUM) == pytest.approx( 4 * np.pi, rel=10**(-1 - order))
def test_gmsh_input_quad(order): pygmsh = pytest.importorskip("pygmsh") # Parameterize test if gmsh gets wider support R = 1 res = 0.2 if order == 2 else 0.2 algorithm = 2 if order == 2 else 5 geo = pygmsh.opencascade.Geometry() geo.add_raw_code("Mesh.ElementOrder={0:d};".format(order)) geo.add_ball([0, 0, 0], R, char_length=res) geo.add_raw_code("Recombine Surface {1};") geo.add_raw_code("Mesh.Algorithm = {0:d};".format(algorithm)) msh = pygmsh.generate_mesh(geo, verbose=True, dim=2) gmsh_quad = perm_gmsh(cpp.mesh.CellType.quadrilateral, (order + 1)**2) cells = msh.cells[-1].data[:, gmsh_quad] mesh = create_mesh(MPI.COMM_WORLD, cells, msh.points, ufl_mesh_from_gmsh(msh.cells[-1].type, msh.points.shape[1])) surface = assemble_scalar(1 * dx(mesh)) assert mesh.mpi_comm().allreduce(surface, op=MPI.SUM) == pytest.approx(4 * np.pi * R * R, rel=1e-5)
def test_gmsh_input_quad(order): gmsh = pytest.importorskip("gmsh") R = 1 res = 0.2 algorithm = 2 if order == 2 else 5 gmsh.initialize() gmsh.option.setNumber("Mesh.CharacteristicLengthMin", res) gmsh.option.setNumber("Mesh.CharacteristicLengthMax", res) gmsh.option.setNumber("Mesh.Algorithm", algorithm) gmsh.model.occ.addSphere(0, 0, 0, 1, tag=1) gmsh.model.occ.synchronize() gmsh.model.mesh.generate(2) gmsh.model.mesh.recombine() gmsh.model.mesh.setOrder(order) idx, points, _ = gmsh.model.mesh.getNodes() points = points.reshape(-1, 3) idx -= 1 srt = np.argsort(idx) assert np.all(idx[srt] == np.arange(len(idx))) x = points[srt] element_types, element_tags, node_tags = gmsh.model.mesh.getElements(dim=2) name, dim, order, num_nodes, local_coords, num_first_order_nodes = gmsh.model.mesh.getElementProperties( element_types[0]) cells = node_tags[0].reshape(-1, num_nodes) - 1 gmsh_cell_id = gmsh.model.mesh.getElementType("quadrangle", order) gmsh.finalize() gmsh_quad = perm_gmsh(cpp.mesh.CellType.quadrilateral, (order + 1)**2) cells = cells[:, gmsh_quad] mesh = create_mesh(MPI.COMM_WORLD, cells, x, ufl_mesh_from_gmsh(gmsh_cell_id, x.shape[1])) surface = assemble_scalar(1 * dx(mesh)) assert mesh.mpi_comm().allreduce(surface, op=MPI.SUM) == pytest.approx( 4 * np.pi * R * R, rel=1e-5)
# Generate mesh model.occ.synchronize() model.mesh.generate(3) # Sort mesh nodes according to their index in gmsh (Starts at 1) x = extract_gmsh_geometry(model, model_name="Sphere") # Extract cells from gmsh (Only interested in tetrahedrons) element_types, element_tags, node_tags = model.mesh.getElements(dim=3) assert len(element_types) == 1 name, dim, order, num_nodes, local_coords, num_first_order_nodes = model.mesh.getElementProperties( element_types[0]) cells = node_tags[0].reshape(-1, num_nodes) - 1 mesh = create_mesh(MPI.COMM_SELF, cells, x, ufl_mesh_from_gmsh(element_types[0], x.shape[1])) with XDMFFile(MPI.COMM_SELF, "mesh_rank_{}.xdmf".format(MPI.COMM_WORLD.rank), "w") as file: file.write_mesh(mesh) # Create a distributed (parallel) mesh with affine geometry. # Generate mesh on rank 0, then build a distributed mesh :: if MPI.COMM_WORLD.rank == 0: # Generate a mesh model.add("Sphere minus box") model.setCurrent("Sphere minus box") sphere_dim_tags = model.occ.addSphere(0, 0, 0, 1)
def gmsh_model_to_mesh(model, cell_data=False, facet_data=False, gdim=None, exportMesh=False, fileName="mesh.msh"): """ Given a GMSH model, create a DOLFIN-X mesh and MeshTags. Can theoretically export to msh file model: The GMSH model cell_data: Boolean, True of a mesh tag for cell data should be returned (Default: False) facet_data: Boolean, True if a mesh tag for facet data should be returned (Default: False) gdim: Geometrical dimension of problem (Default: 3) """ if gdim is None: gdim = 3 if MPI.COMM_WORLD.rank == 0: # Get mesh geometry x = extract_gmsh_geometry(model) # Get mesh topology for each element topologies = extract_gmsh_topology_and_markers(model) # Get information about each cell type from the msh files num_cell_types = len(topologies.keys()) cell_information = {} cell_dimensions = numpy.zeros(num_cell_types, dtype=numpy.int32) for i, element in enumerate(topologies.keys()): properties = model.mesh.getElementProperties(element) name, dim, order, num_nodes, local_coords, _ = properties cell_information[i] = { "id": element, "dim": dim, "num_nodes": num_nodes } cell_dimensions[i] = dim # Sort elements by ascending dimension perm_sort = numpy.argsort(cell_dimensions) # Broadcast cell type data and geometric dimension cell_id = cell_information[perm_sort[-1]]["id"] tdim = cell_information[perm_sort[-1]]["dim"] num_nodes = cell_information[perm_sort[-1]]["num_nodes"] cell_id, num_nodes = MPI.COMM_WORLD.bcast([cell_id, num_nodes], root=0) # Check for facet data and broadcast if found if facet_data: if tdim - 1 in cell_dimensions: num_facet_nodes = MPI.COMM_WORLD.bcast( cell_information[perm_sort[-2]]["num_nodes"], root=0) gmsh_facet_id = cell_information[perm_sort[-2]]["id"] marked_facets = numpy.asarray( topologies[gmsh_facet_id]["topology"], dtype=numpy.int64) facet_values = numpy.asarray( topologies[gmsh_facet_id]["cell_data"], dtype=numpy.int32) else: raise ValueError("No facet data found in file.") cells = numpy.asarray(topologies[cell_id]["topology"], dtype=numpy.int64) cell_values = numpy.asarray(topologies[cell_id]["cell_data"], dtype=numpy.int32) else: cell_id, num_nodes = MPI.COMM_WORLD.bcast([None, None], root=0) cells, x = numpy.empty([0, num_nodes], dtype=numpy.int32), numpy.empty([0, gdim]) cell_values = numpy.empty((0, ), dtype=numpy.int32) if facet_data: num_facet_nodes = MPI.COMM_WORLD.bcast(None, root=0) marked_facets = numpy.empty((0, num_facet_nodes), dtype=numpy.int32) facet_values = numpy.empty((0, ), dtype=numpy.int32) # Create distributed mesh ufl_domain = ufl_mesh_from_gmsh(cell_id, gdim) gmsh_cell_perm = perm_gmsh(to_type(str(ufl_domain.ufl_cell())), num_nodes) cells = cells[:, gmsh_cell_perm] mesh = create_mesh(MPI.COMM_WORLD, cells, x[:, :gdim], ufl_domain) # Create MeshTags for cells if cell_data: local_entities, local_values = distribute_entity_data( mesh, mesh.topology.dim, cells, cell_values) mesh.topology.create_connectivity(mesh.topology.dim, 0) adj = AdjacencyList_int32(local_entities) ct = create_meshtags(mesh, mesh.topology.dim, adj, numpy.int32(local_values)) ct.name = "cells" # Create MeshTags for facets if facet_data: # Permute facets from MSH to Dolfin-X ordering # FIXME: This does not work for prism meshes facet_type = cell_entity_type(to_type(str(ufl_domain.ufl_cell())), mesh.topology.dim - 1, 0) gmsh_facet_perm = perm_gmsh(facet_type, num_facet_nodes) marked_facets = marked_facets[:, gmsh_facet_perm] local_entities, local_values = distribute_entity_data( mesh, mesh.topology.dim - 1, marked_facets, facet_values) mesh.topology.create_connectivity(mesh.topology.dim - 1, mesh.topology.dim) adj = AdjacencyList_int32(local_entities) ft = create_meshtags(mesh, mesh.topology.dim - 1, adj, numpy.int32(local_values)) ft.name = "facets" if exportMesh: gmsh.write(fileName) if cell_data and facet_data: return mesh, ct, ft elif cell_data and not facet_data: return mesh, ct elif not cell_data and facet_data: return mesh, ft else: return mesh
# Generate mesh model.occ.synchronize() model.mesh.generate(3) # Sort mesh nodes according to their index in gmsh (Starts at 1) x = extract_gmsh_geometry(model, model_name="Sphere") # Extract cells from gmsh (Only interested in tetrahedrons) element_types, element_tags, node_tags = model.mesh.getElements(dim=3) assert len(element_types) == 1 name, dim, order, num_nodes, local_coords, num_first_order_nodes = model.mesh.getElementProperties(element_types[0]) cells = node_tags[0].reshape(-1, num_nodes) - 1 mesh = create_mesh(MPI.COMM_SELF, cells, x, ufl_mesh_from_gmsh(element_types[0], x.shape[1])) with XDMFFile(MPI.COMM_SELF, "mesh_rank_{}.xdmf".format(MPI.COMM_WORLD.rank), "w") as file: file.write_mesh(mesh) # Create a distributed (parallel) mesh with affine geometry. # Generate mesh on rank 0, then build a distributed mesh :: if MPI.COMM_WORLD.rank == 0: # Generate a mesh model.add("Sphere minus box") model.setCurrent("Sphere minus box") sphere_dim_tags = model.occ.addSphere(0, 0, 0, 1) box_dim_tags = model.occ.addBox(0, 0, 0, 1, 1, 1)
def gmsh_to_dolfin(gmsh_model, tdim: int, comm=MPI.COMM_WORLD, prune_y=False, prune_z=False): """Converts a gmsh model object into `dolfinx.Mesh` and `dolfinx.MeshTags` for physical tags. Parameters ---------- gmsh_model tdim Topological dimension of the mesh comm: optional ghost_mode: optional prune_y: optional Prune y-components. Used to embed a flat geometries into lower dimension. prune_z: optional Prune z-components. Used to embed a flat geometries into lower dimension. Note ---- User must call `geo.synchronize()` and `mesh.generate()` before passing the model into this method. """ rank = comm.rank logger = logging.getLogger("dolfiny") if rank == 0: # Map from internal gmsh cell type number to gmsh cell name # see https://gitlab.onelab.info/gmsh/gmsh/blob/master/Common/GmshDefines.h#L75 gmsh_cellname = { 1: 'line', 2: 'triangle', 3: "quad", 4: 'tetra', 5: "hexahedron", 8: 'line3', 9: 'triangle6', 10: "quad9", 11: 'tetra10', 12: 'hexahedron27', 15: 'vertex', 21: 'triangle10', 26: 'line4', 29: 'tetra20', 36: 'quad16', # 92: 'hexahedron64', } gmsh_dolfin = { "vertex": (CellType.point, 0), "line": (CellType.interval, 1), "line3": (CellType.interval, 2), "line4": (CellType.interval, 3), "triangle": (CellType.triangle, 1), "triangle6": (CellType.triangle, 2), "triangle10": (CellType.triangle, 3), "quad": (CellType.quadrilateral, 1), "quad9": (CellType.quadrilateral, 2), "quad16": (CellType.quadrilateral, 3), "tetra": (CellType.tetrahedron, 1), "tetra10": (CellType.tetrahedron, 2), "tetra20": (CellType.tetrahedron, 3), "hexahedron": (CellType.hexahedron, 1), "hexahedron27": (CellType.hexahedron, 2), # "hexahedron64": (CellType.hexahedron, 3), } # Number of nodes for gmsh cell type nodes = { 'vertex': 1, 'line': 2, 'line3': 3, 'line4': 4, 'triangle': 3, 'triangle6': 6, 'triangle10': 10, 'tetra': 4, 'tetra10': 10, 'tetra20': 20, 'quad': 4, 'quad9': 9, 'quad16': 16, 'hexahedron': 8, 'hexahedron27': 27, # 'hexahedron64': 64, } # node_tags, coord, param_coords = gmsh_model.mesh.getNodes() # FIXME: This silences the RuntimeWarning (ctypes / PEP3118 format string) caused by Gmsh/numpy import warnings with warnings.catch_warnings(): warnings.simplefilter("ignore", RuntimeWarning) node_tags, coord, param_coords = gmsh_model.mesh.getNodes() # Fetch elements for the mesh cell_types, cell_tags, cell_node_tags = gmsh_model.mesh.getElements( dim=tdim) unused_nodes = numpy.setdiff1d(node_tags, cell_node_tags) unused_nodes_indices = [] # FIXME: This would be expensive for many unused nodes case for unused_node in unused_nodes: unused_nodes_indices.append( numpy.where(node_tags == unused_node)[0]) unused_nodes_indices = numpy.asarray(unused_nodes_indices) # Every node has 3 components in gmsh dim = 3 points = numpy.reshape(coord, (-1, dim)) # Delete unreferenced nodes points = numpy.delete(points, unused_nodes_indices, axis=0) node_tags = numpy.delete(node_tags, unused_nodes_indices) # Prepare a map from node tag to index in coords array nmap = numpy.argsort(node_tags - 1) cells = {} if len(cell_types) > 1: raise RuntimeError("Mixed topology meshes not supported.") try: cellname = gmsh_cellname[cell_types[0]] except KeyError: raise RuntimeError( f"Gmsh cell code {cell_types[0]:d} not supported.") try: num_nodes = nodes[cellname] except KeyError: raise RuntimeError( f"Cannot determine number of nodes for Gmsh cell type \"{cellname:s}\"." ) logger.info(f"Processing mesh of gmsh cell name \"{cellname:s}\"") # Shift 1-based numbering and apply node map cells[cellname] = nmap[cell_node_tags[0] - 1] cells[cellname] = numpy.reshape(cells[cellname], (-1, num_nodes)) if prune_z: if not numpy.allclose(points[:, 2], 0.0): raise RuntimeError("Non-zero z-component would be pruned.") points = points[:, :-1] if prune_y: if not numpy.allclose(points[:, 1], 0.0): raise RuntimeError("Non-zero y-component would be pruned.") if prune_z: # In the case we already pruned z-component points = points[:, 0] else: points = points[:, [0, 2]] try: dolfin_cell_type, order = gmsh_dolfin[cellname] except KeyError: raise RuntimeError( f"Cannot determine dolfin cell type for Gmsh cell type \"{cellname:s}\"." ) perm = cpp.io.perm_gmsh(dolfin_cell_type, num_nodes) logger.info(f"Mesh will be permuted with {perm}") cells = cells[cellname][:, perm] logger.info( f"Constructing mesh for tdim: {tdim:d}, gdim: {points.shape[1]:d}") logger.info(f"Number of elements: {cells.shape[0]:d}") cells_shape, pts_shape, cellname = comm.bcast( [cells.shape, points.shape, cellname], root=0) else: cells_shape, pts_shape, cellname = comm.bcast([None, None, None], root=0) cells = numpy.empty((0, cells_shape[1])) points = numpy.empty((0, pts_shape[1])) mesh = create_mesh(comm, cells, points, ufl_mesh_from_gmsh(cellname, pts_shape[1])) mts = {} # Get physical groups (dimension, tag) pgdim_pgtags = comm.bcast( gmsh_model.getPhysicalGroups() if rank == 0 else None, root=0) for pgdim, pgtag in pgdim_pgtags: # For the current physical tag there could be multiple entities # e.g. user tagged bottom and up boundary part with one physical tag entity_tags = comm.bcast(gmsh_model.getEntitiesForPhysicalGroup( pgdim, pgtag) if rank == 0 else None, root=0) pg_tag_name = comm.bcast( gmsh_model.getPhysicalName(pgdim, pgtag) if rank == 0 else None, root=0) if pg_tag_name == "": pg_tag_name = f"tag_{pgtag:d}" if rank == 0: _mt_cells = [] _mt_values = [] for i, entity_tag in enumerate(entity_tags): pgcell_types, pgcell_tags, pgnode_tags = gmsh_model.mesh.getElements( pgdim, entity_tag) assert (len(pgcell_types) == 1) pgcellname = gmsh_cellname[pgcell_types[0]] pgnum_nodes = nodes[pgcellname] # Shift 1-based numbering and apply node map pgnode_tags[0] = nmap[pgnode_tags[0] - 1] _mt_cells.append(pgnode_tags[0].reshape(-1, pgnum_nodes)) _mt_values.append( numpy.full(_mt_cells[-1].shape[0], pgtag, dtype=numpy.int32)) # Stack all topology and value data. This prepares data # for one MVC per (dim, physical tag) instead of multiple MVCs _mt_values = numpy.hstack(_mt_values) _mt_cells = numpy.vstack(_mt_cells) # Fetch the permutation needed for physical group pgdolfin_cell_type, pgorder = gmsh_dolfin[pgcellname] pgpermutation = cpp.io.perm_gmsh(pgdolfin_cell_type, pgnum_nodes) _mt_cells[:, :] = _mt_cells[:, pgpermutation] logger.info(f"Constructing MVC for tdim: {pgdim:d}") logger.info(f"Number of data values: {_mt_values.shape[0]:d}") mt_cells_shape, pgdim = comm.bcast([_mt_cells.shape, pgdim], root=0) else: mt_cells_shape, pgdim = comm.bcast([None, None], root=0) _mt_cells = numpy.empty((0, mt_cells_shape[1])) _mt_values = numpy.empty((0, )) local_entities, local_values = extract_local_entities( mesh, pgdim, _mt_cells, _mt_values) mesh.topology.create_connectivity(pgdim, 0) mt = create_meshtags(mesh, pgdim, cpp.graph.AdjacencyList_int32(local_entities), numpy.int32(local_values)) mt.name = pg_tag_name mts[pg_tag_name] = mt return mesh, mts
def build_piston(n, length, radius, write_file=False, fname=""): """ Build a hex cylinder mesh using gmsh """ gmsh.initialize() gmsh.option.setNumber("General.Terminal", 0) model = gmsh.model() if MPI.COMM_WORLD.rank == 0: model.add("Piston") model.setCurrent("Piston") h = length / n gmsh.option.setNumber("Mesh.RecombineAll", 2) gmsh.option.setNumber("Mesh.RecombinationAlgorithm", 2) gmsh.option.setNumber("Mesh.CharacteristicLengthMin", 0.98 * h) gmsh.option.setNumber("Mesh.CharacteristicLengthMax", 1.02 * h) circle = model.occ.addDisk(0, 0, 0, radius, radius) model.occ.rotate([(2, circle)], 0., 0., 0., 0., 1., 0., np.pi / 2) model.occ.extrude([(2, circle)], length, 0, 0, numElements=[n], recombine=True) model.occ.synchronize() model.mesh.generate(3) # sort mesh according to their index in gmsh x = extract_gmsh_geometry(model, model.getCurrent()) # extract cells from gmsh element_types, element_tags, node_tags = model.mesh.getElements(dim=3) name, dim, order, num_nodes, local_coords, num_first_order_nodes = \ model.mesh.getElementProperties(element_types[0]) # broadcast cell type data and geometric dimension gmsh_cell_id = MPI.COMM_WORLD.bcast(element_types[0], root=0) # get mesh data for dim (0, tdim) cells = node_tags[0].reshape(-1, num_nodes) - 1 num_nodes = MPI.COMM_WORLD.bcast(cells.shape[1], root=0) gmsh.finalize() else: gmsh_cell_id = MPI.COMM_WORLD.bcast(None, root=0) num_nodes = MPI.COMM_WORLD.bcast(None, root=0) cells, x = np.empty([0, num_nodes]), np.empty([0, 3]) # permute the mesh topology from GMSH ordering to DOLFIN-X ordering domain = ufl_mesh_from_gmsh(gmsh_cell_id, 3) gmsh_hex = perm_gmsh(cpp.mesh.CellType.hexahedron, 8) cells = cells[:, gmsh_hex] mesh = create_mesh(MPI.COMM_WORLD, cells, x, domain) mesh.name = "piston_hex" if write_file: with XDMFFile(MPI.COMM_WORLD, "{}.xdmf".format(fname), "w") as file: file.write_mesh(mesh) return mesh
cells = topologies[gmsh_cell_id]["topology"] cell_data = topologies[gmsh_cell_id]["cell_data"] num_nodes = MPI.COMM_WORLD.bcast(cells.shape[1], root=0) gmsh_facet_id = gmsh.model.mesh.getElementType("line", 2) marked_facets = topologies[gmsh_facet_id]["topology"].astype(np.int64) facet_values = topologies[gmsh_facet_id]["cell_data"].astype(np.int32) else: # Create dolfinx mesh on other processes gmsh_cell_id = MPI.COMM_WORLD.bcast(None, root=0) num_nodes = MPI.COMM_WORLD.bcast(None, root=0) cells, x = np.empty([0, num_nodes]), np.empty([0, 3]) marked_facets = np.empty((0, 3), dtype=np.int64) facet_values = np.empty((0,), dtype=np.int32) # Permute the topology from GMSH to DOLFINx ordering domain = ufl_mesh_from_gmsh(gmsh_cell_id, 2) gmsh_tri6 = perm_gmsh(cpp.mesh.CellType.triangle, cells.shape[1]) cells = cells[:, gmsh_tri6] mesh = create_mesh(MPI.COMM_WORLD, cells, x[:, :2], domain) # Permute also entities which are tagged gmsh_line3 = perm_gmsh(cpp.mesh.CellType.interval, 3) marked_facets = marked_facets[:, gmsh_line3] local_entities, local_values = extract_local_entities( mesh, 1, marked_facets, facet_values) mesh.topology.create_connectivity(1, 0) mt = create_meshtags(mesh, 1, cpp.graph.AdjacencyList_int32(local_entities), np.int32(local_values))
def gmsh_model_to_mesh(model, gdim): """ Given a GMSH model, create a DOLFINx mesh and MeshTags. Parameters ---------- model : gmsh.model The GMSH model. gdim: int Geometrical dimension of problem. Author ---------- J. S. Dokken, http://jsdokken.com/converted_files/tutorial_gmsh.html """ assert MPI.COMM_WORLD.size == 1, "This function has been simplified to the case of serial computations" # Get mesh geometry x = extract_gmsh_geometry(model) # Get mesh topology for each element topologies = extract_gmsh_topology_and_markers(model) # Get information about each cell type from the msh files num_cell_types = len(topologies.keys()) cell_information = {} cell_dimensions = np.zeros(num_cell_types, dtype=np.int32) for i, element in enumerate(topologies.keys()): properties = model.mesh.getElementProperties(element) name, dim, order, num_nodes, coords, _ = properties cell_information[i] = { "id": element, "dim": dim, "num_nodes": num_nodes } cell_dimensions[i] = dim # Sort elements by ascending dimension perm_sort = np.argsort(cell_dimensions) # Get cell type data and geometric dimension cell_id = cell_information[perm_sort[-1]]["id"] tdim = cell_information[perm_sort[-1]]["dim"] num_nodes = cell_information[perm_sort[-1]]["num_nodes"] cells = np.asarray(topologies[cell_id]["topology"], dtype=np.int64) cell_values = np.asarray(topologies[cell_id]["cell_data"], dtype=np.int32) # Look up facet data assert tdim - 1 in cell_dimensions num_facet_nodes = cell_information[perm_sort[-2]]["num_nodes"] gmsh_facet_id = cell_information[perm_sort[-2]]["id"] marked_facets = np.asarray(topologies[gmsh_facet_id]["topology"], dtype=np.int64) facet_values = np.asarray(topologies[gmsh_facet_id]["cell_data"], dtype=np.int32) # Create distributed mesh ufl_domain = ufl_mesh_from_gmsh(cell_id, gdim) gmsh_cell_perm = perm_gmsh(to_type(str(ufl_domain.ufl_cell())), num_nodes) cells = cells[:, gmsh_cell_perm] mesh = create_mesh(MPI.COMM_WORLD, cells, x[:, :gdim], ufl_domain) # Create MeshTags for cells entities, values = distribute_entity_data(mesh, mesh.topology.dim, cells, cell_values) mesh.topology.create_connectivity(mesh.topology.dim, 0) adj = AdjacencyList_int32(entities) ct = meshtags_from_entities(mesh, mesh.topology.dim, adj, np.int32(values)) ct.name = "Cell tags" # Create MeshTags for facets facet_type = cell_entity_type(to_type(str(ufl_domain.ufl_cell())), mesh.topology.dim - 1, 0) gmsh_facet_perm = perm_gmsh(facet_type, num_facet_nodes) marked_facets = marked_facets[:, gmsh_facet_perm] entities, values = distribute_entity_data(mesh, mesh.topology.dim - 1, marked_facets, facet_values) mesh.topology.create_connectivity(mesh.topology.dim - 1, mesh.topology.dim) adj = AdjacencyList_int32(entities) ft = meshtags_from_entities(mesh, mesh.topology.dim - 1, adj, np.int32(values)) ft.name = "Facet tags" return mesh, ct, ft
# Generating a mesh on each process rank # ====================================== # # Generate a mesh on each rank with pygmsh, and create a DOLFIN-X mesh # on each rank # Interface needs updating for (py)msh API change sys.exit(0) geom = pygmsh.opencascade.Geometry() geom.add_ball([0.0, 0.0, 0.0], 1.0, char_length=0.2) pygmsh_mesh = pygmsh.generate_mesh(geom) cells, x = pygmsh_mesh.cells[-1].data, pygmsh_mesh.points pygmsh_cell = pygmsh_mesh.cells[-1].type mesh = create_mesh(MPI.COMM_SELF, cells, x, ufl_mesh_from_gmsh(pygmsh_cell, x.shape[1])) with XDMFFile(MPI.COMM_SELF, "mesh_rank_{}.xdmf".format(MPI.COMM_WORLD.rank), "w") as file: file.write_mesh(mesh) # Create a distributed (parallel) mesh with affine geometry # ========================================================= # # Generate mesh on rank 0, then build a distributed mesh if MPI.COMM_WORLD.rank == 0: # Generate a mesh geom = pygmsh.opencascade.Geometry() ball = geom.add_ball([0.0, 0.0, 0.0], 1.0, char_length=0.2) box = geom.add_box([0.0, 0.0, 0.0], [1.0, 1.0, 1.0])