Skip to content

Switch from EAFP to LBYL #3794

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions python/demo/demo_hdg.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")


Expand Down
6 changes: 3 additions & 3 deletions python/demo/demo_interpolation-io.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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")


Expand Down
4 changes: 2 additions & 2 deletions python/demo/demo_mixed-poisson.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.")
# -
4 changes: 2 additions & 2 deletions python/demo/demo_navier-stokes.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
21 changes: 10 additions & 11 deletions python/dolfinx/fem/bcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)


Expand Down Expand Up @@ -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)


Expand Down Expand Up @@ -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)

Expand Down
5 changes: 2 additions & 3 deletions python/dolfinx/fem/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 = []
Expand Down
21 changes: 9 additions & 12 deletions python/dolfinx/fem/function.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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():
Expand All @@ -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)

Expand Down
51 changes: 35 additions & 16 deletions python/dolfinx/io/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)]
Expand Down Expand Up @@ -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,
):
Expand All @@ -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
Expand Down
46 changes: 23 additions & 23 deletions python/dolfinx/mesh.py
Original file line number Diff line number Diff line change
Expand Up @@ -633,36 +633,36 @@ 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
domain = e
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")
Expand Down
Loading