def test_assembly_ds_domains(mesh): V = dolfinx.FunctionSpace(mesh, ("CG", 1)) u, v = ufl.TrialFunction(V), ufl.TestFunction(V) marker = dolfinx.MeshFunction("size_t", mesh, mesh.topology.dim - 1, 0) def bottom(x): return numpy.isclose(x[1], 0.0) def top(x): return numpy.isclose(x[1], 1.0) def left(x): return numpy.isclose(x[0], 0.0) def right(x): return numpy.isclose(x[0], 1.0) marker.mark(bottom, 111) marker.mark(top, 222) marker.mark(left, 333) marker.mark(right, 444) ds = ufl.Measure('ds', subdomain_data=marker, domain=mesh) w = dolfinx.Function(V) with w.vector.localForm() as w_local: w_local.set(0.5) # Assemble matrix a = w * ufl.inner(u, v) * (ds(111) + ds(222) + ds(333) + ds(444)) A = dolfinx.fem.assemble_matrix(a) A.assemble() norm1 = A.norm() a2 = w * ufl.inner(u, v) * ds A2 = dolfinx.fem.assemble_matrix(a2) A2.assemble() norm2 = A2.norm() assert norm1 == pytest.approx(norm2, 1.0e-12) # Assemble vector L = ufl.inner(w, v) * (ds(111) + ds(222) + ds(333) + ds(444)) b = dolfinx.fem.assemble_vector(L) b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) L2 = ufl.inner(w, v) * ds b2 = dolfinx.fem.assemble_vector(L2) b2.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) assert b.norm() == pytest.approx(b2.norm(), 1.0e-12) # Assemble scalar L = w * (ds(111) + ds(222) + ds(333) + ds(444)) s = dolfinx.fem.assemble_scalar(L) s = dolfinx.MPI.sum(mesh.mpi_comm(), s) L2 = w * ds s2 = dolfinx.fem.assemble_scalar(L2) s2 = dolfinx.MPI.sum(mesh.mpi_comm(), s2) assert (s == pytest.approx(s2, 1.0e-12) and 2.0 == pytest.approx(s, 1.0e-12))
def test_assembly_solve_taylor_hood(mesh): """Assemble Stokes problem with Taylor-Hood elements and solve.""" gdim = mesh.geometry.dim P2 = dolfinx.function.VectorFunctionSpace(mesh, ("Lagrange", 2)) P1 = dolfinx.function.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) def initial_guess_u(x): u_init = numpy.row_stack((numpy.sin(x[0]) * numpy.sin(x[1]), numpy.cos(x[0]) * numpy.cos(x[1]))) if gdim == 3: u_init = numpy.row_stack((u_init, numpy.cos(x[2]))) return u_init def initial_guess_p(x): return -x[0]**2 - x[1]**3 u_bc_0 = dolfinx.Function(P2) u_bc_0.interpolate( lambda x: numpy.row_stack(tuple(x[j] + float(j) for j in range(gdim)))) u_bc_1 = dolfinx.Function(P2) u_bc_1.interpolate( lambda x: numpy.row_stack(tuple(numpy.sin(x[j]) for j in range(gdim)))) facetdim = mesh.topology.dim - 1 mf = dolfinx.MeshFunction("size_t", mesh, facetdim, 0) mf.mark(boundary0, 1) mf.mark(boundary1, 2) bndry_facets0 = numpy.where(mf.values == 1)[0] bndry_facets1 = numpy.where(mf.values == 2)[0] bdofs0 = dolfinx.fem.locate_dofs_topological(P2, facetdim, bndry_facets0) bdofs1 = dolfinx.fem.locate_dofs_topological(P2, facetdim, bndry_facets1) bcs = [ dolfinx.DirichletBC(u_bc_0, bdofs0), dolfinx.DirichletBC(u_bc_1, bdofs1) ] u, p = dolfinx.Function(P2), dolfinx.Function(P1) du, dp = ufl.TrialFunction(P2), ufl.TrialFunction(P1) v, q = ufl.TestFunction(P2), ufl.TestFunction(P1) F = [ inner(ufl.grad(u), ufl.grad(v)) * dx + inner(p, ufl.div(v)) * dx, inner(ufl.div(u), q) * dx ] J = [[derivative(F[0], u, du), derivative(F[0], p, dp)], [derivative(F[1], u, du), derivative(F[1], p, dp)]] P = [[J[0][0], None], [None, inner(dp, q) * dx]] # -- Blocked and monolithic Jmat0 = dolfinx.fem.create_matrix_block(J) Pmat0 = dolfinx.fem.create_matrix_block(P) Fvec0 = dolfinx.fem.create_vector_block(F) snes = PETSc.SNES().create(dolfinx.MPI.comm_world) snes.setTolerances(rtol=1.0e-15, max_it=10) snes.getKSP().setType("minres") snes.getKSP().getPC().setType("lu") snes.getKSP().getPC().setFactorSolverType("mumps") problem = NonlinearPDE_SNESProblem(F, J, [u, p], bcs, P=P) snes.setFunction(problem.F_block, Fvec0) snes.setJacobian(problem.J_block, J=Jmat0, P=Pmat0) u.interpolate(initial_guess_u) p.interpolate(initial_guess_p) x0 = dolfinx.fem.create_vector_block(F) with u.vector.localForm() as _u, p.vector.localForm() as _p: dolfinx.cpp.la.scatter_local_vectors(x0, [_u.array_r, _p.array_r], [ u.function_space.dofmap.index_map, p.function_space.dofmap.index_map ]) x0.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) snes.solve(None, x0) assert snes.getConvergedReason() > 0 # -- Blocked and nested Jmat1 = dolfinx.fem.create_matrix_nest(J) Pmat1 = dolfinx.fem.create_matrix_nest(P) Fvec1 = dolfinx.fem.create_vector_nest(F) snes = PETSc.SNES().create(dolfinx.MPI.comm_world) snes.setTolerances(rtol=1.0e-15, max_it=10) nested_IS = Jmat1.getNestISs() snes.getKSP().setType("minres") snes.getKSP().setTolerances(rtol=1e-12) snes.getKSP().getPC().setType("fieldsplit") snes.getKSP().getPC().setFieldSplitIS(["u", nested_IS[0][0]], ["p", nested_IS[1][1]]) ksp_u, ksp_p = snes.getKSP().getPC().getFieldSplitSubKSP() ksp_u.setType("preonly") ksp_u.getPC().setType('lu') ksp_u.getPC().setFactorSolverType('mumps') ksp_p.setType("preonly") ksp_p.getPC().setType('lu') ksp_p.getPC().setFactorSolverType('mumps') problem = NonlinearPDE_SNESProblem(F, J, [u, p], bcs, P=P) snes.setFunction(problem.F_nest, Fvec1) snes.setJacobian(problem.J_nest, J=Jmat1, P=Pmat1) u.interpolate(initial_guess_u) p.interpolate(initial_guess_p) x1 = dolfinx.fem.create_vector_nest(F) for x1_soln_pair in zip(x1.getNestSubVecs(), (u, p)): x1_sub, soln_sub = x1_soln_pair soln_sub.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) soln_sub.vector.copy(result=x1_sub) x1_sub.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) x1.set(0.0) snes.solve(None, x1) assert snes.getConvergedReason() > 0 assert nest_matrix_norm(Jmat1) == pytest.approx(Jmat0.norm(), 1.0e-12) assert Fvec1.norm() == pytest.approx(Fvec0.norm(), 1.0e-12) assert x1.norm() == pytest.approx(x0.norm(), 1.0e-12) # -- Monolithic P2_el = ufl.VectorElement("Lagrange", mesh.ufl_cell(), 2) P1_el = ufl.FiniteElement("Lagrange", mesh.ufl_cell(), 1) TH = P2_el * P1_el W = dolfinx.FunctionSpace(mesh, TH) U = dolfinx.Function(W) dU = ufl.TrialFunction(W) u, p = ufl.split(U) du, dp = ufl.split(dU) v, q = ufl.TestFunctions(W) F = inner(ufl.grad(u), ufl.grad(v)) * dx + inner(p, ufl.div(v)) * dx \ + inner(ufl.div(u), q) * dx J = derivative(F, U, dU) P = inner(ufl.grad(du), ufl.grad(v)) * dx + inner(dp, q) * dx bdofsW0_P2_0 = dolfinx.fem.locate_dofs_topological((W.sub(0), P2), facetdim, bndry_facets0) bdofsW0_P2_1 = dolfinx.fem.locate_dofs_topological((W.sub(0), P2), facetdim, bndry_facets1) bcs = [ dolfinx.DirichletBC(u_bc_0, bdofsW0_P2_0, W.sub(0)), dolfinx.DirichletBC(u_bc_1, bdofsW0_P2_1, W.sub(0)) ] Jmat2 = dolfinx.fem.create_matrix(J) Pmat2 = dolfinx.fem.create_matrix(P) Fvec2 = dolfinx.fem.create_vector(F) snes = PETSc.SNES().create(dolfinx.MPI.comm_world) snes.setTolerances(rtol=1.0e-15, max_it=10) snes.getKSP().setType("minres") snes.getKSP().getPC().setType("lu") snes.getKSP().getPC().setFactorSolverType("mumps") problem = NonlinearPDE_SNESProblem(F, J, U, bcs, P=P) snes.setFunction(problem.F_mono, Fvec2) snes.setJacobian(problem.J_mono, J=Jmat2, P=Pmat2) U.interpolate(lambda x: numpy.row_stack( (initial_guess_u(x), initial_guess_p(x)))) x2 = dolfinx.fem.create_vector(F) x2.array = U.vector.array_r snes.solve(None, x2) assert snes.getConvergedReason() > 0 assert Jmat2.norm() == pytest.approx(Jmat0.norm(), 1.0e-12) assert Fvec2.norm() == pytest.approx(Fvec0.norm(), 1.0e-12) assert x2.norm() == pytest.approx(x0.norm(), 1.0e-12)
def test_matrix_assembly_block(): """Test assembly of block matrices and vectors into (a) monolithic blocked structures, PETSc Nest structures, and monolithic structures in the nonlinear setting """ mesh = dolfinx.generation.UnitSquareMesh(dolfinx.MPI.comm_world, 4, 8) p0, p1 = 1, 2 P0 = ufl.FiniteElement("Lagrange", mesh.ufl_cell(), p0) P1 = ufl.FiniteElement("Lagrange", mesh.ufl_cell(), p1) V0 = dolfinx.function.FunctionSpace(mesh, P0) V1 = dolfinx.function.FunctionSpace(mesh, P1) def boundary(x): return numpy.logical_or(x[0] < 1.0e-6, x[0] > 1.0 - 1.0e-6) def initial_guess_u(x): return numpy.sin(x[0]) * numpy.sin(x[1]) def initial_guess_p(x): return -x[0]**2 - x[1]**3 def bc_value(x): return numpy.cos(x[0]) * numpy.cos(x[1]) facetdim = mesh.topology.dim - 1 mf = dolfinx.MeshFunction("size_t", mesh, facetdim, 0) mf.mark(boundary, 1) bndry_facets = numpy.where(mf.values == 1)[0] u_bc = dolfinx.function.Function(V1) u_bc.interpolate(bc_value) bdofs = dolfinx.fem.locate_dofs_topological(V1, facetdim, bndry_facets) bc = dolfinx.fem.dirichletbc.DirichletBC(u_bc, bdofs) # Define variational problem du, dp = ufl.TrialFunction(V0), ufl.TrialFunction(V1) u, p = dolfinx.function.Function(V0), dolfinx.function.Function(V1) v, q = ufl.TestFunction(V0), ufl.TestFunction(V1) u.interpolate(initial_guess_u) p.interpolate(initial_guess_p) f = 1.0 g = -3.0 F0 = inner(u, v) * dx + inner(p, v) * dx - inner(f, v) * dx F1 = inner(u, q) * dx + inner(p, q) * dx - inner(g, q) * dx a_block = [[derivative(F0, u, du), derivative(F0, p, dp)], [derivative(F1, u, du), derivative(F1, p, dp)]] L_block = [F0, F1] # Monolithic blocked x0 = dolfinx.fem.create_vector_block(L_block) dolfinx.cpp.la.scatter_local_vectors( x0, [u.vector.array_r, p.vector.array_r], [u.function_space.dofmap.index_map, p.function_space.dofmap.index_map]) x0.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) # Ghosts are updated inside assemble_vector_block A0 = dolfinx.fem.assemble_matrix_block(a_block, [bc]) b0 = dolfinx.fem.assemble_vector_block(L_block, a_block, [bc], x0=x0, scale=-1.0) A0.assemble() assert A0.getType() != "nest" Anorm0 = A0.norm() bnorm0 = b0.norm() # Nested (MatNest) x1 = dolfinx.fem.create_vector_nest(L_block) for x1_soln_pair in zip(x1.getNestSubVecs(), (u, p)): x1_sub, soln_sub = x1_soln_pair soln_sub.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) soln_sub.vector.copy(result=x1_sub) x1_sub.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) A1 = dolfinx.fem.assemble_matrix_nest(a_block, [bc]) b1 = dolfinx.fem.assemble_vector_nest(L_block) dolfinx.fem.apply_lifting_nest(b1, a_block, [bc], x1, scale=-1.0) for b_sub in b1.getNestSubVecs(): b_sub.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) bcs0 = dolfinx.cpp.fem.bcs_rows( dolfinx.fem.assemble._create_cpp_form(L_block), [bc]) dolfinx.fem.set_bc_nest(b1, bcs0, x1, scale=-1.0) A1.assemble() assert A1.getType() == "nest" assert nest_matrix_norm(A1) == pytest.approx(Anorm0, 1.0e-12) assert b1.norm() == pytest.approx(bnorm0, 1.0e-12) # Monolithic version E = P0 * P1 W = dolfinx.function.FunctionSpace(mesh, E) dU = ufl.TrialFunction(W) U = dolfinx.function.Function(W) u0, u1 = ufl.split(U) v0, v1 = ufl.TestFunctions(W) U.interpolate(lambda x: numpy.row_stack( (initial_guess_u(x), initial_guess_p(x)))) F = inner(u0, v0) * dx + inner(u1, v0) * dx + inner(u0, v1) * dx + inner(u1, v1) * dx \ - inner(f, v0) * ufl.dx - inner(g, v1) * dx J = derivative(F, U, dU) bdofsW_V1 = dolfinx.fem.locate_dofs_topological((W.sub(1), V1), facetdim, bndry_facets) bc = dolfinx.fem.dirichletbc.DirichletBC(u_bc, bdofsW_V1, W.sub(1)) A2 = dolfinx.fem.assemble_matrix(J, [bc]) A2.assemble() b2 = dolfinx.fem.assemble_vector(F) dolfinx.fem.apply_lifting(b2, [J], bcs=[[bc]], x0=[U.vector], scale=-1.0) b2.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) dolfinx.fem.set_bc(b2, [bc], x0=U.vector, scale=-1.0) assert A2.getType() != "nest" assert A2.norm() == pytest.approx(Anorm0, 1.0e-12) assert b2.norm() == pytest.approx(bnorm0, 1.0e-12)
def test_assembly_solve_block(): """Solve a two-field nonlinear diffusion like problem with block matrix approaches and test that solution is the same. """ mesh = dolfinx.generation.UnitSquareMesh(dolfinx.MPI.comm_world, 12, 11) p = 1 P = ufl.FiniteElement("Lagrange", mesh.ufl_cell(), p) V0 = dolfinx.function.FunctionSpace(mesh, P) V1 = V0.clone() def bc_val_0(x): return x[0]**2 + x[1]**2 def bc_val_1(x): return numpy.sin(x[0]) * numpy.cos(x[1]) def initial_guess_u(x): return numpy.sin(x[0]) * numpy.sin(x[1]) def initial_guess_p(x): return -x[0]**2 - x[1]**3 def boundary(x): return numpy.logical_or(x[0] < 1.0e-6, x[0] > 1.0 - 1.0e-6) facetdim = mesh.topology.dim - 1 mf = dolfinx.MeshFunction("size_t", mesh, facetdim, 0) mf.mark(boundary, 1) bndry_facets = numpy.where(mf.values == 1)[0] u_bc0 = dolfinx.function.Function(V0) u_bc0.interpolate(bc_val_0) u_bc1 = dolfinx.function.Function(V1) u_bc1.interpolate(bc_val_1) bdofs0 = dolfinx.fem.locate_dofs_topological(V0, facetdim, bndry_facets) bdofs1 = dolfinx.fem.locate_dofs_topological(V1, facetdim, bndry_facets) bcs = [ dolfinx.fem.dirichletbc.DirichletBC(u_bc0, bdofs0), dolfinx.fem.dirichletbc.DirichletBC(u_bc1, bdofs1) ] # Block and Nest variational problem u, p = dolfinx.function.Function(V0), dolfinx.function.Function(V1) du, dp = ufl.TrialFunction(V0), ufl.TrialFunction(V1) v, q = ufl.TestFunction(V0), ufl.TestFunction(V1) f = 1.0 g = -3.0 F = [ inner((u**2 + 1) * ufl.grad(u), ufl.grad(v)) * dx - inner(f, v) * dx, inner((p**2 + 1) * ufl.grad(p), ufl.grad(q)) * dx - inner(g, q) * dx ] J = [[derivative(F[0], u, du), derivative(F[0], p, dp)], [derivative(F[1], u, du), derivative(F[1], p, dp)]] # -- Blocked version Jmat0 = dolfinx.fem.create_matrix_block(J) Fvec0 = dolfinx.fem.create_vector_block(F) snes = PETSc.SNES().create(dolfinx.MPI.comm_world) snes.setTolerances(rtol=1.0e-15, max_it=10) snes.getKSP().setType("preonly") snes.getKSP().getPC().setType("lu") snes.getKSP().getPC().setFactorSolverType("mumps") problem = NonlinearPDE_SNESProblem(F, J, [u, p], bcs) snes.setFunction(problem.F_block, Fvec0) snes.setJacobian(problem.J_block, J=Jmat0, P=None) u.interpolate(initial_guess_u) p.interpolate(initial_guess_p) x0 = dolfinx.fem.create_vector_block(F) dolfinx.cpp.la.scatter_local_vectors( x0, [u.vector.array_r, p.vector.array_r], [u.function_space.dofmap.index_map, p.function_space.dofmap.index_map]) x0.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) snes.solve(None, x0) assert snes.getKSP().getConvergedReason() > 0 assert snes.getConvergedReason() > 0 J0norm = Jmat0.norm() F0norm = Fvec0.norm() x0norm = x0.norm() # -- Nested (MatNest) Jmat1 = dolfinx.fem.create_matrix_nest(J) Fvec1 = dolfinx.fem.create_vector_nest(F) snes = PETSc.SNES().create(dolfinx.MPI.comm_world) snes.setTolerances(rtol=1.0e-15, max_it=10) nested_IS = Jmat1.getNestISs() snes.getKSP().setType("fgmres") snes.getKSP().setTolerances(rtol=1e-12) snes.getKSP().getPC().setType("fieldsplit") snes.getKSP().getPC().setFieldSplitIS(["u", nested_IS[0][0]], ["p", nested_IS[1][1]]) ksp_u, ksp_p = snes.getKSP().getPC().getFieldSplitSubKSP() ksp_u.setType("preonly") ksp_u.getPC().setType('lu') ksp_u.getPC().setFactorSolverType('mumps') ksp_p.setType("preonly") ksp_p.getPC().setType('lu') ksp_p.getPC().setFactorSolverType('mumps') problem = NonlinearPDE_SNESProblem(F, J, [u, p], bcs) snes.setFunction(problem.F_nest, Fvec1) snes.setJacobian(problem.J_nest, J=Jmat1, P=None) u.interpolate(initial_guess_u) p.interpolate(initial_guess_p) x1 = dolfinx.fem.create_vector_nest(F) for x1_soln_pair in zip(x1.getNestSubVecs(), (u, p)): x1_sub, soln_sub = x1_soln_pair soln_sub.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) soln_sub.vector.copy(result=x1_sub) x1_sub.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) snes.solve(None, x1) assert snes.getKSP().getConvergedReason() > 0 assert snes.getConvergedReason() > 0 assert x1.getType() == "nest" assert Jmat1.getType() == "nest" assert Fvec1.getType() == "nest" J1norm = nest_matrix_norm(Jmat1) F1norm = Fvec1.norm() x1norm = x1.norm() assert J1norm == pytest.approx(J0norm, 1.0e-12) assert F1norm == pytest.approx(F0norm, 1.0e-12) assert x1norm == pytest.approx(x0norm, 1.0e-12) # -- Monolithic version E = P * P W = dolfinx.function.FunctionSpace(mesh, E) U = dolfinx.function.Function(W) dU = ufl.TrialFunction(W) u0, u1 = ufl.split(U) v0, v1 = ufl.TestFunctions(W) F = inner((u0**2 + 1) * ufl.grad(u0), ufl.grad(v0)) * dx \ + inner((u1**2 + 1) * ufl.grad(u1), ufl.grad(v1)) * dx \ - inner(f, v0) * ufl.dx - inner(g, v1) * dx J = derivative(F, U, dU) u0_bc = dolfinx.function.Function(V0) u0_bc.interpolate(bc_val_0) u1_bc = dolfinx.function.Function(V1) u1_bc.interpolate(bc_val_1) bdofsW0_V0 = dolfinx.fem.locate_dofs_topological((W.sub(0), V0), facetdim, bndry_facets) bdofsW1_V1 = dolfinx.fem.locate_dofs_topological((W.sub(1), V1), facetdim, bndry_facets) bcs = [ dolfinx.fem.dirichletbc.DirichletBC(u0_bc, bdofsW0_V0, W.sub(0)), dolfinx.fem.dirichletbc.DirichletBC(u1_bc, bdofsW1_V1, W.sub(1)) ] Jmat2 = dolfinx.fem.create_matrix(J) Fvec2 = dolfinx.fem.create_vector(F) snes = PETSc.SNES().create(dolfinx.MPI.comm_world) snes.setTolerances(rtol=1.0e-15, max_it=10) snes.getKSP().setType("preonly") snes.getKSP().getPC().setType("lu") snes.getKSP().getPC().setFactorSolverType("mumps") problem = NonlinearPDE_SNESProblem(F, J, U, bcs) snes.setFunction(problem.F_mono, Fvec2) snes.setJacobian(problem.J_mono, J=Jmat2, P=None) U.interpolate(lambda x: numpy.row_stack( (initial_guess_u(x), initial_guess_p(x)))) x2 = dolfinx.fem.create_vector(F) x2.array = U.vector.array_r snes.solve(None, x2) assert snes.getKSP().getConvergedReason() > 0 assert snes.getConvergedReason() > 0 J2norm = Jmat2.norm() F2norm = Fvec2.norm() x2norm = x2.norm() assert J2norm == pytest.approx(J0norm, 1.0e-12) assert F2norm == pytest.approx(F0norm, 1.0e-12) assert x2norm == pytest.approx(x0norm, 1.0e-12)
def test_assembly_solve_taylor_hood(mesh): """Assemble Stokes problem with Taylor-Hood elements and solve.""" P2 = function.VectorFunctionSpace(mesh, ("Lagrange", 2)) P1 = function.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) facetdim = mesh.topology.dim - 1 mf = dolfinx.MeshFunction("size_t", mesh, facetdim, 0) mf.mark(boundary0, 1) mf.mark(boundary1, 2) bndry_facets0 = numpy.where(mf.values == 1)[0] bndry_facets1 = numpy.where(mf.values == 2)[0] bdofs0 = dolfinx.fem.locate_dofs_topological(P2, facetdim, bndry_facets0) bdofs1 = dolfinx.fem.locate_dofs_topological(P2, facetdim, bndry_facets1) u0 = dolfinx.Function(P2) u0.vector.set(1.0) u0.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) bc0 = dolfinx.DirichletBC(u0, bdofs0) bc1 = dolfinx.DirichletBC(u0, bdofs1) u, p = ufl.TrialFunction(P2), ufl.TrialFunction(P1) v, q = ufl.TestFunction(P2), ufl.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 = dolfinx.Function(P1) f = dolfinx.Function(P2) L0 = ufl.inner(f, v) * dx L1 = ufl.inner(p_zero, q) * dx # -- Blocked (nested) A0 = dolfinx.fem.assemble_matrix_nest([[a00, a01], [a10, a11]], [bc0, bc1]) A0.assemble() A0norm = nest_matrix_norm(A0) P0 = dolfinx.fem.assemble_matrix_nest([[p00, p01], [p10, p11]], [bc0, bc1]) P0.assemble() P0norm = nest_matrix_norm(P0) b0 = dolfinx.fem.assemble_vector_nest([L0, L1]) dolfinx.fem.apply_lifting_nest(b0, [[a00, a01], [a10, a11]], [bc0, bc1]) for b_sub in b0.getNestSubVecs(): b_sub.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) bcs0 = dolfinx.cpp.fem.bcs_rows( dolfinx.fem.assemble._create_cpp_form([L0, L1]), [bc0, bc1]) dolfinx.fem.set_bc_nest(b0, bcs0) b0.assemble() 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 (monolithic) A1 = dolfinx.fem.assemble_matrix_block([[a00, a01], [a10, a11]], [bc0, bc1]) A1.assemble() assert A1.norm() == pytest.approx(A0norm, 1.0e-12) P1 = dolfinx.fem.assemble_matrix_block([[p00, p01], [p10, p11]], [bc0, bc1]) P1.assemble() assert P1.norm() == pytest.approx(P0norm, 1.0e-12) b1 = dolfinx.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_el = ufl.VectorElement("Lagrange", mesh.ufl_cell(), 2) P1_el = ufl.FiniteElement("Lagrange", mesh.ufl_cell(), 1) TH = P2_el * P1_el W = dolfinx.FunctionSpace(mesh, TH) (u, p) = ufl.TrialFunctions(W) (v, q) = ufl.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 = dolfinx.Function(W.sub(0).collapse()) p_zero = dolfinx.Function(W.sub(1).collapse()) L0 = inner(f, v) * dx L1 = inner(p_zero, q) * dx L = L0 + L1 bdofsW0_P2_0 = dolfinx.fem.locate_dofs_topological((W.sub(0), P2), facetdim, bndry_facets0) bdofsW0_P2_1 = dolfinx.fem.locate_dofs_topological((W.sub(0), P2), facetdim, bndry_facets1) bc0 = dolfinx.DirichletBC(u0, bdofsW0_P2_0, W.sub(0)) bc1 = dolfinx.DirichletBC(u0, bdofsW0_P2_1, W.sub(0)) A2 = dolfinx.fem.assemble_matrix(a, [bc0, bc1]) A2.assemble() assert A2.norm() == pytest.approx(A0norm, 1.0e-12) P2 = dolfinx.fem.assemble_matrix(p_form, [bc0, bc1]) P2.assemble() assert P2.norm() == pytest.approx(P0norm, 1.0e-12) b2 = dolfinx.fem.assemble_vector(L) dolfinx.fem.apply_lifting(b2, [a], [[bc0, bc1]]) b2.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) dolfinx.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)
def test_assembly_solve_block(): """Solve a two-field mass-matrix like problem with block matrix approaches and test that solution is the same. """ mesh = dolfinx.generation.UnitSquareMesh(dolfinx.MPI.comm_world, 32, 31) P = ufl.FiniteElement("Lagrange", mesh.ufl_cell(), 1) V0 = dolfinx.function.FunctionSpace(mesh, P) V1 = V0.clone() def boundary(x): return numpy.logical_or(x[0] < 1.0e-6, x[0] > 1.0 - 1.0e-6) facetdim = mesh.topology.dim - 1 mf = dolfinx.MeshFunction("size_t", mesh, facetdim, 0) mf.mark(boundary, 1) bndry_facets = numpy.where(mf.values == 1)[0] bdofsV0 = dolfinx.fem.locate_dofs_topological(V0, facetdim, bndry_facets) bdofsV1 = dolfinx.fem.locate_dofs_topological(V1, facetdim, bndry_facets) u_bc0 = dolfinx.function.Function(V0) u_bc0.vector.set(50.0) u_bc0.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) u_bc1 = dolfinx.function.Function(V1) u_bc1.vector.set(20.0) u_bc1.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) bcs = [ dolfinx.fem.dirichletbc.DirichletBC(u_bc0, bdofsV0), dolfinx.fem.dirichletbc.DirichletBC(u_bc1, bdofsV1) ] # Variational problem u, p = ufl.TrialFunction(V0), ufl.TrialFunction(V1) v, q = ufl.TestFunction(V0), ufl.TestFunction(V1) f = 1.0 g = -3.0 zero = dolfinx.Function(V0) a00 = inner(u, v) * dx a01 = zero * inner(p, v) * dx a10 = zero * inner(u, q) * dx a11 = inner(p, q) * dx L0 = inner(f, v) * dx L1 = inner(g, q) * dx def monitor(ksp, its, rnorm): pass # print("Norm:", its, rnorm) A0 = dolfinx.fem.assemble_matrix_block([[a00, a01], [a10, a11]], bcs) b0 = dolfinx.fem.assemble_vector_block([L0, L1], [[a00, a01], [a10, a11]], bcs) A0.assemble() A0norm = A0.norm() b0norm = b0.norm() x0 = A0.createVecLeft() ksp = PETSc.KSP() ksp.create(mesh.mpi_comm()) ksp.setOperators(A0) ksp.setMonitor(monitor) ksp.setType('cg') ksp.setTolerances(rtol=1.0e-14) ksp.setFromOptions() ksp.solve(b0, x0) x0norm = x0.norm() # Nested (MatNest) A1 = dolfinx.fem.assemble_matrix_nest([[a00, a01], [a10, a11]], bcs) A1.assemble() b1 = dolfinx.fem.assemble_vector_nest([L0, L1]) dolfinx.fem.apply_lifting_nest(b1, [[a00, a01], [a10, a11]], bcs) for b_sub in b1.getNestSubVecs(): b_sub.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) bcs0 = dolfinx.cpp.fem.bcs_rows( dolfinx.fem.assemble._create_cpp_form([L0, L1]), bcs) dolfinx.fem.set_bc_nest(b1, bcs0) b1.assemble() b1norm = b1.norm() assert b1norm == pytest.approx(b0norm, 1.0e-12) A1norm = nest_matrix_norm(A1) assert A0norm == pytest.approx(A1norm, 1.0e-12) x1 = b1.copy() ksp = PETSc.KSP() ksp.create(mesh.mpi_comm()) ksp.setMonitor(monitor) ksp.setOperators(A1) ksp.setType('cg') ksp.setTolerances(rtol=1.0e-12) ksp.setFromOptions() ksp.solve(b1, x1) x1norm = x1.norm() assert x1norm == pytest.approx(x0norm, rel=1.0e-12) # Monolithic version E = P * P W = dolfinx.function.FunctionSpace(mesh, E) u0, u1 = ufl.TrialFunctions(W) v0, v1 = ufl.TestFunctions(W) a = inner(u0, v0) * dx + inner(u1, v1) * dx L = inner(f, v0) * ufl.dx + inner(g, v1) * dx u0_bc = dolfinx.function.Function(V0) u0_bc.vector.set(50.0) u0_bc.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) u1_bc = dolfinx.function.Function(V1) u1_bc.vector.set(20.0) u1_bc.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) bdofsW0_V0 = dolfinx.fem.locate_dofs_topological((W.sub(0), V0), facetdim, bndry_facets) bdofsW1_V1 = dolfinx.fem.locate_dofs_topological((W.sub(1), V1), facetdim, bndry_facets) bcs = [ dolfinx.fem.dirichletbc.DirichletBC(u0_bc, bdofsW0_V0, W.sub(0)), dolfinx.fem.dirichletbc.DirichletBC(u1_bc, bdofsW1_V1, W.sub(1)) ] A2 = dolfinx.fem.assemble_matrix(a, bcs) A2.assemble() b2 = dolfinx.fem.assemble_vector(L) dolfinx.fem.apply_lifting(b2, [a], [bcs]) b2.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) dolfinx.fem.set_bc(b2, bcs) A2norm = A2.norm() b2norm = b2.norm() assert A2norm == pytest.approx(A0norm, 1.0e-12) assert b2norm == pytest.approx(b0norm, 1.0e-12) x2 = b2.copy() ksp = PETSc.KSP() ksp.create(mesh.mpi_comm()) ksp.setMonitor(monitor) ksp.setOperators(A2) ksp.setType('cg') ksp.getPC().setType('jacobi') ksp.setTolerances(rtol=1.0e-12) ksp.setFromOptions() ksp.solve(b2, x2) x2norm = x2.norm() assert x2norm == pytest.approx(x0norm, 1.0e-10)
def test_matrix_assembly_block(): """Test assembly of block matrices and vectors into (a) monolithic blocked structures, PETSc Nest structures, and monolithic structures. """ mesh = dolfinx.generation.UnitSquareMesh(dolfinx.MPI.comm_world, 4, 8) p0, p1 = 1, 2 P0 = ufl.FiniteElement("Lagrange", mesh.ufl_cell(), p0) P1 = ufl.FiniteElement("Lagrange", mesh.ufl_cell(), p1) V0 = dolfinx.function.FunctionSpace(mesh, P0) V1 = dolfinx.function.FunctionSpace(mesh, P1) def boundary(x): return numpy.logical_or(x[0] < 1.0e-6, x[0] > 1.0 - 1.0e-6) # Prepare a MeshFunction used for boundary conditions facetdim = mesh.topology.dim - 1 mf = dolfinx.MeshFunction("size_t", mesh, facetdim, 0) mf.mark(boundary, 1) bndry_facets = numpy.where(mf.values == 1)[0] bdofsV1 = dolfinx.fem.locate_dofs_topological(V1, facetdim, bndry_facets) u_bc = dolfinx.function.Function(V1) with u_bc.vector.localForm() as u_local: u_local.set(50.0) bc = dolfinx.fem.dirichletbc.DirichletBC(u_bc, bdofsV1) # Define variational problem u, p = ufl.TrialFunction(V0), ufl.TrialFunction(V1) v, q = ufl.TestFunction(V0), ufl.TestFunction(V1) f = 1.0 g = -3.0 zero = dolfinx.Function(V0) a00 = inner(u, v) * dx a01 = inner(p, v) * dx a10 = inner(u, q) * dx a11 = inner(p, q) * dx L0 = zero * inner(f, v) * dx L1 = inner(g, q) * dx a_block = [[a00, a01], [a10, a11]] L_block = [L0, L1] # Monolithic blocked A0 = dolfinx.fem.assemble_matrix_block(a_block, [bc]) A0.assemble() b0 = dolfinx.fem.assemble_vector_block(L_block, a_block, [bc]) assert A0.getType() != "nest" Anorm0 = A0.norm() bnorm0 = b0.norm() # Nested (MatNest) A1 = dolfinx.fem.assemble_matrix_nest(a_block, [bc]) A1.assemble() Anorm1 = nest_matrix_norm(A1) assert Anorm0 == pytest.approx(Anorm1, 1.0e-12) b1 = dolfinx.fem.assemble_vector_nest(L_block) dolfinx.fem.apply_lifting_nest(b1, a_block, [bc]) for b_sub in b1.getNestSubVecs(): b_sub.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) bcs0 = dolfinx.cpp.fem.bcs_rows( dolfinx.fem.assemble._create_cpp_form(L_block), [bc]) dolfinx.fem.set_bc_nest(b1, bcs0) b1.assemble() bnorm1 = math.sqrt(sum([x.norm()**2 for x in b1.getNestSubVecs()])) assert bnorm0 == pytest.approx(bnorm1, 1.0e-12) # Monolithic version E = P0 * P1 W = dolfinx.function.FunctionSpace(mesh, E) u0, u1 = ufl.TrialFunctions(W) v0, v1 = ufl.TestFunctions(W) a = inner(u0, v0) * dx + inner(u1, v1) * dx + inner(u0, v1) * dx + inner( u1, v0) * dx L = zero * inner(f, v0) * ufl.dx + inner(g, v1) * dx bdofsW_V1 = dolfinx.fem.locate_dofs_topological( (W.sub(1), V1), mesh.topology.dim - 1, bndry_facets) bc = dolfinx.fem.dirichletbc.DirichletBC(u_bc, bdofsW_V1, W.sub(1)) A2 = dolfinx.fem.assemble_matrix(a, [bc]) A2.assemble() b2 = dolfinx.fem.assemble_vector(L) dolfinx.fem.apply_lifting(b2, [a], [[bc]]) b2.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) dolfinx.fem.set_bc(b2, [bc]) assert A2.getType() != "nest" assert A2.norm() == pytest.approx(Anorm0, 1.0e-9) assert b2.norm() == pytest.approx(bnorm0, 1.0e-9)
U = dolfinx.FunctionSpace(mesh, Ue) # Get local dofmap sizes for later local tensor tabulations Ssize = S.dolfin_element().space_dimension() Usize = U.dolfin_element().space_dimension() sigma, tau = ufl.TrialFunction(S), ufl.TestFunction(S) u, v = ufl.TrialFunction(U), ufl.TestFunction(U) # Homogeneous boundary condition in displacement u_bc = dolfinx.Function(U) with u_bc.vector.localForm() as loc: loc.set(0.0) facetdim = mesh.topology.dim - 1 mf = dolfinx.MeshFunction("size_t", mesh, facetdim, 0) mf.mark(lambda x: numpy.isclose(x[0], 0.0), 1) bndry_facets = numpy.where(mf.values == 1)[0] # Displacement BC is applied to the right side bdofs = dolfinx.fem.locate_dofs_topological(U, facetdim, bndry_facets) bc = dolfinx.fem.DirichletBC(u_bc, bdofs) def free_end(x): """Marks the leftmost points of the cantilever""" return numpy.isclose(x[0], 48.0) # Mark free end facets as 1 mf = dolfinx.mesh.MeshFunction("size_t", mesh, 1, 0)
def test_assembly_dx_domains(mesh): V = dolfinx.FunctionSpace(mesh, ("CG", 1)) u, v = ufl.TrialFunction(V), ufl.TestFunction(V) marker = dolfinx.MeshFunction("size_t", mesh, mesh.topology.dim, 0) values = marker.values # Mark first, second and all other # Their union is the whole domain values[0] = 111 values[1] = 222 values[2:] = 333 dx = ufl.Measure('dx', subdomain_data=marker, domain=mesh) w = dolfinx.Function(V) with w.vector.localForm() as w_local: w_local.set(0.5) # # Assemble matrix # a = w * ufl.inner(u, v) * (dx(111) + dx(222) + dx(333)) A = dolfinx.fem.assemble_matrix(a) A.assemble() norm1 = A.norm() a2 = w * ufl.inner(u, v) * dx A2 = dolfinx.fem.assemble_matrix(a2) A2.assemble() norm2 = A2.norm() assert norm1 == pytest.approx(norm2, 1.0e-12) # # Assemble vector # L = ufl.inner(w, v) * (dx(111) + dx(222) + dx(333)) b = dolfinx.fem.assemble_vector(L) b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) L2 = ufl.inner(w, v) * dx b2 = dolfinx.fem.assemble_vector(L2) b2.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) assert b.norm() == pytest.approx(b2.norm(), 1.0e-12) # # Assemble scalar # L = w * (dx(111) + dx(222) + dx(333)) s = dolfinx.fem.assemble_scalar(L) s = dolfinx.MPI.sum(mesh.mpi_comm(), s) L2 = w * dx s2 = dolfinx.fem.assemble_scalar(L2) s2 = dolfinx.MPI.sum(mesh.mpi_comm(), s2) assert (s == pytest.approx(s2, 1.0e-12) and 0.5 == pytest.approx(s, 1.0e-12))