def test_normals(cube, square): """ Test cell normals for a subset of facets """ def left_side(x): return numpy.isclose(x[0], 0) fdim = cube.topology.dim - 1 facets = locate_entities_boundary(cube, fdim, left_side) normals = cell_normals(cube, fdim, facets) assert (numpy.allclose(normals, [-1, 0, 0])) fdim = square.topology.dim - 1 facets = locate_entities_boundary(square, fdim, left_side) normals = cell_normals(square, fdim, facets) assert (numpy.allclose(normals, [-1, 0, 0]))
def test_mixed_constant_bc(mesh_factory): """Test that setting a dirichletbc with on a component of a mixed function yields the same result as setting it with a function""" func, args = mesh_factory mesh = func(*args) tdim, gdim = mesh.topology.dim, mesh.geometry.dim boundary_facets = locate_entities_boundary( mesh, tdim - 1, lambda x: np.ones(x.shape[1], dtype=bool)) TH = ufl.MixedElement([ ufl.VectorElement("Lagrange", mesh.ufl_cell(), 2), ufl.FiniteElement("Lagrange", mesh.ufl_cell(), 1) ]) W = FunctionSpace(mesh, TH) U = Function(W) # Apply BC to component of a mixed space using a Constant c = Constant(mesh, (PETSc.ScalarType(2), PETSc.ScalarType(2))) dofs0 = locate_dofs_topological(W.sub(0), tdim - 1, boundary_facets) bc0 = dirichletbc(c, dofs0, W.sub(0)) u = U.sub(0) set_bc(u.vector, [bc0]) # Apply BC to component of a mixed space using a Function ubc1 = u.collapse() ubc1.interpolate(lambda x: np.full((gdim, x.shape[1]), 2.0)) dofs1 = locate_dofs_topological((W.sub(0), ubc1.function_space), tdim - 1, boundary_facets) bc1 = dirichletbc(ubc1, dofs1, W.sub(0)) U1 = Function(W) u1 = U1.sub(0) set_bc(u1.vector, [bc1]) # Check that both approaches yield the same vector assert np.allclose(u.x.array, u1.x.array)
def test_sub_constant_bc(mesh_factory): """Test that setting a dirichletbc with on a component of a vector valued function yields the same result as setting it with a function""" func, args = mesh_factory mesh = func(*args) tdim = mesh.topology.dim V = VectorFunctionSpace(mesh, ("Lagrange", 1)) c = Constant(mesh, PETSc.ScalarType(3.14)) boundary_facets = locate_entities_boundary( mesh, tdim - 1, lambda x: np.ones(x.shape[1], dtype=bool)) for i in range(V.num_sub_spaces): Vi = V.sub(i).collapse()[0] u_bci = Function(Vi) u_bci.x.array[:] = PETSc.ScalarType(c.value) boundary_dofsi = locate_dofs_topological((V.sub(i), Vi), tdim - 1, boundary_facets) bc_fi = dirichletbc(u_bci, boundary_dofsi, V.sub(i)) boundary_dofs = locate_dofs_topological(V.sub(i), tdim - 1, boundary_facets) bc_c = dirichletbc(c, boundary_dofs, V.sub(i)) u_f = Function(V) set_bc(u_f.vector, [bc_fi]) u_c = Function(V) set_bc(u_c.vector, [bc_c]) assert np.allclose(u_f.vector.array, u_c.vector.array)
def test_vector_constant_bc(mesh_factory): """Test that setting a dirichletbc with a vector valued constant yields the same result as setting it with a function""" func, args = mesh_factory mesh = func(*args) tdim = mesh.topology.dim V = VectorFunctionSpace(mesh, ("Lagrange", 1)) assert V.num_sub_spaces == mesh.geometry.dim c = np.arange(1, mesh.geometry.dim + 1, dtype=PETSc.ScalarType) boundary_facets = locate_entities_boundary( mesh, tdim - 1, lambda x: np.ones(x.shape[1], dtype=bool)) # Set using sub-functions Vs = [V.sub(i).collapse()[0] for i in range(V.num_sub_spaces)] boundary_dofs = [ locate_dofs_topological((V.sub(i), Vs[i]), tdim - 1, boundary_facets) for i in range(len(Vs)) ] u_bcs = [Function(Vs[i]) for i in range(len(Vs))] bcs_f = [] for i, u in enumerate(u_bcs): u_bcs[i].x.array[:] = c[i] bcs_f.append(dirichletbc(u_bcs[i], boundary_dofs[i], V.sub(i))) u_f = Function(V) set_bc(u_f.vector, bcs_f) # Set using constant boundary_dofs = locate_dofs_topological(V, tdim - 1, boundary_facets) bc_c = dirichletbc(c, boundary_dofs, V) u_c = Function(V) u_c.x.array[:] = 0.0 set_bc(u_c.vector, [bc_c]) assert np.allclose(u_f.x.array, u_c.x.array)
def test_constant_bc(mesh_factory): """Test that setting a dirichletbc with a constant yields the same result as setting it with a function""" func, args = mesh_factory mesh = func(*args) V = FunctionSpace(mesh, ("Lagrange", 1)) c = PETSc.ScalarType(2) tdim = mesh.topology.dim boundary_facets = locate_entities_boundary( mesh, tdim - 1, lambda x: np.ones(x.shape[1], dtype=bool)) boundary_dofs = locate_dofs_topological(V, tdim - 1, boundary_facets) u_bc = Function(V) u_bc.x.array[:] = c bc_f = dirichletbc(u_bc, boundary_dofs) bc_c = dirichletbc(c, boundary_dofs, V) u_f = Function(V) set_bc(u_f.vector, [bc_f]) u_c = Function(V) set_bc(u_c.vector, [bc_c]) assert np.allclose(u_f.vector.array, u_c.vector.array)
def test_sub_bbtree(): """ Testing point collision with a BoundingBoxTree of sub entitites """ mesh = UnitCubeMesh(MPI.COMM_WORLD, 4, 4, 4, cell_type=cpp.mesh.CellType.hexahedron) tdim = mesh.topology.dim fdim = tdim - 1 def top_surface(x): return numpy.isclose(x[2], 1) top_facets = locate_entities_boundary(mesh, fdim, top_surface) f_to_c = mesh.topology.connectivity(tdim - 1, tdim) cells = [f_to_c.links(f)[0] for f in top_facets] bbtree = BoundingBoxTree(mesh, tdim, cells) # Compute a BBtree for all processes process_bbtree = bbtree.compute_global_tree(mesh.mpi_comm()) # Find possible ranks for this point point = numpy.array([0.2, 0.2, 1.0]) ranks = compute_collisions_point(process_bbtree, point) # Compute local collisions cells = compute_collisions_point(bbtree, point) if MPI.COMM_WORLD.rank in ranks: assert(len(cells) > 0) else: assert(len(cells) == 0)
def amg_solve(N, method): # Elasticity parameters E = 1.0e9 nu = 0.3 mu = E / (2.0 * (1.0 + nu)) lmbda = E * nu / ((1.0 + nu) * (1.0 - 2.0 * nu)) # Stress computation def sigma(v): return 2.0 * mu * sym(grad(v)) + lmbda * tr(sym( grad(v))) * Identity(2) # Define problem mesh = create_unit_square(MPI.COMM_WORLD, N, N) V = VectorFunctionSpace(mesh, 'Lagrange', 1) u = TrialFunction(V) v = TestFunction(V) facetdim = mesh.topology.dim - 1 bndry_facets = locate_entities_boundary( mesh, facetdim, lambda x: np.full(x.shape[1], True)) bdofs = locate_dofs_topological(V.sub(0), V, facetdim, bndry_facets) bc = dirichletbc(PETSc.ScalarType(0), bdofs, V.sub(0)) # Forms a, L = inner(sigma(u), grad(v)) * dx, dot(ufl.as_vector( (1.0, 1.0)), v) * dx # Assemble linear algebra objects A = assemble_matrix(a, [bc]) A.assemble() b = assemble_vector(L) apply_lifting(b, [a], [[bc]]) b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) set_bc(b, [bc]) # Create solution function u = Function(V) # Create near null space basis and orthonormalize null_space = build_nullspace(V, u.vector) # Attached near-null space to matrix A.set_near_nullspace(null_space) # Test that basis is orthonormal assert null_space.is_orthonormal() # Create PETSC smoothed aggregation AMG preconditioner, and # create CG solver solver = PETSc.KSP().create(mesh.comm) solver.setType("cg") # Set matrix operator solver.setOperators(A) # Compute solution and return number of iterations return solver.solve(b, u.vector)
def solve_system(N): fenics_mesh = dolfinx.UnitCubeMesh(fenicsx_comm, N, N, N) fenics_space = dolfinx.FunctionSpace(fenics_mesh, ("CG", 1)) u = ufl.TrialFunction(fenics_space) v = ufl.TestFunction(fenics_space) k = 2 # print(u*v*ufl.ds) form = (ufl.inner(ufl.grad(u), ufl.grad(v)) - k**2 * ufl.inner(u, v)) * ufl.dx # locate facets on the cube boundary facets = locate_entities_boundary( fenics_mesh, 2, lambda x: np.logical_or( np.logical_or( np.logical_or(np.isclose(x[2], 0.0), np.isclose(x[2], 1.0)), np.logical_or(np.isclose(x[1], 0.0), np.isclose(x[1], 1.0))), np.logical_or(np.isclose(x[0], 0.0), np.isclose(x[0], 1.0)))) facets.sort() # alternative - more general approach boundary = entities_to_geometry( fenics_mesh, fenics_mesh.topology.dim - 1, exterior_facet_indices(fenics_mesh), True, ) # print(len(facets) assert len(facets) == len(exterior_facet_indices(fenics_mesh)) u0 = fem.Function(fenics_space) with u0.vector.localForm() as u0_loc: u0_loc.set(0) # solution vector bc = DirichletBC(u0, locate_dofs_topological(fenics_space, 2, facets)) A = 1 + 1j f = Function(fenics_space) f.interpolate(lambda x: A * k**2 * np.cos(k * x[0]) * np.cos(k * x[1])) L = ufl.inner(f, v) * ufl.dx u0.name = "u" problem = fem.LinearProblem(form, L, u=u0, petsc_options={ "ksp_type": "preonly", "pc_type": "lu" }) # problem = fem.LinearProblem(form, L, bcs=[bc], u=u0, petsc_options={"ksp_type": "preonly", "pc_type": "lu"}) start_time = time.time() soln = problem.solve() if world_rank == 0: print("--- fenics solve done in %s seconds ---" % (time.time() - start_time))
def test_submesh_boundary(d, n, boundary, ghost_mode): if d == 2: mesh = create_unit_square(MPI.COMM_WORLD, n, n, ghost_mode=ghost_mode) else: mesh = create_unit_cube(MPI.COMM_WORLD, n, n, n, ghost_mode=ghost_mode) edim = mesh.topology.dim - 1 entities = locate_entities_boundary(mesh, edim, boundary) submesh, vertex_map, geom_map = create_submesh(mesh, edim, entities) submesh_topology_test(mesh, submesh, vertex_map, edim, entities) submesh_geometry_test(mesh, submesh, geom_map, edim, entities)
def test_sub_refine(): """Test that refinement of a subset of edges works""" mesh = create_unit_square(MPI.COMM_WORLD, 3, 4, diagonal=DiagonalType.left, ghost_mode=GhostMode.none) mesh.topology.create_entities(1) def left_corner_edge(x, tol=1e-16): return logical_and(isclose(x[0], 0), x[1] < 1 / 4 + tol) edges = locate_entities_boundary(mesh, 1, left_corner_edge) if MPI.COMM_WORLD.size == 0: assert edges == 1 mesh2 = refine(mesh, edges, redistribute=False) assert mesh.topology.index_map(2).size_global + 3 == mesh2.topology.index_map(2).size_global
def test_sub_bbtree_box(ct, N): """Test that the bounding box of the stem of the bounding box tree is what we expect""" mesh = create_unit_cube(MPI.COMM_WORLD, N, N, N, cell_type=ct) tdim = mesh.topology.dim fdim = tdim - 1 facets = locate_entities_boundary(mesh, fdim, lambda x: np.isclose(x[1], 1.0)) f_to_c = mesh.topology.connectivity(fdim, tdim) cells = np.int32(np.unique([f_to_c.links(f)[0] for f in facets])) bbtree = BoundingBoxTree(mesh, tdim, cells) num_boxes = bbtree.num_bboxes if num_boxes > 0: bbox = bbtree.get_bbox(num_boxes - 1) assert np.isclose(bbox[0][1], (N - 1) / N) tree = BoundingBoxTree(mesh, tdim) assert num_boxes < tree.num_bboxes
def test_sub_bbtree_box(ct, N): """ Test that the bounding box of the stem of the bounding box tree is what we expect """ mesh = UnitCubeMesh(MPI.COMM_WORLD, N, N, N, cell_type=ct) tdim = mesh.topology.dim fdim = tdim - 1 def marker(x): return numpy.isclose(x[1], 1.0) facets = locate_entities_boundary(mesh, fdim, marker) f_to_c = mesh.topology.connectivity(fdim, tdim) cells = numpy.unique([f_to_c.links(f)[0] for f in facets]) bbtree = BoundingBoxTree(mesh, tdim, cells) num_boxes = bbtree.num_bboxes if num_boxes > 0: bbox = bbtree.get_bbox(num_boxes - 1) assert numpy.isclose(bbox[0][1], (N - 1) / N) tree = BoundingBoxTree(mesh, tdim) assert num_boxes < tree.num_bboxes
def test_sub_bbtree(): """Testing point collision with a BoundingBoxTree of sub entitites""" mesh = create_unit_cube(MPI.COMM_WORLD, 4, 4, 4, cell_type=CellType.hexahedron) tdim = mesh.topology.dim fdim = tdim - 1 top_facets = locate_entities_boundary(mesh, fdim, lambda x: np.isclose(x[2], 1)) f_to_c = mesh.topology.connectivity(tdim - 1, tdim) cells = [f_to_c.links(f)[0] for f in top_facets] bbtree = BoundingBoxTree(mesh, tdim, cells) # Compute a BBtree for all processes process_bbtree = bbtree.create_global_tree(mesh.comm) # Find possible ranks for this point point = np.array([0.2, 0.2, 1.0]) ranks = compute_collisions(process_bbtree, point) # Compute local collisions cells = compute_collisions(bbtree, point) if MPI.COMM_WORLD.rank in ranks.array: assert len(cells.links(0)) > 0 else: assert len(cells.links(0)) == 0
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)
dl_interp(CC, Cn) my_identity = grad(SpatialCoordinate(mesh)) dl_interp(my_identity, CCv) dl_interp(my_identity, Cvn) dl_interp(my_identity, C_quart) dl_interp(my_identity, C_thr_quart) dl_interp(my_identity, C_half) a_uv = (derivative(freeEnergy(CC, CCv), u, v) * dx + qvals / h_avg * dot(jump(u), jump(v)) * dS) jac = derivative(a_uv, u, du) # assign DirichletBC left_facets = locate_entities_boundary(mesh, mesh.topology.dim - 1, left) right_facets = locate_entities_boundary(mesh, mesh.topology.dim - 1, right) bottom_facets = locate_entities_boundary(mesh, mesh.topology.dim - 1, bottom) back_facets = locate_entities_boundary(mesh, mesh.topology.dim - 1, back) left_dofs = fem.locate_dofs_topological(V.sub(0), mesh.topology.dim - 1, left_facets) right_dofs = fem.locate_dofs_topological(V.sub(0), mesh.topology.dim - 1, right_facets) back_dofs = fem.locate_dofs_topological(V.sub(2), mesh.topology.dim - 1, back_facets) bottom_dofs = fem.locate_dofs_topological(V.sub(1), mesh.topology.dim - 1, bottom_facets) right_disp = fem.Constant(mesh, 0.0) ul = fem.dirichletbc(st(0), left_dofs, V.sub(0))
def mesh_2D_dolfin(celltype: str, theta: float = 0): """ Create two 2D cubes stacked on top of each other, and the corresponding mesh markers using dolfin built-in meshes """ def find_line_function(p0, p1): """ Find line y=ax+b for each of the lines in the mesh https://mathworld.wolfram.com/Two-PointForm.html """ # Line aligned with y axis if np.isclose(p1[0], p0[0]): return lambda x: np.isclose(x[0], p0[0]) return lambda x: np.isclose( x[1], p0[1] + (p1[1] - p0[1]) / (p1[0] - p0[0]) * (x[0] - p0[0])) def over_line(p0, p1): """ Check if a point is over or under y=ax+b for each of the lines in the mesh https://mathworld.wolfram.com/Two-PointForm.html """ return lambda x: x[1] > p0[1] + (p1[1] - p0[1]) / (p1[0] - p0[0]) * (x[ 0] - p0[0]) # Using built in meshes, stacking cubes on top of each other N = 15 if celltype == "quadrilateral": ct = _mesh.CellType.quadrilateral elif celltype == "triangle": ct = _mesh.CellType.triangle else: raise ValueError("celltype has to be tri or quad") if MPI.COMM_WORLD.rank == 0: mesh0 = _mesh.create_unit_square(MPI.COMM_SELF, N, N, ct) mesh1 = _mesh.create_unit_square(MPI.COMM_SELF, 2 * N, 2 * N, ct) mesh0.geometry.x[:, 1] += 1 # Stack the two meshes in one mesh r_matrix = _utils.rotation_matrix([0, 0, 1], theta) points = np.vstack([mesh0.geometry.x, mesh1.geometry.x]) points = np.dot(r_matrix, points.T) points = points[:2, :].T # Transform topology info into geometry info tdim0 = mesh0.topology.dim num_cells0 = mesh0.topology.index_map(tdim0).size_local cells0 = _cpp.mesh.entities_to_geometry( mesh0, tdim0, np.arange(num_cells0, dtype=np.int32).reshape((-1, 1)), False) tdim1 = mesh1.topology.dim num_cells1 = mesh1.topology.index_map(tdim1).size_local cells1 = _cpp.mesh.entities_to_geometry( mesh1, tdim1, np.arange(num_cells1, dtype=np.int32).reshape((-1, 1)), False) cells1 += mesh0.geometry.x.shape[0] cells = np.vstack([cells0, cells1]) cell = ufl.Cell(celltype, geometric_dimension=points.shape[1]) domain = ufl.Mesh(ufl.VectorElement("Lagrange", cell, 1)) mesh = _mesh.create_mesh(MPI.COMM_SELF, cells, points, domain) tdim = mesh.topology.dim fdim = tdim - 1 # Find information about facets to be used in meshtags bottom_points = np.dot( r_matrix, np.array([[0, 0, 0], [1, 0, 0], [1, 1, 0], [0, 1, 0]]).T) bottom = find_line_function(bottom_points[:, 0], bottom_points[:, 1]) bottom_facets = _mesh.locate_entities_boundary(mesh, fdim, bottom) top_points = np.dot( r_matrix, np.array([[0, 1, 0], [1, 1, 0], [1, 2, 0], [0, 2, 0]]).T) top = find_line_function(top_points[:, 2], top_points[:, 3]) top_facets = _mesh.locate_entities_boundary(mesh, fdim, top) left_side = find_line_function(top_points[:, 0], top_points[:, 3]) left_facets = _mesh.locate_entities_boundary(mesh, fdim, left_side) right_side = find_line_function(top_points[:, 1], top_points[:, 2]) right_facets = _mesh.locate_entities_boundary(mesh, fdim, right_side) top_cube = over_line(bottom_points[:, 2], bottom_points[:, 3]) num_cells = mesh.topology.index_map(tdim).size_local cell_midpoints = _cpp.mesh.compute_midpoints(mesh, tdim, range(num_cells)) interface = find_line_function(bottom_points[:, 2], bottom_points[:, 3]) i_facets = _mesh.locate_entities_boundary(mesh, fdim, interface) bottom_interface = [] top_interface = [] mesh.topology.create_connectivity(fdim, tdim) facet_to_cell = mesh.topology.connectivity(fdim, tdim) for facet in i_facets: i_cells = facet_to_cell.links(facet) assert (len(i_cells == 1)) i_cell = i_cells[0] if top_cube(cell_midpoints[i_cell]): top_interface.append(facet) else: bottom_interface.append(facet) top_cube_marker = 2 cell_indices = [] cell_values = [] for cell_index in range(num_cells): if top_cube(cell_midpoints[cell_index]): cell_indices.append(cell_index) cell_values.append(top_cube_marker) ct = _mesh.meshtags(mesh, tdim, np.array(cell_indices, dtype=np.intc), np.array(cell_values, dtype=np.intc)) # Create meshtags for facet data markers: Dict[int, np.ndarray] = { 3: top_facets, 4: np.hstack(bottom_interface), 9: np.hstack(top_interface), 5: bottom_facets, 6: left_facets, 7: right_facets } all_indices = [] all_values = [] for key in markers.keys(): all_indices.append(markers[key]) all_values.append(np.full(len(markers[key]), key, dtype=np.intc)) arg_sort = np.argsort(np.hstack(all_indices)) mt = _mesh.meshtags(mesh, fdim, np.hstack(all_indices)[arg_sort], np.hstack(all_values)[arg_sort]) mt.name = "facet_tags" # type: ignore with _io.XDMFFile(MPI.COMM_SELF, f"meshes/mesh_{celltype}_{theta:.2f}.xdmf", "w") as o_f: o_f.write_mesh(mesh) o_f.write_meshtags(ct) o_f.write_meshtags(mt) MPI.COMM_WORLD.barrier()
def mesh_3D_dolfin(theta: float = 0, ct: _mesh.CellType = _mesh.CellType.tetrahedron, ext: str = "tetrahedron", res: float = 0.1): timer = _common.Timer("~~Contact: Create mesh") def find_plane_function(p0, p1, p2): """ Find plane function given three points: http://www.nabla.hr/CG-LinesPlanesIn3DA3.htm """ v1 = np.array(p1) - np.array(p0) v2 = np.array(p2) - np.array(p0) n = np.cross(v1, v2) D = -(n[0] * p0[0] + n[1] * p0[1] + n[2] * p0[2]) return lambda x: np.isclose(0, np.dot(n, x) + D) def over_plane(p0, p1, p2): """ Returns function that checks if a point is over a plane defined by the points p0, p1 and p2. """ v1 = np.array(p1) - np.array(p0) v2 = np.array(p2) - np.array(p0) n = np.cross(v1, v2) D = -(n[0] * p0[0] + n[1] * p0[1] + n[2] * p0[2]) return lambda x: n[0] * x[0] + n[1] * x[1] + D > -n[2] * x[2] N = int(1 / res) if MPI.COMM_WORLD.rank == 0: mesh0 = _mesh.create_unit_cube(MPI.COMM_SELF, N, N, N, ct) mesh1 = _mesh.create_unit_cube(MPI.COMM_SELF, 2 * N, 2 * N, 2 * N, ct) mesh0.geometry.x[:, 2] += 1 # Stack the two meshes in one mesh r_matrix = _utils.rotation_matrix([1 / np.sqrt(2), 1 / np.sqrt(2), 0], -theta) points = np.vstack([mesh0.geometry.x, mesh1.geometry.x]) points = np.dot(r_matrix, points.T).T # Transform topology info into geometry info tdim0 = mesh0.topology.dim num_cells0 = mesh0.topology.index_map(tdim0).size_local cells0 = _cpp.mesh.entities_to_geometry( mesh0, tdim0, np.arange(num_cells0, dtype=np.int32).reshape((-1, 1)), False) tdim1 = mesh1.topology.dim num_cells1 = mesh1.topology.index_map(tdim1).size_local cells1 = _cpp.mesh.entities_to_geometry( mesh1, tdim1, np.arange(num_cells1, dtype=np.int32).reshape((-1, 1)), False) cells1 += mesh0.geometry.x.shape[0] cells = np.vstack([cells0, cells1]) cell = ufl.Cell(ext, geometric_dimension=points.shape[1]) domain = ufl.Mesh(ufl.VectorElement("Lagrange", cell, 1)) mesh = _mesh.create_mesh(MPI.COMM_SELF, cells, points, domain) tdim = mesh.topology.dim fdim = tdim - 1 # Find information about facets to be used in meshtags bottom_points = np.dot( r_matrix, np.array([[0, 0, 0], [1, 0, 0], [0, 1, 0], [1, 1, 0]]).T) bottom = find_plane_function(bottom_points[:, 0], bottom_points[:, 1], bottom_points[:, 2]) bottom_facets = _mesh.locate_entities_boundary(mesh, fdim, bottom) top_points = np.dot( r_matrix, np.array([[0, 0, 2], [1, 0, 2], [0, 1, 2], [1, 1, 2]]).T) top = find_plane_function(top_points[:, 0], top_points[:, 1], top_points[:, 2]) top_facets = _mesh.locate_entities_boundary(mesh, fdim, top) # left_side = find_line_function(top_points[:, 0], top_points[:, 3]) # left_facets = _mesh.locate_entities_boundary( # mesh, fdim, left_side) # right_side = find_line_function(top_points[:, 1], top_points[:, 2]) # right_facets = _mesh.locate_entities_boundary( # mesh, fdim, right_side) if_points = np.dot( r_matrix, np.array([[0, 0, 1], [1, 0, 1], [0, 1, 1], [1, 1, 1]]).T) interface = find_plane_function(if_points[:, 0], if_points[:, 1], if_points[:, 2]) i_facets = _mesh.locate_entities_boundary(mesh, fdim, interface) mesh.topology.create_connectivity(fdim, tdim) top_interface = [] bottom_interface = [] facet_to_cell = mesh.topology.connectivity(fdim, tdim) num_cells = mesh.topology.index_map(tdim).size_local cell_midpoints = _cpp.mesh.compute_midpoints(mesh, tdim, range(num_cells)) top_cube = over_plane(if_points[:, 0], if_points[:, 1], if_points[:, 2]) for facet in i_facets: i_cells = facet_to_cell.links(facet) assert (len(i_cells == 1)) i_cell = i_cells[0] if top_cube(cell_midpoints[i_cell]): top_interface.append(facet) else: bottom_interface.append(facet) num_cells = mesh.topology.index_map(tdim).size_local cell_midpoints = _cpp.mesh.compute_midpoints(mesh, tdim, range(num_cells)) top_cube_marker = 2 indices = [] values = [] for cell_index in range(num_cells): if top_cube(cell_midpoints[cell_index]): indices.append(cell_index) values.append(top_cube_marker) ct = _mesh.meshtags(mesh, tdim, np.array(indices, dtype=np.int32), np.array(values, dtype=np.int32)) # Create meshtags for facet data markers: Dict[int, np.ndarray] = { 3: top_facets, 4: np.hstack(bottom_interface), 9: np.hstack(top_interface), 5: bottom_facets } # , 6: left_facets, 7: right_facets} all_indices = [] all_values = [] for key in markers.keys(): all_indices.append(np.asarray(markers[key], dtype=np.int32)) all_values.append(np.full(len(markers[key]), key, dtype=np.int32)) arg_sort = np.argsort(np.hstack(all_indices)) sorted_vals = np.asarray(np.hstack(all_values)[arg_sort], dtype=np.int32) sorted_indices = np.asarray(np.hstack(all_indices)[arg_sort], dtype=np.int32) mt = _mesh.meshtags(mesh, fdim, sorted_indices, sorted_vals) mt.name = "facet_tags" # type: ignore fname = f"meshes/mesh_{ext}_{theta:.2f}.xdmf" with _io.XDMFFile(MPI.COMM_SELF, fname, "w") as o_f: o_f.write_mesh(mesh) o_f.write_meshtags(ct) o_f.write_meshtags(mt) timer.stop()
# field:: P2 = ufl.VectorElement("Lagrange", mesh.ufl_cell(), 2) P1 = ufl.FiniteElement("Lagrange", mesh.ufl_cell(), 1) V, Q = FunctionSpace(mesh, P2), FunctionSpace(mesh, P1) # We can define boundary conditions:: # No-slip boundary condition for velocity field (`V`) on boundaries # where x = 0, x = 1, and y = 0 noslip = Function(V) with noslip.vector.localForm() as bc_local: bc_local.set(0.0) facets = locate_entities_boundary(mesh, 1, noslip_boundary) bc0 = DirichletBC(noslip, locate_dofs_topological(V, 1, facets)) # Driving velocity condition u = (1, 0) on top boundary (y = 1) lid_velocity = Function(V) lid_velocity.interpolate(lid_velocity_expression) facets = locate_entities_boundary(mesh, 1, lid) bc1 = DirichletBC(lid_velocity, locate_dofs_topological(V, 1, facets)) # Collect Dirichlet boundary conditions bcs = [bc0, bc1] # We now define the bilinear and linear forms corresponding to the weak # mixed formulation of the Stokes equations in a blocked structure:: # Define variational problem
def __init__(self, mesh, k, omega, c, wx, wy, amp): P = FiniteElement("Lagrange", mesh.ufl_cell(), k) self.V = FunctionSpace(mesh, P) self.u, self.v = Function(self.V), Function(self.V) self.g = Function(self.V) self.g_deriv = Function(self.V) self.omega = omega self.c = c self.a = amp # GEOMETRY: rectangular domain with 5mm radius piston on left wall # |------------------------------------------------------------| # | | # | | # || | # || | # || <-- 5mm radius piston | # || | # || | # | | # | | # |----------------------------------------------------------- | # Locate boundary facets tdim = mesh.topology.dim # facets0 belong to 5mm radius piston at x=0 facets0 = locate_entities_boundary(mesh, tdim - 1, lambda x: (x[0] < 1.0e-6) * (np.abs(x[1]) < 5e-3)) # facets1 belong to right hand wall, at x=wx facets1 = locate_entities_boundary(mesh, tdim - 1, lambda x: x[0] > (wx - 1.0e-6)) # facets2 belong to top and bottom walls, at y=+wy/2 and y=-wy/2 facets2 = locate_entities_boundary(mesh, tdim - 1, lambda x: np.abs(x[1]) > (wy / 2 - 1.0e-6)) indices, pos = np.unique(np.hstack((facets0, facets1, facets2)), return_index=True) values = np.hstack((np.full(facets0.shape, 1, np.intc), np.full(facets1.shape, 2, np.intc), np.full(facets2.shape, 3, np.intc))) marker = dolfinx.mesh.MeshTags(mesh, tdim - 1, indices, values[pos]) ds = ufl.Measure('ds', subdomain_data=marker, domain=mesh) # dv, p = TrialFunction(self.V), TestFunction(self.V) p = TestFunction(self.V) beta = 3.5 delta0 = 3.0e-6 delta = delta0 # # EXPERIMENT: add absorbing layers to top and bottom ("PMLs") # def delta_fun(x): # lam = 2 * np.pi / k # depth = 2 * lam # dist = np.abs(x[1]) - (wy/2 - depth) # inside = (dist >= 0) # # outside = (dist < 0) # return delta0 + inside * (dist**2) * 1e3 # delta = Function(self.V) # delta.interpolate(delta_fun) # delta.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, # mode=PETSc.ScatterMode.FORWARD) # with XDMFFile(mesh.mpi_comm(), "delta.xdmf", "w", # encoding=XDMFFile.Encoding.HDF5) as file: # file.write_mesh(mesh) # file.write_function(delta) # Westervelt equation self.L1 = - inner(grad(self.u), grad(p)) * dx \ - (delta / c**2) * inner(grad(self.v), grad(p)) * dx \ + (2 * beta / (rho * c**4)) * inner(self.v * self.v, p) * dx \ - (1 / c) * inner(self.v, p) * ds \ + inner(self.g, p) * ds(1) \ + (delta / c**2) * inner(self.g_deriv, p) * ds(1) self.lumped = True # Vector to be re-used for assembly self.b = None # TODO: precompile/pre-process Form L if self.lumped: # Westervelt equation a = (1 / c**2) * \ (1 - 2 * beta * self.u / (rho * c**2)) * p * dx(degree=k) \ + (delta / c**3) * p * ds self.M = dolfinx.fem.assemble_vector(a) self.M.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) else: # TODO: non-lumped version of Westervelt # a = (1 / self.c**2) * inner(dv, p) * dx(degree=k * k) M = dolfinx.fem.assemble_matrix(a) M.assemble() self.solver = PETSc.KSP().create(mesh.mpi_comm()) opts = PETSc.Options() opts["ksp_type"] = "cg" opts["ksp_rtol"] = 1.0e-8 self.solver.setFromOptions() self.solver.setOperators(M)
# and the part of the boundary on which the condition applies. # This boundary part is identified with degrees of # freedom in the function space to which we apply the boundary conditions. # A method ``locate_dofs_geometrical`` is provided to extract the boundary # degrees of freedom using a geometrical criterium. # In our example, the function space is ``V``, # the value of the boundary condition (0.0) can represented using a # :py:class:`Function <dolfinx.functions.Function>` and the Dirichlet # boundary is defined immediately above. The definition of the Dirichlet # boundary condition then looks as follows: :: # Define boundary condition on x = 0 or x = 1 u0 = Function(V) u0.vector.set(0.0) facets = locate_entities_boundary( mesh, 1, lambda x: np.logical_or(x[0] < np.finfo(float).eps, x[0] > 1.0 - np.finfo(float).eps)) bc = DirichletBC(u0, locate_dofs_topological(V, 1, facets)) # Next, we want to express the variational problem. First, we need to # specify the trial function :math:`u` and the test function :math:`v`, # both living in the function space :math:`V`. We do this by defining a # :py:class:`TrialFunction <dolfinx.functions.function.TrialFunction>` # and a :py:class:`TestFunction # <dolfinx.functions.function.TrialFunction>` on the previously defined # :py:class:`FunctionSpace <dolfinx.functions.FunctionSpace>` ``V``. # # Further, the source :math:`f` and the boundary normal derivative # :math:`g` are involved in the variational forms, and hence we must # specify these. #
def test_pipeline(u_from_mpc): # Create mesh and function space mesh = create_unit_square(MPI.COMM_WORLD, 5, 5) V = fem.FunctionSpace(mesh, ("Lagrange", 1)) # Solve Problem without MPC for reference u = ufl.TrialFunction(V) v = ufl.TestFunction(V) d = fem.Constant(mesh, PETSc.ScalarType(0.01)) x = ufl.SpatialCoordinate(mesh) f = ufl.sin(2 * ufl.pi * x[0]) * ufl.sin(ufl.pi * x[1]) a = ufl.inner(ufl.grad(u), ufl.grad(v)) * ufl.dx - d * ufl.inner(u, v) * ufl.dx rhs = ufl.inner(f, v) * ufl.dx bilinear_form = fem.form(a) linear_form = fem.form(rhs) # Generate reference matrices A_org = fem.petsc.assemble_matrix(bilinear_form) A_org.assemble() L_org = fem.petsc.assemble_vector(linear_form) L_org.ghostUpdate(addv=PETSc.InsertMode.ADD_VALUES, mode=PETSc.ScatterMode.REVERSE) # Create multipoint constraint def periodic_relation(x): out_x = np.copy(x) out_x[0] = 1 - x[0] return out_x def PeriodicBoundary(x): return np.isclose(x[0], 1) facets = locate_entities_boundary(mesh, mesh.topology.dim - 1, PeriodicBoundary) arg_sort = np.argsort(facets) mt = meshtags(mesh, mesh.topology.dim - 1, facets[arg_sort], np.full(len(facets), 2, dtype=np.int32)) mpc = dolfinx_mpc.MultiPointConstraint(V) mpc.create_periodic_constraint_topological(V, mt, 2, periodic_relation, [], 1) mpc.finalize() if u_from_mpc: uh = fem.Function(mpc.function_space) problem = dolfinx_mpc.LinearProblem(bilinear_form, linear_form, mpc, bcs=[], u=uh, petsc_options={"ksp_type": "preonly", "pc_type": "lu"}) problem.solve() root = 0 dolfinx_mpc.utils.compare_mpc_lhs(A_org, problem.A, mpc, root=root) dolfinx_mpc.utils.compare_mpc_rhs(L_org, problem.b, mpc, root=root) # Gather LHS, RHS and solution on one process A_csr = dolfinx_mpc.utils.gather_PETScMatrix(A_org, root=root) K = dolfinx_mpc.utils.gather_transformation_matrix(mpc, root=root) L_np = dolfinx_mpc.utils.gather_PETScVector(L_org, root=root) u_mpc = dolfinx_mpc.utils.gather_PETScVector(uh.vector, root=root) if MPI.COMM_WORLD.rank == root: KTAK = K.T * A_csr * K reduced_L = K.T @ L_np # Solve linear system d = scipy.sparse.linalg.spsolve(KTAK, reduced_L) # Back substitution to full solution vector uh_numpy = K @ d assert np.allclose(uh_numpy, u_mpc) else: uh = fem.Function(V) with pytest.raises(ValueError): problem = dolfinx_mpc.LinearProblem(bilinear_form, linear_form, mpc, bcs=[], u=uh, petsc_options={"ksp_type": "preonly", "pc_type": "lu"}) problem.solve()
def demo_periodic3D(celltype: CellType): # Create mesh and finite element if celltype == CellType.tetrahedron: # Tet setup N = 10 mesh = create_unit_cube(MPI.COMM_WORLD, N, N, N) V = fem.VectorFunctionSpace(mesh, ("CG", 1)) else: # Hex setup N = 10 mesh = create_unit_cube(MPI.COMM_WORLD, N, N, N, CellType.hexahedron) V = fem.VectorFunctionSpace(mesh, ("CG", 2)) def dirichletboundary(x: NDArray[np.float64]) -> NDArray[np.bool_]: return np.logical_or( np.logical_or(np.isclose(x[1], 0), np.isclose(x[1], 1)), np.logical_or(np.isclose(x[2], 0), np.isclose(x[2], 1))) # Create Dirichlet boundary condition zero = PETSc.ScalarType([0, 0, 0]) geometrical_dofs = fem.locate_dofs_geometrical(V, dirichletboundary) bc = fem.dirichletbc(zero, geometrical_dofs, V) bcs = [bc] def PeriodicBoundary(x): return np.isclose(x[0], 1) facets = locate_entities_boundary(mesh, mesh.topology.dim - 1, PeriodicBoundary) arg_sort = np.argsort(facets) mt = meshtags(mesh, mesh.topology.dim - 1, facets[arg_sort], np.full(len(facets), 2, dtype=np.int32)) def periodic_relation(x): out_x = np.zeros(x.shape) out_x[0] = 1 - x[0] out_x[1] = x[1] out_x[2] = x[2] return out_x with Timer("~~Periodic: Compute mpc condition"): mpc = dolfinx_mpc.MultiPointConstraint(V) mpc.create_periodic_constraint_topological(V.sub(0), mt, 2, periodic_relation, bcs, 1) mpc.finalize() # Define variational problem u = TrialFunction(V) v = TestFunction(V) a = inner(grad(u), grad(v)) * dx x = SpatialCoordinate(mesh) dx_ = x[0] - 0.9 dy_ = x[1] - 0.5 dz_ = x[2] - 0.1 f = as_vector((x[0] * sin(5.0 * pi * x[1]) + 1.0 * exp(-(dx_ * dx_ + dy_ * dy_ + dz_ * dz_) / 0.02), 0.1 * dx_ * dz_, 0.1 * dx_ * dy_)) rhs = inner(f, v) * dx petsc_options: Dict[str, Union[str, float, int]] if complex_mode: rtol = 1e-16 petsc_options = {"ksp_type": "preonly", "pc_type": "lu"} else: rtol = 1e-8 petsc_options = { "ksp_type": "cg", "ksp_rtol": rtol, "pc_type": "hypre", "pc_hypre_typ": "boomeramg", "pc_hypre_boomeramg_max_iter": 1, "pc_hypre_boomeramg_cycle_type": "v", "pc_hypre_boomeramg_print_statistics": 1 } problem = LinearProblem(a, rhs, mpc, bcs, petsc_options=petsc_options) u_h = problem.solve() # --------------------VERIFICATION------------------------- print("----Verification----") u_ = fem.Function(V) u_.x.array[:] = 0 org_problem = fem.petsc.LinearProblem(a, rhs, u=u_, bcs=bcs, petsc_options=petsc_options) with Timer("~Periodic: Unconstrained solve"): org_problem.solve() it = org_problem.solver.getIterationNumber() print(f"Unconstrained solver iterations: {it}") # Write solutions to file ext = "tet" if celltype == CellType.tetrahedron else "hex" u_.name = "u_" + ext + "_unconstrained" # NOTE: Workaround as tabulate dof coordinates does not like extra ghosts u_out = fem.Function(V) old_local = u_out.x.map.size_local * u_out.x.bs old_ghosts = u_out.x.map.num_ghosts * u_out.x.bs mpc_local = u_h.x.map.size_local * u_h.x.bs assert (old_local == mpc_local) u_out.x.array[:old_local + old_ghosts] = u_h.x.array[:mpc_local + old_ghosts] u_out.name = "u_" + ext fname = f"results/demo_periodic3d_{ext}.bp" out_periodic = VTXWriter(MPI.COMM_WORLD, fname, u_out) out_periodic.write(0) out_periodic.close() root = 0 with Timer("~Demo: Verification"): dolfinx_mpc.utils.compare_mpc_lhs(org_problem.A, problem.A, mpc, root=root) dolfinx_mpc.utils.compare_mpc_rhs(org_problem.b, problem.b, mpc, root=root) # Gather LHS, RHS and solution on one process A_csr = dolfinx_mpc.utils.gather_PETScMatrix(org_problem.A, root=root) K = dolfinx_mpc.utils.gather_transformation_matrix(mpc, root=root) L_np = dolfinx_mpc.utils.gather_PETScVector(org_problem.b, root=root) u_mpc = dolfinx_mpc.utils.gather_PETScVector(u_h.vector, root=root) if MPI.COMM_WORLD.rank == root: KTAK = K.T * A_csr * K reduced_L = K.T @ L_np # Solve linear system d = scipy.sparse.linalg.spsolve(KTAK, reduced_L) # Back substitution to full solution vector uh_numpy = K @ d assert np.allclose(uh_numpy, u_mpc, rtol=rtol)
Ny = 20 mesh = BoxMesh(MPI.COMM_WORLD, [np.array([0.0, 0.0, 0.0]), np.array([xdim, ydim, zdim])], [Nx, Ny, Nz]) def right_side(x): return np.isclose(x[1], ydim) def left_side(x): return np.isclose(x[1], 0.0) left_side_facets = locate_entities_boundary(mesh, 2, left_side) right_side_facets = locate_entities_boundary(mesh, 2, right_side) mt = MeshTags(mesh, 2, right_side_facets, 1) # External boundary facets ds = ufl.Measure("ds", domain=mesh, subdomain_data=mt) dx = ufl.Measure("dx", domain=mesh) load_area = mesh.mpi_comm().allreduce( assemble_scalar(1.0 * ds(1, domain=mesh)), MPI.SUM) if rank == 0: logger.info("Mesh hmin={} hmax={}".format(mesh.hmin(), mesh.hmax())) logger.info(f"Load area = {load_area}")
def test_assembly_ds_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) 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_boundary(mesh, mesh.topology.dim - 1, bottom) bottom_vals = numpy.full(bottom_facets.shape, 1, numpy.intc) top_facets = locate_entities_boundary(mesh, mesh.topology.dim - 1, top) top_vals = numpy.full(top_facets.shape, 2, numpy.intc) left_facets = locate_entities_boundary(mesh, mesh.topology.dim - 1, left) left_vals = numpy.full(left_facets.shape, 3, numpy.intc) right_facets = locate_entities_boundary(mesh, mesh.topology.dim - 1, right) 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) bc = dolfinx.fem.DirichletBC(dolfinx.Function(V), range(30)) # 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) 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) * ds b2 = dolfinx.fem.assemble_vector(L2) dolfinx.fem.apply_lifting(b2, [a2], [[bc]]) b2.ghostUpdate(addv=PETSc.InsertMode.ADD_VALUES, mode=PETSc.ScatterMode.REVERSE) dolfinx.fem.set_bc(b2, [bc]) 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 demo_elasticity(): mesh = create_unit_square(MPI.COMM_WORLD, 10, 10) V = fem.VectorFunctionSpace(mesh, ("Lagrange", 1)) # Generate Dirichlet BC on lower boundary (Fixed) def boundaries(x): return np.isclose(x[0], np.finfo(float).eps) facets = locate_entities_boundary(mesh, 1, boundaries) topological_dofs = fem.locate_dofs_topological(V, 1, facets) bc = fem.dirichletbc(np.array([0, 0], dtype=PETSc.ScalarType), topological_dofs, V) bcs = [bc] # Define variational problem u = TrialFunction(V) v = TestFunction(V) # Elasticity parameters E = PETSc.ScalarType(1.0e4) nu = 0.0 mu = fem.Constant(mesh, E / (2.0 * (1.0 + nu))) lmbda = fem.Constant(mesh, E * nu / ((1.0 + nu) * (1.0 - 2.0 * nu))) # Stress computation def sigma(v): return (2.0 * mu * sym(grad(v)) + lmbda * tr(sym(grad(v))) * Identity(len(v))) x = SpatialCoordinate(mesh) # Define variational problem u = TrialFunction(V) v = TestFunction(V) a = inner(sigma(u), grad(v)) * dx rhs = inner(as_vector((0, (x[0] - 0.5) * 10**4 * x[1])), v) * dx # Create MPC def l2b(li): return np.array(li, dtype=np.float64).tobytes() s_m_c = {l2b([1, 0]): {l2b([1, 1]): 0.9}} mpc = MultiPointConstraint(V) mpc.create_general_constraint(s_m_c, 1, 1) mpc.finalize() # Solve Linear problem petsc_options = {"ksp_type": "preonly", "pc_type": "lu"} problem = LinearProblem(a, rhs, mpc, bcs=bcs, petsc_options=petsc_options) u_h = problem.solve() u_h.name = "u_mpc" with XDMFFile(MPI.COMM_WORLD, "results/demo_elasticity.xdmf", "w") as outfile: outfile.write_mesh(mesh) outfile.write_function(u_h) # Solve the MPC problem using a global transformation matrix # and numpy solvers to get reference values bilinear_form = fem.form(a) A_org = fem.petsc.assemble_matrix(bilinear_form, bcs) A_org.assemble() linear_form = fem.form(rhs) L_org = fem.petsc.assemble_vector(linear_form) fem.petsc.apply_lifting(L_org, [bilinear_form], [bcs]) L_org.ghostUpdate(addv=PETSc.InsertMode.ADD_VALUES, mode=PETSc.ScatterMode.REVERSE) fem.petsc.set_bc(L_org, bcs) solver = PETSc.KSP().create(MPI.COMM_WORLD) solver.setType(PETSc.KSP.Type.PREONLY) solver.getPC().setType(PETSc.PC.Type.LU) solver.setOperators(A_org) u_ = fem.Function(V) solver.solve(L_org, u_.vector) u_.x.scatter_forward() u_.name = "u_unconstrained" with XDMFFile(MPI.COMM_WORLD, "results/demo_elasticity.xdmf", "a") as outfile: outfile.write_function(u_) outfile.close() root = 0 with Timer("~Demo: Verification"): dolfinx_mpc.utils.compare_mpc_lhs(A_org, problem.A, mpc, root=root) dolfinx_mpc.utils.compare_mpc_rhs(L_org, problem.b, mpc, root=root) # Gather LHS, RHS and solution on one process A_csr = dolfinx_mpc.utils.gather_PETScMatrix(A_org, root=root) K = dolfinx_mpc.utils.gather_transformation_matrix(mpc, root=root) L_np = dolfinx_mpc.utils.gather_PETScVector(L_org, root=root) u_mpc = dolfinx_mpc.utils.gather_PETScVector(u_h.vector, root=root) if MPI.COMM_WORLD.rank == root: KTAK = K.T * A_csr * K reduced_L = K.T @ L_np # Solve linear system d = scipy.sparse.linalg.spsolve(KTAK, reduced_L) # Back substitution to full solution vector uh_numpy = K @ d assert np.allclose(uh_numpy, u_mpc) # Print out master-slave connectivity for the first slave master_owner = None master_data = None slave_owner = None if mpc.num_local_slaves > 0: slave_owner = MPI.COMM_WORLD.rank bs = mpc.function_space.dofmap.index_map_bs slave = mpc.slaves[0] print("Constrained: {0:.5e}\n Unconstrained: {1:.5e}".format( u_h.x.array[slave], u_.vector.array[slave])) master_owner = mpc._cpp_object.owners.links(slave)[0] _masters = mpc.masters master = _masters.links(slave)[0] glob_master = mpc.function_space.dofmap.index_map.local_to_global( [master // bs])[0] coeffs, offs = mpc.coefficients() master_data = [ glob_master * bs + master % bs, coeffs[offs[slave]:offs[slave + 1]][0] ] # If master not on proc send info to this processor if MPI.COMM_WORLD.rank != master_owner: MPI.COMM_WORLD.send(master_data, dest=master_owner, tag=1) else: print("Master*Coeff: {0:.5e}".format( coeffs[offs[slave]:offs[slave + 1]][0] * u_h.x.array[_masters.links(slave)[0]])) # As a processor with a master is not aware that it has a master, # Determine this so that it can receive the global dof and coefficient master_recv = MPI.COMM_WORLD.allgather(master_owner) for master in master_recv: if master is not None: master_owner = master break if slave_owner != master_owner and MPI.COMM_WORLD.rank == master_owner: dofmap = mpc.function_space.dofmap bs = dofmap.index_map_bs in_data = MPI.COMM_WORLD.recv(source=MPI.ANY_SOURCE, tag=1) num_local = dofmap.index_map.size_local + dofmap.index_map.num_ghosts l2g = dofmap.index_map.local_to_global( np.arange(num_local, dtype=np.int32)) l_index = np.flatnonzero(l2g == in_data[0] // bs)[0] print("Master*Coeff (on other proc): {0:.5e}".format( u_h.x.array[l_index * bs + in_data[0] % bs] * in_data[1]))
def test_assembly_solve_block(): """Solve a two-field nonlinear diffusion like problem with block matrix approaches and test that solution is the same. """ mesh = dolfinx.generation.UnitSquareMesh(MPI.COMM_WORLD, 12, 11) p = 1 P = ufl.FiniteElement("Lagrange", mesh.ufl_cell(), p) V0 = dolfinx.function.FunctionSpace(mesh, P) V1 = V0.clone() def bc_val_0(x): return x[0]**2 + x[1]**2 def bc_val_1(x): return numpy.sin(x[0]) * numpy.cos(x[1]) def initial_guess_u(x): return numpy.sin(x[0]) * numpy.sin(x[1]) def initial_guess_p(x): return -x[0]**2 - x[1]**3 def boundary(x): return numpy.logical_or(x[0] < 1.0e-6, x[0] > 1.0 - 1.0e-6) facetdim = mesh.topology.dim - 1 bndry_facets = locate_entities_boundary(mesh, facetdim, boundary) u_bc0 = dolfinx.function.Function(V0) u_bc0.interpolate(bc_val_0) u_bc1 = dolfinx.function.Function(V1) u_bc1.interpolate(bc_val_1) bdofs0 = dolfinx.fem.locate_dofs_topological(V0, facetdim, bndry_facets) bdofs1 = dolfinx.fem.locate_dofs_topological(V1, facetdim, bndry_facets) bcs = [ dolfinx.fem.dirichletbc.DirichletBC(u_bc0, bdofs0), dolfinx.fem.dirichletbc.DirichletBC(u_bc1, bdofs1) ] # Block and Nest variational problem u, p = dolfinx.function.Function(V0), dolfinx.function.Function(V1) du, dp = ufl.TrialFunction(V0), ufl.TrialFunction(V1) v, q = ufl.TestFunction(V0), ufl.TestFunction(V1) f = 1.0 g = -3.0 F = [ inner((u**2 + 1) * ufl.grad(u), ufl.grad(v)) * dx - inner(f, v) * dx, inner((p**2 + 1) * ufl.grad(p), ufl.grad(q)) * dx - inner(g, q) * dx ] J = [[derivative(F[0], u, du), derivative(F[0], p, dp)], [derivative(F[1], u, du), derivative(F[1], p, dp)]] # -- Blocked version Jmat0 = dolfinx.fem.create_matrix_block(J) Fvec0 = dolfinx.fem.create_vector_block(F) snes = PETSc.SNES().create(MPI.COMM_WORLD) snes.setTolerances(rtol=1.0e-15, max_it=10) snes.getKSP().setType("preonly") snes.getKSP().getPC().setType("lu") snes.getKSP().getPC().setFactorSolverType("superlu_dist") problem = NonlinearPDE_SNESProblem(F, J, [u, p], bcs) snes.setFunction(problem.F_block, Fvec0) snes.setJacobian(problem.J_block, J=Jmat0, P=None) u.interpolate(initial_guess_u) p.interpolate(initial_guess_p) x0 = dolfinx.fem.create_vector_block(F) dolfinx.cpp.la.scatter_local_vectors( x0, [u.vector.array_r, p.vector.array_r], [u.function_space.dofmap.index_map, p.function_space.dofmap.index_map]) x0.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) snes.solve(None, x0) assert snes.getKSP().getConvergedReason() > 0 assert snes.getConvergedReason() > 0 J0norm = Jmat0.norm() F0norm = Fvec0.norm() x0norm = x0.norm() # -- Nested (MatNest) Jmat1 = dolfinx.fem.create_matrix_nest(J) Fvec1 = dolfinx.fem.create_vector_nest(F) snes = PETSc.SNES().create(MPI.COMM_WORLD) snes.setTolerances(rtol=1.0e-15, max_it=10) nested_IS = Jmat1.getNestISs() snes.getKSP().setType("fgmres") snes.getKSP().setTolerances(rtol=1e-12) snes.getKSP().getPC().setType("fieldsplit") snes.getKSP().getPC().setFieldSplitIS(["u", nested_IS[0][0]], ["p", nested_IS[1][1]]) ksp_u, ksp_p = snes.getKSP().getPC().getFieldSplitSubKSP() ksp_u.setType("preonly") ksp_u.getPC().setType('lu') ksp_u.getPC().setFactorSolverType('superlu_dist') ksp_p.setType("preonly") ksp_p.getPC().setType('lu') ksp_p.getPC().setFactorSolverType('superlu_dist') problem = NonlinearPDE_SNESProblem(F, J, [u, p], bcs) snes.setFunction(problem.F_nest, Fvec1) snes.setJacobian(problem.J_nest, J=Jmat1, P=None) u.interpolate(initial_guess_u) p.interpolate(initial_guess_p) x1 = dolfinx.fem.create_vector_nest(F) for x1_soln_pair in zip(x1.getNestSubVecs(), (u, p)): x1_sub, soln_sub = x1_soln_pair soln_sub.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) soln_sub.vector.copy(result=x1_sub) x1_sub.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) snes.solve(None, x1) assert snes.getKSP().getConvergedReason() > 0 assert snes.getConvergedReason() > 0 assert x1.getType() == "nest" assert Jmat1.getType() == "nest" assert Fvec1.getType() == "nest" J1norm = nest_matrix_norm(Jmat1) F1norm = Fvec1.norm() x1norm = x1.norm() assert J1norm == pytest.approx(J0norm, 1.0e-12) assert F1norm == pytest.approx(F0norm, 1.0e-12) assert x1norm == pytest.approx(x0norm, 1.0e-12) # -- Monolithic version E = P * P W = dolfinx.function.FunctionSpace(mesh, E) U = dolfinx.function.Function(W) dU = ufl.TrialFunction(W) u0, u1 = ufl.split(U) v0, v1 = ufl.TestFunctions(W) F = inner((u0**2 + 1) * ufl.grad(u0), ufl.grad(v0)) * dx \ + inner((u1**2 + 1) * ufl.grad(u1), ufl.grad(v1)) * dx \ - inner(f, v0) * ufl.dx - inner(g, v1) * dx J = derivative(F, U, dU) u0_bc = dolfinx.function.Function(V0) u0_bc.interpolate(bc_val_0) u1_bc = dolfinx.function.Function(V1) u1_bc.interpolate(bc_val_1) bdofsW0_V0 = dolfinx.fem.locate_dofs_topological((W.sub(0), V0), facetdim, bndry_facets) bdofsW1_V1 = dolfinx.fem.locate_dofs_topological((W.sub(1), V1), facetdim, bndry_facets) bcs = [ dolfinx.fem.dirichletbc.DirichletBC(u0_bc, bdofsW0_V0, W.sub(0)), dolfinx.fem.dirichletbc.DirichletBC(u1_bc, bdofsW1_V1, W.sub(1)) ] Jmat2 = dolfinx.fem.create_matrix(J) Fvec2 = dolfinx.fem.create_vector(F) snes = PETSc.SNES().create(MPI.COMM_WORLD) snes.setTolerances(rtol=1.0e-15, max_it=10) snes.getKSP().setType("preonly") snes.getKSP().getPC().setType("lu") snes.getKSP().getPC().setFactorSolverType("superlu_dist") problem = NonlinearPDE_SNESProblem(F, J, U, bcs) snes.setFunction(problem.F_mono, Fvec2) snes.setJacobian(problem.J_mono, J=Jmat2, P=None) U.interpolate(lambda x: numpy.row_stack( (initial_guess_u(x), initial_guess_p(x)))) x2 = dolfinx.fem.create_vector(F) x2.array = U.vector.array_r snes.solve(None, x2) assert snes.getKSP().getConvergedReason() > 0 assert snes.getConvergedReason() > 0 J2norm = Jmat2.norm() F2norm = Fvec2.norm() x2norm = x2.norm() assert J2norm == pytest.approx(J0norm, 1.0e-12) assert F2norm == pytest.approx(F0norm, 1.0e-12) assert x2norm == pytest.approx(x0norm, 1.0e-12)
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) 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
# The second argument to {py:class}`FunctionSpace # <dolfinx.fem.FunctionSpace>` is a tuple consisting of `(family, # degree)`, where `family` is the finite element family, and `degree` # specifies the polynomial degree. in this case `V` consists of # first-order, continuous Lagrange finite element functions. # # Next, we locate the mesh facets that lie on the boundary $\Gamma_D$. # We do this using using {py:func}`locate_entities_boundary # <dolfinx.mesh.locate_entities_boundary>` and providing a marker # function that returns `True` for points `x` on the boundary and # `False` otherwise. facets = mesh.locate_entities_boundary( msh, dim=1, marker=lambda x: np.logical_or(np.isclose(x[0], 0.0), np.isclose( x[0], 2.0))) # We now find the degrees-of-freedom that are associated with the # boundary facets using {py:func}`locate_dofs_topological # <dolfinx.fem.locate_dofs_topological>` dofs = fem.locate_dofs_topological(V=V, entity_dim=1, entities=facets) # and use {py:func}`dirichletbc <dolfinx.fem.dirichletbc>` to create a # {py:class}`DirichletBCMetaClass <dolfinx.fem.DirichletBCMetaClass>` # class that represents the boundary condition bc = fem.dirichletbc(value=ScalarType(0), dofs=dofs, V=V)