def merge_meshtags(mts, dim): """ Merge multiple MeshTags into one. Parameters ---------- mts: List of meshtags dim: Dimension of MeshTags which should be merged. Note it is not possible to merge MeshTags with different dimensions into one MeshTags object. """ mts = [(mt, name) for name, mt in mts.items() if mt.dim == dim] if len(mts) == 0: raise RuntimeError(f"Cannot find MeshTags of dimension {dim}") indices = numpy.hstack([mt.indices for mt, name in mts]) values = numpy.hstack([mt.values for mt, name in mts]) keys = {} for mt, name in mts: comm = mt.mesh.comm # In some cases this process could receive a MeshTags which are empty # We need to return correct "keys" mapping on each process, so this # communicates the value from processes which don't have empty meshtags if len(mt.values) == 0: value = -1 else: if numpy.max(mt.values) < 0: raise RuntimeError("Not expecting negative values for MeshTags") value = int(mt.values[0]) value = comm.allreduce(value, op=MPI.MAX) keys[name] = value indices, pos = numpy.unique(indices, return_index=True) mt = meshtags(mts[0][0].mesh, dim, indices, values[pos]) return mt, keys
def test_facet_integral(cell_type): """Test that the integral of a function over a facet is correct""" for count in range(5): mesh = unit_cell(cell_type) tdim = mesh.topology.dim V = FunctionSpace(mesh, ("Lagrange", 2)) v = Function(V) mesh.topology.create_entities(tdim - 1) map_f = mesh.topology.index_map(tdim - 1) num_facets = map_f.size_local + map_f.num_ghosts indices = np.arange(0, num_facets) values = np.arange(0, num_facets, dtype=np.intc) marker = meshtags(mesh, tdim - 1, indices, values) # Functions that will have the same integral over each facet if cell_type == CellType.triangle: root = 3**0.25 # 4th root of 3 v.interpolate(lambda x: (x[0] - 1 / root)**2 + (x[1] - root / 3)**2) elif cell_type == CellType.quadrilateral: v.interpolate(lambda x: x[0] * (1 - x[0]) + x[1] * (1 - x[1])) elif cell_type == CellType.tetrahedron: s = 2**0.5 * 3**(1 / 3) # side length v.interpolate(lambda x: (x[0] - s / 2)**2 + (x[1] - s / 2 / np.sqrt(3))**2 + (x[2] - s * np.sqrt(2 / 3) / 4)**2) elif cell_type == CellType.hexahedron: v.interpolate(lambda x: x[0] * (1 - x[0]) + x[1] * (1 - x[1]) + x[2] * (1 - x[2])) # assert that the integral of these functions over each face are # equal out = [] for j in range(num_facets): a = form(v * ufl.ds(subdomain_data=marker, subdomain_id=j)) result = assemble_scalar(a) out.append(result) assert np.isclose(result, out[0])
def test_surface_integrals(get_assemblers): # noqa: F811 assemble_matrix, assemble_vector = get_assemblers N = 4 mesh = create_unit_square(MPI.COMM_WORLD, N, N) V = fem.VectorFunctionSpace(mesh, ("Lagrange", 1)) # Fixed Dirichlet BC on the left wall def left_wall(x): return np.isclose(x[0], np.finfo(float).eps) fdim = mesh.topology.dim - 1 left_facets = locate_entities_boundary(mesh, fdim, left_wall) bc_dofs = fem.locate_dofs_topological(V, 1, left_facets) u_bc = fem.Function(V) with u_bc.vector.localForm() as u_local: u_local.set(0.0) bc = fem.dirichletbc(u_bc, bc_dofs) bcs = [bc] # Traction on top of domain def top(x): return np.isclose(x[1], 1) top_facets = locate_entities_boundary(mesh, 1, top) arg_sort = np.argsort(top_facets) mt = meshtags(mesh, fdim, top_facets[arg_sort], np.full(len(top_facets), 3, dtype=np.int32)) ds = ufl.Measure("ds", domain=mesh, subdomain_data=mt, subdomain_id=3) g = fem.Constant(mesh, PETSc.ScalarType((0, -9.81e2))) # Elasticity parameters E = PETSc.ScalarType(1.0e4) nu = 0.0 mu = fem.Constant(mesh, E / (2.0 * (1.0 + nu))) lmbda = fem.Constant(mesh, E * nu / ((1.0 + nu) * (1.0 - 2.0 * nu))) # Stress computation def sigma(v): return (2.0 * mu * ufl.sym(ufl.grad(v)) + lmbda * ufl.tr(ufl.sym(ufl.grad(v))) * ufl.Identity(len(v))) # Define variational problem u = ufl.TrialFunction(V) v = ufl.TestFunction(V) a = ufl.inner(sigma(u), ufl.grad(v)) * ufl.dx rhs = ufl.inner(fem.Constant(mesh, PETSc.ScalarType((0, 0))), v) * ufl.dx\ + ufl.inner(g, v) * ds bilinear_form = fem.form(a) linear_form = fem.form(rhs) # Setup LU solver solver = PETSc.KSP().create(MPI.COMM_WORLD) solver.setType(PETSc.KSP.Type.PREONLY) solver.getPC().setType(PETSc.PC.Type.LU) # Setup multipointconstraint def l2b(li): return np.array(li, dtype=np.float64).tobytes() s_m_c = {} for i in range(1, N): s_m_c[l2b([1, i / N])] = {l2b([1, 1]): 0.8} mpc = dolfinx_mpc.MultiPointConstraint(V) mpc.create_general_constraint(s_m_c, 1, 1) mpc.finalize() with Timer("~TEST: Assemble matrix old"): A = assemble_matrix(bilinear_form, mpc, bcs=bcs) with Timer("~TEST: Assemble vector"): b = assemble_vector(linear_form, mpc) dolfinx_mpc.apply_lifting(b, [bilinear_form], [bcs], mpc) b.ghostUpdate(addv=PETSc.InsertMode.ADD_VALUES, mode=PETSc.ScatterMode.REVERSE) fem.petsc.set_bc(b, bcs) solver.setOperators(A) uh = b.copy() uh.set(0) solver.solve(b, uh) uh.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) mpc.backsubstitution(uh) # Write solution to file # u_h = dolfinx.Function(mpc.function_space) # u_h.vector.setArray(uh.array) # u_h.name = "u_mpc" # outfile = dolfinx.io.XDMFFile(MPI.COMM_WORLD, "output/uh.xdmf", "w") # outfile.write_mesh(mesh) # outfile.write_function(u_h) # outfile.close() # Solve the MPC problem using a global transformation matrix # and numpy solvers to get reference values # Generate reference matrices and unconstrained solution A_org = fem.petsc.assemble_matrix(bilinear_form, bcs) A_org.assemble() L_org = fem.petsc.assemble_vector(linear_form) fem.petsc.apply_lifting(L_org, [bilinear_form], [bcs]) L_org.ghostUpdate(addv=PETSc.InsertMode.ADD_VALUES, mode=PETSc.ScatterMode.REVERSE) fem.petsc.set_bc(L_org, bcs) root = 0 comm = mesh.comm with Timer("~TEST: Compare"): dolfinx_mpc.utils.compare_mpc_lhs(A_org, A, mpc, root=root) dolfinx_mpc.utils.compare_mpc_rhs(L_org, b, mpc, root=root) # Gather LHS, RHS and solution on one process A_csr = dolfinx_mpc.utils.gather_PETScMatrix(A_org, root=root) K = dolfinx_mpc.utils.gather_transformation_matrix(mpc, root=root) L_np = dolfinx_mpc.utils.gather_PETScVector(L_org, root=root) u_mpc = dolfinx_mpc.utils.gather_PETScVector(uh, root=root) if MPI.COMM_WORLD.rank == root: KTAK = K.T * A_csr * K reduced_L = K.T @ L_np # Solve linear system d = scipy.sparse.linalg.spsolve(KTAK, reduced_L) # Back substitution to full solution vector uh_numpy = K @ d assert np.allclose(uh_numpy, u_mpc) list_timings(comm, [TimingType.wall])
fdim = mesh.topology.dim - 1 facets = locate_entities_boundary(mesh, fdim, dirichletboundary) topological_dofs = fem.locate_dofs_topological(V, fdim, facets) bc = fem.dirichletbc(u_bc, topological_dofs) bcs = [bc] def periodicboundary(x): return np.isclose(x[0], 1) facets = locate_entities_boundary(mesh, fdim, periodicboundary) arg_sort = np.argsort(facets) mt = meshtags(mesh, fdim, facets[arg_sort], np.full(len(facets), 2, dtype=np.int32)) def periodic_relation(x): out_x = np.zeros(x.shape) out_x[0] = 1 - x[0] out_x[1] = x[1] out_x[2] = x[2] return out_x mpc = MultiPointConstraint(V) mpc.create_periodic_constraint_topological(V, mt, 2, periodic_relation, bcs) mpc.finalize() # Define variational problem u = TrialFunction(V)
def plot_higher_order(): msh = create_unit_square(MPI.COMM_WORLD, 12, 12, cell_type=CellType.quadrilateral) # We continue using the mesh from the previous section, and find all # cells satisfying the condition below def in_circle(x): """Mark sphere with radius < sqrt(2)""" return np.array((x.T[0] - 0.5)**2 + (x.T[1] - 0.5)**2 < 0.2**2, dtype=np.int32) # Create a dolfinx.MeshTag for all cells. If midpoint is inside the # circle, it gets value 1, otherwise 0. num_cells = msh.topology.index_map(msh.topology.dim).size_local midpoints = compute_midpoints(msh, msh.topology.dim, list(np.arange(num_cells, dtype=np.int32))) cell_tags = meshtags(msh, msh.topology.dim, np.arange(num_cells), in_circle(midpoints)) # We start by interpolating a discontinuous function into a second order # discontinuous Lagrange space Note that we use the `cell_tags` from # the previous section to get the cells for each of the regions cells0 = cell_tags.indices[cell_tags.values == 0] cells1 = cell_tags.indices[cell_tags.values == 1] V = FunctionSpace(msh, ("Discontinuous Lagrange", 2)) u = Function(V, dtype=np.float64) u.interpolate(lambda x: x[0], cells0) u.interpolate(lambda x: x[1] + 1, cells1) # To get a topology that has a 1-1 correspondence with the # degrees-of-freedom in the function space, we call # `dolfinx.plot.create_vtk_mesh`. cells, types, x = plot.create_vtk_mesh(V) # Create a pyvista mesh from the topology and geometry, and attach # the coefficients of the degrees of freedom grid = pyvista.UnstructuredGrid(cells, types, x) grid.point_data["u"] = u.x.array grid.set_active_scalars("u") # We would also like to visualize the underlying mesh and obtain # that as we have done previously num_cells = msh.topology.index_map(msh.topology.dim).size_local cell_entities = np.arange(num_cells, dtype=np.int32) cells, types, x = plot.create_vtk_mesh(msh, msh.topology.dim, cell_entities) org_grid = pyvista.UnstructuredGrid(cells, types, x) # We visualize the data plotter = pyvista.Plotter() plotter.add_text("Second-order (P2) discontinuous elements", position="upper_edge", font_size=14, color="black") sargs = dict(height=0.1, width=0.8, vertical=False, position_x=0.1, position_y=0, color="black") plotter.add_mesh(grid, show_edges=False, scalar_bar_args=sargs, line_width=0) plotter.add_mesh(org_grid, color="white", style="wireframe", line_width=5) plotter.add_mesh(grid.copy(), style="points", point_size=15, render_points_as_spheres=True, line_width=0) plotter.view_xy() if pyvista.OFF_SCREEN: plotter.screenshot(f"DG_{MPI.COMM_WORLD.rank}.png", transparent_background=transparent, window_size=[figsize, figsize]) else: plotter.show()
def test_surface_integral_dependency(get_assemblers): # noqa: F811 assemble_matrix, assemble_vector = get_assemblers N = 10 mesh = create_unit_square(MPI.COMM_WORLD, N, N) V = fem.VectorFunctionSpace(mesh, ("Lagrange", 1)) def top(x): return np.isclose(x[1], 1) fdim = mesh.topology.dim - 1 top_facets = locate_entities_boundary(mesh, fdim, top) indices = np.array([], dtype=np.intc) values = np.array([], dtype=np.intc) markers = {3: top_facets} for key in markers.keys(): indices = np.append(indices, markers[key]) values = np.append(values, np.full(len(markers[key]), key, dtype=np.intc)) sort = np.argsort(indices) mt = meshtags(mesh, mesh.topology.dim - 1, np.array(indices[sort], dtype=np.intc), np.array(values[sort], dtype=np.intc)) ds = ufl.Measure("ds", domain=mesh, subdomain_data=mt) g = fem.Constant(mesh, PETSc.ScalarType((2, 1))) h = fem.Constant(mesh, PETSc.ScalarType((3, 2))) # Define variational problem u = ufl.TrialFunction(V) v = ufl.TestFunction(V) a = ufl.inner(u, v) * ds(3) + ufl.inner(ufl.grad(u), ufl.grad(v)) * ds rhs = ufl.inner(g, v) * ds + ufl.inner(h, v) * ds(3) bilinear_form = fem.form(a) linear_form = fem.form(rhs) # Create multipoint constraint and assemble system def l2b(li): return np.array(li, dtype=np.float64).tobytes() s_m_c = {} for i in range(1, N): s_m_c[l2b([1, i / N])] = {l2b([1, 1]): 0.3} mpc = dolfinx_mpc.MultiPointConstraint(V) mpc.create_general_constraint(s_m_c, 1, 1) mpc.finalize() with Timer("~TEST: Assemble matrix"): A = assemble_matrix(bilinear_form, mpc) with Timer("~TEST: Assemble vector"): b = assemble_vector(linear_form, mpc) b.ghostUpdate(addv=PETSc.InsertMode.ADD_VALUES, mode=PETSc.ScatterMode.REVERSE) # Solve the MPC problem using a global transformation matrix # and numpy solvers to get reference values # Generate reference matrices and unconstrained solution A_org = fem.petsc.assemble_matrix(bilinear_form) A_org.assemble() L_org = fem.petsc.assemble_vector(linear_form) L_org.ghostUpdate(addv=PETSc.InsertMode.ADD_VALUES, mode=PETSc.ScatterMode.REVERSE) root = 0 comm = mesh.comm with Timer("~TEST: Compare"): dolfinx_mpc.utils.compare_mpc_lhs(A_org, A, mpc, root=root) dolfinx_mpc.utils.compare_mpc_rhs(L_org, b, mpc, root=root) list_timings(comm, [TimingType.wall])
def test_facet_normals(cell_type): """Test that FacetNormal is outward facing""" for count in range(5): mesh = unit_cell(cell_type) tdim = mesh.topology.dim mesh.topology.create_entities(tdim - 1) V = VectorFunctionSpace(mesh, ("Lagrange", 1)) normal = ufl.FacetNormal(mesh) v = Function(V) mesh.topology.create_entities(tdim - 1) map_f = mesh.topology.index_map(tdim - 1) num_facets = map_f.size_local + map_f.num_ghosts indices = np.arange(0, num_facets) values = np.arange(0, num_facets, dtype=np.intc) marker = meshtags(mesh, tdim - 1, indices, values) # For each facet, check that the inner product of the normal and # the vector that has a positive normal component on only that # facet is positive for i in range(num_facets): if cell_type == CellType.interval: co = mesh.geometry.x[i] v.interpolate(lambda x: x[0] - co[0]) if cell_type == CellType.triangle: co = mesh.geometry.x[i] # Vector function that is zero at `co` and points away # from `co` so that there is no normal component on two # edges and the integral over the other edge is 1 v.interpolate(lambda x: ((x[0] - co[0]) / 2, (x[1] - co[1]) / 2)) elif cell_type == CellType.tetrahedron: co = mesh.geometry.x[i] # Vector function that is zero at `co` and points away # from `co` so that there is no normal component on # three faces and the integral over the other edge is 1 v.interpolate(lambda x: ((x[0] - co[0]) / 3, (x[1] - co[1]) / 3, (x[2] - co[2]) / 3)) elif cell_type == CellType.quadrilateral: # function that is 0 on one edge and points away from # that edge so that there is no normal component on # three edges v.interpolate(lambda x: tuple(x[j] - i % 2 if j == i // 2 else 0 * x[j] for j in range(2))) elif cell_type == CellType.hexahedron: # function that is 0 on one face and points away from # that face so that there is no normal component on five # faces v.interpolate(lambda x: tuple(x[j] - i % 2 if j == i // 3 else 0 * x[j] for j in range(3))) # assert that the integrals these functions dotted with the # normal over a face is 1 on one face and 0 on the others ones = 0 for j in range(num_facets): a = form( ufl.inner(v, normal) * ufl.ds(subdomain_data=marker, subdomain_id=j)) result = assemble_scalar(a) if np.isclose(result, 1): ones += 1 else: assert np.isclose(result, 0) assert ones == 1
def plot_meshtags(): msh = create_unit_square(MPI.COMM_WORLD, 12, 12, cell_type=CellType.quadrilateral) # We continue using the mesh from the previous section, and find all # cells satisfying the condition below def in_circle(x): """True for points inside circle with radius 2""" return np.array((x.T[0] - 0.5)**2 + (x.T[1] - 0.5)**2 < 0.2**2, dtype=np.int32) # Create a dolfinx.MeshTag for all cells. If midpoint is inside the # circle, it gets value 1, otherwise 0. num_cells = msh.topology.index_map(msh.topology.dim).size_local midpoints = compute_midpoints(msh, msh.topology.dim, list(np.arange(num_cells, dtype=np.int32))) cell_tags = meshtags(msh, msh.topology.dim, np.arange(num_cells), in_circle(midpoints)) cells, types, x = plot.create_vtk_mesh(msh, msh.topology.dim) grid = pyvista.UnstructuredGrid(cells, types, x) # As the dolfinx.MeshTag contains a value for every cell in the # geometry, we can attach it directly to the grid grid.cell_data["Marker"] = cell_tags.values grid.set_active_scalars("Marker") # We create a plotter consisting of two windows, and add a plot of the # Meshtags to the first window. subplotter = pyvista.Plotter(shape=(1, 2)) subplotter.subplot(0, 0) subplotter.add_text("Mesh with markers", font_size=14, color="black", position="upper_edge") subplotter.add_mesh(grid, show_edges=True, show_scalar_bar=False) subplotter.view_xy() # We can also visualize subsets of data, by creating a smaller topology, # only consisting of those entities that has value one in the # dolfinx.MeshTag cells, types, x = plot.create_vtk_mesh( msh, msh.topology.dim, cell_tags.indices[cell_tags.values == 1]) # We add this grid to the second plotter sub_grid = pyvista.UnstructuredGrid(cells, types, x) subplotter.subplot(0, 1) subplotter.add_text("Subset of mesh", font_size=14, color="black", position="upper_edge") subplotter.add_mesh(sub_grid, show_edges=True, edge_color="black") if pyvista.OFF_SCREEN: subplotter.screenshot("2D_markers.png", transparent_background=transparent, window_size=[2 * figsize, figsize]) else: subplotter.show()
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 test_3d(tempdir, cell_type, encoding): filename = os.path.join(tempdir, "meshtags_3d.xdmf") comm = MPI.COMM_WORLD mesh = create_unit_cube(comm, 4, 4, 4, cell_type) mesh.topology.create_entities(2) bottom_facets = locate_entities(mesh, 2, lambda x: np.isclose(x[1], 0.0)) bottom_values = np.full(bottom_facets.shape, 1, dtype=np.int32) left_facets = locate_entities(mesh, 2, lambda x: np.isclose(x[0], 0.0)) left_values = np.full(left_facets.shape, 2, dtype=np.int32) indices, pos = np.unique(np.hstack((bottom_facets, left_facets)), return_index=True) mt = meshtags(mesh, 2, indices, np.hstack((bottom_values, left_values))[pos]) mt.name = "facets" top_lines = locate_entities(mesh, 1, lambda x: np.isclose(x[2], 1.0)) top_values = np.full(top_lines.shape, 3, dtype=np.int32) right_lines = locate_entities(mesh, 1, lambda x: np.isclose(x[0], 1.0)) right_values = np.full(right_lines.shape, 4, dtype=np.int32) indices, pos = np.unique(np.hstack((top_lines, right_lines)), return_index=True) mt_lines = meshtags(mesh, 1, indices, np.hstack((top_values, right_values))[pos]) mt_lines.name = "lines" mesh.topology.create_connectivity(1, 3) mesh.topology.create_connectivity(2, 3) with XDMFFile(comm, filename, "w", encoding=encoding) as file: file.write_mesh(mesh) file.write_meshtags(mt) file.write_meshtags(mt_lines) file.write_information("units", "mm") with XDMFFile(comm, filename, "r", encoding=encoding) as file: mesh_in = file.read_mesh() tdim = mesh_in.topology.dim mesh_in.topology.create_connectivity(tdim - 1, tdim) mesh_in.topology.create_connectivity(1, tdim) mt_in = file.read_meshtags(mesh_in, "facets") mt_lines_in = file.read_meshtags(mesh_in, "lines") units = file.read_information("units") assert units == "mm" assert mt_in.name == "facets" assert mt_lines_in.name == "lines" with XDMFFile(comm, os.path.join(tempdir, "meshtags_3d_out.xdmf"), "w", encoding=encoding) as file: file.write_mesh(mesh_in) file.write_meshtags(mt_lines_in) file.write_meshtags(mt_in) # Check number of owned and marked entities lines_local = comm.allreduce( (mt_lines.indices < mesh.topology.index_map(1).size_local).sum(), op=MPI.SUM) lines_local_in = comm.allreduce( (mt_lines_in.indices < mesh_in.topology.index_map(1).size_local).sum(), op=MPI.SUM) assert lines_local == lines_local_in # Check that only owned data is written to file facets_local = comm.allreduce( (mt.indices < mesh.topology.index_map(2).size_local).sum(), op=MPI.SUM) parser = ElementTree.XMLParser() tree = ElementTree.parse(os.path.join(tempdir, "meshtags_3d_out.xdmf"), parser) num_lines = int( tree.findall(".//Grid[@Name='lines']/Topology")[0].get( "NumberOfElements")) num_facets = int( tree.findall(".//Grid[@Name='facets']/Topology")[0].get( "NumberOfElements")) assert num_lines == lines_local assert num_facets == facets_local
def bench_elasticity_edge(tetra: bool = True, r_lvl: int = 0, out_hdf5=None, xdmf: bool = False, boomeramg: bool = False, kspview: bool = False, degree: int = 1, info: bool = False): N = 3 for i in range(r_lvl): N *= 2 ct = CellType.tetrahedron if tetra else CellType.hexahedron mesh = create_unit_cube(MPI.COMM_WORLD, N, N, N, ct) # Get number of unknowns on each edge V = VectorFunctionSpace(mesh, ("Lagrange", int(degree))) # Generate Dirichlet BC (Fixed) u_bc = Function(V) with u_bc.vector.localForm() as u_local: u_local.set(0.0) def boundaries(x): return np.isclose(x[0], np.finfo(float).eps) fdim = mesh.topology.dim - 1 facets = locate_entities_boundary(mesh, fdim, boundaries) topological_dofs = locate_dofs_topological(V, fdim, facets) bc = dirichletbc(u_bc, topological_dofs) bcs = [bc] def PeriodicBoundary(x): return np.logical_and(np.isclose(x[0], 1), np.isclose(x[2], 0)) def periodic_relation(x): out_x = np.zeros(x.shape) out_x[0] = x[0] out_x[1] = x[1] out_x[2] = x[2] + 1 return out_x with Timer("~Elasticity: Initialize MPC"): edim = mesh.topology.dim - 2 edges = locate_entities_boundary(mesh, edim, PeriodicBoundary) arg_sort = np.argsort(edges) periodic_mt = meshtags(mesh, edim, edges[arg_sort], np.full(len(edges), 2, dtype=np.int32)) mpc = MultiPointConstraint(V) mpc.create_periodic_constraint_topological(V, periodic_mt, 2, periodic_relation, bcs, scale=0.5) mpc.finalize() # Create traction meshtag def traction_boundary(x): return np.isclose(x[0], 1) t_facets = locate_entities_boundary(mesh, fdim, traction_boundary) facet_values = np.ones(len(t_facets), dtype=np.int32) arg_sort = np.argsort(t_facets) mt = meshtags(mesh, fdim, t_facets[arg_sort], facet_values) # Elasticity parameters E = PETSc.ScalarType(1.0e4) nu = 0.1 mu = Constant(mesh, E / (2.0 * (1.0 + nu))) lmbda = Constant(mesh, E * nu / ((1.0 + nu) * (1.0 - 2.0 * nu))) g = Constant(mesh, PETSc.ScalarType((0, 0, -1e2))) x = SpatialCoordinate(mesh) f = Constant(mesh, PETSc.ScalarType(1e3)) * as_vector((0, -(x[2] - 0.5)**2, (x[1] - 0.5)**2)) # Stress computation def epsilon(v): return sym(grad(v)) def sigma(v): return (2.0 * mu * epsilon(v) + lmbda * tr(epsilon(v)) * Identity(len(v))) # Define variational problem u = TrialFunction(V) v = TestFunction(V) a = inner(sigma(u), grad(v)) * dx rhs = inner(g, v) * ds(domain=mesh, subdomain_data=mt, subdomain_id=1) + inner(f, v) * dx # Setup MPC system if info: log_info(f"Run {r_lvl}: Assembling matrix and vector") bilinear_form = form(a) linear_form = form(rhs) with Timer("~Elasticity: Assemble LHS and RHS"): A = assemble_matrix(bilinear_form, mpc, bcs=bcs) b = assemble_vector(linear_form, mpc) # Create nullspace for elasticity problem and assign to matrix null_space = rigid_motions_nullspace(mpc.function_space) A.setNearNullSpace(null_space) # Apply boundary conditions apply_lifting(b, [bilinear_form], [bcs], mpc) b.ghostUpdate(addv=PETSc.InsertMode.ADD_VALUES, mode=PETSc.ScatterMode.REVERSE) set_bc(b, bcs) opts = PETSc.Options() if boomeramg: opts["ksp_type"] = "cg" opts["ksp_rtol"] = 1.0e-5 opts["pc_type"] = "hypre" opts['pc_hypre_type'] = 'boomeramg' opts["pc_hypre_boomeramg_max_iter"] = 1 opts["pc_hypre_boomeramg_cycle_type"] = "v" # opts["pc_hypre_boomeramg_print_statistics"] = 1 else: opts["ksp_rtol"] = 1.0e-8 opts["pc_type"] = "gamg" opts["pc_gamg_type"] = "agg" opts["pc_gamg_coarse_eq_limit"] = 1000 opts["pc_gamg_sym_graph"] = True opts["mg_levels_ksp_type"] = "chebyshev" opts["mg_levels_pc_type"] = "jacobi" opts["mg_levels_esteig_ksp_type"] = "cg" opts["matptap_via"] = "scalable" opts["pc_gamg_square_graph"] = 2 opts["pc_gamg_threshold"] = 0.02 # opts["help"] = None # List all available options # opts["ksp_view"] = None # List progress of solver # Setup PETSc solver solver = PETSc.KSP().create(MPI.COMM_WORLD) solver.setFromOptions() if info: log_info(f"Run {r_lvl}: Solving") with Timer("~Elasticity: Solve problem") as timer: solver.setOperators(A) uh = b.copy() uh.set(0) solver.solve(b, uh) uh.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) mpc.backsubstitution(uh) solver_time = timer.elapsed() if kspview: solver.view() mem = sum(MPI.COMM_WORLD.allgather(resource.getrusage(resource.RUSAGE_SELF).ru_maxrss)) it = solver.getIterationNumber() num_dofs = V.dofmap.index_map.size_global * V.dofmap.index_map_bs if out_hdf5 is not None: d_set = out_hdf5.get("its") d_set[r_lvl] = it d_set = out_hdf5.get("num_dofs") d_set[r_lvl] = num_dofs d_set = out_hdf5.get("num_slaves") d_set[r_lvl, MPI.COMM_WORLD.rank] = mpc.num_local_slaves d_set = out_hdf5.get("solve_time") d_set[r_lvl, MPI.COMM_WORLD.rank] = solver_time[0] if info: log_info(f"Lvl: {r_lvl}, Its: {it}, max Mem: {mem}, dim(V): {num_dofs}") if xdmf: # Write solution to file u_h = Function(mpc.function_space) u_h.vector.setArray(uh.array) u_h.name = "u_mpc" fname = f"results/bench_elasticity_edge_{r_lvl}.xdmf" with XDMFFile(MPI.COMM_WORLD, fname, "w") as outfile: outfile.write_mesh(mesh) outfile.write_function(u_h)
def demo_periodic3D(celltype: CellType): # Create mesh and finite element if celltype == CellType.tetrahedron: # Tet setup N = 10 mesh = create_unit_cube(MPI.COMM_WORLD, N, N, N) V = fem.VectorFunctionSpace(mesh, ("CG", 1)) else: # Hex setup N = 10 mesh = create_unit_cube(MPI.COMM_WORLD, N, N, N, CellType.hexahedron) V = fem.VectorFunctionSpace(mesh, ("CG", 2)) def dirichletboundary(x: NDArray[np.float64]) -> NDArray[np.bool_]: return np.logical_or( np.logical_or(np.isclose(x[1], 0), np.isclose(x[1], 1)), np.logical_or(np.isclose(x[2], 0), np.isclose(x[2], 1))) # Create Dirichlet boundary condition zero = PETSc.ScalarType([0, 0, 0]) geometrical_dofs = fem.locate_dofs_geometrical(V, dirichletboundary) bc = fem.dirichletbc(zero, geometrical_dofs, V) bcs = [bc] def PeriodicBoundary(x): return np.isclose(x[0], 1) facets = locate_entities_boundary(mesh, mesh.topology.dim - 1, PeriodicBoundary) arg_sort = np.argsort(facets) mt = meshtags(mesh, mesh.topology.dim - 1, facets[arg_sort], np.full(len(facets), 2, dtype=np.int32)) def periodic_relation(x): out_x = np.zeros(x.shape) out_x[0] = 1 - x[0] out_x[1] = x[1] out_x[2] = x[2] return out_x with Timer("~~Periodic: Compute mpc condition"): mpc = dolfinx_mpc.MultiPointConstraint(V) mpc.create_periodic_constraint_topological(V.sub(0), mt, 2, periodic_relation, bcs, 1) mpc.finalize() # Define variational problem u = TrialFunction(V) v = TestFunction(V) a = inner(grad(u), grad(v)) * dx x = SpatialCoordinate(mesh) dx_ = x[0] - 0.9 dy_ = x[1] - 0.5 dz_ = x[2] - 0.1 f = as_vector((x[0] * sin(5.0 * pi * x[1]) + 1.0 * exp(-(dx_ * dx_ + dy_ * dy_ + dz_ * dz_) / 0.02), 0.1 * dx_ * dz_, 0.1 * dx_ * dy_)) rhs = inner(f, v) * dx petsc_options: Dict[str, Union[str, float, int]] if complex_mode: rtol = 1e-16 petsc_options = {"ksp_type": "preonly", "pc_type": "lu"} else: rtol = 1e-8 petsc_options = { "ksp_type": "cg", "ksp_rtol": rtol, "pc_type": "hypre", "pc_hypre_typ": "boomeramg", "pc_hypre_boomeramg_max_iter": 1, "pc_hypre_boomeramg_cycle_type": "v", "pc_hypre_boomeramg_print_statistics": 1 } problem = LinearProblem(a, rhs, mpc, bcs, petsc_options=petsc_options) u_h = problem.solve() # --------------------VERIFICATION------------------------- print("----Verification----") u_ = fem.Function(V) u_.x.array[:] = 0 org_problem = fem.petsc.LinearProblem(a, rhs, u=u_, bcs=bcs, petsc_options=petsc_options) with Timer("~Periodic: Unconstrained solve"): org_problem.solve() it = org_problem.solver.getIterationNumber() print(f"Unconstrained solver iterations: {it}") # Write solutions to file ext = "tet" if celltype == CellType.tetrahedron else "hex" u_.name = "u_" + ext + "_unconstrained" # NOTE: Workaround as tabulate dof coordinates does not like extra ghosts u_out = fem.Function(V) old_local = u_out.x.map.size_local * u_out.x.bs old_ghosts = u_out.x.map.num_ghosts * u_out.x.bs mpc_local = u_h.x.map.size_local * u_h.x.bs assert (old_local == mpc_local) u_out.x.array[:old_local + old_ghosts] = u_h.x.array[:mpc_local + old_ghosts] u_out.name = "u_" + ext fname = f"results/demo_periodic3d_{ext}.bp" out_periodic = VTXWriter(MPI.COMM_WORLD, fname, u_out) out_periodic.write(0) out_periodic.close() root = 0 with Timer("~Demo: Verification"): dolfinx_mpc.utils.compare_mpc_lhs(org_problem.A, problem.A, mpc, root=root) dolfinx_mpc.utils.compare_mpc_rhs(org_problem.b, problem.b, mpc, root=root) # Gather LHS, RHS and solution on one process A_csr = dolfinx_mpc.utils.gather_PETScMatrix(org_problem.A, root=root) K = dolfinx_mpc.utils.gather_transformation_matrix(mpc, root=root) L_np = dolfinx_mpc.utils.gather_PETScVector(org_problem.b, root=root) u_mpc = dolfinx_mpc.utils.gather_PETScVector(u_h.vector, root=root) if MPI.COMM_WORLD.rank == root: KTAK = K.T * A_csr * K reduced_L = K.T @ L_np # Solve linear system d = scipy.sparse.linalg.spsolve(KTAK, reduced_L) # Back substitution to full solution vector uh_numpy = K @ d assert np.allclose(uh_numpy, u_mpc, rtol=rtol)
def demo_stacked_cubes(outfile: XDMFFile, theta: float, gmsh: bool = True, quad: bool = False, compare: bool = False, res: float = 0.1): log_info( f"Run theta:{theta:.2f}, Quad: {quad}, Gmsh {gmsh}, Res {res:.2e}") celltype = "quadrilateral" if quad else "triangle" if gmsh: mesh, mt = gmsh_2D_stacked(celltype, theta) mesh.name = f"mesh_{celltype}_{theta:.2f}_gmsh" else: mesh_name = "mesh" filename = f"meshes/mesh_{celltype}_{theta:.2f}.xdmf" mesh_2D_dolfin(celltype, theta) with XDMFFile(MPI.COMM_WORLD, filename, "r") as xdmf: mesh = xdmf.read_mesh(name=mesh_name) mesh.name = f"mesh_{celltype}_{theta:.2f}" tdim = mesh.topology.dim fdim = tdim - 1 mesh.topology.create_connectivity(tdim, tdim) mesh.topology.create_connectivity(fdim, tdim) mt = xdmf.read_meshtags(mesh, name="facet_tags") # Helper until meshtags can be read in from xdmf V = VectorFunctionSpace(mesh, ("Lagrange", 1)) r_matrix = rotation_matrix([0, 0, 1], theta) g_vec = np.dot(r_matrix, [0, -1.25e2, 0]) g = Constant(mesh, PETSc.ScalarType(g_vec[:2])) def bottom_corner(x): return np.isclose(x, [[0], [0], [0]]).all(axis=0) # Fix bottom corner bc_value = np.array((0, ) * mesh.geometry.dim, dtype=PETSc.ScalarType) bottom_dofs = locate_dofs_geometrical(V, bottom_corner) bc_bottom = dirichletbc(bc_value, bottom_dofs, V) bcs = [bc_bottom] # Elasticity parameters E = PETSc.ScalarType(1.0e3) nu = 0 mu = Constant(mesh, E / (2.0 * (1.0 + nu))) lmbda = Constant(mesh, E * nu / ((1.0 + nu) * (1.0 - 2.0 * nu))) # Stress computation def sigma(v): return (2.0 * mu * sym(grad(v)) + lmbda * tr(sym(grad(v))) * Identity(len(v))) # Define variational problem u = TrialFunction(V) v = TestFunction(V) a = inner(sigma(u), grad(v)) * dx ds = Measure("ds", domain=mesh, subdomain_data=mt, subdomain_id=3) rhs = inner(Constant(mesh, PETSc.ScalarType( (0, 0))), v) * dx + inner(g, v) * ds def left_corner(x): return np.isclose(x.T, np.dot(r_matrix, [0, 2, 0])).all(axis=1) # Create multi point constraint mpc = MultiPointConstraint(V) with Timer("~Contact: Create contact constraint"): nh = create_normal_approximation(V, mt, 4) mpc.create_contact_slip_condition(mt, 4, 9, nh) with Timer("~Contact: Add non-slip condition at bottom interface"): bottom_normal = facet_normal_approximation(V, mt, 5) mpc.create_slip_constraint(V, (mt, 5), bottom_normal, bcs=bcs) with Timer("~Contact: Add tangential constraint at one point"): vertex = locate_entities_boundary(mesh, 0, left_corner) tangent = facet_normal_approximation(V, mt, 3, tangent=True) mtv = meshtags(mesh, 0, vertex, np.full(len(vertex), 6, dtype=np.int32)) mpc.create_slip_constraint(V, (mtv, 6), tangent, bcs=bcs) mpc.finalize() rtol = 1e-9 petsc_options = { "ksp_rtol": 1e-9, "pc_type": "gamg", "pc_gamg_type": "agg", "pc_gamg_square_graph": 2, "pc_gamg_threshold": 0.02, "pc_gamg_coarse_eq_limit": 1000, "pc_gamg_sym_graph": True, "mg_levels_ksp_type": "chebyshev", "mg_levels_pc_type": "jacobi", "mg_levels_esteig_ksp_type": "cg" # , "help": None, "ksp_view": None } # Solve Linear problem problem = LinearProblem(a, rhs, mpc, bcs=bcs, petsc_options=petsc_options) # Build near nullspace null_space = rigid_motions_nullspace(mpc.function_space) problem.A.setNearNullSpace(null_space) u_h = problem.solve() it = problem.solver.getIterationNumber() if MPI.COMM_WORLD.rank == 0: print("Number of iterations: {0:d}".format(it)) unorm = u_h.vector.norm() if MPI.COMM_WORLD.rank == 0: print(f"Norm of u: {unorm}") # Write solution to file ext = "_gmsh" if gmsh else "" u_h.name = "u_mpc_{0:s}_{1:.2f}{2:s}".format(celltype, theta, ext) outfile.write_mesh(mesh) outfile.write_function(u_h, 0.0, f"Xdmf/Domain/Grid[@Name='{mesh.name}'][1]") # Solve the MPC problem using a global transformation matrix # and numpy solvers to get reference values if not compare: return log_info("Solving reference problem with global matrix (using numpy)") with Timer("~MPC: Reference problem"): # Generate reference matrices and unconstrained solution A_org = assemble_matrix(form(a), bcs) A_org.assemble() L_org = assemble_vector(form(rhs)) apply_lifting(L_org, [form(a)], [bcs]) L_org.ghostUpdate(addv=PETSc.InsertMode.ADD_VALUES, mode=PETSc.ScatterMode.REVERSE) set_bc(L_org, bcs) root = 0 with Timer("~MPC: Verification"): compare_mpc_lhs(A_org, problem.A, mpc, root=root) compare_mpc_rhs(L_org, problem.b, mpc, root=root) # Gather LHS, RHS and solution on one process A_csr = gather_PETScMatrix(A_org, root=root) K = gather_transformation_matrix(mpc, root=root) L_np = gather_PETScVector(L_org, root=root) u_mpc = gather_PETScVector(u_h.vector, root=root) if MPI.COMM_WORLD.rank == root: KTAK = K.T * A_csr * K reduced_L = K.T @ L_np # Solve linear system d = scipy.sparse.linalg.spsolve(KTAK, reduced_L) # Back substitution to full solution vector uh_numpy = K @ d assert np.allclose(uh_numpy, u_mpc, rtol=rtol)
def test_cell_domains(get_assemblers): # noqa: F811 """ Periodic MPC conditions over integral with different cell subdomains """ assemble_matrix, assemble_vector = get_assemblers N = 5 # Create mesh and function space mesh = create_unit_square(MPI.COMM_WORLD, 15, N) V = fem.FunctionSpace(mesh, ("Lagrange", 1)) def left_side(x): return x[0] < 0.5 tdim = mesh.topology.dim num_cells = mesh.topology.index_map(tdim).size_local cell_midpoints = compute_midpoints(mesh, tdim, range(num_cells)) values = np.ones(num_cells, dtype=np.intc) # All cells on right side marked one, all other with 1 values += left_side(cell_midpoints.T) ct = meshtags(mesh, mesh.topology.dim, np.arange(num_cells, dtype=np.int32), values) # Solve Problem without MPC for reference u = ufl.TrialFunction(V) v = ufl.TestFunction(V) x = ufl.SpatialCoordinate(mesh) c1 = fem.Constant(mesh, PETSc.ScalarType(2)) c2 = fem.Constant(mesh, PETSc.ScalarType(10)) dx = ufl.Measure("dx", domain=mesh, subdomain_data=ct) a = c1 * ufl.inner(ufl.grad(u), ufl.grad(v)) * dx(1) +\ c2 * ufl.inner(ufl.grad(u), ufl.grad(v)) * dx(2)\ + 0.01 * ufl.inner(u, v) * dx(1) rhs = ufl.inner(x[1], v) * dx(1) + \ ufl.inner(fem.Constant(mesh, PETSc.ScalarType(1)), v) * dx(2) bilinear_form = fem.form(a) linear_form = fem.form(rhs) # Generate reference matrices A_org = fem.petsc.assemble_matrix(bilinear_form) A_org.assemble() L_org = fem.petsc.assemble_vector(linear_form) L_org.ghostUpdate(addv=PETSc.InsertMode.ADD_VALUES, mode=PETSc.ScatterMode.REVERSE) def l2b(li): return np.array(li, dtype=np.float64).tobytes() s_m_c = {} for i in range(0, N + 1): s_m_c[l2b([1, i / N])] = {l2b([0, i / N]): 1} mpc = dolfinx_mpc.MultiPointConstraint(V) mpc.create_general_constraint(s_m_c) mpc.finalize() # Setup MPC system with Timer("~TEST: Assemble matrix old"): A = assemble_matrix(bilinear_form, mpc) with Timer("~TEST: Assemble vector"): b = assemble_vector(linear_form, mpc) b.ghostUpdate(addv=PETSc.InsertMode.ADD_VALUES, mode=PETSc.ScatterMode.REVERSE) solver = PETSc.KSP().create(MPI.COMM_WORLD) solver.setType(PETSc.KSP.Type.PREONLY) solver.getPC().setType(PETSc.PC.Type.LU) solver.setOperators(A) # Solve uh = b.copy() uh.set(0) solver.solve(b, uh) uh.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) mpc.backsubstitution(uh) root = 0 comm = mesh.comm with Timer("~TEST: Compare"): dolfinx_mpc.utils.compare_mpc_lhs(A_org, A, mpc, root=root) dolfinx_mpc.utils.compare_mpc_rhs(L_org, b, mpc, root=root) # Gather LHS, RHS and solution on one process A_csr = dolfinx_mpc.utils.gather_PETScMatrix(A_org, root=root) K = dolfinx_mpc.utils.gather_transformation_matrix(mpc, root=root) L_np = dolfinx_mpc.utils.gather_PETScVector(L_org, root=root) u_mpc = dolfinx_mpc.utils.gather_PETScVector(uh, root=root) if MPI.COMM_WORLD.rank == root: KTAK = K.T * A_csr * K reduced_L = K.T @ L_np # Solve linear system d = scipy.sparse.linalg.spsolve(KTAK, reduced_L) # Back substitution to full solution vector uh_numpy = K @ d assert np.allclose(uh_numpy, u_mpc) list_timings(comm, [TimingType.wall])
Ue = ufl.VectorElement("Lagrange", msh.ufl_cell(), 2) S = FunctionSpace(msh, Se) U = FunctionSpace(msh, Ue) # Get local dofmap sizes for later local tensor tabulations Ssize = S.element.space_dimension Usize = U.element.space_dimension sigma, tau = ufl.TrialFunction(S), ufl.TestFunction(S) u, v = ufl.TrialFunction(U), ufl.TestFunction(U) # Locate all facets at the free end and assign them value 1. Sort the # facet indices (requirement for constructing MeshTags) free_end_facets = np.sort(locate_entities_boundary(msh, 1, lambda x: np.isclose(x[0], 48.0))) mt = meshtags(msh, 1, free_end_facets, 1) ds = ufl.Measure("ds", subdomain_data=mt) # Homogeneous boundary condition in displacement u_bc = Function(U) u_bc.x.array[:] = 0.0 # Displacement BC is applied to the left side left_facets = locate_entities_boundary(msh, 1, lambda x: np.isclose(x[0], 0.0)) bdofs = locate_dofs_topological(U, 1, left_facets) bc = dirichletbc(u_bc, bdofs) # Elastic stiffness tensor and Poisson ratio E, nu = 1.0, 1.0 / 3.0
def ref_elasticity(tetra: bool = True, r_lvl: int = 0, out_hdf5: h5py.File = None, xdmf: bool = False, boomeramg: bool = False, kspview: bool = False, degree: int = 1): if tetra: N = 3 if degree == 1 else 2 mesh = create_unit_cube(MPI.COMM_WORLD, N, N, N) else: N = 3 mesh = create_unit_cube(MPI.COMM_WORLD, N, N, N, CellType.hexahedron) for i in range(r_lvl): # set_log_level(LogLevel.INFO) N *= 2 if tetra: mesh = refine(mesh, redistribute=True) else: mesh = create_unit_cube(MPI.COMM_WORLD, N, N, N, CellType.hexahedron) # set_log_level(LogLevel.ERROR) N = degree * N fdim = mesh.topology.dim - 1 V = VectorFunctionSpace(mesh, ("Lagrange", int(degree))) # Generate Dirichlet BC on lower boundary (Fixed) u_bc = Function(V) with u_bc.vector.localForm() as u_local: u_local.set(0.0) def boundaries(x): return np.isclose(x[0], np.finfo(float).eps) facets = locate_entities_boundary(mesh, fdim, boundaries) topological_dofs = locate_dofs_topological(V, fdim, facets) bc = dirichletbc(u_bc, topological_dofs) bcs = [bc] # Create traction meshtag def traction_boundary(x): return np.isclose(x[0], 1) t_facets = locate_entities_boundary(mesh, fdim, traction_boundary) facet_values = np.ones(len(t_facets), dtype=np.int32) arg_sort = np.argsort(t_facets) mt = meshtags(mesh, fdim, t_facets[arg_sort], facet_values[arg_sort]) # Elasticity parameters E = PETSc.ScalarType(1.0e4) nu = 0.1 mu = Constant(mesh, E / (2.0 * (1.0 + nu))) lmbda = Constant(mesh, E * nu / ((1.0 + nu) * (1.0 - 2.0 * nu))) g = Constant(mesh, PETSc.ScalarType((0, 0, -1e2))) x = SpatialCoordinate(mesh) f = Constant(mesh, PETSc.ScalarType(1e4)) * \ as_vector((0, -(x[2] - 0.5)**2, (x[1] - 0.5)**2)) # Stress computation def sigma(v): return (2.0 * mu * sym(grad(v)) + lmbda * tr(sym(grad(v))) * Identity(len(v))) # Define variational problem u = TrialFunction(V) v = TestFunction(V) a = inner(sigma(u), grad(v)) * dx rhs = inner(g, v) * ds(domain=mesh, subdomain_data=mt, subdomain_id=1) + inner(f, v) * dx num_dofs = V.dofmap.index_map.size_global * V.dofmap.index_map_bs if MPI.COMM_WORLD.rank == 0: print("Problem size {0:d} ".format(num_dofs)) # Generate reference matrices and unconstrained solution bilinear_form = form(a) A_org = assemble_matrix(bilinear_form, bcs) A_org.assemble() null_space_org = rigid_motions_nullspace(V) A_org.setNearNullSpace(null_space_org) linear_form = form(rhs) L_org = assemble_vector(linear_form) apply_lifting(L_org, [bilinear_form], [bcs]) L_org.ghostUpdate(addv=PETSc.InsertMode.ADD_VALUES, mode=PETSc.ScatterMode.REVERSE) set_bc(L_org, bcs) opts = PETSc.Options() if boomeramg: opts["ksp_type"] = "cg" opts["ksp_rtol"] = 1.0e-5 opts["pc_type"] = "hypre" opts['pc_hypre_type'] = 'boomeramg' opts["pc_hypre_boomeramg_max_iter"] = 1 opts["pc_hypre_boomeramg_cycle_type"] = "v" # opts["pc_hypre_boomeramg_print_statistics"] = 1 else: opts["ksp_rtol"] = 1.0e-8 opts["pc_type"] = "gamg" opts["pc_gamg_type"] = "agg" opts["pc_gamg_coarse_eq_limit"] = 1000 opts["pc_gamg_sym_graph"] = True opts["mg_levels_ksp_type"] = "chebyshev" opts["mg_levels_pc_type"] = "jacobi" opts["mg_levels_esteig_ksp_type"] = "cg" opts["matptap_via"] = "scalable" opts["pc_gamg_square_graph"] = 2 opts["pc_gamg_threshold"] = 0.02 # opts["help"] = None # List all available options # opts["ksp_view"] = None # List progress of solver # Create solver, set operator and options solver = PETSc.KSP().create(MPI.COMM_WORLD) solver.setFromOptions() solver.setOperators(A_org) # Solve linear problem u_ = Function(V) start = perf_counter() with Timer("Ref solve"): solver.solve(L_org, u_.vector) end = perf_counter() u_.x.scatter_forward() if kspview: solver.view() it = solver.getIterationNumber() if out_hdf5 is not None: d_set = out_hdf5.get("its") d_set[r_lvl] = it d_set = out_hdf5.get("num_dofs") d_set[r_lvl] = num_dofs d_set = out_hdf5.get("solve_time") d_set[r_lvl, MPI.COMM_WORLD.rank] = end - start if MPI.COMM_WORLD.rank == 0: print("Refinement level {0:d}, Iterations {1:d}".format(r_lvl, it)) # List memory usage mem = sum(MPI.COMM_WORLD.allgather( resource.getrusage(resource.RUSAGE_SELF).ru_maxrss)) if MPI.COMM_WORLD.rank == 0: print("{1:d}: Max usage after trad. solve {0:d} (kb)" .format(mem, r_lvl)) if xdmf: # Name formatting of functions u_.name = "u_unconstrained" fname = "results/ref_elasticity_{0:d}.xdmf".format(r_lvl) with XDMFFile(MPI.COMM_WORLD, fname, "w") as out_xdmf: out_xdmf.write_mesh(mesh) out_xdmf.write_function(u_, 0.0, "Xdmf/Domain/Grid[@Name='{0:s}'][1]".format(mesh.name))
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_pipeline(u_from_mpc): # Create mesh and function space mesh = create_unit_square(MPI.COMM_WORLD, 5, 5) V = fem.FunctionSpace(mesh, ("Lagrange", 1)) # Solve Problem without MPC for reference u = ufl.TrialFunction(V) v = ufl.TestFunction(V) d = fem.Constant(mesh, PETSc.ScalarType(0.01)) x = ufl.SpatialCoordinate(mesh) f = ufl.sin(2 * ufl.pi * x[0]) * ufl.sin(ufl.pi * x[1]) a = ufl.inner(ufl.grad(u), ufl.grad(v)) * ufl.dx - d * ufl.inner(u, v) * ufl.dx rhs = ufl.inner(f, v) * ufl.dx bilinear_form = fem.form(a) linear_form = fem.form(rhs) # Generate reference matrices A_org = fem.petsc.assemble_matrix(bilinear_form) A_org.assemble() L_org = fem.petsc.assemble_vector(linear_form) L_org.ghostUpdate(addv=PETSc.InsertMode.ADD_VALUES, mode=PETSc.ScatterMode.REVERSE) # Create multipoint constraint def periodic_relation(x): out_x = np.copy(x) out_x[0] = 1 - x[0] return out_x def PeriodicBoundary(x): return np.isclose(x[0], 1) facets = locate_entities_boundary(mesh, mesh.topology.dim - 1, PeriodicBoundary) arg_sort = np.argsort(facets) mt = meshtags(mesh, mesh.topology.dim - 1, facets[arg_sort], np.full(len(facets), 2, dtype=np.int32)) mpc = dolfinx_mpc.MultiPointConstraint(V) mpc.create_periodic_constraint_topological(V, mt, 2, periodic_relation, [], 1) mpc.finalize() if u_from_mpc: uh = fem.Function(mpc.function_space) problem = dolfinx_mpc.LinearProblem(bilinear_form, linear_form, mpc, bcs=[], u=uh, petsc_options={"ksp_type": "preonly", "pc_type": "lu"}) problem.solve() root = 0 dolfinx_mpc.utils.compare_mpc_lhs(A_org, problem.A, mpc, root=root) dolfinx_mpc.utils.compare_mpc_rhs(L_org, problem.b, mpc, root=root) # Gather LHS, RHS and solution on one process A_csr = dolfinx_mpc.utils.gather_PETScMatrix(A_org, root=root) K = dolfinx_mpc.utils.gather_transformation_matrix(mpc, root=root) L_np = dolfinx_mpc.utils.gather_PETScVector(L_org, root=root) u_mpc = dolfinx_mpc.utils.gather_PETScVector(uh.vector, root=root) if MPI.COMM_WORLD.rank == root: KTAK = K.T * A_csr * K reduced_L = K.T @ L_np # Solve linear system d = scipy.sparse.linalg.spsolve(KTAK, reduced_L) # Back substitution to full solution vector uh_numpy = K @ d assert np.allclose(uh_numpy, u_mpc) else: uh = fem.Function(V) with pytest.raises(ValueError): problem = dolfinx_mpc.LinearProblem(bilinear_form, linear_form, mpc, bcs=[], u=uh, petsc_options={"ksp_type": "preonly", "pc_type": "lu"}) problem.solve()
def test_assembly_ds_domains(mode): mesh = create_unit_square(MPI.COMM_WORLD, 10, 10, ghost_mode=mode) V = FunctionSpace(mesh, ("Lagrange", 1)) u, v = ufl.TrialFunction(V), ufl.TestFunction(V) def bottom(x): return np.isclose(x[1], 0.0) def top(x): return np.isclose(x[1], 1.0) def left(x): return np.isclose(x[0], 0.0) def right(x): return np.isclose(x[0], 1.0) bottom_facets = locate_entities_boundary(mesh, mesh.topology.dim - 1, bottom) bottom_vals = np.full(bottom_facets.shape, 1, np.intc) top_facets = locate_entities_boundary(mesh, mesh.topology.dim - 1, top) top_vals = np.full(top_facets.shape, 2, np.intc) left_facets = locate_entities_boundary(mesh, mesh.topology.dim - 1, left) left_vals = np.full(left_facets.shape, 3, np.intc) right_facets = locate_entities_boundary(mesh, mesh.topology.dim - 1, right) right_vals = np.full(right_facets.shape, 6, np.intc) indices = np.hstack((bottom_facets, top_facets, left_facets, right_facets)) values = np.hstack((bottom_vals, top_vals, left_vals, right_vals)) indices, pos = np.unique(indices, return_index=True) marker = meshtags(mesh, mesh.topology.dim - 1, indices, values[pos]) ds = ufl.Measure('ds', subdomain_data=marker, domain=mesh) w = Function(V) w.x.array[:] = 0.5 bc = dirichletbc(Function(V), range(30)) # Assemble matrix a = form(w * ufl.inner(u, v) * (ds(1) + ds(2) + ds(3) + ds(6))) A = assemble_matrix(a) A.assemble() norm1 = A.norm() a2 = form(w * ufl.inner(u, v) * ds) A2 = assemble_matrix(a2) A2.assemble() norm2 = A2.norm() assert norm1 == pytest.approx(norm2, 1.0e-12) # Assemble vector L = form(ufl.inner(w, v) * (ds(1) + ds(2) + ds(3) + ds(6))) b = assemble_vector(L) apply_lifting(b, [a], [[bc]]) b.ghostUpdate(addv=PETSc.InsertMode.ADD_VALUES, mode=PETSc.ScatterMode.REVERSE) set_bc(b, [bc]) L2 = form(ufl.inner(w, v) * ds) b2 = assemble_vector(L2) apply_lifting(b2, [a2], [[bc]]) b2.ghostUpdate(addv=PETSc.InsertMode.ADD_VALUES, mode=PETSc.ScatterMode.REVERSE) set_bc(b2, [bc]) assert b.norm() == pytest.approx(b2.norm(), 1.0e-12) # Assemble scalar L = form(w * (ds(1) + ds(2) + ds(3) + ds(6))) s = assemble_scalar(L) s = mesh.comm.allreduce(s, op=MPI.SUM) L2 = form(w * ds) s2 = assemble_scalar(L2) s2 = mesh.comm.allreduce(s2, op=MPI.SUM) assert (s == pytest.approx(s2, 1.0e-12) and 2.0 == pytest.approx(s, 1.0e-12))
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 bench_elasticity_one(r_lvl: int = 0, out_hdf5: h5py.File = None, xdmf: bool = False, boomeramg: bool = False, kspview: bool = False): N = 3 mesh = create_unit_cube(MPI.COMM_WORLD, N, N, N) for i in range(r_lvl): mesh.topology.create_entities(mesh.topology.dim - 2) mesh = refine(mesh, redistribute=True) fdim = mesh.topology.dim - 1 V = VectorFunctionSpace(mesh, ("Lagrange", 1)) # Generate Dirichlet BC on lower boundary (Fixed) u_bc = Function(V) with u_bc.vector.localForm() as u_local: u_local.set(0.0) def boundaries(x): return np.isclose(x[0], np.finfo(float).eps) facets = locate_entities_boundary(mesh, fdim, boundaries) topological_dofs = locate_dofs_topological(V, fdim, facets) bc = dirichletbc(u_bc, topological_dofs) bcs = [bc] # Create traction meshtag def traction_boundary(x): return np.isclose(x[0], 1) t_facets = locate_entities_boundary(mesh, fdim, traction_boundary) facet_values = np.ones(len(t_facets), dtype=np.int32) arg_sort = np.argsort(t_facets) mt = meshtags(mesh, fdim, t_facets[arg_sort], facet_values[arg_sort]) # Define variational problem u = TrialFunction(V) v = TestFunction(V) # Elasticity parameters E = 1.0e4 nu = 0.1 mu = Constant(mesh, E / (2.0 * (1.0 + nu))) lmbda = Constant(mesh, E * nu / ((1.0 + nu) * (1.0 - 2.0 * nu))) g = Constant(mesh, (0, 0, -1e2)) # Stress computation def sigma(v): return 2.0 * mu * sym(grad(v)) + lmbda * tr(sym(grad(v))) * Identity( len(v)) # Define variational problem u = TrialFunction(V) v = TestFunction(V) a = inner(sigma(u), grad(v)) * dx rhs = inner(g, v) * ds(domain=mesh, subdomain_data=mt, subdomain_id=1) # Create MPC with Timer("~Elasticity: Init constraint"): def l2b(li): return np.array(li, dtype=np.float64).tobytes() s_m_c = {l2b([1, 0, 0]): {l2b([1, 0, 1]): 0.5}} mpc = MultiPointConstraint(V) mpc.create_general_constraint(s_m_c, 2, 2) mpc.finalize() # Setup MPC system bilinear_form = form(a) linear_form = form(rhs) with Timer("~Elasticity: Assemble LHS and RHS"): A = assemble_matrix(bilinear_form, mpc, bcs=bcs) b = assemble_vector(linear_form, mpc) # Apply boundary conditions apply_lifting(b, [bilinear_form], [bcs], mpc) b.ghostUpdate(addv=PETSc.InsertMode.ADD_VALUES, mode=PETSc.ScatterMode.REVERSE) set_bc(b, bcs) # Create functionspace and function for mpc vector # Solve Linear problem solver = PETSc.KSP().create(MPI.COMM_WORLD) opts = PETSc.Options() if boomeramg: opts["ksp_type"] = "cg" opts["ksp_rtol"] = 1.0e-5 opts["pc_type"] = "hypre" opts['pc_hypre_type'] = 'boomeramg' opts["pc_hypre_boomeramg_max_iter"] = 1 opts["pc_hypre_boomeramg_cycle_type"] = "v" # opts["pc_hypre_boomeramg_print_statistics"] = 1 else: opts["ksp_rtol"] = 1.0e-10 opts["pc_type"] = "gamg" opts["pc_gamg_type"] = "agg" opts["pc_gamg_coarse_eq_limit"] = 1000 opts["pc_gamg_sym_graph"] = True opts["mg_levels_ksp_type"] = "chebyshev" opts["mg_levels_pc_type"] = "jacobi" opts["mg_levels_esteig_ksp_type"] = "cg" opts["matptap_via"] = "scalable" # opts["help"] = None # List all available options # opts["ksp_view"] = None # List progress of solver with Timer("~Elasticity: Solve problem") as timer: null_space = rigid_motions_nullspace(mpc.function_space) A.setNearNullSpace(null_space) solver.setFromOptions() solver.setOperators(A) # Solve linear problem uh = b.copy() uh.set(0) solver.solve(b, uh) uh.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) mpc.backsubstitution(uh) solver_time = timer.elapsed() it = solver.getIterationNumber() if kspview: solver.view() # Print max usage of summary mem = sum( MPI.COMM_WORLD.allgather( resource.getrusage(resource.RUSAGE_SELF).ru_maxrss)) num_dofs = V.dofmap.index_map.size_global * V.dofmap.index_map_bs if MPI.COMM_WORLD.rank == 0: print(f"Rlvl {r_lvl}, Iterations {it}") print(f"Rlvl {r_lvl}, Max usage {mem} (kb), #dofs {num_dofs}") if out_hdf5 is not None: d_set = out_hdf5.get("its") d_set[r_lvl] = it d_set = out_hdf5.get("num_dofs") d_set[r_lvl] = num_dofs d_set = out_hdf5.get("solve_time") d_set[r_lvl, MPI.COMM_WORLD.rank] = solver_time[0] if xdmf: # Write solution to file u_h = Function(mpc.function_space) u_h.vector.setArray(uh.array) u_h.name = "u_mpc" fname = f"results/bench_elasticity_{r_lvl}.xdmf" with XDMFFile(MPI.COMM_WORLD, fname, "w") as outfile: outfile.write_mesh(mesh) outfile.write_function(u_h)