def test_b_mesh_mapping(celltype): """ Creates a boundary mesh and checks that the geometrical entities are mapped to the correct cells. """ mesh = dolfinx.UnitCubeMesh(MPI.COMM_WORLD, 2, 2, 2, cell_type=celltype) b_mesh, bndry_to_mesh = dolfinx.plotting.create_boundary_mesh( mesh, MPI.COMM_SELF) # Compute map from boundary mesh topology to boundary mesh geometry b_mesh.topology.create_connectivity(b_mesh.topology.dim, b_mesh.topology.dim) b_imap = b_mesh.topology.index_map(b_mesh.topology.dim) tdim_entities = np.arange(b_imap.size_local, dtype=np.int32) boundary_geometry = cmesh.entities_to_geometry(b_mesh, b_mesh.topology.dim, tdim_entities, False) # Compare geometry maps for i in range(boundary_geometry.shape[0]): assert (np.allclose(b_mesh.geometry.x[boundary_geometry[i]], mesh.geometry.x[bndry_to_mesh[i]])) # Check that boundary mesh integrated has the correct area b_volume = mesh.mpi_comm().allreduce(dolfinx.fem.assemble_scalar( dolfinx.Constant(b_mesh, 1) * ufl.dx), op=MPI.SUM) mesh_surface = mesh.mpi_comm().allreduce(dolfinx.fem.assemble_scalar( dolfinx.Constant(mesh, 1) * ufl.ds), op=MPI.SUM) assert (np.isclose(b_volume, mesh_surface))
def boundary_grid_from_fenics_mesh(fenics_mesh): """ Create a Bempp boundary grid from a FEniCS Mesh. Return the Bempp grid and a map from the node numberings of the FEniCS mesh to the node numbers of the boundary grid. """ import bempp.api import numpy as np from dolfinx.cpp.mesh import entities_to_geometry, exterior_facet_indices boundary = entities_to_geometry( fenics_mesh, fenics_mesh.topology.dim - 1, exterior_facet_indices(fenics_mesh), True, ) bm_nodes = set() for tri in boundary: for node in tri: bm_nodes.add(node) bm_nodes = list(bm_nodes) bm_cells = np.array([[bm_nodes.index(i) for i in tri] for tri in boundary]) bm_coords = fenics_mesh.geometry.x[bm_nodes] bempp_boundary_grid = bempp.api.Grid(bm_coords.transpose(), bm_cells.transpose()) return bempp_boundary_grid, bm_nodes
def bm_from_fenics_mesh(fenics_mesh): boundary = entities_to_geometry( fenics_mesh, fenics_mesh.topology.dim - 1, exterior_facet_indices(fenics_mesh), True, ) # print("number of facets ", len(exterior_facet_indices(fenics_mesh))) bm_nodes = set() for tri in boundary: for node in tri: bm_nodes.add(node) bm_nodes = list(bm_nodes) # bm_cells - remap cell indices between 0-len(bm_nodes) bm_cells = np.array([[bm_nodes.index(i) for i in tri] for tri in boundary]) bm_coords = fenics_mesh.geometry.x[bm_nodes] # print(boundary) # print("fenics mesh dofs\n", fm_dofs) # # print("type of bm_coords ", type(bm_nodes), len(bm_nodes)) # print('shape bm_cells ', bm_cells.shape) # print('type bm_cells ', type(bm_cells)) # print('bm_cells \n', bm_cells) # print('bm_nodes \n', bm_nodes) return bm_nodes, bm_cells, bm_coords
def solve_system(N): fenics_mesh = dolfinx.UnitCubeMesh(fenicsx_comm, N, N, N) fenics_space = dolfinx.FunctionSpace(fenics_mesh, ("CG", 1)) u = ufl.TrialFunction(fenics_space) v = ufl.TestFunction(fenics_space) k = 2 # print(u*v*ufl.ds) form = (ufl.inner(ufl.grad(u), ufl.grad(v)) - k**2 * ufl.inner(u, v)) * ufl.dx # locate facets on the cube boundary facets = locate_entities_boundary( fenics_mesh, 2, lambda x: np.logical_or( np.logical_or( np.logical_or(np.isclose(x[2], 0.0), np.isclose(x[2], 1.0)), np.logical_or(np.isclose(x[1], 0.0), np.isclose(x[1], 1.0))), np.logical_or(np.isclose(x[0], 0.0), np.isclose(x[0], 1.0)))) facets.sort() # alternative - more general approach boundary = entities_to_geometry( fenics_mesh, fenics_mesh.topology.dim - 1, exterior_facet_indices(fenics_mesh), True, ) # print(len(facets) assert len(facets) == len(exterior_facet_indices(fenics_mesh)) u0 = fem.Function(fenics_space) with u0.vector.localForm() as u0_loc: u0_loc.set(0) # solution vector bc = DirichletBC(u0, locate_dofs_topological(fenics_space, 2, facets)) A = 1 + 1j f = Function(fenics_space) f.interpolate(lambda x: A * k**2 * np.cos(k * x[0]) * np.cos(k * x[1])) L = ufl.inner(f, v) * ufl.dx u0.name = "u" problem = fem.LinearProblem(form, L, u=u0, petsc_options={ "ksp_type": "preonly", "pc_type": "lu" }) # problem = fem.LinearProblem(form, L, bcs=[bc], u=u0, petsc_options={"ksp_type": "preonly", "pc_type": "lu"}) start_time = time.time() soln = problem.solve() if world_rank == 0: print("--- fenics solve done in %s seconds ---" % (time.time() - start_time))
def submesh_geometry_test(mesh, submesh, geom_map, entity_dim, entities): submesh_geom_index_map = submesh.geometry.index_map() assert submesh_geom_index_map.size_local + submesh_geom_index_map.num_ghosts == submesh.geometry.x.shape[ 0] # Some processes might not own or ghost entities if len(entities) > 0: assert mesh.geometry.dim == submesh.geometry.dim e_to_g = entities_to_geometry(mesh, entity_dim, entities, False) for submesh_entity in range(len(entities)): submesh_x_dofs = submesh.geometry.dofmap.links(submesh_entity) # e_to_g[i] gets the mesh x_dofs of entities[i], which should # correspond to the x_dofs of cell i in the submesh mesh_x_dofs = e_to_g[submesh_entity] for i in range(len(submesh_x_dofs)): assert mesh_x_dofs[i] == geom_map[submesh_x_dofs[i]] assert np.allclose(mesh.geometry.x[mesh_x_dofs[i]], submesh.geometry.x[submesh_x_dofs[i]])
def bm_from_fenics_mesh_mpi(fenics_mesh, fenics_space): boundary = entities_to_geometry( fenics_mesh, fenics_mesh.topology.dim - 1, exterior_facet_indices(fenics_mesh), True, ) dofmap = fenics_space.dofmap.index_map.global_indices(False) geom_map = fenics_mesh.geometry.index_map().global_indices(False) dofmap_mesh = fenics_mesh.geometry.dofmap assert dofmap == geom_map # print("dofmap ", dofmap) # print("geometry map ", geom_map) # print("dofmap mesh", dofmap_mesh) # print("number of facets ", len(exterior_facet_indices(fenics_mesh))) bm_nodes = set() for i, tri in enumerate(boundary): for j, node in enumerate(tri): # print(node, boundary[i][j]) glob_geom_node = geom_map[node] boundary[i][j] = glob_geom_node bm_nodes.add(node) bm_nodes_global = [geom_map[i] for i in bm_nodes] bm_nodes = list(bm_nodes) bm_coords = fenics_mesh.geometry.x[bm_nodes] # bm_cells - remap cell indices between 0-len(bm_nodes) # bm_cells = np.array([[bm_nodes.index(i) for i in tri] for tri in boundary]) # print("bm_coords\n", bm_coords) # print("bm_nodes\n", bm_nodes) # print("boundary\n", boundary) # # print("type of bm_coords ", type(bm_nodes), len(bm_nodes)) # print('shape bm_cells ', bm_cells.shape) # print('type bm_cells ', type(bm_cells)) # print('bm_cells \n', bm_cells) # print("dofmap ", fenics_mesh.geometry.dofmap) return bm_nodes_global, bm_coords, boundary
def create_boundary_mesh(mesh, comm, orient=False): """ Create a mesh consisting of all exterior facets of a mesh Input: mesh - The mesh comm - The MPI communicator orient - Boolean flag for reorientation of facets to have consistent outwards-pointing normal (default: True) Output: bmesh - The boundary mesh bmesh_to_geometry - Map from cells of the boundary mesh to the geometry of the original mesh """ ext_facets = cmesh.exterior_facet_indices(mesh) boundary_geometry = cmesh.entities_to_geometry(mesh, mesh.topology.dim - 1, ext_facets, orient) facet_type = dolfinx.cpp.mesh.to_string( cmesh.cell_entity_type(mesh.topology.cell_type, mesh.topology.dim - 1)) facet_cell = ufl.Cell(facet_type, geometric_dimension=mesh.geometry.dim) degree = mesh.ufl_domain().ufl_coordinate_element().degree() ufl_domain = ufl.Mesh(ufl.VectorElement("Lagrange", facet_cell, degree)) bmesh = dolfinx.mesh.create_mesh(comm, boundary_geometry, mesh.geometry.x, ufl_domain) return bmesh, boundary_geometry
def mesh_3D_dolfin(theta=0, ct=CellType.tetrahedron, ext="tetrahedron", num_refinements=0, N0=5): timer = Timer("Create mesh") def find_plane_function(p0, p1, p2): """ Find plane function given three points: http://www.nabla.hr/CG-LinesPlanesIn3DA3.htm """ v1 = np.array(p1) - np.array(p0) v2 = np.array(p2) - np.array(p0) n = np.cross(v1, v2) D = -(n[0] * p0[0] + n[1] * p0[1] + n[2] * p0[2]) return lambda x: np.isclose(0, np.dot(n, x) + D) def over_plane(p0, p1, p2): """ Returns function that checks if a point is over a plane defined by the points p0, p1 and p2. """ v1 = np.array(p1) - np.array(p0) v2 = np.array(p2) - np.array(p0) n = np.cross(v1, v2) D = -(n[0] * p0[0] + n[1] * p0[1] + n[2] * p0[2]) return lambda x: n[0] * x[0] + n[1] * x[1] + D > -n[2] * x[2] tmp_mesh_name = "tmp_mesh.xdmf" r_matrix = rotation_matrix([1 / np.sqrt(2), 1 / np.sqrt(2), 0], -theta) if MPI.COMM_WORLD.rank == 0: # Create two coarse meshes and merge them mesh0 = create_unit_cube(MPI.COMM_SELF, N0, N0, N0, ct) mesh0.geometry.x[:, 2] += 1 mesh1 = create_unit_cube(MPI.COMM_SELF, 2 * N0, 2 * N0, 2 * N0, ct) tdim0 = mesh0.topology.dim num_cells0 = mesh0.topology.index_map(tdim0).size_local cells0 = entities_to_geometry( mesh0, tdim0, np.arange(num_cells0, dtype=np.int32).reshape((-1, 1)), False) tdim1 = mesh1.topology.dim num_cells1 = mesh1.topology.index_map(tdim1).size_local cells1 = entities_to_geometry( mesh1, tdim1, np.arange(num_cells1, dtype=np.int32).reshape((-1, 1)), False) cells1 += mesh0.geometry.x.shape[0] # Concatenate points and cells points = np.vstack([mesh0.geometry.x, mesh1.geometry.x]) cells = np.vstack([cells0, cells1]) cell = Cell(ext, geometric_dimension=points.shape[1]) domain = Mesh(VectorElement("Lagrange", cell, 1)) # Rotate mesh points = np.dot(r_matrix, points.T).T mesh = create_mesh(MPI.COMM_SELF, cells, points, domain) with XDMFFile(MPI.COMM_SELF, tmp_mesh_name, "w") as xdmf: xdmf.write_mesh(mesh) MPI.COMM_WORLD.barrier() with XDMFFile(MPI.COMM_WORLD, tmp_mesh_name, "r") as xdmf: mesh = xdmf.read_mesh() # Refine coarse mesh for i in range(num_refinements): mesh.topology.create_entities(mesh.topology.dim - 2) mesh = refine(mesh, redistribute=True) tdim = mesh.topology.dim fdim = tdim - 1 # Find information about facets to be used in meshtags bottom_points = np.dot( r_matrix, np.array([[0, 0, 0], [1, 0, 0], [0, 1, 0], [1, 1, 0]]).T) bottom = find_plane_function(bottom_points[:, 0], bottom_points[:, 1], bottom_points[:, 2]) bottom_facets = locate_entities_boundary(mesh, fdim, bottom) top_points = np.dot( r_matrix, np.array([[0, 0, 2], [1, 0, 2], [0, 1, 2], [1, 1, 2]]).T) top = find_plane_function(top_points[:, 0], top_points[:, 1], top_points[:, 2]) top_facets = locate_entities_boundary(mesh, fdim, top) # Determine interface facets if_points = np.dot( r_matrix, np.array([[0, 0, 1], [1, 0, 1], [0, 1, 1], [1, 1, 1]]).T) interface = find_plane_function(if_points[:, 0], if_points[:, 1], if_points[:, 2]) i_facets = locate_entities_boundary(mesh, fdim, interface) mesh.topology.create_connectivity(fdim, tdim) top_interface = [] bottom_interface = [] facet_to_cell = mesh.topology.connectivity(fdim, tdim) num_cells = mesh.topology.index_map(tdim).size_local # Find top and bottom interface facets cell_midpoints = compute_midpoints(mesh, tdim, range(num_cells)) top_cube = over_plane(if_points[:, 0], if_points[:, 1], if_points[:, 2]) for facet in i_facets: i_cells = facet_to_cell.links(facet) assert (len(i_cells == 1)) i_cell = i_cells[0] if top_cube(cell_midpoints[i_cell]): top_interface.append(facet) else: bottom_interface.append(facet) # Create cell tags num_cells = mesh.topology.index_map(tdim).size_local cell_midpoints = compute_midpoints(mesh, tdim, range(num_cells)) top_cube_marker = 2 indices = [] values = [] for cell_index in range(num_cells): if top_cube(cell_midpoints[cell_index]): indices.append(cell_index) values.append(top_cube_marker) ct = meshtags(mesh, tdim, np.array(indices, dtype=np.intc), np.array(values, dtype=np.intc)) # Create meshtags for facet data markers = { 3: top_facets, 4: bottom_interface, 9: top_interface, 5: bottom_facets } # , 6: left_facets, 7: right_facets} indices = np.array([], dtype=np.intc) values = np.array([], dtype=np.intc) for key in markers.keys(): indices = np.append(indices, markers[key]) values = np.append(values, np.full(len(markers[key]), key, dtype=np.intc)) sorted_indices = np.argsort(indices) mt = meshtags(mesh, fdim, indices[sorted_indices], values[sorted_indices]) mt.name = "facet_tags" fname = f"meshes/mesh_{ext}_{theta:.2f}.xdmf" with XDMFFile(MPI.COMM_WORLD, fname, "w") as o_f: o_f.write_mesh(mesh) o_f.write_meshtags(ct) o_f.write_meshtags(mt) timer.stop()
def get_num_bdry_dofs(fenics_mesh): exterior_facets = exterior_facet_indices(fenics_mesh) boundary = entities_to_geometry( fenics_mesh, fenics_mesh.topology.dim - 1, exterior_facet_indices(fenics_mesh), True, ) bm_nodes = set() fenics_space = dolfinx.FunctionSpace(fenics_mesh, ("CG", 1)) global_dofs_map = fenics_space.dofmap.index_map.global_indices(False) # print(fenics_space.dofmap.index_map.ghosts) mapping, dof_map = vertex_dofmap(fenics_mesh) # value of 9 vertex_err_val = 9 if vertex_err_val in mapping.keys(): print("value of corresponding dof is ", mapping[9]) for i, tri in enumerate(boundary): for j, node in enumerate(tri): # print(node, boundary[i][j]) glob_geom_node = global_dofs_map[node] # glob_geom_node = geom_map[node] boundary[i][j] = glob_geom_node bm_nodes.add(node) bm_nodes_global = [global_dofs_map[i] for i in bm_nodes] ghosts = fenics_space.dofmap.index_map.ghosts ghosts_list = list(ghosts) ghost_owner = fenics_space.dofmap.index_map.ghost_owner_rank() ownership = np.ones_like(bm_nodes_global, dtype=np.int32) * comm.rank for i in range(len(bm_nodes_global)): if bm_nodes_global[i] in ghosts_list: index = ghosts_list.index(bm_nodes_global[i]) ownership[i] = ghost_owner[index] print(ownership) print(bm_nodes_global) print("RANK {} \n".format(comm.Get_rank())) root = 0 rank = comm.Get_rank() sendbuf = np.array(bm_nodes_global) # print("sendbuf ", sendbuf) sendcounts = np.array(comm.gather(len(sendbuf), root)) print("sendcounts ", sendcounts) if rank == root: print("sendcounts: {}, total: {}".format(sendcounts, sum(sendcounts))) recvbuf = np.empty(sum(sendcounts), dtype=np.int64) else: recvbuf = None comm.Gatherv(sendbuf=sendbuf, recvbuf=(recvbuf, sendcounts), root=root) if rank == root: bm_nodes_unique = sorted(np.unique(recvbuf)) print("Gathered array: {}, unique length: {}".format( bm_nodes_unique, len(bm_nodes_unique))) return len(bm_nodes_unique) return 0
def play(fenics_mesh): exterior_facets = exterior_facet_indices(fenics_mesh) num_fenics_vertices = fenics_mesh.topology.connectivity(0, 0).num_nodes tets = fenics_mesh.topology.connectivity(3, 0) fenics_mesh.topology.create_connectivity(2, 0) tris = fenics_mesh.topology.connectivity(2, 0) fenics_mesh.topology.create_connectivity(2, 3) tri_to_tet = fenics_mesh.topology.connectivity(2, 3) exterior_nodes = set() local2global_nodes = fenics_mesh.topology.index_map(0).global_indices( False) # from exterior facets get all nodes (global) on bdry # is the bdry triangle index the same as in tris? for i in exterior_facets: for j in tris.links(i): exterior_nodes.add(local2global_nodes[j]) # print("ghost owner rank ", fenics_mesh.topology.index_map(0)) # print("index_map ", dir(fenics_mesh.topology.index_map(0))) ghosts = fenics_mesh.topology.index_map(0).ghosts # print("l2g ", local2global_nodes) # ghosts_global = [i for i in ghosts] print("ghosts", fenics_mesh.topology.index_map(0).ghosts) # print("ghosts_global", fenics_mesh.topology.index_map(0).ghosts) print("ghost owner rank ", fenics_mesh.topology.index_map(0).ghost_owner_rank()) print("all global indices on this process", fenics_mesh.topology.index_map(0).indices(True)) # print(dir(fenics_mesh.topology.index_map(0))) size_local = fenics_mesh.topology.index_map(0).size_local size_global = fenics_mesh.topology.index_map(0).size_global # shared = fenics_mesh.topology.index_map(0).shared_indices print("size local ", size_local, " size global ", size_global) print("exterior nodes (global)", exterior_nodes) print("exterior nodes length (global)", len(exterior_nodes)) sendbuf_nodes = np.asarray(list(exterior_nodes), dtype=np.int64) print("length of sendbuf ", len(sendbuf_nodes)) # print("exterior facets ", exterior_facets) # print("exterior facet 0", [ local2global_nodes[i] for i in tris.links(0)]) print("RANK ", comm.Get_rank()) # print(local2global_nodes) boundary = entities_to_geometry( fenics_mesh, fenics_mesh.topology.dim - 1, exterior_facet_indices(fenics_mesh), True, ) bm_nodes = set() # this map is wrong: geom_map = fenics_mesh.geometry.index_map().global_indices(False) # use this instead: fenics_space = dolfinx.FunctionSpace(fenics_mesh, ("CG", 1)) global_dofs_map = fenics_space.dofmap.index_map.global_indices(False) mapping_space = space_dofmap(fenics_mesh, fenics_space) # print("mapping space ", mapping_space) # print(mapping) exterior_dofs = [] for i in exterior_nodes: exterior_dofs.append(mapping_space[i]) print("exterior dofs from vertices", exterior_dofs) for i, tri in enumerate(boundary): for j, node in enumerate(tri): # print(node, boundary[i][j]) glob_geom_node = global_dofs_map[node] # glob_geom_node = geom_map[node] boundary[i][j] = glob_geom_node bm_nodes.add(node) bm_nodes_global = [geom_map[i] for i in bm_nodes] print("bm nodes ", bm_nodes_global) mapping, dof_map = vertex_dofmap(fenics_mesh) # print("geom nodes ", bm_nodes_global) # print(exterior_facets) # get mapping between dofs and vertices mesh_dofmap = fenics_mesh.geometry.dofmap # mapping = vertex_dofmap(fenics_mesh) # print(mapping[13]) mesh_dofs = [] for i in exterior_nodes: # print(i) mesh_dofs.append(mapping[i]) # print("mapping ", mapping) # print("dof_map ", dof_map) ma = [dof_map[i] for i in bm_nodes_global] print(ma) print("\n") # print("bm_nodes global ", sorted(bm_nodes_global)) print("do a gather") recvbuf_nodes = None if comm.rank == 0: info = MPI.Status() recvbuf_nodes = np.empty(comm.Get_size() * len(exterior_nodes), dtype=np.int64) comm.Gather(sendbuf_nodes, recvbuf_nodes, root=0) print("received nodes ", len(np.unique(recvbuf_nodes))) exit(0)
def bm_from_fenics_mesh(comm, fenics_comm, fenics_mesh, fenics_space): """ Create a Bempp boundary grid from a FEniCS Mesh. Return the Bempp grid and a map from the node numberings of the FEniCS mesh to the node numbers of the boundary grid. """ from dolfinx.cpp.mesh import entities_to_geometry, exterior_facet_indices boundary = entities_to_geometry( fenics_mesh, fenics_mesh.topology.dim - 1, exterior_facet_indices(fenics_mesh), True, ) dofmap = fenics_space.dofmap.index_map.global_indices(False) geom_map = fenics_mesh.geometry.index_map().global_indices(False) dofmap_mesh = fenics_mesh.geometry.dofmap # assert dofmap == geom_map # print("number of facets ", len(exterior_facet_indices(fenics_mesh))) bm_nodes = set() for i, tri in enumerate(boundary): for j, node in enumerate(tri): # print(node, boundary[i][j]) glob_dof_node = dofmap[node] boundary[i][j] = glob_dof_node bm_nodes.add(node) bm_nodes_global = [dofmap[i] for i in bm_nodes] bm_nodes = list(bm_nodes) bm_coords = fenics_mesh.geometry.x[bm_nodes] # bm_cells - remap cell indices between 0-len(bm_nodes) # bm_cells = np.array([[bm_nodes.index(i) for i in tri] for tri in boundary]) # print('shape bm_cells ', bm_cells.shape) # print('bm_cells \n', bm_cells) # print('bm_coords len ', len(bm_coords)) # print('bm_coords type ', type(bm_coords[0][0])) # print("RANK ", fenics_comm.rank) gathered_bm_coords = gather(fenics_comm, bm_coords, 3, np.float64) gathered_bm_tris = gather(fenics_comm, boundary, 3, np.int32) gathered_bm_nodes = gather(fenics_comm, np.asarray(bm_nodes_global, np.int32), 1, np.int32) global_alldofs = np.asarray( fenics_space.dofmap.index_map.global_indices(False), dtype=np.int32) gathered_global_alldofs = gather(fenics_comm, global_alldofs, 1, np.int32) if fenics_comm.rank == 0: all_bm_coords = gathered_bm_coords.reshape( int(len(gathered_bm_coords) / 3), 3) all_bm_tris = gathered_bm_tris.reshape(int(len(gathered_bm_tris) / 3), 3) all_bm_nodes = gathered_bm_nodes # sort gathered nodes and remove repetitions (ghosts on bdry) sorted_indices = all_bm_nodes.argsort() all_bm_nodes_sorted = all_bm_nodes[sorted_indices] all_bm_coords_sorted = all_bm_coords[sorted_indices] # print("sorted indices, ", sorted_indices) all_bm_nodes, unique = np.unique(all_bm_nodes_sorted, return_index=True) all_bm_coords = all_bm_coords_sorted[unique] all_bm_nodes_list = list(all_bm_nodes) # bm_cells - remap boundary triangle indices between 0-len(bm_nodes) - this can be improved all_bm_cells = np.array([[all_bm_nodes_list.index(i) for i in tri] for tri in all_bm_tris], dtype=np.int32) all_bm_nodes = np.asarray(all_bm_nodes_list, dtype=np.int32) # send to Bempp process send(comm, all_bm_coords, MPI.DOUBLE, 100) send(comm, all_bm_cells, MPI.INT, 101) send(comm, all_bm_nodes, MPI.INT, 102) # print("all_bm_cells ", type(all_bm_cells)) num_fenics_vertices = len(np.unique(np.sort(gathered_global_alldofs))) # hack - to change comm.send(num_fenics_vertices, dest=0, tag=103)