def test_linear_pde(): """Test Newton solver for a linear PDE""" # Create mesh and function space mesh = dolfin.generation.UnitSquareMesh(dolfin.MPI.comm_world, 12, 12) V = functionspace.FunctionSpace(mesh, ("Lagrange", 1)) u = function.Function(V) v = function.TestFunction(V) F = inner(10.0, v) * dx - inner(grad(u), grad(v)) * dx def boundary(x): """Define Dirichlet boundary (x = 0 or x = 1).""" return np.logical_or(x[:, 0] < 1.0e-8, x[:, 0] > 1.0 - 1.0e-8) u_bc = function.Function(V) u_bc.vector.set(1.0) u_bc.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) bc = fem.DirichletBC(V, u_bc, boundary) # Create nonlinear problem problem = NonlinearPDEProblem(F, u, bc) # Create Newton solver and solve solver = dolfin.cpp.nls.NewtonSolver(dolfin.MPI.comm_world) n, converged = solver.solve(problem, u.vector) assert converged assert n == 1 # Increment boundary condition and solve again u_bc.vector.set(2.0) u_bc.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) n, converged = solver.solve(problem, u.vector) assert converged assert n == 1
def test_basic_assembly_constant(): """Tests assembly with Constant The following test should be sensitive to order of flattening the matrix-valued constant. """ mesh = dolfin.generation.UnitSquareMesh(dolfin.MPI.comm_world, 5, 5) V = functionspace.FunctionSpace(mesh, ("Lagrange", 1)) u, v = dolfin.TrialFunction(V), dolfin.TestFunction(V) c = constant.Constant(mesh, [[1.0, 2.0], [5.0, 3.0]]) 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 # Initial assembly A1 = dolfin.fem.assemble_matrix(a) A1.assemble() b1 = dolfin.fem.assemble_vector(L) b1.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) c.value = [[1.0, 2.0], [3.0, 4.0]] A2 = dolfin.fem.assemble_matrix(a) A2.assemble() b2 = dolfin.fem.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_basic_interior_facet_assembly(): ghost_mode = dolfin.cpp.mesh.GhostMode.none if (dolfin.MPI.size(dolfin.MPI.comm_world) > 1): ghost_mode = dolfin.cpp.mesh.GhostMode.shared_facet mesh = dolfin.RectangleMesh( dolfin.MPI.comm_world, [numpy.array([0.0, 0.0, 0.0]), numpy.array([1.0, 1.0, 0.0])], [5, 5], cell_type=dolfin.cpp.mesh.CellType.triangle, ghost_mode=ghost_mode) V = functionspace.FunctionSpace(mesh, ("DG", 1)) u, v = dolfin.TrialFunction(V), dolfin.TestFunction(V) a = ufl.inner(ufl.avg(u), ufl.avg(v)) * ufl.dS A = dolfin.fem.assemble_matrix(a) A.assemble() assert isinstance(A, PETSc.Mat) L = ufl.conj(ufl.avg(v)) * ufl.dS b = dolfin.fem.assemble_vector(L) b.assemble() assert isinstance(b, PETSc.Vec)
def increase_order( V: functionspace.FunctionSpace) -> functionspace.FunctionSpace: """For a given function space, return the same space, but with polynomial degree increase by 1. """ e = ufl.algorithms.elementtransformations.increase_order(V.ufl_element()) return functionspace.FunctionSpace(V.mesh, e)
def change_regularity(V: functionspace.FunctionSpace, family: str) -> functionspace.FunctionSpace: """For a given function space, return the corresponding space with the finite elements specified by 'family'. Possible families are the families supported by the form compiler """ e = ufl.algorithms.elementtransformations.change_regularity( V.ufl_element(), family) return functionspace.FunctionSpace(V.mesh, e)
def test_nonlinear_pde_snes(): """Test Newton solver for a simple nonlinear PDE""" # Create mesh and function space mesh = dolfin.generation.UnitSquareMesh(dolfin.MPI.comm_world, 12, 15) V = functionspace.FunctionSpace(mesh, ("Lagrange", 1)) u = function.Function(V) v = function.TestFunction(V) F = inner(5.0, v) * dx - ufl.sqrt(u * u) * inner( grad(u), grad(v)) * dx - inner(u, v) * dx def boundary(x): """Define Dirichlet boundary (x = 0 or x = 1).""" return np.logical_or(x[:, 0] < 1.0e-8, x[:, 0] > 1.0 - 1.0e-8) u_bc = function.Function(V) u_bc.vector.set(1.0) u_bc.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) bc = fem.DirichletBC(V, u_bc, boundary) # Create nonlinear problem problem = NonlinearPDE_SNESProblem(F, u, bc) u.vector.set(0.9) u.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) b = dolfin.cpp.la.create_vector(V.dofmap.index_map) J = dolfin.cpp.fem.create_matrix(problem.a_comp._cpp_object) # Create Newton solver and solve snes = PETSc.SNES().create() snes.setFunction(problem.F, b) snes.setJacobian(problem.J, J) snes.setTolerances(rtol=1.0e-9, max_it=10) snes.setFromOptions() snes.getKSP().setTolerances(rtol=1.0e-9) snes.solve(None, u.vector) assert snes.getConvergedReason() > 0 assert snes.getIterationNumber() < 6 # Modify boundary condition and solve again u_bc.vector.set(0.5) u_bc.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) snes.solve(None, u.vector) assert snes.getConvergedReason() > 0 assert snes.getIterationNumber() < 6
def test_newton_solver_iheritance_override_methods(): import functools called_methods = {} def check_is_called(method): @functools.wraps(method) def wrapper(*args, **kwargs): called_methods[method.__name__] = True return method(*args, **kwargs) return wrapper class CustomNewtonSolver(dolfin.cpp.nls.NewtonSolver): def __init__(self, comm): super().__init__(comm) @check_is_called def update_solution(self, x, dx, relaxation, problem, it): return super().update_solution(x, dx, relaxation, problem, it) @check_is_called def converged(self, r, problem, it): return super().converged(r, problem, it) mesh = dolfin.generation.UnitSquareMesh(dolfin.MPI.comm_world, 12, 12) V = functionspace.FunctionSpace(mesh, ("Lagrange", 1)) u = function.Function(V) v = function.TestFunction(V) F = inner(10.0, v) * dx - inner(grad(u), grad(v)) * dx def boundary(x): """Define Dirichlet boundary (x = 0 or x = 1).""" return np.logical_or(x[:, 0] < 1.0e-8, x[:, 0] > 1.0 - 1.0e-8) u_bc = function.Function(V) bc = fem.DirichletBC(V, u_bc, boundary) # Create nonlinear problem problem = NonlinearPDEProblem(F, u, bc) # Create Newton solver and solve solver = CustomNewtonSolver(dolfin.MPI.comm_world) n, converged = solver.solve(problem, u.vector) assert called_methods[CustomNewtonSolver.converged.__name__] assert called_methods[CustomNewtonSolver.update_solution.__name__]
def collapse(self): u_collapsed = self._cpp_object.collapse() V_collapsed = functionspace.FunctionSpace(None, self.ufl_element(), u_collapsed.function_space) return Function(V_collapsed, u_collapsed.vector)
def test_assembly_solve_taylor_hood(mesh): """Assemble Stokes problem with Taylor-Hood elements and solve.""" P2 = functionspace.VectorFunctionSpace(mesh, ("Lagrange", 2)) P1 = functionspace.FunctionSpace(mesh, ("Lagrange", 1)) def boundary0(x): """Define boundary x = 0""" return x[:, 0] < 10 * numpy.finfo(float).eps def boundary1(x): """Define boundary x = 1""" return x[:, 0] > (1.0 - 10 * numpy.finfo(float).eps) u0 = dolfin.Function(P2) u0.vector.set(1.0) u0.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) bc0 = dolfin.DirichletBC(P2, u0, boundary0) bc1 = dolfin.DirichletBC(P2, u0, boundary1) u, p = dolfin.TrialFunction(P2), dolfin.TrialFunction(P1) v, q = dolfin.TestFunction(P2), dolfin.TestFunction(P1) a00 = inner(ufl.grad(u), ufl.grad(v)) * dx a01 = ufl.inner(p, ufl.div(v)) * dx a10 = ufl.inner(ufl.div(u), q) * dx a11 = None p00 = a00 p01, p10 = None, None p11 = inner(p, q) * dx # FIXME # We need zero function for the 'zero' part of L p_zero = dolfin.Function(P1) f = dolfin.Function(P2) L0 = ufl.inner(f, v) * dx L1 = ufl.inner(p_zero, q) * dx # -- Blocked and nested A0 = dolfin.fem.assemble_matrix_nest([[a00, a01], [a10, a11]], [bc0, bc1]) A0norm = nest_matrix_norm(A0) P0 = dolfin.fem.assemble_matrix_nest([[p00, p01], [p10, p11]], [bc0, bc1]) P0norm = nest_matrix_norm(P0) b0 = dolfin.fem.assemble_vector_nest([L0, L1], [[a00, a01], [a10, a11]], [bc0, bc1]) b0norm = b0.norm() ksp = PETSc.KSP() ksp.create(mesh.mpi_comm()) ksp.setOperators(A0, P0) nested_IS = P0.getNestISs() ksp.setType("minres") pc = ksp.getPC() pc.setType("fieldsplit") pc.setFieldSplitIS(["u", nested_IS[0][0]], ["p", nested_IS[1][1]]) ksp_u, ksp_p = pc.getFieldSplitSubKSP() ksp_u.setType("preonly") ksp_u.getPC().setType('lu') ksp_u.getPC().setFactorSolverType('mumps') ksp_p.setType("preonly") def monitor(ksp, its, rnorm): # print("Num it, rnorm:", its, rnorm) pass ksp.setTolerances(rtol=1.0e-8, max_it=50) ksp.setMonitor(monitor) ksp.setFromOptions() x0 = b0.copy() ksp.solve(b0, x0) assert ksp.getConvergedReason() > 0 # -- Blocked and monolithic A1 = dolfin.fem.assemble_matrix_block([[a00, a01], [a10, a11]], [bc0, bc1]) assert A1.norm() == pytest.approx(A0norm, 1.0e-12) P1 = dolfin.fem.assemble_matrix_block([[p00, p01], [p10, p11]], [bc0, bc1]) assert P1.norm() == pytest.approx(P0norm, 1.0e-12) b1 = dolfin.fem.assemble_vector_block([L0, L1], [[a00, a01], [a10, a11]], [bc0, bc1]) assert b1.norm() == pytest.approx(b0norm, 1.0e-12) ksp = PETSc.KSP() ksp.create(mesh.mpi_comm()) ksp.setOperators(A1, P1) ksp.setType("minres") pc = ksp.getPC() pc.setType('lu') pc.setFactorSolverType('mumps') ksp.setTolerances(rtol=1.0e-8, max_it=50) ksp.setFromOptions() x1 = A1.createVecRight() ksp.solve(b1, x1) assert ksp.getConvergedReason() > 0 assert x1.norm() == pytest.approx(x0.norm(), 1e-8) # -- Monolithic P2 = ufl.VectorElement("Lagrange", mesh.ufl_cell(), 2) P1 = ufl.FiniteElement("Lagrange", mesh.ufl_cell(), 1) TH = P2 * P1 W = dolfin.FunctionSpace(mesh, TH) (u, p) = dolfin.TrialFunctions(W) (v, q) = dolfin.TestFunctions(W) a00 = ufl.inner(ufl.grad(u), ufl.grad(v)) * dx a01 = ufl.inner(p, ufl.div(v)) * dx a10 = ufl.inner(ufl.div(u), q) * dx a = a00 + a01 + a10 p00 = ufl.inner(ufl.grad(u), ufl.grad(v)) * dx p11 = ufl.inner(p, q) * dx p_form = p00 + p11 f = dolfin.Function(W.sub(0).collapse()) p_zero = dolfin.Function(W.sub(1).collapse()) L0 = inner(f, v) * dx L1 = inner(p_zero, q) * dx L = L0 + L1 bc0 = dolfin.DirichletBC(W.sub(0), u0, boundary0) bc1 = dolfin.DirichletBC(W.sub(0), u0, boundary1) A2 = dolfin.fem.assemble_matrix(a, [bc0, bc1]) A2.assemble() assert A2.norm() == pytest.approx(A0norm, 1.0e-12) P2 = dolfin.fem.assemble_matrix(p_form, [bc0, bc1]) P2.assemble() assert P2.norm() == pytest.approx(P0norm, 1.0e-12) b2 = dolfin.fem.assemble_vector(L) dolfin.fem.apply_lifting(b2, [a], [[bc0, bc1]]) b2.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) dolfin.fem.set_bc(b2, [bc0, bc1]) b2norm = b2.norm() assert b2norm == pytest.approx(b0norm, 1.0e-12) ksp = PETSc.KSP() ksp.create(mesh.mpi_comm()) ksp.setOperators(A2, P2) ksp.setType("minres") pc = ksp.getPC() pc.setType('lu') pc.setFactorSolverType('mumps') def monitor(ksp, its, rnorm): # print("Num it, rnorm:", its, rnorm) pass ksp.setTolerances(rtol=1.0e-8, max_it=50) ksp.setMonitor(monitor) ksp.setFromOptions() x2 = A2.createVecRight() ksp.solve(b2, x2) assert ksp.getConvergedReason() > 0 assert x0.norm() == pytest.approx(x2.norm(), 1e-8)