From 9fbe4edcd20779dc27c4807009016e72e49954c9 Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Fri, 20 May 2022 09:17:17 +0200 Subject: [PATCH 01/59] Remove adjoint, unused and untested. --- python/dolfinx/fem/formmanipulations.py | 42 ------------------------- 1 file changed, 42 deletions(-) delete mode 100644 python/dolfinx/fem/formmanipulations.py diff --git a/python/dolfinx/fem/formmanipulations.py b/python/dolfinx/fem/formmanipulations.py deleted file mode 100644 index 43677b96901..00000000000 --- a/python/dolfinx/fem/formmanipulations.py +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright (C) 2010-2012 Marie E. Rognes -# -# This file is part of DOLFINx (https://www.fenicsproject.org) -# -# SPDX-License-Identifier: LGPL-3.0-or-later - -import ufl -from dolfinx.fem import function - - -def adjoint(form: ufl.Form, reordered_arguments=None) -> ufl.Form: - """Compute adjoint of a bilinear form by changing the ordering (count) - of the test and trial functions. - - The functions wraps ``ufl.adjoint``, and by default UFL will create new - ``Argument`` s. To specify the ``Argument`` s rather than creating new ones, - pass a tuple of ``Argument`` s as ``reordered_arguments``. - See the documentation for ``ufl.adjoint`` for more details. - - """ - - if reordered_arguments is not None: - return ufl.adjoint(form, reordered_arguments=reordered_arguments) - - # Extract form arguments - arguments = form.arguments() - if len(arguments) != 2: - raise RuntimeError( - "Cannot compute adjoint of form, form is not bilinear") - if any(arg.part() is not None for arg in arguments): - raise RuntimeError( - "Cannot compute adjoint of form, parts not supported") - - # Create new Arguments in the same spaces (NB: Order does not matter - # anymore here because number is absolute) - v1 = function.Argument(arguments[1].function_space, - arguments[0].number(), arguments[0].part()) - v0 = function.Argument(arguments[0].function_space, - arguments[1].number(), arguments[1].part()) - - # Return form with swapped arguments as new arguments - return ufl.adjoint(form, reordered_arguments=(v1, v0)) From 17f5d63a651d6bd287a5aabd38c1c57a9c67f630 Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Fri, 20 May 2022 09:18:56 +0200 Subject: [PATCH 02/59] Remove this, cannot work with missing RTLD_NOW in modern ctypes. --- python/dolfinx/__init__.py | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/python/dolfinx/__init__.py b/python/dolfinx/__init__.py index 04609b9dd9a..e41abe07ee7 100644 --- a/python/dolfinx/__init__.py +++ b/python/dolfinx/__init__.py @@ -6,28 +6,6 @@ """Main module for DOLFINx""" # flake8: noqa - -# Store dl open flags to restore them after import -import sys - -stored_dlopen_flags = sys.getdlopenflags() - -# Developer note: below is related to OpenMPI -# Fix dlopen flags (may need reorganising) -if "linux" in sys.platform: - # FIXME: What with other platforms? - try: - from ctypes import RTLD_GLOBAL, RTLD_NOW - except ImportError: - RTLD_NOW = 2 - RTLD_GLOBAL = 256 - sys.setdlopenflags(RTLD_NOW | RTLD_GLOBAL) -del sys - -# Reset dl open flags -# sys.setdlopenflags(stored_dlopen_flags) -# del sys - import sys from dolfinx import common From f7f9d33761365b6b536c9cf2f71c1607e2d65402 Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Fri, 20 May 2022 09:21:47 +0200 Subject: [PATCH 03/59] Work in progress for mypy pass (MetaClass stuff is tricky). --- python/dolfinx/fem/forms.py | 15 +++++++++++++-- python/dolfinx/fem/function.py | 8 ++++---- python/dolfinx/fem/petsc.py | 4 ++-- python/dolfinx/jit.py | 4 ++-- python/dolfinx/la.py | 6 +++++- python/dolfinx/mesh.py | 6 +++--- 6 files changed, 29 insertions(+), 14 deletions(-) diff --git a/python/dolfinx/fem/forms.py b/python/dolfinx/fem/forms.py index d7832733552..444a7a0e3e1 100644 --- a/python/dolfinx/fem/forms.py +++ b/python/dolfinx/fem/forms.py @@ -9,6 +9,8 @@ import collections import typing +from dolfinx.fem.function import FunctionSpace + if typing.TYPE_CHECKING: from dolfinx.fem import function @@ -24,7 +26,8 @@ class FormMetaClass: def __init__(self, form, V: list[_cpp.fem.FunctionSpace], coeffs, constants, - subdomains: dict[_cpp.mesh.MeshTags_int32], mesh: _cpp.mesh.Mesh, code): + subdomains: dict[_cpp.mesh.MeshTags_int32, typing.Union[None, typing.Any]], mesh: _cpp.mesh.Mesh, + code): """A finite element form Notes: @@ -46,7 +49,7 @@ def __init__(self, form, V: list[_cpp.fem.FunctionSpace], coeffs, constants, self._ufcx_form = form ffi = cffi.FFI() super().__init__(ffi.cast("uintptr_t", ffi.addressof(self._ufcx_form)), - V, coeffs, constants, subdomains, mesh) + V, coeffs, constants, subdomains, mesh) # type: ignore @property def ufcx_form(self): @@ -58,6 +61,14 @@ def code(self) -> str: """C code strings""" return self._code + @property + def function_spaces(self) -> typing.List[FunctionSpace]: + raise NotImplementedError + + @property + def dtype(self) -> np.dtype: + raise NotImplementedError + def form(form: typing.Union[ufl.Form, typing.Iterable[ufl.Form]], dtype: np.dtype = PETSc.ScalarType, form_compiler_params: dict = {}, jit_params: dict = {}) -> FormMetaClass: diff --git a/python/dolfinx/fem/function.py b/python/dolfinx/fem/function.py index 604f8d2402a..84cf3cac4d3 100644 --- a/python/dolfinx/fem/function.py +++ b/python/dolfinx/fem/function.py @@ -402,7 +402,7 @@ def split(self) -> tuple[Function, ...]: def collapse(self) -> Function: u_collapsed = self._cpp_object.collapse() - V_collapsed = FunctionSpace(None, self.ufl_element(), + V_collapsed = FunctionSpace(self.mesh, self.ufl_element(), u_collapsed.function_space) return Function(V_collapsed, u_collapsed.x) @@ -467,7 +467,7 @@ def clone(self) -> FunctionSpace: """ Vcpp = _cpp.fem.FunctionSpace(self._cpp_object.mesh, self._cpp_object.element, self._cpp_object.dofmap) - return FunctionSpace(None, self.ufl_element(), Vcpp) + return FunctionSpace(self.mesh, self.ufl_element(), Vcpp) @property def num_sub_spaces(self) -> int: @@ -487,7 +487,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.""" @@ -543,7 +543,7 @@ 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: diff --git a/python/dolfinx/fem/petsc.py b/python/dolfinx/fem/petsc.py index 8cf8833ecf5..03433fb4d28 100644 --- a/python/dolfinx/fem/petsc.py +++ b/python/dolfinx/fem/petsc.py @@ -50,8 +50,8 @@ def fn(form): Vblock = map(partial(map, fn), a) # Compute spaces for each row/column block - rows = [set() for i in range(len(a))] - cols = [set() for i in range(len(a[0]))] + rows: typing.List[typing.Set] = [set() for i in range(len(a))] + cols: typing.List[typing.Set] = [set() for i in range(len(a[0]))] for i, Vrow in enumerate(Vblock): for j, V in enumerate(Vrow): if V is not None: diff --git a/python/dolfinx/jit.py b/python/dolfinx/jit.py index a51bc73dabd..7b395fabaa1 100644 --- a/python/dolfinx/jit.py +++ b/python/dolfinx/jit.py @@ -132,7 +132,7 @@ def get_parameters(priority_parameters: Optional[dict] = None) -> dict: """ parameters = {} - for param, (value, desc) in DOLFINX_DEFAULT_JIT_PARAMETERS.items(): + for param, (value, _) in DOLFINX_DEFAULT_JIT_PARAMETERS.items(): parameters[param] = value # NOTE: _load_parameters uses functools.lru_cache @@ -143,7 +143,7 @@ def get_parameters(priority_parameters: Optional[dict] = None) -> dict: if priority_parameters is not None: parameters.update(priority_parameters) - parameters["cache_dir"] = Path(parameters["cache_dir"]).expanduser() + parameters["cache_dir"] = Path(str(parameters["cache_dir"])).expanduser() return parameters diff --git a/python/dolfinx/la.py b/python/dolfinx/la.py index de5f1a44429..fd95a49ae8b 100644 --- a/python/dolfinx/la.py +++ b/python/dolfinx/la.py @@ -94,7 +94,11 @@ def __init__(self, map, bs): and not created using the class initialiser. """ - super().__init__(map, bs) + super().__init__(map, bs) # type: ignore + + @property + def array(self) -> np.ndarray: + raise NotImplementedError def vector(map, bs=1, dtype=np.float64) -> VectorMetaClass: diff --git a/python/dolfinx/mesh.py b/python/dolfinx/mesh.py index fda5a2a3f54..37b0896bf3a 100644 --- a/python/dolfinx/mesh.py +++ b/python/dolfinx/mesh.py @@ -217,7 +217,7 @@ def __init__(self, mesh: Mesh, dim: int, indices: np.ndarray, values: np.ndarray directly. """ - super().__init__(mesh, dim, indices.astype(np.int32), values) + super().__init__(mesh, dim, indices.astype(np.int32), values) # type: ignore def ufl_id(self) -> int: """Object identifier. @@ -343,7 +343,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: typing.List[np.array], n: list, cell_type=CellType.triangle, +def create_rectangle(comm: _MPI.Comm, points: typing.List[np.ndarray], 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 @@ -395,7 +395,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[np.array], n: list, +def create_box(comm: _MPI.Comm, points: typing.List[np.ndarray], n: list, cell_type=CellType.tetrahedron, ghost_mode=GhostMode.shared_facet, partitioner=_cpp.mesh.create_cell_partitioner()) -> Mesh: From 0a849cd272c179d4ad6d1c160171f0433b385c23 Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Fri, 20 May 2022 09:26:33 +0200 Subject: [PATCH 04/59] Add mypy to ubuntu image --- .github/workflows/ccpp.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index 2c7f2738eff..f49d6242474 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -89,6 +89,14 @@ jobs: run: | cd python/dolfinx/wrappers find . -type f \( -name "*.cpp" -o -name "*.h" \) | xargs clang-format --dry-run --Werror + - name: mypy checks (non-blocking) + continue-on-error: true + run: | + python -m pip install mypy # To remove once Docker images re-built + cd python/ + mypy --ignore-missing-imports dolfinx + mypy --ignore-missing-imports demo + mypy --ignore-missing-imports test - name: Configure C++ run: cmake -G Ninja -DCMAKE_BUILD_TYPE=Developer -B build -S cpp/ From bd8a5086a5084d1d5b8c97bd2c7145b2b5fbee3a Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Fri, 20 May 2022 09:26:52 +0200 Subject: [PATCH 05/59] Again --- docker/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index b60b89672c5..0cfde76c9e2 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -173,8 +173,8 @@ RUN if [ "$MPI" = "mpich" ]; then \ # - First set of packages are required to build and run DOLFINx Python. # - Second set of packages are recommended and/or required to build # documentation or run tests. -RUN pip3 install --no-cache-dir cffi mpi4py numba && \ - pip3 install --no-cache-dir cppimport flake8 isort jupytext matplotlib myst-parser pybind11==${PYBIND11_VERSION} pytest pytest-xdist sphinx sphinx_rtd_theme +RUN pip3 install --no-cache-dir cffi mpi4py numba pybind11==${PYBIND11_VERSION} && \ + pip3 install --no-cache-dir cppimport flake8 isort jupytext matplotlib mypy myst-parser pytest pytest-xdist sphinx sphinx_rtd_theme # Upgrade numpy via pip. Exclude binaries to avoid conflicts with libblas # (See issue #126 and #1305) From c417f260e31ac9d5d403b3ed17fb7584ded9cbb9 Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Fri, 20 May 2022 09:35:12 +0200 Subject: [PATCH 06/59] Move later --- .github/workflows/ccpp.yml | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index f49d6242474..945a3b4bac2 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -89,14 +89,6 @@ jobs: run: | cd python/dolfinx/wrappers find . -type f \( -name "*.cpp" -o -name "*.h" \) | xargs clang-format --dry-run --Werror - - name: mypy checks (non-blocking) - continue-on-error: true - run: | - python -m pip install mypy # To remove once Docker images re-built - cd python/ - mypy --ignore-missing-imports dolfinx - mypy --ignore-missing-imports demo - mypy --ignore-missing-imports test - name: Configure C++ run: cmake -G Ninja -DCMAKE_BUILD_TYPE=Developer -B build -S cpp/ @@ -147,6 +139,15 @@ jobs: mkdir -p ~/.config/dolfinx echo '{ "cffi_extra_compile_args": ["-g0", "-O0" ] }' > ~/.config/dolfinx/dolfinx_jit_parameters.json + - name: mypy checks (non-blocking) + continue-on-error: true + run: | + python -m pip install mypy # To remove once Docker images re-built + cd python/ + mypy --ignore-missing-imports dolfinx + mypy --ignore-missing-imports demo + mypy --ignore-missing-imports test + - name: Run demos (Python, serial) run: python3 -m pytest -n=2 -m serial --durations=10 python/demo/test.py - name: Run demos (Python, MPI (np=2)) From 3494584332bb3b076994ced6e01fc9772f04df84 Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Fri, 20 May 2022 09:53:10 +0200 Subject: [PATCH 07/59] Bit more typing, remove adjoint import --- python/dolfinx/fem/__init__.py | 1 - python/dolfinx/fem/forms.py | 13 +++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/python/dolfinx/fem/__init__.py b/python/dolfinx/fem/__init__.py index 8f2fcd2494c..c7a2f6136a6 100644 --- a/python/dolfinx/fem/__init__.py +++ b/python/dolfinx/fem/__init__.py @@ -14,7 +14,6 @@ from dolfinx.fem.bcs import (DirichletBCMetaClass, bcs_by_block, dirichletbc, locate_dofs_geometrical, locate_dofs_topological) from dolfinx.fem.dofmap import DofMap -from dolfinx.fem.formmanipulations import adjoint from dolfinx.fem.forms import FormMetaClass, extract_function_spaces, form from dolfinx.fem.function import (Constant, Expression, Function, FunctionSpace, TensorFunctionSpace, diff --git a/python/dolfinx/fem/forms.py b/python/dolfinx/fem/forms.py index 444a7a0e3e1..e95b6ab5c80 100644 --- a/python/dolfinx/fem/forms.py +++ b/python/dolfinx/fem/forms.py @@ -13,6 +13,7 @@ if typing.TYPE_CHECKING: from dolfinx.fem import function + from dolfinx.mesh import Mesh import cffi import numpy as np @@ -63,10 +64,22 @@ def code(self) -> str: @property def function_spaces(self) -> typing.List[FunctionSpace]: + """Function spaces on which this form is defined""" raise NotImplementedError @property def dtype(self) -> np.dtype: + """dtype of this form""" + raise NotImplementedError + + @property + def mesh(self) -> Mesh: + """Mesh on which this form is defined""" + raise NotImplementedError + + @property + def integral_types(self): + """Integral types in the form""" raise NotImplementedError From 068c3e82f742975aa0c26e6b22853044624cb0d1 Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Fri, 20 May 2022 10:23:22 +0200 Subject: [PATCH 08/59] Fix but more typing errors back --- python/dolfinx/fem/function.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/python/dolfinx/fem/function.py b/python/dolfinx/fem/function.py index 84cf3cac4d3..e7380a09d7f 100644 --- a/python/dolfinx/fem/function.py +++ b/python/dolfinx/fem/function.py @@ -402,7 +402,7 @@ def split(self) -> tuple[Function, ...]: def collapse(self) -> Function: u_collapsed = self._cpp_object.collapse() - V_collapsed = FunctionSpace(self.mesh, self.ufl_element(), + V_collapsed = FunctionSpace(None, self.ufl_element(), u_collapsed.function_space) return Function(V_collapsed, u_collapsed.x) @@ -417,7 +417,7 @@ class ElementMetaData(typing.NamedTuple): class FunctionSpace(ufl.FunctionSpace): """A space on which Functions (fields) can be defined.""" - def __init__(self, mesh: Mesh, element: typing.Union[ufl.FiniteElementBase, ElementMetaData], + def __init__(self, mesh: typing.Union[None, Mesh], element: typing.Union[ufl.FiniteElementBase, ElementMetaData], cppV: typing.Optional[_cpp.fem.FunctionSpace] = None, form_compiler_params: dict = {}, jit_params: dict = {}): """Create a finite element function space.""" @@ -467,7 +467,7 @@ def clone(self) -> FunctionSpace: """ Vcpp = _cpp.fem.FunctionSpace(self._cpp_object.mesh, self._cpp_object.element, self._cpp_object.dofmap) - return FunctionSpace(self.mesh, self.ufl_element(), Vcpp) + return FunctionSpace(None, self.ufl_element(), Vcpp) @property def num_sub_spaces(self) -> int: @@ -487,7 +487,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(self.mesh, sub_element, cppV_sub) + return FunctionSpace(None, sub_element, cppV_sub) def component(self): """Return the component relative to the parent space.""" @@ -543,7 +543,7 @@ def collapse(self) -> tuple[FunctionSpace, np.ndarray]: """ cpp_space, dofs = self._cpp_object.collapse() - V = FunctionSpace(self.mesh, self.ufl_element(), cpp_space) + V = FunctionSpace(None, self.ufl_element(), cpp_space) return V, dofs def tabulate_dof_coordinates(self) -> np.ndarray: From 764faae4ae4e9ee59a3590437454b6db07779821 Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Fri, 20 May 2022 10:32:38 +0200 Subject: [PATCH 09/59] Adding if makes type check pass --- python/dolfinx/fem/function.py | 42 ++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/python/dolfinx/fem/function.py b/python/dolfinx/fem/function.py index e7380a09d7f..bc9d996bf17 100644 --- a/python/dolfinx/fem/function.py +++ b/python/dolfinx/fem/function.py @@ -431,26 +431,28 @@ def __init__(self, mesh: typing.Union[None, Mesh], element: typing.Union[ufl.Fin self._cpp_object = cppV return - # Initialise the ufl.FunctionSpace - if isinstance(element, ufl.FiniteElementBase): - super().__init__(mesh.ufl_domain(), element) - else: - e = ElementMetaData(*element) - ufl_element = ufl.FiniteElement(e.family, mesh.ufl_cell(), e.degree, form_degree=e.form_degree) - super().__init__(mesh.ufl_domain(), ufl_element) - - # Compile dofmap and element and create DOLFIN objects - (self._ufcx_element, self._ufcx_dofmap), module, code = jit.ffcx_jit( - mesh.comm, self.ufl_element(), form_compiler_params=form_compiler_params, - jit_params=jit_params) - - ffi = cffi.FFI() - 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) + # This if is required for type checks to pass + if mesh is not None: + # Initialise the ufl.FunctionSpace + if isinstance(element, ufl.FiniteElementBase): + super().__init__(mesh.ufl_domain(), element) + else: + e = ElementMetaData(*element) + ufl_element = ufl.FiniteElement(e.family, mesh.ufl_cell(), e.degree, form_degree=e.form_degree) + super().__init__(mesh.ufl_domain(), ufl_element) + + # Compile dofmap and element and create DOLFIN objects + (self._ufcx_element, self._ufcx_dofmap), module, code = jit.ffcx_jit( + mesh.comm, self.ufl_element(), form_compiler_params=form_compiler_params, + jit_params=jit_params) + + ffi = cffi.FFI() + 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) def clone(self) -> FunctionSpace: """Return a new FunctionSpace :math:`W` which shares data with this From 5d2c43901dd6a4765802b8cc2bec373a6328d413 Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Fri, 20 May 2022 14:56:10 +0200 Subject: [PATCH 10/59] 35 errors left in python/dolfinx --- python/dolfinx/fem/bcs.py | 47 ++++++++++++++----------------------- python/dolfinx/fem/forms.py | 14 ++++++----- python/dolfinx/la.py | 2 +- 3 files changed, 27 insertions(+), 36 deletions(-) diff --git a/python/dolfinx/fem/bcs.py b/python/dolfinx/fem/bcs.py index a815036fb22..66a68fc69a7 100644 --- a/python/dolfinx/fem/bcs.py +++ b/python/dolfinx/fem/bcs.py @@ -11,7 +11,7 @@ import typing if typing.TYPE_CHECKING: - from dolfinx.fem.function import Constant, Function, FunctionSpace + from dolfinx.fem.function import Constant, Function import collections.abc import types @@ -20,10 +20,11 @@ import numpy as np import ufl +import dolfinx from dolfinx import cpp as _cpp -def locate_dofs_geometrical(V: typing.Iterable[typing.Union[_cpp.fem.FunctionSpace, FunctionSpace]], +def locate_dofs_geometrical(V: typing.Union[dolfinx.fem.FunctionSpace, typing.Iterable[dolfinx.fem.FunctionSpace]], marker: types.FunctionType) -> np.ndarray: """Locate degrees-of-freedom geometrically using a marker function. @@ -48,21 +49,15 @@ def locate_dofs_geometrical(V: typing.Iterable[typing.Union[_cpp.fem.FunctionSpa """ if isinstance(V, collections.abc.Sequence): - _V = [] - for space in V: - try: - _V.append(space._cpp_object) - except AttributeError: - _V.append(space) + _V = [space._cpp_object for space in V] return _cpp.fem.locate_dofs_geometrical(_V, marker) + elif isinstance(V, dolfinx.fem.FunctionSpace): + return _cpp.fem.locate_dofs_geometrical(V._cpp_object, marker) else: - try: - return _cpp.fem.locate_dofs_geometrical(V, marker) - except TypeError: - return _cpp.fem.locate_dofs_geometrical(V._cpp_object, marker) + raise TypeError -def locate_dofs_topological(V: typing.Iterable[typing.Union[_cpp.fem.FunctionSpace, FunctionSpace]], +def locate_dofs_topological(V: typing.Union[dolfinx.fem.FunctionSpace, typing.Iterable[dolfinx.fem.FunctionSpace]], entity_dim: int, entities: typing.List[int], remote: bool = True) -> np.ndarray: """Locate degrees-of-freedom belonging to mesh entities topologically. @@ -87,23 +82,17 @@ def locate_dofs_topological(V: typing.Iterable[typing.Union[_cpp.fem.FunctionSpa _entities = np.asarray(entities, dtype=np.int32) if isinstance(V, collections.abc.Sequence): - _V = [] - for space in V: - try: - _V.append(space._cpp_object) - except AttributeError: - _V.append(space) + _V = [space._cpp_object for space in V] return _cpp.fem.locate_dofs_topological(_V, entity_dim, _entities, remote) + elif isinstance(V, dolfinx.fem.FunctionSpace): + return _cpp.fem.locate_dofs_topological(V._cpp_object, entity_dim, _entities, remote) else: - try: - return _cpp.fem.locate_dofs_topological(V, entity_dim, _entities, remote) - except TypeError: - return _cpp.fem.locate_dofs_topological(V._cpp_object, entity_dim, _entities, remote) + raise TypeError class DirichletBCMetaClass: def __init__(self, value: typing.Union[ufl.Coefficient, Function, Constant], - dofs: typing.List[int], V: FunctionSpace = None): + dofs: typing.List[int], V: dolfinx.fem.FunctionSpace = None): """Representation of Dirichlet boundary condition which is imposed on a linear system. @@ -133,11 +122,11 @@ class initialiser. This class is combined with different if V is not None: try: - super().__init__(_value, dofs, V) + super().__init__(_value, dofs, V) # type: ignore except TypeError: - super().__init__(_value, dofs, V._cpp_object) + super().__init__(_value, dofs, V._cpp_object) # type: ignore else: - super().__init__(_value, dofs) + super().__init__(_value, dofs) # type: ignore @property def g(self): @@ -146,7 +135,7 @@ def g(self): def dirichletbc(value: typing.Union[Function, Constant], - dofs: typing.List[int], V: FunctionSpace = None) -> DirichletBCMetaClass: + dofs: typing.List[int], V: dolfinx.fem.FunctionSpace = None) -> DirichletBCMetaClass: """Create a representation of Dirichlet boundary condition which is imposed on a linear system. @@ -181,7 +170,7 @@ def dirichletbc(value: typing.Union[Function, Constant], return formcls(value, dofs, V) -def bcs_by_block(spaces: typing.Iterable[FunctionSpace], +def bcs_by_block(spaces: typing.Iterable[dolfinx.fem.FunctionSpace], bcs: typing.Iterable[DirichletBCMetaClass]) -> typing.Iterable[typing.Iterable[DirichletBCMetaClass]]: """Arrange Dirichlet boundary conditions by the function space that they constrain. diff --git a/python/dolfinx/fem/forms.py b/python/dolfinx/fem/forms.py index e95b6ab5c80..82215a2ba3c 100644 --- a/python/dolfinx/fem/forms.py +++ b/python/dolfinx/fem/forms.py @@ -7,6 +7,7 @@ from __future__ import annotations import collections +import collections.abc import typing from dolfinx.fem.function import FunctionSpace @@ -62,29 +63,30 @@ def code(self) -> str: """C code strings""" return self._code + # The below member function definitions are necessary for type checking @property def function_spaces(self) -> typing.List[FunctionSpace]: """Function spaces on which this form is defined""" - raise NotImplementedError + return super().function_spaces # type: ignore @property def dtype(self) -> np.dtype: """dtype of this form""" - raise NotImplementedError + return super().dtype # type: ignore @property def mesh(self) -> Mesh: """Mesh on which this form is defined""" - raise NotImplementedError + return super().mesh # type: ignore @property def integral_types(self): """Integral types in the form""" - raise NotImplementedError + return super().integral_types # type: ignore def form(form: typing.Union[ufl.Form, typing.Iterable[ufl.Form]], dtype: np.dtype = PETSc.ScalarType, - form_compiler_params: dict = {}, jit_params: dict = {}) -> FormMetaClass: + form_compiler_params: dict = {}, jit_params: dict = {}): """Create a DOLFINx Form or an array of Forms Args: @@ -165,7 +167,7 @@ def _create_form(form): def extract_function_spaces(forms: typing.Union[typing.Iterable[FormMetaClass], typing.Iterable[typing.Iterable[FormMetaClass]]], - index: int = 0) -> typing.Iterable[function.FunctionSpace]: + index: int = 0) -> typing.Iterable[typing.Union[None, function.FunctionSpace]]: """Extract common function spaces from an array of forms. If `forms` is a list of linear form, this function returns of list of the corresponding test functions. If `forms` is a 2D array of bilinear diff --git a/python/dolfinx/la.py b/python/dolfinx/la.py index fd95a49ae8b..0a9bf606093 100644 --- a/python/dolfinx/la.py +++ b/python/dolfinx/la.py @@ -98,7 +98,7 @@ def __init__(self, map, bs): @property def array(self) -> np.ndarray: - raise NotImplementedError + return super().array # type: ignore def vector(map, bs=1, dtype=np.float64) -> VectorMetaClass: From 129fda7a3661e6c8470c30fa449abe6e659ed7d0 Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Fri, 20 May 2022 17:13:01 +0200 Subject: [PATCH 11/59] Remaining issues are due to use of single dispatch --- python/dolfinx/fem/petsc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/dolfinx/fem/petsc.py b/python/dolfinx/fem/petsc.py index 03433fb4d28..c5ff9d9cfdf 100644 --- a/python/dolfinx/fem/petsc.py +++ b/python/dolfinx/fem/petsc.py @@ -47,7 +47,7 @@ def _extract_function_spaces(a: typing.List[typing.List[FormMetaClass]]): def fn(form): return form.function_spaces if form is not None else None from functools import partial - Vblock = map(partial(map, fn), a) + Vblock: typing.Iterable = map(partial(map, fn), a) # Compute spaces for each row/column block rows: typing.List[typing.Set] = [set() for i in range(len(a))] @@ -441,7 +441,7 @@ def _(A: PETSc.Mat, a: typing.List[typing.List[FormMetaClass]], def apply_lifting(b: PETSc.Vec, a: typing.List[FormMetaClass], bcs: typing.List[typing.List[DirichletBCMetaClass]], - x0: typing.Optional[typing.List[PETSc.Vec]] = [], + x0: typing.List[PETSc.Vec] = [], scale: float = 1.0, constants=None, coeffs=None) -> None: """Apply the function :func:`dolfinx.fem.apply_lifting` to a PETSc Vector.""" with contextlib.ExitStack() as stack: From edff60ba015ab8a468db58370577659bfae0ce74 Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Fri, 20 May 2022 17:35:13 +0200 Subject: [PATCH 12/59] Add py.typed files so that users actually see type annotations --- python/demo/demo_tnt-elements.py | 5 +++-- python/dolfinx/fem/py.typed | 0 python/dolfinx/nls/py.typed | 0 python/dolfinx/py.typed | 0 python/setup.py | 3 ++- 5 files changed, 5 insertions(+), 3 deletions(-) create mode 100644 python/dolfinx/fem/py.typed create mode 100644 python/dolfinx/nls/py.typed create mode 100644 python/dolfinx/py.typed diff --git a/python/demo/demo_tnt-elements.py b/python/demo/demo_tnt-elements.py index 9d8862f0475..c5dc6865797 100644 --- a/python/demo/demo_tnt-elements.py +++ b/python/demo/demo_tnt-elements.py @@ -17,6 +17,7 @@ # We begin this demo by importing everything we require. # + +import typing import matplotlib.pylab as plt import numpy as np @@ -68,8 +69,8 @@ # + geometry = basix.geometry(basix.CellType.quadrilateral) topology = basix.topology(basix.CellType.quadrilateral) -x = [[], [], [], []] -M = [[], [], [], []] +x : typing.List[typing.List[np.ndarray]] = [[], [], [], []] +M : typing.List[typing.List[np.ndarray]] = [[], [], [], []] for v in topology[0]: x[0].append(np.array(geometry[v])) diff --git a/python/dolfinx/fem/py.typed b/python/dolfinx/fem/py.typed new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/dolfinx/nls/py.typed b/python/dolfinx/nls/py.typed new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/dolfinx/py.typed b/python/dolfinx/py.typed new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/setup.py b/python/setup.py index 73de388aeba..2c8fc71c938 100644 --- a/python/setup.py +++ b/python/setup.py @@ -73,7 +73,8 @@ def build_extension(self, ext): "dolfinx.fem", "dolfinx.nls", "dolfinx.wrappers"], - package_data={'dolfinx.wrappers': ['*.h']}, + package_data={'dolfinx.wrappers': ['*.h'], 'dolfinx': ['py.typed'], + 'dolfinx.fem': ['py.typed'], 'dolfinx.nls': ['py.typed']}, ext_modules=[CMakeExtension('dolfinx.cpp')], cmdclass=dict(build_ext=CMakeBuild), install_requires=REQUIREMENTS, From a3b5a863eb81ea857f13b25e3729060c0e3b202c Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Fri, 20 May 2022 19:19:01 +0200 Subject: [PATCH 13/59] Generalised arguments types for mesh constructors --- python/demo/demo_poisson.py | 2 +- python/dolfinx/fem/bcs.py | 7 ++++--- python/dolfinx/mesh.py | 5 +++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/python/demo/demo_poisson.py b/python/demo/demo_poisson.py index 8a6e8c095a5..7b547c6b8d0 100644 --- a/python/demo/demo_poisson.py +++ b/python/demo/demo_poisson.py @@ -155,7 +155,7 @@ # + try: import pyvista - cells, types, x = plot.create_vtk_mesh(V) + cells, types, x = plot.create_vtk_mesh(V, dim=2) grid = pyvista.UnstructuredGrid(cells, types, x) grid.point_data["u"] = uh.x.array.real grid.set_active_scalars("u") diff --git a/python/dolfinx/fem/bcs.py b/python/dolfinx/fem/bcs.py index 66a68fc69a7..a68d7abf56d 100644 --- a/python/dolfinx/fem/bcs.py +++ b/python/dolfinx/fem/bcs.py @@ -9,6 +9,7 @@ from __future__ import annotations import typing +import numpy.typing if typing.TYPE_CHECKING: from dolfinx.fem.function import Constant, Function @@ -58,7 +59,7 @@ def locate_dofs_geometrical(V: typing.Union[dolfinx.fem.FunctionSpace, typing.It def locate_dofs_topological(V: typing.Union[dolfinx.fem.FunctionSpace, typing.Iterable[dolfinx.fem.FunctionSpace]], - entity_dim: int, entities: typing.List[int], + entity_dim: int, entities: numpy.typing.NDArray[np.int32], remote: bool = True) -> np.ndarray: """Locate degrees-of-freedom belonging to mesh entities topologically. @@ -92,7 +93,7 @@ def locate_dofs_topological(V: typing.Union[dolfinx.fem.FunctionSpace, typing.It class DirichletBCMetaClass: def __init__(self, value: typing.Union[ufl.Coefficient, Function, Constant], - dofs: typing.List[int], V: dolfinx.fem.FunctionSpace = None): + dofs: numpy.typing.ArrayLike, V: dolfinx.fem.FunctionSpace = None): """Representation of Dirichlet boundary condition which is imposed on a linear system. @@ -135,7 +136,7 @@ def g(self): def dirichletbc(value: typing.Union[Function, Constant], - dofs: typing.List[int], V: dolfinx.fem.FunctionSpace = None) -> DirichletBCMetaClass: + dofs: numpy.typing.NDArray[np.int32], V: dolfinx.fem.FunctionSpace = None) -> DirichletBCMetaClass: """Create a representation of Dirichlet boundary condition which is imposed on a linear system. diff --git a/python/dolfinx/mesh.py b/python/dolfinx/mesh.py index 37b0896bf3a..3edc05d6520 100644 --- a/python/dolfinx/mesh.py +++ b/python/dolfinx/mesh.py @@ -11,6 +11,7 @@ import typing import numpy as np +import numpy.typing import ufl from dolfinx import cpp as _cpp @@ -84,7 +85,7 @@ def locate_entities(mesh: Mesh, dim: int, marker: types.FunctionType) -> np.ndar return _cpp.mesh.locate_entities(mesh, dim, marker) -def locate_entities_boundary(mesh: Mesh, dim: int, marker: types.FunctionType) -> np.ndarray: +def locate_entities_boundary(mesh: Mesh, dim: int, marker: typing.Callable) -> np.ndarray: """Compute mesh entities that are connected to an owned boundary facet and satisfy a geometric marking function @@ -343,7 +344,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: typing.List[np.ndarray], n: list, cell_type=CellType.triangle, +def create_rectangle(comm: _MPI.Comm, points: numpy.typing.ArrayLike, n: numpy.typing.ArrayLike, cell_type=CellType.triangle, ghost_mode=GhostMode.shared_facet, partitioner=_cpp.mesh.create_cell_partitioner(), diagonal: DiagonalType = DiagonalType.right) -> Mesh: """Create rectangle mesh From 1d50a2ef4386e456da09ca947bc456723cd8eb65 Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Sat, 21 May 2022 16:22:18 +0200 Subject: [PATCH 14/59] Fix singledispatch definition to raise NotImplementedError if no method found. --- python/dolfinx/fem/assemble.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/python/dolfinx/fem/assemble.py b/python/dolfinx/fem/assemble.py index 35d06ae973f..eab858d6244 100644 --- a/python/dolfinx/fem/assemble.py +++ b/python/dolfinx/fem/assemble.py @@ -1,4 +1,4 @@ -# Copyright (C) 2018-2022 Garth N. Wells +# Copyright (C) 2018-2022 Garth N. Wells, Jack S. Hale # # This file is part of DOLFINx (https://www.fenicsproject.org) # @@ -11,7 +11,6 @@ import typing if typing.TYPE_CHECKING: - from dolfinx.fem.forms import FormMetaClass from dolfinx.fem.bcs import DirichletBCMetaClass import functools @@ -23,6 +22,7 @@ from dolfinx import la from dolfinx.cpp.fem import pack_coefficients as _pack_coefficients from dolfinx.cpp.fem import pack_constants as _pack_constants +from dolfinx.fem.forms import FormMetaClass def pack_constants(form: typing.Union[FormMetaClass, @@ -133,11 +133,16 @@ def assemble_scalar(M: FormMetaClass, constants=None, coeffs=None): # -- Vector assembly --------------------------------------------------------- @functools.singledispatch -def assemble_vector(L: FormMetaClass, constants=None, coeffs=None) -> la.VectorMetaClass: +def assemble_vector(L: typing.Any, constants=None, coeffs=None): + raise NotImplementedError + + +@assemble_vector.register(FormMetaClass) +def _(L: FormMetaClass, constants=None, coeffs=None) -> la.VectorMetaClass: """Assemble linear form into a new Vector. Args: - L: The linear form assemble. + L: The linear form to assemble. constants: Constants that appear in the form. If not provided, any required constants will be computed. coeffs: Coefficients that appear in the form. If not provided, From 31d55be09a9ad183c73f3eda3b82ffded03ff718 Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Sat, 21 May 2022 16:41:31 +0200 Subject: [PATCH 15/59] Fixes all typing issues in assemble. --- python/dolfinx/fem/assemble.py | 72 ++++++++++++++++++++-------------- 1 file changed, 42 insertions(+), 30 deletions(-) diff --git a/python/dolfinx/fem/assemble.py b/python/dolfinx/fem/assemble.py index eab858d6244..018b6b3fb37 100644 --- a/python/dolfinx/fem/assemble.py +++ b/python/dolfinx/fem/assemble.py @@ -134,11 +134,14 @@ def assemble_scalar(M: FormMetaClass, constants=None, coeffs=None): @functools.singledispatch def assemble_vector(L: typing.Any, constants=None, coeffs=None): - raise NotImplementedError + try: + return _assemble_vector_form(L, constants, coeffs) + except TypeError: + raise NotImplementedError @assemble_vector.register(FormMetaClass) -def _(L: FormMetaClass, constants=None, coeffs=None) -> la.VectorMetaClass: +def _assemble_vector_form(L: FormMetaClass, constants=None, coeffs=None) -> la.VectorMetaClass: """Assemble linear form into a new Vector. Args: @@ -167,12 +170,12 @@ def _(L: FormMetaClass, constants=None, coeffs=None) -> la.VectorMetaClass: b.array[:] = 0 constants = constants or _pack_constants(L) coeffs = coeffs or _pack_coefficients(L) - _cpp.fem.assemble_vector(b.array, L, constants, coeffs) + _assemble_vector_array(b.array, L, constants, coeffs) return b @assemble_vector.register(np.ndarray) -def _(b: np.ndarray, L: FormMetaClass, constants=None, coeffs=None): +def _assemble_vector_array(b: np.ndarray, L: FormMetaClass, constants=None, coeffs=None): """Assemble linear form into a new Vector. Args: @@ -206,67 +209,76 @@ def _(b: np.ndarray, L: FormMetaClass, constants=None, coeffs=None): @functools.singledispatch -def assemble_matrix(a: FormMetaClass, bcs: typing.List[DirichletBCMetaClass] = None, - diagonal: float = 1.0, - constants=None, coeffs=None) -> la.MatrixCSRMetaClass: +def assemble_matrix(a: typing.Any, bcs: typing.List[DirichletBCMetaClass] = None, + diagonal: float = 1.0, constants=None, coeffs=None): + try: + return _assemble_matrix_form(a, bcs, diagonal, constants, coeffs) + except TypeError: + raise NotImplementedError + + +@assemble_matrix.register(la.MatrixCSRMetaClass) +def _assemble_matrix_csr(A: la.MatrixCSRMetaClass, a: FormMetaClass, + bcs: typing.List[DirichletBCMetaClass] = None, + diagonal: float = 1.0, constants=None, coeffs=None) -> la.MatrixCSRMetaClass: """Assemble bilinear form into a matrix. - Args: + Args: a: The bilinear form assemble. bcs: Boundary conditions that affect the assembled matrix. Degrees-of-freedom constrained by a boundary condition will - have their rows/columns zeroed and the value ``diagonal`` - set on on the matrix diagonal. + have their rows/columns zeroed and the value ``diagonal`` set + on on the matrix diagonal. constants: Constants that appear in the form. If not provided, any required constants will be computed. coeffs: Coefficients that appear in the form. If not provided, any required coefficients will be computed. - Returns: - Matrix representation of the bilinear form ``a``. - Note: The returned matrix is not finalised, i.e. ghost values are not accumulated. """ bcs = [] if bcs is None else bcs - A = create_matrix(a) - assemble_matrix(A, a, bcs, diagonal, constants, coeffs) + constants = _pack_constants(a) if constants is None else constants + coeffs = _pack_coefficients(a) if coeffs is None else coeffs + _cpp.fem.assemble_matrix(A, a, constants, coeffs, bcs) + + # If matrix is a 'diagonal'block, set diagonal entry for constrained + # dofs + if a.function_spaces[0] is a.function_spaces[1]: + _cpp.fem.insert_diagonal(A, a.function_spaces[0], bcs, diagonal) return A -@assemble_matrix.register(la.MatrixCSRMetaClass) -def _(A: la.MatrixCSRMetaClass, a: FormMetaClass, - bcs: typing.List[DirichletBCMetaClass] = None, - diagonal: float = 1.0, constants=None, coeffs=None) -> la.MatrixCSRMetaClass: +@assemble_matrix.register(FormMetaClass) +def _assemble_matrix_form(a: FormMetaClass, bcs: typing.List[DirichletBCMetaClass] = None, + diagonal: float = 1.0, + constants=None, coeffs=None) -> la.MatrixCSRMetaClass: """Assemble bilinear form into a matrix. - Args: + Args: a: The bilinear form assemble. bcs: Boundary conditions that affect the assembled matrix. Degrees-of-freedom constrained by a boundary condition will - have their rows/columns zeroed and the value ``diagonal`` set - on on the matrix diagonal. + have their rows/columns zeroed and the value ``diagonal`` + set on on the matrix diagonal. constants: Constants that appear in the form. If not provided, any required constants will be computed. coeffs: Coefficients that appear in the form. If not provided, any required coefficients will be computed. + Returns: + Matrix representation of the bilinear form ``a``. + Note: The returned matrix is not finalised, i.e. ghost values are not accumulated. """ bcs = [] if bcs is None else bcs - constants = _pack_constants(a) if constants is None else constants - coeffs = _pack_coefficients(a) if coeffs is None else coeffs - _cpp.fem.assemble_matrix(A, a, constants, coeffs, bcs) - - # If matrix is a 'diagonal'block, set diagonal entry for constrained - # dofs - if a.function_spaces[0] is a.function_spaces[1]: - _cpp.fem.insert_diagonal(A, a.function_spaces[0], bcs, diagonal) + A: la.MatrixCSRMetaClass = create_matrix(a) + _assemble_matrix_csr(A, a, bcs, diagonal, constants, coeffs) return A From 6a200005bbfc3c222aea2e890d4d9aeaed857cd5 Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Sat, 21 May 2022 16:49:38 +0200 Subject: [PATCH 16/59] 9 left in demos, 22 in main library (mainly in petsc.py) --- python/demo/demo_cahn-hilliard.py | 2 +- python/demo/demo_lagrange_variants.py | 1 + python/demo/demo_static-condensation.py | 2 +- python/demo/demo_stokes.py | 2 +- python/demo/demo_tnt-elements.py | 4 ++-- python/dolfinx/fem/bcs.py | 6 +++--- python/dolfinx/mesh.py | 2 +- python/setup.py | 2 +- 8 files changed, 11 insertions(+), 10 deletions(-) diff --git a/python/demo/demo_cahn-hilliard.py b/python/demo/demo_cahn-hilliard.py index 338f557b59f..db0ecb5fe0f 100644 --- a/python/demo/demo_cahn-hilliard.py +++ b/python/demo/demo_cahn-hilliard.py @@ -301,7 +301,7 @@ # Prepare viewer for plotting the solution during the computation if have_pyvista: # Create a VTK 'mesh' with 'nodes' at the function dofs - topology, cell_types, x = plot.create_vtk_mesh(V0) + topology, cell_types, x = plot.create_vtk_mesh(V0, msh.topology.dim) grid = pv.UnstructuredGrid(topology, cell_types, x) # Set output data diff --git a/python/demo/demo_lagrange_variants.py b/python/demo/demo_lagrange_variants.py index b5decee1f6c..8b9c954c699 100644 --- a/python/demo/demo_lagrange_variants.py +++ b/python/demo/demo_lagrange_variants.py @@ -177,6 +177,7 @@ def saw_tooth(x): pts.append([cell / 10 + i / 50 / 10, 0, 0]) cells.append(cell) pts = np.array(pts) + cells = np.array(cells) values = uh.eval(pts, cells) plt.plot(pts[:, 0], [saw_tooth(i[0]) for i in pts], "k--") plt.plot(pts[:, 0], values, "r-") diff --git a/python/demo/demo_static-condensation.py b/python/demo/demo_static-condensation.py index 73ac74763b7..c574f1b9d0e 100644 --- a/python/demo/demo_static-condensation.py +++ b/python/demo/demo_static-condensation.py @@ -63,7 +63,7 @@ # Locate all facets at the free end and assign them value 1. Sort the # facet indices (requirement for constructing MeshTags) free_end_facets = np.sort(locate_entities_boundary(msh, 1, lambda x: np.isclose(x[0], 48.0))) -mt = meshtags(msh, 1, free_end_facets, 1) +mt = meshtags(msh, 1, free_end_facets, np.array([1])) ds = ufl.Measure("ds", subdomain_data=mt) diff --git a/python/demo/demo_stokes.py b/python/demo/demo_stokes.py index e6bcb8d5839..d7816c15586 100644 --- a/python/demo/demo_stokes.py +++ b/python/demo/demo_stokes.py @@ -136,7 +136,7 @@ def lid_velocity_expression(x): # + # No-slip boundary condition for velocity field (`V`) on boundaries # where x = 0, x = 1, and y = 0 -noslip = np.zeros(msh.geometry.dim, dtype=PETSc.ScalarType) +noslip = Function(V) facets = locate_entities_boundary(msh, 1, noslip_boundary) bc0 = dirichletbc(noslip, locate_dofs_topological(V, 1, facets), V) diff --git a/python/demo/demo_tnt-elements.py b/python/demo/demo_tnt-elements.py index c5dc6865797..11f0cd5223c 100644 --- a/python/demo/demo_tnt-elements.py +++ b/python/demo/demo_tnt-elements.py @@ -69,8 +69,8 @@ # + geometry = basix.geometry(basix.CellType.quadrilateral) topology = basix.topology(basix.CellType.quadrilateral) -x : typing.List[typing.List[np.ndarray]] = [[], [], [], []] -M : typing.List[typing.List[np.ndarray]] = [[], [], [], []] +x: typing.List[typing.List[np.ndarray]] = [[], [], [], []] +M: typing.List[typing.List[np.ndarray]] = [[], [], [], []] for v in topology[0]: x[0].append(np.array(geometry[v])) diff --git a/python/dolfinx/fem/bcs.py b/python/dolfinx/fem/bcs.py index a68d7abf56d..ab5366b7e94 100644 --- a/python/dolfinx/fem/bcs.py +++ b/python/dolfinx/fem/bcs.py @@ -26,7 +26,7 @@ def locate_dofs_geometrical(V: typing.Union[dolfinx.fem.FunctionSpace, typing.Iterable[dolfinx.fem.FunctionSpace]], - marker: types.FunctionType) -> np.ndarray: + marker: typing.Callable) -> np.ndarray: """Locate degrees-of-freedom geometrically using a marker function. Args: @@ -171,8 +171,8 @@ def dirichletbc(value: typing.Union[Function, Constant], return formcls(value, dofs, V) -def bcs_by_block(spaces: typing.Iterable[dolfinx.fem.FunctionSpace], - bcs: typing.Iterable[DirichletBCMetaClass]) -> typing.Iterable[typing.Iterable[DirichletBCMetaClass]]: +def bcs_by_block(spaces: typing.Iterable[typing.Union[dolfinx.fem.FunctionSpace, None]], + bcs: typing.Iterable[DirichletBCMetaClass]) -> typing.List[typing.List[DirichletBCMetaClass]]: """Arrange Dirichlet boundary conditions by the function space that they constrain. diff --git a/python/dolfinx/mesh.py b/python/dolfinx/mesh.py index 3edc05d6520..2aa8fcd667e 100644 --- a/python/dolfinx/mesh.py +++ b/python/dolfinx/mesh.py @@ -68,7 +68,7 @@ def ufl_domain(self) -> ufl.Mesh: return self._ufl_domain -def locate_entities(mesh: Mesh, dim: int, marker: types.FunctionType) -> np.ndarray: +def locate_entities(mesh: Mesh, dim: int, marker: typing.Callable) -> np.ndarray: """Compute mesh entities satisfying a geometric marking function Args: diff --git a/python/setup.py b/python/setup.py index 2c8fc71c938..074e24a4a18 100644 --- a/python/setup.py +++ b/python/setup.py @@ -15,7 +15,7 @@ VERSION = "0.4.2.dev0" REQUIREMENTS = [ - "numpy", + "numpy>=1.20", "mpi4py", "petsc4py", "fenics-ffcx>=0.4.3.dev0,<0.5.0", From 5a02e4bd194f374a4f652ce9d9bb27d8066cd744 Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Sat, 21 May 2022 16:51:43 +0200 Subject: [PATCH 17/59] flake8 fixes --- python/dolfinx/fem/bcs.py | 4 +--- python/dolfinx/mesh.py | 6 +++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/python/dolfinx/fem/bcs.py b/python/dolfinx/fem/bcs.py index ab5366b7e94..9464eb1e936 100644 --- a/python/dolfinx/fem/bcs.py +++ b/python/dolfinx/fem/bcs.py @@ -8,15 +8,13 @@ from __future__ import annotations +import collections.abc import typing import numpy.typing if typing.TYPE_CHECKING: from dolfinx.fem.function import Constant, Function -import collections.abc -import types -import typing import numpy as np diff --git a/python/dolfinx/mesh.py b/python/dolfinx/mesh.py index 2aa8fcd667e..8c9bc7cec3d 100644 --- a/python/dolfinx/mesh.py +++ b/python/dolfinx/mesh.py @@ -7,7 +7,6 @@ from __future__ import annotations -import types import typing import numpy as np @@ -344,8 +343,9 @@ 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, cell_type=CellType.triangle, - ghost_mode=GhostMode.shared_facet, partitioner=_cpp.mesh.create_cell_partitioner(), +def create_rectangle(comm: _MPI.Comm, points: numpy.typing.ArrayLike, n: numpy.typing.ArrayLike, + cell_type=CellType.triangle, ghost_mode=GhostMode.shared_facet, + partitioner=_cpp.mesh.create_cell_partitioner(), diagonal: DiagonalType = DiagonalType.right) -> Mesh: """Create rectangle mesh From 2b1e356d770be75388477ed15a67e5ca30c47482 Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Sun, 22 May 2022 10:48:48 +0200 Subject: [PATCH 18/59] Demos pass, petsc.py and two strange ones to go --- python/demo/demo_elasticity.py | 4 ++-- python/demo/demo_gmsh.py | 6 +++--- python/demo/demo_interpolation-io.py | 2 +- python/demo/demo_lagrange_variants.py | 8 ++++---- python/demo/demo_static-condensation.py | 2 +- python/dolfinx/fem/function.py | 2 +- python/dolfinx/mesh.py | 4 ++-- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/python/demo/demo_elasticity.py b/python/demo/demo_elasticity.py index 67319a85d26..f102e1cb919 100644 --- a/python/demo/demo_elasticity.py +++ b/python/demo/demo_elasticity.py @@ -129,8 +129,8 @@ def σ(v): facets = locate_entities_boundary(msh, dim=2, marker=lambda x: np.logical_or(np.isclose(x[0], 0.0), np.isclose(x[1], 1.0))) -bc = dirichletbc(np.zeros(3, dtype=dtype), - locate_dofs_topological(V, entity_dim=2, entities=facets), V=V) +u_zero = Function(V) +bc = dirichletbc(u_zero, locate_dofs_topological(V, entity_dim=2, entities=facets), V=V) # ## Assemble and solve # diff --git a/python/demo/demo_gmsh.py b/python/demo/demo_gmsh.py index 920f0ab5a26..689f7ff89a4 100644 --- a/python/demo/demo_gmsh.py +++ b/python/demo/demo_gmsh.py @@ -120,7 +120,7 @@ entities, values = distribute_entity_data(msh, 2, marked_facets, facet_values) msh.topology.create_connectivity(2, 0) -mt = meshtags_from_entities(msh, 2, create_adjacencylist(entities), np.int32(values)) +mt = meshtags_from_entities(msh, 2, create_adjacencylist(entities), np.array(values, dtype=np.int32)) mt.name = "ball_d1_surface" with XDMFFile(MPI.COMM_WORLD, "out_gmsh/mesh.xdmf", "w") as file: @@ -180,7 +180,7 @@ entities, values = distribute_entity_data(msh, 2, marked_facets, facet_values) msh.topology.create_connectivity(2, 0) -mt = meshtags_from_entities(msh, 2, create_adjacencylist(entities), np.int32(values)) +mt = meshtags_from_entities(msh, 2, create_adjacencylist(entities), np.array(values, dtype=np.int32)) mt.name = "ball_d2_surface" with XDMFFile(MPI.COMM_WORLD, "out_gmsh/mesh.xdmf", "a") as file: file.write_mesh(msh) @@ -257,7 +257,7 @@ entities, values = distribute_entity_data(msh, 2, marked_facets, facet_values) msh.topology.create_connectivity(2, 0) -mt = meshtags_from_entities(msh, 2, create_adjacencylist(entities), np.int32(values)) +mt = meshtags_from_entities(msh, 2, create_adjacencylist(entities), np.array(values, dtype=np.int32)) mt.name = "hex_d2_surface" with XDMFFile(MPI.COMM_WORLD, "out_gmsh/mesh.xdmf", "a") as file: diff --git a/python/demo/demo_interpolation-io.py b/python/demo/demo_interpolation-io.py index 6ff41805ffe..882861c8b8f 100644 --- a/python/demo/demo_interpolation-io.py +++ b/python/demo/demo_interpolation-io.py @@ -70,7 +70,7 @@ # Plot solution try: import pyvista - cells, types, x = plot.create_vtk_mesh(V0) + cells, types, x = plot.create_vtk_mesh(V0, dim=msh.topology.dim) grid = pyvista.UnstructuredGrid(cells, types, x) values = np.zeros((x.shape[0], 3), dtype=np.float64) values[:, :msh.topology.dim] = u0.x.array.reshape(x.shape[0], msh.topology.dim).real diff --git a/python/demo/demo_lagrange_variants.py b/python/demo/demo_lagrange_variants.py index 8b9c954c699..c069dea3ba2 100644 --- a/python/demo/demo_lagrange_variants.py +++ b/python/demo/demo_lagrange_variants.py @@ -176,10 +176,10 @@ def saw_tooth(x): for i in range(51): pts.append([cell / 10 + i / 50 / 10, 0, 0]) cells.append(cell) - pts = np.array(pts) - cells = np.array(cells) - values = uh.eval(pts, cells) - plt.plot(pts[:, 0], [saw_tooth(i[0]) for i in pts], "k--") + pts_np = np.array(pts) + cells_np = np.array(cells) + values = uh.eval(pts_np, cells_np) + plt.plot(pts_np[:, 0], [saw_tooth(i[0]) for i in pts], "k--") plt.plot(pts[:, 0], values, "r-") plt.legend(["function", "approximation"]) diff --git a/python/demo/demo_static-condensation.py b/python/demo/demo_static-condensation.py index c574f1b9d0e..286727fcf7b 100644 --- a/python/demo/demo_static-condensation.py +++ b/python/demo/demo_static-condensation.py @@ -63,7 +63,7 @@ # Locate all facets at the free end and assign them value 1. Sort the # facet indices (requirement for constructing MeshTags) free_end_facets = np.sort(locate_entities_boundary(msh, 1, lambda x: np.isclose(x[0], 48.0))) -mt = meshtags(msh, 1, free_end_facets, np.array([1])) +mt = meshtags(msh, 1, free_end_facets, np.ones_like(free_end_facets)) ds = ufl.Measure("ds", subdomain_data=mt) diff --git a/python/dolfinx/fem/function.py b/python/dolfinx/fem/function.py index bc9d996bf17..a06a1b780fb 100644 --- a/python/dolfinx/fem/function.py +++ b/python/dolfinx/fem/function.py @@ -552,7 +552,7 @@ def tabulate_dof_coordinates(self) -> np.ndarray: return self._cpp_object.tabulate_dof_coordinates() -def VectorFunctionSpace(mesh: Mesh, element: ElementMetaData, dim=None, +def VectorFunctionSpace(mesh: Mesh, element: typing.Union[ElementMetaData, typing.Tuple[str, int]], dim=None, restriction=None) -> FunctionSpace: """Create vector finite element (composition of scalar elements) function space.""" diff --git a/python/dolfinx/mesh.py b/python/dolfinx/mesh.py index 8c9bc7cec3d..0ed84532eec 100644 --- a/python/dolfinx/mesh.py +++ b/python/dolfinx/mesh.py @@ -301,7 +301,7 @@ def meshtags_from_entities(mesh: Mesh, dim: int, entities: _cpp.graph.AdjacencyL return _cpp.mesh.create_meshtags(mesh, dim, entities, values) -def create_interval(comm: _MPI.Comm, nx: int, points: list, ghost_mode=GhostMode.shared_facet, +def create_interval(comm: _MPI.Comm, nx: int, points: numpy.typing.ArrayLike, ghost_mode=GhostMode.shared_facet, partitioner=_cpp.mesh.create_cell_partitioner()) -> Mesh: """Create an interval mesh @@ -396,7 +396,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[np.ndarray], n: list, +def create_box(comm: _MPI.Comm, points: typing.List[numpy.typing.ArrayLike], n: list, cell_type=CellType.tetrahedron, ghost_mode=GhostMode.shared_facet, partitioner=_cpp.mesh.create_cell_partitioner()) -> Mesh: From ff21edfcf69cd6cf174177e04413c19e6d09bfab Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Sun, 22 May 2022 15:49:05 +0200 Subject: [PATCH 19/59] Liberal mypy passes, all tests pass --- python/demo/demo_elasticity.py | 2 +- python/demo/demo_lagrange_variants.py | 2 +- python/demo/demo_poisson.py | 2 +- python/demo/demo_stokes.py | 2 +- python/dolfinx/fem/bcs.py | 2 +- python/dolfinx/fem/forms.py | 4 +- python/dolfinx/fem/function.py | 3 +- python/dolfinx/fem/petsc.py | 149 +++++++++++++++++--------- python/setup.cfg | 12 +++ 9 files changed, 121 insertions(+), 57 deletions(-) diff --git a/python/demo/demo_elasticity.py b/python/demo/demo_elasticity.py index f102e1cb919..8242428ead0 100644 --- a/python/demo/demo_elasticity.py +++ b/python/demo/demo_elasticity.py @@ -130,7 +130,7 @@ def σ(v): marker=lambda x: np.logical_or(np.isclose(x[0], 0.0), np.isclose(x[1], 1.0))) u_zero = Function(V) -bc = dirichletbc(u_zero, locate_dofs_topological(V, entity_dim=2, entities=facets), V=V) +bc = dirichletbc(u_zero, locate_dofs_topological(V, entity_dim=2, entities=facets)) # ## Assemble and solve # diff --git a/python/demo/demo_lagrange_variants.py b/python/demo/demo_lagrange_variants.py index c069dea3ba2..d9896a08cf9 100644 --- a/python/demo/demo_lagrange_variants.py +++ b/python/demo/demo_lagrange_variants.py @@ -180,7 +180,7 @@ def saw_tooth(x): cells_np = np.array(cells) values = uh.eval(pts_np, cells_np) plt.plot(pts_np[:, 0], [saw_tooth(i[0]) for i in pts], "k--") - plt.plot(pts[:, 0], values, "r-") + plt.plot(pts_np[:, 0], values, "r-") plt.legend(["function", "approximation"]) plt.ylim([-0.1, 0.4]) diff --git a/python/demo/demo_poisson.py b/python/demo/demo_poisson.py index 7b547c6b8d0..2004afbce82 100644 --- a/python/demo/demo_poisson.py +++ b/python/demo/demo_poisson.py @@ -124,7 +124,7 @@ u = ufl.TrialFunction(V) v = ufl.TestFunction(V) x = ufl.SpatialCoordinate(msh) -f = 10 * ufl.exp(-((x[0] - 0.5) ** 2 + (x[1] - 0.5) ** 2) / 0.02) +f = 10.0 * ufl.exp(-((x[0] - 0.5) ** 2 + (x[1] - 0.5) ** 2) / 0.02) g = ufl.sin(5 * x[0]) a = inner(grad(u), grad(v)) * dx L = inner(f, v) * dx + inner(g, v) * ds diff --git a/python/demo/demo_stokes.py b/python/demo/demo_stokes.py index d7816c15586..88c2f040907 100644 --- a/python/demo/demo_stokes.py +++ b/python/demo/demo_stokes.py @@ -138,7 +138,7 @@ def lid_velocity_expression(x): # where x = 0, x = 1, and y = 0 noslip = Function(V) facets = locate_entities_boundary(msh, 1, noslip_boundary) -bc0 = dirichletbc(noslip, locate_dofs_topological(V, 1, facets), V) +bc0 = dirichletbc(noslip, locate_dofs_topological(V, 1, facets)) # Driving velocity condition u = (1, 0) on top boundary (y = 1) lid_velocity = Function(V) diff --git a/python/dolfinx/fem/bcs.py b/python/dolfinx/fem/bcs.py index 9464eb1e936..8e2fdb24c3b 100644 --- a/python/dolfinx/fem/bcs.py +++ b/python/dolfinx/fem/bcs.py @@ -90,7 +90,7 @@ def locate_dofs_topological(V: typing.Union[dolfinx.fem.FunctionSpace, typing.It class DirichletBCMetaClass: - def __init__(self, value: typing.Union[ufl.Coefficient, Function, Constant], + def __init__(self, value: typing.Union[ufl.Coefficient, Function, Constant, numpy.ndarray], dofs: numpy.typing.ArrayLike, V: dolfinx.fem.FunctionSpace = None): """Representation of Dirichlet boundary condition which is imposed on a linear system. diff --git a/python/dolfinx/fem/forms.py b/python/dolfinx/fem/forms.py index 82215a2ba3c..1adecdf4357 100644 --- a/python/dolfinx/fem/forms.py +++ b/python/dolfinx/fem/forms.py @@ -182,7 +182,7 @@ def extract_function_spaces(forms: typing.Union[typing.Iterable[FormMetaClass], for form in _forms: if form is not None: assert form.rank == 1, "Expected linear form" - return [form.function_spaces[0] if form is not None else None for form in forms] + return [form.function_spaces[0] if form is not None else None for form in forms] # type: ignore[union-attr] elif _forms.ndim == 2: assert index == 0 or index == 1 extract_spaces = np.vectorize(lambda form: form.function_spaces[index] if form is not None else None) @@ -210,3 +210,5 @@ def unique_spaces(V): return list(unique_spaces(V.transpose())) else: raise RuntimeError("Unsupported array of forms") + + return [] # For static type checkers, will never reach. diff --git a/python/dolfinx/fem/function.py b/python/dolfinx/fem/function.py index a06a1b780fb..ac72c6e4841 100644 --- a/python/dolfinx/fem/function.py +++ b/python/dolfinx/fem/function.py @@ -417,7 +417,8 @@ 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], element: typing.Union[ufl.FiniteElementBase, ElementMetaData], + def __init__(self, mesh: typing.Union[None, Mesh], + element: typing.Union[ufl.FiniteElementBase, ElementMetaData, typing.Tuple], cppV: typing.Optional[_cpp.fem.FunctionSpace] = None, form_compiler_params: dict = {}, jit_params: dict = {}): """Create a finite element function space.""" diff --git a/python/dolfinx/fem/petsc.py b/python/dolfinx/fem/petsc.py index c5ff9d9cfdf..bf03280529d 100644 --- a/python/dolfinx/fem/petsc.py +++ b/python/dolfinx/fem/petsc.py @@ -14,10 +14,6 @@ import typing -if typing.TYPE_CHECKING: - from dolfinx.fem.forms import FormMetaClass - from dolfinx.fem.bcs import DirichletBCMetaClass - import contextlib import functools @@ -28,8 +24,10 @@ from dolfinx.cpp.fem import pack_constants as _pack_constants from dolfinx.fem import assemble from dolfinx.fem.bcs import bcs_by_block as _bcs_by_block +from dolfinx.fem.bcs import DirichletBCMetaClass from dolfinx.fem.forms import extract_function_spaces as _extract_spaces from dolfinx.fem.forms import form as _create_form +from dolfinx.fem.forms import FormMetaClass from dolfinx.fem.function import Function as _Function from petsc4py import PETSc @@ -161,7 +159,12 @@ def create_matrix_nest(a: typing.List[typing.List[FormMetaClass]]) -> PETSc.Mat: # -- Vector assembly --------------------------------------------------------- @functools.singledispatch -def assemble_vector(L: FormMetaClass, constants=None, coeffs=None) -> PETSc.Vec: +def assemble_vector(L: typing.Any, constants=None, coeffs=None) -> PETSc.Vec: + raise NotImplementedError + + +@assemble_vector.register(FormMetaClass) +def _assemble_vector_form(L: FormMetaClass, constants=None, coeffs=None) -> PETSc.Vec: """Assemble linear form into a new PETSc vector. Note: @@ -178,12 +181,12 @@ def assemble_vector(L: FormMetaClass, constants=None, coeffs=None) -> PETSc.Vec: b = la.create_petsc_vector(L.function_spaces[0].dofmap.index_map, L.function_spaces[0].dofmap.index_map_bs) with b.localForm() as b_local: - assemble.assemble_vector(b_local.array_w, L, constants, coeffs) + assemble._assemble_vector_array(b_local.array_w, L, constants, coeffs) return b @assemble_vector.register(PETSc.Vec) -def _(b: PETSc.Vec, L: FormMetaClass, constants=None, coeffs=None) -> PETSc.Vec: +def _assemble_vector_vec(b: PETSc.Vec, L: FormMetaClass, constants=None, coeffs=None) -> PETSc.Vec: """Assemble linear form into an existing PETSc vector. Note: @@ -200,12 +203,17 @@ def _(b: PETSc.Vec, L: FormMetaClass, constants=None, coeffs=None) -> PETSc.Vec: """ with b.localForm() as b_local: - assemble.assemble_vector(b_local.array_w, L, constants, coeffs) + assemble._assemble_vector_array(b_local.array_w, L, constants, coeffs) return b @functools.singledispatch -def assemble_vector_nest(L: typing.List[FormMetaClass], constants=None, coeffs=None) -> PETSc.Vec: +def assemble_vector_nest(L: typing.Any, constants=None, coeffs=None) -> PETSc.Vec: + raise NotImplementedError + + +@assemble_vector_nest.register(list) +def _assemble_vector_nest_forms(L: typing.List[FormMetaClass], constants=None, coeffs=None) -> PETSc.Vec: """Assemble linear forms into a new nested PETSc (VecNest) vector. The returned vector is not finalised, i.e. ghost values are not accumulated on the owning processes. @@ -217,11 +225,11 @@ def assemble_vector_nest(L: typing.List[FormMetaClass], constants=None, coeffs=N for b_sub in b.getNestSubVecs(): with b_sub.localForm() as b_local: b_local.set(0.0) - return assemble_vector_nest(b, L, constants, coeffs) + return _assemble_vector_nest_vec(b, L, constants, coeffs) -@assemble_vector_nest.register(PETSc.Vec) -def _(b: PETSc.Vec, L: typing.List[FormMetaClass], constants=None, coeffs=None) -> PETSc.Vec: +@assemble_vector_nest.register +def _assemble_vector_nest_vec(b: PETSc.Vec, L: typing.List[FormMetaClass], constants=None, coeffs=None) -> PETSc.Vec: """Assemble linear forms into a nested PETSc (VecNest) vector. The vector is not zeroed before assembly and it is not finalised, i.e. ghost values are not accumulated on the owning processes. @@ -231,19 +239,30 @@ def _(b: PETSc.Vec, L: typing.List[FormMetaClass], constants=None, coeffs=None) coeffs = [None] * len(L) if coeffs is None else coeffs for b_sub, L_sub, const, coeff in zip(b.getNestSubVecs(), L, constants, coeffs): with b_sub.localForm() as b_local: - assemble.assemble_vector(b_local.array_w, L_sub, const, coeff) + assemble._assemble_vector_array(b_local.array_w, L_sub, const, coeff) return b # FIXME: Revise this interface @functools.singledispatch -def assemble_vector_block(L: typing.List[FormMetaClass], +def assemble_vector_block(L: typing.Any, a: typing.List[typing.List[FormMetaClass]], bcs: typing.List[DirichletBCMetaClass] = [], x0: typing.Optional[PETSc.Vec] = None, scale: float = 1.0, constants_L=None, coeffs_L=None, constants_a=None, coeffs_a=None) -> PETSc.Vec: + raise NotImplementedError + + +@assemble_vector_block.register(list) +def _assemble_vector_block_forms(L: typing.List[FormMetaClass], + a: typing.List[typing.List[FormMetaClass]], + bcs: typing.List[DirichletBCMetaClass] = [], + x0: typing.Optional[PETSc.Vec] = None, + scale: float = 1.0, + constants_L=None, coeffs_L=None, + constants_a=None, coeffs_a=None) -> PETSc.Vec: """Assemble linear forms into a monolithic vector. The vector is not finalised, i.e. ghost values are not accumulated. @@ -253,19 +272,19 @@ def assemble_vector_block(L: typing.List[FormMetaClass], b = _cpp.fem.petsc.create_vector_block(maps) with b.localForm() as b_local: b_local.set(0.0) - return assemble_vector_block(b, L, a, bcs, x0, scale, constants_L, coeffs_L, - constants_a, coeffs_a) - - -@assemble_vector_block.register(PETSc.Vec) -def _(b: PETSc.Vec, - L: typing.List[FormMetaClass], - a, - bcs: typing.List[DirichletBCMetaClass] = [], - x0: typing.Optional[PETSc.Vec] = None, - scale: float = 1.0, - constants_L=None, coeffs_L=None, - constants_a=None, coeffs_a=None) -> PETSc.Vec: + return _assemble_vector_block_vec(b, L, a, bcs, x0, scale, constants_L, coeffs_L, + constants_a, coeffs_a) + + +@assemble_vector_block.register +def _assemble_vector_block_vec(b: PETSc.Vec, + L: typing.List[FormMetaClass], + a: typing.List[typing.List[FormMetaClass]], + bcs: typing.List[DirichletBCMetaClass] = [], + x0: typing.Optional[PETSc.Vec] = None, + scale: float = 1.0, + constants_L=None, coeffs_L=None, + constants_a=None, coeffs_a=None) -> PETSc.Vec: """Assemble linear forms into a monolithic vector. The vector is not zeroed and it is not finalised, i.e. ghost values are not accumulated. @@ -311,24 +330,32 @@ def _(b: PETSc.Vec, # -- Matrix assembly --------------------------------------------------------- - - @functools.singledispatch -def assemble_matrix(a: FormMetaClass, bcs: typing.List[DirichletBCMetaClass] = [], +def assemble_matrix(a: typing.Any, bcs: typing.List[DirichletBCMetaClass] = [], diagonal: float = 1.0, constants=None, coeffs=None) -> PETSc.Mat: + try: + return _assemble_matrix_form(a, bcs, diagonal, constants, coeffs) + except TypeError: + raise NotImplementedError + + +@assemble_matrix.register +def _assemble_matrix_form(a: FormMetaClass, bcs: typing.List[DirichletBCMetaClass] = [], + diagonal: float = 1.0, + constants=None, coeffs=None) -> PETSc.Mat: """Assemble bilinear form into a matrix. The returned matrix is not finalised, i.e. ghost values are not accumulated. """ A = _cpp.fem.petsc.create_matrix(a) - assemble_matrix(A, a, bcs, diagonal, constants, coeffs) + _assemble_matrix_mat(A, a, bcs, diagonal, constants, coeffs) return A -@assemble_matrix.register(PETSc.Mat) -def _(A: PETSc.Mat, a: FormMetaClass, bcs: typing.List[DirichletBCMetaClass] = [], - diagonal: float = 1.0, constants=None, coeffs=None) -> PETSc.Mat: +@assemble_matrix.register +def _assemble_matrix_mat(A: PETSc.Mat, a: FormMetaClass, bcs: typing.List[DirichletBCMetaClass] = [], + diagonal: float = 1.0, constants=None, coeffs=None) -> PETSc.Mat: """Assemble bilinear form into a matrix. The returned matrix is not finalised, i.e. ghost values are not accumulated. @@ -345,20 +372,31 @@ def _(A: PETSc.Mat, a: FormMetaClass, bcs: typing.List[DirichletBCMetaClass] = [ # FIXME: Revise this interface @functools.singledispatch -def assemble_matrix_nest(a: typing.List[typing.List[FormMetaClass]], +def assemble_matrix_nest(a: typing.Any, bcs: typing.List[DirichletBCMetaClass] = [], mat_types=[], diagonal: float = 1.0, constants=None, coeffs=None) -> PETSc.Mat: + try: + return _assemble_matrix_nest_form(a, bcs, diagonal, constants, coeffs) + except TypeError: + raise NotImplementedError + + +@assemble_matrix_nest.register(list) +def _assemble_matrix_nest_form(a: typing.List[typing.List[FormMetaClass]], + bcs: typing.List[DirichletBCMetaClass] = [], mat_types=[], + diagonal: float = 1.0, + constants=None, coeffs=None) -> PETSc.Mat: """Assemble bilinear forms into matrix""" A = _cpp.fem.petsc.create_matrix_nest(a, mat_types) - assemble_matrix_nest(A, a, bcs, diagonal, constants, coeffs) + _assemble_matrix_nest_mat(A, a, bcs, diagonal, constants, coeffs) return A -@assemble_matrix_nest.register(PETSc.Mat) -def _(A: PETSc.Mat, a: typing.List[typing.List[FormMetaClass]], - bcs: typing.List[DirichletBCMetaClass] = [], diagonal: float = 1.0, - constants=None, coeffs=None) -> PETSc.Mat: +@assemble_matrix_nest.register +def _assemble_matrix_nest_mat(A: PETSc.Mat, a: typing.List[typing.List[FormMetaClass]], + bcs: typing.List[DirichletBCMetaClass] = [], diagonal: float = 1.0, + constants=None, coeffs=None) -> PETSc.Mat: """Assemble bilinear forms into matrix""" constants = [[form and _pack_constants(form) for form in forms] for forms in a] if constants is None else constants @@ -368,7 +406,7 @@ def _(A: PETSc.Mat, a: typing.List[typing.List[FormMetaClass]], for j, (a_block, const, coeff) in enumerate(zip(a_row, const_row, coeff_row)): if a_block is not None: Asub = A.getNestSubMatrix(i, j) - assemble_matrix(Asub, a_block, bcs, diagonal, const, coeff) + _assemble_matrix_mat(Asub, a_block, bcs, diagonal, const, coeff) elif i == j: for bc in bcs: row_forms = [row_form for row_form in a_row if row_form is not None] @@ -382,19 +420,30 @@ def _(A: PETSc.Mat, a: typing.List[typing.List[FormMetaClass]], # FIXME: Revise this interface @functools.singledispatch -def assemble_matrix_block(a: typing.List[typing.List[FormMetaClass]], +def assemble_matrix_block(a: typing.Any, bcs: typing.List[DirichletBCMetaClass] = [], diagonal: float = 1.0, constants=None, coeffs=None) -> PETSc.Mat: + try: + return _assemble_matrix_block_form(a, bcs, diagonal, constants, coeffs) + except TypeError: + raise NotImplementedError + + +@assemble_matrix_block.register(list) +def _assemble_matrix_block_form(a: typing.List[typing.List[FormMetaClass]], + bcs: typing.List[DirichletBCMetaClass] = [], + diagonal: float = 1.0, + constants=None, coeffs=None) -> PETSc.Mat: """Assemble bilinear forms into matrix""" A = _cpp.fem.petsc.create_matrix_block(a) - return assemble_matrix_block(A, a, bcs, diagonal, constants, coeffs) + return _assemble_matrix_block_mat(A, a, bcs, diagonal, constants, coeffs) -@assemble_matrix_block.register(PETSc.Mat) -def _(A: PETSc.Mat, a: typing.List[typing.List[FormMetaClass]], - bcs: typing.List[DirichletBCMetaClass] = [], diagonal: float = 1.0, - constants=None, coeffs=None) -> PETSc.Mat: +@assemble_matrix_block.register +def _assemble_matrix_block_mat(A: PETSc.Mat, a: typing.List[typing.List[FormMetaClass]], + bcs: typing.List[DirichletBCMetaClass] = [], diagonal: float = 1.0, + constants=None, coeffs=None) -> PETSc.Mat: """Assemble bilinear forms into matrix""" constants = [[form and _pack_constants(form) for form in forms] @@ -486,7 +535,7 @@ def set_bc_nest(b: PETSc.Vec, bcs: typing.List[typing.List[DirichletBCMetaClass] set_bc(b_sub, bc, x_sub, scale) -class LinearProblem(): +class LinearProblem: """Class for solving a linear variational problem of the form :math:`a(u, v) = L(v) \\, \\forall v \\in V` using PETSc as a linear algebra backend. @@ -561,7 +610,7 @@ def solve(self) -> _Function: # Assemble lhs self._A.zeroEntries() - assemble_matrix(self._A, self._a, bcs=self.bcs) + _assemble_matrix_mat(self._A, self._a, bcs=self.bcs) self._A.assemble() # Assemble rhs @@ -694,5 +743,5 @@ def J(self, x: PETSc.Vec, A: PETSc.Mat): """ A.zeroEntries() - assemble_matrix(A, self._a, self.bcs) + _assemble_matrix_mat(A, self._a, self.bcs) A.assemble() diff --git a/python/setup.cfg b/python/setup.cfg index 22933b97c2d..e56dad8e715 100644 --- a/python/setup.cfg +++ b/python/setup.cfg @@ -4,3 +4,15 @@ ignore = W503 [tool:pytest] junit_family = xunit2 + +[mypy] +# Suggested at https://blog.wolt.com/engineering/2021/09/30/professional-grade-mypy-configuration/ +# Goal would be to make all of the below True long-term +disallow_untyped_defs = False +disallow_any_unimported = False +no_implicit_optional = False +check_untyped_defs = False +warn_return_any = False +warn_unused_ignores = False +show_error_codes = True +ignore_missing_imports = True From 5f49d1a94029b3bc867f858772a664c06ba2d93d Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Sun, 22 May 2022 16:08:21 +0200 Subject: [PATCH 20/59] Fix fallback vector --- python/dolfinx/fem/petsc.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python/dolfinx/fem/petsc.py b/python/dolfinx/fem/petsc.py index bf03280529d..8bd2326349f 100644 --- a/python/dolfinx/fem/petsc.py +++ b/python/dolfinx/fem/petsc.py @@ -160,7 +160,10 @@ def create_matrix_nest(a: typing.List[typing.List[FormMetaClass]]) -> PETSc.Mat: @functools.singledispatch def assemble_vector(L: typing.Any, constants=None, coeffs=None) -> PETSc.Vec: - raise NotImplementedError + try: + _assemble_vector_form(L, constants, coeffs) + except TypeError: + raise NotImplementedError @assemble_vector.register(FormMetaClass) From 04dd71eacf02bb838796891c3713c0ac96ceb5c7 Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Sun, 22 May 2022 16:17:35 +0200 Subject: [PATCH 21/59] Fixes --- python/dolfinx/fem/bcs.py | 9 +++++---- python/dolfinx/fem/petsc.py | 26 ++++++++++++++++---------- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/python/dolfinx/fem/bcs.py b/python/dolfinx/fem/bcs.py index 8e2fdb24c3b..97417e2f8b7 100644 --- a/python/dolfinx/fem/bcs.py +++ b/python/dolfinx/fem/bcs.py @@ -114,10 +114,11 @@ class initialiser. This class is combined with different """ # Unwrap value object, if required - try: - _value = value._cpp_object - except AttributeError: - _value = value + if not isinstance(value, np.ndarray): + try: + _value = value._cpp_object + except AttributeError: + _value = value if V is not None: try: diff --git a/python/dolfinx/fem/petsc.py b/python/dolfinx/fem/petsc.py index 8bd2326349f..1a34900fb14 100644 --- a/python/dolfinx/fem/petsc.py +++ b/python/dolfinx/fem/petsc.py @@ -161,7 +161,7 @@ def create_matrix_nest(a: typing.List[typing.List[FormMetaClass]]) -> PETSc.Mat: @functools.singledispatch def assemble_vector(L: typing.Any, constants=None, coeffs=None) -> PETSc.Vec: try: - _assemble_vector_form(L, constants, coeffs) + return _assemble_vector_form(L, constants, coeffs) except TypeError: raise NotImplementedError @@ -212,7 +212,10 @@ def _assemble_vector_vec(b: PETSc.Vec, L: FormMetaClass, constants=None, coeffs= @functools.singledispatch def assemble_vector_nest(L: typing.Any, constants=None, coeffs=None) -> PETSc.Vec: - raise NotImplementedError + try: + return _assemble_vector_form(L, constants, coeffs) + except TypeError: + raise NotImplementedError @assemble_vector_nest.register(list) @@ -255,17 +258,20 @@ def assemble_vector_block(L: typing.Any, scale: float = 1.0, constants_L=None, coeffs_L=None, constants_a=None, coeffs_a=None) -> PETSc.Vec: - raise NotImplementedError + try: + return _assemble_vector_block_form(L, a, bcs, x0, scale, constants_L, coeffs_L, constants_a, coeffs_a) + except TypeError: + raise NotImplementedError @assemble_vector_block.register(list) -def _assemble_vector_block_forms(L: typing.List[FormMetaClass], - a: typing.List[typing.List[FormMetaClass]], - bcs: typing.List[DirichletBCMetaClass] = [], - x0: typing.Optional[PETSc.Vec] = None, - scale: float = 1.0, - constants_L=None, coeffs_L=None, - constants_a=None, coeffs_a=None) -> PETSc.Vec: +def _assemble_vector_block_form(L: typing.List[FormMetaClass], + a: typing.List[typing.List[FormMetaClass]], + bcs: typing.List[DirichletBCMetaClass] = [], + x0: typing.Optional[PETSc.Vec] = None, + scale: float = 1.0, + constants_L=None, coeffs_L=None, + constants_a=None, coeffs_a=None) -> PETSc.Vec: """Assemble linear forms into a monolithic vector. The vector is not finalised, i.e. ghost values are not accumulated. From 1d9c83614f3432a0ea926c3ac4c6e4c626fab14c Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Sun, 22 May 2022 16:20:26 +0200 Subject: [PATCH 22/59] mypy settings in cfg file --- .github/workflows/ccpp.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index 945a3b4bac2..60f6445396e 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -144,9 +144,9 @@ jobs: run: | python -m pip install mypy # To remove once Docker images re-built cd python/ - mypy --ignore-missing-imports dolfinx - mypy --ignore-missing-imports demo - mypy --ignore-missing-imports test + mypy dolfinx + mypy demo + mypy test - name: Run demos (Python, serial) run: python3 -m pytest -n=2 -m serial --durations=10 python/demo/test.py From ea5165a30b9b7c8ce117542de2d5d6a82d11ff8b Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Sun, 22 May 2022 16:23:41 +0200 Subject: [PATCH 23/59] Small tweak --- python/demo/demo_poisson.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/demo/demo_poisson.py b/python/demo/demo_poisson.py index 2004afbce82..2094a7b82d2 100644 --- a/python/demo/demo_poisson.py +++ b/python/demo/demo_poisson.py @@ -155,7 +155,7 @@ # + try: import pyvista - cells, types, x = plot.create_vtk_mesh(V, dim=2) + cells, types, x = plot.create_vtk_mesh(V, dim=msh.topology.dim) grid = pyvista.UnstructuredGrid(cells, types, x) grid.point_data["u"] = uh.x.array.real grid.set_active_scalars("u") From 23d7f699909563e9a0b904442f5f8a564d8cba3f Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Sun, 22 May 2022 18:00:44 +0200 Subject: [PATCH 24/59] Bound numpy while 1.22 breaks numba --- python/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/setup.py b/python/setup.py index 074e24a4a18..05800be1295 100644 --- a/python/setup.py +++ b/python/setup.py @@ -15,7 +15,7 @@ VERSION = "0.4.2.dev0" REQUIREMENTS = [ - "numpy>=1.20", + "numpy>=1.20,<=1.21", # Remove once numba supports latest numpy "mpi4py", "petsc4py", "fenics-ffcx>=0.4.3.dev0,<0.5.0", From 7876b16f7203b002a78ae6ab7353ff0b3a3dfb79 Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Sun, 22 May 2022 18:01:35 +0200 Subject: [PATCH 25/59] pep8 --- python/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/setup.py b/python/setup.py index 05800be1295..dc166fd77ca 100644 --- a/python/setup.py +++ b/python/setup.py @@ -15,7 +15,7 @@ VERSION = "0.4.2.dev0" REQUIREMENTS = [ - "numpy>=1.20,<=1.21", # Remove once numba supports latest numpy + "numpy>=1.20,<=1.21", # Remove once numba supports latest numpy "mpi4py", "petsc4py", "fenics-ffcx>=0.4.3.dev0,<0.5.0", From a4ccbbf8727815e3d789a6ba7db94f0777e87e80 Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Mon, 23 May 2022 10:37:29 +0200 Subject: [PATCH 26/59] Remove numpy version --- python/dolfinx/fem/function.py | 4 ++-- python/setup.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/python/dolfinx/fem/function.py b/python/dolfinx/fem/function.py index ac72c6e4841..e363fa12db9 100644 --- a/python/dolfinx/fem/function.py +++ b/python/dolfinx/fem/function.py @@ -418,9 +418,9 @@ class FunctionSpace(ufl.FunctionSpace): """A space on which Functions (fields) can be defined.""" def __init__(self, mesh: typing.Union[None, Mesh], - element: typing.Union[ufl.FiniteElementBase, ElementMetaData, typing.Tuple], + element: typing.Union[ufl.FiniteElementBase, ElementMetaData, typing.Tuple[str, int]], cppV: typing.Optional[_cpp.fem.FunctionSpace] = None, - form_compiler_params: dict = {}, jit_params: dict = {}): + form_compiler_params: dict[str, typing.Any] = {}, jit_params: dict[str, typing.Any] = {}): """Create a finite element function space.""" # Create function space from a UFL element and existing cpp diff --git a/python/setup.py b/python/setup.py index dc166fd77ca..074e24a4a18 100644 --- a/python/setup.py +++ b/python/setup.py @@ -15,7 +15,7 @@ VERSION = "0.4.2.dev0" REQUIREMENTS = [ - "numpy>=1.20,<=1.21", # Remove once numba supports latest numpy + "numpy>=1.20", "mpi4py", "petsc4py", "fenics-ffcx>=0.4.3.dev0,<0.5.0", From 89e89cc6bd5e376804bd03b6f1a69c1e6b7dc246 Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Mon, 23 May 2022 10:45:54 +0200 Subject: [PATCH 27/59] Move back to old use --- python/demo/demo_elasticity.py | 4 ++-- python/dolfinx/fem/bcs.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/python/demo/demo_elasticity.py b/python/demo/demo_elasticity.py index 8242428ead0..67319a85d26 100644 --- a/python/demo/demo_elasticity.py +++ b/python/demo/demo_elasticity.py @@ -129,8 +129,8 @@ def σ(v): facets = locate_entities_boundary(msh, dim=2, marker=lambda x: np.logical_or(np.isclose(x[0], 0.0), np.isclose(x[1], 1.0))) -u_zero = Function(V) -bc = dirichletbc(u_zero, locate_dofs_topological(V, entity_dim=2, entities=facets)) +bc = dirichletbc(np.zeros(3, dtype=dtype), + locate_dofs_topological(V, entity_dim=2, entities=facets), V=V) # ## Assemble and solve # diff --git a/python/dolfinx/fem/bcs.py b/python/dolfinx/fem/bcs.py index 97417e2f8b7..0988df26703 100644 --- a/python/dolfinx/fem/bcs.py +++ b/python/dolfinx/fem/bcs.py @@ -134,7 +134,7 @@ def g(self): return self.value -def dirichletbc(value: typing.Union[Function, Constant], +def dirichletbc(value: typing.Union[Function, Constant, np.ndarray], dofs: numpy.typing.NDArray[np.int32], V: dolfinx.fem.FunctionSpace = None) -> DirichletBCMetaClass: """Create a representation of Dirichlet boundary condition which is imposed on a linear system. From af65b6bfc323d8fc7052733a0e374f02d6e3b954 Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Mon, 23 May 2022 11:50:22 +0200 Subject: [PATCH 28/59] fix --- python/dolfinx/fem/bcs.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/python/dolfinx/fem/bcs.py b/python/dolfinx/fem/bcs.py index 0988df26703..2509a6584ad 100644 --- a/python/dolfinx/fem/bcs.py +++ b/python/dolfinx/fem/bcs.py @@ -90,7 +90,7 @@ def locate_dofs_topological(V: typing.Union[dolfinx.fem.FunctionSpace, typing.It class DirichletBCMetaClass: - def __init__(self, value: typing.Union[ufl.Coefficient, Function, Constant, numpy.ndarray], + def __init__(self, value: typing.Union[Function, Constant, numpy.ndarray], dofs: numpy.typing.ArrayLike, V: dolfinx.fem.FunctionSpace = None): """Representation of Dirichlet boundary condition which is imposed on a linear system. @@ -106,19 +106,17 @@ class initialiser. This class is combined with different value: Lifted boundary values function. dofs: Local indices of degrees of freedom in function space to which boundary condition applies. Expects array of size (number of - dofs, 2) if function space of the problem, ``V``, is passed. + dofs, 2) if function space of the problem, ``V`` is passed. Otherwise assumes function space of the problem is the same - of function space of boundary values function. V: Function - space of a problem to which boundary conditions are applied. - + of function space of boundary values function. + V: Function space of a problem to which boundary conditions are applied. """ # Unwrap value object, if required - if not isinstance(value, np.ndarray): - try: - _value = value._cpp_object - except AttributeError: - _value = value + try: + _value = value._cpp_object + except AttributeError: + _value = value if V is not None: try: From e3c049db50c9717fc564bf809df45d64eb37dc14 Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Mon, 23 May 2022 11:55:34 +0200 Subject: [PATCH 29/59] flake8 --- python/dolfinx/fem/bcs.py | 1 - 1 file changed, 1 deletion(-) diff --git a/python/dolfinx/fem/bcs.py b/python/dolfinx/fem/bcs.py index 2509a6584ad..e3fc65db2f3 100644 --- a/python/dolfinx/fem/bcs.py +++ b/python/dolfinx/fem/bcs.py @@ -18,7 +18,6 @@ import numpy as np -import ufl import dolfinx from dolfinx import cpp as _cpp From 07b8f05692fb911d6fedbd10b8181275c3fe2c4e Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Mon, 23 May 2022 12:22:49 +0200 Subject: [PATCH 30/59] Test fixes --- python/dolfinx/fem/bcs.py | 9 ++++++--- python/test/conftest.py | 5 +++-- python/test/unit/fem/test_custom_assembler.py | 3 ++- python/test/unit/fem/test_expression.py | 3 ++- python/test/unit/io/test_xdmf_function.py | 2 +- python/test/unit/io/test_xdmf_mesh.py | 2 +- python/test/unit/io/test_xdmf_meshdata.py | 4 ++-- python/test/unit/io/test_xdmf_meshtags.py | 2 +- 8 files changed, 18 insertions(+), 12 deletions(-) diff --git a/python/dolfinx/fem/bcs.py b/python/dolfinx/fem/bcs.py index e3fc65db2f3..4f2eee731d6 100644 --- a/python/dolfinx/fem/bcs.py +++ b/python/dolfinx/fem/bcs.py @@ -112,10 +112,13 @@ class initialiser. This class is combined with different """ # Unwrap value object, if required - try: - _value = value._cpp_object - except AttributeError: + if isinstance(value, np.ndarray): _value = value + else: + try: + _value = value._cpp_object + except AttributeError: + _value = value if V is not None: try: diff --git a/python/test/conftest.py b/python/test/conftest.py index 89629bffe44..bd7f2efcbf6 100644 --- a/python/test/conftest.py +++ b/python/test/conftest.py @@ -119,8 +119,9 @@ def _create_tempdir(request): return path -_create_tempdir._sequencenumber = defaultdict(int) -_create_tempdir._basepaths = set() +# Assigning a function member variables is a bit of a nasty hack +_create_tempdir._sequencenumber = defaultdict(int) # type: ignore +_create_tempdir._basepaths = set() # type: ignore @pytest.fixture(scope="function") diff --git a/python/test/unit/fem/test_custom_assembler.py b/python/test/unit/fem/test_custom_assembler.py index 57d9be8cbba..cf75f60287f 100644 --- a/python/test/unit/fem/test_custom_assembler.py +++ b/python/test/unit/fem/test_custom_assembler.py @@ -17,6 +17,7 @@ import numba import numba.core.typing.cffi_utils as cffi_support import numpy as np +import numpy.typing import pytest import dolfinx @@ -47,7 +48,7 @@ if index_size == 8: c_int_t = "int64_t" - ctypes_index = ctypes.c_int64 + ctypes_index: numpy.typing.DTypeLike = ctypes.c_int64 elif index_size == 4: c_int_t = "int32_t" ctypes_index = ctypes.c_int32 diff --git a/python/test/unit/fem/test_expression.py b/python/test/unit/fem/test_expression.py index ff08582707c..08aa92258a9 100644 --- a/python/test/unit/fem/test_expression.py +++ b/python/test/unit/fem/test_expression.py @@ -11,6 +11,7 @@ import cffi import numba import numpy as np +import numpy.typing import basix import ufl @@ -41,7 +42,7 @@ if index_size == 8: c_int_t = "int64_t" - ctypes_index = ctypes.c_int64 + ctypes_index: np.typing.DTypeLike = ctypes.c_int64 elif index_size == 4: c_int_t = "int32_t" ctypes_index = ctypes.c_int32 diff --git a/python/test/unit/io/test_xdmf_function.py b/python/test/unit/io/test_xdmf_function.py index e708a762b37..e931825ab22 100644 --- a/python/test/unit/io/test_xdmf_function.py +++ b/python/test/unit/io/test_xdmf_function.py @@ -20,7 +20,7 @@ # Supported XDMF file encoding if MPI.COMM_WORLD.size > 1: - encodings = (XDMFFile.Encoding.HDF5, ) + encodings = (XDMFFile.Encoding.HDF5) else: encodings = (XDMFFile.Encoding.HDF5, XDMFFile.Encoding.ASCII) diff --git a/python/test/unit/io/test_xdmf_mesh.py b/python/test/unit/io/test_xdmf_mesh.py index b14593d03db..b03fca056ec 100644 --- a/python/test/unit/io/test_xdmf_mesh.py +++ b/python/test/unit/io/test_xdmf_mesh.py @@ -20,7 +20,7 @@ # Supported XDMF file encoding if MPI.COMM_WORLD.size > 1: - encodings = (XDMFFile.Encoding.HDF5, ) + encodings = (XDMFFile.Encoding.HDF5) else: encodings = (XDMFFile.Encoding.HDF5, XDMFFile.Encoding.ASCII) diff --git a/python/test/unit/io/test_xdmf_meshdata.py b/python/test/unit/io/test_xdmf_meshdata.py index 4c4da0520ed..c1890edf6c7 100644 --- a/python/test/unit/io/test_xdmf_meshdata.py +++ b/python/test/unit/io/test_xdmf_meshdata.py @@ -16,10 +16,10 @@ # Supported XDMF file encoding if MPI.COMM_WORLD.size > 1: - encodings = (XDMFFile.Encoding.HDF5, ) + encodings = (XDMFFile.Encoding.HDF5) else: encodings = (XDMFFile.Encoding.HDF5, XDMFFile.Encoding.ASCII) - encodings = (XDMFFile.Encoding.HDF5, ) + encodings = (XDMFFile.Encoding.HDF5) celltypes_2D = [CellType.triangle, CellType.quadrilateral] celltypes_3D = [CellType.tetrahedron, CellType.hexahedron] diff --git a/python/test/unit/io/test_xdmf_meshtags.py b/python/test/unit/io/test_xdmf_meshtags.py index 0155b28f1b9..eb259a6116a 100644 --- a/python/test/unit/io/test_xdmf_meshtags.py +++ b/python/test/unit/io/test_xdmf_meshtags.py @@ -17,7 +17,7 @@ # Supported XDMF file encoding if MPI.COMM_WORLD.size > 1: - encodings = (XDMFFile.Encoding.HDF5, ) + encodings = (XDMFFile.Encoding.HDF5) else: encodings = (XDMFFile.Encoding.ASCII, XDMFFile.Encoding.HDF5) From 98e214035f193209e39e1fbe1cb2cacfdf7943a6 Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Mon, 23 May 2022 12:24:05 +0200 Subject: [PATCH 31/59] move mypy up --- .github/workflows/ccpp.yml | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index 60f6445396e..723f567a93a 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -79,6 +79,14 @@ jobs: python3 -m isort --check dolfinx python3 -m isort --check demo python3 -m isort --check test + - name: mypy checks (non-blocking) + continue-on-error: true + run: | + python -m pip install mypy # To remove once Docker images re-built + cd python/ + mypy dolfinx + mypy demo + mypy test - name: clang-format C++ checks (non-blocking) continue-on-error: true run: | @@ -139,15 +147,6 @@ jobs: mkdir -p ~/.config/dolfinx echo '{ "cffi_extra_compile_args": ["-g0", "-O0" ] }' > ~/.config/dolfinx/dolfinx_jit_parameters.json - - name: mypy checks (non-blocking) - continue-on-error: true - run: | - python -m pip install mypy # To remove once Docker images re-built - cd python/ - mypy dolfinx - mypy demo - mypy test - - name: Run demos (Python, serial) run: python3 -m pytest -n=2 -m serial --durations=10 python/demo/test.py - name: Run demos (Python, MPI (np=2)) From 2edac28ae6ccecd447195ffc5ed2709118b462fe Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Mon, 23 May 2022 12:31:49 +0200 Subject: [PATCH 32/59] fix mypy install --- .github/workflows/ccpp.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index 723f567a93a..b5f85f2afb6 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -82,7 +82,7 @@ jobs: - name: mypy checks (non-blocking) continue-on-error: true run: | - python -m pip install mypy # To remove once Docker images re-built + python3 -m pip install mypy # To remove once Docker images re-built cd python/ mypy dolfinx mypy demo From c70f63b973d10de3bf69adfad6564add81177248 Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Mon, 23 May 2022 14:11:05 +0200 Subject: [PATCH 33/59] Fixes --- python/test/unit/fem/test_custom_assembler.py | 5 +++-- python/test/unit/io/test_xdmf_function.py | 4 ++-- python/test/unit/io/test_xdmf_mesh.py | 4 ++-- python/test/unit/io/test_xdmf_meshdata.py | 5 ++--- python/test/unit/io/test_xdmf_meshtags.py | 4 ++-- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/python/test/unit/fem/test_custom_assembler.py b/python/test/unit/fem/test_custom_assembler.py index cf75f60287f..3be30cd5757 100644 --- a/python/test/unit/fem/test_custom_assembler.py +++ b/python/test/unit/fem/test_custom_assembler.py @@ -86,9 +86,10 @@ raise # Get the PETSc MatSetValuesLocal function via ctypes +# ctypes does not support static types well, ignore type check errors MatSetValues_ctypes = petsc_lib_ctypes.MatSetValuesLocal -MatSetValues_ctypes.argtypes = (ctypes.c_void_p, ctypes_index, ctypes.POINTER( - ctypes_index), ctypes_index, ctypes.POINTER(ctypes_index), ctypes.c_void_p, ctypes.c_int) +MatSetValues_ctypes.argtypes = [ctypes.c_void_p, ctypes_index, ctypes.POINTER( # type: ignore + ctypes_index), ctypes_index, ctypes.POINTER(ctypes_index), ctypes.c_void_p, ctypes.c_int] # type: ignore del petsc_lib_ctypes diff --git a/python/test/unit/io/test_xdmf_function.py b/python/test/unit/io/test_xdmf_function.py index e931825ab22..76aca050479 100644 --- a/python/test/unit/io/test_xdmf_function.py +++ b/python/test/unit/io/test_xdmf_function.py @@ -20,9 +20,9 @@ # Supported XDMF file encoding if MPI.COMM_WORLD.size > 1: - encodings = (XDMFFile.Encoding.HDF5) + encodings = [XDMFFile.Encoding.HDF5] else: - encodings = (XDMFFile.Encoding.HDF5, XDMFFile.Encoding.ASCII) + encodings = [XDMFFile.Encoding.HDF5, XDMFFile.Encoding.ASCII] celltypes_2D = [CellType.triangle, CellType.quadrilateral] celltypes_3D = [CellType.tetrahedron, CellType.hexahedron] diff --git a/python/test/unit/io/test_xdmf_mesh.py b/python/test/unit/io/test_xdmf_mesh.py index b03fca056ec..e7b6b122431 100644 --- a/python/test/unit/io/test_xdmf_mesh.py +++ b/python/test/unit/io/test_xdmf_mesh.py @@ -20,9 +20,9 @@ # Supported XDMF file encoding if MPI.COMM_WORLD.size > 1: - encodings = (XDMFFile.Encoding.HDF5) + encodings = [XDMFFile.Encoding.HDF5] else: - encodings = (XDMFFile.Encoding.HDF5, XDMFFile.Encoding.ASCII) + encodings = [XDMFFile.Encoding.HDF5, XDMFFile.Encoding.ASCII] celltypes_2D = [CellType.triangle, CellType.quadrilateral] celltypes_3D = [CellType.tetrahedron, CellType.hexahedron] diff --git a/python/test/unit/io/test_xdmf_meshdata.py b/python/test/unit/io/test_xdmf_meshdata.py index c1890edf6c7..d6c95f38de2 100644 --- a/python/test/unit/io/test_xdmf_meshdata.py +++ b/python/test/unit/io/test_xdmf_meshdata.py @@ -16,10 +16,9 @@ # Supported XDMF file encoding if MPI.COMM_WORLD.size > 1: - encodings = (XDMFFile.Encoding.HDF5) + encodings = [XDMFFile.Encoding.HDF5] else: - encodings = (XDMFFile.Encoding.HDF5, XDMFFile.Encoding.ASCII) - encodings = (XDMFFile.Encoding.HDF5) + encodings = [XDMFFile.Encoding.HDF5, XDMFFile.Encoding.ASCII] celltypes_2D = [CellType.triangle, CellType.quadrilateral] celltypes_3D = [CellType.tetrahedron, CellType.hexahedron] diff --git a/python/test/unit/io/test_xdmf_meshtags.py b/python/test/unit/io/test_xdmf_meshtags.py index eb259a6116a..0977b0e6612 100644 --- a/python/test/unit/io/test_xdmf_meshtags.py +++ b/python/test/unit/io/test_xdmf_meshtags.py @@ -17,9 +17,9 @@ # Supported XDMF file encoding if MPI.COMM_WORLD.size > 1: - encodings = (XDMFFile.Encoding.HDF5) + encodings = [XDMFFile.Encoding.HDF5] else: - encodings = (XDMFFile.Encoding.ASCII, XDMFFile.Encoding.HDF5) + encodings = [XDMFFile.Encoding.ASCII, XDMFFile.Encoding.HDF5] celltypes_3D = [CellType.tetrahedron, CellType.hexahedron] From e6e5fb2d8490b83f152bb2891634b4077c57ab94 Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Mon, 23 May 2022 14:31:35 +0200 Subject: [PATCH 34/59] isort --- python/dolfinx/fem/bcs.py | 2 +- python/dolfinx/fem/petsc.py | 7 +++---- python/dolfinx/mesh.py | 3 +-- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/python/dolfinx/fem/bcs.py b/python/dolfinx/fem/bcs.py index 4f2eee731d6..9a3eb677f4a 100644 --- a/python/dolfinx/fem/bcs.py +++ b/python/dolfinx/fem/bcs.py @@ -10,12 +10,12 @@ import collections.abc import typing + import numpy.typing if typing.TYPE_CHECKING: from dolfinx.fem.function import Constant, Function - import numpy as np import dolfinx diff --git a/python/dolfinx/fem/petsc.py b/python/dolfinx/fem/petsc.py index 1a34900fb14..4e63cdc4a85 100644 --- a/python/dolfinx/fem/petsc.py +++ b/python/dolfinx/fem/petsc.py @@ -12,10 +12,9 @@ from __future__ import annotations -import typing - import contextlib import functools +import typing import ufl from dolfinx import cpp as _cpp @@ -23,11 +22,11 @@ from dolfinx.cpp.fem import pack_coefficients as _pack_coefficients from dolfinx.cpp.fem import pack_constants as _pack_constants from dolfinx.fem import assemble -from dolfinx.fem.bcs import bcs_by_block as _bcs_by_block from dolfinx.fem.bcs import DirichletBCMetaClass +from dolfinx.fem.bcs import bcs_by_block as _bcs_by_block +from dolfinx.fem.forms import FormMetaClass from dolfinx.fem.forms import extract_function_spaces as _extract_spaces from dolfinx.fem.forms import form as _create_form -from dolfinx.fem.forms import FormMetaClass from dolfinx.fem.function import Function as _Function from petsc4py import PETSc diff --git a/python/dolfinx/mesh.py b/python/dolfinx/mesh.py index 0ed84532eec..ac2057b0738 100644 --- a/python/dolfinx/mesh.py +++ b/python/dolfinx/mesh.py @@ -18,8 +18,7 @@ build_dual_graph, cell_dim, compute_boundary_facets, compute_incident_entities, compute_midpoints, - create_cell_partitioner, - to_string, to_type) + create_cell_partitioner, to_string, to_type) from mpi4py import MPI as _MPI From d7a7e1f56adb2d04657248432cc6300ce5961e76 Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Mon, 23 May 2022 14:33:08 +0200 Subject: [PATCH 35/59] Free numpy version --- python/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/setup.py b/python/setup.py index 074e24a4a18..2c8fc71c938 100644 --- a/python/setup.py +++ b/python/setup.py @@ -15,7 +15,7 @@ VERSION = "0.4.2.dev0" REQUIREMENTS = [ - "numpy>=1.20", + "numpy", "mpi4py", "petsc4py", "fenics-ffcx>=0.4.3.dev0,<0.5.0", From 675e85eb4d3521c5ee5a9a7dbb31056fc7bf1c2c Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Mon, 23 May 2022 21:57:37 +0200 Subject: [PATCH 36/59] Might need to re-run tests once Docker images update --- python/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/setup.py b/python/setup.py index 2c8fc71c938..074e24a4a18 100644 --- a/python/setup.py +++ b/python/setup.py @@ -15,7 +15,7 @@ VERSION = "0.4.2.dev0" REQUIREMENTS = [ - "numpy", + "numpy>=1.20", "mpi4py", "petsc4py", "fenics-ffcx>=0.4.3.dev0,<0.5.0", From 1179dc7f6858081fc8fb77481d273de5776405cf Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Mon, 23 May 2022 21:59:23 +0200 Subject: [PATCH 37/59] Add mypy to image --- docker/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index f5a919642eb..b6e2aa2dc53 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -174,7 +174,7 @@ RUN if [ "$MPI" = "mpich" ]; then \ # - Second set of packages are recommended and/or required to build # documentation or run tests. RUN pip3 install --no-binary="numpy" --no-cache-dir cffi mpi4py numba numpy==${NUMPY_VERSION} scipy && \ - pip3 install --no-cache-dir cppimport flake8 isort jupytext matplotlib myst-parser pybind11==${PYBIND11_VERSION} pytest pytest-xdist sphinx sphinx_rtd_theme + pip3 install --no-cache-dir cppimport flake8 isort jupytext matplotlib mypy myst-parser pybind11==${PYBIND11_VERSION} pytest pytest-xdist sphinx sphinx_rtd_theme # Install xtl, xtensor RUN git clone -b ${XTL_VERSION} --single-branch --depth 1 https://github.com/xtensor-stack/xtl.git && \ From 5b62896d004a8e761639b41ea34036c09cd64377 Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Tue, 24 May 2022 11:13:15 +0200 Subject: [PATCH 38/59] Type pybind11 . It seems like there are projects to generate typing data from pybind11 automagically but I think it looks too complex for a few methods. --- python/demo/demo_gmsh.py | 2 +- python/dolfinx/io.py | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/python/demo/demo_gmsh.py b/python/demo/demo_gmsh.py index 689f7ff89a4..5bd55b0babf 100644 --- a/python/demo/demo_gmsh.py +++ b/python/demo/demo_gmsh.py @@ -120,7 +120,7 @@ entities, values = distribute_entity_data(msh, 2, marked_facets, facet_values) msh.topology.create_connectivity(2, 0) -mt = meshtags_from_entities(msh, 2, create_adjacencylist(entities), np.array(values, dtype=np.int32)) +mt = meshtags_from_entities(msh, 2, create_adjacencylist(entities), values) mt.name = "ball_d1_surface" with XDMFFile(MPI.COMM_WORLD, "out_gmsh/mesh.xdmf", "w") as file: diff --git a/python/dolfinx/io.py b/python/dolfinx/io.py index d4cae64f00f..625df3de8c0 100644 --- a/python/dolfinx/io.py +++ b/python/dolfinx/io.py @@ -10,10 +10,10 @@ import typing import numpy as np +import numpy.typing as npt import ufl from dolfinx import cpp as _cpp -from dolfinx.cpp.io import distribute_entity_data # noqa: F401 from dolfinx.cpp.io import perm_gmsh as cell_perm_gmsh # noqa F401 from dolfinx.fem import Function from dolfinx.mesh import GhostMode, Mesh @@ -23,6 +23,11 @@ __all__ = ["FidesWriter", "VTKFile", "VTXWriter", "XDMFFile", "cell_perm_gmsh", "distribute_entity_data"] +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) + + def _extract_cpp_functions(functions: typing.Union[typing.List[Function], Function]): """Extract C++ object for a single function or a list of functions""" if isinstance(functions, (list, tuple)): From 8bcf9854b9e9b0c3a99b8822b1c0388b0fadc503 Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Tue, 24 May 2022 11:14:54 +0200 Subject: [PATCH 39/59] Remove mypy install from CI --- .github/workflows/ccpp.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index d095f4bdb6d..64509abf5d8 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -82,7 +82,6 @@ jobs: - name: mypy checks (non-blocking) continue-on-error: true run: | - python3 -m pip install mypy # To remove once Docker images re-built cd python/ mypy dolfinx mypy demo From 917e3cf6f38a265c6b3bb9b58740571be2699b63 Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Tue, 24 May 2022 11:25:27 +0200 Subject: [PATCH 40/59] Also wrap cell_perm_gmsh --- python/dolfinx/io.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/python/dolfinx/io.py b/python/dolfinx/io.py index 625df3de8c0..495e8c5b93e 100644 --- a/python/dolfinx/io.py +++ b/python/dolfinx/io.py @@ -14,20 +14,14 @@ import ufl from dolfinx import cpp as _cpp -from dolfinx.cpp.io import perm_gmsh as cell_perm_gmsh # noqa F401 from dolfinx.fem import Function -from dolfinx.mesh import GhostMode, Mesh +from dolfinx.mesh import GhostMode, Mesh, CellType from mpi4py import MPI as _MPI __all__ = ["FidesWriter", "VTKFile", "VTXWriter", "XDMFFile", "cell_perm_gmsh", "distribute_entity_data"] -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) - - def _extract_cpp_functions(functions: typing.Union[typing.List[Function], Function]): """Extract C++ object for a single function or a list of functions""" if isinstance(functions, (list, tuple)): @@ -179,6 +173,15 @@ def read_meshtags(self, mesh, name, xpath="/Xdmf/Domain"): return super().read_meshtags(mesh, 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) + + +def cell_perm_gmsh(cell_type: CellType, dim: int) -> typing.List[int]: + return _cpp.io.perm_gmsh(cell_type, dim) + + def extract_gmsh_topology_and_markers(gmsh_model, model_name=None): """Extract all entities tagged with a physical marker in the gmsh model, and collect the data per cell type. Returns a nested From 239d93d7c204b9d166cae2b157ad79172a681a4b Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Tue, 24 May 2022 11:38:23 +0200 Subject: [PATCH 41/59] Make dim optional, grab tdim? --- python/demo/demo_poisson.py | 2 +- python/demo/demo_pyvista.py | 8 ++++---- python/dolfinx/plot.py | 7 ++++++- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/python/demo/demo_poisson.py b/python/demo/demo_poisson.py index 2094a7b82d2..2d74d7c8eb3 100644 --- a/python/demo/demo_poisson.py +++ b/python/demo/demo_poisson.py @@ -155,7 +155,7 @@ # + try: import pyvista - cells, types, x = plot.create_vtk_mesh(V, dim=msh.topology.dim) + cells, types, x = plot.create_vtk_mesh(V) grid = pyvista.UnstructuredGrid(cells, types, x) grid.point_data["u"] = uh.x.array.real grid.set_active_scalars("u") diff --git a/python/demo/demo_pyvista.py b/python/demo/demo_pyvista.py index 6e7febaaf5e..3253232b16f 100644 --- a/python/demo/demo_pyvista.py +++ b/python/demo/demo_pyvista.py @@ -109,7 +109,7 @@ def in_circle(x): midpoints = compute_midpoints(msh, msh.topology.dim, list(np.arange(num_cells, dtype=np.int32))) cell_tags = meshtags(msh, msh.topology.dim, np.arange(num_cells), in_circle(midpoints)) - cells, types, x = plot.create_vtk_mesh(msh, msh.topology.dim) + cells, types, x = plot.create_vtk_mesh(msh) grid = pyvista.UnstructuredGrid(cells, types, x) # As the dolfinx.MeshTag contains a value for every cell in the @@ -129,7 +129,7 @@ def in_circle(x): # only consisting of those entities that has value one in the # dolfinx.MeshTag cells, types, x = plot.create_vtk_mesh( - msh, msh.topology.dim, cell_tags.indices[cell_tags.values == 1]) + msh, entities=cell_tags.indices[cell_tags.values == 1]) # We add this grid to the second plotter sub_grid = pyvista.UnstructuredGrid(cells, types, x) @@ -191,7 +191,7 @@ def in_circle(x): # that as we have done previously num_cells = msh.topology.index_map(msh.topology.dim).size_local cell_entities = np.arange(num_cells, dtype=np.int32) - cells, types, x = plot.create_vtk_mesh(msh, msh.topology.dim, cell_entities) + cells, types, x = plot.create_vtk_mesh(msh, entities=cell_entities) org_grid = pyvista.UnstructuredGrid(cells, types, x) # We visualize the data @@ -225,7 +225,7 @@ def plot_nedelec(): position="upper_edge", font_size=14, color="black") # Next, we create a pyvista.UnstructuredGrid based on the mesh - pyvista_cells, cell_types, x = plot.create_vtk_mesh(msh, msh.topology.dim) + pyvista_cells, cell_types, x = plot.create_vtk_mesh(msh) grid = pyvista.UnstructuredGrid(pyvista_cells, cell_types, x) # Add this grid (as a wireframe) to the plotter diff --git a/python/dolfinx/plot.py b/python/dolfinx/plot.py index c2cea72225b..c728848a141 100644 --- a/python/dolfinx/plot.py +++ b/python/dolfinx/plot.py @@ -6,6 +6,7 @@ """Support functions for plotting""" import functools +import typing import warnings import numpy as np @@ -29,13 +30,17 @@ @functools.singledispatch -def create_vtk_mesh(msh: mesh.Mesh, dim: int, entities=None): +def create_vtk_mesh(msh: mesh.Mesh, dim: typing.Optional[int] = None, entities=None): """Create vtk mesh topology data for mesh entities of a given dimension. The vertex indices in the returned topology array are the indices for the associated entry in the mesh geometry. """ + if dim is None: + dim = msh.topology.dim + tdim = msh.topology.dim + cell_type = _cpp.mesh.cell_entity_type(msh.topology.cell_type, dim, 0) degree = msh.geometry.cmap.degree if cell_type == mesh.CellType.prism: From d07815986d51853bc0bfbcf7792013e0a1d43e35 Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Tue, 24 May 2022 11:43:07 +0200 Subject: [PATCH 42/59] Reallow value to be passed --- python/demo/demo_static-condensation.py | 2 +- python/dolfinx/mesh.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/python/demo/demo_static-condensation.py b/python/demo/demo_static-condensation.py index 286727fcf7b..73ac74763b7 100644 --- a/python/demo/demo_static-condensation.py +++ b/python/demo/demo_static-condensation.py @@ -63,7 +63,7 @@ # Locate all facets at the free end and assign them value 1. Sort the # facet indices (requirement for constructing MeshTags) free_end_facets = np.sort(locate_entities_boundary(msh, 1, lambda x: np.isclose(x[0], 48.0))) -mt = meshtags(msh, 1, free_end_facets, np.ones_like(free_end_facets)) +mt = meshtags(msh, 1, free_end_facets, 1) ds = ufl.Measure("ds", subdomain_data=mt) diff --git a/python/dolfinx/mesh.py b/python/dolfinx/mesh.py index ac2057b0738..4eba03184ff 100644 --- a/python/dolfinx/mesh.py +++ b/python/dolfinx/mesh.py @@ -231,7 +231,8 @@ def ufl_id(self) -> int: return id(self) -def meshtags(mesh: Mesh, dim: int, indices: np.ndarray, values: np.ndarray) -> MeshTagsMetaClass: +def meshtags(mesh: Mesh, dim: int, indices: np.ndarray, + values: typing.Union[np.ndarray, int, float]) -> MeshTagsMetaClass: """Create a MeshTags object that associates data with a subset of mesh entities. Args: From 99bc314725d9a7735fe5322a08a449db2a068755 Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Tue, 24 May 2022 11:48:26 +0200 Subject: [PATCH 43/59] Allow lists to eval --- python/dolfinx/fem/function.py | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/python/dolfinx/fem/function.py b/python/dolfinx/fem/function.py index e363fa12db9..bd9745b546e 100644 --- a/python/dolfinx/fem/function.py +++ b/python/dolfinx/fem/function.py @@ -16,6 +16,7 @@ import cffi import numpy as np +import numpy.typing as npt import ufl import ufl.algorithms @@ -265,29 +266,29 @@ def function_space(self) -> FunctionSpace: """The FunctionSpace that the Function is defined on""" return self._V - def eval(self, x: np.ndarray, cells: np.ndarray, u=None) -> np.ndarray: + def eval(self, x: npt.ArrayLike, cells: npt.ArrayLike, u=None) -> np.ndarray: """Evaluate Function at points x, where x has shape (num_points, 3), and cells has shape (num_points,) and cell[i] is the index of the cell containing point x[i]. If the cell index is negative the point is ignored.""" # Make sure input coordinates are a NumPy array - x = np.asarray(x, dtype=np.float64) - assert x.ndim < 3 - if len(x) == 0: - x = np.zeros((0, 3)) + _x = np.asarray(x, dtype=np.float64) + assert _x.ndim < 3 + if len(_x) == 0: + _x = np.zeros((0, 3)) else: - shape0 = x.shape[0] if x.ndim == 2 else 1 - x = np.reshape(x, (shape0, -1)) - num_points = x.shape[0] - if x.shape[1] != 3: + shape0 = _x.shape[0] if _x.ndim == 2 else 1 + _x = np.reshape(_x, (shape0, -1)) + num_points = _x.shape[0] + if _x.shape[1] != 3: raise ValueError("Coordinate(s) for Function evaluation must have length 3.") # Make sure cells are a NumPy array - cells = np.asarray(cells, dtype=np.int32) - assert cells.ndim < 2 - num_points_c = cells.shape[0] if cells.ndim == 1 else 1 - cells = np.reshape(cells, num_points_c) + _cells = np.asarray(cells, dtype=np.int32) + assert _cells.ndim < 2 + num_points_c = _cells.shape[0] if _cells.ndim == 1 else 1 + _cells = np.reshape(_cells, num_points_c) # Allocate memory for return value if not provided if u is None: @@ -297,7 +298,7 @@ def eval(self, x: np.ndarray, cells: np.ndarray, u=None) -> np.ndarray: else: u = np.empty((num_points, value_size)) - self._cpp_object.eval(x, cells, u) + self._cpp_object.eval(_x, _cells, u) if num_points == 1: u = np.reshape(u, (-1, )) return u From 73f4d965f6ba2d42484cf87c01af0e685da5eb89 Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Tue, 24 May 2022 11:53:04 +0200 Subject: [PATCH 44/59] Remove comment --- python/dolfinx/fem/forms.py | 1 - 1 file changed, 1 deletion(-) diff --git a/python/dolfinx/fem/forms.py b/python/dolfinx/fem/forms.py index 1adecdf4357..3096c6570b0 100644 --- a/python/dolfinx/fem/forms.py +++ b/python/dolfinx/fem/forms.py @@ -63,7 +63,6 @@ def code(self) -> str: """C code strings""" return self._code - # The below member function definitions are necessary for type checking @property def function_spaces(self) -> typing.List[FunctionSpace]: """Function spaces on which this form is defined""" From ade54ba88673ac1b05314bb5dcc879314b14c4cb Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Tue, 24 May 2022 12:10:08 +0200 Subject: [PATCH 45/59] Better API? --- python/dolfinx/fem/assemble.py | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/python/dolfinx/fem/assemble.py b/python/dolfinx/fem/assemble.py index 018b6b3fb37..50695e1358b 100644 --- a/python/dolfinx/fem/assemble.py +++ b/python/dolfinx/fem/assemble.py @@ -133,15 +133,18 @@ def assemble_scalar(M: FormMetaClass, constants=None, coeffs=None): # -- Vector assembly --------------------------------------------------------- @functools.singledispatch -def assemble_vector(L: typing.Any, constants=None, coeffs=None): - try: - return _assemble_vector_form(L, constants, coeffs) - except TypeError: - raise NotImplementedError +def assemble_vector(L: typing.Any, + constants=None, coeffs=None): + raise NotImplementedError +@assemble_vector.register(_cpp.fem.Form_float32) +@assemble_vector.register(_cpp.fem.Form_float64) +@assemble_vector.register(_cpp.fem.Form_complex64) +@assemble_vector.register(_cpp.fem.Form_complex128) @assemble_vector.register(FormMetaClass) -def _assemble_vector_form(L: FormMetaClass, constants=None, coeffs=None) -> la.VectorMetaClass: +def _assemble_vector_form(L: typing.Union[FormMetaClass, _cpp.fem.Form_float32, + _cpp.fem.Form_float64, _cpp.fem.Form_complex64, _cpp.fem.Form_complex128], constants=None, coeffs=None) -> la.VectorMetaClass: """Assemble linear form into a new Vector. Args: @@ -209,12 +212,11 @@ def _assemble_vector_array(b: np.ndarray, L: FormMetaClass, constants=None, coef @functools.singledispatch -def assemble_matrix(a: typing.Any, bcs: typing.List[DirichletBCMetaClass] = None, +def assemble_matrix(a: typing.Union[FormMetaClass, la.MatrixCSRMetaClass, _cpp.fem.Form_float32, + _cpp.fem.Form_float64, _cpp.fem.Form_complex64, _cpp.fem.Form_complex128], + bcs: typing.List[DirichletBCMetaClass] = None, diagonal: float = 1.0, constants=None, coeffs=None): - try: - return _assemble_matrix_form(a, bcs, diagonal, constants, coeffs) - except TypeError: - raise NotImplementedError + return _assemble_matrix_form(a, bcs, diagonal, constants, coeffs) @assemble_matrix.register(la.MatrixCSRMetaClass) From 79620328766d4859590852f712e212399517ebaf Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Tue, 24 May 2022 12:28:40 +0200 Subject: [PATCH 46/59] Prefer this design. --- python/demo/demo_static-condensation.py | 4 ++-- python/dolfinx/fem/assemble.py | 12 +++--------- python/dolfinx/fem/petsc.py | 20 ++++---------------- 3 files changed, 9 insertions(+), 27 deletions(-) diff --git a/python/demo/demo_static-condensation.py b/python/demo/demo_static-condensation.py index 73ac74763b7..cc23d96e5e5 100644 --- a/python/demo/demo_static-condensation.py +++ b/python/demo/demo_static-condensation.py @@ -32,8 +32,8 @@ from dolfinx.cpp.fem import Form_complex128, Form_float64 from dolfinx.fem import (Function, FunctionSpace, IntegralType, dirichletbc, form, locate_dofs_topological) -from dolfinx.fem.petsc import (apply_lifting, assemble_matrix, assemble_vector, - set_bc) +from dolfinx.fem.petsc import (apply_lifting, set_bc, assemble_vector) +from dolfinx.fem.petsc import _assemble_matrix_form as assemble_matrix from dolfinx.io import XDMFFile from dolfinx.jit import ffcx_jit from dolfinx.mesh import locate_entities_boundary, meshtags diff --git a/python/dolfinx/fem/assemble.py b/python/dolfinx/fem/assemble.py index 50695e1358b..a13bed49912 100644 --- a/python/dolfinx/fem/assemble.py +++ b/python/dolfinx/fem/assemble.py @@ -138,13 +138,8 @@ def assemble_vector(L: typing.Any, raise NotImplementedError -@assemble_vector.register(_cpp.fem.Form_float32) -@assemble_vector.register(_cpp.fem.Form_float64) -@assemble_vector.register(_cpp.fem.Form_complex64) -@assemble_vector.register(_cpp.fem.Form_complex128) @assemble_vector.register(FormMetaClass) -def _assemble_vector_form(L: typing.Union[FormMetaClass, _cpp.fem.Form_float32, - _cpp.fem.Form_float64, _cpp.fem.Form_complex64, _cpp.fem.Form_complex128], constants=None, coeffs=None) -> la.VectorMetaClass: +def _assemble_vector_form(L: FormMetaClass, constants=None, coeffs=None) -> la.VectorMetaClass: """Assemble linear form into a new Vector. Args: @@ -212,11 +207,10 @@ def _assemble_vector_array(b: np.ndarray, L: FormMetaClass, constants=None, coef @functools.singledispatch -def assemble_matrix(a: typing.Union[FormMetaClass, la.MatrixCSRMetaClass, _cpp.fem.Form_float32, - _cpp.fem.Form_float64, _cpp.fem.Form_complex64, _cpp.fem.Form_complex128], +def assemble_matrix(a: typing.Any, bcs: typing.List[DirichletBCMetaClass] = None, diagonal: float = 1.0, constants=None, coeffs=None): - return _assemble_matrix_form(a, bcs, diagonal, constants, coeffs) + raise NotImplementedError @assemble_matrix.register(la.MatrixCSRMetaClass) diff --git a/python/dolfinx/fem/petsc.py b/python/dolfinx/fem/petsc.py index 4e63cdc4a85..afbd2e460cb 100644 --- a/python/dolfinx/fem/petsc.py +++ b/python/dolfinx/fem/petsc.py @@ -159,10 +159,7 @@ def create_matrix_nest(a: typing.List[typing.List[FormMetaClass]]) -> PETSc.Mat: @functools.singledispatch def assemble_vector(L: typing.Any, constants=None, coeffs=None) -> PETSc.Vec: - try: - return _assemble_vector_form(L, constants, coeffs) - except TypeError: - raise NotImplementedError + raise NotImplementedError @assemble_vector.register(FormMetaClass) @@ -211,10 +208,7 @@ def _assemble_vector_vec(b: PETSc.Vec, L: FormMetaClass, constants=None, coeffs= @functools.singledispatch def assemble_vector_nest(L: typing.Any, constants=None, coeffs=None) -> PETSc.Vec: - try: - return _assemble_vector_form(L, constants, coeffs) - except TypeError: - raise NotImplementedError + raise NotImplementedError @assemble_vector_nest.register(list) @@ -342,10 +336,7 @@ def _assemble_vector_block_vec(b: PETSc.Vec, def assemble_matrix(a: typing.Any, bcs: typing.List[DirichletBCMetaClass] = [], diagonal: float = 1.0, constants=None, coeffs=None) -> PETSc.Mat: - try: - return _assemble_matrix_form(a, bcs, diagonal, constants, coeffs) - except TypeError: - raise NotImplementedError + raise NotImplementedError @assemble_matrix.register @@ -432,10 +423,7 @@ def assemble_matrix_block(a: typing.Any, bcs: typing.List[DirichletBCMetaClass] = [], diagonal: float = 1.0, constants=None, coeffs=None) -> PETSc.Mat: - try: - return _assemble_matrix_block_form(a, bcs, diagonal, constants, coeffs) - except TypeError: - raise NotImplementedError + raise NotImplementedError @assemble_matrix_block.register(list) From 89c891b6daaf726309c86e7f6b33f0a6ba639dbf Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Tue, 24 May 2022 13:15:57 +0200 Subject: [PATCH 47/59] Better singledispatch la --- python/demo/demo_gmsh.py | 1 + python/demo/demo_lagrange_variants.py | 8 +-- python/demo/demo_poisson.py | 1 + python/demo/demo_static-condensation.py | 4 +- python/demo/demo_stokes.py | 1 + python/demo/demo_tnt-elements.py | 2 + python/dolfinx/fem/assemble.py | 21 ++++---- python/dolfinx/fem/bcs.py | 10 ++-- python/dolfinx/fem/forms.py | 4 ++ python/dolfinx/fem/petsc.py | 67 ++++++++++++------------- python/dolfinx/io.py | 2 +- python/setup.py | 8 ++- 12 files changed, 66 insertions(+), 63 deletions(-) diff --git a/python/demo/demo_gmsh.py b/python/demo/demo_gmsh.py index 5bd55b0babf..37c0b6efabf 100644 --- a/python/demo/demo_gmsh.py +++ b/python/demo/demo_gmsh.py @@ -32,6 +32,7 @@ from dolfinx.mesh import CellType, create_mesh, meshtags_from_entities from mpi4py import MPI + # - # Generate a mesh on each rank with the gmsh API, and create a DOLFINx diff --git a/python/demo/demo_lagrange_variants.py b/python/demo/demo_lagrange_variants.py index d9896a08cf9..291358c2a76 100644 --- a/python/demo/demo_lagrange_variants.py +++ b/python/demo/demo_lagrange_variants.py @@ -17,25 +17,25 @@ # # We begin this demo by importing everything we require. +import matplotlib.pylab as plt # + import numpy as np -import ufl +import basix +import basix.ufl_wrapper +import ufl from dolfinx import fem, mesh from ufl import ds, dx, grad, inner from mpi4py import MPI from petsc4py.PETSc import ScalarType -import matplotlib.pylab as plt # - # In addition to the imports seen in other demos, we also import Basix # and its UFL wrapper directly. Basix is the element definition and # tabulation library that is used by FEniCSx. -import basix -import basix.ufl_wrapper # ## Equispaced points vs GLL points # The basis function of Lagrange elements are defined by placing points diff --git a/python/demo/demo_poisson.py b/python/demo/demo_poisson.py index 2d74d7c8eb3..af7d2a3561f 100644 --- a/python/demo/demo_poisson.py +++ b/python/demo/demo_poisson.py @@ -75,6 +75,7 @@ from mpi4py import MPI from petsc4py.PETSc import ScalarType + # - # We begin by using {py:func}`create_rectangle diff --git a/python/demo/demo_static-condensation.py b/python/demo/demo_static-condensation.py index cc23d96e5e5..73ac74763b7 100644 --- a/python/demo/demo_static-condensation.py +++ b/python/demo/demo_static-condensation.py @@ -32,8 +32,8 @@ from dolfinx.cpp.fem import Form_complex128, Form_float64 from dolfinx.fem import (Function, FunctionSpace, IntegralType, dirichletbc, form, locate_dofs_topological) -from dolfinx.fem.petsc import (apply_lifting, set_bc, assemble_vector) -from dolfinx.fem.petsc import _assemble_matrix_form as assemble_matrix +from dolfinx.fem.petsc import (apply_lifting, assemble_matrix, assemble_vector, + set_bc) from dolfinx.io import XDMFFile from dolfinx.jit import ffcx_jit from dolfinx.mesh import locate_entities_boundary, meshtags diff --git a/python/demo/demo_stokes.py b/python/demo/demo_stokes.py index 88c2f040907..c59d265e0ad 100644 --- a/python/demo/demo_stokes.py +++ b/python/demo/demo_stokes.py @@ -92,6 +92,7 @@ from mpi4py import MPI from petsc4py import PETSc + # - # We create a Mesh and attach a coordinate map to the mesh: diff --git a/python/demo/demo_tnt-elements.py b/python/demo/demo_tnt-elements.py index 11f0cd5223c..7cd00db0764 100644 --- a/python/demo/demo_tnt-elements.py +++ b/python/demo/demo_tnt-elements.py @@ -18,6 +18,7 @@ # + import typing + import matplotlib.pylab as plt import numpy as np @@ -28,6 +29,7 @@ grad, inner, sin) from mpi4py import MPI + # - # ## Defining a degree 1 TNT element diff --git a/python/dolfinx/fem/assemble.py b/python/dolfinx/fem/assemble.py index a13bed49912..81c126c5253 100644 --- a/python/dolfinx/fem/assemble.py +++ b/python/dolfinx/fem/assemble.py @@ -8,12 +8,8 @@ from __future__ import annotations import collections -import typing - -if typing.TYPE_CHECKING: - from dolfinx.fem.bcs import DirichletBCMetaClass - import functools +import typing import numpy as np @@ -22,7 +18,8 @@ from dolfinx import la from dolfinx.cpp.fem import pack_coefficients as _pack_coefficients from dolfinx.cpp.fem import pack_constants as _pack_constants -from dolfinx.fem.forms import FormMetaClass +from dolfinx.fem.bcs import DirichletBCMetaClass +from dolfinx.fem.forms import FormMetaClass, form_types def pack_constants(form: typing.Union[FormMetaClass, @@ -139,7 +136,7 @@ def assemble_vector(L: typing.Any, @assemble_vector.register(FormMetaClass) -def _assemble_vector_form(L: FormMetaClass, constants=None, coeffs=None) -> la.VectorMetaClass: +def _assemble_vector_form(L: form_types, constants=None, coeffs=None) -> la.VectorMetaClass: """Assemble linear form into a new Vector. Args: @@ -210,11 +207,11 @@ def _assemble_vector_array(b: np.ndarray, L: FormMetaClass, constants=None, coef def assemble_matrix(a: typing.Any, bcs: typing.List[DirichletBCMetaClass] = None, diagonal: float = 1.0, constants=None, coeffs=None): - raise NotImplementedError + _assemble_matrix_form(a, bcs, diagonal, constants, coeffs) -@assemble_matrix.register(la.MatrixCSRMetaClass) -def _assemble_matrix_csr(A: la.MatrixCSRMetaClass, a: FormMetaClass, +@assemble_matrix.register +def _assemble_matrix_csr(A: la.MatrixCSRMetaClass, a: form_types, bcs: typing.List[DirichletBCMetaClass] = None, diagonal: float = 1.0, constants=None, coeffs=None) -> la.MatrixCSRMetaClass: """Assemble bilinear form into a matrix. @@ -247,8 +244,8 @@ def _assemble_matrix_csr(A: la.MatrixCSRMetaClass, a: FormMetaClass, return A -@assemble_matrix.register(FormMetaClass) -def _assemble_matrix_form(a: FormMetaClass, bcs: typing.List[DirichletBCMetaClass] = None, +@assemble_vector.register(FormMetaClass) +def _assemble_matrix_form(a: form_types, bcs: typing.List[DirichletBCMetaClass] = None, diagonal: float = 1.0, constants=None, coeffs=None) -> la.MatrixCSRMetaClass: """Assemble bilinear form into a matrix. diff --git a/python/dolfinx/fem/bcs.py b/python/dolfinx/fem/bcs.py index 9a3eb677f4a..1bb38c90b4f 100644 --- a/python/dolfinx/fem/bcs.py +++ b/python/dolfinx/fem/bcs.py @@ -110,7 +110,6 @@ class initialiser. This class is combined with different of function space of boundary values function. V: Function space of a problem to which boundary conditions are applied. """ - # Unwrap value object, if required if isinstance(value, np.ndarray): _value = value @@ -129,9 +128,14 @@ class initialiser. This class is combined with different super().__init__(_value, dofs) # type: ignore @property - def g(self): + def value(self): """The boundary condition value(s)""" - return self.value + return super().value # type: ignore + + @property + def function_space(self) -> dolfinx.fem.FunctionSpace: + """The function space on which the boundary condition is defined""" + return super().function_space # type: ignore def dirichletbc(value: typing.Union[Function, Constant, np.ndarray], diff --git a/python/dolfinx/fem/forms.py b/python/dolfinx/fem/forms.py index 3096c6570b0..6922bd00676 100644 --- a/python/dolfinx/fem/forms.py +++ b/python/dolfinx/fem/forms.py @@ -84,6 +84,10 @@ def integral_types(self): return super().integral_types # type: ignore +form_types = typing.Union[FormMetaClass, _cpp.fem.Form_float32, _cpp.fem.Form_float64, + _cpp.fem.Form_complex64, _cpp.fem.Form_complex128] + + def form(form: typing.Union[ufl.Form, typing.Iterable[ufl.Form]], dtype: np.dtype = PETSc.ScalarType, form_compiler_params: dict = {}, jit_params: dict = {}): """Create a DOLFINx Form or an array of Forms diff --git a/python/dolfinx/fem/petsc.py b/python/dolfinx/fem/petsc.py index afbd2e460cb..33b0b71c97b 100644 --- a/python/dolfinx/fem/petsc.py +++ b/python/dolfinx/fem/petsc.py @@ -27,6 +27,7 @@ from dolfinx.fem.forms import FormMetaClass from dolfinx.fem.forms import extract_function_spaces as _extract_spaces from dolfinx.fem.forms import form as _create_form +from dolfinx.fem.forms import form_types from dolfinx.fem.function import Function as _Function from petsc4py import PETSc @@ -65,7 +66,7 @@ def fn(form): # -- Vector instantiation ---------------------------------------------------- -def create_vector(L: FormMetaClass) -> PETSc.Vec: +def create_vector(L: form_types) -> PETSc.Vec: """Create a PETSc vector that is compaible with a linear form. Args: @@ -79,7 +80,7 @@ def create_vector(L: FormMetaClass) -> PETSc.Vec: return la.create_petsc_vector(dofmap.index_map, dofmap.index_map_bs) -def create_vector_block(L: typing.List[FormMetaClass]) -> PETSc.Vec: +def create_vector_block(L: typing.List[form_types]) -> PETSc.Vec: """Create a PETSc vector (blocked) that is compaible with a list of linear forms. Args: @@ -94,7 +95,7 @@ def create_vector_block(L: typing.List[FormMetaClass]) -> PETSc.Vec: return _cpp.fem.petsc.create_vector_block(maps) -def create_vector_nest(L: typing.List[FormMetaClass]) -> PETSc.Vec: +def create_vector_nest(L: typing.List[form_types]) -> PETSc.Vec: """Create a PETSc netsted vector (``VecNest``) that is compaible with a list of linear forms. Args: @@ -112,7 +113,7 @@ def create_vector_nest(L: typing.List[FormMetaClass]) -> PETSc.Vec: # -- Matrix instantiation ---------------------------------------------------- -def create_matrix(a: FormMetaClass, mat_type=None) -> PETSc.Mat: +def create_matrix(a: form_types, mat_type=None) -> PETSc.Mat: """Create a PETSc matrix that is compaible with a bilinear form. Args: @@ -129,7 +130,7 @@ def create_matrix(a: FormMetaClass, mat_type=None) -> PETSc.Mat: return _cpp.fem.petsc.create_matrix(a, mat_type) -def create_matrix_block(a: typing.List[typing.List[FormMetaClass]]) -> PETSc.Mat: +def create_matrix_block(a: typing.List[typing.List[form_types]]) -> PETSc.Mat: """Create a PETSc matrix that is compaible with a rectangular array of bilinear forms. Args: @@ -142,7 +143,7 @@ def create_matrix_block(a: typing.List[typing.List[FormMetaClass]]) -> PETSc.Mat return _cpp.fem.petsc.create_matrix_block(a) -def create_matrix_nest(a: typing.List[typing.List[FormMetaClass]]) -> PETSc.Mat: +def create_matrix_nest(a: typing.List[typing.List[form_types]]) -> PETSc.Mat: """Create a PETSc matrix (``MatNest``) that is compaible with a rectangular array of bilinear forms. Args: @@ -159,11 +160,11 @@ def create_matrix_nest(a: typing.List[typing.List[FormMetaClass]]) -> PETSc.Mat: @functools.singledispatch def assemble_vector(L: typing.Any, constants=None, coeffs=None) -> PETSc.Vec: - raise NotImplementedError + return _assemble_vector_form(L, constants, coeffs) @assemble_vector.register(FormMetaClass) -def _assemble_vector_form(L: FormMetaClass, constants=None, coeffs=None) -> PETSc.Vec: +def _assemble_vector_form(L: form_types, constants=None, coeffs=None) -> PETSc.Vec: """Assemble linear form into a new PETSc vector. Note: @@ -185,7 +186,7 @@ def _assemble_vector_form(L: FormMetaClass, constants=None, coeffs=None) -> PETS @assemble_vector.register(PETSc.Vec) -def _assemble_vector_vec(b: PETSc.Vec, L: FormMetaClass, constants=None, coeffs=None) -> PETSc.Vec: +def _assemble_vector_vec(b: PETSc.Vec, L: form_types, constants=None, coeffs=None) -> PETSc.Vec: """Assemble linear form into an existing PETSc vector. Note: @@ -208,11 +209,11 @@ def _assemble_vector_vec(b: PETSc.Vec, L: FormMetaClass, constants=None, coeffs= @functools.singledispatch def assemble_vector_nest(L: typing.Any, constants=None, coeffs=None) -> PETSc.Vec: - raise NotImplementedError + return _assemble_vector_nest_forms(L, constants, coeffs) @assemble_vector_nest.register(list) -def _assemble_vector_nest_forms(L: typing.List[FormMetaClass], constants=None, coeffs=None) -> PETSc.Vec: +def _assemble_vector_nest_forms(L: typing.List[form_types], constants=None, coeffs=None) -> PETSc.Vec: """Assemble linear forms into a new nested PETSc (VecNest) vector. The returned vector is not finalised, i.e. ghost values are not accumulated on the owning processes. @@ -228,7 +229,7 @@ def _assemble_vector_nest_forms(L: typing.List[FormMetaClass], constants=None, c @assemble_vector_nest.register -def _assemble_vector_nest_vec(b: PETSc.Vec, L: typing.List[FormMetaClass], constants=None, coeffs=None) -> PETSc.Vec: +def _assemble_vector_nest_vec(b: PETSc.Vec, L: typing.List[form_types], constants=None, coeffs=None) -> PETSc.Vec: """Assemble linear forms into a nested PETSc (VecNest) vector. The vector is not zeroed before assembly and it is not finalised, i.e. ghost values are not accumulated on the owning processes. @@ -245,21 +246,18 @@ def _assemble_vector_nest_vec(b: PETSc.Vec, L: typing.List[FormMetaClass], const # FIXME: Revise this interface @functools.singledispatch def assemble_vector_block(L: typing.Any, - a: typing.List[typing.List[FormMetaClass]], + a: typing.List[typing.List[form_types]], bcs: typing.List[DirichletBCMetaClass] = [], x0: typing.Optional[PETSc.Vec] = None, scale: float = 1.0, constants_L=None, coeffs_L=None, constants_a=None, coeffs_a=None) -> PETSc.Vec: - try: - return _assemble_vector_block_form(L, a, bcs, x0, scale, constants_L, coeffs_L, constants_a, coeffs_a) - except TypeError: - raise NotImplementedError + return _assemble_vector_block_form(L, a, bcs, x0, scale, constants_L, coeffs_L, constants_a, coeffs_a) @assemble_vector_block.register(list) -def _assemble_vector_block_form(L: typing.List[FormMetaClass], - a: typing.List[typing.List[FormMetaClass]], +def _assemble_vector_block_form(L: typing.List[form_types], + a: typing.List[typing.List[form_types]], bcs: typing.List[DirichletBCMetaClass] = [], x0: typing.Optional[PETSc.Vec] = None, scale: float = 1.0, @@ -280,8 +278,8 @@ def _assemble_vector_block_form(L: typing.List[FormMetaClass], @assemble_vector_block.register def _assemble_vector_block_vec(b: PETSc.Vec, - L: typing.List[FormMetaClass], - a: typing.List[typing.List[FormMetaClass]], + L: typing.List[form_types], + a: typing.List[typing.List[form_types]], bcs: typing.List[DirichletBCMetaClass] = [], x0: typing.Optional[PETSc.Vec] = None, scale: float = 1.0, @@ -336,11 +334,11 @@ def _assemble_vector_block_vec(b: PETSc.Vec, def assemble_matrix(a: typing.Any, bcs: typing.List[DirichletBCMetaClass] = [], diagonal: float = 1.0, constants=None, coeffs=None) -> PETSc.Mat: - raise NotImplementedError + return _assemble_matrix_form(a, bcs, diagonal, constants, coeffs) -@assemble_matrix.register -def _assemble_matrix_form(a: FormMetaClass, bcs: typing.List[DirichletBCMetaClass] = [], +@assemble_matrix.register(FormMetaClass) +def _assemble_matrix_form(a: form_types, bcs: typing.List[DirichletBCMetaClass] = [], diagonal: float = 1.0, constants=None, coeffs=None) -> PETSc.Mat: """Assemble bilinear form into a matrix. The returned matrix is not @@ -353,7 +351,7 @@ def _assemble_matrix_form(a: FormMetaClass, bcs: typing.List[DirichletBCMetaClas @assemble_matrix.register -def _assemble_matrix_mat(A: PETSc.Mat, a: FormMetaClass, bcs: typing.List[DirichletBCMetaClass] = [], +def _assemble_matrix_mat(A: PETSc.Mat, a: form_types, bcs: typing.List[DirichletBCMetaClass] = [], diagonal: float = 1.0, constants=None, coeffs=None) -> PETSc.Mat: """Assemble bilinear form into a matrix. The returned matrix is not finalised, i.e. ghost values are not accumulated. @@ -375,14 +373,11 @@ def assemble_matrix_nest(a: typing.Any, bcs: typing.List[DirichletBCMetaClass] = [], mat_types=[], diagonal: float = 1.0, constants=None, coeffs=None) -> PETSc.Mat: - try: - return _assemble_matrix_nest_form(a, bcs, diagonal, constants, coeffs) - except TypeError: - raise NotImplementedError + return _assemble_matrix_nest_form(a, bcs, diagonal, constants, coeffs) @assemble_matrix_nest.register(list) -def _assemble_matrix_nest_form(a: typing.List[typing.List[FormMetaClass]], +def _assemble_matrix_nest_form(a: typing.List[typing.List[form_types]], bcs: typing.List[DirichletBCMetaClass] = [], mat_types=[], diagonal: float = 1.0, constants=None, coeffs=None) -> PETSc.Mat: @@ -393,7 +388,7 @@ def _assemble_matrix_nest_form(a: typing.List[typing.List[FormMetaClass]], @assemble_matrix_nest.register -def _assemble_matrix_nest_mat(A: PETSc.Mat, a: typing.List[typing.List[FormMetaClass]], +def _assemble_matrix_nest_mat(A: PETSc.Mat, a: typing.List[typing.List[form_types]], bcs: typing.List[DirichletBCMetaClass] = [], diagonal: float = 1.0, constants=None, coeffs=None) -> PETSc.Mat: """Assemble bilinear forms into matrix""" @@ -423,11 +418,11 @@ def assemble_matrix_block(a: typing.Any, bcs: typing.List[DirichletBCMetaClass] = [], diagonal: float = 1.0, constants=None, coeffs=None) -> PETSc.Mat: - raise NotImplementedError + _assemble_matrix_block_form(a, bcs, diagonal, constants, coeffs) @assemble_matrix_block.register(list) -def _assemble_matrix_block_form(a: typing.List[typing.List[FormMetaClass]], +def _assemble_matrix_block_form(a: typing.List[typing.List[form_types]], bcs: typing.List[DirichletBCMetaClass] = [], diagonal: float = 1.0, constants=None, coeffs=None) -> PETSc.Mat: @@ -437,7 +432,7 @@ def _assemble_matrix_block_form(a: typing.List[typing.List[FormMetaClass]], @assemble_matrix_block.register -def _assemble_matrix_block_mat(A: PETSc.Mat, a: typing.List[typing.List[FormMetaClass]], +def _assemble_matrix_block_mat(A: PETSc.Mat, a: typing.List[typing.List[form_types]], bcs: typing.List[DirichletBCMetaClass] = [], diagonal: float = 1.0, constants=None, coeffs=None) -> PETSc.Mat: """Assemble bilinear forms into matrix""" @@ -484,7 +479,7 @@ def _assemble_matrix_block_mat(A: PETSc.Mat, a: typing.List[typing.List[FormMeta # -- Modifiers for Dirichlet conditions --------------------------------------- -def apply_lifting(b: PETSc.Vec, a: typing.List[FormMetaClass], +def apply_lifting(b: PETSc.Vec, a: typing.List[form_types], bcs: typing.List[typing.List[DirichletBCMetaClass]], x0: typing.List[PETSc.Vec] = [], scale: float = 1.0, constants=None, coeffs=None) -> None: @@ -496,7 +491,7 @@ def apply_lifting(b: PETSc.Vec, a: typing.List[FormMetaClass], assemble.apply_lifting(b_local.array_w, a, bcs, x0_r, scale, constants, coeffs) -def apply_lifting_nest(b: PETSc.Vec, a: typing.List[typing.List[FormMetaClass]], +def apply_lifting_nest(b: PETSc.Vec, a: typing.List[typing.List[form_types]], bcs: typing.List[DirichletBCMetaClass], x0: typing.Optional[PETSc.Vec] = None, scale: float = 1.0, constants=None, coeffs=None) -> PETSc.Vec: diff --git a/python/dolfinx/io.py b/python/dolfinx/io.py index 495e8c5b93e..bbf84988264 100644 --- a/python/dolfinx/io.py +++ b/python/dolfinx/io.py @@ -15,7 +15,7 @@ import ufl from dolfinx import cpp as _cpp from dolfinx.fem import Function -from dolfinx.mesh import GhostMode, Mesh, CellType +from dolfinx.mesh import CellType, GhostMode, Mesh from mpi4py import MPI as _MPI diff --git a/python/setup.py b/python/setup.py index 074e24a4a18..cea3efbbde3 100644 --- a/python/setup.py +++ b/python/setup.py @@ -1,6 +1,4 @@ import os -import platform -import re import subprocess import sys import sysconfig @@ -8,8 +6,8 @@ from setuptools import Extension, setup from setuptools.command.build_ext import build_ext -if sys.version_info < (3, 7): - print("Python 3.7 or higher required, please upgrade.") +if sys.version_info < (3, 8): + print("Python 3.8 or higher required, please upgrade.") sys.exit(1) VERSION = "0.4.2.dev0" @@ -32,7 +30,7 @@ def __init__(self, name, sourcedir=''): class CMakeBuild(build_ext): def run(self): try: - out = subprocess.check_output(['cmake', '--version']) + _ = subprocess.check_output(['cmake', '--version']) except OSError: raise RuntimeError("CMake must be installed to build the following extensions: " + ", ".join(e.name for e in self.extensions)) From 16ec231cb4e713e60e9c3056a4f6b906fc881ed3 Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Tue, 24 May 2022 15:34:15 +0200 Subject: [PATCH 48/59] Bug fixes --- python/dolfinx/fem/assemble.py | 6 +++--- python/dolfinx/fem/petsc.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/python/dolfinx/fem/assemble.py b/python/dolfinx/fem/assemble.py index 81c126c5253..aeb360fb062 100644 --- a/python/dolfinx/fem/assemble.py +++ b/python/dolfinx/fem/assemble.py @@ -132,7 +132,7 @@ def assemble_scalar(M: FormMetaClass, constants=None, coeffs=None): @functools.singledispatch def assemble_vector(L: typing.Any, constants=None, coeffs=None): - raise NotImplementedError + return _assemble_vector_form(L, constants, coeffs) @assemble_vector.register(FormMetaClass) @@ -207,7 +207,7 @@ def _assemble_vector_array(b: np.ndarray, L: FormMetaClass, constants=None, coef def assemble_matrix(a: typing.Any, bcs: typing.List[DirichletBCMetaClass] = None, diagonal: float = 1.0, constants=None, coeffs=None): - _assemble_matrix_form(a, bcs, diagonal, constants, coeffs) + return _assemble_matrix_form(a, bcs, diagonal, constants, coeffs) @assemble_matrix.register @@ -244,7 +244,7 @@ def _assemble_matrix_csr(A: la.MatrixCSRMetaClass, a: form_types, return A -@assemble_vector.register(FormMetaClass) +@assemble_matrix.register(FormMetaClass) def _assemble_matrix_form(a: form_types, bcs: typing.List[DirichletBCMetaClass] = None, diagonal: float = 1.0, constants=None, coeffs=None) -> la.MatrixCSRMetaClass: diff --git a/python/dolfinx/fem/petsc.py b/python/dolfinx/fem/petsc.py index 33b0b71c97b..f4fd03a0cf7 100644 --- a/python/dolfinx/fem/petsc.py +++ b/python/dolfinx/fem/petsc.py @@ -418,7 +418,7 @@ def assemble_matrix_block(a: typing.Any, bcs: typing.List[DirichletBCMetaClass] = [], diagonal: float = 1.0, constants=None, coeffs=None) -> PETSc.Mat: - _assemble_matrix_block_form(a, bcs, diagonal, constants, coeffs) + return _assemble_matrix_block_form(a, bcs, diagonal, constants, coeffs) @assemble_matrix_block.register(list) From e0e30ecb76be3ba26c7b8c3738c2990a4344d1bd Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Wed, 25 May 2022 10:04:34 +0200 Subject: [PATCH 49/59] Fix --- python/dolfinx/fem/bcs.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/dolfinx/fem/bcs.py b/python/dolfinx/fem/bcs.py index 1bb38c90b4f..6684a0e498a 100644 --- a/python/dolfinx/fem/bcs.py +++ b/python/dolfinx/fem/bcs.py @@ -128,9 +128,9 @@ class initialiser. This class is combined with different super().__init__(_value, dofs) # type: ignore @property - def value(self): + def g(self): """The boundary condition value(s)""" - return super().value # type: ignore + return self.value # type: ignore @property def function_space(self) -> dolfinx.fem.FunctionSpace: From 947051bde7bd31210602346344a54d225455e853 Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Wed, 25 May 2022 10:17:02 +0200 Subject: [PATCH 50/59] Ignore return error --- docker/complex-kernel.json | 2 +- python/dolfinx/fem/forms.py | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/docker/complex-kernel.json b/docker/complex-kernel.json index 14092205d54..a319d48ca3c 100644 --- a/docker/complex-kernel.json +++ b/docker/complex-kernel.json @@ -14,7 +14,7 @@ "env": { "PKG_CONFIG_PATH": "/usr/local/dolfinx-complex/lib/pkgconfig", "PETSC_ARCH": "linux-gnu-complex-32", - "PYTHONPATH": "/usr/local/dolfinx-complex/lib/python3.8/dist-packages", + "PYTHONPATH": "/usr/local/dolfinx-complex/lib/python3.10/dist-packages", "LD_LIBRARY_PATH": "/usr/local/dolfinx-complex/lib" } } diff --git a/python/dolfinx/fem/forms.py b/python/dolfinx/fem/forms.py index 6922bd00676..022b1c3c5e1 100644 --- a/python/dolfinx/fem/forms.py +++ b/python/dolfinx/fem/forms.py @@ -168,7 +168,7 @@ def _create_form(form): return _create_form(form) -def extract_function_spaces(forms: typing.Union[typing.Iterable[FormMetaClass], +def extract_function_spaces(forms: typing.Union[typing.Iterable[FormMetaClass], # type: ignore [return] typing.Iterable[typing.Iterable[FormMetaClass]]], index: int = 0) -> typing.Iterable[typing.Union[None, function.FunctionSpace]]: """Extract common function spaces from an array of forms. If `forms` @@ -213,5 +213,3 @@ def unique_spaces(V): return list(unique_spaces(V.transpose())) else: raise RuntimeError("Unsupported array of forms") - - return [] # For static type checkers, will never reach. From 9296b15aa21999531e5a3acbfba6b5dd5730ffa1 Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Wed, 25 May 2022 10:17:34 +0200 Subject: [PATCH 51/59] flake8 --- python/dolfinx/fem/forms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/dolfinx/fem/forms.py b/python/dolfinx/fem/forms.py index 022b1c3c5e1..191e665ed57 100644 --- a/python/dolfinx/fem/forms.py +++ b/python/dolfinx/fem/forms.py @@ -168,7 +168,7 @@ def _create_form(form): return _create_form(form) -def extract_function_spaces(forms: typing.Union[typing.Iterable[FormMetaClass], # type: ignore [return] +def extract_function_spaces(forms: typing.Union[typing.Iterable[FormMetaClass], # type: ignore [return] typing.Iterable[typing.Iterable[FormMetaClass]]], index: int = 0) -> typing.Iterable[typing.Union[None, function.FunctionSpace]]: """Extract common function spaces from an array of forms. If `forms` From d4244c66ce8a52a3e125d3d6f10233bb3d814cfe Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Wed, 25 May 2022 10:23:23 +0200 Subject: [PATCH 52/59] Remove explicit casts --- python/demo/demo_gmsh.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/demo/demo_gmsh.py b/python/demo/demo_gmsh.py index 7cd55d05d01..8e19d0259db 100644 --- a/python/demo/demo_gmsh.py +++ b/python/demo/demo_gmsh.py @@ -180,7 +180,7 @@ entities, values = distribute_entity_data(msh, 2, marked_facets, facet_values) msh.topology.create_connectivity(2, 0) -mt = meshtags_from_entities(msh, 2, create_adjacencylist(entities), np.array(values, dtype=np.int32)) +mt = meshtags_from_entities(msh, 2, create_adjacencylist(entities), values) mt.name = "ball_d2_surface" with XDMFFile(MPI.COMM_WORLD, "out_gmsh/mesh.xdmf", "a") as file: file.write_mesh(msh) @@ -257,7 +257,7 @@ entities, values = distribute_entity_data(msh, 2, marked_facets, facet_values) msh.topology.create_connectivity(2, 0) -mt = meshtags_from_entities(msh, 2, create_adjacencylist(entities), np.array(values, dtype=np.int32)) +mt = meshtags_from_entities(msh, 2, create_adjacencylist(entities), values) mt.name = "hex_d2_surface" with XDMFFile(MPI.COMM_WORLD, "out_gmsh/mesh.xdmf", "a") as file: From b352006f174a388a235198b33466383b8f6f5a48 Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Wed, 25 May 2022 10:46:04 +0200 Subject: [PATCH 53/59] Remove cryptic typings, ignore errors --- python/demo/demo_tnt-elements.py | 4 ++-- python/dolfinx/fem/function.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/python/demo/demo_tnt-elements.py b/python/demo/demo_tnt-elements.py index 7cd00db0764..3ac5813c2bb 100644 --- a/python/demo/demo_tnt-elements.py +++ b/python/demo/demo_tnt-elements.py @@ -71,8 +71,8 @@ # + geometry = basix.geometry(basix.CellType.quadrilateral) topology = basix.topology(basix.CellType.quadrilateral) -x: typing.List[typing.List[np.ndarray]] = [[], [], [], []] -M: typing.List[typing.List[np.ndarray]] = [[], [], [], []] +x = [[], [], [], []] # type: ignore [var-annotated] +M = [[], [], [], []] # type: ignore [var-annotated] for v in topology[0]: x[0].append(np.array(geometry[v])) diff --git a/python/dolfinx/fem/function.py b/python/dolfinx/fem/function.py index bd9745b546e..a79540eddd0 100644 --- a/python/dolfinx/fem/function.py +++ b/python/dolfinx/fem/function.py @@ -433,8 +433,8 @@ def __init__(self, mesh: typing.Union[None, Mesh], self._cpp_object = cppV return - # This if is required for type checks to pass if mesh is not None: + assert cppV is None # Initialise the ufl.FunctionSpace if isinstance(element, ufl.FiniteElementBase): super().__init__(mesh.ufl_domain(), element) From 83cb9eb702fbcf5dd3098594b54befebda933cc2 Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Wed, 25 May 2022 10:50:00 +0200 Subject: [PATCH 54/59] Revert some files to main --- docker/complex-kernel.json | 2 +- python/demo/demo_stokes.py | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/docker/complex-kernel.json b/docker/complex-kernel.json index a319d48ca3c..14092205d54 100644 --- a/docker/complex-kernel.json +++ b/docker/complex-kernel.json @@ -14,7 +14,7 @@ "env": { "PKG_CONFIG_PATH": "/usr/local/dolfinx-complex/lib/pkgconfig", "PETSC_ARCH": "linux-gnu-complex-32", - "PYTHONPATH": "/usr/local/dolfinx-complex/lib/python3.10/dist-packages", + "PYTHONPATH": "/usr/local/dolfinx-complex/lib/python3.8/dist-packages", "LD_LIBRARY_PATH": "/usr/local/dolfinx-complex/lib" } } diff --git a/python/demo/demo_stokes.py b/python/demo/demo_stokes.py index 6c66aa9525d..ed056fd92db 100644 --- a/python/demo/demo_stokes.py +++ b/python/demo/demo_stokes.py @@ -92,7 +92,6 @@ from mpi4py import MPI from petsc4py import PETSc - # - # We create a {py:class}`Mesh `, define functions to @@ -140,9 +139,9 @@ def lid_velocity_expression(x): # + # No-slip boundary condition for velocity field (`V`) on boundaries # where x = 0, x = 1, and y = 0 -noslip = Function(V) +noslip = np.zeros(msh.geometry.dim, dtype=PETSc.ScalarType) facets = locate_entities_boundary(msh, 1, noslip_boundary) -bc0 = dirichletbc(noslip, locate_dofs_topological(V, 1, facets)) +bc0 = dirichletbc(noslip, locate_dofs_topological(V, 1, facets), V) # Driving velocity condition u = (1, 0) on top boundary (y = 1) lid_velocity = Function(V) From 5477334ac661bf5fbe7ce792ff0da368f35b9ff1 Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Wed, 25 May 2022 10:50:38 +0200 Subject: [PATCH 55/59] Remove explicit dim --- python/demo/demo_cahn-hilliard.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/demo/demo_cahn-hilliard.py b/python/demo/demo_cahn-hilliard.py index 9778142c76b..9616a4a4ca6 100644 --- a/python/demo/demo_cahn-hilliard.py +++ b/python/demo/demo_cahn-hilliard.py @@ -301,7 +301,7 @@ # Prepare viewer for plotting the solution during the computation if have_pyvista: # Create a VTK 'mesh' with 'nodes' at the function dofs - topology, cell_types, x = plot.create_vtk_mesh(V0, msh.topology.dim) + topology, cell_types, x = plot.create_vtk_mesh(V0) grid = pv.UnstructuredGrid(topology, cell_types, x) # Set output data From 4dadcba8be5a3b753ba4cb523c7764179d6f7cd0 Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Wed, 25 May 2022 10:58:17 +0200 Subject: [PATCH 56/59] Small tweaks. --- python/demo/demo_interpolation-io.py | 2 +- python/demo/demo_lagrange_variants.py | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/python/demo/demo_interpolation-io.py b/python/demo/demo_interpolation-io.py index ea25fc9cdb3..7e7f05b10b3 100644 --- a/python/demo/demo_interpolation-io.py +++ b/python/demo/demo_interpolation-io.py @@ -70,7 +70,7 @@ # Plot solution try: import pyvista - cells, types, x = plot.create_vtk_mesh(V0, dim=msh.topology.dim) + cells, types, x = plot.create_vtk_mesh(V0) grid = pyvista.UnstructuredGrid(cells, types, x) values = np.zeros((x.shape[0], 3), dtype=np.float64) values[:, :msh.topology.dim] = u0.x.array.reshape(x.shape[0], msh.topology.dim).real diff --git a/python/demo/demo_lagrange_variants.py b/python/demo/demo_lagrange_variants.py index 00760c16bbc..e0778cb0968 100644 --- a/python/demo/demo_lagrange_variants.py +++ b/python/demo/demo_lagrange_variants.py @@ -176,11 +176,9 @@ def saw_tooth(x): for i in range(51): pts.append([cell / 10 + i / 50 / 10, 0, 0]) cells.append(cell) - pts_np = np.array(pts) - cells_np = np.array(cells) - values = uh.eval(pts_np, cells_np) - plt.plot(pts_np[:, 0], [saw_tooth(i[0]) for i in pts], "k--") - plt.plot(pts_np[:, 0], values, "r-") + values = uh.eval(pts, cells) + plt.plot(pts, [saw_tooth(i[0]) for i in pts], "k--") + plt.plot(pts, values, "r-") plt.legend(["function", "approximation"]) plt.ylim([-0.1, 0.4]) From e431eb07282770c4cd9433435b097d3d59fe1404 Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Wed, 25 May 2022 10:58:37 +0200 Subject: [PATCH 57/59] Revert --- python/demo/demo_poisson.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/python/demo/demo_poisson.py b/python/demo/demo_poisson.py index 994350191bc..6f384cc2572 100644 --- a/python/demo/demo_poisson.py +++ b/python/demo/demo_poisson.py @@ -75,7 +75,6 @@ from mpi4py import MPI from petsc4py.PETSc import ScalarType - # - # We begin by using {py:func}`create_rectangle @@ -125,7 +124,7 @@ u = ufl.TrialFunction(V) v = ufl.TestFunction(V) x = ufl.SpatialCoordinate(msh) -f = 10.0 * ufl.exp(-((x[0] - 0.5) ** 2 + (x[1] - 0.5) ** 2) / 0.02) +f = 10 * ufl.exp(-((x[0] - 0.5) ** 2 + (x[1] - 0.5) ** 2) / 0.02) g = ufl.sin(5 * x[0]) a = inner(grad(u), grad(v)) * dx L = inner(f, v) * dx + inner(g, v) * ds From 6bd4d0693c2b2847023164b6abd02b288ac778f4 Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Wed, 25 May 2022 11:00:48 +0200 Subject: [PATCH 58/59] flake8 --- python/demo/demo_tnt-elements.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/python/demo/demo_tnt-elements.py b/python/demo/demo_tnt-elements.py index 3ac5813c2bb..28d1a24421d 100644 --- a/python/demo/demo_tnt-elements.py +++ b/python/demo/demo_tnt-elements.py @@ -17,8 +17,6 @@ # We begin this demo by importing everything we require. # + -import typing - import matplotlib.pylab as plt import numpy as np From ecc87b3fb032a8fcef1905881697e5f3ee953d67 Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Wed, 25 May 2022 16:24:06 +0200 Subject: [PATCH 59/59] Fix, should discuss this again --- python/dolfinx/__init__.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/python/dolfinx/__init__.py b/python/dolfinx/__init__.py index e41abe07ee7..308221b8e49 100644 --- a/python/dolfinx/__init__.py +++ b/python/dolfinx/__init__.py @@ -6,6 +6,24 @@ """Main module for DOLFINx""" # flake8: noqa + +# Store dl open flags to restore them after import +import sys + +stored_dlopen_flags = sys.getdlopenflags() + +# Developer note: below is related to OpenMPI +# Fix dlopen flags +if "linux" in sys.platform: + RTLD_NOW = 2 + RTLD_GLOBAL = 256 + sys.setdlopenflags(RTLD_NOW | RTLD_GLOBAL) +del sys + +# Reset dl open flags +# sys.setdlopenflags(stored_dlopen_flags) +# del sys + import sys from dolfinx import common