def test_assemble_derivatives(): """This test checks the original_coefficient_positions, which may change under differentiation (some coefficients and constants are eliminated)""" mesh = create_unit_square(MPI.COMM_WORLD, 12, 12) Q = FunctionSpace(mesh, ("Lagrange", 1)) u = Function(Q) v = ufl.TestFunction(Q) du = ufl.TrialFunction(Q) b = Function(Q) c1 = Constant(mesh, np.array([[1.0, 0.0], [3.0, 4.0]], PETSc.ScalarType)) c2 = Constant(mesh, PETSc.ScalarType(2.0)) b.x.array[:] = 2.0 # derivative eliminates 'u' and 'c1' L = ufl.inner(c1, c1) * v * dx + c2 * b * inner(u, v) * dx a = form(derivative(L, u, du)) A1 = assemble_matrix(a) A1.assemble() a = form(c2 * b * inner(du, v) * dx) A2 = assemble_matrix(a) A2.assemble() assert (A1 - A2).norm() == pytest.approx(0.0, rel=1e-12, abs=1e-12)
def test_vector_types(): """Assemble form using different types""" mesh = create_unit_square(MPI.COMM_WORLD, 3, 5) V = FunctionSpace(mesh, ("Lagrange", 3)) v = ufl.TestFunction(V) c = Constant(mesh, np.float64(1)) L = inner(c, v) * ufl.dx x0 = _cpp.la.Vector_float64(V.dofmap.index_map, V.dofmap.index_map_bs) L = form(L, dtype=x0.array.dtype) c0 = pack_constants(L) c1 = pack_coefficients(L) _cpp.fem.assemble_vector(x0.array, L, c0, c1) x0.scatter_reverse(_cpp.common.ScatterMode.add) c = Constant(mesh, np.complex128(1)) L = inner(c, v) * ufl.dx x1 = _cpp.la.Vector_complex128(V.dofmap.index_map, V.dofmap.index_map_bs) L = form(L, dtype=x1.array.dtype) c0 = pack_constants(L) c1 = pack_coefficients(L) _cpp.fem.assemble_vector(x1.array, L, c0, c1) x1.scatter_reverse(_cpp.common.ScatterMode.add) c = Constant(mesh, np.float32(1)) L = inner(c, v) * ufl.dx x2 = _cpp.la.Vector_float32(V.dofmap.index_map, V.dofmap.index_map_bs) L = form(L, dtype=x2.array.dtype) c0 = pack_constants(L) c1 = pack_coefficients(L) _cpp.fem.assemble_vector(x2.array, L, c0, c1) x2.scatter_reverse(_cpp.common.ScatterMode.add) assert np.linalg.norm(x0.array - x1.array) == pytest.approx(0.0) assert np.linalg.norm(x0.array - x2.array) == pytest.approx(0.0, abs=1e-8)
def test_vector_constant(): mesh = create_unit_cube(MPI.COMM_WORLD, 2, 2, 2) c0 = Constant(mesh, [1.0, 2.0]) c1 = Constant(mesh, np.array([1.0, 2.0])) assert (c0.value.all() == c1.value.all()) c0.value += 1.0 assert c0.value.all() == np.array([2.0, 3.0]).all() c0.value -= [1.0, 2.0] assert c0.value[0] == c0.value[1]
def test_assembly_dS_domains(mode): N = 10 mesh = create_unit_square(MPI.COMM_WORLD, N, N, ghost_mode=mode) one = Constant(mesh, PETSc.ScalarType(1)) val = assemble_scalar(form(one * ufl.dS)) val = mesh.comm.allreduce(val, op=MPI.SUM) assert val == pytest.approx(2 * (N - 1) + N * np.sqrt(2), 1.0e-7)
def test_mixed_constant_bc(mesh_factory): """Test that setting a dirichletbc with on a component of a mixed function yields the same result as setting it with a function""" func, args = mesh_factory mesh = func(*args) tdim, gdim = mesh.topology.dim, mesh.geometry.dim boundary_facets = locate_entities_boundary( mesh, tdim - 1, lambda x: np.ones(x.shape[1], dtype=bool)) TH = ufl.MixedElement([ ufl.VectorElement("Lagrange", mesh.ufl_cell(), 2), ufl.FiniteElement("Lagrange", mesh.ufl_cell(), 1) ]) W = FunctionSpace(mesh, TH) U = Function(W) # Apply BC to component of a mixed space using a Constant c = Constant(mesh, (PETSc.ScalarType(2), PETSc.ScalarType(2))) dofs0 = locate_dofs_topological(W.sub(0), tdim - 1, boundary_facets) bc0 = dirichletbc(c, dofs0, W.sub(0)) u = U.sub(0) set_bc(u.vector, [bc0]) # Apply BC to component of a mixed space using a Function ubc1 = u.collapse() ubc1.interpolate(lambda x: np.full((gdim, x.shape[1]), 2.0)) dofs1 = locate_dofs_topological((W.sub(0), ubc1.function_space), tdim - 1, boundary_facets) bc1 = dirichletbc(ubc1, dofs1, W.sub(0)) U1 = Function(W) u1 = U1.sub(0) set_bc(u1.vector, [bc1]) # Check that both approaches yield the same vector assert np.allclose(u.x.array, u1.x.array)
def test_basic_assembly_constant(mode): """Tests assembly with Constant The following test should be sensitive to order of flattening the matrix-valued constant. """ mesh = create_unit_square(MPI.COMM_WORLD, 5, 5, ghost_mode=mode) V = FunctionSpace(mesh, ("Lagrange", 1)) u, v = ufl.TrialFunction(V), ufl.TestFunction(V) c = Constant(mesh, np.array([[1.0, 2.0], [5.0, 3.0]], PETSc.ScalarType)) a = inner(c[1, 0] * u, v) * dx + inner(c[1, 0] * u, v) * ds L = inner(c[1, 0], v) * dx + inner(c[1, 0], v) * ds a, L = form(a), form(L) # Initial assembly A1 = assemble_matrix(a) A1.assemble() b1 = assemble_vector(L) b1.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) c.value = [[1.0, 2.0], [3.0, 4.0]] A2 = assemble_matrix(a) A2.assemble() b2 = assemble_vector(L) b2.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) assert (A1 * 3.0 - A2 * 5.0).norm() == pytest.approx(0.0) assert (b1 * 3.0 - b2 * 5.0).norm() == pytest.approx(0.0)
def test_sub_constant_bc(mesh_factory): """Test that setting a dirichletbc with on a component of a vector valued function yields the same result as setting it with a function""" func, args = mesh_factory mesh = func(*args) tdim = mesh.topology.dim V = VectorFunctionSpace(mesh, ("Lagrange", 1)) c = Constant(mesh, PETSc.ScalarType(3.14)) boundary_facets = locate_entities_boundary( mesh, tdim - 1, lambda x: np.ones(x.shape[1], dtype=bool)) for i in range(V.num_sub_spaces): Vi = V.sub(i).collapse()[0] u_bci = Function(Vi) u_bci.x.array[:] = PETSc.ScalarType(c.value) boundary_dofsi = locate_dofs_topological((V.sub(i), Vi), tdim - 1, boundary_facets) bc_fi = dirichletbc(u_bci, boundary_dofsi, V.sub(i)) boundary_dofs = locate_dofs_topological(V.sub(i), tdim - 1, boundary_facets) bc_c = dirichletbc(c, boundary_dofs, V.sub(i)) u_f = Function(V) set_bc(u_f.vector, [bc_fi]) u_c = Function(V) set_bc(u_c.vector, [bc_c]) assert np.allclose(u_f.vector.array, u_c.vector.array)
def test_pack_coefficients(): """Test packing of form coefficients ahead of main assembly call""" mesh = create_unit_square(MPI.COMM_WORLD, 12, 15) V = FunctionSpace(mesh, ("Lagrange", 1)) # Non-blocked u = Function(V) v = ufl.TestFunction(V) c = Constant(mesh, PETSc.ScalarType(12.0)) F = ufl.inner(c, v) * dx - c * ufl.sqrt(u * u) * ufl.inner(u, v) * dx u.x.array[:] = 10.0 _F = form(F) # -- Test vector b0 = assemble_vector(_F) b0.assemble() constants = pack_constants(_F) coeffs = pack_coefficients(_F) with b0.localForm() as _b0: for c in [(None, None), (None, coeffs), (constants, None), (constants, coeffs)]: b = assemble_vector(_F, coeffs=c) b.assemble() with b.localForm() as _b: assert (_b0.array_r == _b.array_r).all() # Change coefficients constants *= 5.0 for coeff in coeffs.values(): coeff *= 5.0 with b0.localForm() as _b0: for c in [(None, coeffs), (constants, None), (constants, coeffs)]: b = assemble_vector(_F, coeffs=c) b.assemble() with b.localForm() as _b: assert (_b0 - _b).norm() > 1.0e-5 # -- Test matrix du = ufl.TrialFunction(V) J = ufl.derivative(F, u, du) J = form(J) A0 = assemble_matrix(J) A0.assemble() constants = pack_constants(J) coeffs = pack_coefficients(J) for c in [(None, None), (None, coeffs), (constants, None), (constants, coeffs)]: A = assemble_matrix(J, coeffs=c) A.assemble() assert pytest.approx((A - A0).norm(), 1.0e-12) == 0.0 # Change coefficients constants *= 5.0 for coeff in coeffs.values(): coeff *= 5.0 for c in [(None, coeffs), (constants, None), (constants, coeffs)]: A = assemble_matrix(J, coeffs=c) A.assemble() assert (A - A0).norm() > 1.0e-5
def test_tensor_constant(): mesh = create_unit_cube(MPI.COMM_WORLD, 2, 2, 2) data = [[1.0, 2.0, 1.0], [1.0, 2.0, 1.0], [1.0, 2.0, 1.0]] c0 = Constant(mesh, data) assert c0.value.shape == (3, 3) assert c0.value.all() == np.asarray(data).all() c0.value *= 2.0 assert c0.value.all() == (2.0 * np.asarray(data)).all()
def assemble_div_vector(k, offset): mesh = create_quad_mesh(offset) V = FunctionSpace(mesh, ("RTCF", k + 1)) v = ufl.TestFunction(V) L = form( ufl.inner(Constant(mesh, PETSc.ScalarType(1)), ufl.div(v)) * ufl.dx) b = assemble_vector(L) return b[:]
def test_scalar_constant(): mesh = create_unit_cube(MPI.COMM_WORLD, 2, 2, 2) c = Constant(mesh, 1.0) assert c.value.shape == () assert c.value == 1.0 c.value += 1.0 assert c.value == 2.0 c.value = 3.0 assert c.value == 3.0
def test_facet_area1D(): mesh = create_unit_interval(MPI.COMM_WORLD, 10) # NOTE: Area of a vertex is defined to 1 in ufl c0 = ufl.FacetArea(mesh) c = Constant(mesh, ScalarType(1)) ds = ufl.Measure("ds", domain=mesh) a0 = mesh.comm.allreduce(assemble_scalar(form(c * ds)), op=MPI.SUM) a = mesh.comm.allreduce(assemble_scalar(form(c0 * ds)), op=MPI.SUM) assert numpy.isclose(a.real, 2) assert numpy.isclose(a0.real, 2)
def test_facet_area(mesh_factory): """ Compute facet area of cell. UFL currently only supports affine cells for this computation """ # NOTE: UFL only supports facet area calculations of affine cells func, args, exact_area = mesh_factory mesh = func(*args) c0 = ufl.FacetArea(mesh) c = Constant(mesh, ScalarType(1)) tdim = mesh.topology.dim num_faces = 4 if tdim == 2 else 6 ds = ufl.Measure("ds", domain=mesh) a = mesh.comm.allreduce(assemble_scalar(form(c * ds)), op=MPI.SUM) a0 = mesh.comm.allreduce(assemble_scalar(form(c0 * ds)), op=MPI.SUM) assert numpy.isclose(a.real, num_faces) assert numpy.isclose(a0.real, num_faces * exact_area)
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_simple_evaluation(): """Test evaluation of UFL Expression. This test evaluates a UFL Expression on cells of the mesh and compares the result with an analytical expression. For a function f(x, y) = 3*(x^2 + 2*y^2) the result is compared with the exact gradient: grad f(x, y) = 3*[2*x, 4*y]. (x^2 + 2*y^2) is first interpolated into a P2 finite element space. The scaling by a constant factor of 3 and the gradient is calculated using code generated by FFCx. The analytical solution is found by evaluating the spatial coordinates as an Expression using UFL/FFCx and passing the result to a numpy function that calculates the exact gradient. """ mesh = create_unit_square(MPI.COMM_WORLD, 3, 3) P2 = FunctionSpace(mesh, ("P", 2)) # NOTE: The scaling by a constant factor of 3.0 to get f(x, y) is # implemented within the UFL Expression. This is to check that the # Constants are being set up correctly. def exact_expr(x): return x[0]**2 + 2.0 * x[1]**2 # Unused, but remains for clarity. def f(x): return 3 * (x[0]**2 + 2.0 * x[1]**2) def exact_grad_f(x): values = np.zeros_like(x) values[:, 0::2] = 2 * x[:, 0::2] values[:, 1::2] = 4 * x[:, 1::2] values *= 3.0 return values expr = Function(P2) expr.interpolate(exact_expr) ufl_grad_f = Constant(mesh, PETSc.ScalarType(3.0)) * ufl.grad(expr) points = np.array([[0.0, 0.0], [1.0, 0.0], [0.0, 1.0]]) grad_f_expr = Expression(ufl_grad_f, points) assert grad_f_expr.X.shape[0] == points.shape[0] assert grad_f_expr.value_size == 2 # NOTE: Cell numbering is process local. map_c = mesh.topology.index_map(mesh.topology.dim) num_cells = map_c.size_local + map_c.num_ghosts cells = np.arange(0, num_cells, dtype=np.int32) grad_f_evaluated = grad_f_expr.eval(cells) assert grad_f_evaluated.shape[0] == cells.shape[0] assert grad_f_evaluated.shape[ 1] == grad_f_expr.value_size * grad_f_expr.X.shape[0] # Evaluate points in global space ufl_x = ufl.SpatialCoordinate(mesh) x_expr = Expression(ufl_x, points) assert x_expr.X.shape[0] == points.shape[0] assert x_expr.value_size == 2 x_evaluated = x_expr.eval(cells) assert x_evaluated.shape[0] == cells.shape[0] assert x_evaluated.shape[1] == x_expr.X.shape[0] * x_expr.value_size # Evaluate exact gradient using global points grad_f_exact = exact_grad_f(x_evaluated) assert np.allclose(grad_f_evaluated, grad_f_exact)
lid_velocity.interpolate(lid_velocity_expression) facets = locate_entities_boundary(msh, 1, lid) bc1 = dirichletbc(lid_velocity, locate_dofs_topological(V, 1, facets)) # Collect Dirichlet boundary conditions bcs = [bc0, bc1] # - # We now define the bilinear and linear forms corresponding to the weak # mixed formulation of the Stokes equations in a blocked structure: # + # Define variational problem (u, p) = ufl.TrialFunction(V), ufl.TrialFunction(Q) (v, q) = ufl.TestFunction(V), ufl.TestFunction(Q) f = Constant(msh, (PETSc.ScalarType(0), PETSc.ScalarType(0))) a = form([[inner(grad(u), grad(v)) * dx, inner(p, div(v)) * dx], [inner(div(u), q) * dx, None]]) L = form([inner(f, v) * dx, inner(Constant(msh, PETSc.ScalarType(0)), q) * dx]) # - # We will use a block-diagonal preconditioner to solve this problem: a_p11 = form(inner(p, q) * dx) a_p = [[a[0][0], None], [None, a_p11]] # ### Nested matrix solver # # We now assemble the bilinear form into a nested matrix `A`, and call # the `assemble()` method to communicate shared entries in parallel.
np.concatenate([dofs_alpha_left, dofs_alpha_right]), V_alpha, ) ] set_bc(alpha_ub.vector, bcs_alpha) alpha_ub.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) bcs = {"bcs_u": bcs_u, "bcs_alpha": bcs_alpha} # Define the model model = Brittle(parameters["model"]) # Energy functional f = Constant(mesh, np.array([0, 0], dtype=PETSc.ScalarType)) external_work = ufl.dot(f, state["u"]) * dx total_energy = model.total_energy_density(state) * dx - external_work load_par = parameters["loading"] loads = np.linspace(load_par["min"], load_par["max"], load_par["steps"]) solver = AlternateMinimisation(total_energy, state, bcs, parameters.get("solvers"), bounds=(alpha_lb, alpha_ub)) history_data = { "load": [], "elastic_energy": [],
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 demo_stacked_cubes(theta, ct, noslip, num_refinements, N0, timings=False): celltype = "hexahedron" if ct == CellType.hexahedron else "tetrahedron" type_ext = "no_slip" if noslip else "slip" log_info(f"Run theta: {theta:.2f}, Cell: {celltype:s}, Noslip: {noslip:b}") # Read in mesh mesh_3D_dolfin(theta=theta, ct=ct, ext=celltype, num_refinements=num_refinements, N0=N0) comm.barrier() with XDMFFile(comm, f"meshes/mesh_{celltype}_{theta:.2f}.xdmf", "r") as xdmf: mesh = xdmf.read_mesh(name="mesh") tdim = mesh.topology.dim fdim = tdim - 1 mesh.topology.create_connectivity(tdim, tdim) mesh.topology.create_connectivity(fdim, tdim) mt = xdmf.read_meshtags(mesh, "facet_tags") mesh.name = f"mesh_{celltype}_{theta:.2f}{type_ext:s}" # Create functionspaces V = VectorFunctionSpace(mesh, ("Lagrange", 1)) # Define boundary conditions # Bottom boundary is fixed in all directions u_bc = Function(V) with u_bc.vector.localForm() as u_local: u_local.set(0.0) bottom_dofs = locate_dofs_topological(V, fdim, mt.find(5)) bc_bottom = dirichletbc(u_bc, bottom_dofs) g_vec = [0, 0, -4.25e-1] if not noslip: # Helper for orienting traction r_matrix = rotation_matrix([1 / np.sqrt(2), 1 / np.sqrt(2), 0], -theta) # Top boundary has a given deformation normal to the interface g_vec = np.dot(r_matrix, [0, 0, -4.25e-1]) def top_v(x): values = np.empty((3, x.shape[1])) values[0] = g_vec[0] values[1] = g_vec[1] values[2] = g_vec[2] return values u_top = Function(V) u_top.interpolate(top_v) u_top.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT_VALUES, mode=PETSc.ScatterMode.FORWARD) top_dofs = locate_dofs_topological(V, fdim, mt.find(3)) bc_top = dirichletbc(u_top, top_dofs) bcs = [bc_bottom, bc_top] # 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 rhs = inner(Constant(mesh, PETSc.ScalarType((0, 0, 0))), v) * dx log_info("Create constraints") mpc = MultiPointConstraint(V) num_dofs = V.dofmap.index_map.size_global * V.dofmap.index_map_bs if noslip: with Timer(f"{num_dofs}: Contact-constraint"): mpc.create_contact_inelastic_condition(mt, 4, 9) else: with Timer(f"{num_dofs}: FacetNormal"): nh = create_normal_approximation(V, mt, 4) with Timer(f"{num_dofs}: Contact-constraint"): mpc.create_contact_slip_condition(mt, 4, 9, nh) with Timer(f"{num_dofs}: MPC-init"): mpc.finalize() null_space = rigid_motions_nullspace(mpc.function_space) log_info(f"Num dofs: {num_dofs}") log_info("Assemble matrix") bilinear_form = form(a) linear_form = form(rhs) with Timer(f"{num_dofs}: Assemble-matrix (C++)"): A = assemble_matrix(bilinear_form, mpc, bcs=bcs) with Timer(f"{num_dofs}: Assemble-vector (C++)"): b = assemble_vector(linear_form, mpc) apply_lifting(b, [bilinear_form], [bcs], mpc) b.ghostUpdate(addv=PETSc.InsertMode.ADD_VALUES, mode=PETSc.ScatterMode.REVERSE) set_bc(b, bcs) list_timings(MPI.COMM_WORLD, [TimingType.wall]) # Solve Linear problem opts = PETSc.Options() # 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"] = 1e-2 # opts["help"] = None # List all available options if timings: opts["ksp_view"] = None # List progress of solver # Create functionspace and build near nullspace A.setNearNullSpace(null_space) solver = PETSc.KSP().create(comm) solver.setOperators(A) solver.setFromOptions() uh = b.copy() uh.set(0) log_info("Solve") with Timer(f"{num_dofs}: Solve"): solver.solve(b, uh) uh.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) log_info("Backsub") with Timer(f"{num_dofs}: Backsubstitution"): mpc.backsubstitution(uh) it = solver.getIterationNumber() # Write solution to file u_h = Function(mpc.function_space) u_h.vector.setArray(uh.array) u_h.name = "u" with XDMFFile(comm, f"results/bench_contact_{num_dofs}.xdmf", "w") as outfile: outfile.write_mesh(mesh) outfile.write_function(u_h, 0.0, f"Xdmf/Domain/Grid[@Name='{mesh.name}'][1]") # Write performance data to file if timings: log_info("Timings") num_slaves = MPI.COMM_WORLD.allreduce(mpc.num_local_slaves, op=MPI.SUM) results_file = None num_procs = comm.size if comm.rank == 0: results_file = open(f"results_bench_{num_dofs}.txt", "w") print(f"#Procs: {num_procs}", file=results_file) print(f"#Dofs: {num_dofs}", file=results_file) print(f"#Slaves: {num_slaves}", file=results_file) print(f"#Iterations: {it}", file=results_file) operations = [ "Solve", "Assemble-matrix (C++)", "MPC-init", "Contact-constraint", "FacetNormal", "Assemble-vector (C++)", "Backsubstitution" ] if comm.rank == 0: print("Operation #Calls Avg Min Max", file=results_file) for op in operations: op_timing = timing(f"{num_dofs}: {op}") num_calls = op_timing[0] wall_time = op_timing[1] avg_time = comm.allreduce(wall_time, op=MPI.SUM) / comm.size min_time = comm.allreduce(wall_time, op=MPI.MIN) max_time = comm.allreduce(wall_time, op=MPI.MAX) if comm.rank == 0: print(op, num_calls, avg_time, min_time, max_time, file=results_file) list_timings(MPI.COMM_WORLD, [TimingType.wall])
def test_wrong_dim(): mesh = create_unit_cube(MPI.COMM_WORLD, 2, 2, 2) c = Constant(mesh, [1.0, 2.0]) assert c.value.shape == (2, ) with pytest.raises(ValueError): c.value = [1.0, 2.0, 3.0]
def test_reshape(): mesh = create_unit_cube(MPI.COMM_WORLD, 2, 2, 2) c = Constant(mesh, 1.0) with pytest.raises(ValueError): c.value.resize(100)
def test_assembly_into_quadrature_function(): """Test assembly into a Quadrature function. This test evaluates a UFL Expression into a Quadrature function space by evaluating the Expression on all cells of the mesh, and then inserting the evaluated values into a PETSc Vector constructed from a matching Quadrature function space. Concretely, we consider the evaluation of: e = B*(K(T)))**2 * grad(T) where K = 1/(A + B*T) where A and B are Constants and T is a Coefficient on a P2 finite element space with T = x + 2*y. The result is compared with interpolating the analytical expression of e directly into the Quadrature space. In parallel, each process evaluates the Expression on both local cells and ghost cells so that no parallel communication is required after insertion into the vector. """ mesh = create_unit_square(MPI.COMM_WORLD, 3, 6) quadrature_degree = 2 quadrature_points, wts = basix.make_quadrature(basix.CellType.triangle, quadrature_degree) Q_element = ufl.VectorElement("Quadrature", ufl.triangle, quadrature_degree, quad_scheme="default") Q = FunctionSpace(mesh, Q_element) P2 = FunctionSpace(mesh, ("P", 2)) T = Function(P2) T.interpolate(lambda x: x[0] + 2.0 * x[1]) A = Constant(mesh, PETSc.ScalarType(1.0)) B = Constant(mesh, PETSc.ScalarType(2.0)) K = 1.0 / (A + B * T) e = B * K**2 * ufl.grad(T) e_expr = Expression(e, quadrature_points) map_c = mesh.topology.index_map(mesh.topology.dim) num_cells = map_c.size_local + map_c.num_ghosts cells = np.arange(0, num_cells, dtype=np.int32) e_eval = e_expr.eval(cells) # Assemble into Function e_Q = Function(Q) with e_Q.vector.localForm() as e_Q_local: e_Q_local.setBlockSize(e_Q.function_space.dofmap.bs) e_Q_local.setValuesBlocked(Q.dofmap.list.array, e_eval, addv=PETSc.InsertMode.INSERT) def e_exact(x): T = x[0] + 2.0 * x[1] K = 1.0 / (A.value + B.value * T) grad_T = np.zeros((2, x.shape[1])) grad_T[0, :] = 1.0 grad_T[1, :] = 2.0 e = B.value * K**2 * grad_T return e # FIXME: Below is only for testing purposes, # never to be used in user code! # # Replace when interpolation into Quadrature element works. coord_dofs = mesh.geometry.dofmap x_g = mesh.geometry.x tdim = mesh.topology.dim Q_dofs = Q.dofmap.list.array.reshape(num_cells, quadrature_points.shape[0]) bs = Q.dofmap.bs Q_dofs_unrolled = bs * np.repeat(Q_dofs, bs).reshape(-1, bs) + np.arange(bs) Q_dofs_unrolled = Q_dofs_unrolled.reshape( -1, bs * quadrature_points.shape[0]).astype(Q_dofs.dtype) with e_Q.vector.localForm() as local: e_exact_eval = np.zeros_like(local.array) for cell in range(num_cells): xg = x_g[coord_dofs.links(cell), :tdim] x = mesh.geometry.cmap.push_forward(quadrature_points, xg) e_exact_eval[Q_dofs_unrolled[cell]] = e_exact(x.T).T.flatten() assert np.allclose(local.array, e_exact_eval)
tau, v = ufl.TestFunctions(V) def S(tau): return tau - ufl.Identity(2) * ufl.tr(tau) # Discrete duality inner product # cf. eq. 4.5 Lizao Li's PhD thesis def b(tau_S, v): n = FacetNormal(mesh) return inner(tau_S, grad(grad(v))) * dx \ - ufl.dot(ufl.dot(tau_S('+'), n('+')), n('+')) * jump(grad(v), n) * dS \ - ufl.dot(ufl.dot(tau_S, n), n) * ufl.dot(grad(v), n) * ds sigma_S = S(sigma) tau_S = S(tau) f_exact = Constant(mesh, np.array(-1., dtype=PETSc.ScalarType)) # Non-symmetric formulation a = form(ufl.inner(sigma_S, tau_S) * dx - b(tau_S, u) + b(sigma_S, v)) L = form(ufl.inner(f_exact, v) * dx) zero_u = Function(V_1) zero_u.x.array[:] = 0.0 boundary_facets = dolfinx.mesh.locate_entities_boundary( mesh, mesh.topology.dim - 1, lambda x: np.full(x.shape[1], True, dtype=bool)) boundary_dofs = dolfinx.fem.locate_dofs_topological( (V.sub(1), V_1), mesh.topology.dim - 1, boundary_facets) bcs = [dirichletbc(zero_u, boundary_dofs, V.sub(1))]
# 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) dx = Measure("dx", domain=mesh, subdomain_data=ct) a = inner(sigma(u), grad(v)) * dx x = SpatialCoordinate(mesh) rhs = inner(Constant(mesh, PETSc.ScalarType((0, 0, 0))), v) * dx rhs += inner(Constant(mesh, PETSc.ScalarType((0.01, 0.02, 0))), v) * dx(outer_tag) rhs += inner(as_vector(PETSc.ScalarType((0, 0, -9.81e-2))), v) * dx(inner_tag) # Create dirichletbc owning_processor, bc_dofs = determine_closest_block(V, -np.array([-r2, 0, 0])) bc_dofs = [] if bc_dofs is None else bc_dofs u_fixed = np.array([0, 0, 0], dtype=PETSc.ScalarType) bc_fixed = dirichletbc(u_fixed, np.asarray(bc_dofs, dtype=np.int32), V) bcs = [bc_fixed] # Create point to point constraints mpc = MultiPointConstraint(V) signs = [-1, 1]
# Driving velocity condition u = (1, 0) on top boundary (y = 1) lid_velocity = Function(V) lid_velocity.interpolate(lid_velocity_expression) facets = locate_entities_boundary(mesh, 1, lid) bc1 = dirichletbc(lid_velocity, locate_dofs_topological(V, 1, facets)) # Collect Dirichlet boundary conditions bcs = [bc0, bc1] # We now define the bilinear and linear forms corresponding to the weak # mixed formulation of the Stokes equations in a blocked structure:: # Define variational problem (u, p) = ufl.TrialFunction(V), ufl.TrialFunction(Q) (v, q) = ufl.TestFunction(V), ufl.TestFunction(Q) f = Constant(mesh, (PETSc.ScalarType(0), PETSc.ScalarType(0))) a = form([[inner(grad(u), grad(v)) * dx, inner(p, div(v)) * dx], [inner(div(u), q) * dx, None]]) L = form( [inner(f, v) * dx, inner(Constant(mesh, PETSc.ScalarType(0)), q) * dx]) # We will use a block-diagonal preconditioner to solve this problem:: a_p11 = form(inner(p, q) * dx) a_p = [[a[0][0], None], [None, a_p11]] # Nested matrix solver # ^^^^^^^^^^^^^^^^^^^^ #
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 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)
(1 - 2 * nu_right)) # 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) dx = Measure("dx", domain=mesh, subdomain_data=ct) a = inner(sigma(u), grad(v)) * dx x = SpatialCoordinate(mesh) rhs = inner(Constant(mesh, PETSc.ScalarType((0, 0))), v) * dx # Set boundary conditions u_push = np.array([0.1, 0], dtype=PETSc.ScalarType) dofs = locate_dofs_geometrical(V, lambda x: np.isclose(x[0], 0)) bc_push = dirichletbc(u_push, dofs, V) u_fix = np.array([0, 0], dtype=PETSc.ScalarType) bc_fix = dirichletbc( u_fix, locate_dofs_geometrical(V, lambda x: np.isclose(x[0], 2.1)), V) bcs = [bc_push, bc_fix] def gather_dof_coordinates(V: FunctionSpace, dofs: np.ndarray): """ Distributes the dof coordinates of this subset of dofs to all processors """