def test_manifold_point_search(): # Simple two-triangle surface in 3d vertices = np.array([[0.0, 0.0, 1.0], [1.0, 1.0, 1.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]) cells = np.array([[0, 1, 2], [0, 1, 3]], dtype=np.int64) domain = ufl.Mesh(ufl.VectorElement("Lagrange", "triangle", 1)) mesh = create_mesh(MPI.COMM_WORLD, cells, vertices, domain) bb = BoundingBoxTree(mesh, mesh.topology.dim) # Find cell colliding with point points = np.array([[0.5, 0.25, 0.75], [0.25, 0.5, 0.75]]) cell_candidates = geometry.compute_collisions(bb, points) colliding_cells = geometry.compute_colliding_cells(mesh, cell_candidates, points) # Extract vertices of cell indices = _cpp.mesh.entities_to_geometry( mesh, mesh.topology.dim, [colliding_cells.links(0)[0], colliding_cells.links(1)[0]], False) cell_vertices = mesh.geometry.x[indices] # Compare vertices with input assert np.allclose(cell_vertices, vertices[cells])
def test_manifold_point_search(): # Simple two-triangle surface in 3d vertices = numpy.array([[0.0, 0.0, 1.0], [1.0, 1.0, 1.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]) cells = numpy.array([[0, 1, 2], [0, 1, 3]], dtype=numpy.int64) domain = ufl.Mesh(ufl.VectorElement("Lagrange", "triangle", 1)) mesh = create_mesh(MPI.COMM_WORLD, cells, vertices, domain) x = mesh.geometry.x tdim = mesh.topology.dim bb = BoundingBoxTree(mesh, tdim) # Find cell colliding with point p = numpy.array([0.5, 0.25, 0.75]) cell_candidates = geometry.compute_collisions_point(bb, p) cell = cpp.geometry.select_colliding_cells(mesh, cell_candidates, p, 1) # Extract vertices of cell top_indices = cpp.mesh.entities_to_geometry(mesh, tdim, [cell], False) cell_vertices = x[top_indices] # Compare vertices with input (should be in cell 0) assert numpy.allclose(cell_vertices, vertices[cells[0]]) # Find cell colliding with point p = numpy.array([0.25, 0.5, 0.75]) cell_candidates = geometry.compute_collisions_point(bb, p) cell = cpp.geometry.select_colliding_cells(mesh, cell_candidates, p, 1) # Extract vertices of cell top_indices = cpp.mesh.entities_to_geometry(mesh, tdim, [cell], False) x = mesh.geometry.x cell_vertices = x[top_indices] # Compare vertices with input (should be in cell 1) assert numpy.allclose(cell_vertices, vertices[cells[1]])
def test_second_order_quad(L, H, Z): """ Test by comparing integration of z+x*y against sympy/scipy integration of a quad element. Z>0 implies curved element. *-----* 3--6--2 | | | | | | 7 8 5 | | | | *-----* 0--4--1 """ points = np.array([[0, 0, 0], [L, 0, 0], [L, H, Z], [0, H, Z], [L / 2, 0, 0], [L, H / 2, 0], [L / 2, H, Z], [0, H / 2, 0], [L / 2, H / 2, 0], [2 * L, 0, 0], [2 * L, H, Z]]) cells = np.array([[0, 1, 2, 3, 4, 5, 6, 7, 8]]) cells = cells[:, perm_vtk(CellType.quadrilateral, cells.shape[1])] cell = ufl.Cell("quadrilateral", geometric_dimension=points.shape[1]) domain = ufl.Mesh(ufl.VectorElement("Lagrange", cell, 2)) mesh = create_mesh(MPI.COMM_WORLD, cells, points, domain) def e2(x): return x[2] + x[0] * x[1] # Interpolate function V = FunctionSpace(mesh, ("CG", 2)) u = Function(V) u.interpolate(e2) intu = assemble_scalar(u * dx(mesh)) intu = mesh.mpi_comm().allreduce(intu, op=MPI.SUM) nodes = [0, 3, 7] ref = sympy_scipy(points, nodes, L, H) assert ref == pytest.approx(intu, rel=1e-6)
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 test_third_order_quad(L, H, Z): """Test by comparing integration of z+x*y against sympy/scipy integration of a quad element. Z>0 implies curved element. *---------* 3--8--9--2-22-23-17 | | | | | | | 11 14 15 7 26 27 21 | | | | | | | 10 12 13 6 24 25 20 | | | | | *---------* 0--4--5--1-18-19-16 """ points = np.array([ [0, 0, 0], [L, 0, 0], [L, H, Z], [0, H, Z], # 0 1 2 3 [L / 3, 0, 0], [2 * L / 3, 0, 0], # 4 5 [L, H / 3, 0], [L, 2 * H / 3, 0], # 6 7 [L / 3, H, Z], [2 * L / 3, H, Z], # 8 9 [0, H / 3, 0], [0, 2 * H / 3, 0], # 10 11 [L / 3, H / 3, 0], [2 * L / 3, H / 3, 0], # 12 13 [L / 3, 2 * H / 3, 0], [2 * L / 3, 2 * H / 3, 0], # 14 15 [2 * L, 0, 0], [2 * L, H, Z], # 16 17 [4 * L / 3, 0, 0], [5 * L / 3, 0, 0], # 18 19 [2 * L, H / 3, 0], [2 * L, 2 * H / 3, 0], # 20 21 [4 * L / 3, H, Z], [5 * L / 3, H, Z], # 22 23 [4 * L / 3, H / 3, 0], [5 * L / 3, H / 3, 0], # 24 25 [4 * L / 3, 2 * H / 3, 0], [5 * L / 3, 2 * H / 3, 0] ]) # 26 27 # Change to multiple cells when matthews dof-maps work for quads cells = np.array( [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], [1, 16, 17, 2, 18, 19, 20, 21, 22, 23, 6, 7, 24, 25, 26, 27]]) cells = cells[:, perm_vtk(CellType.quadrilateral, cells.shape[1])] cell = ufl.Cell("quadrilateral", geometric_dimension=points.shape[1]) domain = ufl.Mesh(ufl.VectorElement("Lagrange", cell, 3)) mesh = create_mesh(MPI.COMM_WORLD, cells, points, domain) def e2(x): return x[2] + x[0] * x[1] # Interpolate function V = FunctionSpace(mesh, ("CG", 3)) u = Function(V) u.interpolate(e2) intu = assemble_scalar(u * dx(mesh)) intu = mesh.mpi_comm().allreduce(intu, op=MPI.SUM) nodes = [0, 3, 10, 11] ref = sympy_scipy(points, nodes, 2 * L, H) assert ref == pytest.approx(intu, rel=1e-6)
def test_nth_order_triangle(order): num_nodes = (order + 1) * (order + 2) / 2 cells = np.array([range(int(num_nodes))]) cells = cells[:, perm_vtk(CellType.triangle, cells.shape[1])] if order == 1: points = np.array([[0.00000, 0.00000, 0.00000], [1.00000, 0.00000, 0.00000], [0.00000, 1.00000, 0.00000]]) elif order == 2: points = np.array([[0.00000, 0.00000, 0.00000], [1.00000, 0.00000, 0.00000], [0.00000, 1.00000, 0.00000], [0.50000, 0.00000, 0.00000], [0.50000, 0.50000, -0.25000], [0.00000, 0.50000, -0.25000]]) elif order == 3: points = np.array([[0.00000, 0.00000, 0.00000], [1.00000, 0.00000, 0.00000], [0.00000, 1.00000, 0.00000], [0.33333, 0.00000, 0.00000], [0.66667, 0.00000, 0.00000], [0.66667, 0.33333, -0.11111], [0.33333, 0.66667, 0.11111], [0.00000, 0.66667, 0.11111], [0.00000, 0.33333, -0.11111], [0.33333, 0.33333, -0.11111]]) elif order == 4: points = np.array([[0.00000, 0.00000, 0.00000], [1.00000, 0.00000, 0.00000], [0.00000, 1.00000, 0.00000], [0.25000, 0.00000, 0.00000], [0.50000, 0.00000, 0.00000], [0.75000, 0.00000, 0.00000], [0.75000, 0.25000, -0.06250], [0.50000, 0.50000, 0.06250], [0.25000, 0.75000, -0.06250], [0.00000, 0.75000, -0.06250], [0.00000, 0.50000, 0.06250], [0.00000, 0.25000, -0.06250], [0.25000, 0.25000, -0.06250], [0.50000, 0.25000, -0.06250], [0.25000, 0.50000, 0.06250]]) elif order == 5: points = np.array([[0.00000, 0.00000, 0.00000], [1.00000, 0.00000, 0.00000], [0.00000, 1.00000, 0.00000], [0.20000, 0.00000, 0.00000], [0.40000, 0.00000, 0.00000], [0.60000, 0.00000, 0.00000], [0.80000, 0.00000, 0.00000], [0.80000, 0.20000, -0.04000], [0.60000, 0.40000, 0.04000], [0.40000, 0.60000, -0.04000], [0.20000, 0.80000, 0.04000], [0.00000, 0.80000, 0.04000], [0.00000, 0.60000, -0.04000], [0.00000, 0.40000, 0.04000], [0.00000, 0.20000, -0.04000], [0.20000, 0.20000, -0.04000], [0.60000, 0.20000, -0.04000], [0.20000, 0.60000, -0.04000], [0.40000, 0.20000, -0.04000], [0.40000, 0.40000, 0.04000], [0.20000, 0.40000, 0.04000]]) elif order == 6: points = np.array([[0.00000, 0.00000, 0.00000], [1.00000, 0.00000, 0.00000], [0.00000, 1.00000, 0.00000], [0.16667, 0.00000, 0.00000], [0.33333, 0.00000, 0.00000], [0.50000, 0.00000, 0.00000], [0.66667, 0.00000, 0.00000], [0.83333, 0.00000, 0.00000], [0.83333, 0.16667, -0.00463], [0.66667, 0.33333, 0.00463], [0.50000, 0.50000, -0.00463], [0.33333, 0.66667, 0.00463], [0.16667, 0.83333, -0.00463], [0.00000, 0.83333, -0.00463], [0.00000, 0.66667, 0.00463], [0.00000, 0.50000, -0.00463], [0.00000, 0.33333, 0.00463], [0.00000, 0.16667, -0.00463], [0.16667, 0.16667, -0.00463], [0.66667, 0.16667, -0.00463], [0.16667, 0.66667, 0.00463], [0.33333, 0.16667, -0.00463], [0.50000, 0.16667, -0.00463], [0.50000, 0.33333, 0.00463], [0.33333, 0.50000, -0.00463], [0.16667, 0.50000, -0.00463], [0.16667, 0.33333, 0.00463], [0.33333, 0.33333, 0.00463]]) elif order == 7: points = np.array([[0.00000, 0.00000, 0.00000], [1.00000, 0.00000, 0.00000], [0.00000, 1.00000, 0.00000], [0.14286, 0.00000, 0.00000], [0.28571, 0.00000, 0.00000], [0.42857, 0.00000, 0.00000], [0.57143, 0.00000, 0.00000], [0.71429, 0.00000, 0.00000], [0.85714, 0.00000, 0.00000], [0.85714, 0.14286, -0.02041], [0.71429, 0.28571, 0.02041], [0.57143, 0.42857, -0.02041], [0.42857, 0.57143, 0.02041], [0.28571, 0.71429, -0.02041], [0.14286, 0.85714, 0.02041], [0.00000, 0.85714, 0.02041], [0.00000, 0.71429, -0.02041], [0.00000, 0.57143, 0.02041], [0.00000, 0.42857, -0.02041], [0.00000, 0.28571, 0.02041], [0.00000, 0.14286, -0.02041], [0.14286, 0.14286, -0.02041], [0.71429, 0.14286, -0.02041], [0.14286, 0.71429, -0.02041], [0.28571, 0.14286, -0.02041], [0.42857, 0.14286, -0.02041], [0.57143, 0.14286, -0.02041], [0.57143, 0.28571, 0.02041], [0.42857, 0.42857, -0.02041], [0.28571, 0.57143, 0.02041], [0.14286, 0.57143, 0.02041], [0.14286, 0.42857, -0.02041], [0.14286, 0.28571, 0.02041], [0.28571, 0.28571, 0.02041], [0.42857, 0.28571, 0.02041], [0.28571, 0.42857, -0.02041]]) # Higher order tests are too slow elif order == 8: points = np.array([[0.00000, 0.00000, 0.00000], [1.00000, 0.00000, 0.00000], [0.00000, 1.00000, 0.00000], [0.12500, 0.00000, 0.00000], [0.25000, 0.00000, 0.00000], [0.37500, 0.00000, 0.00000], [0.50000, 0.00000, 0.00000], [0.62500, 0.00000, 0.00000], [0.75000, 0.00000, 0.00000], [0.87500, 0.00000, 0.00000], [0.87500, 0.12500, -0.00195], [0.75000, 0.25000, 0.00195], [0.62500, 0.37500, -0.00195], [0.50000, 0.50000, 0.00195], [0.37500, 0.62500, -0.00195], [0.25000, 0.75000, 0.00195], [0.12500, 0.87500, -0.00195], [0.00000, 0.87500, -0.00195], [0.00000, 0.75000, 0.00195], [0.00000, 0.62500, -0.00195], [0.00000, 0.50000, 0.00195], [0.00000, 0.37500, -0.00195], [0.00000, 0.25000, 0.00195], [0.00000, 0.12500, -0.00195], [0.12500, 0.12500, -0.00195], [0.75000, 0.12500, -0.00195], [0.12500, 0.75000, 0.00195], [0.25000, 0.12500, -0.00195], [0.37500, 0.12500, -0.00195], [0.50000, 0.12500, -0.00195], [0.62500, 0.12500, -0.00195], [0.62500, 0.25000, 0.00195], [0.50000, 0.37500, -0.00195], [0.37500, 0.50000, 0.00195], [0.25000, 0.62500, -0.00195], [0.12500, 0.62500, -0.00195], [0.12500, 0.50000, 0.00195], [0.12500, 0.37500, -0.00195], [0.12500, 0.25000, 0.00195], [0.25000, 0.25000, 0.00195], [0.50000, 0.25000, 0.00195], [0.25000, 0.50000, 0.00195], [0.37500, 0.25000, 0.00195], [0.37500, 0.37500, -0.00195], [0.25000, 0.37500, -0.00195]]) cell = ufl.Cell("triangle", geometric_dimension=points.shape[1]) domain = ufl.Mesh(ufl.VectorElement("Lagrange", cell, order)) mesh = create_mesh(MPI.COMM_WORLD, cells, points, domain) # Find nodes corresponding to y axis nodes = [] for j in range(points.shape[0]): if np.isclose(points[j][0], 0): nodes.append(j) def e2(x): return x[2] + x[0] * x[1] # For solution to be in functionspace V = FunctionSpace(mesh, ("CG", max(2, order))) u = Function(V) u.interpolate(e2) quad_order = 30 intu = assemble_scalar(u * dx(metadata={"quadrature_degree": quad_order})) intu = mesh.mpi_comm().allreduce(intu, op=MPI.SUM) ref = scipy_one_cell(points, nodes) assert ref == pytest.approx(intu, rel=3e-3)
# 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 mesh_2D_dolfin(celltype: str, theta: float = 0): """ Create two 2D cubes stacked on top of each other, and the corresponding mesh markers using dolfin built-in meshes """ def find_line_function(p0, p1): """ Find line y=ax+b for each of the lines in the mesh https://mathworld.wolfram.com/Two-PointForm.html """ # Line aligned with y axis if np.isclose(p1[0], p0[0]): return lambda x: np.isclose(x[0], p0[0]) return lambda x: np.isclose( x[1], p0[1] + (p1[1] - p0[1]) / (p1[0] - p0[0]) * (x[0] - p0[0])) def over_line(p0, p1): """ Check if a point is over or under y=ax+b for each of the lines in the mesh https://mathworld.wolfram.com/Two-PointForm.html """ return lambda x: x[1] > p0[1] + (p1[1] - p0[1]) / (p1[0] - p0[0]) * (x[ 0] - p0[0]) # Using built in meshes, stacking cubes on top of each other N = 15 if celltype == "quadrilateral": ct = _mesh.CellType.quadrilateral elif celltype == "triangle": ct = _mesh.CellType.triangle else: raise ValueError("celltype has to be tri or quad") if MPI.COMM_WORLD.rank == 0: mesh0 = _mesh.create_unit_square(MPI.COMM_SELF, N, N, ct) mesh1 = _mesh.create_unit_square(MPI.COMM_SELF, 2 * N, 2 * N, ct) mesh0.geometry.x[:, 1] += 1 # Stack the two meshes in one mesh r_matrix = _utils.rotation_matrix([0, 0, 1], theta) points = np.vstack([mesh0.geometry.x, mesh1.geometry.x]) points = np.dot(r_matrix, points.T) points = points[:2, :].T # Transform topology info into geometry info tdim0 = mesh0.topology.dim num_cells0 = mesh0.topology.index_map(tdim0).size_local cells0 = _cpp.mesh.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 = _cpp.mesh.entities_to_geometry( mesh1, tdim1, np.arange(num_cells1, dtype=np.int32).reshape((-1, 1)), False) cells1 += mesh0.geometry.x.shape[0] cells = np.vstack([cells0, cells1]) cell = ufl.Cell(celltype, geometric_dimension=points.shape[1]) domain = ufl.Mesh(ufl.VectorElement("Lagrange", cell, 1)) mesh = _mesh.create_mesh(MPI.COMM_SELF, cells, points, domain) 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], [1, 1, 0], [0, 1, 0]]).T) bottom = find_line_function(bottom_points[:, 0], bottom_points[:, 1]) bottom_facets = _mesh.locate_entities_boundary(mesh, fdim, bottom) top_points = np.dot( r_matrix, np.array([[0, 1, 0], [1, 1, 0], [1, 2, 0], [0, 2, 0]]).T) top = find_line_function(top_points[:, 2], top_points[:, 3]) top_facets = _mesh.locate_entities_boundary(mesh, fdim, top) left_side = find_line_function(top_points[:, 0], top_points[:, 3]) left_facets = _mesh.locate_entities_boundary(mesh, fdim, left_side) right_side = find_line_function(top_points[:, 1], top_points[:, 2]) right_facets = _mesh.locate_entities_boundary(mesh, fdim, right_side) top_cube = over_line(bottom_points[:, 2], bottom_points[:, 3]) num_cells = mesh.topology.index_map(tdim).size_local cell_midpoints = _cpp.mesh.compute_midpoints(mesh, tdim, range(num_cells)) interface = find_line_function(bottom_points[:, 2], bottom_points[:, 3]) i_facets = _mesh.locate_entities_boundary(mesh, fdim, interface) bottom_interface = [] top_interface = [] mesh.topology.create_connectivity(fdim, tdim) facet_to_cell = mesh.topology.connectivity(fdim, tdim) 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) top_cube_marker = 2 cell_indices = [] cell_values = [] for cell_index in range(num_cells): if top_cube(cell_midpoints[cell_index]): cell_indices.append(cell_index) cell_values.append(top_cube_marker) ct = _mesh.meshtags(mesh, tdim, np.array(cell_indices, dtype=np.intc), np.array(cell_values, dtype=np.intc)) # Create meshtags for facet data markers: Dict[int, np.ndarray] = { 3: top_facets, 4: np.hstack(bottom_interface), 9: np.hstack(top_interface), 5: bottom_facets, 6: left_facets, 7: right_facets } all_indices = [] all_values = [] for key in markers.keys(): all_indices.append(markers[key]) all_values.append(np.full(len(markers[key]), key, dtype=np.intc)) arg_sort = np.argsort(np.hstack(all_indices)) mt = _mesh.meshtags(mesh, fdim, np.hstack(all_indices)[arg_sort], np.hstack(all_values)[arg_sort]) mt.name = "facet_tags" # type: ignore with _io.XDMFFile(MPI.COMM_SELF, f"meshes/mesh_{celltype}_{theta:.2f}.xdmf", "w") as o_f: o_f.write_mesh(mesh) o_f.write_meshtags(ct) o_f.write_meshtags(mt) MPI.COMM_WORLD.barrier()
def randomly_ordered_mesh(cell_type): """Create a randomly ordered mesh to use in the test.""" random.seed(6) domain = ufl.Mesh(ufl.VectorElement("Lagrange", cell_type, 1)) # Create a mesh if MPI.COMM_WORLD.rank == 0: N = 6 if cell_type == "triangle" or cell_type == "quadrilateral": temp_points = np.array([[x / 2, y / 2] for y in range(N) for x in range(N)]) elif cell_type == "tetrahedron" or cell_type == "hexahedron": temp_points = np.array([[x / 2, y / 2, z / 2] for z in range(N) for y in range(N) for x in range(N)]) order = [i for i, j in enumerate(temp_points)] random.shuffle(order) points = np.zeros(temp_points.shape) for i, j in enumerate(order): points[j] = temp_points[i] if cell_type == "triangle": # Make triangle cells using the randomly ordered points cells = [] for x in range(N - 1): for y in range(N - 1): a = N * y + x # Adds two triangle cells: # a+N -- a+N+1 # | / | # | / | # | / | # a --- a+1 for cell in [[a, a + 1, a + N + 1], [a, a + N + 1, a + N]]: cells.append([order[i] for i in cell]) elif cell_type == "quadrilateral": cells = [] for x in range(N - 1): for y in range(N - 1): a = N * y + x cell = [order[i] for i in [a, a + 1, a + N, a + N + 1]] cells.append(cell) elif cell_type == "tetrahedron": cells = [] for x in range(N - 1): for y in range(N - 1): for z in range(N - 1): a = N**2 * z + N * y + x for c in [ [a + N, a + N**2 + 1, a, a + 1], [a + N, a + N**2 + 1, a + 1, a + N + 1], [a + N, a + N**2 + 1, a + N + 1, a + N**2 + N + 1], [ a + N, a + N**2 + 1, a + N**2 + N + 1, a + N**2 + N ], [a + N, a + N**2 + 1, a + N**2 + N, a + N**2], [a + N, a + N**2 + 1, a + N**2, a] ]: cell = [order[i] for i in c] cells.append(cell) elif cell_type == "hexahedron": cells = [] for x in range(N - 1): for y in range(N - 1): for z in range(N - 1): a = N**2 * z + N * y + x cell = [ order[i] for i in [ a, a + 1, a + N, a + N + 1, a + N**2, a + 1 + N**2, a + N + N**2, a + N + 1 + N**2 ] ] cells.append(cell) # On process 0, input mesh data and distribute to other # processes return create_mesh(MPI.COMM_WORLD, cells, points, domain) else: if cell_type == "triangle": return create_mesh(MPI.COMM_WORLD, np.ndarray((0, 3)), np.ndarray((0, 2)), domain) elif cell_type == "quadrilateral": return create_mesh(MPI.COMM_WORLD, np.ndarray((0, 4)), np.ndarray((0, 2)), domain) elif cell_type == "tetrahedron": return create_mesh(MPI.COMM_WORLD, np.ndarray((0, 4)), np.ndarray((0, 3)), domain) elif cell_type == "hexahedron": return create_mesh(MPI.COMM_WORLD, np.ndarray((0, 8)), np.ndarray((0, 3)), domain)
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
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 DOLFIN-X 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(1 * dx(mesh)) assert mesh.mpi_comm().allreduce(volume, op=MPI.SUM) == pytest.approx( np.pi, rel=10**(-1 - order))
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
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)) n = FacetNormal(mesh) ds = Measure("ds", subdomain_data=mt)
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])
def test_hexahedron_dof_ordering(space_type): """Checks that dofs on shared hexahedron edges match up""" domain = ufl.Mesh(ufl.VectorElement("Lagrange", "hexahedron", 1)) if MPI.COMM_WORLD.rank == 0: N = 5 temp_points = np.array([[x / 2, y / 2, z / 2] for x in range(N) for y in range(N) for z in range(N)]) order = [i for i, j in enumerate(temp_points)] shuffle(order) points = np.zeros(temp_points.shape) for i, j in enumerate(order): points[j] = temp_points[i] cells = [] for x in range(N - 1): for y in range(N - 1): for z in range(N - 1): a = N ** 2 * z + N * y + x cell = [order[i] for i in [a, a + 1, a + N, a + N + 1, a + N ** 2, a + 1 + N ** 2, a + N + N ** 2, a + N + 1 + N ** 2]] cells.append(cell) # On process 0, input mesh data and distribute to other # processes mesh = create_mesh(MPI.COMM_WORLD, cells, points, domain) else: mesh = create_mesh(MPI.COMM_WORLD, np.ndarray((0, 8)), np.ndarray((0, 3)), domain) V = FunctionSpace(mesh, space_type) dofmap = V.dofmap edges = {} faces = {} # Get coordinates of dofs and edges and check that they are the same # for each global dof number X = V.element.dof_reference_coordinates() coord_dofs = mesh.geometry.dofmap x_g = mesh.geometry.x cmap = fem.create_coordinate_map(mesh.ufl_domain()) for cell_n in range(coord_dofs.num_nodes): dofs = dofmap.cell_dofs(cell_n) x_coord_new = np.zeros([8, 3]) for v in range(8): x_coord_new[v] = x_g[coord_dofs.links(cell_n)[v]] x = X.copy() cmap.push_forward(x, X, x_coord_new) edge_dofs_local = [] for i in range(12): edge_dofs_local += list(dofmap.dof_layout.entity_dofs(1, i)) edge_dofs = [dofs[i] for i in edge_dofs_local] for i, j in zip(edge_dofs, x[edge_dofs_local]): if i in edges: assert np.allclose(j, edges[i]) else: edges[i] = j face_dofs_local = [] for i in range(6): face_dofs_local += list(dofmap.dof_layout.entity_dofs(2, i)) face_dofs = [dofs[i] for i in face_dofs_local] for i, j in zip(face_dofs, x[face_dofs_local]): if i in faces: assert np.allclose(j, faces[i]) else: faces[i] = j
def test_triangle_dof_ordering(space_type): """Checks that dofs on shared triangle edges match up""" # Create a mesh domain = ufl.Mesh(ufl.VectorElement("Lagrange", "triangle", 1)) if MPI.COMM_WORLD.rank == 0: N = 6 # Create a grid of points [0, 0.5, ..., 9.5]**2, then order them # in a random order temp_points = np.array([[x / 2, y / 2] for x in range(N) for y in range(N)]) order = [i for i, j in enumerate(temp_points)] shuffle(order) points = np.zeros(temp_points.shape) for i, j in enumerate(order): points[j] = temp_points[i] # Make triangle cells using the randomly ordered points cells = [] for x in range(N - 1): for y in range(N - 1): a = N * y + x # Adds two triangle cells: # a+N -- a+N+1 # | / | # | / | # | / | # a --- a+1 for cell in [[a, a + 1, a + N + 1], [a, a + N + 1, a + N]]: cells.append([order[i] for i in cell]) # On process 0, input mesh data and distribute to other # processes mesh = create_mesh(MPI.COMM_WORLD, cells, points, domain) else: mesh = create_mesh(MPI.COMM_WORLD, np.ndarray((0, 3)), np.ndarray((0, 2)), domain) V = FunctionSpace(mesh, space_type) dofmap = V.dofmap edges = {} # Get coordinates of dofs and edges and check that they are the same # for each global dof number X = V.element.dof_reference_coordinates() coord_dofs = mesh.geometry.dofmap x_g = mesh.geometry.x cmap = fem.create_coordinate_map(mesh.ufl_domain()) for cell_n in range(coord_dofs.num_nodes): dofs = dofmap.cell_dofs(cell_n) x_coord_new = np.zeros([3, 2]) for v in range(3): x_coord_new[v] = x_g[coord_dofs.links(cell_n)[v], :2] x = X.copy() cmap.push_forward(x, X, x_coord_new) edge_dofs_local = [] for i in range(3): edge_dofs_local += list(dofmap.dof_layout.entity_dofs(1, i)) edge_dofs = [dofs[i] for i in edge_dofs_local] for i, j in zip(edge_dofs, x[edge_dofs_local]): if i in edges: assert np.allclose(j, edges[i]) else: edges[i] = j
def xtest_quadrilateral_integral(space_type, space_order): domain = ufl.Mesh(ufl.VectorElement("Lagrange", "quadrilateral", 1)) temp_points = np.array([[-1., -1.], [0., 0.], [1., 0.], [-1., 1.], [0., 1.], [2., 2.]]) for repeat in range(10): order = [i for i, j in enumerate(temp_points)] shuffle(order) points = np.zeros(temp_points.shape) for i, j in enumerate(order): points[j] = temp_points[i] connections = {0: [1, 2], 1: [0, 3], 2: [0, 3], 3: [1, 2]} cells = [] for cell in [[0, 1, 3, 4], [1, 2, 4, 5]]: # Randomly number the cell start = choice(range(4)) cell_order = [start] for i in range(2): diff = choice([ i for i in connections[start] if i not in cell_order ]) - cell_order[0] cell_order += [c + diff for c in cell_order] cells.append([order[cell[i]] for i in cell_order]) mesh = create_mesh(MPI.COMM_WORLD, cells, points, domain) V = FunctionSpace(mesh, (space_type, space_order)) Vvec = VectorFunctionSpace(mesh, ("P", 1)) dofs = [i for i in V.dofmap.cell_dofs(0) if i in V.dofmap.cell_dofs(1)] for d in dofs: v = Function(V) v.vector[:] = [ 1 if i == d else 0 for i in range(v.vector.local_size) ] if space_type in ["RTCF"]: # Hdiv def normal(x): values = np.zeros((2, x.shape[1])) values[0] = [1 for i in values[0]] return values n = Function(Vvec) n.interpolate(normal) form = ufl.inner(ufl.jump(v), n) * ufl.dS elif space_type in ["RTCE"]: # Hcurl def tangent(x): values = np.zeros((2, x.shape[1])) values[1] = [1 for i in values[1]] return values t = Function(Vvec) t.interpolate(tangent) form = ufl.inner(ufl.jump(v), t) * ufl.dS else: form = ufl.jump(v) * ufl.dS value = fem.assemble_scalar(form) assert np.isclose(value, 0)
def random_evaluation_mesh(cell_type): random.seed(6) domain = ufl.Mesh(ufl.VectorElement("Lagrange", cell_type, 1)) if cell_type == "triangle": temp_points = np.array([[-1., -1.], [0., 0.], [1., 0.], [0., 1.]]) temp_cells = [[0, 1, 3], [1, 2, 3]] elif cell_type == "quadrilateral": temp_points = np.array([[-1., -1.], [0., 0.], [1., 0.], [-1., 1.], [0., 1.], [2., 2.]]) temp_cells = [[0, 1, 3, 4], [1, 2, 4, 5]] elif cell_type == "tetrahedron": temp_points = np.array([[-1., 0., -1.], [0., 0., 0.], [1., 0., 1.], [0., 1., 0.], [0., 0., 1.]]) temp_cells = [[0, 1, 3, 4], [1, 2, 3, 4]] elif cell_type == "hexahedron": temp_points = np.array([[-1., 0., -1.], [0., 0., 0.], [1., 0., 1.], [-1., 1., 1.], [0., 1., 0.], [1., 1., 1.], [-1., 0., 0.], [0., 0., 1.], [1., 0., 2.], [-1., 1., 2.], [0., 1., 1.], [1., 1., 2.]]) temp_cells = [[0, 1, 3, 4, 6, 7, 9, 10], [1, 2, 4, 5, 7, 8, 10, 11]] order = [i for i, j in enumerate(temp_points)] random.shuffle(order) points = np.zeros(temp_points.shape) for i, j in enumerate(order): points[j] = temp_points[i] cells = [] for cell in temp_cells: # Randomly number the cell if cell_type == "triangle": cell_order = list(range(3)) random.shuffle(cell_order) elif cell_type == "quadrilateral": connections = {0: [1, 2], 1: [0, 3], 2: [0, 3], 3: [1, 2]} start = random.choice(range(4)) cell_order = [start] for i in range(2): diff = random.choice([ i for i in connections[start] if i not in cell_order ]) - cell_order[0] cell_order += [c + diff for c in cell_order] elif cell_type == "tetrahedron": cell_order = list(range(4)) random.shuffle(cell_order) elif cell_type == "hexahedron": connections = { 0: [1, 2, 4], 1: [0, 3, 5], 2: [0, 3, 6], 3: [1, 2, 7], 4: [0, 5, 6], 5: [1, 4, 7], 6: [2, 4, 7], 7: [3, 5, 6] } start = random.choice(range(8)) cell_order = [start] for i in range(3): diff = random.choice([ i for i in connections[start] if i not in cell_order ]) - cell_order[0] cell_order += [c + diff for c in cell_order] cells.append([order[cell[i]] for i in cell_order]) return create_mesh(MPI.COMM_WORLD, cells, points, domain)
def xtest_tetrahedron_integral(space_type, space_order): domain = ufl.Mesh(ufl.VectorElement("Lagrange", "tetrahedron", 1)) temp_points = np.array([[-1., 0., -1.], [0., 0., 0.], [1., 0., 1.], [0., 1., 0.], [0., 0., 1.]]) for repeat in range(10): order = [i for i, j in enumerate(temp_points)] shuffle(order) points = np.zeros(temp_points.shape) for i, j in enumerate(order): points[j] = temp_points[i] cells = [] for cell in [[0, 1, 3, 4], [1, 2, 3, 4]]: # Randomly number the cell cell_order = list(range(4)) shuffle(cell_order) cells.append([order[cell[i]] for i in cell_order]) mesh = create_mesh(MPI.COMM_WORLD, cells, points, domain) V = FunctionSpace(mesh, (space_type, space_order)) Vvec = VectorFunctionSpace(mesh, ("P", 1)) dofs = [i for i in V.dofmap.cell_dofs(0) if i in V.dofmap.cell_dofs(1)] for d in dofs: v = Function(V) v.vector[:] = [ 1 if i == d else 0 for i in range(v.vector.local_size) ] if space_type in ["RT", "BDM"]: # Hdiv def normal(x): values = np.zeros((3, x.shape[1])) values[0] = [1 for i in values[0]] return values n = Function(Vvec) n.interpolate(normal) form = ufl.inner(ufl.jump(v), n) * ufl.dS elif space_type in ["N1curl", "N2curl"]: # Hcurl def tangent1(x): values = np.zeros((3, x.shape[1])) values[1] = [1 for i in values[1]] return values def tangent2(x): values = np.zeros((3, x.shape[1])) values[2] = [1 for i in values[2]] return values t1 = Function(Vvec) t1.interpolate(tangent1) t2 = Function(Vvec) t2.interpolate(tangent1) form = ufl.inner(ufl.jump(v), t1) * ufl.dS form += ufl.inner(ufl.jump(v), t2) * ufl.dS else: form = ufl.jump(v) * ufl.dS value = fem.assemble_scalar(form) assert np.isclose(value, 0)
def test_volume_quadrilateralR3(coordinates): x = numpy.array(coordinates, dtype=numpy.float64) cells = numpy.array([[0, 1, 2, 3]], dtype=numpy.int32) domain = ufl.Mesh(ufl.VectorElement("Lagrange", "quadrilateral", 1)) mesh = create_mesh(MPI.COMM_SELF, cells, x, domain) assert cpp.mesh.volume_entities(mesh, [0], mesh.topology.dim) == 1.0
def test_hexahedron_evaluation(space_type, space_order): if space_type == "NCF" and space_order >= 3: print("Eval in this space not supported yet") return if space_type == "NCE" and space_order >= 2: print("Eval in this space not supported yet") return domain = ufl.Mesh(ufl.VectorElement("Lagrange", "hexahedron", 1)) temp_points = np.array([[-1., 0., -1.], [0., 0., 0.], [1., 0., 1.], [-1., 1., 1.], [0., 1., 0.], [1., 1., 1.], [-1., 0., 0.], [0., 0., 1.], [1., 0., 2.], [-1., 1., 2.], [0., 1., 1.], [1., 1., 2.]]) for repeat in range(10): order = [i for i, j in enumerate(temp_points)] shuffle(order) points = np.zeros(temp_points.shape) for i, j in enumerate(order): points[j] = temp_points[i] connections = { 0: [1, 2, 4], 1: [0, 3, 5], 2: [0, 3, 6], 3: [1, 2, 7], 4: [0, 5, 6], 5: [1, 4, 7], 6: [2, 4, 7], 7: [3, 5, 6] } cells = [] for cell in [[0, 1, 3, 4, 6, 7, 9, 10], [1, 2, 4, 5, 7, 8, 10, 11]]: # Randomly number the cell start = choice(range(8)) cell_order = [start] for i in range(3): diff = choice([ i for i in connections[start] if i not in cell_order ]) - cell_order[0] cell_order += [c + diff for c in cell_order] cells.append([order[cell[i]] for i in cell_order]) mesh = create_mesh(MPI.COMM_WORLD, cells, points, domain) V = FunctionSpace(mesh, (space_type, space_order)) dofs = [i for i in V.dofmap.cell_dofs(0) if i in V.dofmap.cell_dofs(1)] N = 6 eval_points = np.array([[0., i / N, j / N] for i in range(N + 1) for j in range(N + 1)]) for d in dofs: v = Function(V) v.vector[:] = [1 if i == d else 0 for i in range(V.dim)] values0 = v.eval(eval_points, [0 for i in eval_points]) values1 = v.eval(eval_points, [1 for i in eval_points]) if len(eval_points) == 1: values0 = [values0] values1 = [values1] if space_type == "NCF": # Hdiv for i, j in zip(values0, values1): assert np.isclose(i[0], j[0]) elif space_type == "NCE": # Hcurl for i, j in zip(values0, values1): assert np.allclose(i[1:], j[1:]) else: assert np.allclose(values0, values1)
def mesh_3D_dolfin(theta: float = 0, ct: _mesh.CellType = _mesh.CellType.tetrahedron, ext: str = "tetrahedron", res: float = 0.1): timer = _common.Timer("~~Contact: 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] N = int(1 / res) if MPI.COMM_WORLD.rank == 0: mesh0 = _mesh.create_unit_cube(MPI.COMM_SELF, N, N, N, ct) mesh1 = _mesh.create_unit_cube(MPI.COMM_SELF, 2 * N, 2 * N, 2 * N, ct) mesh0.geometry.x[:, 2] += 1 # Stack the two meshes in one mesh r_matrix = _utils.rotation_matrix([1 / np.sqrt(2), 1 / np.sqrt(2), 0], -theta) points = np.vstack([mesh0.geometry.x, mesh1.geometry.x]) points = np.dot(r_matrix, points.T).T # Transform topology info into geometry info tdim0 = mesh0.topology.dim num_cells0 = mesh0.topology.index_map(tdim0).size_local cells0 = _cpp.mesh.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 = _cpp.mesh.entities_to_geometry( mesh1, tdim1, np.arange(num_cells1, dtype=np.int32).reshape((-1, 1)), False) cells1 += mesh0.geometry.x.shape[0] cells = np.vstack([cells0, cells1]) cell = ufl.Cell(ext, geometric_dimension=points.shape[1]) domain = ufl.Mesh(ufl.VectorElement("Lagrange", cell, 1)) mesh = _mesh.create_mesh(MPI.COMM_SELF, cells, points, domain) 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 = _mesh.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 = _mesh.locate_entities_boundary(mesh, fdim, top) # left_side = find_line_function(top_points[:, 0], top_points[:, 3]) # left_facets = _mesh.locate_entities_boundary( # mesh, fdim, left_side) # right_side = find_line_function(top_points[:, 1], top_points[:, 2]) # right_facets = _mesh.locate_entities_boundary( # mesh, fdim, right_side) 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 = _mesh.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 cell_midpoints = _cpp.mesh.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) num_cells = mesh.topology.index_map(tdim).size_local cell_midpoints = _cpp.mesh.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 = _mesh.meshtags(mesh, tdim, np.array(indices, dtype=np.int32), np.array(values, dtype=np.int32)) # Create meshtags for facet data markers: Dict[int, np.ndarray] = { 3: top_facets, 4: np.hstack(bottom_interface), 9: np.hstack(top_interface), 5: bottom_facets } # , 6: left_facets, 7: right_facets} all_indices = [] all_values = [] for key in markers.keys(): all_indices.append(np.asarray(markers[key], dtype=np.int32)) all_values.append(np.full(len(markers[key]), key, dtype=np.int32)) arg_sort = np.argsort(np.hstack(all_indices)) sorted_vals = np.asarray(np.hstack(all_values)[arg_sort], dtype=np.int32) sorted_indices = np.asarray(np.hstack(all_indices)[arg_sort], dtype=np.int32) mt = _mesh.meshtags(mesh, fdim, sorted_indices, sorted_vals) mt.name = "facet_tags" # type: ignore fname = f"meshes/mesh_{ext}_{theta:.2f}.xdmf" with _io.XDMFFile(MPI.COMM_SELF, fname, "w") as o_f: o_f.write_mesh(mesh) o_f.write_meshtags(ct) o_f.write_meshtags(mt) timer.stop()
def xtest_hexahedron_integral(space_type, space_order): domain = ufl.Mesh(ufl.VectorElement("Lagrange", "hexahedron", 1)) temp_points = np.array([[-1., 0., -1.], [0., 0., 0.], [1., 0., 1.], [-1., 1., 1.], [0., 1., 0.], [1., 1., 1.], [-1., 0., 0.], [0., 0., 1.], [1., 0., 2.], [-1., 1., 2.], [0., 1., 1.], [1., 1., 2.]]) for repeat in range(10): order = [i for i, j in enumerate(temp_points)] shuffle(order) points = np.zeros(temp_points.shape) for i, j in enumerate(order): points[j] = temp_points[i] connections = { 0: [1, 2, 4], 1: [0, 3, 5], 2: [0, 3, 6], 3: [1, 2, 7], 4: [0, 5, 6], 5: [1, 4, 7], 6: [2, 4, 7], 7: [3, 5, 6] } cells = [] for cell in [[0, 1, 3, 4, 6, 7, 9, 10], [1, 2, 4, 5, 7, 8, 10, 11]]: # Randomly number the cell start = choice(range(8)) cell_order = [start] for i in range(3): diff = choice([ i for i in connections[start] if i not in cell_order ]) - cell_order[0] cell_order += [c + diff for c in cell_order] cells.append([order[cell[i]] for i in cell_order]) mesh = create_mesh(MPI.COMM_WORLD, cells, points, domain) V = FunctionSpace(mesh, (space_type, space_order)) Vvec = VectorFunctionSpace(mesh, ("P", 1)) dofs = [i for i in V.dofmap.cell_dofs(0) if i in V.dofmap.cell_dofs(1)] for d in dofs: v = Function(V) v.vector[:] = [1 if i == d else 0 for i in range(V.dim)] if space_type in ["NCF"]: # Hdiv def normal(x): values = np.zeros((3, x.shape[1])) values[0] = [1 for i in values[0]] return values n = Function(Vvec) n.interpolate(normal) form = ufl.inner(ufl.jump(v), n) * ufl.dS elif space_type in ["NCE"]: # Hcurl def tangent1(x): values = np.zeros((3, x.shape[1])) values[1] = [1 for i in values[1]] return values def tangent2(x): values = np.zeros((3, x.shape[1])) values[2] = [1 for i in values[2]] return values t1 = Function(Vvec) t1.interpolate(tangent1) t2 = Function(Vvec) t2.interpolate(tangent1) form = ufl.inner(ufl.jump(v), t1) * ufl.dS form += ufl.inner(ufl.jump(v), t2) * ufl.dS else: form = ufl.jump(v) * ufl.dS value = fem.assemble_scalar(form) assert np.isclose(value, 0)
def test_fourth_order_tri(): L = 1 # *--*--*--*--* 3-21-20-19--2 # | \ | | \ | # * * * * * 10 9 24 23 18 # | \ | | \ | # * * * * * 11 15 8 22 17 # | \ | | \ | # * * * * * 12 13 14 7 16 # | \ | | \ | # *--*--*--*--* 0--4--5--6--1 for H in (1.0, 2.0): for Z in (0.0, 0.5): points = np.array([ [0, 0, 0], [L, 0, 0], [L, H, Z], [0, H, Z], # 0, 1, 2, 3 [L / 4, 0, 0], [L / 2, 0, 0], [3 * L / 4, 0, 0], # 4, 5, 6 [3 / 4 * L, H / 4, Z / 2], [L / 2, H / 2, 0], # 7, 8 [L / 4, 3 * H / 4, 0], [0, 3 * H / 4, 0], # 9, 10 [0, H / 2, 0], [0, H / 4, Z / 2], # 11, 12 [L / 4, H / 4, Z / 2], [L / 2, H / 4, Z / 2], [L / 4, H / 2, 0], # 13, 14, 15 [L, H / 4, Z / 2], [L, H / 2, 0], [L, 3 * H / 4, 0], # 16, 17, 18 [3 * L / 4, H, Z], [L / 2, H, Z], [L / 4, H, Z], # 19, 20, 21 [3 * L / 4, H / 2, 0], [3 * L / 4, 3 * H / 4, 0], # 22, 23 [L / 2, 3 * H / 4, 0] ] # 24 ) cells = np.array( [[0, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], [1, 2, 3, 16, 17, 18, 19, 20, 21, 9, 8, 7, 22, 23, 24]]) cells = cells[:, perm_vtk(CellType.triangle, cells.shape[1])] cell = ufl.Cell("triangle", geometric_dimension=points.shape[1]) domain = ufl.Mesh(ufl.VectorElement("Lagrange", cell, 4)) mesh = create_mesh(MPI.COMM_WORLD, cells, points, domain) def e2(x): return x[2] + x[0] * x[1] # Interpolate function V = FunctionSpace(mesh, ("Lagrange", 4)) u = Function(V) u.interpolate(e2) intu = assemble_scalar(u * dx(metadata={"quadrature_degree": 50})) intu = mesh.mpi_comm().allreduce(intu, op=MPI.SUM) nodes = [0, 3, 10, 11, 12] ref = sympy_scipy(points, nodes, L, H) assert ref == pytest.approx(intu, rel=1e-4)
def test_curl(space_type, order): """Test that curl is consistent for different cell permutations of a tetrahedron.""" tdim = cpp.mesh.cell_dim(CellType.tetrahedron) points = unit_cell_points(CellType.tetrahedron) spaces = [] results = [] cell = list(range(len(points))) random.seed(2) # Assemble vector on 5 randomly numbered cells for i in range(5): random.shuffle(cell) domain = ufl.Mesh( ufl.VectorElement("Lagrange", cpp.mesh.to_string(CellType.tetrahedron), 1)) mesh = create_mesh(MPI.COMM_WORLD, [cell], points, domain) V = FunctionSpace(mesh, (space_type, order)) v = ufl.TestFunction(V) f = ufl.as_vector(tuple(1 if i == 0 else 0 for i in range(tdim))) form = ufl.inner(f, ufl.curl(v)) * ufl.dx result = fem.assemble_vector(form) spaces.append(V) results.append(result.array) # Set data for first space V0 = spaces[0] c10_0 = V.mesh.topology.connectivity(1, 0) # Check that all DOFs on edges agree # Loop over cell edges for i, edge in enumerate(V0.mesh.topology.connectivity(tdim, 1).links(0)): # Get the edge vertices vertices0 = c10_0.links(edge) # Need to map back # Get assembled values on edge values0 = sorted([ result[V0.dofmap.cell_dofs(0)[a]] for a in V0.dofmap.dof_layout.entity_dofs(1, i) ]) for V, result in zip(spaces[1:], results[1:]): # Get edge->vertex connectivity c10 = V.mesh.topology.connectivity(1, 0) # Loop over cell edges for j, e in enumerate( V.mesh.topology.connectivity(tdim, 1).links(0)): if sorted(c10.links(e)) == sorted( vertices0): # need to map back c.links(e) values = sorted([ result[V.dofmap.cell_dofs(0)[a]] for a in V.dofmap.dof_layout.entity_dofs(1, j) ]) assert np.allclose(values0, values) break else: continue break
def two_unit_cells(cell_type, agree=False, random_order=True, return_order=False): if cell_type == CellType.interval: points = np.array([[0.], [1.], [-1.]]) if agree: cells = [[0, 1], [2, 0]] else: cells = [[0, 1], [0, 2]] if cell_type == CellType.triangle: # Define equilateral triangles with area 1 root = 3**0.25 # 4th root of 3 points = np.array([[0., 0.], [2 / root, 0.], [1 / root, root], [1 / root, -root]]) if agree: cells = [[0, 1, 2], [0, 3, 1]] else: cells = [[0, 1, 2], [1, 0, 3]] elif cell_type == CellType.tetrahedron: # Define regular tetrahedra with volume 1 s = 2**0.5 * 3**(1 / 3) # side length points = np.array([[0., 0., 0.], [s, 0., 0.], [s / 2, s * np.sqrt(3) / 2, 0.], [s / 2, s / 2 / np.sqrt(3), s * np.sqrt(2 / 3)], [s / 2, s / 2 / np.sqrt(3), -s * np.sqrt(2 / 3)]]) if agree: cells = [[0, 1, 2, 3], [0, 1, 4, 2]] else: cells = [[0, 1, 2, 3], [0, 2, 1, 4]] elif cell_type == CellType.quadrilateral: # Define unit quadrilaterals (area 1) points = np.array([[0., 0.], [1., 0.], [0., 1.], [1., 1.], [0., -1.], [1., -1.]]) if agree: cells = [[0, 1, 2, 3], [4, 5, 0, 1]] else: cells = [[0, 1, 2, 3], [5, 1, 4, 0]] elif cell_type == CellType.hexahedron: # Define unit hexahedra (volume 1) points = np.array([[0., 0., 0.], [1., 0., 0.], [0., 1., 0.], [1., 1., 0.], [0., 0., 1.], [1., 0., 1.], [0., 1., 1.], [1., 1., 1.], [0., 0., -1.], [1., 0., -1.], [0., 1., -1.], [1., 1., -1.]]) if agree: cells = [[0, 1, 2, 3, 4, 5, 6, 7], [8, 9, 10, 11, 0, 1, 2, 3]] else: cells = [[0, 1, 2, 3, 4, 5, 6, 7], [9, 11, 8, 10, 1, 3, 0, 2]] num_points = len(points) # Randomly number the points and create the mesh order = list(range(num_points)) if random_order: random.shuffle(order) ordered_points = np.zeros(points.shape) for i, j in enumerate(order): ordered_points[j] = points[i] ordered_cells = np.array([[order[i] for i in c] for c in cells]) domain = ufl.Mesh( ufl.VectorElement("Lagrange", cpp.mesh.to_string(cell_type), 1)) mesh = create_mesh(MPI.COMM_WORLD, ordered_cells, ordered_points, domain) if return_order: return mesh, order return mesh
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 test_fourth_order_quad(L, H, Z): """Test by comparing integration of z+x*y against sympy/scipy integration of a quad element. Z>0 implies curved element. *---------* 20-21-22-23-24-41--42--43--44 | | | | | | | 15 16 17 18 19 37 38 39 40 | | | | | | | 10 11 12 13 14 33 34 35 36 | | | | | | | 5 6 7 8 9 29 30 31 32 | | | | | *---------* 0--1--2--3--4--25--26--27--28 """ points = np.array([ [0, 0, 0], [L / 4, 0, 0], [L / 2, 0, 0], # 0 1 2 [3 * L / 4, 0, 0], [L, 0, 0], # 3 4 [0, H / 4, -Z / 3], [L / 4, H / 4, -Z / 3], [L / 2, H / 4, -Z / 3], # 5 6 7 [3 * L / 4, H / 4, -Z / 3], [L, H / 4, -Z / 3], # 8 9 [0, H / 2, 0], [L / 4, H / 2, 0], [L / 2, H / 2, 0], # 10 11 12 [3 * L / 4, H / 2, 0], [L, H / 2, 0], # 13 14 [0, (3 / 4) * H, 0], [L / 4, (3 / 4) * H, 0], # 15 16 [L / 2, (3 / 4) * H, 0], [3 * L / 4, (3 / 4) * H, 0], # 17 18 [L, (3 / 4) * H, 0], [0, H, Z], [L / 4, H, Z], # 19 20 21 [L / 2, H, Z], [3 * L / 4, H, Z], [L, H, Z], # 22 23 24 [(5 / 4) * L, 0, 0], [(6 / 4) * L, 0, 0], # 25 26 [(7 / 4) * L, 0, 0], [2 * L, 0, 0], # 27 28 [(5 / 4) * L, H / 4, -Z / 3], [(6 / 4) * L, H / 4, -Z / 3], # 29 30 [(7 / 4) * L, H / 4, -Z / 3], [2 * L, H / 4, -Z / 3], # 31 32 [(5 / 4) * L, H / 2, 0], [(6 / 4) * L, H / 2, 0], # 33 34 [(7 / 4) * L, H / 2, 0], [2 * L, H / 2, 0], # 35 36 [(5 / 4) * L, 3 / 4 * H, 0], # 37 [(6 / 4) * L, 3 / 4 * H, 0], # 38 [(7 / 4) * L, 3 / 4 * H, 0], [2 * L, 3 / 4 * H, 0], # 39 40 [(5 / 4) * L, H, Z], [(6 / 4) * L, H, Z], # 41 42 [(7 / 4) * L, H, Z], [2 * L, H, Z] ]) # 43 44 # VTK ordering cells = np.array([[ 0, 4, 24, 20, 1, 2, 3, 9, 14, 19, 21, 22, 23, 5, 10, 15, 6, 7, 8, 11, 12, 13, 16, 17, 18 ], [ 4, 28, 44, 24, 25, 26, 27, 32, 36, 40, 41, 42, 43, 9, 14, 19, 29, 30, 31, 33, 34, 35, 37, 38, 39 ]]) cells = cells[:, perm_vtk(CellType.quadrilateral, cells.shape[1])] cell = ufl.Cell("quadrilateral", geometric_dimension=points.shape[1]) domain = ufl.Mesh(ufl.VectorElement("Lagrange", cell, 4)) mesh = create_mesh(MPI.COMM_WORLD, cells, points, domain) def e2(x): return x[2] + x[0] * x[1] V = FunctionSpace(mesh, ("CG", 4)) u = Function(V) u.interpolate(e2) intu = assemble_scalar(u * dx(mesh)) intu = mesh.mpi_comm().allreduce(intu, op=MPI.SUM) nodes = [0, 5, 10, 15, 20] ref = sympy_scipy(points, nodes, 2 * L, H) assert ref == pytest.approx(intu, rel=1e-5)
def test_volume_quadrilateralR3(x): cells = [[0, 1, 2, 3]] domain = ufl.Mesh(ufl.VectorElement("Lagrange", "quadrilateral", 1)) mesh = create_mesh(MPI.COMM_SELF, cells, x, domain) assert _cpp.mesh.volume_entities(mesh, [0], mesh.topology.dim) == 1.0