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 b99425e8333..c3072297152 100644 --- a/python/demo/demo_mixed-poisson.py +++ b/python/demo/demo_mixed-poisson.py @@ -354,12 +354,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 diff --git a/python/dolfinx/fem/bcs.py b/python/dolfinx/fem/bcs.py index 182ec38892e..a3510ac4030 100644 --- a/python/dolfinx/fem/bcs.py +++ b/python/dolfinx/fem/bcs.py @@ -47,9 +47,9 @@ def locate_dofs_geometrical( first column. """ if not isinstance(V, Iterable): - return _cpp.fem.locate_dofs_geometrical(V._cpp_object, marker) + return _cpp.fem.locate_dofs_geometrical(V._cpp_object, marker) # type: ignore - _V = [space._cpp_object for space in V] + _V = [space._cpp_object for space in V] # type: ignore return _cpp.fem.locate_dofs_geometrical(_V, marker) @@ -83,9 +83,9 @@ def locate_dofs_topological( """ _entities = np.asarray(entities, dtype=np.int32) if not isinstance(V, Iterable): - return _cpp.fem.locate_dofs_topological(V._cpp_object, entity_dim, _entities, remote) + return _cpp.fem.locate_dofs_topological(V._cpp_object, entity_dim, _entities, remote) # type: ignore - _V = [space._cpp_object for space in V] + _V = [space._cpp_object for space in V] # type: ignore return _cpp.fem.locate_dofs_topological(_V, entity_dim, _entities, remote) @@ -219,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 - except AttributeError: - _value = value # type: ignore[assignment] + 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) diff --git a/python/dolfinx/fem/forms.py b/python/dolfinx/fem/forms.py index 01f80325352..681d460072e 100644 --- a/python/dolfinx/fem/forms.py +++ b/python/dolfinx/fem/forms.py @@ -358,10 +358,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 = [] 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) diff --git a/python/dolfinx/io/utils.py b/python/dolfinx/io/utils.py index 79a38c0e543..a35129f73eb 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,9 +27,18 @@ __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[Function, Iterable[Function]]): """Extract C++ objects""" - if isinstance(functions, (list, tuple)): + 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)] @@ -56,7 +66,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 +91,36 @@ 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, + _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): + dtype = next(iter(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 diff --git a/python/dolfinx/mesh.py b/python/dolfinx/mesh.py index a48ca5276f3..be0c5e121eb 100644 --- a/python/dolfinx/mesh.py +++ b/python/dolfinx/mesh.py @@ -633,7 +633,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 @@ -641,28 +641,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")