def test_dof_coords_3d(degree): mesh = create_unit_cube(MPI.COMM_WORLD, 10, 10, 10) V = FunctionSpace(mesh, ("Lagrange", degree)) u = Function(V) u.interpolate(lambda x: x[0]) u.x.scatter_forward() x = V.tabulate_dof_coordinates() val = u.vector.array for i in range(len(val)): assert np.isclose(x[i, 0], val[i], rtol=1e-3)
def rigid_motions_nullspace(V: _fem.FunctionSpace): """ Function to build nullspace for 2D/3D elasticity. Parameters: =========== V The function space """ _x = _fem.Function(V) # Get geometric dim gdim = V.mesh.geometry.dim assert gdim == 2 or gdim == 3 # Set dimension of nullspace dim = 3 if gdim == 2 else 6 # Create list of vectors for null space nullspace_basis = [_x.vector.copy() for _ in range(dim)] with ExitStack() as stack: vec_local = [stack.enter_context(x.localForm()) for x in nullspace_basis] basis = [np.asarray(x) for x in vec_local] dofs = [V.sub(i).dofmap.list.array for i in range(gdim)] # Build translational null space basis for i in range(gdim): basis[i][dofs[i]] = 1.0 # Build rotational null space basis x = V.tabulate_dof_coordinates() dofs_block = V.dofmap.list.array x0, x1, x2 = x[dofs_block, 0], x[dofs_block, 1], x[dofs_block, 2] if gdim == 2: basis[2][dofs[0]] = -x1 basis[2][dofs[1]] = x0 elif gdim == 3: basis[3][dofs[0]] = -x1 basis[3][dofs[1]] = x0 basis[4][dofs[0]] = x2 basis[4][dofs[2]] = -x0 basis[5][dofs[2]] = x1 basis[5][dofs[1]] = -x2 _la.orthonormalize(nullspace_basis) assert _la.is_orthonormal(nullspace_basis) return PETSc.NullSpace().create(vectors=nullspace_basis)
def gather_dof_coordinates(V: FunctionSpace, dofs: np.ndarray): """ Distributes the dof coordinates of this subset of dofs to all processors """ x = V.tabulate_dof_coordinates() local_dofs = dofs[dofs < V.dofmap.index_map.size_local * V.dofmap.index_map_bs] coords = x[local_dofs] num_nodes = len(coords) glob_num_nodes = MPI.COMM_WORLD.allreduce(num_nodes, op=MPI.SUM) recvbuf = None if MPI.COMM_WORLD.rank == 0: recvbuf = np.zeros(3 * glob_num_nodes, dtype=np.float64) sendbuf = coords.reshape(-1) sendcounts = np.array(MPI.COMM_WORLD.gather(len(sendbuf), 0)) MPI.COMM_WORLD.Gatherv(sendbuf, (recvbuf, sendcounts), root=0) glob_coords = MPI.COMM_WORLD.bcast(recvbuf, root=0).reshape((-1, 3)) return glob_coords
def _(V: fem.FunctionSpace, entities=None): """Creates a VTK mesh topology (topology array and array of cell types) that is based on the degree-of-freedom coordinates. Note that this function supports Lagrange elements (continuous and discontinuous) only. """ family = V.ufl_element().family() if not (family in ['Discontinuous Lagrange', "Lagrange", "DQ", "Q"]): raise RuntimeError( "Can only create meshes from Continuous or Discontinuous function-spaces" ) if V.ufl_element().degree() == 0: raise RuntimeError("Cannot create topology from cellwise constants.") mesh = V.mesh if entities is None: num_cells = mesh.topology.index_map(mesh.topology.dim).size_local entities = np.arange(num_cells, dtype=np.int32) else: num_cells = entities.size dofmap = V.dofmap num_dofs_per_cell = V.dofmap.dof_layout.num_dofs degree = V.ufl_element().degree() cell_type = mesh.topology.cell_type perm = np.argsort(_cpp.io.perm_vtk(cell_type, num_dofs_per_cell)) if degree == 1: cell_types = np.full(num_cells, _first_order_vtk[mesh.topology.cell_type]) else: warnings.warn("Plotting of higher order functions is experimental.") cell_types = np.full( num_cells, _cpp.io.get_vtk_cell_type(mesh, mesh.topology.dim)) topology = np.zeros((num_cells, num_dofs_per_cell + 1), dtype=np.int32) topology[:, 0] = num_dofs_per_cell dofmap_ = dofmap.list.array.reshape(dofmap.list.num_nodes, num_dofs_per_cell) topology[:, 1:] = dofmap_[:num_cells, perm] return topology.reshape(1, -1)[0], cell_types, V.tabulate_dof_coordinates()
def _(V: fem.FunctionSpace, entities=None): """Creates a VTK mesh topology (topology array and array of cell types) that is based on the degree-of-freedom coordinates. Note that this function supports Lagrange elements (continuous and discontinuous) only. """ if not (V.ufl_element().family() in ['Discontinuous Lagrange', "Lagrange", "DQ", "Q"]): raise RuntimeError( "Can only create meshes from continuous or discontinuous Lagrange spaces" ) degree = V.ufl_element().degree() if degree == 0: raise RuntimeError("Cannot create topology from cellwise constants.") # Use all local cells if not supplied msh = V.mesh tdim = msh.topology.dim if entities is None: entities = range(msh.topology.index_map(tdim).size_local) dofmap = V.dofmap num_dofs_per_cell = V.dofmap.dof_layout.num_dofs cell_type = msh.topology.cell_type perm = np.argsort(_cpp.io.perm_vtk(cell_type, num_dofs_per_cell)) vtk_type = _first_order_vtk[ cell_type] if degree == 1 else _cpp.io.get_vtk_cell_type( cell_type, tdim) cell_types = np.full(len(entities), vtk_type) topology = np.zeros((len(entities), num_dofs_per_cell + 1), dtype=np.int32) topology[:, 0] = num_dofs_per_cell dofmap_ = dofmap.list.array.reshape(dofmap.list.num_nodes, num_dofs_per_cell) topology[:, 1:] = dofmap_[:len(entities), perm] return topology.reshape(1, -1)[0], cell_types, V.tabulate_dof_coordinates()
def test_locate_dofs_geometrical(): """Test that locate_dofs_geometrical, when passed two function spaces, returns the correct degrees of freedom in each space""" 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) W = FunctionSpace(mesh, P0 * P1) V = W.sub(0).collapse()[0] with pytest.raises(RuntimeError): locate_dofs_geometrical( W, lambda x: np.isclose(x.T, [0, 0, 0]).all(axis=1)) dofs = locate_dofs_geometrical( (W.sub(0), V), lambda x: np.isclose(x.T, [0, 0, 0]).all(axis=1)) # Collect dofs (global indices) from all processes dofs0_global = W.sub(0).dofmap.index_map.local_to_global(dofs[0]) dofs1_global = V.dofmap.index_map.local_to_global(dofs[1]) all_dofs0 = set(np.concatenate(MPI.COMM_WORLD.allgather(dofs0_global))) all_dofs1 = set(np.concatenate(MPI.COMM_WORLD.allgather(dofs1_global))) # Check only one dof pair is found globally assert len(all_dofs0) == 1 assert len(all_dofs1) == 1 # On process with the dof pair if len(dofs) == 1: # Check correct dof returned in W coords_W = W.tabulate_dof_coordinates() assert np.isclose(coords_W[dofs[0][0]], [0, 0, 0]).all() # Check correct dof returned in V coords_V = V.tabulate_dof_coordinates() assert np.isclose(coords_V[dofs[0][1]], [0, 0, 0]).all()