def test_krylov_solver_lu(): mesh = UnitSquareMesh(MPI.comm_world, 12, 12) V = FunctionSpace(mesh, ("Lagrange", 1)) u, v = TrialFunction(V), TestFunction(V) a = inner(u, v) * dx L = inner(1.0, v) * dx A = assemble_matrix(a) A.assemble() b = assemble_vector(L) b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) norm = 13.0 solver = PETScKrylovSolver(mesh.mpi_comm()) solver.set_options_prefix("test_lu_") PETScOptions.set("test_lu_ksp_type", "preonly") PETScOptions.set("test_lu_pc_type", "lu") solver.set_from_options() x = A.createVecRight() solver.set_operator(A) solver.solve(x, b) # *Tight* tolerance for LU solves assert round(x.norm(PETSc.NormType.N2) - norm, 12) == 0
def test_computed_norms_against_references(): # Reference values for norm of solution vector reference = { ("16x16 unit tri square", 1): 9.547454087328376, ("16x16 unit tri square", 2): 18.42366670418269, ("16x16 unit tri square", 3): 27.29583104732836, ("16x16 unit tri square", 4): 36.16867128121694, ("4x4x4 unit tet cube", 1): 12.23389289626038, ("4x4x4 unit tet cube", 2): 28.96491629163837, ("4x4x4 unit tet cube", 3): 49.97350551329799, ("4x4x4 unit tet cube", 4): 74.49938266409099, ("16x16 unit quad square", 1): 9.550848071820747, ("16x16 unit quad square", 2): 18.423668706176354, ("16x16 unit quad square", 3): 27.295831017251672, ("16x16 unit quad square", 4): 36.168671281610855, ("4x4x4 unit hex cube", 1): 12.151954087339782, ("4x4x4 unit hex cube", 2): 28.965646690046885, ("4x4x4 unit hex cube", 3): 49.97349423895635, ("4x4x4 unit hex cube", 4): 74.49938136593539 } # Mesh files and degrees to check meshes = [(UnitSquareMesh(MPI.comm_world, 16, 16), "16x16 unit tri square"), (UnitCubeMesh(MPI.comm_world, 4, 4, 4), "4x4x4 unit tet cube")] # (UnitSquareMesh(MPI.comm_world, 16, 16, CellType.Type.quadrilateral), "16x16 unit quad square"), # (UnitCubeMesh(MPI.comm_world, 4, 4, 4, CellType.Type.hexahedron), "4x4x4 unit hex cube")] degrees = [1, 2] # For MUMPS, increase estimated require memory increase. Typically # required for high order elements on small meshes in 3D PETScOptions.set("mat_mumps_icntl_14", 40) # Iterate over test cases and collect results results = [] for mesh in meshes: for degree in degrees: gc_barrier() norm = compute_norm(mesh[0], degree) results.append((mesh[1], degree, norm)) # Change option back to default PETScOptions.set("mat_mumps_icntl_14", 20) # Check results errors = check_results(results, reference, tol) # Print errors for debugging if they fail if errors: print_errors(errors) # Print results for use as reference if any(e[-1] is None for e in errors): # e[-1] is diff print_reference(results) # A passing test should have no errors assert len(errors) == 0 # See stdout for detailed norms and diffs.
def test_krylov_reuse_pc_lu(): """Test that LU re-factorisation is only performed after set_operator(A) is called""" # Test requires PETSc version 3.5 or later. Use petsc4py to check # version number. try: from petsc4py import PETSc except ImportError: pytest.skip("petsc4py required to check PETSc version") else: if not PETSc.Sys.getVersion() >= (3, 5, 0): pytest.skip("PETSc version must be 3.5 of higher") mesh = UnitSquareMesh(MPI.comm_world, 12, 12) V = FunctionSpace(mesh, ("Lagrange", 1)) u, v = TrialFunction(V), TestFunction(V) a = Constant(1.0) * u * v * dx L = Constant(1.0) * v * dx assembler = fem.Assembler(a, L) A = assembler.assemble_matrix() b = assembler.assemble_vector() norm = 13.0 solver = PETScKrylovSolver(mesh.mpi_comm()) solver.set_options_prefix("test_lu_") PETScOptions.set("test_lu_ksp_type", "preonly") PETScOptions.set("test_lu_pc_type", "lu") solver.set_from_options() solver.set_operator(A) x = PETScVector(mesh.mpi_comm()) solver.solve(x, b) assert round(x.norm(cpp.la.Norm.l2) - norm, 10) == 0 assembler = fem.assemble.Assembler(Constant(0.5) * u * v * dx, L) assembler.assemble(A) x = PETScVector(mesh.mpi_comm()) solver.solve(x, b) assert round(x.norm(cpp.la.Norm.l2) - 2.0 * norm, 10) == 0 solver.set_operator(A) solver.solve(x, b) assert round(x.norm(cpp.la.Norm.l2) - 2.0 * norm, 10) == 0
def test_krylov_solver_lu(): mesh = UnitSquareMesh(MPI.comm_world, 12, 12) V = FunctionSpace(mesh, ("Lagrange", 1)) u, v = TrialFunction(V), TestFunction(V) a = Constant(1.0) * inner(u, v) * dx L = inner(Constant(1.0), v) * dx A = assemble(a) b = assemble(L) norm = 13.0 solver = PETScKrylovSolver(mesh.mpi_comm()) solver.set_options_prefix("test_lu_") PETScOptions.set("test_lu_ksp_type", "preonly") PETScOptions.set("test_lu_pc_type", "lu") solver.set_from_options() x = PETScVector() solver.set_operator(A) solver.solve(x, b) # *Tight* tolerance for LU solves assert round(x.norm(cpp.la.Norm.l2) - norm, 12) == 0
def xtest_mg_solver_stokes(): mesh0 = UnitCubeMesh(2, 2, 2) mesh1 = UnitCubeMesh(4, 4, 4) mesh2 = UnitCubeMesh(8, 8, 8) Ve = VectorElement("CG", mesh0.ufl_cell(), 2) Qe = FiniteElement("CG", mesh0.ufl_cell(), 1) Ze = MixedElement([Ve, Qe]) Z0 = FunctionSpace(mesh0, Ze) Z1 = FunctionSpace(mesh1, Ze) Z2 = FunctionSpace(mesh2, Ze) W = Z2 # Boundaries def right(x, on_boundary): return x[0] > (1.0 - DOLFIN_EPS) def left(x, on_boundary): return x[0] < DOLFIN_EPS def top_bottom(x, on_boundary): return x[1] > 1.0 - DOLFIN_EPS or x[1] < DOLFIN_EPS # No-slip boundary condition for velocity noslip = Constant((0.0, 0.0, 0.0)) bc0 = DirichletBC(W.sub(0), noslip, top_bottom) # Inflow boundary condition for velocity inflow = Expression(("-sin(x[1]*pi)", "0.0", "0.0"), degree=2) bc1 = DirichletBC(W.sub(0), inflow, right) # Collect boundary conditions bcs = [bc0, bc1] # Define variational problem (u, p) = TrialFunctions(W) (v, q) = TestFunctions(W) f = Constant((0.0, 0.0, 0.0)) a = inner(grad(u), grad(v)) * dx + div(v) * p * dx + q * div(u) * dx L = inner(f, v) * dx # Form for use in constructing preconditioner matrix b = inner(grad(u), grad(v)) * dx + p * q * dx # Assemble system A, bb = assemble_system(a, L, bcs) # Assemble preconditioner system P, btmp = assemble_system(b, L, bcs) spaces = [Z0, Z1, Z2] dm_collection = PETScDMCollection(spaces) solver = PETScKrylovSolver() solver.set_operators(A, P) PETScOptions.set("ksp_type", "gcr") PETScOptions.set("pc_type", "mg") PETScOptions.set("pc_mg_levels", 3) PETScOptions.set("pc_mg_galerkin") PETScOptions.set("ksp_monitor_true_residual") PETScOptions.set("ksp_atol", 1.0e-10) PETScOptions.set("ksp_rtol", 1.0e-10) solver.set_from_options() from petsc4py import PETSc ksp = solver.ksp() ksp.setDM(dm_collection.dm()) ksp.setDMActive(False) x = PETScVector() solver.solve(x, bb) # Check multigrid solution against LU solver solver = LUSolver(A) # noqa x_lu = PETScVector() solver.solve(x_lu, bb) assert round((x - x_lu).norm("l2"), 10) == 0 # Clear all PETSc options opts = PETSc.Options() for key in opts.getAll(): opts.delValue(key)
def test_mg_solver_laplace(): # Create meshes and function spaces meshes = [UnitSquareMesh(N, N) for N in [16, 32, 64]] V = [FunctionSpace(mesh, "Lagrange", 1) for mesh in meshes] # Create variational problem on fine grid u, v = TrialFunction(V[-1]), TestFunction(V[-1]) a = dot(grad(u), grad(v)) * dx L = v * dx bc = DirichletBC(V[-1], Constant(0.0), "on_boundary") A, b = assemble_system(a, L, bc) # Create collection of PETSc DM objects dm_collection = PETScDMCollection(V) # Create PETSc Krylov solver and set operator solver = PETScKrylovSolver() solver.set_operator(A) # Set PETSc solver type PETScOptions.set("ksp_type", "richardson") PETScOptions.set("pc_type", "mg") # Set PETSc MG type and levels PETScOptions.set("pc_mg_levels", len(V)) PETScOptions.set("pc_mg_galerkin") # Set smoother PETScOptions.set("mg_levels_ksp_type", "chebyshev") PETScOptions.set("mg_levels_pc_type", "jacobi") # Set tolerance and monitor residual PETScOptions.set("ksp_monitor_true_residual") PETScOptions.set("ksp_atol", 1.0e-12) PETScOptions.set("ksp_rtol", 1.0e-12) solver.set_from_options() # Get fine grid DM and attach fine grid DM to solver solver.set_dm(dm_collection.get_dm(-1)) solver.set_dm_active(False) # Solve x = PETScVector() solver.solve(x, b) # Check multigrid solution against LU solver solution solver = LUSolver(A) # noqa x_lu = PETScVector() solver.solve(x_lu, b) assert round((x - x_lu).norm("l2"), 10) == 0 # Clear all PETSc options from petsc4py import PETSc opts = PETSc.Options() for key in opts.getAll(): opts.delValue(key)
# symmetry) A, b = assemble_system(a, L, bc) # Create solution function u = Function(V) # Create near null space basis (required for smoothed aggregation # AMG). The solution vector is passed so that it can be copied to # generate compatible vectors for the nullspace. null_space = build_nullspace(V, u.vector()) # Attach near nullspace to matrix A.set_near_nullspace(null_space) # Set solver options PETScOptions.set("ksp_view") PETScOptions.set("ksp_type", "cg") PETScOptions.set("ksp_rtol", 1.0e-12) PETScOptions.set("pc_type", "gamg") # Use Chebyshev smoothing for multigrid PETScOptions.set("mg_levels_ksp_type", "chebyshev") PETScOptions.set("mg_levels_pc_type", "jacobi") # Improve estimate of eigenvalues for Chebyshev smoothing PETScOptions.set("mg_levels_esteig_ksp_type", "cg") PETScOptions.set("mg_levels_ksp_chebyshev_esteig_steps", 20) # Monitor solver PETScOptions.set("ksp_monitor")
def test_krylov_samg_solver_elasticity(): "Test PETScKrylovSolver with smoothed aggregation AMG" def build_nullspace(V, x): """Function to build null space for 2D elasticity""" # Create list of vectors for null space nullspace_basis = [x.copy() for i in range(3)] with ExitStack() as stack: vec_local = [stack.enter_context(x.localForm()) for x in nullspace_basis] basis = [np.asarray(x) for x in vec_local] # Build translational null space basis V.sub(0).dofmap.set(basis[0], 1.0) V.sub(1).dofmap.set(basis[1], 1.0) # Build rotational null space basis V.sub(0).set_x(basis[2], -1.0, 1) V.sub(1).set_x(basis[2], 1.0, 0) null_space = VectorSpaceBasis(nullspace_basis) null_space.orthonormalize() return null_space def amg_solve(N, method): # Elasticity parameters E = 1.0e9 nu = 0.3 mu = E / (2.0 * (1.0 + nu)) lmbda = 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(2) # Define problem mesh = UnitSquareMesh(MPI.comm_world, N, N) V = VectorFunctionSpace(mesh, 'Lagrange', 1) bc0 = Function(V) with bc0.vector.localForm() as bc_local: bc_local.set(0.0) def boundary(x, only_boundary): return [only_boundary] * x.shape(0) bc = DirichletBC(V.sub(0), bc0, boundary) u = TrialFunction(V) v = TestFunction(V) # Forms a, L = inner(sigma(u), grad(v)) * dx, dot(ufl.as_vector((1.0, 1.0)), v) * dx # Assemble linear algebra objects A = assemble_matrix(a, [bc]) A.assemble() b = assemble_vector(L) apply_lifting(b, [a], [[bc]]) b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) set_bc(b, [bc]) # Create solution function u = Function(V) # Create near null space basis and orthonormalize null_space = build_nullspace(V, u.vector) # Attached near-null space to matrix A.set_near_nullspace(null_space) # Test that basis is orthonormal assert null_space.is_orthonormal() # Create PETSC smoothed aggregation AMG preconditioner, and # create CG solver solver = PETScKrylovSolver("cg", method) # Set matrix operator solver.set_operator(A) # Compute solution and return number of iterations return solver.solve(u.vector, b) # Set some multigrid smoother parameters PETScOptions.set("mg_levels_ksp_type", "chebyshev") PETScOptions.set("mg_levels_pc_type", "jacobi") # Improve estimate of eigenvalues for Chebyshev smoothing PETScOptions.set("mg_levels_esteig_ksp_type", "cg") PETScOptions.set("mg_levels_ksp_chebyshev_esteig_steps", 50) # Build list of smoothed aggregation preconditioners methods = ["petsc_amg"] # if "ml_amg" in PETScPreconditioner.preconditioners(): # methods.append("ml_amg") # Test iteration count with increasing mesh size for each # preconditioner for method in methods: for N in [8, 16, 32, 64]: print("Testing method '{}' with {} x {} mesh".format(method, N, N)) niter = amg_solve(N, method) assert niter < 18
def test_krylov_samg_solver_elasticity(): "Test PETScKrylovSolver with smoothed aggregation AMG" def build_nullspace(V, x): """Function to build null space for 2D elasticity""" # Create list of vectors for null space nullspace_basis = [x.copy() for i in range(3)] # Build translational null space basis V.sub(0).dofmap().set(nullspace_basis[0], 1.0) V.sub(1).dofmap().set(nullspace_basis[1], 1.0) # Build rotational null space basis V.sub(0).set_x(nullspace_basis[2], -1.0, 1) V.sub(1).set_x(nullspace_basis[2], 1.0, 0) for x in nullspace_basis: x.apply("insert") null_space = VectorSpaceBasis(nullspace_basis) null_space.orthonormalize() return null_space def amg_solve(N, method): # Elasticity parameters E = 1.0e9 nu = 0.3 mu = E / (2.0 * (1.0 + nu)) lmbda = 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(2) # Define problem mesh = UnitSquareMesh(MPI.comm_world, N, N) V = VectorFunctionSpace(mesh, 'Lagrange', 1) bc = DirichletBC(V, Constant((0.0, 0.0)), lambda x, on_boundary: on_boundary) u = TrialFunction(V) v = TestFunction(V) # Forms a, L = inner(sigma(u), grad(v)) * dx, dot(Constant((1.0, 1.0)), v) * dx # Assemble linear algebra objects A, b = assemble_system(a, L, bc) # Create solution function u = Function(V) # Create near null space basis and orthonormalize null_space = build_nullspace(V, u.vector()) # Attached near-null space to matrix A.set_near_nullspace(null_space) # Test that basis is orthonormal assert null_space.is_orthonormal() # Create PETSC smoothed aggregation AMG preconditioner, and # create CG solver solver = PETScKrylovSolver("cg", method) # Set matrix operator solver.set_operator(A) # Compute solution and return number of iterations return solver.solve(u.vector(), b) # Set some multigrid smoother parameters PETScOptions.set("mg_levels_ksp_type", "chebyshev") PETScOptions.set("mg_levels_pc_type", "jacobi") # Improve estimate of eigenvalues for Chebyshev smoothing PETScOptions.set("mg_levels_esteig_ksp_type", "cg") PETScOptions.set("mg_levels_ksp_chebyshev_esteig_steps", 50) # Build list of smoothed aggregation preconditioners methods = ["petsc_amg"] # if "ml_amg" in PETScPreconditioner.preconditioners(): # methods.append("ml_amg") # Test iteration count with increasing mesh size for each # preconditioner for method in methods: for N in [8, 16, 32, 64]: print("Testing method '{}' with {} x {} mesh".format(method, N, N)) niter = amg_solve(N, method) assert niter < 18