def test_basic_interior_facet_assembly(): mesh = dolfinx.RectangleMesh(MPI.COMM_WORLD, [numpy.array([0.0, 0.0, 0.0]), numpy.array([1.0, 1.0, 0.0])], [5, 5], cell_type=dolfinx.cpp.mesh.CellType.triangle, ghost_mode=dolfinx.cpp.mesh.GhostMode.shared_facet) V = function.FunctionSpace(mesh, ("DG", 1)) u, v = ufl.TrialFunction(V), ufl.TestFunction(V) a = ufl.inner(ufl.avg(u), ufl.avg(v)) * ufl.dS A = dolfinx.fem.assemble_matrix(a) A.assemble() assert isinstance(A, PETSc.Mat) L = ufl.conj(ufl.avg(v)) * ufl.dS b = dolfinx.fem.assemble_vector(L) b.assemble() assert isinstance(b, PETSc.Vec)
def test_mass_bilinear_form_2d(mode, expected_result, compile_args): cell = ufl.triangle element = ufl.FiniteElement("Lagrange", cell, 1) u, v = ufl.TrialFunction(element), ufl.TestFunction(element) a = ufl.inner(u, v) * ufl.dx L = ufl.conj(v) * ufl.dx forms = [a, L] compiled_forms, module = ffcx.codegeneration.jit.compile_forms( forms, parameters={'scalar_type': mode}, cffi_extra_compile_args=compile_args) for f, compiled_f in zip(forms, compiled_forms): assert compiled_f.rank == len(f.arguments()) form0 = compiled_forms[0][0].create_cell_integral(-1) form1 = compiled_forms[1][0].create_cell_integral(-1) c_type, np_type = float_to_type(mode) A = np.zeros((3, 3), dtype=np_type) w = np.array([], dtype=np_type) c = np.array([], dtype=np_type) ffi = cffi.FFI() coords = np.array([0.0, 0.0, 1.0, 0.0, 0.0, 1.0], dtype=np.float64) form0.tabulate_tensor( ffi.cast('{type} *'.format(type=c_type), A.ctypes.data), ffi.cast('{type} *'.format(type=c_type), w.ctypes.data), ffi.cast('{type} *'.format(type=c_type), c.ctypes.data), ffi.cast('double *', coords.ctypes.data), ffi.NULL, ffi.NULL, 0) b = np.zeros(3, dtype=np_type) form1.tabulate_tensor( ffi.cast('{type} *'.format(type=c_type), b.ctypes.data), ffi.cast('{type} *'.format(type=c_type), w.ctypes.data), ffi.cast('{type} *'.format(type=c_type), c.ctypes.data), ffi.cast('double *', coords.ctypes.data), ffi.NULL, ffi.NULL, 0) assert np.allclose(A, expected_result) assert np.allclose(b, 1.0 / 6.0)
def test_custom_mesh_loop_ctypes_rank2(): """Test numba assembler for bilinear form""" # Create mesh and function space mesh = dolfinx.generation.UnitSquareMesh(MPI.COMM_WORLD, 64, 64) V = dolfinx.FunctionSpace(mesh, ("Lagrange", 1)) # Extract 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).astype(np.dtype(PETSc.IntType)) # Generated case with general assembler u, v = ufl.TrialFunction(V), ufl.TestFunction(V) a = inner(u, v) * dx A0 = dolfinx.fem.assemble_matrix(a) A0.assemble() A0.zeroEntries() start = time.time() dolfinx.fem.assemble_matrix(A0, a) end = time.time() print("Time (C++, pass 2):", end - start) A0.assemble() # Custom case A1 = A0.copy() for i in range(2): A1.zeroEntries() mat = A1.handle start = time.time() assemble_matrix_ctypes(mat, (x_dofs, x), dofmap, num_owned_cells, MatSetValues_ctypes, PETSc.InsertMode.ADD_VALUES) end = time.time() print("Time (numba, pass {}): {}".format(i, end - start)) A1.assemble() assert (A0 - A1).norm() == pytest.approx(0.0, abs=1.0e-9)
def test_custom_quadrature(compile_args): ve = ufl.VectorElement("P", "triangle", 1) mesh = ufl.Mesh(ve) e = ufl.FiniteElement("P", mesh.ufl_cell(), 2) V = ufl.FunctionSpace(mesh, e) u, v = ufl.TrialFunction(V), ufl.TestFunction(V) points = [[0.0, 0.0], [1.0, 0.0], [0.0, 1.0], [0.5, 0.5], [0.0, 0.5], [0.5, 0.0]] weights = [1 / 12] * 6 a = u * v * ufl.dx( metadata={ "quadrature_rule": "custom", "quadrature_points": points, "quadrature_weights": weights }) forms = [a] compiled_forms, module, code = ffcx.codegeneration.jit.compile_forms( forms, cffi_extra_compile_args=compile_args) ffi = cffi.FFI() form = compiled_forms[0] default_integral = form.integrals(module.lib.cell)[0] A = np.zeros((6, 6), dtype=np.float64) w = np.array([], dtype=np.float64) c = np.array([], dtype=np.float64) coords = np.array([[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]], dtype=np.float64) default_integral.tabulate_tensor(ffi.cast("double *", A.ctypes.data), ffi.cast("double *", w.ctypes.data), ffi.cast("double *", c.ctypes.data), ffi.cast("double *", coords.ctypes.data), ffi.NULL, ffi.NULL) # Check that A is diagonal assert np.count_nonzero(A - np.diag(np.diagonal(A))) == 0
def test_additive_facet_integral(mode): cell = ufl.triangle element = ufl.FiniteElement("Lagrange", cell, 1) u, v = ufl.TrialFunction(element), ufl.TestFunction(element) a = ufl.inner(u, v) * ufl.ds forms = [a] compiled_forms, module = ffc.codegeneration.jit.compile_forms(forms, parameters={'scalar_type': mode}) for f, compiled_f in zip(forms, compiled_forms): assert compiled_f.rank == len(f.arguments()) ffi = cffi.FFI() form0 = compiled_forms[0][0] assert form0.num_exterior_facet_integrals == 1 ids = np.zeros(form0.num_exterior_facet_integrals, dtype=np.int32) form0.get_exterior_facet_integral_ids(ffi.cast('int *', ids.ctypes.data)) assert ids[0] == -1 default_integral = form0.create_exterior_facet_integral(ids[0]) c_type, np_type = float_to_type(mode) A = np.zeros((3, 3), dtype=np_type) w = np.array([], dtype=np_type) c = np.array([], dtype=np_type) facets = np.array([0], dtype=np.int32) coords = np.array([0.0, 2.0, np.sqrt(3.0), -1.0, -np.sqrt(3.0), -1.0], dtype=np.float64) for i in range(3): facets[0] = i default_integral.tabulate_tensor( ffi.cast('{type} *'.format(type=c_type), A.ctypes.data), ffi.cast('{type} *'.format(type=c_type), w.ctypes.data), ffi.cast('{type} *'.format(type=c_type), c.ctypes.data), ffi.cast('double *', coords.ctypes.data), ffi.cast('int *', facets.ctypes.data), ffi.NULL) assert np.isclose(A.sum(), np.sqrt(12) * (i + 1))
def test_interior_facet_integral(mode, compile_args): cell = ufl.triangle element = ufl.FiniteElement("Lagrange", cell, 1) u, v = ufl.TrialFunction(element), ufl.TestFunction(element) a0 = ufl.inner(ufl.jump(ufl.grad(u)), ufl.jump(ufl.grad(v))) * ufl.dS forms = [a0] compiled_forms, module, code = ffcx.codegeneration.jit.compile_forms( forms, parameters={'scalar_type': mode}, cffi_extra_compile_args=compile_args) for f, compiled_f in zip(forms, compiled_forms): assert compiled_f.rank == len(f.arguments()) ffi = cffi.FFI() form0 = compiled_forms[0] ffi = cffi.FFI() c_type, np_type = float_to_type(mode) integral0 = form0.integrals(module.lib.interior_facet)[0] A = np.zeros((6, 6), dtype=np_type) w = np.array([], dtype=np_type) c = np.array([], dtype=np.float64) facets = np.array([0, 2], dtype=np.intc) perms = np.array([0, 1], dtype=np.uint8) coords = np.array([[0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0], [1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0]], dtype=np.float64) integral0.tabulate_tensor(ffi.cast('{} *'.format(c_type), A.ctypes.data), ffi.cast('{} *'.format(c_type), w.ctypes.data), ffi.cast('{} *'.format(c_type), c.ctypes.data), ffi.cast('double *', coords.ctypes.data), ffi.cast('int *', facets.ctypes.data), ffi.cast('uint8_t *', perms.ctypes.data))
def __init__(self, F: ufl.form.Form, u: Function, bcs: typing.List[DirichletBCMetaClass] = [], J: ufl.form.Form = None, form_compiler_parameters={}, jit_parameters={}): """Initialize class that sets up structures for solving the non-linear problem using Newton's method, dF/du(u) du = -F(u) Parameters ---------- F The PDE residual F(u, v) u The unknown bcs List of Dirichlet boundary conditions J UFL representation of the Jacobian (Optional) form_compiler_parameters Parameters used in FFCx compilation of this form. Run `ffcx --help` at the commandline to see all available options. Takes priority over all other parameter values, except for `scalar_type` which is determined by DOLFINx. jit_parameters Parameters used in CFFI JIT compilation of C code generated by FFCx. See `python/dolfinx/jit.py` for all available parameters. Takes priority over all other parameter values. .. code-block:: python problem = LinearProblem(F, u, [bc0, bc1]) """ self._L = create_form(F, form_compiler_parameters=form_compiler_parameters, jit_parameters=jit_parameters) # Create the Jacobian matrix, dF/du if J is None: V = u.function_space du = ufl.TrialFunction(V) J = ufl.derivative(F, u, du) self._a = create_form(J, form_compiler_parameters=form_compiler_parameters, jit_parameters=jit_parameters) self.bcs = bcs
def test_slave_on_same_cell(master_point, degree, celltype, get_assemblers): # noqa: F811 assemble_matrix, _ = get_assemblers # Create mesh and function space mesh = create_unit_square(MPI.COMM_WORLD, 1, 8, celltype) V = fem.FunctionSpace(mesh, ("Lagrange", degree)) # Build master slave map s_m_c = { np.array([1, 0], dtype=np.float64).tobytes(): { np.array([0, 1], dtype=np.float64).tobytes(): 0.43, np.array([1, 1], dtype=np.float64).tobytes(): 0.11 }, np.array([0, 0], dtype=np.float64).tobytes(): { np.array(master_point, dtype=np.float64).tobytes(): 0.69 } } with Timer("~TEST: MPC INIT"): mpc = dolfinx_mpc.MultiPointConstraint(V) mpc.create_general_constraint(s_m_c) mpc.finalize() # Test against generated code and general assembler u = ufl.TrialFunction(V) v = ufl.TestFunction(V) a = ufl.inner(ufl.grad(u), ufl.grad(v)) * ufl.dx bilinear_form = fem.form(a) with Timer("~TEST: Assemble matrix"): A_mpc = assemble_matrix(bilinear_form, mpc) with Timer("~TEST: Compare with numpy"): # Create globally reduced system A_org = fem.petsc.assemble_matrix(bilinear_form) A_org.assemble() dolfinx_mpc.utils.compare_mpc_lhs(A_org, A_mpc, mpc) list_timings(mesh.comm, [TimingType.wall])
def test_custom_mesh_loop_ctypes_rank2(): """Test numba assembler for bilinear form""" # Create mesh and function space mesh = dolfinx.generation.UnitSquareMesh(dolfinx.MPI.comm_world, 64, 64) V = dolfinx.FunctionSpace(mesh, ("Lagrange", 1)) # Extract mesh and dofmap data c = mesh.topology.connectivity(2, 0).array() pos = mesh.topology.connectivity(2, 0).offsets() geom = mesh.geometry.points dofs = V.dofmap.dof_array # Generated case with general assembler u, v = ufl.TrialFunction(V), ufl.TestFunction(V) a = inner(u, v) * dx A0 = dolfinx.fem.assemble_matrix(a) A0.assemble() A0.zeroEntries() start = time.time() dolfinx.fem.assemble_matrix(A0, a) end = time.time() print("Time (C++, pass 2):", end - start) A0.assemble() # Custom case A1 = A0.copy() for i in range(2): A1.zeroEntries() mat = A1.handle start = time.time() assemble_matrix_ctypes(mat, (c, pos), geom, dofs, MatSetValues_ctypes, PETSc.InsertMode.ADD_VALUES) end = time.time() print("Time (numba, pass {}): {}".format(i, end - start)) A1.assemble() assert (A0 - A1).norm() == pytest.approx(0.0, abs=1.0e-9)
def test_laplace_bilinear_form_2d(mode, expected_result): cell = ufl.triangle element = ufl.FiniteElement("Lagrange", cell, 1) kappa = ufl.Constant(cell, shape=(2, 2)) u, v = ufl.TrialFunction(element), ufl.TestFunction(element) a = ufl.tr(kappa) * ufl.inner(ufl.grad(u), ufl.grad(v)) * ufl.dx forms = [a] compiled_forms, module = ffc.codegeneration.jit.compile_forms( forms, parameters={'scalar_type': mode}) for f, compiled_f in zip(forms, compiled_forms): assert compiled_f.rank == len(f.arguments()) ffi = cffi.FFI() form0 = compiled_forms[0][0] assert form0.num_cell_integrals == 1 ids = np.zeros(form0.num_cell_integrals, dtype=np.int32) form0.get_cell_integral_ids(ffi.cast('int *', ids.ctypes.data)) assert ids[0] == -1 default_integral = form0.create_cell_integral(ids[0]) c_type, np_type = float_to_type(mode) A = np.zeros((3, 3), dtype=np_type) w = np.array([], dtype=np_type) kappa_value = np.array([[1.0, 2.0], [3.0, 4.0]]) c = np.array(kappa_value.flatten(), dtype=np_type) coords = np.array([0.0, 0.0, 1.0, 0.0, 0.0, 1.0], dtype=np.float64) default_integral.tabulate_tensor( ffi.cast('{type} *'.format(type=c_type), A.ctypes.data), ffi.cast('{type} *'.format(type=c_type), w.ctypes.data), ffi.cast('{type} *'.format(type=c_type), c.ctypes.data), ffi.cast('double *', coords.ctypes.data), ffi.NULL, ffi.NULL) assert np.allclose(A, np.trace(kappa_value) * expected_result)
def test_cache_modes(): cell = ufl.triangle element = ufl.FiniteElement("Lagrange", cell, 1) u, v = ufl.TrialFunction(element), ufl.TestFunction(element) a = ufl.inner(ufl.grad(u), ufl.grad(v)) * ufl.dx forms = [a] # Load form from /tmp compiled_forms, module = ffc.codegeneration.jit.compile_forms(forms, parameters={'use_cache': False}) tmpname = module.__name__ tmpfile = module.__file__ print(tmpname, tmpfile) del sys.modules[tmpname] # Load form from cache compiled_forms, module = ffc.codegeneration.jit.compile_forms(forms, parameters={'use_cache': True}) newname = module.__name__ newfile = module.__file__ print(newname, newfile) assert(newname == tmpname) assert(newfile != tmpfile)
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_custom_mesh_loop_cffi_rank2(set_vals): """Test numba assembler for bilinear form""" mesh = dolfinx.generation.UnitSquareMesh(MPI.COMM_WORLD, 64, 64) V = dolfinx.FunctionSpace(mesh, ("Lagrange", 1)) # Test against generated code and general assembler u, v = ufl.TrialFunction(V), ufl.TestFunction(V) a = inner(u, v) * dx A0 = dolfinx.fem.assemble_matrix(a) A0.assemble() A0.zeroEntries() start = time.time() dolfinx.fem.assemble_matrix(A0, a) end = time.time() print("Time (C++, pass 2):", end - start) A0.assemble() # 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).astype(np.dtype(PETSc.IntType)) A1 = A0.copy() for i in range(2): A1.zeroEntries() start = time.time() assemble_matrix_cffi(A1.handle, (x_dofs, x), dofmap, num_owned_cells, set_vals, PETSc.InsertMode.ADD_VALUES) end = time.time() print("Time (Numba, pass {}): {}".format(i, end - start)) A1.assemble() assert (A1 - A0).norm() == pytest.approx(0.0)
def test_subdomains(): cell = ufl.triangle element = ufl.FiniteElement("Lagrange", cell, 1) u, v = ufl.TrialFunction(element), ufl.TestFunction(element) a0 = ufl.inner(u, v) * ufl.dx + ufl.inner(u, v) * ufl.dx(2) a1 = ufl.inner(u, v) * ufl.dx(2) + ufl.inner(u, v) * ufl.dx a2 = ufl.inner(u, v) * ufl.dx(2) + ufl.inner(u, v) * ufl.dx(1) a3 = ufl.inner(u, v) * ufl.ds(210) + ufl.inner(u, v) * ufl.ds(0) forms = [a0, a1, a2, a3] compiled_forms, module = ffc.codegeneration.jit.compile_forms( forms, parameters={'scalar_type': 'double'}) for f, compiled_f in zip(forms, compiled_forms): assert compiled_f.rank == len(f.arguments()) ffi = cffi.FFI() form0 = compiled_forms[0][0] ids = np.zeros(form0.num_cell_integrals, dtype=np.int32) form0.get_cell_integral_ids(ffi.cast('int *', ids.ctypes.data)) assert ids[0] == -1 and ids[1] == 2 form1 = compiled_forms[1][0] ids = np.zeros(form1.num_cell_integrals, dtype=np.int32) form1.get_cell_integral_ids(ffi.cast('int *', ids.ctypes.data)) assert ids[0] == -1 and ids[1] == 2 form2 = compiled_forms[2][0] ids = np.zeros(form2.num_cell_integrals, dtype=np.int32) form2.get_cell_integral_ids(ffi.cast('int *', ids.ctypes.data)) assert ids[0] == 1 and ids[1] == 2 form3 = compiled_forms[3][0] ids = np.zeros(form3.num_cell_integrals, dtype=np.int32) form3.get_cell_integral_ids(ffi.cast('int *', ids.ctypes.data)) assert len(ids) == 0 ids = np.zeros(form3.num_exterior_facet_integrals, dtype=np.int32) form3.get_exterior_facet_integral_ids(ffi.cast('int *', ids.ctypes.data)) assert ids[0] == 0 and ids[1] == 210
def test_assembly_bcs(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) a = inner(u, v) * dx + inner(u, v) * ds L = inner(1.0, v) * dx def boundary(x): return numpy.logical_or(x[0] < 1.0e-6, x[0] > 1.0 - 1.0e-6) bdofsV = dolfinx.fem.locate_dofs_geometrical(V, boundary) u_bc = dolfinx.fem.Function(V) with u_bc.vector.localForm() as u_local: u_local.set(1.0) bc = dolfinx.fem.dirichletbc.DirichletBC(u_bc, bdofsV) # Assemble and apply 'global' lifting of bcs A = dolfinx.fem.assemble_matrix(a) A.assemble() b = dolfinx.fem.assemble_vector(L) b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) g = b.duplicate() with g.localForm() as g_local: g_local.set(0.0) dolfinx.fem.set_bc(g, [bc]) f = b - A * g dolfinx.fem.set_bc(f, [bc]) # Assemble vector and apply lifting of bcs during assembly b = dolfinx.fem.assemble_vector(L) b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) b_bc = dolfinx.fem.assemble_vector(L) dolfinx.fem.apply_lifting(b_bc, [a], [[bc]]) b_bc.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) dolfinx.fem.set_bc(b_bc, [bc]) assert (f - b_bc).norm() == pytest.approx(0.0, rel=1e-12, abs=1e-12)
def test_helmholtz_form_2d(mode, expected_result, compile_args): cell = ufl.triangle element = ufl.FiniteElement("Lagrange", cell, 1) u, v = ufl.TrialFunction(element), ufl.TestFunction(element) if mode == "double": k = 1.0 elif mode == "double complex": k = ufl.constantvalue.ComplexValue(1j) else: raise RuntimeError("Unknown mode type") a = (ufl.inner(ufl.grad(u), ufl.grad(v)) - ufl.inner(k * u, v)) * ufl.dx forms = [a] compiled_forms, module, code = ffcx.codegeneration.jit.compile_forms( forms, parameters={'scalar_type': mode}, cffi_extra_compile_args=compile_args) for f, compiled_f in zip(forms, compiled_forms): assert compiled_f.rank == len(f.arguments()) form0 = compiled_forms[0].integrals(module.lib.cell)[0] c_type, np_type = float_to_type(mode) A = np.zeros((3, 3), dtype=np_type) w = np.array([], dtype=np_type) c = np.array([], dtype=np_type) ffi = cffi.FFI() coords = np.array([[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]], dtype=np.float64) form0.tabulate_tensor( ffi.cast('{type} *'.format(type=c_type), A.ctypes.data), ffi.cast('{type} *'.format(type=c_type), w.ctypes.data), ffi.cast('{type} *'.format(type=c_type), c.ctypes.data), ffi.cast('double *', coords.ctypes.data), ffi.NULL, ffi.NULL) assert np.allclose(A, expected_result)
def project(v, target_func, degree, bcs=[]): # Ensure we have a mesh and attach to measure V = target_func.function_space dx = ufl.dx(V.mesh, degree=degree) # Define variational problem for projection w = ufl.TestFunction(V) Pv = ufl.TrialFunction(V) a = fem.form(ufl.inner(Pv, w) * dx) L = fem.form(ufl.inner(v, w) * dx) # Assemble linear system A = fem.assemble_matrix(a, bcs) A.assemble() b = fem.assemble_vector(L) fem.apply_lifting(b, [a], [bcs]) b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) fem.set_bc(b, bcs) # Solve linear system solver = PETSc.KSP().create(A.getComm()) solver.setOperators(A) solver.solve(b, target_func.vector)
def test_eigen_assembly(mode): """Compare assembly into scipy.CSR matrix with PETSc assembly""" mesh = UnitSquareMesh(MPI.COMM_WORLD, 12, 12, ghost_mode=mode) Q = dolfinx.FunctionSpace(mesh, ("Lagrange", 1)) u = ufl.TrialFunction(Q) v = ufl.TestFunction(Q) a = ufl.inner(ufl.grad(u), ufl.grad(v)) * ufl.dx def boundary(x): return numpy.logical_or(x[0] < 1.0e-6, x[0] > 1.0 - 1.0e-6) bdofsQ = dolfinx.fem.locate_dofs_geometrical(Q, boundary) u_bc = dolfinx.function.Function(Q) with u_bc.vector.localForm() as u_local: u_local.set(1.0) bc = dolfinx.fem.dirichletbc.DirichletBC(u_bc, bdofsQ) A1 = dolfinx.fem.assemble_matrix(a, [bc]) A1.assemble() A2 = dolfinx.fem.assemble_csr_matrix(a, [bc]) assert numpy.isclose(A1.norm(), scipy.sparse.linalg.norm(A2))
def run_vector_test(mesh, V, degree): """Projection into H(div/curl) spaces""" u, v = ufl.TrialFunction(V), ufl.TestFunction(V) a = inner(u, v) * dx # Source term x = SpatialCoordinate(mesh) u_exact = x[0]**degree L = inner(u_exact, v[0]) * dx b = assemble_vector(L) b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) A = assemble_matrix(a) A.assemble() # Create LU linear solver (Note: need to use a solver that # re-orders to handle pivots, e.g. not the PETSc built-in LU solver) solver = PETSc.KSP().create(MPI.COMM_WORLD) solver.setType("preonly") solver.getPC().setType('lu') solver.setOperators(A) # Solve uh = Function(V) solver.solve(b, uh.vector) uh.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) # Calculate error M = (u_exact - uh[0])**2 * dx for i in range(1, mesh.topology.dim): M += uh[i]**2 * dx M = fem.Form(M) error = mesh.mpi_comm().allreduce(assemble_scalar(M), op=MPI.SUM) assert np.absolute(error) < 1.0e-14
def test_mpc_assembly(master_point, degree, celltype, get_assemblers): # noqa: F811 assemble_matrix, _ = get_assemblers # Create mesh and function space mesh = create_unit_square(MPI.COMM_WORLD, 5, 3, celltype) V = fem.FunctionSpace(mesh, ("Lagrange", degree)) # Test against generated code and general assembler u = ufl.TrialFunction(V) v = ufl.TestFunction(V) a = ufl.inner(ufl.grad(u), ufl.grad(v)) * ufl.dx bilinear_form = fem.form(a) def l2b(li): return np.array(li, dtype=np.float64).tobytes() s_m_c = { l2b([1, 0]): { l2b([0, 1]): 0.43, l2b([1, 1]): 0.11 }, l2b([0, 0]): { l2b(master_point): 0.69 } } mpc = dolfinx_mpc.MultiPointConstraint(V) mpc.create_general_constraint(s_m_c) mpc.finalize() with Timer("~TEST: Assemble matrix"): A_mpc = assemble_matrix(bilinear_form, mpc) with Timer("~TEST: Compare with numpy"): # Create globally reduced system A_org = fem.petsc.assemble_matrix(bilinear_form) A_org.assemble() dolfinx_mpc.utils.compare_mpc_lhs(A_org, A_mpc, mpc)
def test_mixed_element(ElementType, space, cell, order): if cell == ufl.triangle: mesh = create_unit_square(MPI.COMM_WORLD, 1, 1, CellType.triangle, GhostMode.shared_facet) else: mesh = create_unit_cube(MPI.COMM_WORLD, 1, 1, 1, CellType.tetrahedron, GhostMode.shared_facet) norms = [] U_el = ufl.FiniteElement(space, cell, order) for i in range(3): U = FunctionSpace(mesh, U_el) u = ufl.TrialFunction(U) v = ufl.TestFunction(U) a = form(ufl.inner(u, v) * ufl.dx) A = dolfinx.fem.petsc.assemble_matrix(a) A.assemble() norms.append(A.norm()) U_el = ufl.MixedElement(U_el) for i in norms[1:]: assert np.isclose(norms[0], i)
def test_custom_mesh_loop_cffi_rank2(set_vals): """Test numba assembler for bilinear form""" mesh = dolfinx.generation.UnitSquareMesh(dolfinx.MPI.comm_world, 64, 64) V = dolfinx.FunctionSpace(mesh, ("Lagrange", 1)) # Test against generated code and general assembler u, v = ufl.TrialFunction(V), ufl.TestFunction(V) a = inner(u, v) * dx A0 = dolfinx.fem.assemble_matrix(a) A0.assemble() A0.zeroEntries() start = time.time() dolfinx.fem.assemble_matrix(A0, a) end = time.time() print("Time (C++, pass 2):", end - start) A0.assemble() # Unpack mesh and dofmap data c = mesh.topology.connectivity(2, 0).array() pos = mesh.topology.connectivity(2, 0).offsets() geom = mesh.geometry.points dofs = V.dofmap.dof_array A1 = A0.copy() for i in range(2): A1.zeroEntries() start = time.time() assemble_matrix_cffi(A1.handle, (c, pos), geom, dofs, set_vals, PETSc.InsertMode.ADD_VALUES) end = time.time() print("Time (Numba, pass {}): {}".format(i, end - start)) A1.assemble() assert (A1 - A0).norm() == pytest.approx(0.0)
encoding=dolfinx.cpp.io.XDMFFile.Encoding.ASCII) mesh = infile.read_mesh(name="Grid") infile.close() # Stress (Se) and displacement (Ue) elements Se = ufl.TensorElement("DG", mesh.ufl_cell(), 1, symmetry=True) Ue = ufl.VectorElement("CG", mesh.ufl_cell(), 2) S = dolfinx.FunctionSpace(mesh, Se) 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) def free_end(x): """Marks the leftmost points of the cantilever""" 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)
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_assembly_solve_taylor_hood_nl(mesh): """Assemble Stokes problem with Taylor-Hood elements and solve.""" gdim = mesh.geometry.dim P2 = VectorFunctionSpace(mesh, ("Lagrange", 2)) P1 = FunctionSpace(mesh, ("Lagrange", 1)) def boundary0(x): """Define boundary x = 0""" return np.isclose(x[0], 0.0) def boundary1(x): """Define boundary x = 1""" return np.isclose(x[0], 1.0) def initial_guess_u(x): u_init = np.row_stack( (np.sin(x[0]) * np.sin(x[1]), np.cos(x[0]) * np.cos(x[1]))) if gdim == 3: u_init = np.row_stack((u_init, np.cos(x[2]))) return u_init def initial_guess_p(x): return -x[0]**2 - x[1]**3 u_bc_0 = Function(P2) u_bc_0.interpolate( lambda x: np.row_stack(tuple(x[j] + float(j) for j in range(gdim)))) u_bc_1 = Function(P2) u_bc_1.interpolate( lambda x: np.row_stack(tuple(np.sin(x[j]) for j in range(gdim)))) facetdim = mesh.topology.dim - 1 bndry_facets0 = locate_entities_boundary(mesh, facetdim, boundary0) bndry_facets1 = locate_entities_boundary(mesh, facetdim, boundary1) bdofs0 = locate_dofs_topological(P2, facetdim, bndry_facets0) bdofs1 = locate_dofs_topological(P2, facetdim, bndry_facets1) bcs = [dirichletbc(u_bc_0, bdofs0), dirichletbc(u_bc_1, bdofs1)] u, p = Function(P2), 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]] F, J, P = form(F), form(J), form(P) # -- Blocked and monolithic Jmat0 = create_matrix_block(J) Pmat0 = create_matrix_block(P) Fvec0 = create_vector_block(F) snes = PETSc.SNES().create(MPI.COMM_WORLD) snes.setTolerances(rtol=1.0e-15, max_it=10) snes.getKSP().setType("minres") snes.getKSP().getPC().setType("lu") 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 = create_vector_block(F) with u.vector.localForm() as _u, p.vector.localForm() as _p: scatter_local_vectors(x0, [_u.array_r, _p.array_r], [(u.function_space.dofmap.index_map, u.function_space.dofmap.index_map_bs), (p.function_space.dofmap.index_map, p.function_space.dofmap.index_map_bs)]) x0.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) snes.solve(None, x0) assert snes.getConvergedReason() > 0 # -- Blocked and nested Jmat1 = create_matrix_nest(J) Pmat1 = create_matrix_nest(P) Fvec1 = create_vector_nest(F) snes = PETSc.SNES().create(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_p.setType("preonly") ksp_p.getPC().setType('lu') 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 = 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 = FunctionSpace(mesh, TH) U = 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 F, J, P = form(F), form(J), form(P) bdofsW0_P2_0 = locate_dofs_topological((W.sub(0), P2), facetdim, bndry_facets0) bdofsW0_P2_1 = locate_dofs_topological((W.sub(0), P2), facetdim, bndry_facets1) bcs = [ dirichletbc(u_bc_0, bdofsW0_P2_0, W.sub(0)), dirichletbc(u_bc_1, bdofsW0_P2_1, W.sub(0)) ] Jmat2 = create_matrix(J) Pmat2 = create_matrix(P) Fvec2 = create_vector(F) snes = PETSc.SNES().create(MPI.COMM_WORLD) snes.setTolerances(rtol=1.0e-15, max_it=10) snes.getKSP().setType("minres") snes.getKSP().getPC().setType("lu") 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.sub(0).interpolate(initial_guess_u) U.sub(1).interpolate(initial_guess_p) x2 = 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_nl(): """Test assembly of block matrices and vectors into (a) monolithic blocked structures, PETSc Nest structures, and monolithic structures in the nonlinear setting """ mesh = create_unit_square(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 = FunctionSpace(mesh, P0) V1 = FunctionSpace(mesh, P1) def initial_guess_u(x): return np.sin(x[0]) * np.sin(x[1]) def initial_guess_p(x): return -x[0]**2 - x[1]**3 def bc_value(x): return np.cos(x[0]) * np.cos(x[1]) facetdim = mesh.topology.dim - 1 bndry_facets = locate_entities_boundary( mesh, facetdim, lambda x: np.logical_or(np.isclose(x[0], 0.0), np.isclose(x[0], 1.0))) u_bc = Function(V1) u_bc.interpolate(bc_value) bdofs = locate_dofs_topological(V1, facetdim, bndry_facets) bc = dirichletbc(u_bc, bdofs) # Define variational problem du, dp = ufl.TrialFunction(V0), ufl.TrialFunction(V1) u, p = Function(V0), 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 = form([[derivative(F0, u, du), derivative(F0, p, dp)], [derivative(F1, u, du), derivative(F1, p, dp)]]) L_block = form([F0, F1]) # Monolithic blocked x0 = create_vector_block(L_block) scatter_local_vectors(x0, [u.vector.array_r, p.vector.array_r], [(u.function_space.dofmap.index_map, u.function_space.dofmap.index_map_bs), (p.function_space.dofmap.index_map, p.function_space.dofmap.index_map_bs)]) x0.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) # Ghosts are updated inside assemble_vector_block A0 = assemble_matrix_block(a_block, bcs=[bc]) b0 = assemble_vector_block(L_block, a_block, bcs=[bc], x0=x0, scale=-1.0) A0.assemble() assert A0.getType() != "nest" Anorm0 = A0.norm() bnorm0 = b0.norm() # Nested (MatNest) x1 = 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 = assemble_matrix_nest(a_block, bcs=[bc]) b1 = assemble_vector_nest(L_block) apply_lifting_nest(b1, a_block, bcs=[bc], x0=x1, scale=-1.0) for b_sub in b1.getNestSubVecs(): b_sub.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) bcs0 = bcs_by_block([L.function_spaces[0] for L in L_block], [bc]) 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 = FunctionSpace(mesh, E) dU = ufl.TrialFunction(W) U = Function(W) u0, u1 = ufl.split(U) v0, v1 = ufl.TestFunctions(W) U.sub(0).interpolate(initial_guess_u) U.sub(1).interpolate(initial_guess_p) 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) F, J = form(F), form(J) bdofsW_V1 = locate_dofs_topological((W.sub(1), V1), facetdim, bndry_facets) bc = dirichletbc(u_bc, bdofsW_V1, W.sub(1)) A2 = assemble_matrix(J, bcs=[bc]) A2.assemble() b2 = assemble_vector(F) apply_lifting(b2, [J], bcs=[[bc]], x0=[U.vector], scale=-1.0) b2.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) 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_nl(): """Solve a two-field nonlinear diffusion like problem with block matrix approaches and test that solution is the same. """ mesh = create_unit_square(MPI.COMM_WORLD, 12, 11) p = 1 P = ufl.FiniteElement("Lagrange", mesh.ufl_cell(), p) V0 = FunctionSpace(mesh, P) V1 = V0.clone() def bc_val_0(x): return x[0]**2 + x[1]**2 def bc_val_1(x): return np.sin(x[0]) * np.cos(x[1]) def initial_guess_u(x): return np.sin(x[0]) * np.sin(x[1]) def initial_guess_p(x): return -x[0]**2 - x[1]**3 facetdim = mesh.topology.dim - 1 bndry_facets = locate_entities_boundary( mesh, facetdim, lambda x: np.logical_or(np.isclose(x[0], 0.0), np.isclose(x[0], 1.0))) u_bc0 = Function(V0) u_bc0.interpolate(bc_val_0) u_bc1 = Function(V1) u_bc1.interpolate(bc_val_1) bdofs0 = locate_dofs_topological(V0, facetdim, bndry_facets) bdofs1 = locate_dofs_topological(V1, facetdim, bndry_facets) bcs = [dirichletbc(u_bc0, bdofs0), dirichletbc(u_bc1, bdofs1)] # Block and Nest variational problem u, p = Function(V0), 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)]] F, J = form(F), form(J) def blocked_solve(): """Blocked version""" Jmat = create_matrix_block(J) Fvec = create_vector_block(F) snes = PETSc.SNES().create(MPI.COMM_WORLD) snes.setTolerances(rtol=1.0e-15, max_it=10) snes.getKSP().setType("preonly") snes.getKSP().getPC().setType("lu") problem = NonlinearPDE_SNESProblem(F, J, [u, p], bcs) snes.setFunction(problem.F_block, Fvec) snes.setJacobian(problem.J_block, J=Jmat, P=None) u.interpolate(initial_guess_u) p.interpolate(initial_guess_p) x = create_vector_block(F) scatter_local_vectors(x, [u.vector.array_r, p.vector.array_r], [(u.function_space.dofmap.index_map, u.function_space.dofmap.index_map_bs), (p.function_space.dofmap.index_map, p.function_space.dofmap.index_map_bs)]) x.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) snes.solve(None, x) assert snes.getKSP().getConvergedReason() > 0 assert snes.getConvergedReason() > 0 return x.norm() def nested_solve(): """Nested version""" Jmat = create_matrix_nest(J) assert Jmat.getType() == "nest" Fvec = create_vector_nest(F) assert Fvec.getType() == "nest" snes = PETSc.SNES().create(MPI.COMM_WORLD) snes.setTolerances(rtol=1.0e-15, max_it=10) nested_IS = Jmat.getNestISs() snes.getKSP().setType("gmres") 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_p.setType("preonly") ksp_p.getPC().setType('lu') problem = NonlinearPDE_SNESProblem(F, J, [u, p], bcs) snes.setFunction(problem.F_nest, Fvec) snes.setJacobian(problem.J_nest, J=Jmat, P=None) u.interpolate(initial_guess_u) p.interpolate(initial_guess_p) x = create_vector_nest(F) assert x.getType() == "nest" for x_soln_pair in zip(x.getNestSubVecs(), (u, p)): x_sub, soln_sub = x_soln_pair soln_sub.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) soln_sub.vector.copy(result=x_sub) x_sub.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) snes.solve(None, x) assert snes.getKSP().getConvergedReason() > 0 assert snes.getConvergedReason() > 0 return x.norm() def monolithic_solve(): """Monolithic version""" E = P * P W = FunctionSpace(mesh, E) U = 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) F, J = form(F), form(J) u0_bc = Function(V0) u0_bc.interpolate(bc_val_0) u1_bc = Function(V1) u1_bc.interpolate(bc_val_1) bdofsW0_V0 = locate_dofs_topological((W.sub(0), V0), facetdim, bndry_facets) bdofsW1_V1 = locate_dofs_topological((W.sub(1), V1), facetdim, bndry_facets) bcs = [ dirichletbc(u0_bc, bdofsW0_V0, W.sub(0)), dirichletbc(u1_bc, bdofsW1_V1, W.sub(1)) ] Jmat = create_matrix(J) Fvec = create_vector(F) snes = PETSc.SNES().create(MPI.COMM_WORLD) snes.setTolerances(rtol=1.0e-15, max_it=10) snes.getKSP().setType("preonly") snes.getKSP().getPC().setType("lu") problem = NonlinearPDE_SNESProblem(F, J, U, bcs) snes.setFunction(problem.F_mono, Fvec) snes.setJacobian(problem.J_mono, J=Jmat, P=None) U.sub(0).interpolate(initial_guess_u) U.sub(1).interpolate(initial_guess_p) x = create_vector(F) x.array = U.vector.array_r snes.solve(None, x) assert snes.getKSP().getConvergedReason() > 0 assert snes.getConvergedReason() > 0 return x.norm() norm0 = blocked_solve() norm1 = nested_solve() norm2 = monolithic_solve() assert norm1 == pytest.approx(norm0, 1.0e-12) assert norm2 == pytest.approx(norm0, 1.0e-12)
import ufl from ufl import grad, div, dot, dx, ds, inner, sin, cos, pi, exp, sqrt import dune.ufl import dune.grid import dune.fem endTime = 0.1 saveInterval = 1 # for VTK gridView = dune.grid.structuredGrid([-1,-1],[1,1],[40,40]) space = dune.fem.space.lagrange(gridView, order=1) u = ufl.TrialFunction(space) phi = ufl.TestFunction(space) x = ufl.SpatialCoordinate(space) dt = dune.ufl.Constant(5e-2, "timeStep") t = dune.ufl.Constant(0.0, "time") # define storage for discrete solutions uh = space.interpolate(0, name="uh") uh_old = uh.copy() # initial solution initial = 0 # problem definition # moving oven ROven = 0.6 omegaOven = 0.01 * pi * t P = ufl.as_vector([ROven*cos(omegaOven*t), ROven*sin(omegaOven*t)])