From fd3359ec85318b1f59ef799aacbf0f07137664bc Mon Sep 17 00:00:00 2001 From: schnellerhase <56360279+schnellerhase@users.noreply.github.com> Date: Wed, 9 Jul 2025 20:39:48 +0200 Subject: [PATCH 01/12] Fix utils.py --- python/dolfinx/io/utils.py | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/python/dolfinx/io/utils.py b/python/dolfinx/io/utils.py index 79a38c0e543..9be4f39e85d 100644 --- a/python/dolfinx/io/utils.py +++ b/python/dolfinx/io/utils.py @@ -26,9 +26,9 @@ __all__ = ["VTKFile", "XDMFFile", "cell_perm_gmsh", "cell_perm_vtk", "distribute_entity_data"] -def _extract_cpp_objects(functions: typing.Union[Mesh, Function, tuple[Function], list[Function]]): +def _extract_cpp_objects(functions: typing.Union[Mesh, Function, typing.Iterable[Function]]): """Extract C++ objects""" - if isinstance(functions, (list, tuple)): + if not isinstance(functions, Function): return [getattr(u, "_cpp_object", u) for u in functions] else: return [getattr(functions, "_cpp_object", functions)] @@ -56,7 +56,7 @@ def __init__( self, comm: _MPI.Comm, filename: typing.Union[str, Path], - output: typing.Union[Mesh, Function, list[Function], tuple[Function]], + output: typing.Union[Mesh, Function, typing.Iterable[Function]], engine: str = "BPFile", mesh_policy: VTXMeshPolicy = VTXMeshPolicy.update, ): @@ -81,27 +81,27 @@ def __init__( have the same element type. """ # Get geometry type - try: - dtype = output.geometry.x.dtype # type: ignore - except AttributeError: - try: - dtype = output.function_space.mesh.geometry.x.dtype # type: ignore - except AttributeError: - dtype = output[0].function_space.mesh.geometry.x.dtype # type: ignore + + if isinstance(output, Mesh): + dtype = output.geometry.x.dtype + elif isinstance(output, Function): + dtype = output.function_space.mesh.geometry.x.dtype + elif isinstance(output, typing.Iterable): + dtype = next(output).function_space.mesh.geometry.x.dtype # type: ignore + else: + raise RuntimeError(f"Can not write type {type(output)}.") if np.issubdtype(dtype, np.float32): _vtxwriter = _cpp.io.VTXWriter_float32 elif np.issubdtype(dtype, np.float64): _vtxwriter = _cpp.io.VTXWriter_float64 - try: - # Input is a mesh - self._cpp_object = _vtxwriter(comm, filename, output._cpp_object, engine) # type: ignore[union-attr] - except (NotImplementedError, TypeError, AttributeError): - # Input is a single function or a list of functions + if isinstance(output, Mesh): + self._cpp_object = _vtxwriter(comm, filename, output._cpp_object, engine) + else: self._cpp_object = _vtxwriter( comm, filename, _extract_cpp_objects(output), engine, mesh_policy - ) # type: ignore[arg-type] + ) def __enter__(self): return self From 95879e43a3d40aae2da090e32136178e5c8811a3 Mon Sep 17 00:00:00 2001 From: schnellerhase <56360279+schnellerhase@users.noreply.github.com> Date: Wed, 9 Jul 2025 21:05:42 +0200 Subject: [PATCH 02/12] Adapt demos --- python/demo/demo_hdg.py | 4 ++-- python/demo/demo_interpolation-io.py | 6 +++--- python/demo/demo_mixed-poisson.py | 4 ++-- python/demo/demo_navier-stokes.py | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/python/demo/demo_hdg.py b/python/demo/demo_hdg.py index 49fcfa6401c..28b70f1efa3 100644 --- a/python/demo/demo_hdg.py +++ b/python/demo/demo_hdg.py @@ -216,14 +216,14 @@ def u_e(x): ubar.x.scatter_forward() # Write to file -try: +if dolfinx.has_adios2: from dolfinx.io import VTXWriter with VTXWriter(msh.comm, "u.bp", u, "bp4") as f: f.write(0.0) with VTXWriter(msh.comm, "ubar.bp", ubar, "bp4") as f: f.write(0.0) -except ImportError: +else: print("ADIOS2 required for VTX output") diff --git a/python/demo/demo_interpolation-io.py b/python/demo/demo_interpolation-io.py index b91aa15c4a5..91d2a170d79 100644 --- a/python/demo/demo_interpolation-io.py +++ b/python/demo/demo_interpolation-io.py @@ -23,7 +23,7 @@ # + import numpy as np -from dolfinx import default_scalar_type, plot +from dolfinx import default_scalar_type, has_adios2, plot from dolfinx.fem import Function, functionspace from dolfinx.mesh import CellType, create_rectangle, locate_entities @@ -64,12 +64,12 @@ # the field, at $x_0 = 0.5$ the $x_0$-component should appear # discontinuous and the $x_1$-component should appear continuous. -try: +if has_adios2: from dolfinx.io import VTXWriter with VTXWriter(msh.comm, "output_nedelec.bp", u0, "bp4") as f: f.write(0.0) -except ImportError: +else: print("ADIOS2 required for VTX output") diff --git a/python/demo/demo_mixed-poisson.py b/python/demo/demo_mixed-poisson.py index de204742a3e..4ce70f2828b 100644 --- a/python/demo/demo_mixed-poisson.py +++ b/python/demo/demo_mixed-poisson.py @@ -353,12 +353,12 @@ # We save the solution `u` in VTX format: # + -try: +if dolfinx.has_adios2: from dolfinx.io import VTXWriter u.name = "u" with VTXWriter(msh.comm, "output_mixed_poisson.bp", u, "bp4") as f: f.write(0.0) -except ImportError: +else: print("ADIOS2 required for VTX output.") # - diff --git a/python/demo/demo_navier-stokes.py b/python/demo/demo_navier-stokes.py index 27a85c3f427..ee5a6d1b904 100644 --- a/python/demo/demo_navier-stokes.py +++ b/python/demo/demo_navier-stokes.py @@ -372,12 +372,12 @@ def jump(phi, n): # Write initial condition to file t = 0.0 -try: +if dolfinx.has_adios2: u_file = io.VTXWriter(msh.comm, "u.bp", u_vis) p_file = io.VTXWriter(msh.comm, "p.bp", p_h) u_file.write(t) p_file.write(t) -except AttributeError: +else: print("File output requires ADIOS2.") # Create function to store solution and previous time step From 260eee9d0866cb97dab73070e19f8fbdae1a1004 Mon Sep 17 00:00:00 2001 From: schnellerhase <56360279+schnellerhase@users.noreply.github.com> Date: Wed, 9 Jul 2025 21:16:26 +0200 Subject: [PATCH 03/12] Fix function --- python/dolfinx/fem/function.py | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/python/dolfinx/fem/function.py b/python/dolfinx/fem/function.py index 5e81b90c797..a0ddf235df9 100644 --- a/python/dolfinx/fem/function.py +++ b/python/dolfinx/fem/function.py @@ -141,10 +141,7 @@ def __init__( # Attempt to deduce dtype if dtype is None: - try: - dtype = e.dtype # type: ignore - except AttributeError: - dtype = default_scalar_type + dtype = e.dtype if hasattr(e, "dtype") else default_scalar_type # Compile UFL expression with JIT if form_compiler_options is None: @@ -599,18 +596,18 @@ def functionspace( """ # Create UFL element dtype = mesh.geometry.x.dtype - try: - e = ElementMetaData(*element) # type: ignore + if isinstance(element, ufl.finiteelement.AbstractFiniteElement): + ufl_e = element + else: + e = ElementMetaData(*element) ufl_e = basix.ufl.element( e.family, - mesh.basix_cell(), # type: ignore + mesh.basix_cell(), e.degree, shape=e.shape, symmetry=e.symmetry, dtype=dtype, ) - except TypeError: - ufl_e = element # type: ignore # Check that element and mesh cell types match if ((domain := mesh.ufl_domain()) is None) or ufl_e.cell != domain.ufl_cell(): @@ -625,10 +622,10 @@ def functionspace( ) # Initialize the cpp.FunctionSpace - try: - cppV = _cpp.fem.FunctionSpace_float64(mesh._cpp_object, element._cpp_object, cpp_dofmap) # type: ignore - except TypeError: + if np.issubdtype(dtype, np.float32): cppV = _cpp.fem.FunctionSpace_float32(mesh._cpp_object, element._cpp_object, cpp_dofmap) # type: ignore + else: + cppV = _cpp.fem.FunctionSpace_float64(mesh._cpp_object, element._cpp_object, cpp_dofmap) # type: ignore return FunctionSpace(mesh, ufl_e, cppV) From d39cb41ca7eb762d6d8c931789ca1defd1610e0b Mon Sep 17 00:00:00 2001 From: schnellerhase <56360279+schnellerhase@users.noreply.github.com> Date: Wed, 9 Jul 2025 21:35:22 +0200 Subject: [PATCH 04/12] abc.Iterable --- python/dolfinx/io/utils.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/python/dolfinx/io/utils.py b/python/dolfinx/io/utils.py index 9be4f39e85d..ea62f63cf62 100644 --- a/python/dolfinx/io/utils.py +++ b/python/dolfinx/io/utils.py @@ -7,6 +7,7 @@ """IO module for input data and post-processing file output.""" import typing +from collections.abc import Iterable from pathlib import Path from mpi4py import MPI as _MPI @@ -26,7 +27,7 @@ __all__ = ["VTKFile", "XDMFFile", "cell_perm_gmsh", "cell_perm_vtk", "distribute_entity_data"] -def _extract_cpp_objects(functions: typing.Union[Mesh, Function, typing.Iterable[Function]]): +def _extract_cpp_objects(functions: typing.Union[Function, Iterable[Function]]): """Extract C++ objects""" if not isinstance(functions, Function): return [getattr(u, "_cpp_object", u) for u in functions] @@ -86,7 +87,7 @@ def __init__( dtype = output.geometry.x.dtype elif isinstance(output, Function): dtype = output.function_space.mesh.geometry.x.dtype - elif isinstance(output, typing.Iterable): + elif isinstance(output, Iterable): dtype = next(output).function_space.mesh.geometry.x.dtype # type: ignore else: raise RuntimeError(f"Can not write type {type(output)}.") From 343d337cd8cf3fda248d1de53ea0f4b57be39a36 Mon Sep 17 00:00:00 2001 From: schnellerhase <56360279+schnellerhase@users.noreply.github.com> Date: Thu, 10 Jul 2025 20:11:45 +0200 Subject: [PATCH 05/12] Fix forms.py --- python/dolfinx/fem/forms.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/python/dolfinx/fem/forms.py b/python/dolfinx/fem/forms.py index c5d039f0b8b..b058f337d79 100644 --- a/python/dolfinx/fem/forms.py +++ b/python/dolfinx/fem/forms.py @@ -355,10 +355,9 @@ def _form(form): # Subdomain ids can be strings, its or tuples with # strings and ints if integral.subdomain_id() != "everywhere": - try: + if not isinstance(integral, ufl.integral.Integral): ids = [sid for sid in integral.subdomain_id() if sid != "everywhere"] - except TypeError: - # If not tuple, but single integer id + else: ids = [integral.subdomain_id()] else: ids = [] From 0d5c897c7c8b8297dafde2ff2d8a01d676e59ac3 Mon Sep 17 00:00:00 2001 From: schnellerhase <56360279+schnellerhase@users.noreply.github.com> Date: Thu, 10 Jul 2025 20:18:08 +0200 Subject: [PATCH 06/12] Fix bcs.py --- python/dolfinx/fem/bcs.py | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/python/dolfinx/fem/bcs.py b/python/dolfinx/fem/bcs.py index 2a6f55efd8b..a3510ac4030 100644 --- a/python/dolfinx/fem/bcs.py +++ b/python/dolfinx/fem/bcs.py @@ -11,16 +11,14 @@ import numbers import typing - -import numpy.typing as npt - -if typing.TYPE_CHECKING: - from dolfinx.fem.function import Constant, Function +from collections.abc import Iterable import numpy as np +import numpy.typing as npt import dolfinx from dolfinx import cpp as _cpp +from dolfinx.fem.function import Constant, Function def locate_dofs_geometrical( @@ -48,11 +46,11 @@ def locate_dofs_geometrical( Returned degree-of-freedom indices are unique and ordered by the first column. """ - try: + if not isinstance(V, Iterable): return _cpp.fem.locate_dofs_geometrical(V._cpp_object, marker) # type: ignore - except AttributeError: - _V = [space._cpp_object for space in V] # type: ignore - return _cpp.fem.locate_dofs_geometrical(_V, marker) + + _V = [space._cpp_object for space in V] # type: ignore + return _cpp.fem.locate_dofs_geometrical(_V, marker) def locate_dofs_topological( @@ -84,11 +82,11 @@ def locate_dofs_topological( first column. """ _entities = np.asarray(entities, dtype=np.int32) - try: + if not isinstance(V, Iterable): return _cpp.fem.locate_dofs_topological(V._cpp_object, entity_dim, _entities, remote) # type: ignore - except AttributeError: - _V = [space._cpp_object for space in V] # type: ignore - return _cpp.fem.locate_dofs_topological(_V, entity_dim, _entities, remote) + + _V = [space._cpp_object for space in V] # type: ignore + return _cpp.fem.locate_dofs_topological(_V, entity_dim, _entities, remote) class DirichletBC: @@ -221,17 +219,16 @@ def dirichletbc( # Unwrap value object, if required if isinstance(value, np.ndarray): _value = value + elif isinstance(value, (Function, Constant)): + _value = value._cpp_object # type: ignore else: - try: - _value = value._cpp_object # type: ignore - except AttributeError: - _value = value # type: ignore + raise ValueError(f"Unsupported value tpye {type(value)}.") if V is not None: - try: - bc = bctype(_value, dofs, V) - except TypeError: + if isinstance(V, dolfinx.fem.FunctionSpace): bc = bctype(_value, dofs, V._cpp_object) + else: + bc = bctype(_value, dofs, V) else: bc = bctype(_value, dofs) From ef26002eb0f4a0038eceaecce6c6de9b98255a3b Mon Sep 17 00:00:00 2001 From: schnellerhase <56360279+schnellerhase@users.noreply.github.com> Date: Thu, 10 Jul 2025 20:35:30 +0200 Subject: [PATCH 07/12] Fix --- python/dolfinx/io/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/dolfinx/io/utils.py b/python/dolfinx/io/utils.py index ea62f63cf62..bd761925c75 100644 --- a/python/dolfinx/io/utils.py +++ b/python/dolfinx/io/utils.py @@ -88,7 +88,7 @@ def __init__( elif isinstance(output, Function): dtype = output.function_space.mesh.geometry.x.dtype elif isinstance(output, Iterable): - dtype = next(output).function_space.mesh.geometry.x.dtype # type: ignore + dtype = next(iter(output)).function_space.mesh.geometry.x.dtype # type: ignore else: raise RuntimeError(f"Can not write type {type(output)}.") From 9b80fc6b272cfdf7983f716e4229b138b58920e5 Mon Sep 17 00:00:00 2001 From: schnellerhase <56360279+schnellerhase@users.noreply.github.com> Date: Thu, 10 Jul 2025 20:46:23 +0200 Subject: [PATCH 08/12] Fix mesh --- python/dolfinx/mesh.py | 46 +++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/python/dolfinx/mesh.py b/python/dolfinx/mesh.py index 5afe5c87803..9c934abc85c 100644 --- a/python/dolfinx/mesh.py +++ b/python/dolfinx/mesh.py @@ -634,7 +634,7 @@ def create_mesh( gdim = x.shape[1] dtype = None - try: + if isinstance(e, ufl.domain.Mesh): # e is a UFL domain e_ufl = e.ufl_coordinate_element() # type: ignore cmap = _coordinate_element(e_ufl.basix_element) # type: ignore @@ -642,28 +642,28 @@ def create_mesh( dtype = cmap.dtype # TODO: Resolve UFL vs Basix geometric dimension issue # assert domain.geometric_dimension() == gdim - except AttributeError: - try: - # e is a Basix 'UFL' element - cmap = _coordinate_element(e.basix_element) # type: ignore - domain = ufl.Mesh(e) - dtype = cmap.dtype - assert domain.geometric_dimension() == gdim - except AttributeError: - try: - # e is a Basix element - # TODO: Resolve geometric dimension vs shape for manifolds - cmap = _coordinate_element(e) # type: ignore - e_ufl = basix.ufl._BasixElement(e) # type: ignore - e_ufl = basix.ufl.blocked_element(e_ufl, shape=(gdim,)) - domain = ufl.Mesh(e_ufl) - dtype = cmap.dtype - assert domain.geometric_dimension() == gdim - except (AttributeError, TypeError): - # e is a CoordinateElement - cmap = e - domain = None - dtype = cmap.dtype # type: ignore + elif isinstance(e, basix.finite_element.FiniteElement): + # e is a Basix element + # TODO: Resolve geometric dimension vs shape for manifolds + cmap = _coordinate_element(e) # type: ignore + e_ufl = basix.ufl._BasixElement(e) # type: ignore + e_ufl = basix.ufl.blocked_element(e_ufl, shape=(gdim,)) + domain = ufl.Mesh(e_ufl) + dtype = cmap.dtype + assert domain.geometric_dimension() == gdim + elif isinstance(e, ufl.finiteelement.AbstractFiniteElement): + # e is a Basix 'UFL' element + cmap = _coordinate_element(e.basix_element) # type: ignore + domain = ufl.Mesh(e) + dtype = cmap.dtype + assert domain.geometric_dimension() == gdim + elif isinstance(e, _CoordinateElement): + # e is a CoordinateElement + cmap = e + domain = None + dtype = cmap.dtype # type: ignore + else: + raise ValueError(f"Unsupported element type {type(e)}.") x = np.asarray(x, dtype=dtype, order="C") cells = np.asarray(cells, dtype=np.int64, order="C") From 15d46350262457a71353953fb6ec43e2b26f3239 Mon Sep 17 00:00:00 2001 From: schnellerhase <56360279+schnellerhase@users.noreply.github.com> Date: Thu, 10 Jul 2025 21:01:06 +0200 Subject: [PATCH 09/12] Fix write adios2 --- python/dolfinx/io/utils.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/python/dolfinx/io/utils.py b/python/dolfinx/io/utils.py index bd761925c75..a4c5ba87670 100644 --- a/python/dolfinx/io/utils.py +++ b/python/dolfinx/io/utils.py @@ -29,7 +29,7 @@ def _extract_cpp_objects(functions: typing.Union[Function, Iterable[Function]]): """Extract C++ objects""" - if not isinstance(functions, Function): + if not isinstance(functions, (Function, _cpp.fem.Function_float32, _cpp.fem.Function_float64)): return [getattr(u, "_cpp_object", u) for u in functions] else: return [getattr(functions, "_cpp_object", functions)] @@ -85,7 +85,9 @@ def __init__( if isinstance(output, Mesh): dtype = output.geometry.x.dtype - elif isinstance(output, Function): + elif isinstance( + output, (Function, _cpp.fem.Function_float32, _cpp.fem.Function_float64) + ): dtype = output.function_space.mesh.geometry.x.dtype elif isinstance(output, Iterable): dtype = next(iter(output)).function_space.mesh.geometry.x.dtype # type: ignore From 81d8c21e2d3f856793f9c68e71e35dc797bc6e14 Mon Sep 17 00:00:00 2001 From: schnellerhase <56360279+schnellerhase@users.noreply.github.com> Date: Thu, 10 Jul 2025 21:17:05 +0200 Subject: [PATCH 10/12] Add complex --- python/dolfinx/io/utils.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/python/dolfinx/io/utils.py b/python/dolfinx/io/utils.py index a4c5ba87670..a35129f73eb 100644 --- a/python/dolfinx/io/utils.py +++ b/python/dolfinx/io/utils.py @@ -29,7 +29,16 @@ def _extract_cpp_objects(functions: typing.Union[Function, Iterable[Function]]): """Extract C++ objects""" - if not isinstance(functions, (Function, _cpp.fem.Function_float32, _cpp.fem.Function_float64)): + if not isinstance( + functions, + ( + Function, + _cpp.fem.Function_float32, + _cpp.fem.Function_float64, + _cpp.fem.Function_complex64, + _cpp.fem.Function_complex128, + ), + ): return [getattr(u, "_cpp_object", u) for u in functions] else: return [getattr(functions, "_cpp_object", functions)] @@ -86,7 +95,14 @@ def __init__( if isinstance(output, Mesh): dtype = output.geometry.x.dtype elif isinstance( - output, (Function, _cpp.fem.Function_float32, _cpp.fem.Function_float64) + output, + ( + Function, + _cpp.fem.Function_float32, + _cpp.fem.Function_float64, + _cpp.fem.Function_complex64, + _cpp.fem.Function_complex128, + ), ): dtype = output.function_space.mesh.geometry.x.dtype elif isinstance(output, Iterable): From 2488c8a6e13e8bfafd1ef1d1384c74d1e238f023 Mon Sep 17 00:00:00 2001 From: schnellerhase <56360279+schnellerhase@users.noreply.github.com> Date: Mon, 21 Jul 2025 20:15:15 +0200 Subject: [PATCH 11/12] Fix import --- python/demo/demo_navier-stokes.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/demo/demo_navier-stokes.py b/python/demo/demo_navier-stokes.py index 440f3748b77..944f0541350 100644 --- a/python/demo/demo_navier-stokes.py +++ b/python/demo/demo_navier-stokes.py @@ -174,7 +174,7 @@ import numpy as np import ufl -from dolfinx import default_real_type, fem, io, mesh +from dolfinx import default_real_type, fem, has_adios2, io, mesh from dolfinx.fem.petsc import LinearProblem if np.issubdtype(PETSc.ScalarType, np.complexfloating): @@ -351,7 +351,7 @@ def jump(phi, n): # Write initial condition to file t = 0.0 -if dolfinx.has_adios2: +if has_adios2: u_file = io.VTXWriter(msh.comm, "u.bp", u_vis) p_file = io.VTXWriter(msh.comm, "p.bp", p_h) u_file.write(t) From a50ebe42378d299ffb42bafdaf96b468e36bbfa7 Mon Sep 17 00:00:00 2001 From: schnellerhase <56360279+schnellerhase@users.noreply.github.com> Date: Mon, 21 Jul 2025 20:19:32 +0200 Subject: [PATCH 12/12] Trigger CI