def test_additivity(mode): mesh = dolfinx.UnitSquareMesh(MPI.COMM_WORLD, 12, 12, ghost_mode=mode) V = dolfinx.FunctionSpace(mesh, ("CG", 1)) f1 = dolfinx.Function(V) f2 = dolfinx.Function(V) f3 = dolfinx.Function(V) with f1.vector.localForm() as f1_local: f1_local.set(1.0) with f2.vector.localForm() as f2_local: f2_local.set(2.0) with f3.vector.localForm() as f3_local: f3_local.set(3.0) j1 = ufl.inner(f1, f1) * ufl.dx(mesh) j2 = ufl.inner(f2, f2) * ufl.ds(mesh) j3 = ufl.inner(ufl.avg(f3), ufl.avg(f3)) * ufl.dS(mesh) # Assemble each scalar form separately J1 = mesh.mpi_comm().allreduce(dolfinx.fem.assemble_scalar(j1), op=MPI.SUM) J2 = mesh.mpi_comm().allreduce(dolfinx.fem.assemble_scalar(j2), op=MPI.SUM) J3 = mesh.mpi_comm().allreduce(dolfinx.fem.assemble_scalar(j3), op=MPI.SUM) # Sum forms and assemble the result J12 = mesh.mpi_comm().allreduce(dolfinx.fem.assemble_scalar(j1 + j2), op=MPI.SUM) J13 = mesh.mpi_comm().allreduce(dolfinx.fem.assemble_scalar(j1 + j3), op=MPI.SUM) J23 = mesh.mpi_comm().allreduce(dolfinx.fem.assemble_scalar(j2 + j3), op=MPI.SUM) J123 = mesh.mpi_comm().allreduce(dolfinx.fem.assemble_scalar(j1 + j2 + j3), op=MPI.SUM) # Compare assembled values assert (J1 + J2) == pytest.approx(J12) assert (J1 + J3) == pytest.approx(J13) assert (J2 + J3) == pytest.approx(J23) assert (J1 + J2 + J3) == pytest.approx(J123)
def test_assemble_derivatives(): """This test checks the original_coefficient_positions, which may change under differentiation (some coefficients and constants are eliminated)""" mesh = UnitSquareMesh(MPI.COMM_WORLD, 12, 12) Q = dolfinx.FunctionSpace(mesh, ("Lagrange", 1)) u = dolfinx.Function(Q) v = ufl.TestFunction(Q) du = ufl.TrialFunction(Q) b = dolfinx.Function(Q) c1 = fem.Constant(mesh, [[1.0, 0.0], [3.0, 4.0]]) c2 = fem.Constant(mesh, 2.0) with b.vector.localForm() as b_local: b_local.set(2.0) # derivative eliminates 'u' and 'c1' L = ufl.inner(c1, c1) * v * dx + c2 * b * inner(u, v) * dx a = derivative(L, u, du) A1 = dolfinx.fem.assemble_matrix(a) A1.assemble() a = c2 * b * inner(du, v) * dx A2 = dolfinx.fem.assemble_matrix(a) A2.assemble() assert (A1 - A2).norm() == pytest.approx(0.0, rel=1e-12, abs=1e-12)
def test_custom_mesh_loop_rank1(): # Create mesh and function space mesh = dolfinx.generation.UnitSquareMesh(MPI.COMM_WORLD, 64, 64) V = dolfinx.FunctionSpace(mesh, ("Lagrange", 1)) # Unpack mesh and dofmap data pos = mesh.geometry.dofmap.offsets() x_dofs = mesh.geometry.dofmap.array() x = mesh.geometry.x dofs = V.dofmap.list.array() # Assemble with pure Numba function (two passes, first will include JIT overhead) b0 = dolfinx.Function(V) for i in range(2): with b0.vector.localForm() as b: b.set(0.0) start = time.time() assemble_vector(np.asarray(b), (pos, x_dofs, x), dofs) end = time.time() print("Time (numba, pass {}): {}".format(i, end - start)) b0.vector.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) assert (b0.vector.sum() == pytest.approx(1.0)) # Test against generated code and general assembler v = ufl.TestFunction(V) L = inner(1.0, v) * dx start = time.time() b1 = dolfinx.fem.assemble_vector(L) end = time.time() print("Time (C++, pass 1):", end - start) with b1.localForm() as b_local: b_local.set(0.0) start = time.time() dolfinx.fem.assemble_vector(b1, L) end = time.time() print("Time (C++, pass 2):", end - start) b1.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) assert ((b1 - b0.vector).norm() == pytest.approx(0.0)) # Assemble using generated tabulate_tensor kernel and Numba assembler b3 = dolfinx.Function(V) ufc_form = dolfinx.jit.ffcx_jit(L) kernel = ufc_form.create_cell_integral(-1).tabulate_tensor for i in range(2): with b3.vector.localForm() as b: b.set(0.0) start = time.time() assemble_vector_ufc(np.asarray(b), kernel, (pos, x_dofs, x), dofs) end = time.time() print("Time (numba/cffi, pass {}): {}".format(i, end - start)) b3.vector.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) assert ((b3.vector - b0.vector).norm() == pytest.approx(0.0))
def test_expression_linearise(V1, V2, squaremesh_5): u1, u10 = dolfinx.Function(V1), dolfinx.Function(V1) u2, u20 = dolfinx.Function(V2), dolfinx.Function(V2) dx = ufl.dx(squaremesh_5) # Test linearisation of expressions at u0 assert dolfiny.expression.linearise(1 * u1, u1, u0=u10) == \ u10 + (u1 + (-1) * u10) assert dolfiny.expression.linearise(2 * u1 + u2, u1, u0=u10) == \ (u2 + 2 * u10) + (2 * u1 + (-1) * (2 * u10)) assert dolfiny.expression.linearise(u1**2 + u2, u1, u0=u10) == \ (u10 * (2 * u1) + (-1) * (u10 * 2 * u10)) + (u10**2 + u2) assert dolfiny.expression.linearise(u1**2 + u2**2, [u1, u2], u0=[u10, u20]) == \ (u10 * (2 * u1) + u20 * (2 * u2) + (-1) * (u10 * (2 * u10) + u20 * (2 * u20))) + (u10**2 + u20**2) assert dolfiny.expression.linearise([u1**2, u2], u1, u0=u10) == \ [(u10 * (2 * u1) + (-1) * (u10 * 2 * u10)) + u10**2, u2] assert dolfiny.expression.linearise([u1**2 + u2, u2], [u1, u2], u0=[u10, u20]) == \ [(u10 * (2 * u1) + u2 + (-1) * (u10 * (2 * u10) + u20)) + (u10**2 + u20), (u2 + (-1) * u20) + u20] # Test linearisation of forms at u0 assert dolfiny.expression.linearise(1 * u1 * dx, u1, u0=u10) == \ u10 * dx + (u1 * dx + (-1) * u10 * dx) assert dolfiny.expression.linearise([u1**2 * dx, u2 * dx], u1, u0=u10) == \ [u10**2 * dx + u10 * (2 * u1) * dx + (-1) * (u10 * 2 * u10) * dx, u2 * dx]
def test_assembly_dx_domains(mode): mesh = dolfinx.generation.UnitSquareMesh(MPI.COMM_WORLD, 10, 10, ghost_mode=mode) V = dolfinx.FunctionSpace(mesh, ("CG", 1)) u, v = ufl.TrialFunction(V), ufl.TestFunction(V) # Prepare a marking structures # indices cover all cells # values are [1, 2, 3, 3, ...] cell_map = mesh.topology.index_map(mesh.topology.dim) num_cells = cell_map.size_local + cell_map.num_ghosts indices = numpy.arange(0, num_cells) values = numpy.full(indices.shape, 3, dtype=numpy.intc) values[0] = 1 values[1] = 2 marker = dolfinx.mesh.MeshTags(mesh, mesh.topology.dim, indices, values) 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) bc = dolfinx.fem.DirichletBC(dolfinx.Function(V), range(30)) # Assemble matrix a = w * ufl.inner(u, v) * (dx(1) + dx(2) + dx(3)) A = dolfinx.fem.assemble_matrix(a) A.assemble() a2 = w * ufl.inner(u, v) * dx A2 = dolfinx.fem.assemble_matrix(a2) A2.assemble() assert (A - A2).norm() < 1.0e-12 # Assemble vector L = ufl.inner(w, v) * (dx(1) + dx(2) + dx(3)) b = dolfinx.fem.assemble_vector(L) dolfinx.fem.apply_lifting(b, [a], [[bc]]) b.ghostUpdate(addv=PETSc.InsertMode.ADD_VALUES, mode=PETSc.ScatterMode.REVERSE) dolfinx.fem.set_bc(b, [bc]) L2 = ufl.inner(w, v) * dx b2 = dolfinx.fem.assemble_vector(L2) dolfinx.fem.apply_lifting(b2, [a], [[bc]]) b2.ghostUpdate(addv=PETSc.InsertMode.ADD_VALUES, mode=PETSc.ScatterMode.REVERSE) dolfinx.fem.set_bc(b2, [bc]) assert (b - b2).norm() < 1.0e-12 # Assemble scalar L = w * (dx(1) + dx(2) + dx(3)) s = dolfinx.fem.assemble_scalar(L) s = mesh.mpi_comm().allreduce(s, op=MPI.SUM) assert s == pytest.approx(0.5, 1.0e-12) L2 = w * dx s2 = dolfinx.fem.assemble_scalar(L2) s2 = mesh.mpi_comm().allreduce(s2, op=MPI.SUM) assert s == pytest.approx(s2, 1.0e-12)
def test_expression_assemble(V1, vV1, squaremesh_5): u1, u2 = dolfinx.Function(V1), dolfinx.Function(vV1) dx = ufl.dx(squaremesh_5) u1.vector.set(3.0) u2.vector.set(2.0) u1.vector.ghostUpdate() u2.vector.ghostUpdate() # check assembled shapes assert numpy.shape(dolfiny.expression.assemble(1.0, dx)) == () assert numpy.shape(dolfiny.expression.assemble(ufl.grad(u1), dx)) == (2,) assert numpy.shape(dolfiny.expression.assemble(ufl.grad(u2), dx)) == (2, 2) # check assembled values assert numpy.isclose(dolfiny.expression.assemble(1.0, dx), 1.0) assert numpy.isclose(dolfiny.expression.assemble(u1, dx), 3.0) assert numpy.isclose(dolfiny.expression.assemble(u2, dx), 2.0).all() assert numpy.isclose(dolfiny.expression.assemble(u1 * u2, dx), 6.0).all() assert numpy.isclose(dolfiny.expression.assemble(ufl.grad(u1), dx), 0.0).all() assert numpy.isclose(dolfiny.expression.assemble(ufl.grad(u2), dx), 0.0).all()
def monolithic_solve(): """Monolithic (interleaved) solver""" 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)) A = dolfinx.fem.assemble_matrix(a, [bc0, bc1]) A.assemble() P = dolfinx.fem.assemble_matrix(p_form, [bc0, bc1]) P.assemble() b = dolfinx.fem.assemble_vector(L) dolfinx.fem.apply_lifting(b, [a], [[bc0, bc1]]) b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) dolfinx.fem.set_bc(b, [bc0, bc1]) ksp = PETSc.KSP() ksp.create(mesh.mpi_comm()) ksp.setOperators(A, P) ksp.setType("minres") pc = ksp.getPC() pc.setType('lu') 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() x = A.createVecRight() ksp.solve(b, x) assert ksp.getConvergedReason() > 0 return b.norm(), x.norm(), A.norm(), P.norm()
def test_overlapping_bcs(): """Test that, when boundaries condition overlap, the last provided boundary condition is applied. """ n = 23 mesh = dolfinx.generation.UnitSquareMesh(MPI.COMM_WORLD, n, n) V = dolfinx.fem.FunctionSpace(mesh, ("Lagrange", 1)) u, v = ufl.TrialFunction(V), ufl.TestFunction(V) a = inner(u, v) * dx L = inner(1, v) * dx dofs_left = dolfinx.fem.locate_dofs_geometrical( V, lambda x: x[0] < 1.0 / (2.0 * n)) dofs_top = dolfinx.fem.locate_dofs_geometrical( V, lambda x: x[1] > 1.0 - 1.0 / (2.0 * n)) dof_corner = np.array(list(set(dofs_left).intersection(set(dofs_top))), dtype=np.int64) # Check only one dof pair is found globally assert len(set(np.concatenate(MPI.COMM_WORLD.allgather(dof_corner)))) == 1 u0, u1 = dolfinx.Function(V), dolfinx.Function(V) with u0.vector.localForm() as u0_loc: u0_loc.set(0) with u1.vector.localForm() as u1_loc: u1_loc.set(123.456) bcs = [ dolfinx.DirichletBC(u0, dofs_left), dolfinx.DirichletBC(u1, dofs_top) ] A, b = dolfinx.fem.create_matrix(a), dolfinx.fem.create_vector(L) dolfinx.fem.assemble_matrix(A, a, bcs=bcs) A.assemble() # Check the diagonal (only on the rank that owns the row) d = A.getDiagonal() if len(dof_corner) > 0 and dof_corner[0] < V.dofmap.index_map.size_local: d.array_r[dof_corner[0]] == 1.0 with b.localForm() as b_loc: b_loc.set(0) dolfinx.fem.assemble_vector(b, L) dolfinx.fem.apply_lifting(b, [a], [bcs]) b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) dolfinx.fem.set_bc(b, bcs) b.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) if len(dof_corner) > 0: with b.localForm() as b_loc: print(b_loc[dof_corner[0]]) assert b_loc[dof_corner[0]] == 123.456
def test_p1_trace(has_dolfinx): """Test the trace of a P1 Dolfin function.""" if has_dolfinx: import dolfinx import dolfinx.geometry else: try: import dolfinx import dolfinx.geometry except ImportError: pytest.skip("DOLFIN-X must be installed to run this test") import bempp.api from bempp.api.external.fenicsx import fenics_to_bempp_trace_data fenics_mesh = dolfinx.UnitCubeMesh(MPI.COMM_WORLD, 2, 2, 2) fenics_space = dolfinx.FunctionSpace(fenics_mesh, ("CG", 1)) bempp_space, trace_matrix = fenics_to_bempp_trace_data(fenics_space) fenics_coeffs = np.random.rand(fenics_space.dofmap.index_map.size_global) bempp_coeffs = trace_matrix @ fenics_coeffs fenics_fun = dolfinx.Function(fenics_space) fenics_fun.vector[:] = fenics_coeffs bempp_fun = bempp.api.GridFunction(bempp_space, coefficients=bempp_coeffs) tree = dolfinx.geometry.BoundingBoxTree(fenics_mesh, 3) for cell in bempp_space.grid.entity_iterator(0): mid = cell.geometry.centroid bempp_val = bempp_fun.evaluate(cell.index, np.array([[1 / 3], [1 / 3]])) fenics_cell = dolfinx.geometry.compute_closest_entity(tree, mid, fenics_mesh)[0] fenics_val = fenics_fun.eval([mid.T], [fenics_cell]) assert np.isclose(bempp_val[0, 0], fenics_val[0])
def test_assemble_manifold(): """Test assembly of poisson problem on a mesh with topological dimension 1 but embedded in 2D (gdim=2). """ points = numpy.array([[0.0, 0.0], [0.2, 0.0], [0.4, 0.0], [0.6, 0.0], [0.8, 0.0], [1.0, 0.0]], dtype=numpy.float64) cells = numpy.array([[0, 1], [1, 2], [2, 3], [3, 4], [4, 5]], dtype=numpy.int32) cell = ufl.Cell("interval", geometric_dimension=points.shape[1]) domain = ufl.Mesh(ufl.VectorElement("Lagrange", cell, 1)) mesh = create_mesh(MPI.COMM_WORLD, cells, points, domain) assert mesh.geometry.dim == 2 assert mesh.topology.dim == 1 U = dolfinx.FunctionSpace(mesh, ("P", 1)) u, v = ufl.TrialFunction(U), ufl.TestFunction(U) w = dolfinx.Function(U) a = ufl.inner(ufl.grad(u), ufl.grad(v)) * ufl.dx(mesh) L = ufl.inner(1.0, v) * ufl.dx(mesh) bcdofs = dolfinx.fem.locate_dofs_geometrical( U, lambda x: numpy.isclose(x[0], 0.0)) bcs = [dolfinx.DirichletBC(w, bcdofs)] A = dolfinx.fem.assemble_matrix(a, bcs) A.assemble() b = dolfinx.fem.assemble_vector(L) dolfinx.fem.apply_lifting(b, [a], [bcs]) dolfinx.fem.set_bc(b, bcs) assert numpy.isclose(b.norm(), 0.41231) assert numpy.isclose(A.norm(), 25.0199)
def interpolate_on_mesh(self, mesh, q, u): # Extract mesh geometry nodal coordinates dm = mesh.geometry.dofmap oq = [0] + [*range(2, q + 1) ] + [1] # reorder lineX nodes: all ducks in a row... x0_idx = [[dm.links(i).tolist()[k] for k in oq] for i in range(dm.num_nodes)] x0_idx = [item for sublist in x0_idx for item in sublist] x0 = mesh.geometry.x[x0_idx] # Interpolate solution at mesh geometry nodes import dolfinx import dolfiny.interpolation Q = dolfinx.FunctionSpace(mesh, ("P", q)) uf = dolfinx.Function(Q) if isinstance(u, list): ui = [] for u_ in u: dolfiny.interpolation.interpolate(u_, uf) ui.append(uf.vector[x0_idx]) else: dolfiny.interpolation.interpolate(u, uf) ui = uf.vector[x0_idx] return x0, ui
def test_assembly_dx_domains(mesh): V = dolfinx.FunctionSpace(mesh, ("CG", 1)) u, v = ufl.TrialFunction(V), ufl.TestFunction(V) # Prepare a marking structures # indices cover all cells # values are [1, 2, 3, 3, ...] imap = mesh.topology.index_map(mesh.topology.dim) num_cells = imap.size_local + imap.num_ghosts indices = numpy.arange(0, num_cells) values = numpy.full(indices.shape, 3, dtype=numpy.intc) values[0] = 1 values[1] = 2 marker = dolfinx.mesh.MeshTags(mesh, mesh.topology.dim, indices, values) 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(1) + dx(2) + dx(3)) 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(1) + dx(2) + dx(3)) 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(1) + dx(2) + dx(3)) s = dolfinx.fem.assemble_scalar(L) s = mesh.mpi_comm().allreduce(s, op=MPI.SUM) L2 = w * dx s2 = dolfinx.fem.assemble_scalar(L2) s2 = mesh.mpi_comm().allreduce(s2, op=MPI.SUM) assert (s == pytest.approx(s2, 1.0e-12) and 0.5 == pytest.approx(s, 1.0e-12))
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_block(V1, V2, squaremesh_5, nest): mesh = squaremesh_5 u0 = dolfinx.Function(V1, name="u0") u1 = dolfinx.Function(V2, name="u1") v0 = ufl.TestFunction(V1) v1 = ufl.TestFunction(V2) Phi = (ufl.sin(u0) - 0.5)**2 * ufl.dx(mesh) + (4.0 * u0 - u1)**2 * ufl.dx(mesh) F0 = ufl.derivative(Phi, u0, v0) F1 = ufl.derivative(Phi, u1, v1) F = [F0, F1] u = [u0, u1] opts = PETSc.Options("block") opts.setValue('snes_type', 'newtontr') opts.setValue('snes_rtol', 1.0e-08) opts.setValue('snes_max_it', 12) if nest: opts.setValue('ksp_type', 'cg') opts.setValue('pc_type', 'fieldsplit') opts.setValue('fieldsplit_pc_type', 'lu') opts.setValue('ksp_rtol', 1.0e-10) else: opts.setValue('ksp_type', 'preonly') opts.setValue('pc_type', 'lu') opts.setValue('pc_factor_mat_solver_type', 'mumps') problem = dolfiny.snesblockproblem.SNESBlockProblem(F, u, nest=nest, prefix="block") sol = problem.solve() assert problem.snes.getConvergedReason() > 0 assert np.isclose((sol[0].vector - np.arcsin(0.5)).norm(), 0.0) assert np.isclose((sol[1].vector - 4.0 * np.arcsin(0.5)).norm(), 0.0)
def test_mixed_element_interpolation(): def f(x): return np.ones(2, x.shape[1]) mesh = UnitCubeMesh(MPI.COMM_WORLD, 3, 3, 3) el = ufl.FiniteElement("CG", mesh.ufl_cell(), 1) V = dolfinx.FunctionSpace(mesh, ufl.MixedElement([el, el])) u = dolfinx.Function(V) with pytest.raises(RuntimeError): u.interpolate(f)
def test_dof_coords_2d(degree): mesh = dolfinx.UnitSquareMesh(MPI.COMM_WORLD, 10, 10) V = dolfinx.FunctionSpace(mesh, ("CG", degree)) u = dolfinx.Function(V) u.interpolate(lambda x: x[0]) u.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) x = V.tabulate_dof_coordinates() val = u.vector.array for i in range(len(val)): assert np.isclose(x[i, 0], val[i], rtol=1e-3)
def linearise(e, u, u0=None): """Generate the first order Taylor series expansion of UFL expressions (or list of expressions) for the given function(s) u at u0. Example (linearise around zero): linF = dolfiny.expression.linearise(F, u) Example (linearise around given state): linF = dolfiny.expression.linearise(F, u, u0) Parameters ---------- e: UFL Expr/Form or list of UFL expressions/forms u: UFL Function or list of UFL functions u0: UFL Function or list of UFL functions, defaults to zero Returns ------- 1st order Taylor series expansion of expression/form (or list of expressions/forms). """ if u0 is None: if isinstance(u, list): u0 = [] for v in u: u0.append(dolfinx.Function(v.function_space, name=v.name + '_0')) else: u0 = dolfinx.Function(u.function_space, name=u.name + '_0') e0 = evaluate(e, u, u0) deu = derivative(e, u, u, u0) deu0 = derivative(e, u, u0, u0) if isinstance(e, list): de = [] for e0_, deu_, deu0_ in zip(e0, deu, deu0): de.append(e0_ + (deu_ - deu0_)) else: de = e0 + (deu - deu0) return de
def test_expression_derivative(V1, V2, squaremesh_5): u1, du1, v1 = dolfinx.Function(V1), ufl.TrialFunction(V1), ufl.TestFunction(V1) u2, du2, v2 = dolfinx.Function(V2), ufl.TrialFunction(V2), ufl.TestFunction(V2) dx = ufl.dx(squaremesh_5) # Test derivative of expressions assert dolfiny.expression.derivative(1 * u1, u1, du1) == 1 * du1 assert dolfiny.expression.derivative(2 * u1 + u2, u1, du1) == 2 * du1 assert dolfiny.expression.derivative(u1**2 + u2, u1, du1) == du1 * 2 * u1 assert dolfiny.expression.derivative(u1 + u2, [u1, u2], [v1, v2]) == v1 + v2 assert dolfiny.expression.derivative([u1, u2], u1, v1) == [v1, 0] assert dolfiny.expression.derivative([u1, u2], [u1, u2], [v1, v2]) == [v1, v2] # Test derivative of forms assert dolfiny.expression.derivative(1 * u1 * dx, u1, du1) == 1 * du1 * dx assert dolfiny.expression.derivative(2 * u1 * dx + u2 * dx, u1, du1) == 2 * du1 * dx assert dolfiny.expression.derivative(u1**2 * dx + u2 * dx, u1, du2) == du2 * 2 * u1 * dx assert dolfiny.expression.derivative(u1 * dx + u2 * dx, [u1, u2], [v1, v2]) == v1 * dx + v2 * dx assert dolfiny.expression.derivative([u1 * dx, u2 * dx], u1, v1) == [v1 * dx, ufl.Form([])] assert dolfiny.expression.derivative([u1 * dx, u2 * dx], [u1, u2], [v1, v2]) == [v1 * dx, v2 * dx] # Test derivative of expressions at u0 u10, u20 = dolfinx.Function(V1), dolfinx.Function(V2) assert dolfiny.expression.derivative(1 * u1, u1, du1, u0=u10) == 1 * du1 assert dolfiny.expression.derivative(2 * u1 + u2, u1, du1, u0=u10) == 2 * du1 assert dolfiny.expression.derivative(u1**2 + u2, u1, du1, u0=u10) == du1 * 2 * u10 assert dolfiny.expression.derivative(u1**2 + u2**2, [u1, u2], [v1, v2], [u10, u20]) == v1 * 2 * u10 + v2 * 2 * u20 assert dolfiny.expression.derivative([u1**2, u2], u1, v1, u0=u10) == [v1 * 2 * u10, 0] assert dolfiny.expression.derivative([u1**2 + u2, u2], [u1, u2], [v1, v2], [u10, u20]) == [v1 * 2 * u10 + v2, v2]
def monolithic_assembly(clock, reps, mesh, use_cpp_forms): 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) num_dofs = W.dim U = dolfinx.Function(W) u, p = ufl.split(U) v, q = ufl.TestFunctions(W) g = ufl.as_vector([0.0, 0.0, -1.0]) F = ( ufl.inner(ufl.grad(u), ufl.grad(v)) * ufl.dx + ufl.inner(p, ufl.div(v)) * ufl.dx + ufl.inner(ufl.div(u), q) * ufl.dx - ufl.inner(g, v) * ufl.dx ) J = ufl.derivative(F, U, ufl.TrialFunction(W)) bcs = [] # Get jitted forms for better performance if use_cpp_forms: F = dolfinx.fem.assemble._create_cpp_form(F) J = dolfinx.fem.assemble._create_cpp_form(J) b = dolfinx.fem.create_vector(F) A = dolfinx.fem.create_matrix(J) for i in range(reps): A.zeroEntries() with b.localForm() as b_local: b_local.set(0.0) with dolfinx.common.Timer("ZZZ Mat Monolithic") as tmr: dolfinx.fem.assemble_matrix(A, J, bcs) A.assemble() clock["mat"] += tmr.elapsed()[0] with dolfinx.common.Timer("ZZZ Vec Monolithic") as tmr: dolfinx.fem.assemble_vector(b, F) dolfinx.fem.apply_lifting(b, [J], bcs=[bcs], x0=[U.vector], scale=-1.0) b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) dolfinx.fem.set_bc(b, bcs, x0=U.vector, scale=-1.0) b.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) clock["vec"] += tmr.elapsed()[0] return num_dofs, A, b
def test_basic_assembly(mode): mesh = UnitSquareMesh(MPI.COMM_WORLD, 12, 12, ghost_mode=mode) V = dolfinx.FunctionSpace(mesh, ("Lagrange", 1)) u, v = ufl.TrialFunction(V), ufl.TestFunction(V) f = dolfinx.Function(V) with f.vector.localForm() as f_local: f_local.set(10.0) a = inner(f * u, v) * dx + inner(u, v) * ds L = inner(f, v) * dx + inner(2.0, v) * ds # Initial assembly A = dolfinx.fem.assemble_matrix(a) A.assemble() assert isinstance(A, PETSc.Mat) b = dolfinx.fem.assemble_vector(L) b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) assert isinstance(b, PETSc.Vec) # Second assembly normA = A.norm() A.zeroEntries() A = dolfinx.fem.assemble_matrix(A, a) A.assemble() assert isinstance(A, PETSc.Mat) assert normA == pytest.approx(A.norm()) normb = b.norm() with b.localForm() as b_local: b_local.set(0.0) b = dolfinx.fem.assemble_vector(b, L) b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) assert isinstance(b, PETSc.Vec) assert normb == pytest.approx(b.norm()) # Vector re-assembly - no zeroing (but need to zero ghost entries) with b.localForm() as b_local: b_local.array[b.local_size:] = 0.0 dolfinx.fem.assemble_vector(b, L) b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) assert 2.0 * normb == pytest.approx(b.norm()) # Matrix re-assembly (no zeroing) dolfinx.fem.assemble_matrix(A, a) A.assemble() assert 2.0 * normA == pytest.approx(A.norm())
def test_assemble_manifold(): """Test assembly of poisson problem on a mesh with topological dimension 1 but embedded in 2D (gdim=2). """ points = numpy.array([[0.0, 0.0], [0.2, 0.0], [0.4, 0.0], [0.6, 0.0], [0.8, 0.0], [1.0, 0.0]], dtype=numpy.float64) cells = numpy.array([[0, 1], [1, 2], [2, 3], [3, 4], [4, 5]], dtype=numpy.int32) mesh = dolfinx.Mesh(dolfinx.MPI.comm_world, dolfinx.cpp.mesh.CellType.interval, points, cells, [], dolfinx.cpp.mesh.GhostMode.none) mesh.geometry.coord_mapping = dolfinx.fem.create_coordinate_map(mesh) assert mesh.geometry.dim == 2 assert mesh.topology.dim == 1 U = dolfinx.FunctionSpace(mesh, ("P", 1)) u, v = ufl.TrialFunction(U), ufl.TestFunction(U) w = dolfinx.Function(U) a = ufl.inner(ufl.grad(u), ufl.grad(v)) * ufl.dx(mesh) L = ufl.inner(1.0, v) * ufl.dx(mesh) bcdofs = dolfinx.fem.locate_dofs_geometrical( U, lambda x: numpy.isclose(x[0], 0.0)) bcs = [dolfinx.DirichletBC(w, bcdofs)] A = dolfinx.fem.assemble_matrix(a, bcs) A.assemble() b = dolfinx.fem.assemble_vector(L) dolfinx.fem.apply_lifting(b, [a], [bcs]) dolfinx.fem.set_bc(b, bcs) assert numpy.isclose(b.norm(), 0.41231) assert numpy.isclose(A.norm(), 25.0199)
def test_monolithic(V1, V2, squaremesh_5): mesh = squaremesh_5 Wel = ufl.MixedElement([V1.ufl_element(), V2.ufl_element()]) W = dolfinx.FunctionSpace(mesh, Wel) u = dolfinx.Function(W) u0, u1 = ufl.split(u) v = ufl.TestFunction(W) v0, v1 = ufl.split(v) Phi = (ufl.sin(u0) - 0.5)**2 * ufl.dx(mesh) + (4.0 * u0 - u1)**2 * ufl.dx(mesh) F = ufl.derivative(Phi, u, v) opts = PETSc.Options("monolithic") opts.setValue('snes_type', 'newtonls') opts.setValue('snes_linesearch_type', 'basic') opts.setValue('snes_rtol', 1.0e-10) opts.setValue('snes_max_it', 20) opts.setValue('ksp_type', 'preonly') opts.setValue('pc_type', 'lu') opts.setValue('pc_factor_mat_solver_type', 'mumps') problem = dolfiny.snesblockproblem.SNESBlockProblem([F], [u], prefix="monolithic") sol, = problem.solve() u0, u1 = sol.split() u0 = u0.collapse() u1 = u1.collapse() assert np.isclose((u0.vector - np.arcsin(0.5)).norm(), 0.0) assert np.isclose((u1.vector - 4.0 * np.arcsin(0.5)).norm(), 0.0)
return numpy.isclose(x[0], 48.0) def left(x): """Marks left part of boundary, where cantilever is attached to wall""" return numpy.isclose(x[0], 0.0) # Locate all facets at the free end and assign them value 1 free_end_facets = locate_entities_boundary(mesh, 1, free_end) mt = dolfinx.mesh.MeshTags(mesh, 1, free_end_facets, 1) ds = ufl.Measure("ds", subdomain_data=mt) # Homogeneous boundary condition in displacement u_bc = dolfinx.Function(U) with u_bc.vector.localForm() as loc: loc.set(0.0) # Displacement BC is applied to the left side left_facets = locate_entities_boundary(mesh, 1, left) bdofs = locate_dofs_topological(U, 1, left_facets) bc = dolfinx.fem.DirichletBC(u_bc, bdofs) # Elastic stiffness tensor and Poisson ratio E, nu = 1.0, 1.0 / 3.0 def sigma_u(u): """Consitutive relation for stress-strain. Assuming plane-stress in XY""" eps = 0.5 * (ufl.grad(u) + ufl.grad(u).T)
# Plotting a 3D dolfinx.Function with pyvista # =========================================== # Interpolate a simple scalar function in 3D def int_u(x): return x[0] + 3 * x[1] + 5 * x[2] mesh = dolfinx.UnitCubeMesh(MPI.COMM_WORLD, 4, 3, 5, cell_type=dolfinx.cpp.mesh.CellType.tetrahedron) V = dolfinx.FunctionSpace(mesh, ("CG", 1)) u = dolfinx.Function(V) u.interpolate(int_u) # Extract mesh data from dolfin-X (only plot cells owned by the # processor) and create a pyvista UnstructuredGrid num_cells = mesh.topology.index_map(mesh.topology.dim).size_local cell_entities = np.arange(num_cells, dtype=np.int32) pyvista_cells, cell_types = dolfinx.plot.create_vtk_topology( mesh, mesh.topology.dim, cell_entities) grid = pyvista.UnstructuredGrid(pyvista_cells, cell_types, mesh.geometry.x) # Compute the function values at the vertices, this is equivalent to a # P1 Lagrange interpolation, and can be directly attached to the Pyvista # mesh. Discard complex value if running dolfin-X with complex PETSc as # backend vertex_values = u.compute_point_values()
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_assembly_ds_domains(mesh): V = dolfinx.FunctionSpace(mesh, ("CG", 1)) u, v = ufl.TrialFunction(V), ufl.TestFunction(V) 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) bottom_facets = locate_entities_geometrical(mesh, mesh.topology.dim - 1, bottom, boundary_only=True) bottom_vals = numpy.full(bottom_facets.shape, 1, numpy.intc) top_facets = locate_entities_geometrical(mesh, mesh.topology.dim - 1, top, boundary_only=True) top_vals = numpy.full(top_facets.shape, 2, numpy.intc) left_facets = locate_entities_geometrical(mesh, mesh.topology.dim - 1, left, boundary_only=True) left_vals = numpy.full(left_facets.shape, 3, numpy.intc) right_facets = locate_entities_geometrical(mesh, mesh.topology.dim - 1, right, boundary_only=True) right_vals = numpy.full(right_facets.shape, 6, numpy.intc) indices = numpy.hstack( (bottom_facets, top_facets, left_facets, right_facets)) values = numpy.hstack((bottom_vals, top_vals, left_vals, right_vals)) indices, pos = numpy.unique(indices, return_index=True) marker = dolfinx.mesh.MeshTags(mesh, mesh.topology.dim - 1, indices, values[pos]) 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(1) + ds(2) + ds(3) + ds(6)) 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(1) + ds(2) + ds(3) + ds(6)) 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(1) + ds(2) + ds(3) + ds(6)) s = dolfinx.fem.assemble_scalar(L) s = mesh.mpi_comm().allreduce(s, op=MPI.SUM) L2 = w * ds s2 = dolfinx.fem.assemble_scalar(L2) s2 = mesh.mpi_comm().allreduce(s2, op=MPI.SUM) 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.""" P2 = fem.VectorFunctionSpace(mesh, ("Lagrange", 2)) P1 = fem.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) # Locate facets on boundaries facetdim = mesh.topology.dim - 1 bndry_facets0 = dolfinx.mesh.locate_entities_boundary( mesh, facetdim, boundary0) bndry_facets1 = dolfinx.mesh.locate_entities_boundary( mesh, facetdim, boundary1) 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 def nested_solve(): """Nested solver""" A = dolfinx.fem.assemble_matrix_nest([[a00, a01], [a10, a11]], [bc0, bc1], [["baij", "aij"], ["aij", ""]]) A.assemble() P = dolfinx.fem.assemble_matrix_nest([[p00, p01], [p10, p11]], [bc0, bc1], [["aij", "aij"], ["aij", ""]]) P.assemble() b = dolfinx.fem.assemble_vector_nest([L0, L1]) dolfinx.fem.apply_lifting_nest(b, [[a00, a01], [a10, a11]], [bc0, bc1]) for b_sub in b.getNestSubVecs(): b_sub.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) bcs = dolfinx.cpp.fem.bcs_rows( dolfinx.fem.assemble._create_cpp_form([L0, L1]), [bc0, bc1]) dolfinx.fem.set_bc_nest(b, bcs) b.assemble() ksp = PETSc.KSP() ksp.create(mesh.mpi_comm()) ksp.setOperators(A, P) nested_IS = P.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_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() x = b.copy() ksp.solve(b, x) assert ksp.getConvergedReason() > 0 return b.norm(), x.norm(), nest_matrix_norm(A), nest_matrix_norm(P) def blocked_solve(): """Blocked (monolithic) solver""" A = dolfinx.fem.assemble_matrix_block([[a00, a01], [a10, a11]], [bc0, bc1]) A.assemble() P = dolfinx.fem.assemble_matrix_block([[p00, p01], [p10, p11]], [bc0, bc1]) P.assemble() b = dolfinx.fem.assemble_vector_block([L0, L1], [[a00, a01], [a10, a11]], [bc0, bc1]) ksp = PETSc.KSP() ksp.create(mesh.mpi_comm()) ksp.setOperators(A, P) ksp.setType("minres") pc = ksp.getPC() pc.setType('lu') ksp.setTolerances(rtol=1.0e-8, max_it=50) ksp.setFromOptions() x = A.createVecRight() ksp.solve(b, x) assert ksp.getConvergedReason() > 0 return b.norm(), x.norm(), A.norm(), P.norm() def monolithic_solve(): """Monolithic (interleaved) solver""" 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)) A = dolfinx.fem.assemble_matrix(a, [bc0, bc1]) A.assemble() P = dolfinx.fem.assemble_matrix(p_form, [bc0, bc1]) P.assemble() b = dolfinx.fem.assemble_vector(L) dolfinx.fem.apply_lifting(b, [a], [[bc0, bc1]]) b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) dolfinx.fem.set_bc(b, [bc0, bc1]) ksp = PETSc.KSP() ksp.create(mesh.mpi_comm()) ksp.setOperators(A, P) ksp.setType("minres") pc = ksp.getPC() pc.setType('lu') 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() x = A.createVecRight() ksp.solve(b, x) assert ksp.getConvergedReason() > 0 return b.norm(), x.norm(), A.norm(), P.norm() bnorm0, xnorm0, Anorm0, Pnorm0 = nested_solve() bnorm1, xnorm1, Anorm1, Pnorm1 = blocked_solve() bnorm2, xnorm2, Anorm2, Pnorm2 = monolithic_solve() assert bnorm1 == pytest.approx(bnorm0, 1.0e-12) assert xnorm1 == pytest.approx(xnorm0, 1.0e-8) assert Anorm1 == pytest.approx(Anorm0, 1.0e-12) assert Pnorm1 == pytest.approx(Pnorm0, 1.0e-12) assert bnorm2 == pytest.approx(bnorm0, 1.0e-12) assert xnorm2 == pytest.approx(xnorm0, 1.0e-8) assert Anorm2 == pytest.approx(Anorm0, 1.0e-12) assert Pnorm2 == pytest.approx(Pnorm0, 1.0e-12)
def test_assembly_solve_block(mode): """Solve a two-field mass-matrix like problem with block matrix approaches and test that solution is the same. """ mesh = UnitSquareMesh(MPI.COMM_WORLD, 32, 31, ghost_mode=mode) P = ufl.FiniteElement("Lagrange", mesh.ufl_cell(), 1) V0 = dolfinx.fem.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) # Locate facets on boundary facetdim = mesh.topology.dim - 1 bndry_facets = dolfinx.mesh.locate_entities_boundary( mesh, facetdim, boundary) bdofsV0 = dolfinx.fem.locate_dofs_topological(V0, facetdim, bndry_facets) bdofsV1 = dolfinx.fem.locate_dofs_topological(V1, facetdim, bndry_facets) u_bc0 = dolfinx.fem.Function(V0) u_bc0.vector.set(50.0) u_bc0.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) u_bc1 = dolfinx.fem.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, diagonal=1.0) 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.fem.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.fem.Function(V0) u0_bc.vector.set(50.0) u0_bc.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) u1_bc = dolfinx.fem.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(mode): """Test assembly of block matrices and vectors into (a) monolithic blocked structures, PETSc Nest structures, and monolithic structures. """ mesh = UnitSquareMesh(MPI.COMM_WORLD, 4, 8, ghost_mode=mode) p0, p1 = 1, 2 P0 = ufl.FiniteElement("Lagrange", mesh.ufl_cell(), p0) P1 = ufl.FiniteElement("Lagrange", mesh.ufl_cell(), p1) V0 = dolfinx.fem.FunctionSpace(mesh, P0) V1 = dolfinx.fem.FunctionSpace(mesh, P1) def boundary(x): return numpy.logical_or(x[0] < 1.0e-6, x[0] > 1.0 - 1.0e-6) # Locate facets on boundary facetdim = mesh.topology.dim - 1 bndry_facets = dolfinx.mesh.locate_entities_boundary( mesh, facetdim, boundary) bdofsV1 = dolfinx.fem.locate_dofs_topological(V1, facetdim, bndry_facets) u_bc = dolfinx.fem.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], [["baij", "aij"], ["aij", ""]]) 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.fem.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)
def test_custom_mesh_loop_rank1(): # Create mesh and function space mesh = dolfinx.generation.UnitSquareMesh(MPI.COMM_WORLD, 64, 64) V = dolfinx.FunctionSpace(mesh, ("Lagrange", 1)) # Unpack mesh and dofmap data num_owned_cells = mesh.topology.index_map(mesh.topology.dim).size_local num_cells = num_owned_cells + mesh.topology.index_map(mesh.topology.dim).num_ghosts x_dofs = mesh.geometry.dofmap.array.reshape(num_cells, 3) x = mesh.geometry.x dofmap = V.dofmap.list.array.reshape(num_cells, 3) dofmap_t = dolfinx.cpp.fem.transpose_dofmap(V.dofmap.list, num_owned_cells) # Assemble with pure Numba function (two passes, first will include # JIT overhead) b0 = dolfinx.Function(V) for i in range(2): with b0.vector.localForm() as b: b.set(0.0) start = time.time() assemble_vector(np.asarray(b), (x_dofs, x), dofmap, num_owned_cells) end = time.time() print("Time (numba, pass {}): {}".format(i, end - start)) b0.vector.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) assert b0.vector.sum() == pytest.approx(1.0) # Assemble with pure Numba function using parallel loop (two passes, # first will include JIT overhead) btmp = dolfinx.Function(V) for i in range(2): with btmp.vector.localForm() as b: b.set(0.0) start = time.time() assemble_vector_parallel(np.asarray(b), x_dofs, x, dofmap_t.array, dofmap_t.offsets, num_owned_cells) end = time.time() print("Time (numba parallel, pass {}): {}".format(i, end - start)) btmp.vector.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) assert (btmp.vector - b0.vector).norm() == pytest.approx(0.0) # Test against generated code and general assembler v = ufl.TestFunction(V) L = inner(1.0, v) * dx start = time.time() b1 = dolfinx.fem.assemble_vector(L) end = time.time() print("Time (C++, pass 0):", end - start) with b1.localForm() as b_local: b_local.set(0.0) start = time.time() dolfinx.fem.assemble_vector(b1, L) end = time.time() print("Time (C++, pass 1):", end - start) b1.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) assert (b1 - b0.vector).norm() == pytest.approx(0.0) # Assemble using generated tabulate_tensor kernel and Numba assembler b3 = dolfinx.Function(V) ufc_form, module, code = dolfinx.jit.ffcx_jit(mesh.mpi_comm(), L) # First 0 for "cell" integrals, second 0 for the first one, i.e. default domain kernel = ufc_form.integrals(0)[0].tabulate_tensor for i in range(2): with b3.vector.localForm() as b: b.set(0.0) start = time.time() assemble_vector_ufc(np.asarray(b), kernel, (x_dofs, x), dofmap, num_owned_cells) end = time.time() print("Time (numba/cffi, pass {}): {}".format(i, end - start)) b3.vector.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) assert (b3.vector - b0.vector).norm() == pytest.approx(0.0)