diff --git a/python/demo/demo_lagrange_variants.py b/python/demo/demo_lagrange_variants.py index a4654d9117b..be3d812342e 100644 --- a/python/demo/demo_lagrange_variants.py +++ b/python/demo/demo_lagrange_variants.py @@ -157,15 +157,15 @@ def saw_tooth(x): # elements, and plot the finite element interpolation. # + -mesh = mesh.create_unit_interval(MPI.COMM_WORLD, 10) +msh = mesh.create_unit_interval(MPI.COMM_WORLD, 10) -x = ufl.SpatialCoordinate(mesh) +x = ufl.SpatialCoordinate(msh) u_exact = saw_tooth(x[0]) for variant in [basix.LagrangeVariant.equispaced, basix.LagrangeVariant.gll_warped]: element = basix.create_element(basix.ElementFamily.P, basix.CellType.interval, 10, variant) ufl_element = basix.ufl_wrapper.BasixElement(element) - V = fem.FunctionSpace(mesh, ufl_element) + V = fem.FunctionSpace(msh, ufl_element) uh = fem.Function(V) uh.interpolate(lambda x: saw_tooth(x[0])) if MPI.COMM_WORLD.size == 1: # Skip this plotting in parallel @@ -205,11 +205,11 @@ def saw_tooth(x): for variant in [basix.LagrangeVariant.equispaced, basix.LagrangeVariant.gll_warped]: element = basix.create_element(basix.ElementFamily.P, basix.CellType.interval, 10, variant) ufl_element = basix.ufl_wrapper.BasixElement(element) - V = fem.FunctionSpace(mesh, ufl_element) + V = fem.FunctionSpace(msh, ufl_element) uh = fem.Function(V) uh.interpolate(lambda x: saw_tooth(x[0])) M = fem.form((u_exact - uh)**2 * dx) - error = mesh.comm.allreduce(fem.assemble_scalar(M), op=MPI.SUM) + error = msh.comm.allreduce(fem.assemble_scalar(M), op=MPI.SUM) print(f"Computed L2 interpolation error ({variant.name}):", error ** 0.5) # - diff --git a/python/demo/demo_types.py b/python/demo/demo_types.py index 684c0618589..3ccfbb18ca5 100644 --- a/python/demo/demo_types.py +++ b/python/demo/demo_types.py @@ -26,7 +26,6 @@ from dolfinx import fem, la, mesh, plot from mpi4py import MPI - # - # SciPy solvers do not support MPI, so all computations will be diff --git a/python/dolfinx/fem/function.py b/python/dolfinx/fem/function.py index bba839d2ba4..79b12976fbc 100644 --- a/python/dolfinx/fem/function.py +++ b/python/dolfinx/fem/function.py @@ -1,9 +1,9 @@ -# Copyright (C) 2009-2022 Chris N. Richardson, Garth N. Wells and Michal Habera +# Copyright (C) 2009-2023 Chris N. Richardson, Garth N. Wells and Michal Habera # # This file is part of DOLFINx (https://www.fenicsproject.org) # # SPDX-License-Identifier: LGPL-3.0-or-later -"""Collection of functions and function spaces""" +"""Finite element function spaces and functions""" from __future__ import annotations @@ -14,20 +14,19 @@ from functools import singledispatch -import numpy as np -import numpy.typing as npt - import basix import basix.ufl_wrapper +import numpy as np +import numpy.typing as npt import ufl import ufl.algorithms import ufl.algorithms.analysis -from dolfinx import cpp as _cpp -from dolfinx import jit, la from dolfinx.fem import dofmap +from petsc4py import PETSc from ufl.domain import extract_unique_domain -from petsc4py import PETSc +from dolfinx import cpp as _cpp +from dolfinx import jit, la class Constant(ufl.Constant): @@ -41,7 +40,6 @@ def __init__(self, domain, c: typing.Union[np.ndarray, typing.Sequence, float]): """ c = np.asarray(c) super().__init__(domain, c.shape) - try: if c.dtype == np.complex64: self._cpp_object = _cpp.fem.Constant_complex64(c) @@ -373,13 +371,11 @@ def _(expr: Expression, cells: typing.Optional[np.ndarray] = None): except TypeError: # u is callable assert callable(u) - x = _cpp.fem.interpolation_coords( - self._V.element, self._V.mesh, cells) - self._cpp_object.interpolate( - np.asarray(u(x), dtype=self.dtype), cells) + x = _cpp.fem.interpolation_coords(self._V.element, self._V.mesh._cpp_object, cells) + self._cpp_object.interpolate(np.asarray(u(x), dtype=self.dtype), cells) def copy(self) -> Function: - """Return a copy of the Function. The FunctionSpace is shared and the + """Create a copy of the Function. The FunctionSpace is shared and the degree-of-freedom vector is copied. """ @@ -445,8 +441,7 @@ def split(self) -> tuple[Function, ...]: def collapse(self) -> Function: u_collapsed = self._cpp_object.collapse() - V_collapsed = FunctionSpace(None, self.ufl_element(), - u_collapsed.function_space) + V_collapsed = FunctionSpace(self.function_space._mesh, self.ufl_element(), u_collapsed.function_space) return Function(V_collapsed, u_collapsed.x) @@ -459,23 +454,13 @@ class ElementMetaData(typing.NamedTuple): class FunctionSpace(ufl.FunctionSpace): """A space on which Functions (fields) can be defined.""" - def __init__(self, mesh: typing.Union[None, Mesh], + def __init__(self, mesh: Mesh, element: typing.Union[ufl.FiniteElementBase, ElementMetaData, typing.Tuple[str, int]], cppV: typing.Optional[_cpp.fem.FunctionSpace] = None, form_compiler_options: dict[str, typing.Any] = {}, jit_options: dict[str, typing.Any] = {}): """Create a finite element function space.""" - # Create function space from a UFL element and existing cpp - # FunctionSpace - if cppV is not None: - assert mesh is None - ufl_domain = cppV.mesh.ufl_domain() - super().__init__(ufl_domain, element) - self._cpp_object = cppV - return - - if mesh is not None: - assert cppV is None + if cppV is None: # Initialise the ufl.FunctionSpace if isinstance(element, ufl.FiniteElementBase): super().__init__(mesh.ufl_domain(), element) @@ -491,17 +476,26 @@ def __init__(self, mesh: typing.Union[None, Mesh], jit_options=jit_options) ffi = module.ffi - cpp_element = _cpp.fem.FiniteElement( - ffi.cast("uintptr_t", ffi.addressof(self._ufcx_element))) + cpp_element = _cpp.fem.FiniteElement(ffi.cast("uintptr_t", ffi.addressof(self._ufcx_element))) cpp_dofmap = _cpp.fem.create_dofmap(mesh.comm, ffi.cast( "uintptr_t", ffi.addressof(self._ufcx_dofmap)), mesh.topology, cpp_element) - # Initialize the cpp.FunctionSpace - self._cpp_object = _cpp.fem.FunctionSpace( - mesh, cpp_element, cpp_dofmap) + # Initialize the cpp.FunctionSpace and store mesh + self._cpp_object = _cpp.fem.FunctionSpace(mesh._cpp_object, cpp_element, cpp_dofmap) + self._mesh = mesh + else: + # Create function space from a UFL element and an existing + # C++ FunctionSpace + if mesh._cpp_object is not cppV.mesh: + raise RecursionError("Meshes do not match in FunctionSpace initialisation.") + ufl_domain = mesh.ufl_domain() + super().__init__(ufl_domain, element) + self._cpp_object = cppV + self._mesh = mesh + return def clone(self) -> FunctionSpace: - """Return a new FunctionSpace :math:`W` which shares data with this + """Create a new FunctionSpace :math:`W` which shares data with this FunctionSpace :math:`V`, but with a different unique integer ID. This function is helpful for defining mixed problems and using @@ -513,10 +507,12 @@ def clone(self) -> FunctionSpace: diagonal blocks. This is relevant for the handling of boundary conditions. + Returns: + A new function space that shares data + """ - Vcpp = _cpp.fem.FunctionSpace( - self._cpp_object.mesh, self._cpp_object.element, self._cpp_object.dofmap) - return FunctionSpace(None, self.ufl_element(), Vcpp) + Vcpp = _cpp.fem.FunctionSpace(self._cpp_object.mesh, self._cpp_object.element, self._cpp_object.dofmap) + return FunctionSpace(self._mesh, self.ufl_element(), Vcpp) @property def num_sub_spaces(self) -> int: @@ -536,7 +532,7 @@ def sub(self, i: int) -> FunctionSpace: assert self.ufl_element().num_sub_elements() > i sub_element = self.ufl_element().sub_elements()[i] cppV_sub = self._cpp_object.sub([i]) - return FunctionSpace(None, sub_element, cppV_sub) + return FunctionSpace(self._mesh, sub_element, cppV_sub) def component(self): """Return the component relative to the parent space.""" @@ -562,15 +558,13 @@ def __ne__(self, other): """Comparison for inequality.""" return super().__ne__(other) or self._cpp_object != other._cpp_object - def ufl_cell(self): - return self._cpp_object.mesh.ufl_cell() - def ufl_function_space(self) -> ufl.FunctionSpace: """UFL function space""" return self @property def element(self): + """Function space finite element.""" return self._cpp_object.element @property @@ -579,9 +573,9 @@ def dofmap(self) -> dofmap.DofMap: return dofmap.DofMap(self._cpp_object.dofmap) @property - def mesh(self) -> _cpp.mesh.Mesh: - """Return the mesh on which the function space is defined.""" - return self._cpp_object.mesh + def mesh(self) -> Mesh: + """Mesh on which the function space is defined.""" + return self._mesh def collapse(self) -> tuple[FunctionSpace, np.ndarray]: """Collapse a subspace and return a new function space and a map from @@ -592,31 +586,37 @@ def collapse(self) -> tuple[FunctionSpace, np.ndarray]: """ cpp_space, dofs = self._cpp_object.collapse() - V = FunctionSpace(None, self.ufl_element(), cpp_space) + V = FunctionSpace(self._mesh, self.ufl_element(), cpp_space) return V, dofs - def tabulate_dof_coordinates(self) -> np.ndarray: + def tabulate_dof_coordinates(self) -> npt.NDArray[np.float64]: + """Tabulate the coordinates of the degrees-of-freedom in the function space. + + Returns: + Coordinates of the degrees-of-freedom. + + Notes: + This method should be used only for elements with point + evaluation degrees-of-freedom. + + """ return self._cpp_object.tabulate_dof_coordinates() -def VectorFunctionSpace(mesh: Mesh, element: typing.Union[ElementMetaData, typing.Tuple[str, int]], dim=None, - restriction=None) -> FunctionSpace: +def VectorFunctionSpace(mesh: Mesh, element: typing.Union[ElementMetaData, typing.Tuple[str, int]], + dim=None) -> FunctionSpace: """Create vector finite element (composition of scalar elements) function space.""" - e = ElementMetaData(*element) - ufl_element = basix.ufl_wrapper.create_vector_element( - e.family, mesh.ufl_cell().cellname(), e.degree, dim=dim, - gdim=mesh.geometry.dim) - + ufl_element = basix.ufl_wrapper.create_vector_element(e.family, mesh.ufl_cell().cellname(), e.degree, + dim=dim, gdim=mesh.geometry.dim) return FunctionSpace(mesh, ufl_element) def TensorFunctionSpace(mesh: Mesh, element: typing.Union[ElementMetaData, typing.Tuple[str, int]], shape=None, - symmetry: typing.Optional[bool] = None, restriction=None) -> FunctionSpace: + symmetry: typing.Optional[bool] = None) -> FunctionSpace: """Create tensor finite element (composition of scalar elements) function space.""" - e = ElementMetaData(*element) - ufl_element = basix.ufl_wrapper.create_tensor_element( - e.family, mesh.ufl_cell().cellname(), e.degree, shape=shape, symmetry=symmetry, - gdim=mesh.geometry.dim) + ufl_element = basix.ufl_wrapper.create_tensor_element(e.family, mesh.ufl_cell().cellname(), + e.degree, shape=shape, symmetry=symmetry, + gdim=mesh.geometry.dim) return FunctionSpace(mesh, ufl_element) diff --git a/python/dolfinx/geometry.py b/python/dolfinx/geometry.py index aa6671add17..71b552c931a 100644 --- a/python/dolfinx/geometry.py +++ b/python/dolfinx/geometry.py @@ -9,15 +9,17 @@ import typing +import numpy as np +import numpy.typing as npt + if typing.TYPE_CHECKING: from dolfinx.mesh import Mesh from dolfinx.cpp.graph import AdjacencyList_int32 import numpy +from dolfinx.cpp.geometry import compute_collisions, compute_distance_gjk from dolfinx import cpp as _cpp -from dolfinx.cpp.geometry import (compute_closest_entity, compute_collisions, - compute_distance_gjk, create_midpoint_tree) __all__ = ["compute_colliding_cells", "squared_distance", "compute_closest_entity", "compute_collisions", "compute_distance_gjk", "create_midpoint_tree"] @@ -44,7 +46,30 @@ def __init__(self, mesh: Mesh, dim: int, entities=None, padding: float = 0.0): if entities is None: entities = range(0, map.size_local + map.num_ghosts) - super().__init__(mesh, dim, entities, padding) + super().__init__(mesh._cpp_object, dim, entities, padding) + + +def compute_closest_entity(tree: BoundingBoxTree, midpoint_tree: BoundingBoxTree, mesh: Mesh, + points: numpy.ndarray) -> npt.NDArray[np.int32]: + """Compute closest mesh entity to a point. + + Args: + tree: bounding box tree for the entities + midpoint_tree: A bounding box tree with the midpoints of all + the mesh entities. This is used to accelerate the search. + mesh: The mesh + points: The points to check for collision, shape=(num_points, 3) + + Returns: + Mesh entity index for each point in `points`. Returns -1 for + a point if the bounding box tree is empty. + + """ + return _cpp.geometry.compute_closest_entity(tree, midpoint_tree, mesh._cpp_object, points) + + +def create_midpoint_tree(mesh: Mesh, dim: int, entities: numpy.ndarray): + return _cpp.geometry.create_midpoint_tree(mesh._cpp_object, dim, entities) def compute_colliding_cells(mesh: Mesh, candidates: AdjacencyList_int32, x: numpy.ndarray): @@ -60,7 +85,7 @@ def compute_colliding_cells(mesh: Mesh, candidates: AdjacencyList_int32, x: nump Adjacency list where the ith node is the list of entities that collide with the ith point """ - return _cpp.geometry.compute_colliding_cells(mesh, candidates, x) + return _cpp.geometry.compute_colliding_cells(mesh._cpp_object, candidates, x) def squared_distance(mesh: Mesh, dim: int, entities: typing.List[int], points: numpy.ndarray): @@ -80,4 +105,4 @@ def squared_distance(mesh: Mesh, dim: int, entities: typing.List[int], points: n Squared shortest distance from points[i] to entities[i] """ - return _cpp.geometry.squared_distance(mesh, dim, entities, points) + return _cpp.geometry.squared_distance(mesh._cpp_object, dim, entities, points) diff --git a/python/dolfinx/io/gmshio.py b/python/dolfinx/io/gmshio.py index 7d4219223f9..4572a980067 100644 --- a/python/dolfinx/io/gmshio.py +++ b/python/dolfinx/io/gmshio.py @@ -230,7 +230,6 @@ def model_to_mesh(model: gmsh.model, comm: _MPI.Comm, rank: int, gdim: int = 3, cells = np.asarray(topologies[cell_id]["topology"], dtype=np.int64) cell_values = np.asarray(topologies[cell_id]["cell_data"], dtype=np.int32) - else: cell_id, num_nodes = comm.bcast([None, None], root=rank) cells, x = np.empty([0, num_nodes], dtype=np.int32), np.empty([0, gdim]) @@ -248,7 +247,8 @@ def model_to_mesh(model: gmsh.model, comm: _MPI.Comm, rank: int, gdim: int = 3, mesh = create_mesh(comm, cells, x[:, :gdim], ufl_domain, partitioner) # Create MeshTags for cells - local_entities, local_values = _cpp.io.distribute_entity_data(mesh, mesh.topology.dim, cells, cell_values) + local_entities, local_values = _cpp.io.distribute_entity_data( + mesh._cpp_object, mesh.topology.dim, cells, cell_values) mesh.topology.create_connectivity(mesh.topology.dim, 0) adj = _cpp.graph.AdjacencyList_int32(local_entities) ct = meshtags_from_entities(mesh, mesh.topology.dim, adj, local_values.astype(np.int32, copy=False)) @@ -257,7 +257,7 @@ def model_to_mesh(model: gmsh.model, comm: _MPI.Comm, rank: int, gdim: int = 3, # Create MeshTags for facets topology = mesh.topology if has_facet_data: - # Permute facets from MSH to Dolfin-X ordering + # Permute facets from MSH to DOLFINx ordering # FIXME: This does not work for prism meshes if topology.cell_type == CellType.prism or topology.cell_type == CellType.pyramid: raise RuntimeError(f"Unsupported cell type {topology.cell_type}") @@ -267,7 +267,7 @@ def model_to_mesh(model: gmsh.model, comm: _MPI.Comm, rank: int, gdim: int = 3, marked_facets = marked_facets[:, gmsh_facet_perm] local_entities, local_values = _cpp.io.distribute_entity_data( - mesh, mesh.topology.dim - 1, marked_facets, facet_values) + mesh._cpp_object, mesh.topology.dim - 1, marked_facets, facet_values) mesh.topology.create_connectivity(topology.dim - 1, topology.dim) adj = _cpp.graph.AdjacencyList_int32(local_entities) ft = meshtags_from_entities(mesh, topology.dim - 1, adj, local_values.astype(np.int32, copy=False)) @@ -301,11 +301,11 @@ def read_from_msh(filename: str, comm: _MPI.Comm, rank: int = 0, gdim: int = 3, gmsh.initialize() gmsh.model.add("Mesh from file") gmsh.merge(filename) - - output = model_to_mesh(gmsh.model, comm, rank, gdim=gdim, partitioner=partitioner) - if comm.rank == rank: + msh = model_to_mesh(gmsh.model, comm, rank, gdim=gdim, partitioner=partitioner) gmsh.finalize() - return output + return msh + else: + return model_to_mesh(gmsh.model, comm, rank, gdim=gdim, partitioner=partitioner) # Map from Gmsh cell type identifier (integer) to DOLFINx cell type # and degree http://gmsh.info//doc/texinfo/gmsh.html#MSH-file-format diff --git a/python/dolfinx/io/utils.py b/python/dolfinx/io/utils.py index 02acfb94902..ede06c5400e 100644 --- a/python/dolfinx/io/utils.py +++ b/python/dolfinx/io/utils.py @@ -50,7 +50,7 @@ class VTXWriter(_cpp.io.VTXWriter): """ - def __init__(self, comm: _MPI.Comm, filename: str, output: typing.Union[Mesh, typing.List[Function], Function]): + def __init__(self, comm: _MPI.Comm, filename: str, output: typing.Union[Mesh, Function, typing.List[Function]]): """Initialize a writer for outputting data in the VTX format. Args: @@ -67,10 +67,10 @@ def __init__(self, comm: _MPI.Comm, filename: str, output: typing.Union[Mesh, ty """ try: # Input is a mesh - super().__init__(comm, filename, output) - except (NotImplementedError, TypeError): + super().__init__(comm, filename, output._cpp_object) # type: ignore[union-attr] + except (NotImplementedError, TypeError, AttributeError): # Input is a single function or a list of functions - super().__init__(comm, filename, _extract_cpp_functions(output)) + super().__init__(comm, filename, _extract_cpp_functions(output)) # type: ignore[arg-type] def __enter__(self): return self @@ -105,9 +105,9 @@ def __init__(self, comm: _MPI.Comm, filename: str, output: typing.Union[Mesh, ty """ try: - super().__init__(comm, filename, output) - except (NotImplementedError, TypeError): - super().__init__(comm, filename, _extract_cpp_functions(output)) + super().__init__(comm, filename, output._cpp_object) # type: ignore[union-attr] + except (NotImplementedError, TypeError, AttributeError): + super().__init__(comm, filename, _extract_cpp_functions(output)) # type: ignore[arg-type] def __enter__(self): return self @@ -133,7 +133,7 @@ def __exit__(self, exception_type, exception_value, traceback): def write_mesh(self, mesh: Mesh, t: float = 0.0) -> None: """Write mesh to file for a given time (default 0.0)""" - self.write(mesh, t) + self.write(mesh._cpp_object, t) def write_function(self, u: typing.Union[typing.List[Function], Function], t: float = 0.0) -> None: """Write a single function or a list of functions to file for a given time (default 0.0)""" @@ -149,7 +149,7 @@ def __exit__(self, exception_type, exception_value, traceback): def write_mesh(self, mesh: Mesh) -> None: """Write mesh to file for a given time (default 0.0)""" - super().write_mesh(mesh) + super().write_mesh(mesh._cpp_object) def write_function(self, u, t: float = 0.0, mesh_xpath="/Xdmf/Domain/Grid[@GridType='Uniform'][1]"): super().write_function(getattr(u, "_cpp_object", u), t, mesh_xpath) @@ -162,19 +162,19 @@ def read_mesh(self, ghost_mode=GhostMode.shared_facet, name="mesh", xpath="/Xdmf # 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, _cpp.mesh.create_cell_partitioner(ghost_mode)) - mesh.name = name + msh = _cpp.mesh.create_mesh(self.comm(), _cpp.graph.AdjacencyList_int64(cells), + cmap, x, _cpp.mesh.create_cell_partitioner(ghost_mode)) + msh.name = name domain = ufl.Mesh(basix.ufl_wrapper.create_vector_element( "Lagrange", cell_shape.name, cell_degree, basix.LagrangeVariant.equispaced, dim=x.shape[1], gdim=x.shape[1])) - return Mesh.from_cpp(mesh, domain) + return Mesh(msh, domain) def read_meshtags(self, mesh, name, xpath="/Xdmf/Domain"): - return super().read_meshtags(mesh, name, xpath) + return super().read_meshtags(mesh._cpp_object, name, xpath) def distribute_entity_data(mesh: Mesh, entity_dim: int, entities: npt.NDArray[np.int64], values: npt.NDArray[np.int32]) -> typing.Tuple[npt.NDArray[np.int64], npt.NDArray[np.int32]]: - return _cpp.io.distribute_entity_data(mesh, entity_dim, entities, values) + return _cpp.io.distribute_entity_data(mesh._cpp_object, entity_dim, entities, values) diff --git a/python/dolfinx/mesh.py b/python/dolfinx/mesh.py index dcbd0621942..a075ec55e28 100644 --- a/python/dolfinx/mesh.py +++ b/python/dolfinx/mesh.py @@ -9,21 +9,19 @@ import typing -import numpy as np -import numpy.typing - import basix import basix.ufl_wrapper +import numpy as np +import numpy.typing as npt import ufl -from dolfinx import cpp as _cpp from dolfinx.cpp.mesh import (CellType, DiagonalType, GhostMode, build_dual_graph, cell_dim, - compute_incident_entities, compute_midpoints, create_cell_partitioner, exterior_facet_indices, to_string, to_type) - from mpi4py import MPI as _MPI +from dolfinx import cpp as _cpp + __all__ = ["meshtags_from_entities", "locate_entities", "locate_entities_boundary", "refine", "create_mesh", "Mesh", "MeshTagsMetaClass", "meshtags", "CellType", "GhostMode", "build_dual_graph", "cell_dim", "compute_midpoints", @@ -32,32 +30,41 @@ "create_box", "create_unit_cube", "to_type", "to_string"] -class Mesh(_cpp.mesh.Mesh): - def __init__(self, comm: _MPI.Comm, topology: _cpp.mesh.Topology, - geometry: _cpp.mesh.Geometry, domain: ufl.Mesh): +def compute_incident_entities(mesh: Mesh, entities: npt.NDArray[np.int32], d0: int, d1: int): + return _cpp.mesh.compute_incident_entities(mesh._cpp_object, entities, d0, d1) + + +def compute_midpoints(mesh: Mesh, dim: int, entities: npt.NDArray[np.int32]): + return _cpp.mesh.compute_midpoints(mesh._cpp_object, dim, entities) + + +class Mesh: + def __init__(self, mesh: _cpp.mesh.Mesh, domain: ufl.Mesh): """A class for representing meshes Args: - comm: The MPI communicator - topology: The mesh topology - geometry: The mesh geometry - domain: The MPI communicator + mesh: The C++ mesh object + domain: The UFL domain Note: - Mesh objects are not generally created using this class directly. + Mesh objects should not usually be created using this class directly. """ - super().__init__(comm, topology, geometry) + self._cpp_object = mesh self._ufl_domain = domain - domain._ufl_cargo = self + self._ufl_domain._ufl_cargo = self._cpp_object + + @property + def comm(self): + return self._cpp_object.comm - @classmethod - def from_cpp(cls, obj: _cpp.mesh.Mesh, domain: ufl.Mesh) -> Mesh: - """Create Mesh object from a C++ Mesh object""" - obj._ufl_domain = domain - obj.__class__ = Mesh - domain._ufl_cargo = obj - return obj + @property + def name(self): + return self._cpp_object.name + + @name.setter + def name(self, value): + self._cpp_object.name = value def ufl_cell(self) -> ufl.Cell: """Return the UFL cell type""" @@ -67,6 +74,18 @@ def ufl_domain(self) -> ufl.Mesh: """Return the ufl domain corresponding to the mesh.""" return self._ufl_domain + def h(self, dim: int, entities: npt.NDArray[np.int32]) -> npt.NDArray[np.float64]: + """Size measure for each cell.""" + return _cpp.mesh.h(self._cpp_object, dim, entities) + + @property + def topology(self): + return self._cpp_object.topology + + @property + def geometry(self): + return self._cpp_object.geometry + def locate_entities(mesh: Mesh, dim: int, marker: typing.Callable) -> np.ndarray: """Compute mesh entities satisfying a geometric marking function @@ -82,7 +101,7 @@ def locate_entities(mesh: Mesh, dim: int, marker: typing.Callable) -> np.ndarray Indices (local to the process) of marked mesh entities. """ - return _cpp.mesh.locate_entities(mesh, dim, marker) + return _cpp.mesh.locate_entities(mesh._cpp_object, dim, marker) def locate_entities_boundary(mesh: Mesh, dim: int, marker: typing.Callable) -> np.ndarray: @@ -109,7 +128,7 @@ def locate_entities_boundary(mesh: Mesh, dim: int, marker: typing.Callable) -> n Indices (local to the process) of marked mesh entities. """ - return _cpp.mesh.locate_entities_boundary(mesh, dim, marker) + return _cpp.mesh.locate_entities_boundary(mesh._cpp_object, dim, marker) _uflcell_to_dolfinxcell = { @@ -140,13 +159,13 @@ def refine(mesh: Mesh, edges: typing.Optional[np.ndarray] = None, redistribute: A refined mesh """ if edges is None: - mesh_refined = _cpp.refinement.refine(mesh, redistribute) + mesh_refined = _cpp.refinement.refine(mesh._cpp_object, redistribute) else: - mesh_refined = _cpp.refinement.refine(mesh, edges, redistribute) + mesh_refined = _cpp.refinement.refine(mesh._cpp_object, edges, redistribute) coordinate_element = mesh._ufl_domain.ufl_coordinate_element() domain = ufl.Mesh(coordinate_element) - return Mesh.from_cpp(mesh_refined, domain) + return Mesh(mesh_refined, domain) def create_mesh(comm: _MPI.Comm, cells: typing.Union[np.ndarray, _cpp.graph.AdjacencyList_int64], @@ -180,18 +199,16 @@ def create_mesh(comm: _MPI.Comm, cells: typing.Union[np.ndarray, _cpp.graph.Adja except TypeError: mesh = _cpp.mesh.create_mesh(comm, _cpp.graph.AdjacencyList_int64(np.cast['int64'](cells)), cmap, x, partitioner) - domain._ufl_cargo = mesh - return Mesh.from_cpp(mesh, domain) + return Mesh(mesh, domain) -def create_submesh(mesh, dim, entities): - submesh, entity_map, 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) - submesh_domain = ufl.Mesh(basix.ufl_wrapper.create_vector_element( - "Lagrange", submesh_ufl_cell.cellname(), submesh.geometry.cmap.degree, submesh.geometry.cmap.variant, - dim=submesh.geometry.dim, gdim=submesh.geometry.dim)) - return (Mesh.from_cpp(submesh, submesh_domain), entity_map, vertex_map, geom_map) +def create_submesh(msh, dim, entities): + submsh, entity_map, vertex_map, geom_map = _cpp.mesh.create_submesh(msh._cpp_object, dim, entities) + submsh_ufl_cell = ufl.Cell(submsh.topology.cell_name(), geometric_dimension=submsh.geometry.dim) + submsh_domain = ufl.Mesh(basix.ufl_wrapper.create_vector_element( + "Lagrange", submsh_ufl_cell.cellname(), submsh.geometry.cmap.degree, submsh.geometry.cmap.variant, + dim=submsh.geometry.dim, gdim=submsh.geometry.dim)) + return (Mesh(submsh, submsh_domain), entity_map, vertex_map, geom_map) # Add attribute to MeshTags @@ -208,8 +225,8 @@ def _ufl_id(self) -> int: class MeshTagsMetaClass: - def __init__(self, mesh: Mesh, dim: int, entities: numpy.typing.NDArray[typing.Any], - values: numpy.typing.NDArray[typing.Any]): + def __init__(self, mesh: Mesh, dim: int, entities: npt.NDArray[typing.Any], + values: npt.NDArray[typing.Any]): """A distributed sparse matrix that uses compressed sparse row storage. Args: @@ -226,7 +243,7 @@ def __init__(self, mesh: Mesh, dim: int, entities: numpy.typing.NDArray[typing.A directly. """ - super().__init__(mesh, dim, np.asarray(entities, dtype=np.int32), values) # type: ignore + super().__init__(mesh._cpp_object, dim, np.asarray(entities, dtype=np.int32), values) # type: ignore def ufl_id(self) -> int: """Object identifier. @@ -241,7 +258,7 @@ def ufl_id(self) -> int: return id(self) -def meshtags(mesh: Mesh, dim: int, entities: np.ndarray, +def meshtags(mesh: Mesh, dim: int, entities: npt.NDArray[np.int64], values: typing.Union[np.ndarray, int, float]) -> MeshTagsMetaClass: """Create a MeshTags object that associates data with a subset of mesh entities. @@ -285,7 +302,7 @@ def meshtags(mesh: Mesh, dim: int, entities: np.ndarray, def meshtags_from_entities(mesh: Mesh, dim: int, entities: _cpp.graph.AdjacencyList_int32, - values: numpy.typing.NDArray[typing.Any]): + values: npt.NDArray[typing.Any]): """Create a MeshTags object that associates data with a subset of mesh entities, where the entities are defined by their vertices. @@ -312,10 +329,10 @@ def meshtags_from_entities(mesh: Mesh, dim: int, entities: _cpp.graph.AdjacencyL values = np.full(entities.num_nodes, values, dtype=np.double) values = np.asarray(values) - return _cpp.mesh.create_meshtags(mesh, dim, entities, values) + return _cpp.mesh.create_meshtags(mesh._cpp_object, dim, entities, values) -def create_interval(comm: _MPI.Comm, nx: int, points: numpy.typing.ArrayLike, +def create_interval(comm: _MPI.Comm, nx: int, points: npt.ArrayLike, ghost_mode=GhostMode.shared_facet, partitioner=None) -> Mesh: """Create an interval mesh @@ -336,7 +353,7 @@ def create_interval(comm: _MPI.Comm, nx: int, points: numpy.typing.ArrayLike, partitioner = _cpp.mesh.create_cell_partitioner(ghost_mode) domain = ufl.Mesh(basix.ufl_wrapper.create_vector_element("Lagrange", "interval", 1)) mesh = _cpp.mesh.create_interval(comm, nx, points, ghost_mode, partitioner) - return Mesh.from_cpp(mesh, domain) + return Mesh(mesh, domain) def create_unit_interval(comm: _MPI.Comm, nx: int, ghost_mode=GhostMode.shared_facet, @@ -361,7 +378,7 @@ def create_unit_interval(comm: _MPI.Comm, nx: int, ghost_mode=GhostMode.shared_f return create_interval(comm, nx, [0.0, 1.0], ghost_mode, partitioner) -def create_rectangle(comm: _MPI.Comm, points: numpy.typing.ArrayLike, n: numpy.typing.ArrayLike, +def create_rectangle(comm: _MPI.Comm, points: npt.ArrayLike, n: npt.ArrayLike, cell_type=CellType.triangle, ghost_mode=GhostMode.shared_facet, partitioner=None, diagonal: DiagonalType = DiagonalType.right) -> Mesh: @@ -388,8 +405,7 @@ def create_rectangle(comm: _MPI.Comm, points: numpy.typing.ArrayLike, n: numpy.t partitioner = _cpp.mesh.create_cell_partitioner(ghost_mode) domain = ufl.Mesh(basix.ufl_wrapper.create_vector_element("Lagrange", cell_type.name, 1)) mesh = _cpp.mesh.create_rectangle(comm, points, n, cell_type, partitioner, diagonal) - - return Mesh.from_cpp(mesh, domain) + return Mesh(mesh, domain) def create_unit_square(comm: _MPI.Comm, nx: int, ny: int, cell_type=CellType.triangle, @@ -419,7 +435,7 @@ def create_unit_square(comm: _MPI.Comm, nx: int, ny: int, cell_type=CellType.tri partitioner, diagonal) -def create_box(comm: _MPI.Comm, points: typing.List[numpy.typing.ArrayLike], n: list, +def create_box(comm: _MPI.Comm, points: typing.List[npt.ArrayLike], n: list, cell_type=CellType.tetrahedron, ghost_mode=GhostMode.shared_facet, partitioner=None) -> Mesh: @@ -443,8 +459,7 @@ def create_box(comm: _MPI.Comm, points: typing.List[numpy.typing.ArrayLike], n: partitioner = _cpp.mesh.create_cell_partitioner(ghost_mode) domain = ufl.Mesh(basix.ufl_wrapper.create_vector_element("Lagrange", cell_type.name, 1)) mesh = _cpp.mesh.create_box(comm, points, n, cell_type, partitioner) - - return Mesh.from_cpp(mesh, domain) + return Mesh(mesh, domain) def create_unit_cube(comm: _MPI.Comm, nx: int, ny: int, nz: int, cell_type=CellType.tetrahedron, diff --git a/python/dolfinx/plot.py b/python/dolfinx/plot.py index ad773581f7f..d6b029cae45 100644 --- a/python/dolfinx/plot.py +++ b/python/dolfinx/plot.py @@ -51,11 +51,11 @@ def create_vtk_mesh(msh: mesh.Mesh, dim: typing.Optional[int] = None, entities=N entities = range(msh.topology.index_map(dim).size_local) if dim == tdim: - vtk_topology = _cpp.io.extract_vtk_connectivity(msh)[entities] + vtk_topology = _cpp.io.extract_vtk_connectivity(msh._cpp_object)[entities] num_nodes_per_cell = vtk_topology.shape[1] else: # NOTE: This linearizes higher order geometries - geometry_entities = _cpp.mesh.entities_to_geometry(msh, dim, entities, False) + geometry_entities = _cpp.mesh.entities_to_geometry(msh._cpp_object, dim, entities, False) if degree > 1: warnings.warn("Linearizing topology for higher order sub entities.") diff --git a/python/test/unit/fem/test_custom_assembler.py b/python/test/unit/fem/test_custom_assembler.py index add296ba8fb..63c02c13b23 100644 --- a/python/test/unit/fem/test_custom_assembler.py +++ b/python/test/unit/fem/test_custom_assembler.py @@ -14,24 +14,24 @@ import time import cffi -import numba -import numba.core.typing.cffi_utils as cffi_support +import dolfinx.pkgconfig import numpy as np import numpy.typing +import petsc4py.lib import pytest - -import dolfinx -import dolfinx.pkgconfig import ufl from dolfinx.fem import Function, FunctionSpace, form from dolfinx.fem.petsc import assemble_matrix, load_petsc_lib from dolfinx.mesh import create_unit_square -from ufl import dx, inner - -import petsc4py.lib from mpi4py import MPI from petsc4py import PETSc from petsc4py import get_config as PETSc_get_config +from ufl import dx, inner + +import dolfinx + +numba = pytest.importorskip("numba") +cffi_support = pytest.importorskip("numba.core.typing.cffi_utils") # Get details of PETSc install petsc_dir = PETSc_get_config()['PETSC_DIR'] diff --git a/python/test/unit/fem/test_custom_jit_kernels.py b/python/test/unit/fem/test_custom_jit_kernels.py index 745a8e92f14..09572b3846e 100644 --- a/python/test/unit/fem/test_custom_jit_kernels.py +++ b/python/test/unit/fem/test_custom_jit_kernels.py @@ -9,19 +9,19 @@ import os import sys -import numba import numpy as np import pytest +from dolfinx.fem import Function, FunctionSpace, IntegralType +from dolfinx.mesh import create_unit_square, meshtags +from mpi4py import MPI +from petsc4py import PETSc import dolfinx from dolfinx import TimingType from dolfinx import cpp as _cpp from dolfinx import fem, la, list_timings -from dolfinx.fem import Function, FunctionSpace, IntegralType -from dolfinx.mesh import create_unit_square, meshtags -from mpi4py import MPI -from petsc4py import PETSc +numba = pytest.importorskip("numba") # Add current directory - required for some Python versions to find cffi # compiled modules diff --git a/python/test/unit/fem/test_expression.py b/python/test/unit/fem/test_expression.py index b764b9657ec..3e58cbe89c5 100644 --- a/python/test/unit/fem/test_expression.py +++ b/python/test/unit/fem/test_expression.py @@ -7,23 +7,25 @@ import ctypes import ctypes.util +import basix import cffi -import numba -import numba.core.typing.cffi_utils as cffi_support import numpy as np - -import basix -import dolfinx.cpp +import pytest import ufl from dolfinx.cpp.la.petsc import create_matrix from dolfinx.fem import (Constant, Expression, Function, FunctionSpace, VectorFunctionSpace, create_sparsity_pattern, form) from dolfinx.fem.petsc import load_petsc_lib from dolfinx.mesh import create_unit_square - from mpi4py import MPI from petsc4py import PETSc +import dolfinx.cpp + +numba = pytest.importorskip("numba") +cffi_support = pytest.importorskip("numba.core.typing.cffi_utils") + + dolfinx.cpp.common.init_logging(["-v"]) # Get PETSc int and scalar types diff --git a/python/test/unit/fem/test_function_space.py b/python/test/unit/fem/test_function_space.py index a12ab18b84b..fd1cc39a1d1 100644 --- a/python/test/unit/fem/test_function_space.py +++ b/python/test/unit/fem/test_function_space.py @@ -65,8 +65,8 @@ def test_python_interface(V, V2, W, W2, Q): assert isinstance(V2, FunctionSpace) assert isinstance(W2, FunctionSpace) - assert V.ufl_cell() == V2.ufl_cell() - assert W.ufl_cell() == W2.ufl_cell() + assert V.mesh.ufl_cell() == V2.mesh.ufl_cell() + assert W.mesh.ufl_cell() == W2.mesh.ufl_cell() assert V.element == V2.element assert W.element == W2.element assert V.ufl_element() == V2.ufl_element() diff --git a/python/test/unit/fem/test_interpolation.py b/python/test/unit/fem/test_interpolation.py index 54aefd04978..134f05aadfe 100644 --- a/python/test/unit/fem/test_interpolation.py +++ b/python/test/unit/fem/test_interpolation.py @@ -7,18 +7,15 @@ import random -import numba -import numpy as np -import pytest - import basix import basix.ufl_wrapper +import numpy as np +import pytest import ufl from dolfinx.fem import (Expression, Function, FunctionSpace, VectorFunctionSpace, assemble_scalar, form) from dolfinx.mesh import (CellType, create_mesh, create_unit_cube, create_unit_square, locate_entities, meshtags) - from mpi4py import MPI parametrize_cell_types = pytest.mark.parametrize( @@ -611,6 +608,8 @@ def test_interpolate_callable(): V = FunctionSpace(mesh, ("Lagrange", 2)) u0, u1 = Function(V), Function(V) + numba = pytest.importorskip("numba") + @numba.njit def f(x): return x[0] diff --git a/python/test/unit/geometry/test_bounding_box_tree.py b/python/test/unit/geometry/test_bounding_box_tree.py index a5758189298..0e754fcf666 100644 --- a/python/test/unit/geometry/test_bounding_box_tree.py +++ b/python/test/unit/geometry/test_bounding_box_tree.py @@ -7,8 +7,6 @@ import numpy as np import pytest - -from dolfinx import cpp as _cpp from dolfinx.geometry import (BoundingBoxTree, compute_closest_entity, compute_colliding_cells, compute_collisions, compute_distance_gjk, create_midpoint_tree) @@ -16,18 +14,17 @@ create_unit_interval, create_unit_square, exterior_facet_indices, locate_entities, locate_entities_boundary) - from mpi4py import MPI +from dolfinx import cpp as _cpp + def extract_geometricial_data(mesh, dim, entities): """For a set of entities in a mesh, return the coordinates of the vertices""" mesh_nodes = [] geom = mesh.geometry - g_indices = _cpp.mesh.entities_to_geometry(mesh, dim, - np.array(entities, dtype=np.int32), - False) + g_indices = _cpp.mesh.entities_to_geometry(mesh._cpp_object, dim, np.array(entities, dtype=np.int32), False) for cell in g_indices: nodes = np.zeros((len(cell), 3), dtype=np.float64) for j, entity in enumerate(cell): @@ -55,8 +52,8 @@ def find_colliding_cells(mesh, bbox): # Find actual cells using known bounding box tree colliding_cells = [] num_cells = mesh.topology.index_map(mesh.topology.dim).size_local - x_indices = _cpp.mesh.entities_to_geometry( - mesh, mesh.topology.dim, np.arange(num_cells, dtype=np.int32), False) + x_indices = _cpp.mesh.entities_to_geometry(mesh._cpp_object, mesh.topology.dim, + np.arange(num_cells, dtype=np.int32), False) points = mesh.geometry.x bounding_box = expand_bbox(bbox) for cell in range(num_cells): @@ -148,7 +145,7 @@ def test_compute_collisions_point_1d(): assert len(entities.array) == 1 # Get the vertices of the geometry - geom_entities = _cpp.mesh.entities_to_geometry(mesh, tdim, entities.array, False)[0] + geom_entities = _cpp.mesh.entities_to_geometry(mesh._cpp_object, tdim, entities.array, False)[0] x = mesh.geometry.x cell_vertices = x[geom_entities] # Check that we get the cell with correct vertices @@ -164,7 +161,7 @@ def test_compute_collisions_tree_1d(point): def locator_A(x): return x[0] >= point[0] # Locate all vertices of mesh A that should collide - vertices_A = _cpp.mesh.locate_entities(mesh_A, 0, locator_A) + vertices_A = _cpp.mesh.locate_entities(mesh_A._cpp_object, 0, locator_A) mesh_A.topology.create_connectivity(0, mesh_A.topology.dim) v_to_c = mesh_A.topology.connectivity(0, mesh_A.topology.dim) @@ -179,7 +176,7 @@ def locator_B(x): return x[0] <= 1 # Locate all vertices of mesh B that should collide - vertices_B = _cpp.mesh.locate_entities(mesh_B, 0, locator_B) + vertices_B = _cpp.mesh.locate_entities(mesh_B._cpp_object, 0, locator_B) mesh_B.topology.create_connectivity(0, mesh_B.topology.dim) v_to_c = mesh_B.topology.connectivity(0, mesh_B.topology.dim) diff --git a/python/test/unit/io/test_adios2.py b/python/test/unit/io/test_adios2.py index 73db08adc59..a8df9a71bc0 100644 --- a/python/test/unit/io/test_adios2.py +++ b/python/test/unit/io/test_adios2.py @@ -93,12 +93,19 @@ def test_findes_single_function(tempdir, dim, simplex): @pytest.mark.parametrize("simplex", [True, False]) def test_fides_function_at_nodes(tempdir, dim, simplex): """Test saving P1 functions with Fides (with changing geometry)""" + from petsc4py import PETSc + dtype = PETSc.ScalarType mesh = generate_mesh(dim, simplex) - v = Function(VectorFunctionSpace(mesh, ("Lagrange", 1))) + v = Function(VectorFunctionSpace(mesh, ("Lagrange", 1)), dtype=dtype) v.name = "v" q = Function(FunctionSpace(mesh, ("Lagrange", 1))) q.name = "q" filename = Path(tempdir, "v.bp") + if np.issubdtype(dtype, np.complexfloating): + alpha = 1j + else: + alpha = 0 + with FidesWriter(mesh.comm, filename, [v, q]) as f: for t in [0.1, 0.5, 1]: # Only change one function @@ -107,9 +114,9 @@ def test_fides_function_at_nodes(tempdir, dim, simplex): mesh.geometry.x[:, :2] += 0.1 if mesh.geometry.dim == 2: - v.interpolate(lambda x: np.vstack((t * x[0], x[1] + x[1] * 1j))) + v.interpolate(lambda x: np.vstack((t * x[0], x[1] + x[1] * alpha))) elif mesh.geometry.dim == 3: - v.interpolate(lambda x: np.vstack((t * x[2], x[0] + x[2] * 2j, x[1]))) + v.interpolate(lambda x: np.vstack((t * x[2], x[0] + x[2] * 2 * alpha, x[1]))) f.write(t) diff --git a/python/test/unit/io/test_xdmf_mesh.py b/python/test/unit/io/test_xdmf_mesh.py index a10112c3d35..9fe332fb484 100644 --- a/python/test/unit/io/test_xdmf_mesh.py +++ b/python/test/unit/io/test_xdmf_mesh.py @@ -64,9 +64,9 @@ def test_save_and_load_2d_mesh(tempdir, encoding, cell_type): mesh2 = file.read_mesh(name="square") assert mesh2.name == mesh.name - assert mesh.topology.index_map(0).size_global == mesh2.topology.index_map(0).size_global - assert mesh.topology.index_map(mesh.topology.dim).size_global == mesh2.topology.index_map( - mesh.topology.dim).size_global + topology, topology2 = mesh.topology, mesh2.topology + assert topology.index_map(0).size_global == topology2.index_map(0).size_global + assert topology.index_map(topology.dim).size_global == topology2.index_map(topology.dim).size_global @pytest.mark.parametrize("cell_type", celltypes_3D) @@ -80,9 +80,9 @@ def test_save_and_load_3d_mesh(tempdir, encoding, cell_type): with XDMFFile(MPI.COMM_WORLD, filename, "r", encoding=encoding) as file: mesh2 = file.read_mesh() - assert mesh.topology.index_map(0).size_global == mesh2.topology.index_map(0).size_global - assert mesh.topology.index_map(mesh.topology.dim).size_global == mesh2.topology.index_map( - mesh.topology.dim).size_global + topology, topology2 = mesh.topology, mesh2.topology + assert topology.index_map(0).size_global == topology2.index_map(0).size_global + assert topology.index_map(topology.dim).size_global == topology2.index_map(topology.dim).size_global @pytest.mark.parametrize("encoding", encodings) @@ -131,9 +131,9 @@ def test_read_write_p2_mesh(tempdir, encoding): with XDMFFile(mesh.comm, filename, "r", encoding=encoding) as xdmf: mesh2 = xdmf.read_mesh() - assert mesh.topology.index_map(0).size_global == mesh2.topology.index_map(0).size_global - assert mesh.topology.index_map(mesh.topology.dim).size_global == mesh2.topology.index_map( - mesh.topology.dim).size_global + topology, topology2 = mesh.topology, mesh2.topology + assert topology.index_map(0).size_global == topology2.index_map(0).size_global + assert topology.index_map(topology.dim).size_global == topology2.index_map(topology.dim).size_global @pytest.mark.parametrize("d", [2, 3]) diff --git a/python/test/unit/mesh/test_face.py b/python/test/unit/mesh/test_face.py index b393c0dd4cc..b665ca04280 100644 --- a/python/test/unit/mesh/test_face.py +++ b/python/test/unit/mesh/test_face.py @@ -49,10 +49,10 @@ def left_side(x): return np.isclose(x[0], 0) fdim = cube.topology.dim - 1 facets = locate_entities_boundary(cube, fdim, left_side) - normals = cell_normals(cube, fdim, facets) + normals = cell_normals(cube._cpp_object, fdim, facets) assert np.allclose(normals, [-1, 0, 0]) fdim = square.topology.dim - 1 facets = locate_entities_boundary(square, fdim, left_side) - normals = cell_normals(square, fdim, facets) + normals = cell_normals(square._cpp_object, fdim, facets) assert np.allclose(normals, [-1, 0, 0]) diff --git a/python/test/unit/mesh/test_manifold_point_search.py b/python/test/unit/mesh/test_manifold_point_search.py index 67d0f4e9d4b..8f8b10d7f87 100644 --- a/python/test/unit/mesh/test_manifold_point_search.py +++ b/python/test/unit/mesh/test_manifold_point_search.py @@ -25,8 +25,9 @@ def test_manifold_point_search(): colliding_cells = geometry.compute_colliding_cells(mesh, cell_candidates, points) # Extract vertices of cell - indices = _cpp.mesh.entities_to_geometry(mesh, mesh.topology.dim, [colliding_cells.links(0)[ - 0], colliding_cells.links(1)[0]], False) + indices = _cpp.mesh.entities_to_geometry(mesh._cpp_object, mesh.topology.dim, + [colliding_cells.links(0)[0], + colliding_cells.links(1)[0]], False) cell_vertices = mesh.geometry.x[indices] # Compare vertices with input diff --git a/python/test/unit/mesh/test_mesh.py b/python/test/unit/mesh/test_mesh.py index 38ab131cca4..591d00c6c3f 100644 --- a/python/test/unit/mesh/test_mesh.py +++ b/python/test/unit/mesh/test_mesh.py @@ -65,7 +65,7 @@ def submesh_geometry_test(mesh, submesh, entity_map, geom_map, entity_dim): if len(entity_map) > 0: assert mesh.geometry.dim == submesh.geometry.dim - e_to_g = entities_to_geometry(mesh, entity_dim, entity_map, False) + e_to_g = entities_to_geometry(mesh._cpp_object, entity_dim, entity_map, False) for submesh_entity in range(len(entity_map)): submesh_x_dofs = submesh.geometry.dofmap.links(submesh_entity) # e_to_g[i] gets the mesh x_dofs of entities[i], which should @@ -312,7 +312,7 @@ def test_cell_circumradius(c0, c1, c5): @pytest.mark.skip_in_parallel def test_cell_h(c0, c1, c5): for c in [c0, c1, c5]: - assert _cpp.mesh.h(c[0], c[1], [c[2]]) == pytest.approx(math.sqrt(2.0)) + assert c[0].h(c[1], [c[2]]) def test_cell_h_prism(): @@ -321,7 +321,7 @@ def test_cell_h_prism(): tdim = mesh.topology.dim num_cells = mesh.topology.index_map(tdim).size_local cells = np.arange(num_cells, dtype=np.int32) - h = _cpp.mesh.h(mesh, tdim, cells) + h = _cpp.mesh.h(mesh._cpp_object, tdim, cells) assert np.allclose(h, np.sqrt(3 / (N**2))) @@ -330,7 +330,7 @@ def test_facet_h(ct): N = 3 mesh = create_unit_cube(MPI.COMM_WORLD, N, N, N, ct) left_facets = locate_entities_boundary(mesh, mesh.topology.dim - 1, lambda x: np.isclose(x[0], 0)) - h = _cpp.mesh.h(mesh, mesh.topology.dim - 1, left_facets) + h = _cpp.mesh.h(mesh._cpp_object, mesh.topology.dim - 1, left_facets) assert np.allclose(h, np.sqrt(2 / (N**2))) @@ -358,7 +358,7 @@ def test_hmin_hmax(_mesh, hmin, hmax): mesh = _mesh() tdim = mesh.topology.dim num_cells = mesh.topology.index_map(tdim).size_local - h = _cpp.mesh.h(mesh, tdim, range(num_cells)) + h = _cpp.mesh.h(mesh._cpp_object, tdim, range(num_cells)) assert h.min() == pytest.approx(hmin) assert h.max() == pytest.approx(hmax) diff --git a/python/test/unit/mesh/test_refinement.py b/python/test/unit/mesh/test_refinement.py index 21ed639c3eb..589903d7a7a 100644 --- a/python/test/unit/mesh/test_refinement.py +++ b/python/test/unit/mesh/test_refinement.py @@ -139,7 +139,7 @@ def test_refine_facet_meshtag(tdim): numpy.arange(len(facet_indices), dtype=numpy.int32)) fine_mesh, parent_cell, parent_facet = _cpp.refinement.plaza_refine_data( - mesh, False, _cpp.refinement.RefinementOptions.parent_cell_and_facet) + mesh._cpp_object, False, _cpp.refinement.RefinementOptions.parent_cell_and_facet) fine_mesh.topology.create_entities(tdim - 1) new_meshtag = _cpp.refinement.transfer_facet_meshtag(meshtag, fine_mesh, parent_cell, parent_facet) @@ -177,7 +177,7 @@ def test_refine_cell_meshtag(tdim): numpy.arange(len(cell_indices), dtype=numpy.int32)) fine_mesh, parent_cell, parent_facet = _cpp.refinement.plaza_refine_data( - mesh, False, _cpp.refinement.RefinementOptions.parent_cell_and_facet) + mesh._cpp_object, False, _cpp.refinement.RefinementOptions.parent_cell_and_facet) new_meshtag = _cpp.refinement.transfer_cell_meshtag(meshtag, fine_mesh, parent_cell) diff --git a/python/test/unit/nls/test_newton.py b/python/test/unit/nls/test_newton.py index 25b66c56f23..4bf843c8552 100644 --- a/python/test/unit/nls/test_newton.py +++ b/python/test/unit/nls/test_newton.py @@ -120,7 +120,6 @@ def test_linear_pde(): def test_nonlinear_pde(): """Test Newton solver for a simple nonlinear PDE""" - # Create mesh and function space mesh = create_unit_square(MPI.COMM_WORLD, 12, 5) V = FunctionSpace(mesh, ("Lagrange", 1)) u = Function(V) @@ -154,13 +153,11 @@ def test_nonlinear_pde(): def test_nonlinear_pde_snes(): """Test Newton solver for a simple nonlinear PDE""" - # Create mesh and function space mesh = create_unit_square(MPI.COMM_WORLD, 12, 15) V = FunctionSpace(mesh, ("Lagrange", 1)) u = Function(V) v = TestFunction(V) - F = inner(5.0, v) * dx - ufl.sqrt(u * u) * inner( - grad(u), grad(v)) * dx - inner(u, v) * dx + F = inner(5.0, v) * dx - ufl.sqrt(u * u) * inner(grad(u), grad(v)) * dx - inner(u, v) * dx u_bc = Function(V) u_bc.x.array[:] = 1.0