def test_clear_sub_map_data_vector(mesh): mesh = UnitSquareMesh(8, 8) P1 = FiniteElement("Lagrange", mesh.ufl_cell(), 1) W = FunctionSpace(mesh, P1 * P1) # Check block size assert W.dofmap.index_map.block_size == 2 W.dofmap.clear_sub_map_data() with pytest.raises(RuntimeError): W0 = W.sub(0) assert (W0) with pytest.raises(RuntimeError): W1 = W.sub(1) assert (W1)
def test_tabulate_dofs(mesh_factory): func, args = mesh_factory mesh = func(*args) W0 = FiniteElement("Lagrange", mesh.ufl_cell(), 1) W1 = VectorElement("Lagrange", mesh.ufl_cell(), 1) W = FunctionSpace(mesh, W0 * W1) L0 = W.sub(0) L1 = W.sub(1) L01 = L1.sub(0) L11 = L1.sub(1) for i in range(mesh.num_cells()): dofs0 = L0.dofmap.cell_dofs(i) dofs1 = L01.dofmap.cell_dofs(i) dofs2 = L11.dofmap.cell_dofs(i) dofs3 = L1.dofmap.cell_dofs(i) assert len(np.intersect1d(dofs0, dofs1)) == 0 assert len(np.intersect1d(dofs0, dofs2)) == 0 assert len(np.intersect1d(dofs1, dofs2)) == 0 assert np.array_equal(np.append(dofs1, dofs2), dofs3)
def test_tabulate_coord_periodic(mesh_factory): def periodic_boundary(x): return x[0] < np.finfo(float).eps func, args = mesh_factory mesh = func(*args) V = FiniteElement("Lagrange", mesh.ufl_cell(), 1) Q = VectorElement("Lagrange", mesh.ufl_cell(), 1) W = V * Q V = FunctionSpace(mesh, V, constrained_domain=periodic_boundary) W = FunctionSpace(mesh, W, constrained_domain=periodic_boundary) L0 = W.sub(0) L1 = W.sub(1) L01 = L1.sub(0) L11 = L1.sub(1) sdim = V.element.space_dimension() coord0 = np.zeros((sdim, 2), dtype="d") coord1 = np.zeros((sdim, 2), dtype="d") coord2 = np.zeros((sdim, 2), dtype="d") coord3 = np.zeros((sdim, 2), dtype="d") map = mesh.topology.index_map(mesh.topology.dim) num_cells = map.size_local + map.num_ghosts for i in range(num_cells): cell = MeshEntity(mesh, mesh.topology.dim, i) coord0 = V.element.tabulate_dof_coordinates(cell) coord1 = L0.element.tabulate_dof_coordinates(cell) coord2 = L01.element.tabulate_dof_coordinates(cell) coord3 = L11.element.tabulate_dof_coordinates(cell) coord4 = L1.element.tabulate_dof_coordinates(cell) assert (coord0 == coord1).all() assert (coord0 == coord2).all() assert (coord0 == coord3).all() assert (coord4[:sdim] == coord0).all() assert (coord4[sdim:] == coord0).all()
def test_tabulate_dofs(mesh_factory): func, args = mesh_factory mesh = func(*args) W0 = FiniteElement("Lagrange", mesh.ufl_cell(), 1) W1 = VectorElement("Lagrange", mesh.ufl_cell(), 1) W = FunctionSpace(mesh, W0 * W1) L0 = W.sub(0) L1 = W.sub(1) L01 = L1.sub(0) L11 = L1.sub(1) map = mesh.topology.index_map(mesh.topology.dim) num_cells = map.size_local + map.num_ghosts for c in range(num_cells): dofs0 = L0.dofmap.cell_dofs(c) dofs1 = L01.dofmap.cell_dofs(c) dofs2 = L11.dofmap.cell_dofs(c) dofs3 = L1.dofmap.cell_dofs(c) assert len(np.intersect1d(dofs0, dofs1)) == 0 assert len(np.intersect1d(dofs0, dofs2)) == 0 assert len(np.intersect1d(dofs1, dofs2)) == 0 assert np.array_equal(np.append(dofs1, dofs2), dofs3)
def test_clear_sub_map_data_scalar(mesh): V = FunctionSpace(mesh, ("CG", 2)) with pytest.raises(ValueError): V.sub(1) V = VectorFunctionSpace(mesh, ("CG", 2)) V1 = V.sub(1) assert (V1) # Clean sub-map data V.dofmap.clear_sub_map_data() # Can still get previously computed map V1 = V.sub(1) # New sub-map should throw an error with pytest.raises(RuntimeError): V.sub(0)
print("(C) Norm of velocity coefficient vector (blocked, direct): {}".format(norm_u_2)) print("(C) Norm of pressure coefficient vector (blocked, direct): {}".format(norm_p_2)) assert np.isclose(norm_u_2, norm_u_0) assert np.isclose(norm_p_2, norm_p_0) # Non-blocked direct solver # ^^^^^^^^^^^^^^^^^^^^^^^^^ # # Again, solve the same problem but this time with a non-blocked direct # solver approach # Create the function space TH = P2 * P1 W = FunctionSpace(mesh, TH) W0 = W.sub(0).collapse() # No slip boundary condition noslip = Function(V) facets = locate_entities_boundary(mesh, 1, noslip_boundary) dofs = locate_dofs_topological((W.sub(0), V), 1, facets) bc0 = DirichletBC(noslip, dofs, W.sub(0)) # Driving velocity condition u = (1, 0) on top boundary (y = 1) lid_velocity = Function(W0) lid_velocity.interpolate(lid_velocity_expression) facets = locate_entities_boundary(mesh, 1, lid) dofs = locate_dofs_topological((W.sub(0), V), 1, facets) bc1 = DirichletBC(lid_velocity, dofs, W.sub(0))
if MPI.COMM_WORLD.rank == 0: print("(C) Norm of velocity coefficient vector: {}".format(norm_u_2)) print("(C) Norm of pressure coefficient vector: {}".format(norm_p_2)) assert np.isclose(norm_u_2, norm_u_0) assert np.isclose(norm_p_2, norm_p_0) # Non-blocked direct solver # ^^^^^^^^^^^^^^^^^^^^^^^^^ # # Again, solve the same problem but this time with a non-blocked direct # solver approach # Create the function space TH = P2 * P1 W = FunctionSpace(mesh, TH) W0 = W.sub(0).collapse() # No slip boundary condition noslip = Function(W0) facets = locate_entities_boundary(mesh, 1, noslip_boundary) dofs = locate_dofs_topological((W.sub(0), V), 1, facets) bc0 = DirichletBC(noslip, dofs, W.sub(0)) # Driving velocity condition u = (1, 0) on top boundary (y = 1) lid_velocity = Function(W0) lid_velocity.interpolate(lid_velocity_expression) facets = locate_entities_boundary(mesh, 1, lid) dofs = locate_dofs_topological((W.sub(0), V), 1, facets) bc1 = DirichletBC(lid_velocity, dofs, W.sub(0)) # Since for this problem the pressure is only determined up to a constant,
def test_biharmonic(): """Manufactured biharmonic problem. Solved using rotated Regge mixed finite element method. This is equivalent to the Hellan-Herrmann-Johnson (HHJ) finite element method in two-dimensions.""" mesh = RectangleMesh(MPI.COMM_WORLD, [np.array([0.0, 0.0, 0.0]), np.array([1.0, 1.0, 0.0])], [32, 32], CellType.triangle) element = ufl.MixedElement([ufl.FiniteElement("Regge", ufl.triangle, 1), ufl.FiniteElement("Lagrange", ufl.triangle, 2)]) V = FunctionSpace(mesh, element) sigma, u = ufl.TrialFunctions(V) tau, v = ufl.TestFunctions(V) x = ufl.SpatialCoordinate(mesh) u_exact = ufl.sin(ufl.pi * x[0]) * ufl.sin(ufl.pi * x[0]) * ufl.sin(ufl.pi * x[1]) * ufl.sin(ufl.pi * x[1]) f_exact = div(grad(div(grad(u_exact)))) sigma_exact = grad(grad(u_exact)) # sigma and tau are tangential-tangential continuous according to the # H(curl curl) continuity of the Regge space. However, for the biharmonic # problem we require normal-normal continuity H (div div). Theorem 4.2 of # Lizao Li's PhD thesis shows that the latter space can be constructed by # the former through the action of the operator S: def S(tau): return tau - ufl.Identity(2) * ufl.tr(tau) sigma_S = S(sigma) tau_S = S(tau) # Discrete duality inner product eq. 4.5 Lizao Li's PhD thesis def b(tau_S, v): n = FacetNormal(mesh) return inner(tau_S, grad(grad(v))) * dx \ - ufl.dot(ufl.dot(tau_S('+'), n('+')), n('+')) * jump(grad(v), n) * dS \ - ufl.dot(ufl.dot(tau_S, n), n) * ufl.dot(grad(v), n) * ds # Non-symmetric formulation a = inner(sigma_S, tau_S) * dx - b(tau_S, u) + b(sigma_S, v) L = inner(f_exact, v) * dx V_1 = V.sub(1).collapse() zero_u = Function(V_1) with zero_u.vector.localForm() as zero_u_local: zero_u_local.set(0.0) # Strong (Dirichlet) boundary condition boundary_facets = locate_entities_boundary( mesh, mesh.topology.dim - 1, lambda x: np.full(x.shape[1], True, dtype=bool)) boundary_dofs = locate_dofs_topological((V.sub(1), V_1), mesh.topology.dim - 1, boundary_facets) bcs = [DirichletBC(zero_u, boundary_dofs, V.sub(1))] A = assemble_matrix(a, bcs=bcs) A.assemble() b = assemble_vector(L) apply_lifting(b, [a], [bcs]) b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) # Solve solver = PETSc.KSP().create(MPI.COMM_WORLD) PETSc.Options()["ksp_type"] = "preonly" PETSc.Options()["pc_type"] = "lu" # PETSc.Options()["pc_factor_mat_solver_type"] = "mumps" solver.setFromOptions() solver.setOperators(A) x_h = Function(V) solver.solve(b, x_h.vector) x_h.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) # Recall that x_h has flattened indices. u_error_numerator = np.sqrt(mesh.mpi_comm().allreduce(assemble_scalar( inner(u_exact - x_h[4], u_exact - x_h[4]) * dx(mesh, metadata={"quadrature_degree": 5})), op=MPI.SUM)) u_error_denominator = np.sqrt(mesh.mpi_comm().allreduce(assemble_scalar( inner(u_exact, u_exact) * dx(mesh, metadata={"quadrature_degree": 5})), op=MPI.SUM)) assert(np.absolute(u_error_numerator / u_error_denominator) < 0.05) # Reconstruct tensor from flattened indices. # Apply inverse transform. In 2D we have S^{-1} = S. sigma_h = S(ufl.as_tensor([[x_h[0], x_h[1]], [x_h[2], x_h[3]]])) sigma_error_numerator = np.sqrt(mesh.mpi_comm().allreduce(assemble_scalar( inner(sigma_exact - sigma_h, sigma_exact - sigma_h) * dx(mesh, metadata={"quadrature_degree": 5})), op=MPI.SUM)) sigma_error_denominator = np.sqrt(mesh.mpi_comm().allreduce(assemble_scalar( inner(sigma_exact, sigma_exact) * dx(mesh, metadata={"quadrature_degree": 5})), op=MPI.SUM)) assert(np.absolute(sigma_error_numerator / sigma_error_denominator) < 0.005)
P1 = FiniteElement("Lagrange", mesh.ufl_cell(), 1) TH = P2 * P1 W = FunctionSpace(mesh, TH) # The mixed finite element space is known as Taylor–Hood. # It is a stable, standard element pair for the Stokes # equations. Now we can define boundary conditions:: # Extract subdomain facet arrays mf = sub_domains.values mf0 = np.where(mf == 0)[0] mf1 = np.where(mf == 1)[0] # No-slip boundary condition for velocity # x1 = 0, x1 = 1 and around the dolphin noslip = Function(W.sub(0).collapse()) noslip.interpolate(lambda x: np.zeros_like(x[:mesh.geometry.dim])) bdofs = locate_dofs_topological((W.sub(0), noslip.function_space), sub_domains.dim, mf0) bc0 = DirichletBC(noslip, bdofs, W.sub(0)) # Inflow boundary condition for velocity # x0 = 1 def inflow_eval(x): values = np.zeros((2, x.shape[1])) values[0] = -np.sin(x[1] * np.pi) return values