def test_save_vtk_mixed(tempdir): mesh = create_unit_cube(MPI.COMM_WORLD, 3, 3, 3) P2 = ufl.VectorElement("Lagrange", mesh.ufl_cell(), 1) P1 = ufl.FiniteElement("Lagrange", mesh.ufl_cell(), 1) W = FunctionSpace(mesh, P2 * P1) V1 = FunctionSpace(mesh, P1) V2 = FunctionSpace(mesh, P2) U = Function(W) U.sub(0).interpolate(lambda x: np.vstack((x[0], 0.2 * x[1], np.zeros_like(x[0])))) U.sub(1).interpolate(lambda x: 0.5 * x[0]) U1, U2 = Function(V1), Function(V2) U1.interpolate(U.sub(1)) U2.interpolate(U.sub(0)) U2.name = "u" U1.name = "p" filename = os.path.join(tempdir, "u.pvd") with VTKFile(mesh.comm, filename, "w") as vtk: vtk.write_function([U2, U1], 0.) with VTKFile(mesh.comm, filename, "w") as vtk: vtk.write_function([U1, U2], 0.) Up = U.sub(1) Up.name = "psub" with pytest.raises(RuntimeError): with VTKFile(mesh.comm, filename, "w") as vtk: vtk.write_function([U2, Up, U1], 0) with pytest.raises(RuntimeError): with VTKFile(mesh.comm, filename, "w") as vtk: vtk.write_function([U.sub(i) for i in range(W.num_sub_spaces)], 0)
def __init__(self, value, cell=None, name=None): """ Create constant-valued function with given value. *Arguments* value The value may be either a single scalar value, or a tuple/list of values for vector-valued functions, or nested lists or a numpy array for tensor-valued functions. cell Optional argument. A :py:class:`Cell <ufl.Cell>` which defines the geometrical dimensions the Constant is defined for. name Optional argument. A str which overrules the default name of the Constant. The data type Constant represents a constant value that is unknown at compile-time. Its values can thus be changed without requiring re-generation and re-compilation of C++ code. *Examples of usage* .. code-block:: python p = Constant(pi/4) # scalar C = Constant((0.0, -1.0, 0.0)) # constant vector """ # TODO: Either take mesh instead of cell, or drop cell and let # grad(c) be undefined. if cell is not None: cell = ufl.as_cell(cell) ufl_domain = None array = numpy.array(value) rank = len(array.shape) floats = list(map(float, array.flat)) # Create UFL element and initialize constant if rank == 0: ufl_element = ufl.FiniteElement("Real", cell, 0) cpp.Constant.__init__(self, floats[0]) elif rank == 1: ufl_element = ufl.VectorElement("Real", cell, 0, dim=len(floats)) cpp.Constant.__init__(self, floats) else: ufl_element = ufl.TensorElement("Real", cell, 0, shape=array.shape) cpp.Constant.__init__(self, list(array.shape), floats) # Initialize base classes ufl_function_space = ufl.FunctionSpace(ufl_domain, ufl_element) ufl.Coefficient.__init__(self, ufl_function_space, count=self.id()) # Set name as given or automatic name = name or "f_%d" % self.count() self.rename(name, "a Constant")
def RectangleMesh(comm, points: typing.List[numpy.array], n: list, cell_type=cpp.mesh.CellType.triangle, ghost_mode=cpp.mesh.GhostMode.shared_facet, diagonal: str = "right"): """Create rectangle mesh Parameters ---------- comm MPI communicator points List of `Points` representing vertices n List of number of cells in each direction diagonal Direction of diagonal """ domain = ufl.Mesh( ufl.VectorElement("Lagrange", cpp.mesh.to_string(cell_type), 1)) cmap = fem.create_coordinate_map(comm, domain) mesh = cpp.generation.RectangleMesh.create(comm, points, n, cmap, ghost_mode, diagonal) domain._ufl_cargo = mesh mesh._ufl_domain = domain return mesh
def __init__(self, element): cell = element.cell() degree = element.degree() family = lambda c: "DG" if c.is_simplex() else "DQ" if isinstance(cell, ufl.TensorProductCell): scalar_element = ufl.TensorProductElement( *(ufl.FiniteElement(family(c), cell=c, degree=d) for (c, d) in zip(cell.sub_cells(), degree))) else: scalar_element = ufl.FiniteElement(family(cell), cell=cell, degree=degree) shape = element.value_shape() if len(shape) == 0: DG = scalar_element elif len(shape) == 1: shape, = shape DG = ufl.VectorElement(scalar_element, dim=shape) else: DG = ufl.TensorElement(scalar_element, shape=shape) self.embedding_element = DG self._V_DG_mass = {} self._DG_inv_mass = {} self._V_approx_inv_mass = {} self._V_inv_mass_ksp = {} self._DG_work = {} self._work_vec = {} self._V_dof_weights = {}
def monolithic_solve(): """Monolithic (interleaved) solver""" P2_el = ufl.VectorElement("Lagrange", mesh.ufl_cell(), 2) P1_el = ufl.FiniteElement("Lagrange", mesh.ufl_cell(), 1) TH = P2_el * P1_el W = dolfinx.FunctionSpace(mesh, TH) (u, p) = ufl.TrialFunctions(W) (v, q) = ufl.TestFunctions(W) a00 = ufl.inner(ufl.grad(u), ufl.grad(v)) * dx a01 = ufl.inner(p, ufl.div(v)) * dx a10 = ufl.inner(ufl.div(u), q) * dx a = a00 + a01 + a10 p00 = ufl.inner(ufl.grad(u), ufl.grad(v)) * dx p11 = ufl.inner(p, q) * dx p_form = p00 + p11 f = dolfinx.Function(W.sub(0).collapse()) p_zero = dolfinx.Function(W.sub(1).collapse()) L0 = inner(f, v) * dx L1 = inner(p_zero, q) * dx L = L0 + L1 bdofsW0_P2_0 = dolfinx.fem.locate_dofs_topological( (W.sub(0), P2), facetdim, bndry_facets0) bdofsW0_P2_1 = dolfinx.fem.locate_dofs_topological( (W.sub(0), P2), facetdim, bndry_facets1) bc0 = dolfinx.DirichletBC(u0, bdofsW0_P2_0, W.sub(0)) bc1 = dolfinx.DirichletBC(u0, bdofsW0_P2_1, W.sub(0)) A = dolfinx.fem.assemble_matrix(a, [bc0, bc1]) A.assemble() P = dolfinx.fem.assemble_matrix(p_form, [bc0, bc1]) P.assemble() b = dolfinx.fem.assemble_vector(L) dolfinx.fem.apply_lifting(b, [a], [[bc0, bc1]]) b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) dolfinx.fem.set_bc(b, [bc0, bc1]) ksp = PETSc.KSP() ksp.create(mesh.mpi_comm()) ksp.setOperators(A, P) ksp.setType("minres") pc = ksp.getPC() pc.setType('lu') def monitor(ksp, its, rnorm): # print("Num it, rnorm:", its, rnorm) pass ksp.setTolerances(rtol=1.0e-8, max_it=50) ksp.setMonitor(monitor) ksp.setFromOptions() x = A.createVecRight() ksp.solve(b, x) assert ksp.getConvergedReason() > 0 return b.norm(), x.norm(), A.norm(), P.norm()
def test_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 VectorFunctionSpace(mesh, family, degree=None, dim=None, name=None, vfamily=None, vdegree=None): """Create a rank-1 :class:`.FunctionSpace`. :arg mesh: The mesh to determine the cell from. :arg family: The finite element family. :arg degree: The degree of the finite element. :arg dim: An optional number of degrees of freedom per function space node (defaults to the geometric dimension of the mesh). :arg name: An optional name for the function space. :arg vfamily: The finite element in the vertical dimension (extruded meshes only). :arg vdegree: The degree of the element in the vertical dimension (extruded meshes only). The ``family`` argument may be an existing :class:`ufl.FiniteElementBase`, in which case all other arguments are ignored and the appropriate :class:`.FunctionSpace` is returned. In this case, the provided element must have an empty :meth:`ufl.FiniteElementBase.value_shape`. .. note:: The element that you provide need be a scalar element (with empty ``value_shape``), however, it should not be an existing :class:`~ufl.classes.VectorElement`. If you already have an existing :class:`~ufl.classes.VectorElement`, you should pass it to :func:`FunctionSpace` directly instead. """ sub_element = make_scalar_element(mesh, family, degree, vfamily, vdegree) dim = dim or mesh.ufl_cell().geometric_dimension() element = ufl.VectorElement(sub_element, dim=dim) return FunctionSpace(mesh, element, name=name)
def test_cmap_triangle(degree, compile_args): """Test triangle cell.""" cell = ufl.triangle element = ufl.VectorElement("Lagrange", cell, degree) mesh = ufl.Mesh(element) compiled_cmap, module = ffcx.codegeneration.jit.compile_coordinate_maps( [mesh], cffi_extra_compile_args=compile_args, cache_dir=".") assert compiled_cmap[0].is_affine == (1 if (degree == 1) else 0) assert compiled_cmap[0].geometric_dimension == 2 assert compiled_cmap[0].topological_dimension == 2 # Reference coordinates X to basis phi = np.zeros(((degree + 2) * (degree + 1)) // 2, dtype=np.float64) phi_ptr = module.ffi.cast("double *", module.ffi.from_buffer(phi)) X = np.array([[1 / 3, 1 / 3]], dtype=np.float64) X_ptr = module.ffi.cast("double *", module.ffi.from_buffer(X)) compiled_cmap[0].evaluate_basis_derivatives(phi_ptr, 0, X.shape[0], X_ptr) assert np.isclose(sum(phi), 1.0) num_entity_dofs = compiled_cmap[0].create_scalar_dofmap().num_entity_dofs assert num_entity_dofs[0] == 1 assert num_entity_dofs[2] == 0 assert num_entity_dofs[3] == 0 if degree == 1: assert num_entity_dofs[1] == 0 elif degree == 2: assert num_entity_dofs[1] == 1
def test_cmap_hex(degree, compile_args): """Test hexahedron cell""" # Assuming FIAT Tensor Product layout of cell. cell = ufl.hexahedron e = ufl.VectorElement("Lagrange", cell, degree) mesh = ufl.Mesh(e) compiled_cmap, module = ffcx.codegeneration.jit.compile_coordinate_maps( [mesh], cffi_extra_compile_args=compile_args) assert compiled_cmap[0].is_affine == 0 assert compiled_cmap[0].geometric_dimension == 3 assert compiled_cmap[0].topological_dimension == 3 # Reference coordinates X to basis phi = np.zeros((degree + 1)**3, dtype=np.float64) phi_ptr = module.ffi.cast("double *", module.ffi.from_buffer(phi)) X = np.array([[0.5, 0.5, 0.5]], dtype=np.float64) X_ptr = module.ffi.cast("double *", module.ffi.from_buffer(X)) compiled_cmap[0].evaluate_basis_derivatives(phi_ptr, 0, X.shape[0], X_ptr) assert np.isclose(sum(phi), 1.0) num_entity_dofs = compiled_cmap[0].create_scalar_dofmap().num_entity_dofs assert num_entity_dofs[0] == 1 if degree == 1: assert num_entity_dofs[1] == 0 assert num_entity_dofs[2] == 0 assert num_entity_dofs[3] == 0 elif degree == 2: assert num_entity_dofs[1] == 1 assert num_entity_dofs[2] == 1 assert num_entity_dofs[3] == 1
def __init__(self, mesh, family, degree, dim=None, form_degree=None, constrained_domain=None, restriction=None): """Create vector-valued finite element function space. Use VectorFunctionSpace if the unknown is a vector field, instead of a :py:class:`FunctionSpace <dolfin.functions.functionspace.FunctionSpace>` object for scalar fields. *Arguments* mesh (:py:class:`Mesh <dolfin.cpp.Mesh>`) the mesh family (string) a string specifying the element family, see :py:class:`FunctionSpace <dolfin.functions.functionspace.FunctionSpace>` for alternatives. degree (int) the (polynomial) degree of the element. dim (int) an optional argument specifying the number of components. form_degree (int) an optional argument specifying the degree of the k-form (used for FEEC notation) If the dim argument is not provided, the dimension will be deduced from the dimension of the mesh. *Example of usage* .. code-block:: python V = VectorFunctionSpace(mesh, "CG", 1) """ # Get Mesh or Restriction from Domain or Domain from Mesh or # Restriction ufl_domain, mesh = _analyse_mesh_argument(mesh) # Create element element = ufl.VectorElement(family, ufl_domain, degree, dim=dim, form_degree=form_degree) if restriction is not None: element = element[restriction] # Initialize base class FunctionSpaceBase.__init__(self, mesh, element, constrained_domain=constrained_domain)
def test_save_2d_mixed(tempdir): mesh = UnitCubeMesh(MPI.COMM_WORLD, 3, 3, 3) P2 = ufl.VectorElement("Lagrange", mesh.ufl_cell(), 2) P1 = ufl.FiniteElement("Lagrange", mesh.ufl_cell(), 1) TH = P2 * P1 W = FunctionSpace(mesh, TH) def vec_func(x): vals = np.zeros((3, x.shape[1])) vals[0] = x[0] vals[1] = 0.2 * x[1] return vals def scal_func(x): return 0.5 * x[0] U = Function(W) U.sub(0).interpolate(vec_func) U.sub(1).interpolate(scal_func) U.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) filename = os.path.join(tempdir, "u.pvd") with VTKFile(mesh.mpi_comm(), filename, "w") as vtk: vtk.write_function([U.sub(i) for i in range(W.num_sub_spaces())], 0.)
def test_collision_2nd_order_triangle(): points = np.array([[0, 0], [1, 0], [0, 1], [0.65, 0.65], [0, 0.5], [0.5, 0]]) cells = np.array([[0, 1, 2, 3, 4, 5]]) cell = ufl.Cell("triangle", geometric_dimension=2) domain = ufl.Mesh(ufl.VectorElement("Lagrange", cell, 2)) mesh = create_mesh(MPI.COMM_WORLD, cells, points, domain) # Sample points along an interior line of the domain. The last point # is outside the simplex made by the vertices. sample_points = np.array([[0.1, 0.3, 0], [0.2, 0.5, 0], [0.6, 0.6, 0]]) # Create boundingboxtree tree = geometry.BoundingBoxTree(mesh, mesh.geometry.dim) for point in sample_points: colliding_cell = geometry.compute_colliding_cells(tree, mesh, point, 1) assert(len(colliding_cell) == 1) # Check if there is a point on the linear approximation of the # curved facet def line_through_points(p0, p1): return lambda x: (p1[1] - p0[1]) / (p1[0] - p0[0]) * (x - p0[0]) + p0[1] line_func = line_through_points(points[2], points[3]) point = np.array([0.2, line_func(0.2), 0]) # Point inside 2nd order geometry, outside linear approximation # Usefull for debugging on a later stage # point = np.array([0.25, 0.89320760, 0]) distance = cpp.geometry.squared_distance(mesh, mesh.topology.dim - 1, 2, point) assert np.isclose(distance, 0)
def test_mixed_interpolation(cell_type, order): """Test that interpolation is correct in a MixedElement.""" mesh = one_cell_mesh(cell_type) tdim = mesh.topology.dim A = ufl.FiniteElement("Lagrange", mesh.ufl_cell(), order) B = ufl.VectorElement("Lagrange", mesh.ufl_cell(), order) V = FunctionSpace(mesh, ufl.MixedElement([A, B])) v = Function(V) if tdim == 1: def f(x): return (x[0]**order, 2 * x[0]) elif tdim == 2: def f(x): return (x[1], 2 * x[0]**order, 3 * x[1]) else: def f(x): return (x[1], 2 * x[0]**order, 3 * x[2], 4 * x[0]) v.interpolate(f) points = [random_point_in_cell(cell_type) for count in range(5)] cells = [0 for count in range(5)] values = v.eval(points, cells) for p, v in zip(points, values): assert np.allclose(v, f(p))
def test_vector_element(compile_args): ufl_element = ufl.VectorElement("Lagrange", ufl.triangle, 1) jit_compiled_elements, module, code = ffcx.codegeneration.jit.compile_elements( [ufl_element], cffi_extra_compile_args=compile_args) ufc_element, ufc_dofmap = jit_compiled_elements[0] assert ufc_element.topological_dimension == 2 assert ufc_element.geometric_dimension == 2 assert ufc_element.space_dimension == 6 assert ufc_element.value_rank == 1 assert ufc_element.value_shape[0] == 2 assert ufc_element.value_size == 2 assert ufc_element.reference_value_rank == 1 assert ufc_element.reference_value_shape[0] == 2 assert ufc_element.reference_value_size == 2 assert ufc_element.block_size == 2 assert ufc_element.num_sub_elements == 2 assert ufc_dofmap.block_size == 2 assert ufc_dofmap.num_global_support_dofs == 0 assert ufc_dofmap.num_global_support_dofs == 0 assert ufc_dofmap.num_element_support_dofs == 3 assert ufc_dofmap.num_entity_dofs[0] == 1 assert ufc_dofmap.num_entity_dofs[1] == 0 assert ufc_dofmap.num_entity_dofs[2] == 0 assert ufc_dofmap.num_entity_dofs[3] == 0 for v in range(3): vals = np.zeros(1, dtype=np.int32) vals_ptr = module.ffi.cast("int *", module.ffi.from_buffer(vals)) ufc_dofmap.tabulate_entity_dofs(vals_ptr, 0, v) assert vals[0] == v assert ufc_dofmap.num_sub_dofmaps == 2
def create_rectangle(comm: _MPI.Comm, points: typing.List[np.array], n: list, cell_type=CellType.triangle, ghost_mode=GhostMode.shared_facet, partitioner=_cpp.mesh.create_cell_partitioner(), diagonal: DiagonalType = DiagonalType.right) -> Mesh: """Create rectangle mesh Args: comm: MPI communicator points: Coordinates of the lower-left and upper-right corners of the rectangle n: Number of cells in each direction cell_type: Mesh cell type ghost_mode: Ghost mode used in the mesh partitioning partitioner: Function that computes the parallel distribution of cells across MPI ranks diagonal: Direction of diagonal of triangular meshes. The options are ``left``, ``right``, ``crossed``, ``left/right``, ``right/left``. Returns: A mesh of a rectangle """ domain = ufl.Mesh(ufl.VectorElement("Lagrange", cell_type.name, 1)) mesh = _cpp.mesh.create_rectangle(comm, points, n, cell_type, ghost_mode, partitioner, diagonal) return Mesh.from_cpp(mesh, domain)
def test_triangle_mesh(order): points = [] points += [[i / order, 0] for i in range(order + 1)] for j in range(1, order): points += [[i / order + 0.1, j / order] for i in range(order + 1 - j)] points += [[0, 1]] def coord_to_vertex(x, y): return y * (2 * order + 3 - y) // 2 + x # Define a cell using dolfin ordering cell = [coord_to_vertex(i, j) for i, j in [(0, 0), (order, 0), (0, order)]] if order > 1: for i in range(1, order): cell.append(coord_to_vertex(order - i, i)) for i in range(1, order): cell.append(coord_to_vertex(0, i)) for i in range(1, order): cell.append(coord_to_vertex(i, 0)) for j in range(1, order): for i in range(1, order - j): cell.append(coord_to_vertex(i, j)) domain = ufl.Mesh( ufl.VectorElement("Lagrange", ufl.Cell("triangle", geometric_dimension=2), order)) check_cell_volume(points, cell, domain, 0.5)
def create_box( comm: _MPI.Comm, points: typing.List[np.array], n: list, cell_type=CellType.tetrahedron, ghost_mode=GhostMode.shared_facet, partitioner=_cpp.mesh.create_cell_partitioner() ) -> Mesh: """Create box mesh Args: comm: MPI communicator points: Coordinates of the 'lower-left' and 'upper-right' corners of the box n: List of cells in each direction cell_type: The cell type ghost_mode: The ghost mode used in the mesh partitioning partitioner: Function that computes the parallel distribution of cells across MPI ranks Returns: A mesh of a box domain """ domain = ufl.Mesh(ufl.VectorElement("Lagrange", cell_type.name, 1)) mesh = _cpp.mesh.create_box(comm, points, n, cell_type, ghost_mode, partitioner) return Mesh.from_cpp(mesh, domain)
def test_volume_quadrilateralR3(coordinates): x = numpy.array(coordinates, dtype=numpy.float64) cells = numpy.array([[0, 1, 2, 3]], dtype=numpy.int32) domain = ufl.Mesh(ufl.VectorElement("Lagrange", "quadrilateral", 1)) mesh = create_mesh(MPI.COMM_SELF, cells, x, domain) mesh.topology.create_connectivity_all() assert cpp.mesh.volume_entities(mesh, [0], mesh.topology.dim) == 1.0
def one_cell_mesh(cell_type): if cell_type == CellType.interval: points = np.array([[-1.], [2.]]) if cell_type == CellType.triangle: points = np.array([[-1., -1.], [2., 0.], [0., 0.5]]) elif cell_type == CellType.tetrahedron: points = np.array([[-1., -1., -1.], [2., 0., 0.], [0., 0.5, 0.], [0., 0., 1.]]) elif cell_type == CellType.quadrilateral: points = np.array([[-1., 0.], [1., 0.], [-1., 1.5], [1., 1.5]]) elif cell_type == CellType.hexahedron: points = np.array([[-1., -0.5, 0.], [1., -0.5, 0.], [-1., 1.5, 0.], [1., 1.5, 0.], [0., -0.5, 1.], [1., -0.5, 1.], [-1., 1.5, 1.], [1., 1.5, 1.]]) num_points = len(points) # Randomly number the points and create the mesh order = list(range(num_points)) random.shuffle(order) ordered_points = np.zeros(points.shape) for i, j in enumerate(order): ordered_points[j] = points[i] cells = np.array([order]) domain = ufl.Mesh(ufl.VectorElement("Lagrange", cpp.mesh.to_string(cell_type), 1)) mesh = create_mesh(MPI.COMM_WORLD, cells, ordered_points, domain) mesh.topology.create_connectivity_all() return mesh
def create_submesh(mesh, dim, entities): submesh, vertex_map, geom_map = _cpp.mesh.create_submesh(mesh, dim, entities) submesh_ufl_cell = ufl.Cell(submesh.topology.cell_name(), geometric_dimension=submesh.geometry.dim) # FIXME Don't hard code degree (and maybe Lagrange?) submesh_domain = ufl.Mesh(ufl.VectorElement("Lagrange", cell=submesh_ufl_cell, degree=1)) return (Mesh.from_cpp(submesh, submesh_domain), vertex_map, geom_map)
def BoxMesh(comm, points: typing.List[numpy.array], n: list, cell_type=cpp.mesh.CellType.tetrahedron, ghost_mode=cpp.mesh.GhostMode.shared_facet, partitioner=cpp.mesh.partition_cells_graph): """Create box mesh Parameters ---------- comm MPI communicator points List of points representing vertices n List of cells in each direction """ domain = ufl.Mesh( ufl.VectorElement("Lagrange", cpp.mesh.to_string(cell_type), 1)) mesh = cpp.generation.create_box_mesh(comm, points, n, cell_type, ghost_mode, partitioner) domain._ufl_cargo = mesh mesh._ufl_domain = domain return mesh
def xtest_tetrahedron_integral(space_type, space_order): domain = ufl.Mesh(ufl.VectorElement("Lagrange", "tetrahedron", 1)) temp_points = np.array([[-1., 0., -1.], [0., 0., 0.], [1., 0., 1.], [0., 1., 0.], [0., 0., 1.]]) for repeat in range(10): order = [i for i, j in enumerate(temp_points)] shuffle(order) points = np.zeros(temp_points.shape) for i, j in enumerate(order): points[j] = temp_points[i] cells = [] for cell in [[0, 1, 3, 4], [1, 2, 3, 4]]: # Randomly number the cell cell_order = list(range(4)) shuffle(cell_order) cells.append([order[cell[i]] for i in cell_order]) mesh = create_mesh(MPI.COMM_WORLD, cells, points, domain) V = FunctionSpace(mesh, (space_type, space_order)) Vvec = VectorFunctionSpace(mesh, ("P", 1)) dofs = [i for i in V.dofmap.cell_dofs(0) if i in V.dofmap.cell_dofs(1)] for d in dofs: v = Function(V) v.vector[:] = [1 if i == d else 0 for i in range(V.dim)] if space_type in ["RT", "BDM"]: # Hdiv def normal(x): values = np.zeros((3, x.shape[1])) values[0] = [1 for i in values[0]] return values n = Function(Vvec) n.interpolate(normal) form = ufl.inner(ufl.jump(v), n) * ufl.dS elif space_type in ["N1curl", "N2curl"]: # Hcurl def tangent1(x): values = np.zeros((3, x.shape[1])) values[1] = [1 for i in values[1]] return values def tangent2(x): values = np.zeros((3, x.shape[1])) values[2] = [1 for i in values[2]] return values t1 = Function(Vvec) t1.interpolate(tangent1) t2 = Function(Vvec) t2.interpolate(tangent1) form = ufl.inner(ufl.jump(v), t1) * ufl.dS form += ufl.inner(ufl.jump(v), t2) * ufl.dS else: form = ufl.jump(v) * ufl.dS value = fem.assemble_scalar(form) assert np.isclose(value, 0)
def test_assemble_manifold(): """Test assembly of poisson problem on a mesh with topological dimension 1 but embedded in 2D (gdim=2). """ points = numpy.array([[0.0, 0.0], [0.2, 0.0], [0.4, 0.0], [0.6, 0.0], [0.8, 0.0], [1.0, 0.0]], dtype=numpy.float64) cells = numpy.array([[0, 1], [1, 2], [2, 3], [3, 4], [4, 5]], dtype=numpy.int32) cell = ufl.Cell("interval", geometric_dimension=points.shape[1]) domain = ufl.Mesh(ufl.VectorElement("Lagrange", cell, 1)) mesh = create_mesh(MPI.COMM_WORLD, cells, points, domain) assert mesh.geometry.dim == 2 assert mesh.topology.dim == 1 U = dolfinx.FunctionSpace(mesh, ("P", 1)) u, v = ufl.TrialFunction(U), ufl.TestFunction(U) w = dolfinx.Function(U) a = ufl.inner(ufl.grad(u), ufl.grad(v)) * ufl.dx(mesh) L = ufl.inner(1.0, v) * ufl.dx(mesh) bcdofs = dolfinx.fem.locate_dofs_geometrical( U, lambda x: numpy.isclose(x[0], 0.0)) bcs = [dolfinx.DirichletBC(w, bcdofs)] A = dolfinx.fem.assemble_matrix(a, bcs) A.assemble() b = dolfinx.fem.assemble_vector(L) dolfinx.fem.apply_lifting(b, [a], [bcs]) dolfinx.fem.set_bc(b, bcs) assert numpy.isclose(b.norm(), 0.41231) assert numpy.isclose(A.norm(), 25.0199)
def _process_args(cls, mesh, family, degree=None, dim=None, vfamily=None, vdegree=None, **kwargs): # VectorFunctionSpace dimension defaults to the geometric dimension of the mesh. dim = dim or mesh.ufl_cell().geometric_dimension() if isinstance(mesh, mesh_t.ExtrudedMesh) and isinstance( family, ufl.OuterProductElement): element = ufl.OuterProductVectorElement(family, dim=dim) elif isinstance(mesh, mesh_t.ExtrudedMesh ) and vfamily is not None and vdegree is not None: la = ufl.FiniteElement(family, domain=mesh._old_mesh.ufl_cell(), degree=degree) lb = ufl.FiniteElement(vfamily, domain=ufl.Cell("interval", 1), degree=vdegree) element = ufl.OuterProductVectorElement(la, lb, dim=dim) else: element = ufl.VectorElement(family, domain=mesh.ufl_cell(), degree=degree, dim=dim) return (mesh, mesh, element), dict(kwargs, dim=dim)
def test_cmap_hex(degree, compile_args): """Test hexahedron cell""" cell = ufl.hexahedron e = ufl.VectorElement("Lagrange", cell, degree) mesh = ufl.Mesh(e) compiled_cmap, module = ffcx.codegeneration.jit.compile_coordinate_maps( [mesh], cffi_extra_compile_args=compile_args) assert compiled_cmap[0].is_affine == 0 assert compiled_cmap[0].geometric_dimension == 3 assert compiled_cmap[0].topological_dimension == 3 num_entity_dofs = compiled_cmap[0].create_scalar_dofmap().num_entity_dofs assert num_entity_dofs[0] == 1 if degree == 1: assert num_entity_dofs[1] == 0 assert num_entity_dofs[2] == 0 assert num_entity_dofs[3] == 0 elif degree == 2: assert num_entity_dofs[1] == 1 assert num_entity_dofs[2] == 1 assert num_entity_dofs[3] == 1
def create_boundary_mesh(mesh, comm, orient=False): """ Create a mesh consisting of all exterior facets of a mesh Input: mesh - The mesh comm - The MPI communicator orient - Boolean flag for reorientation of facets to have consistent outwards-pointing normal (default: True) Output: bmesh - The boundary mesh bmesh_to_geometry - Map from cells of the boundary mesh to the geometry of the original mesh """ ext_facets = cpp.mesh.exterior_facet_indices(mesh) boundary_geometry = cpp.mesh.entities_to_geometry(mesh, mesh.topology.dim - 1, ext_facets, orient) facet_type = cpp.mesh.to_string( cpp.mesh.cell_entity_type(mesh.topology.cell_type, mesh.topology.dim - 1)) facet_cell = ufl.Cell(facet_type, geometric_dimension=mesh.geometry.dim) degree = mesh.ufl_domain().ufl_coordinate_element().degree() ufl_domain = ufl.Mesh(ufl.VectorElement("Lagrange", facet_cell, degree)) bmesh = create_mesh(comm, boundary_geometry, mesh.geometry.x, ufl_domain) return bmesh, boundary_geometry
def read_mesh(self, ghost_mode=cpp.mesh.GhostMode.shared_facet, name="mesh", xpath="/Xdmf/Domain"): # Read mesh data from file cell_shape, cell_degree = super().read_cell_type(name, xpath) cells = super().read_topology_data(name, xpath) x = super().read_geometry_data(name, xpath) # Construct the geometry map cell = ufl.Cell(cpp.mesh.to_string(cell_shape), geometric_dimension=x.shape[1]) domain = ufl.Mesh(ufl.VectorElement("Lagrange", cell, cell_degree)) # Build the mesh cmap = cpp.fem.CoordinateElement(cell_shape, cell_degree) mesh = cpp.mesh.create_mesh(self.comm(), cpp.graph.AdjacencyList_int64(cells), cmap, x, ghost_mode, cpp.mesh.partition_cells_graph) mesh.name = name domain._ufl_cargo = mesh mesh._ufl_domain = domain return mesh
def create_interval( comm: _MPI.Comm, nx: int, points: list, ghost_mode=GhostMode.shared_facet, partitioner=_cpp.mesh.create_cell_partitioner() ) -> Mesh: """Create an interval mesh Args: comm: MPI communicator nx: Number of cells points: Coordinates of the end points ghost_mode: Ghost mode used in the mesh partitioning. Options are `GhostMode.none' and `GhostMode.shared_facet`. partitioner: Partitioning function to use for determining the parallel distribution of cells across MPI ranks Returns: An interval mesh """ domain = ufl.Mesh(ufl.VectorElement("Lagrange", "interval", 1)) mesh = _cpp.mesh.create_interval(comm, nx, points, ghost_mode, partitioner) return Mesh.from_cpp(mesh, domain)
def test_higher_order_coordinate_map(points, celltype, order): """Computes physical coordinates of a cell, based on the coordinate map.""" print(celltype) cells = np.array([range(len(points))]) domain = ufl.Mesh(ufl.VectorElement("Lagrange", cpp.mesh.to_string(celltype), order)) mesh = create_mesh(MPI.COMM_WORLD, cells, points, domain) V = FunctionSpace(mesh, ("Lagrange", 2)) X = V.element.interpolation_points() coord_dofs = mesh.geometry.dofmap x_g = mesh.geometry.x cmap = mesh.geometry.cmap x_coord_new = np.zeros([len(points), mesh.geometry.dim]) i = 0 for node in range(len(points)): x_coord_new[i] = x_g[coord_dofs.links(0)[node], :mesh.geometry.dim] i += 1 x = cmap.push_forward(X, x_coord_new) assert np.allclose(x[:, 0], X[:, 0]) assert np.allclose(x[:, 1], 2 * X[:, 1]) if mesh.geometry.dim == 3: assert np.allclose(x[:, 2], 3 * X[:, 2])
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 = ffcx.codegeneration.jit.compile_forms(forms, cffi_extra_compile_args=compile_args) ffi = cffi.FFI() form = compiled_forms[0][0] default_integral = form.create_cell_integral(-1) 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, 1.0, 0.0, 0.0, 1.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, 0) # Check that A is diagonal assert np.count_nonzero(A - np.diag(np.diagonal(A))) == 0