def test_mpc_assembly(master_point, degree, celltype, get_assemblers): # noqa: F811 _, assemble_vector = get_assemblers # Create mesh and function space mesh = create_unit_square(MPI.COMM_WORLD, 3, 5, celltype) V = fem.FunctionSpace(mesh, ("Lagrange", degree)) # Generate reference vector v = ufl.TestFunction(V) x = ufl.SpatialCoordinate(mesh) f = ufl.sin(2 * ufl.pi * x[0]) * ufl.sin(ufl.pi * x[1]) rhs = ufl.inner(f, v) * ufl.dx linear_form = fem.form(rhs) def l2b(li): return np.array(li, dtype=np.float64).tobytes() s_m_c = { l2b([1, 0]): { l2b([0, 1]): 0.43, l2b([1, 1]): 0.11 }, l2b([0, 0]): { l2b(master_point): 0.69 } } mpc = dolfinx_mpc.MultiPointConstraint(V) mpc.create_general_constraint(s_m_c) mpc.finalize() b = assemble_vector(linear_form, mpc) b.ghostUpdate(addv=PETSc.InsertMode.ADD_VALUES, mode=PETSc.ScatterMode.REVERSE) # Reduce system with global matrix K after assembly 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_rhs(L_org, b, mpc, root=root) list_timings(comm, [TimingType.wall])
def run_vector_test(mesh, V, degree): """Projection into H(div/curl) spaces""" u, v = ufl.TrialFunction(V), ufl.TestFunction(V) a = inner(u, v) * dx # Source term x = SpatialCoordinate(mesh) u_exact = x[0]**degree L = inner(u_exact, v[0]) * dx with common.Timer("Assemble vector"): b = assemble_vector(L) b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) with common.Timer("Assemble matrix"): A = assemble_matrix(a) A.assemble() with common.Timer("Solve"): # Create LU linear solver (Note: need to use a solver that # re-orders to handle pivots, e.g. not the PETSc built-in LU solver) solver = PETSc.KSP().create(MPI.COMM_WORLD) solver.setType("preonly") solver.getPC().setType('lu') solver.setOperators(A) # Solve uh = Function(V) solver.solve(b, uh.vector) uh.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) with common.Timer("Error functional compile"): # Calculate error M = (u_exact - uh[0])**2 * dx for i in range(1, mesh.topology.dim): M += uh[i]**2 * dx M = fem.Form(M) with common.Timer("Error assembly"): error = mesh.mpi_comm().allreduce(assemble_scalar(M), op=MPI.SUM) common.list_timings(MPI.COMM_WORLD, [common.TimingType.wall]) assert np.absolute(error) < 1.0e-14
def test_slave_on_same_cell(master_point, degree, celltype, get_assemblers): # noqa: F811 assemble_matrix, _ = get_assemblers # Create mesh and function space mesh = create_unit_square(MPI.COMM_WORLD, 1, 8, celltype) V = fem.FunctionSpace(mesh, ("Lagrange", degree)) # Build master slave map s_m_c = { np.array([1, 0], dtype=np.float64).tobytes(): { np.array([0, 1], dtype=np.float64).tobytes(): 0.43, np.array([1, 1], dtype=np.float64).tobytes(): 0.11 }, np.array([0, 0], dtype=np.float64).tobytes(): { np.array(master_point, dtype=np.float64).tobytes(): 0.69 } } with Timer("~TEST: MPC INIT"): mpc = dolfinx_mpc.MultiPointConstraint(V) mpc.create_general_constraint(s_m_c) mpc.finalize() # Test against generated code and general assembler u = ufl.TrialFunction(V) v = ufl.TestFunction(V) a = ufl.inner(ufl.grad(u), ufl.grad(v)) * ufl.dx bilinear_form = fem.form(a) with Timer("~TEST: Assemble matrix"): A_mpc = assemble_matrix(bilinear_form, mpc) with Timer("~TEST: Compare with numpy"): # Create globally reduced system A_org = fem.petsc.assemble_matrix(bilinear_form) A_org.assemble() dolfinx_mpc.utils.compare_mpc_lhs(A_org, A_mpc, mpc) list_timings(mesh.comm, [TimingType.wall])
def run_scalar_test(mesh, V, degree): """ Manufactured Poisson problem, solving u = x[1]**p, where p is the degree of the Lagrange function space. """ u, v = TrialFunction(V), TestFunction(V) a = inner(grad(u), grad(v)) * dx # Get quadrature degree for bilinear form integrand (ignores effect of non-affine map) a = inner(grad(u), grad(v)) * dx(metadata={"quadrature_degree": -1}) a.integrals()[0].metadata( )["quadrature_degree"] = ufl.algorithms.estimate_total_polynomial_degree(a) # Source term x = SpatialCoordinate(mesh) u_exact = x[1]**degree f = -div(grad(u_exact)) # Set quadrature degree for linear form integrand (ignores effect of non-affine map) L = inner(f, v) * dx(metadata={"quadrature_degree": -1}) L.integrals()[0].metadata( )["quadrature_degree"] = ufl.algorithms.estimate_total_polynomial_degree(L) with common.Timer("Linear form compile"): L = fem.Form(L) with common.Timer("Function interpolation"): u_bc = Function(V) u_bc.interpolate(lambda x: x[1]**degree) # Create Dirichlet boundary condition mesh.topology.create_connectivity_all() facetdim = mesh.topology.dim - 1 bndry_facets = np.where( np.array(cpp.mesh.compute_boundary_facets(mesh.topology)) == 1)[0] bdofs = locate_dofs_topological(V, facetdim, bndry_facets) bc = DirichletBC(u_bc, bdofs) with common.Timer("Vector assembly"): b = assemble_vector(L) apply_lifting(b, [a], [[bc]]) b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) set_bc(b, [bc]) with common.Timer("Bilinear form compile"): a = fem.Form(a) with common.Timer("Matrix assembly"): A = assemble_matrix(a, [bc]) A.assemble() # Create LU linear solver solver = PETSc.KSP().create(MPI.COMM_WORLD) solver.setType(PETSc.KSP.Type.PREONLY) solver.getPC().setType(PETSc.PC.Type.LU) solver.setOperators(A) with common.Timer("Solve"): uh = Function(V) solver.solve(b, uh.vector) uh.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) with common.Timer("Error functional compile"): M = (u_exact - uh)**2 * dx M = fem.Form(M) with common.Timer("Error assembly"): error = mesh.mpi_comm().allreduce(assemble_scalar(M), op=MPI.SUM) common.list_timings(MPI.COMM_WORLD, [common.TimingType.wall]) assert np.absolute(error) < 1.0e-14
def run_dg_test(mesh, V, degree): """ Manufactured Poisson problem, solving u = x[component]**n, where n is the degree of the Lagrange function space. """ u, v = TrialFunction(V), TestFunction(V) # Exact solution x = SpatialCoordinate(mesh) u_exact = x[1]**degree # Coefficient k = Function(V) k.vector.set(2.0) k.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) # Source term f = -div(k * grad(u_exact)) # Mesh normals and element size n = FacetNormal(mesh) h = CellDiameter(mesh) h_avg = (h("+") + h("-")) / 2.0 # Penalty parameter alpha = 32 dx_ = dx(metadata={"quadrature_degree": -1}) ds_ = ds(metadata={"quadrature_degree": -1}) dS_ = dS(metadata={"quadrature_degree": -1}) with common.Timer("Compile forms"): a = inner(k * grad(u), grad(v)) * dx_ \ - k("+") * inner(avg(grad(u)), jump(v, n)) * dS_ \ - k("+") * inner(jump(u, n), avg(grad(v))) * dS_ \ + k("+") * (alpha / h_avg) * inner(jump(u, n), jump(v, n)) * dS_ \ - inner(k * grad(u), v * n) * ds_ \ - inner(u * n, k * grad(v)) * ds_ \ + (alpha / h) * inner(k * u, v) * ds_ L = inner(f, v) * dx_ - inner(k * u_exact * n, grad(v)) * ds_ \ + (alpha / h) * inner(k * u_exact, v) * ds_ for integral in a.integrals(): integral.metadata( )["quadrature_degree"] = ufl.algorithms.estimate_total_polynomial_degree( a) for integral in L.integrals(): integral.metadata( )["quadrature_degree"] = ufl.algorithms.estimate_total_polynomial_degree( L) with common.Timer("Assemble vector"): b = assemble_vector(L) b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) with common.Timer("Assemble matrix"): A = assemble_matrix(a, []) A.assemble() with common.Timer("Solve"): # Create LU linear solver 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 = Function(V) solver.solve(b, uh.vector) uh.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) with common.Timer("Error functional compile"): # Calculate error M = (u_exact - uh)**2 * dx M = fem.Form(M) with common.Timer("Error assembly"): error = mesh.mpi_comm().allreduce(assemble_scalar(M), op=MPI.SUM) common.list_timings(MPI.COMM_WORLD, [common.TimingType.wall]) assert np.absolute(error) < 1.0e-14
history_data["dissipated_energy"].append(dissipated_energy) history_data["elastic_energy"].append(elastic_energy) history_data["total_energy"].append(elastic_energy + dissipated_energy) history_data["solver_data"].append(solver.data) with XDMFFile(comm, f"{prefix}.xdmf", "a", encoding=XDMFFile.Encoding.HDF5) as file: file.write_function(u, t) file.write_function(alpha, t) if comm.rank == 0: a_file = open(f"{prefix}-data.json", "w") json.dump(history_data, a_file) a_file.close() list_timings(MPI.COMM_WORLD, [dolfinx.common.TimingType.wall]) import pandas as pd df = pd.DataFrame(history_data) print(df) # Viz xvfb.start_xvfb(wait=0.05) pyvista.OFF_SCREEN = True plotter = pyvista.Plotter( title="Displacement", window_size=[1600, 600], shape=(1, 2), ) _plt = plot_scalar(alpha, plotter, subplot=(0, 0))
def test_pipeline(master_point, get_assemblers): # noqa: F811 assemble_matrix, assemble_vector = get_assemblers # Create mesh and function space mesh = create_unit_square(MPI.COMM_WORLD, 3, 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(1.5)) c = fem.Constant(mesh, PETSc.ScalarType(2)) x = ufl.SpatialCoordinate(mesh) f = c * ufl.sin(2 * ufl.pi * x[0]) * ufl.sin(ufl.pi * x[1]) g = fem.Function(V) g.interpolate(lambda x: np.sin(x[0]) * x[1]) h = fem.Function(V) h.interpolate(lambda x: 2 + x[1] * x[0]) a = d * g * ufl.inner(ufl.grad(u), ufl.grad(v)) * ufl.dx rhs = h * 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 l2b(li): return np.array(li, dtype=np.float64).tobytes() s_m_c = { l2b([1, 0]): { l2b([0, 1]): 0.43, l2b([1, 1]): 0.11 }, l2b([0, 0]): { l2b(master_point): 0.69 } } mpc = dolfinx_mpc.MultiPointConstraint(V) mpc.create_general_constraint(s_m_c) mpc.finalize() A = assemble_matrix(bilinear_form, mpc) 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])
def test_linearproblem(master_point): # Create mesh and function space mesh = create_unit_square(MPI.COMM_WORLD, 3, 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(1.5)) c = fem.Constant(mesh, PETSc.ScalarType(2)) x = ufl.SpatialCoordinate(mesh) f = c * ufl.sin(2 * ufl.pi * x[0]) * ufl.sin(ufl.pi * x[1]) g = fem.Function(V) g.interpolate(lambda x: np.sin(x[0]) * x[1]) h = fem.Function(V) h.interpolate(lambda x: 2 + x[1] * x[0]) a = d * g * ufl.inner(ufl.grad(u), ufl.grad(v)) * ufl.dx rhs = h * ufl.inner(f, v) * ufl.dx # Generate reference matrices A_org = fem.petsc.assemble_matrix(fem.form(a)) A_org.assemble() L_org = fem.petsc.assemble_vector(fem.form(rhs)) L_org.ghostUpdate(addv=PETSc.InsertMode.ADD_VALUES, mode=PETSc.ScatterMode.REVERSE) # Create multipoint constraint def l2b(li): return np.array(li, dtype=np.float64).tobytes() s_m_c = { l2b([1, 0]): { l2b([0, 1]): 0.43, l2b([1, 1]): 0.11 }, l2b([0, 0]): { l2b(master_point): 0.69 } } mpc = dolfinx_mpc.MultiPointConstraint(V) mpc.create_general_constraint(s_m_c) mpc.finalize() problem = dolfinx_mpc.LinearProblem(a, rhs, mpc, bcs=[], petsc_options={ "ksp_type": "preonly", "pc_type": "lu" }) uh = problem.solve() root = 0 comm = mesh.comm with Timer("~TEST: Compare"): 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) list_timings(comm, [TimingType.wall])
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])
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_cube_contact(generate_hex_boxes, nonslip, get_assemblers): # noqa: F811 assemble_matrix, assemble_vector = get_assemblers comm = MPI.COMM_WORLD root = 0 # Generate mesh mesh_data = generate_hex_boxes mesh, mt = mesh_data fdim = mesh.topology.dim - 1 # Create functionspaces V = fem.VectorFunctionSpace(mesh, ("Lagrange", 1)) # Helper for orienting traction # Bottom boundary is fixed in all directions u_bc = fem.Function(V) with u_bc.vector.localForm() as u_local: u_local.set(0.0) bottom_dofs = fem.locate_dofs_topological(V, fdim, mt.find(5)) bc_bottom = fem.dirichletbc(u_bc, bottom_dofs) g_vec = [0, 0, -4.25e-1] if not nonslip: # Helper for orienting traction r_matrix = dolfinx_mpc.utils.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]) # Top boundary has a given deformation normal to the interface 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 = fem.Function(V) u_top.interpolate(top_v) top_dofs = fem.locate_dofs_topological(V, fdim, mt.find(3)) bc_top = fem.dirichletbc(u_top, top_dofs) bcs = [bc_bottom, bc_top] # Elasticity parameters E = PETSc.ScalarType(1.0e3) nu = 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, 0))), v) * ufl.dx bilinear_form = fem.form(a) linear_form = fem.form(rhs) # Create LU solver solver = PETSc.KSP().create(comm) solver.setType("preonly") solver.setTolerances(rtol=1.0e-14) solver.getPC().setType("lu") # Create MPC contact condition and assemble matrices mpc = dolfinx_mpc.MultiPointConstraint(V) if nonslip: with Timer("~Contact: Create non-elastic constraint"): mpc.create_contact_inelastic_condition(mt, 4, 9) else: with Timer("~Contact: Create contact constraint"): nh = dolfinx_mpc.utils.create_normal_approximation(V, mt, 4) mpc.create_contact_slip_condition(mt, 4, 9, nh) mpc.finalize() with Timer("~TEST: Assemble bilinear form"): 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) with Timer("~MPC: Solve"): 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 = fem.Function(mpc.function_space) # u_h.vector.setArray(uh.array) # u_h.x.scatter_forward() # u_h.name = "u_{0:.2f}".format(theta) # import dolfinx.io as io # with io.XDMFFile(comm, "output/rotated_cube3D.xdmf", "w") as outfile: # 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 dolfinx_mpc.utils.log_info( "Solving reference problem with global matrix (using numpy)") with Timer("~TEST: Assemble bilinear form (unconstrained)"): 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) 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])
def test_lifting(get_assemblers): # noqa: F811 """ Test MPC lifting operation on a single cell """ assemble_matrix, assemble_vector = get_assemblers # Create mesh and function space mesh = create_unit_square(MPI.COMM_WORLD, 1, 1, CellType.quadrilateral) V = fem.FunctionSpace(mesh, ("Lagrange", 1)) # Solve Problem without MPC for reference u = ufl.TrialFunction(V) v = ufl.TestFunction(V) x = ufl.SpatialCoordinate(mesh) f = x[1] * ufl.sin(2 * ufl.pi * x[0]) a = ufl.inner(ufl.grad(u), ufl.grad(v)) * ufl.dx rhs = ufl.inner(f, v) * ufl.dx bilinear_form = fem.form(a) linear_form = fem.form(rhs) # Create Dirichlet boundary condition u_bc = fem.Function(V) with u_bc.vector.localForm() as u_local: u_local.set(2.3) def dirichletboundary(x): return np.isclose(x[0], 1) mesh.topology.create_connectivity(2, 1) geometrical_dofs = fem.locate_dofs_geometrical(V, dirichletboundary) bc = fem.dirichletbc(u_bc, geometrical_dofs) bcs = [bc] # Generate reference matrices A_org = fem.petsc.assemble_matrix(bilinear_form, bcs=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) # Create multipoint constraint def l2b(li): return np.array(li, dtype=np.float64).tobytes() s_m_c = {l2b([0, 0]): {l2b([0, 1]): 1}} mpc = dolfinx_mpc.MultiPointConstraint(V) mpc.create_general_constraint(s_m_c) mpc.finalize() A = assemble_matrix(bilinear_form, mpc, bcs=bcs) 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 = 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) V_mpc = mpc.function_space u_out = fem.Function(V_mpc) u_out.vector.array[:] = uh.array 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) # constants = dolfinx_mpc.utils.gather_contants(mpc, root=root) if MPI.COMM_WORLD.rank == root: KTAK = K.T * A_csr * K reduced_L = K.T @ (L_np) # - constants) # Solve linear system d = scipy.sparse.linalg.spsolve(KTAK, reduced_L) # Back substitution to full solution vecto uh_numpy = K @ (d) # + constants) assert np.allclose(uh_numpy, u_mpc) list_timings(comm, [TimingType.wall])
def demo_stacked_cubes(outfile: XDMFFile, theta: float, gmsh: bool = False, ct: CellType = CellType.tetrahedron, compare: bool = True, res: float = 0.1, noslip: bool = False): celltype = "hexahedron" if ct == CellType.hexahedron else "tetrahedron" type_ext = "no_slip" if noslip else "slip" mesh_ext = "_gmsh_" if gmsh else "_" log_info(f"Run theta:{theta:.2f}, Cell: {celltype}, GMSH {gmsh}, Noslip: {noslip}") # Read in mesh if gmsh: mesh, mt = gmsh_3D_stacked(celltype, theta, res) tdim = mesh.topology.dim fdim = tdim - 1 mesh.topology.create_connectivity(tdim, tdim) mesh.topology.create_connectivity(fdim, tdim) else: mesh_3D_dolfin(theta, ct, celltype, res) MPI.COMM_WORLD.barrier() with XDMFFile(MPI.COMM_WORLD, 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}{mesh_ext}" # Create functionspaces V = fem.VectorFunctionSpace(mesh, ("Lagrange", 1)) # Define boundary conditions # Bottom boundary is fixed in all directions bottom_dofs = fem.locate_dofs_topological(V, fdim, mt.find(5)) # type: ignore u_bc = np.array((0, ) * mesh.geometry.dim, dtype=PETSc.ScalarType) bc_bottom = fem.dirichletbc(u_bc, bottom_dofs, V) g_vec = np.array([0, 0, -4.25e-1], dtype=PETSc.ScalarType) 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, g_vec) top_dofs = fem.locate_dofs_topological(V, fdim, mt.find(3)) # type: ignore bc_top = fem.dirichletbc(g_vec, top_dofs, V) bcs = [bc_bottom, bc_top] # Elasticity parameters E = PETSc.ScalarType(1.0e3) nu = 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 * 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 # NOTE: Traction deactivated until we have a way of fixing nullspace # g = fem.Constant(mesh, PETSc.ScalarType(g_vec)) # ds = Measure("ds", domain=mesh, subdomain_data=mt, subdomain_id=3) rhs = inner(fem.Constant(mesh, PETSc.ScalarType((0, 0, 0))), v) * dx # + inner(g, v) * ds bilinear_form = fem.form(a) linear_form = fem.form(rhs) mpc = MultiPointConstraint(V) if noslip: with Timer("~~Contact: Create non-elastic constraint"): mpc.create_contact_inelastic_condition(mt, 4, 9) else: 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 data and finialize MPC"): mpc.finalize() # Create null-space null_space = rigid_motions_nullspace(mpc.function_space) num_dofs = V.dofmap.index_map.size_global * V.dofmap.index_map_bs with Timer(f"~~Contact: Assemble matrix ({num_dofs})"): A = assemble_matrix(bilinear_form, mpc, bcs=bcs) with Timer(f"~~Contact: Assemble vector ({num_dofs})"): b = assemble_vector(linear_form, 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) # 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 # opts["ksp_view"] = None # List progress of solver # Create functionspace and build near nullspace A.setNearNullSpace(null_space) solver = PETSc.KSP().create(mesh.comm) solver.setOperators(A) solver.setFromOptions() u_h = fem.Function(mpc.function_space) with Timer("~~Contact: Solve"): solver.solve(b, u_h.vector) u_h.x.scatter_forward() with Timer("~~Contact: Backsubstitution"): mpc.backsubstitution(u_h.vector) it = solver.getIterationNumber() unorm = u_h.vector.norm() num_slaves = MPI.COMM_WORLD.allreduce(mpc.num_local_slaves, op=MPI.SUM) if mesh.comm.rank == 0: num_dofs = V.dofmap.index_map.size_global * V.dofmap.index_map_bs print(f"Number of dofs: {num_dofs}") print(f"Number of slaves: {num_slaves}") print(f"Number of iterations: {it}") print(f"Norm of u {unorm:.5e}") # Write solution to file u_h.name = f"u_{celltype}_{theta:.2f}{mesh_ext}{type_ext}".format(celltype, theta, type_ext, mesh_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 scipy)") with Timer("~~Contact: Reference problem"): 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 with Timer("~~Contact: Compare LHS, RHS and solution"): compare_mpc_lhs(A_org, A, mpc, root=root) compare_mpc_rhs(L_org, 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) list_timings(mesh.comm, [TimingType.wall])
def test_vector_possion(Nx, Ny, slave_space, master_space, get_assemblers): # noqa: F811 assemble_matrix, assemble_vector = get_assemblers # Create mesh and function space mesh = create_unit_square(MPI.COMM_WORLD, Nx, Ny) V = fem.VectorFunctionSpace(mesh, ("Lagrange", 1)) def boundary(x): return np.isclose(x.T, [0, 0, 0]).all(axis=1) # Define boundary conditions (HAS TO BE NON-MASTER NODES) u_bc = fem.Function(V) with u_bc.vector.localForm() as u_local: u_local.set(0.0) bdofsV = fem.locate_dofs_geometrical(V, boundary) bc = fem.dirichletbc(u_bc, bdofsV) bcs = [bc] # Define variational problem u = ufl.TrialFunction(V) v = ufl.TestFunction(V) x = ufl.SpatialCoordinate(mesh) f = ufl.as_vector((-5 * x[1], 7 * x[0])) a = ufl.inner(ufl.grad(u), ufl.grad(v)) * ufl.dx rhs = ufl.inner(f, v) * ufl.dx 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) # Create multipoint constraint def l2b(li): return np.array(li, dtype=np.float64).tobytes() s_m_c = {l2b([1, 0]): {l2b([1, 1]): 0.1, l2b([0.5, 1]): 0.3}} mpc = dolfinx_mpc.MultiPointConstraint(V) mpc.create_general_constraint(s_m_c, slave_space, master_space) mpc.finalize() with Timer("~TEST: Assemble matrix"): A = assemble_matrix(bilinear_form, mpc, bcs=bcs) with Timer("~TEST: Assemble vector"): b = dolfinx_mpc.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) # Generate reference matrices for unconstrained problem 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])
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])
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) if __name__ == "__main__": for celltype in [CellType.hexahedron, CellType.tetrahedron]: demo_periodic3D(celltype) list_timings(MPI.COMM_WORLD, [TimingType.wall])
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])