diff --git a/examples/multiple-meshes.py b/examples/multiple-meshes.py index aea174aa..1b977d29 100644 --- a/examples/multiple-meshes.py +++ b/examples/multiple-meshes.py @@ -1,13 +1,13 @@ import sys -import numpy as np # noqa +import numpy as np order = 4 def main(): - from meshmode.mesh.generation import make_curve_mesh, starfish # noqa + from meshmode.mesh.generation import make_curve_mesh, starfish mesh1 = make_curve_mesh(starfish, np.linspace(0, 1, 20), 4) from meshmode.mesh.processing import affine_map, merge_disjoint_meshes diff --git a/examples/simple-dg.py b/examples/simple-dg.py index 42fc87de..138b7d65 100644 --- a/examples/simple-dg.py +++ b/examples/simple-dg.py @@ -402,7 +402,7 @@ def wave_operator(actx, discr, c, q): u=c*discr.div(q.v), v=c*discr.grad(q.u) ) - - # noqa: W504 + - discr.inverse_mass( discr.face_mass( wave_flux(actx, discr, c=c, diff --git a/meshmode/array_context.py b/meshmode/array_context.py index 8b749e8d..fbd8e25d 100644 --- a/meshmode/array_context.py +++ b/meshmode/array_context.py @@ -25,7 +25,6 @@ THE SOFTWARE. """ -import sys from warnings import warn from arraycontext import ( @@ -326,27 +325,19 @@ def actx_class(self): ) -if sys.version_info >= (3, 7): - def __getattr__(name): - if name not in _actx_names: - raise AttributeError(name) +def __getattr__(name): + if name not in _actx_names: + raise AttributeError(name) - import arraycontext - result = getattr(arraycontext, name) + import arraycontext + result = getattr(arraycontext, name) - warn(f"meshmode.array_context.{name} is deprecated. " - f"Use arraycontext.{name} instead. " - f"meshmode.array_context.{name} will continue to work until 2022.", - DeprecationWarning, stacklevel=2) + warn(f"meshmode.array_context.{name} is deprecated. " + f"Use arraycontext.{name} instead. " + f"meshmode.array_context.{name} will continue to work until 2022.", + DeprecationWarning, stacklevel=2) - return result -else: - def _import_names(): - import arraycontext - for name in _actx_names: - globals()[name] = getattr(arraycontext, name) - - _import_names() + return result # }}} diff --git a/meshmode/discretization/connection/__init__.py b/meshmode/discretization/connection/__init__.py index 2d08e574..fe3ac157 100644 --- a/meshmode/discretization/connection/__init__.py +++ b/meshmode/discretization/connection/__init__.py @@ -63,26 +63,25 @@ __all__ = [ - "DiscretizationConnection", - "IdentityDiscretizationConnection", - "DirectDiscretizationConnection", - "ChainedDiscretizationConnection", - "L2ProjectionInverseDiscretizationConnection", - "NodalToModalDiscretizationConnection", - "ModalToNodalDiscretizationConnection", - - "make_same_mesh_connection", - "FACE_RESTR_INTERIOR", "FACE_RESTR_ALL", - "make_face_restriction", - "make_face_to_all_faces_embedding", - "make_opposite_face_connection", - "make_partition_connection", - "make_refinement_connection", - "flatten_chained_connection", - - "InterpolationBatch", - "DiscretizationConnectionElementGroup", - ] + "FACE_RESTR_ALL", + "FACE_RESTR_INTERIOR", + "ChainedDiscretizationConnection", + "DirectDiscretizationConnection", + "DiscretizationConnection", + "DiscretizationConnectionElementGroup", + "IdentityDiscretizationConnection", + "InterpolationBatch", + "L2ProjectionInverseDiscretizationConnection", + "ModalToNodalDiscretizationConnection", + "NodalToModalDiscretizationConnection", + "flatten_chained_connection", + "make_face_restriction", + "make_face_to_all_faces_embedding", + "make_opposite_face_connection", + "make_partition_connection", + "make_refinement_connection", + "make_same_mesh_connection", +] __doc__ = """ Base classes diff --git a/meshmode/discretization/connection/direct.py b/meshmode/discretization/connection/direct.py index ffc3d153..06d00dd8 100644 --- a/meshmode/discretization/connection/direct.py +++ b/meshmode/discretization/connection/direct.py @@ -525,7 +525,7 @@ def _per_target_group_pick_info( if (from_el_indices[to_el_ind] != -1).any(): from warnings import warn warn("per-batch target elements not disjoint during " - "attempted merge") + "attempted merge", stacklevel=3) return None from_el_indices[to_el_ind] = \ @@ -927,7 +927,7 @@ def knl(): from_group_sizes = [ grp.nelements*grp.nunit_dofs for grp in conn.from_discr.groups] - from_group_starts = np.cumsum([0] + from_group_sizes) + from_group_starts = np.cumsum([0, *from_group_sizes]) tgt_node_nr_base = 0 mats = [] diff --git a/meshmode/discretization/connection/face.py b/meshmode/discretization/connection/face.py index c446e261..3b7705de 100644 --- a/meshmode/discretization/connection/face.py +++ b/meshmode/discretization/connection/face.py @@ -323,11 +323,11 @@ def make_face_restriction(actx, discr, group_factory, boundary_tag, # Find vertex_indices glob_face_vertices = mgrp.vertex_indices[ batch_boundary_el_numbers_in_grp][:, face.volume_vertex_indices] - vertex_indices[new_el_numbers] = ( # pylint: disable=possibly-used-before-assignment # noqa: E501 + vertex_indices[new_el_numbers] = ( # pylint: disable=possibly-used-before-assignment vol_to_bdry_vertices[glob_face_vertices]) # Find nodes - nodes[:, new_el_numbers, :] = np.einsum( # pylint: disable=possibly-used-before-assignment # noqa: E501 + nodes[:, new_el_numbers, :] = np.einsum( # pylint: disable=possibly-used-before-assignment "ij,dej->dei", resampling_mat, mgrp.nodes[:, batch_boundary_el_numbers_in_grp, :]) diff --git a/meshmode/discretization/connection/opposite_face.py b/meshmode/discretization/connection/opposite_face.py index 7e4455a3..048397a6 100644 --- a/meshmode/discretization/connection/opposite_face.py +++ b/meshmode/discretization/connection/opposite_face.py @@ -198,10 +198,12 @@ def get_map_jacobian(unit_nodes): # {{{ test map applier and jacobian if 0: + rng = np.random.default_rng(seed=None) + u = src_unit_nodes f = apply_map(u) for h in [1e-1, 1e-2]: - du = h*np.random.randn(*u.shape) + du = h*rng.normal(size=u.shape) f_2 = apply_map(u+du) diff --git a/meshmode/discretization/poly_element.py b/meshmode/discretization/poly_element.py index 2d020bbb..da6ec2b8 100644 --- a/meshmode/discretization/poly_element.py +++ b/meshmode/discretization/poly_element.py @@ -983,7 +983,8 @@ def default_simplex_group_factory(base_dim, order): elif base_dim == 3: return PolynomialWarpAndBlend3DRestrictingGroupFactory(order) else: - raise ValueError(f"no usable set of nodes found for {base_dim}D") + raise ValueError( + f"no usable set of nodes found for {base_dim}D") from None return PolynomialRecursiveNodesGroupFactory(order, family="lgl") diff --git a/meshmode/discretization/visualization.py b/meshmode/discretization/visualization.py index 4d556409..4a8c8d15 100644 --- a/meshmode/discretization/visualization.py +++ b/meshmode/discretization/visualization.py @@ -588,7 +588,7 @@ def show_scalar_in_mayavi(self, field, **kwargs): nodes.append(0*nodes[0]) assert len(nodes) == 3 - args = tuple(nodes) + (field,) + args = (*nodes, field) # https://docs.enthought.com/mayavi/mayavi/auto/example_plotting_many_lines.html # noqa: E501 src = mlab.pipeline.scalar_scatter(*args) @@ -603,7 +603,7 @@ def show_scalar_in_mayavi(self, field, **kwargs): while len(nodes) < 3: nodes.append(0*nodes[0]) - args = tuple(nodes) + (vis_connectivity.reshape(-1, 3),) + args = (*nodes, vis_connectivity.reshape(-1, 3)) kwargs["scalars"] = field mlab.triangular_mesh(*args, **kwargs) @@ -742,7 +742,7 @@ def write_vtk_file(self, file_name, names_and_fields, - Added *par_manifest_filename* and *par_file_names*. - Added *use_high_order*. - """ # noqa: E501 + """ if use_high_order is None: use_high_order = False diff --git a/meshmode/dof_array.py b/meshmode/dof_array.py index 72184e40..fbd1f3e4 100644 --- a/meshmode/dof_array.py +++ b/meshmode/dof_array.py @@ -28,7 +28,7 @@ from contextlib import contextmanager from functools import partial, update_wrapper from numbers import Number -from typing import Any, Callable, Iterable, Optional, Tuple +from typing import Any, Callable, Iterable from warnings import warn import numpy as np @@ -138,7 +138,7 @@ class DOFArray: the array context given to :func:`array_context_for_pickling`. """ - def __init__(self, actx: Optional[ArrayContext], data: Tuple[Any]) -> None: + def __init__(self, actx: ArrayContext | None, data: tuple[Any, ...]) -> None: if __debug__: if not (actx is None or isinstance(actx, ArrayContext)): raise TypeError("actx must be of type ArrayContext") @@ -162,7 +162,7 @@ def entry_dtype(self) -> np.dtype: return single_valued(subary.dtype for subary in self._data) @classmethod - def from_list(cls, actx: Optional[ArrayContext], res_list) -> "DOFArray": + def from_list(cls, actx: ArrayContext | None, res_list) -> DOFArray: r"""Create a :class:`DOFArray` from a list of arrays (one per :class:`~meshmode.discretization.ElementGroupBase`). @@ -178,10 +178,10 @@ def from_list(cls, actx: Optional[ArrayContext], res_list) -> "DOFArray": return cls(actx, tuple(res_list)) def __str__(self) -> str: - return f"DOFArray({str(self._data)})" + return f"DOFArray({self._data})" def __repr__(self) -> str: - return f"DOFArray({repr(self._data)})" + return f"DOFArray({self._data!r})" # {{{ sequence protocol @@ -207,7 +207,7 @@ def _like_me(self, data: Iterable[Array]) -> DOFArray: return DOFArray(self.array_context, tuple(data)) @property - def shape(self) -> Tuple[int]: + def shape(self) -> tuple[int]: return (len(self),) @property @@ -263,15 +263,15 @@ def _ibop(self, f, arg): return self - def __iadd__(self, arg): return self._ibop(op.iadd, arg) # noqa: E704 - def __isub__(self, arg): return self._ibop(op.isub, arg) # noqa: E704 - def __imul__(self, arg): return self._ibop(op.imul, arg) # noqa: E704 - def __itruediv__(self, arg): return self._ibop(op.itruediv, arg) # noqa: E704 - def __imod__(self, arg): return self._ibop(op.imod, arg) # noqa: E704 + def __iadd__(self, arg): return self._ibop(op.iadd, arg) + def __isub__(self, arg): return self._ibop(op.isub, arg) + def __imul__(self, arg): return self._ibop(op.imul, arg) + def __itruediv__(self, arg): return self._ibop(op.itruediv, arg) + def __imod__(self, arg): return self._ibop(op.imod, arg) - def __iand__(self, arg): return self._ibop(op.iand, arg) # noqa: E704 - def __ixor__(self, arg): return self._ibop(op.ixor, arg) # noqa: E704 - def __ior__(self, arg): return self._ibop(op.ior, arg) # noqa: E704 + def __iand__(self, arg): return self._ibop(op.iand, arg) + def __ixor__(self, arg): return self._ibop(op.ixor, arg) + def __ior__(self, arg): return self._ibop(op.ior, arg) # }}} @@ -327,7 +327,8 @@ def __setstate__(self, state): # For backwards compatibility from warnings import warn warn("A DOFArray is being unpickled without (tag) metadata. " - "Program transformation may fail as a result.") + "Program transformation may fail as a result.", + stacklevel=2) data = state tags = [frozenset() for _ in range(len(data))] @@ -383,7 +384,7 @@ def _serialize_dof_container(ary: DOFArray): @deserialize_container.register(DOFArray) def _deserialize_dof_container( - template: Any, iterable: Iterable[Tuple[Any, Any]]): + template: Any, iterable: Iterable[tuple[Any, Any]]): if __debug__: def _raise_index_inconsistency(i, stream_i): raise ValueError( @@ -586,14 +587,14 @@ def _unflatten_group_sizes(discr, ndofs_per_element_per_group): in zip(discr.groups, ndofs_per_element_per_group)] group_sizes = [nel * ndof for nel, ndof in group_shapes] - group_starts = np.cumsum([0] + group_sizes) + group_starts = np.cumsum([0, *group_sizes]) return group_shapes, group_starts def unflatten( actx: ArrayContext, discr, ary: ArrayOrContainerT, - ndofs_per_element_per_group: Optional[Iterable[int]] = None, *, + ndofs_per_element_per_group: Iterable[int] | None = None, *, strict: bool = True, ) -> ArrayOrContainerT: r"""Convert all "flat" arrays returned by :func:`flatten` back to @@ -668,7 +669,7 @@ def _unflatten_like(_ary, _prototype): if isinstance(_prototype, DOFArray): group_shapes = [subary.shape for subary in _prototype] group_sizes = [subary.size for subary in _prototype] - group_starts = np.cumsum([0] + group_sizes) + group_starts = np.cumsum([0, *group_sizes]) return _unflatten_dof_array( actx, _ary, group_shapes, group_starts, @@ -680,9 +681,11 @@ def _unflatten_like(_ary, _prototype): serialize_container(_prototype)) except NotAnArrayContainerError: if strict: - raise ValueError("cannot unflatten array " - f"with prototype '{type(_prototype).__name__}'; " - "use 'strict=False' to leave the array unchanged") + raise ValueError( + "cannot unflatten array with prototype " + f"'{type(_prototype).__name__}': " + "use 'strict=False' to leave the array unchanged" + ) from None assert type(_ary) is type(_prototype) return _ary @@ -716,7 +719,7 @@ def _flatten_to_numpy(subary): def unflatten_from_numpy( actx: ArrayContext, discr, ary: ArrayOrContainerT, - ndofs_per_element_per_group: Optional[Iterable[int]] = None, *, + ndofs_per_element_per_group: Iterable[int] | None = None, *, strict: bool = True, ) -> ArrayOrContainerT: r"""Takes "flat" arrays returned by :func:`flatten_to_numpy` and @@ -808,7 +811,8 @@ def _rec(_ary): try: iterable = serialize_container(_ary) except NotAnArrayContainerError: - raise TypeError(f"unsupported array type: '{type(_ary).__name__}'") + raise TypeError( + f"unsupported array type: '{type(_ary).__name__}'") from None else: arys = [_rec(subary) for _, subary in iterable] return _reduce_norm(actx, arys, ord=ord) diff --git a/meshmode/interop/firedrake/__init__.py b/meshmode/interop/firedrake/__init__.py index ab34373a..464d9907 100644 --- a/meshmode/interop/firedrake/__init__.py +++ b/meshmode/interop/firedrake/__init__.py @@ -32,7 +32,10 @@ ) -__all__ = ["build_connection_from_firedrake", "build_connection_to_firedrake", - "FiredrakeConnection", "import_firedrake_mesh", - "export_mesh_to_firedrake", - ] +__all__ = [ + "FiredrakeConnection", + "build_connection_from_firedrake", + "build_connection_to_firedrake", + "export_mesh_to_firedrake", + "import_firedrake_mesh", +] diff --git a/meshmode/interop/firedrake/connection.py b/meshmode/interop/firedrake/connection.py index d11ab07d..828434fc 100644 --- a/meshmode/interop/firedrake/connection.py +++ b/meshmode/interop/firedrake/connection.py @@ -314,8 +314,8 @@ def _validate_function(self, function, function_name, raise ValueError(f"'{function_name}.dat.dtype' must be " f"{dtype}, not '{function.dat.data.dtype}'") if shape is not None and function.function_space().shape != shape: - raise ValueError("'{function_name}.function_space().shape' must be" - " {shape}, not '{function.function_space().shape}" + raise ValueError(f"'{function_name}.function_space().shape' must be" + f" {shape}, not '{function.function_space().shape}" "'") def _validate_field(self, field, field_name, shape=None, dtype=None): @@ -375,7 +375,7 @@ def check_dof_array(arr, arr_name): " for FiredrakeConnection.from_meshmode or " \ "FiredrakeConnection.from_firedrake to see how " \ "fields in a discretization are represented." - raise TypeError(prefix + "\n" + msg) + raise TypeError(f"{prefix}\n{msg}") from None else: raise TypeError("'field' must be of type DOFArray or a numpy object " "array of those, not '%s'." % type(field)) @@ -463,13 +463,13 @@ def reorder_and_resample(dof_array, fd_data): else: # firedrake drops extra dimensions if len(function_data.shape) != 1 + len(fspace_shape): - shape = (function_data.shape[0],) + fspace_shape + shape = (function_data.shape[0], *fspace_shape) function_data = function_data.reshape(shape) # otherwise, have to grab each dofarray and the corresponding # data from *function_data* for multi_index in np.ndindex(fspace_shape): dof_array = out[multi_index] - index = (np.s_[:],) + multi_index + index = (np.s_[:], *multi_index) fd_data = function_data[index] reorder_and_resample(dof_array, fd_data) @@ -543,7 +543,7 @@ def from_meshmode(self, mm_field, out=None): out_data = out.dat.data # Handle firedrake dropping dimensions if len(out.dat.data.shape) != 1 + len(fspace_shape): - shape = (out.dat.data.shape[0],) + fspace_shape + shape = (out.dat.data.shape[0], *fspace_shape) out_data = out_data.reshape(shape) def resample_and_reorder(fd_data, dof_array): @@ -566,7 +566,7 @@ def resample_and_reorder(fd_data, dof_array): # data from *function_data* for multi_index in np.ndindex(fspace_shape): # have to be careful to take view and not copy - index = (np.s_[:],) + multi_index + index = (np.s_[:], *multi_index) fd_data = out_data[index] dof_array = mm_field[multi_index] resample_and_reorder(fd_data, dof_array) diff --git a/meshmode/interop/firedrake/mesh.py b/meshmode/interop/firedrake/mesh.py index ada0fff5..e97f3a63 100644 --- a/meshmode/interop/firedrake/mesh.py +++ b/meshmode/interop/firedrake/mesh.py @@ -407,7 +407,7 @@ def _get_firedrake_facial_adjacency_groups(fdrake_mesh_topology, # }}} - return [[interconnectivity_grp] + exterior_grps] + return [[interconnectivity_grp, *exterior_grps]] # }}} @@ -466,7 +466,8 @@ def _get_firedrake_orientations(fdrake_mesh, unflipped_group, vertices, if np.cross(normal, edge) < 0: orient[i] = -1.0 elif no_normals_warn: - warn("Assuming all elements are positively-oriented.") + warn("Assuming all elements are positively-oriented.", + stacklevel=2) elif tdim == 2 and gdim == 3: # In this case we have a 2-surface embedded in 3-space. @@ -646,7 +647,7 @@ def import_firedrake_mesh(fdrake_mesh, cells_to_use=None, nodes = np.real(coords.dat.data[cell_node_list]) # Add extra dim in 1D for shape (nelements, nunit_nodes, dim) if tdim == 1: - nodes = np.reshape(nodes, nodes.shape + (1,)) + nodes = np.reshape(nodes, (*nodes.shape, 1)) # Transpose nodes to have shape (dim, nelements, nunit_nodes) nodes = np.transpose(nodes, (2, 0, 1)) diff --git a/meshmode/interop/firedrake/reference_cell.py b/meshmode/interop/firedrake/reference_cell.py index b060434d..aa25f1ce 100644 --- a/meshmode/interop/firedrake/reference_cell.py +++ b/meshmode/interop/firedrake/reference_cell.py @@ -82,7 +82,7 @@ def get_affine_reference_simplex_mapping(ambient_dim, firedrake_to_meshmode=True # Compute matrix A and vector b so that A f_i + b -> t_i # for each "from" vertex f_i and corresponding "to" vertex t_i assert from_verts.shape == to_verts.shape - dim, nvects = from_verts.shape + _dim, nvects = from_verts.shape # If we only have one vertex, have A = I and b = to_vert - from_vert if nvects == 1: @@ -142,8 +142,8 @@ def get_finat_element_unit_nodes(finat_element): GaussLobattoLegendre, GaussLegendre) if not isinstance(finat_element, allowed_finat_elts): raise TypeError("'finat_element' is of unexpected type " - f"{type(finat_element)}. 'finat_element' must be of " - "one of the following types: {allowed_finat_elts}") + f"{type(finat_element).__name__}. 'finat_element' must be of " + f"one of the following types: {allowed_finat_elts}") if not isinstance(finat_element.cell, Simplex): raise TypeError("Reference element of the finat element MUST be a" " simplex, i.e. 'finat_element's *cell* attribute must" diff --git a/meshmode/interop/nodal_dg.py b/meshmode/interop/nodal_dg.py index 0891443d..95fa79e5 100644 --- a/meshmode/interop/nodal_dg.py +++ b/meshmode/interop/nodal_dg.py @@ -83,8 +83,8 @@ def __exit__(self, exc_type, exc_val, exc_tb): self.octave.exit() - REF_AXES = ["r", "s", "t"] - AXES = ["x", "y", "z"] + REF_AXES = ("r", "s", "t") + AXES = ("x", "y", "z") def set_mesh(self, mesh: meshmode.mesh.Mesh, order): """Set the mesh information in the nodal DG Octave instance to @@ -132,7 +132,7 @@ def get_discr(self, actx) -> meshmode.discretization.Discretization: f"Nodes{dim}D(N)", nout=dim, verbose=False) equilat_to_unit_func_name = ( - "".join(self.AXES[:dim] + ["to"] + self.REF_AXES[:dim])) + "".join(self.AXES[:dim] + ("to",) + self.REF_AXES[:dim])) unit_nodes_arrays = self.octave.feval( equilat_to_unit_func_name, *unit_nodes_arrays, diff --git a/meshmode/mesh/__init__.py b/meshmode/mesh/__init__.py index eb4f6e7a..7218d943 100644 --- a/meshmode/mesh/__init__.py +++ b/meshmode/mesh/__init__.py @@ -1561,7 +1561,7 @@ def _compute_nodal_adjacency_from_vertices(mesh): lengths = [len(el_list) for el_list in element_to_element] neighbors_starts = np.cumsum( - np.array([0] + lengths, dtype=mesh.element_id_dtype)) + np.array([0, *lengths], dtype=mesh.element_id_dtype)) from pytools import flatten neighbors = np.array( list(flatten(element_to_element)), @@ -1818,12 +1818,12 @@ def _merge_boundary_adjacency_groups( elements=np.empty((0,), dtype=element_id_dtype), element_faces=np.empty((0,), dtype=face_id_dtype)) - max_ielem = max([ + max_ielem = max( np.max(grp.elements, initial=0) - for grp in bdry_grps]) - max_iface = max([ + for grp in bdry_grps) + max_iface = max( np.max(grp.element_faces, initial=0) - for grp in bdry_grps]) + for grp in bdry_grps) face_has_adj = np.full((max_iface+1, max_ielem+1), False) @@ -2065,10 +2065,10 @@ def check_bc_coverage(mesh, boundary_tags, incomplete_ok=False, else: all_btag = BTAG_REALLY_ALL - all_bdry_grp, = [ + all_bdry_grp, = ( fagrp for fagrp in fagrp_list if isinstance(fagrp, BoundaryAdjacencyGroup) - and fagrp.boundary_tag == all_btag] + and fagrp.boundary_tag == all_btag) matching_bdry_grps = [ fagrp for fagrp in fagrp_list @@ -2111,10 +2111,10 @@ def is_boundary_tag_empty(mesh, boundary_tag): raise ValueError(f"invalid boundary tag {boundary_tag}.") for igrp in range(len(mesh.groups)): - nfaces = sum([ + nfaces = sum( len(grp.elements) for grp in mesh.facial_adjacency_groups[igrp] if isinstance(grp, BoundaryAdjacencyGroup) - and grp.boundary_tag == boundary_tag]) + and grp.boundary_tag == boundary_tag) if nfaces > 0: return False diff --git a/meshmode/mesh/generation.py b/meshmode/mesh/generation.py index b9e207c4..323fa66e 100644 --- a/meshmode/mesh/generation.py +++ b/meshmode/mesh/generation.py @@ -154,7 +154,7 @@ def n_gon(n_corners: int, t: np.ndarray) -> np.ndarray: t = t*n_corners - result = np.empty((2,)+t.shape) + result = np.empty((2, *t.shape)) for side in range(n_corners): indices = np.where((side <= t) & (t < side+1)) @@ -256,7 +256,7 @@ def rotation_matrix(angle: float) -> np.ndarray: # NOTE: Split [0, 1] interval into 5 chunks that have about equal arclength. # This is possible because each chunk is a circle arc, so we know its length. - L = ( # noqa: N806 + L = ( inv_gap * r_major + inv_gap * r_minor + 2 * np.pi * r_cap) @@ -274,7 +274,7 @@ def rotation_matrix(angle: float) -> np.ndarray: # first cap m_caps0 = np.logical_and(t >= t1, t < t2).astype(t.dtype) theta = m_caps0 * (np.pi / 2 + np.pi * (t - (t2 + t1) / 2) / (t2 - t1)) - R = r_cap * rotation_matrix(-gap) # noqa: N806 + R = r_cap * rotation_matrix(-gap) f_caps0 = R @ np.stack([ np.cos(theta) - 1, np.sin(theta) ]) + r_major * np.stack([[np.cos(-gap), np.sin(-gap)]]).T @@ -287,7 +287,7 @@ def rotation_matrix(angle: float) -> np.ndarray: # second cap m_caps1 = (t >= t3).astype(t.dtype) theta = m_caps1 * (np.pi / 2 + np.pi * (t - (t3 + t4) / 2) / (t4 - t3)) - R = r_cap * rotation_matrix(np.pi + gap) # noqa: N806 + R = r_cap * rotation_matrix(np.pi + gap) f_caps1 = R @ np.stack([ np.cos(theta) + 1, np.sin(theta) ]) + r_major * np.stack([[np.cos(gap), np.sin(gap)]]).T @@ -1150,7 +1150,7 @@ def generate_box_mesh( vertex_indices = np.arange(nvertices).reshape(*shape) - vertices = np.empty((dim,)+shape, dtype=coord_dtype) + vertices = np.empty((dim, *shape), dtype=coord_dtype) for idim in range(dim): vshape = (shape[idim],) + (1,)*(dim-1-idim) vertices[idim] = axis_coords[idim].reshape(*vshape) @@ -1200,7 +1200,7 @@ def generate_box_mesh( nvertices + np.arange(nmidpoints).reshape(*shape_m1, order="F")) - midpoints = np.empty((dim,)+shape_m1, dtype=coord_dtype) + midpoints = np.empty((dim, *shape_m1), dtype=coord_dtype) for idim in range(dim): vshape = (shape_m1[idim],) + (1,)*(1-idim) left_axis_coords = axis_coords[idim][:-1] @@ -1659,8 +1659,6 @@ def warp_and_refine_until_resolved( raise TypeError( f"Unsupported element group type: '{type(egrp).__name__}'") - dim, _ = egrp.unit_nodes.shape - interp_err_est_mat = simplex_interp_error_coefficient_estimator_matrix( egrp.unit_nodes, egrp.order, n_tail_orders=1 if warped_mesh.dim > 1 else 2) diff --git a/meshmode/mesh/io.py b/meshmode/mesh/io.py index 77dc1836..f3d3a326 100644 --- a/meshmode/mesh/io.py +++ b/meshmode/mesh/io.py @@ -350,10 +350,10 @@ def generate_gmsh(source, dimensions=None, order=None, other_options=None, for idim in range(dim): if (mesh.vertices[idim] == 0).all(): from warnings import warn - warn("all vertices' %s coordinate is zero--perhaps you want to pass " - "force_ambient_dim=%d (pass any fixed value to " - "force_ambient_dim to silence this warning)" % ( - AXIS_NAMES[idim], idim)) + warn(f"all vertices' {AXIS_NAMES[idim]} coordinate is zero -- " + f"perhaps you want to pass force_ambient_dim={idim} (pass " + "any fixed value to force_ambient_dim to silence this warning)", + stacklevel=2) break return result diff --git a/meshmode/mesh/processing.py b/meshmode/mesh/processing.py index 45ab7557..1c23fbc0 100644 --- a/meshmode/mesh/processing.py +++ b/meshmode/mesh/processing.py @@ -1438,12 +1438,12 @@ def map_mesh(mesh: Mesh, f: Callable[[np.ndarray], np.ndarray]) -> Mesh: def affine_map( mesh: Mesh, - A: Optional[Union[np.generic, np.ndarray]] = None, # noqa: N803 + A: Optional[Union[np.generic, np.ndarray]] = None, b: Optional[Union[np.generic, np.ndarray]] = None) -> Mesh: """Apply the affine map :math:`f(x) = A x + b` to the geometry of *mesh*.""" if A is not None and not isinstance(A, np.ndarray): - A = np.diag([A] * mesh.ambient_dim) # noqa: N806 + A = np.diag([A] * mesh.ambient_dim) if b is not None and not isinstance(b, np.ndarray): b = np.array([b] * mesh.ambient_dim) diff --git a/meshmode/mesh/tools.py b/meshmode/mesh/tools.py index 1b718e0c..aba0f0ad 100644 --- a/meshmode/mesh/tools.py +++ b/meshmode/mesh/tools.py @@ -70,7 +70,7 @@ def make_element_lookup_tree(mesh, eps=1e-12): # {{{ random rotation matrix -def rand_rotation_matrix(ambient_dim, deflection=1.0, randnums=None): +def rand_rotation_matrix(ambient_dim, deflection=1.0, randnums=None, rng=None): """Creates a random rotation matrix. :arg deflection: the magnitude of the rotation. For 0, no rotation; for 1, @@ -85,7 +85,10 @@ def rand_rotation_matrix(ambient_dim, deflection=1.0, randnums=None): raise NotImplementedError("ambient_dim=%d" % ambient_dim) if randnums is None: - randnums = np.random.uniform(size=(3,)) + if rng is None: + rng = np.random.default_rng() + + randnums = rng.uniform(size=(3,)) theta, phi, z = randnums @@ -100,7 +103,7 @@ def rand_rotation_matrix(ambient_dim, deflection=1.0, randnums=None): # has length sqrt(2) to eliminate the 2 in the Householder matrix. r = np.sqrt(z) - V = ( # noqa: N806 + V = ( np.sin(phi) * r, np.cos(phi) * r, np.sqrt(2.0 - z) @@ -109,11 +112,11 @@ def rand_rotation_matrix(ambient_dim, deflection=1.0, randnums=None): st = np.sin(theta) ct = np.cos(theta) - R = np.array(((ct, st, 0), (-st, ct, 0), (0, 0, 1))) # noqa: N806 + R = np.array(((ct, st, 0), (-st, ct, 0), (0, 0, 1))) # Construct the rotation matrix ( V Transpose(V) - I ) R. - M = (np.outer(V, V) - np.eye(3)).dot(R) # noqa: N806 + M = (np.outer(V, V) - np.eye(3)).dot(R) return M # }}} diff --git a/meshmode/mesh/visualization.py b/meshmode/mesh/visualization.py index 49091c9f..4f9d184f 100644 --- a/meshmode/mesh/visualization.py +++ b/meshmode/mesh/visualization.py @@ -45,6 +45,7 @@ def draw_2d_mesh( mesh: Mesh, *, + rng: Optional[np.random.Generator] = None, draw_vertex_numbers: bool = True, draw_element_numbers: bool = True, draw_nodal_adjacency: bool = False, @@ -59,6 +60,9 @@ def draw_2d_mesh( """ assert mesh.ambient_dim == 2 + if rng is None: + rng = np.random.default_rng() + import matplotlib.patches as mpatches import matplotlib.pyplot as pt from matplotlib.path import Path @@ -135,8 +139,8 @@ def global_iel_to_group_and_iel(global_iel): start = centroid + 0.15*dx mag = np.max(np.abs(dx)) - start += 0.05*(np.random.rand(2)-0.5)*mag - dx += 0.05*(np.random.rand(2)-0.5)*mag + start += 0.05*(rng.random(2)-0.5)*mag + dx += 0.05*(rng.random(2)-0.5)*mag pt.arrow(start[0], start[1], 0.7*dx[0], 0.7*dx[1], length_includes_head=True, @@ -242,7 +246,7 @@ def write_vertex_vtk_file( }[egrp.dim] else: raise NotImplementedError("mesh vtk file writing for " - "element group of type '%s'" % type(egrp).__name__) + f"element group of type '{type(egrp).__name__}'") cell_types[base_element_nr:base_element_nr + egrp.nelements] = vtk_cell_type @@ -290,7 +294,7 @@ def write_vertex_vtk_file( if overwrite: os.remove(file_name) else: - raise FileExistsError("output file '%s' already exists" % file_name) + raise FileExistsError(f"output file '{file_name}' already exists") with open(file_name, "w") as outf: AppendedDataXMLGenerator(compressor)(grid).write(outf) @@ -317,12 +321,11 @@ def mesh_to_tikz(mesh: Mesh) -> str: centroid = np.average(elverts, axis=1) lines.append(r"\coordinate (cent%d) at (%s);" - % (el_nr, - ", ".join("%.5f" % (vi) for vi in centroid))) + % (el_nr, ", ".join(f"{vi:.5f}" for vi in centroid))) for ivert, vert in enumerate(elverts.T): lines.append(r"\coordinate (v%d-%d) at (%s);" - % (el_nr, ivert+1, ", ".join("%.5f" % vi for vi in vert))) + % (el_nr, ivert+1, ", ".join(f"{vi:.5f}" for vi in vert))) drawel_lines.append( r"\draw [#1] %s -- cycle;" % " -- ".join( diff --git a/pyproject.toml b/pyproject.toml index 5e17361a..6f03b227 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -67,8 +67,47 @@ include = [ "meshmode*", ] -[tool.isort] -known_firstparty = [ +[tool.ruff] +preview = true + +[tool.ruff.lint] +extend-select = [ + "B", # flake8-bugbear + "C", # flake8-comprehensions + "E", # pycodestyle + "F", # pyflakes + "G", # flake8-logging-format + "I", # flake8-isort + "N", # pep8-naming + "NPY", # numpy + "Q", # flake8-quotes + "RUF", # ruff + "UP", # pyupgrade + "W", # pycodestyle +] +extend-ignore = [ + "C90", # McCabe complexity + "E226", # missing whitespace around arithmetic operator + "E241", # multiple spaces after comma + "E242", # tab after comma + "E265", # comment should have a space + "E402", # module level import not at the top of file + "N802", # function name should be lowercase + "N803", # argument name should be lowercase + "N806", # variable name should be lowercase + "N818", # error suffix in exception names + "UP031", # use f-strings instead of % format + "UP032", # use f-strings instead of .format +] + +[tool.ruff.lint.flake8-quotes] +docstring-quotes = "double" +inline-quotes = "double" +multiline-quotes = "double" + +[tool.ruff.lint.isort] +combine-as-imports = true +known-first-party = [ "pytools", "pyopencl", "loopy", @@ -81,11 +120,10 @@ known_firstparty = [ "pymetis", "firedrake", ] -known_local_folder = [ "meshmode" ] -line_length = 85 -lines_after_imports = 2 -combine_as_imports = true -multi_line_output = 4 +known-local-folder = [ + "meshmode", +] +lines-after-imports = 2 [tool.pytest.ini_options] markers = [ diff --git a/test/test_array.py b/test/test_array.py index 7a44226f..f6a3b209 100644 --- a/test/test_array.py +++ b/test/test_array.py @@ -82,7 +82,9 @@ def test_flatten_unflatten(actx_factory): b=(+0.5,)*ambient_dim, nelements_per_axis=(3,)*ambient_dim, order=1) discr = Discretization(actx, mesh, default_simplex_group_factory(ambient_dim, 3)) - a = np.random.randn(discr.ndofs) + + rng = np.random.default_rng(seed=42) + a = rng.normal(size=discr.ndofs) from meshmode.dof_array import flatten, unflatten a_round_trip = actx.to_numpy(flatten(unflatten(actx, discr, actx.from_numpy(a)))) @@ -176,7 +178,7 @@ def test_container_norm(actx_factory, ord): def test_dof_array_pickling(actx_factory): actx = actx_factory() - ary_dof, ary_of_dofs, mat_of_dofs, dc_of_dofs = _get_test_containers(actx) + _, _, mat_of_dofs, dc_of_dofs = _get_test_containers(actx) from pickle import dumps, loads with array_context_for_pickling(actx): diff --git a/test/test_chained.py b/test/test_chained.py index b00356c8..45b36620 100644 --- a/test/test_chained.py +++ b/test/test_chained.py @@ -92,7 +92,8 @@ def create_refined_connection(actx, discr, threshold=0.3): ) from meshmode.mesh.refinement import RefinerWithoutAdjacency - flags = np.random.rand(discr.mesh.nelements) < threshold + rng = np.random.default_rng(seed=42) + flags = rng.random(size=discr.mesh.nelements) < threshold refiner = RefinerWithoutAdjacency(discr.mesh) refiner.refine(flags) diff --git a/test/test_firedrake_interop.py b/test/test_firedrake_interop.py index 14bbe594..bed5c46e 100644 --- a/test/test_firedrake_interop.py +++ b/test/test_firedrake_interop.py @@ -329,8 +329,8 @@ def test_bdy_tags(mesh_name, bdy_ids, coord_indices, coord_values, if only_convert_bdy: from meshmode.interop.firedrake.connection import _get_cells_to_use cells_to_use = _get_cells_to_use(square_or_cube_mesh, "on_boundary") - mm_mesh, orient = import_firedrake_mesh(square_or_cube_mesh, - cells_to_use=cells_to_use) + mm_mesh, _orient = import_firedrake_mesh(square_or_cube_mesh, + cells_to_use=cells_to_use) # Check disjoint coverage of bdy ids and BTAG_ALL check_bc_coverage(mm_mesh, [BTAG_ALL]) check_bc_coverage(mm_mesh, bdy_ids) @@ -513,8 +513,8 @@ def get_fdrake_mesh_and_h_from_par(mesh_par): # assert that order is correct or error is "low enough" for ((fd2mm, d), eoc_rec) in eoc_recorders.items(): - print("\nfiredrake -> meshmode: %s\nvector *x* -> *sin(x[%s])*\n" - % (fd2mm, d), eoc_rec) + print(f"\nfiredrake -> meshmode: {fd2mm}\nvector *x* -> *sin(x[{d}])*\n", + eoc_rec) assert ( eoc_rec.order_estimate() >= fspace_degree or eoc_rec.max_error() < 2e-14) @@ -588,7 +588,7 @@ def test_to_fd_transfer(actx_factory, fspace_degree, mesh_name, mesh_pars, dim): # assert that order is correct or error is "low enough" for d, eoc_rec in eoc_recorders.items(): - print("\nvector *x* -> *x[%s]*\n" % d, eoc_rec) + print(f"\nvector *x* -> *x[{d}]*\n", eoc_rec) assert ( eoc_rec.order_estimate() >= fspace_degree or eoc_rec.max_error() < 2e-14) diff --git a/test/test_mesh.py b/test/test_mesh.py index 9f733464..6b0d4c87 100644 --- a/test/test_mesh.py +++ b/test/test_mesh.py @@ -313,15 +313,17 @@ def test_mesh_as_python(): # {{{ test_affine_map def test_affine_map(): + rng = np.random.default_rng(seed=42) + for d in range(1, 5): for _ in range(100): - a = np.random.randn(d, d)+10*np.eye(d) - b = np.random.randn(d) + a = rng.normal(size=(d, d)) + 10*np.eye(d) + b = rng.normal(size=d) m = AffineMap(a, b) assert la.norm(m.inverted().matrix - la.inv(a)) < 1e-10*la.norm(a) - x = np.random.randn(d) + x = rng.normal(size=d) m_inv = m.inverted() assert la.norm(x-m_inv(m(x))) < 1e-10 @@ -489,7 +491,7 @@ def test_mesh_to_tikz(): FileSource(str(thisdir / "blob-2d.step")), 2, order=order, force_ambient_dim=2, other_options=[ - "-string", "Mesh.CharacteristicLengthMax = %s;" % h], + "-string", f"Mesh.CharacteristicLengthMax = {h};"], target_unit="MM", ) @@ -802,9 +804,10 @@ def test_lookup_tree(visualize=False): bbox_min, bbox_max = mproc.find_bounding_box(mesh) extent = bbox_max-bbox_min + rng = np.random.default_rng(seed=42) for _ in range(20): - pt = bbox_min + np.random.rand(2) * extent + pt = bbox_min + rng.random(size=2) * extent print(pt) for igrp, iel in tree.generate_matches(pt): print(igrp, iel) @@ -861,7 +864,7 @@ def test_boundary_tags(): def test_volume_tags(): from meshmode.mesh.io import read_gmsh - mesh, tag_to_elements_map = read_gmsh( # pylint: disable=unpacking-non-sequence + _mesh, tag_to_elements_map = read_gmsh( # pylint: disable=unpacking-non-sequence str(thisdir / "testmesh_multivol.msh"), return_tag_to_elements_map=True) assert len(tag_to_elements_map) == 2 @@ -1152,7 +1155,7 @@ def gen_rect_mesh_with_perturbed_vertices( a, b, nelements_per_axis, perturb_amount): mesh_unperturbed = mgen.generate_regular_rect_mesh( a=a, b=b, nelements_per_axis=nelements_per_axis) - return mesh_unperturbed.copy( # noqa: F841 + return mesh_unperturbed.copy( vertices=( mesh_unperturbed.vertices + perturb_amount*np.ones(mesh_unperturbed.vertices.shape)), @@ -1274,7 +1277,7 @@ def gen_rect_mesh_with_perturbed_vertices( vol_mesh_unrotated = mgen.generate_regular_rect_mesh( a=(-1,)*2, b=(1,)*2, nelements_per_axis=(8,)*2) - vol_mesh = vol_mesh_unrotated.copy( # noqa: F841 + vol_mesh = vol_mesh_unrotated.copy( groups=[ replace( grp, diff --git a/test/test_meshmode.py b/test/test_meshmode.py index ff2fe521..526e7a2e 100644 --- a/test/test_meshmode.py +++ b/test/test_meshmode.py @@ -271,7 +271,7 @@ def f(x): FileSource(str(thisdir / "blob-2d.step")), 2, order=order, force_ambient_dim=2, other_options=[ - "-string", "Mesh.CharacteristicLengthMax = %s;" % h], + "-string", f"Mesh.CharacteristicLengthMax = {h};"], target_unit="MM", ) print("END GEN") @@ -408,7 +408,7 @@ def f(x): FileSource(str(thisdir / "blob-2d.step")), 2, order=order, force_ambient_dim=2, other_options=[ - "-string", "Mesh.CharacteristicLengthMax = %s;" % h], + "-string", f"Mesh.CharacteristicLengthMax = {h};"], target_unit="MM", ) print("END GEN") @@ -533,7 +533,7 @@ def test_orientation_3d(actx_factory, what, mesh_gen_func, visualize=False): from meshmode.discretization.visualization import make_visualizer vis = make_visualizer(actx, discr, 3) - vis.write_vtk_file("orientation_3d_%s_normals.vtu" % what, [ + vis.write_vtk_file(f"orientation_3d_{what}_normals.vtu", [ ("normals", normals), ]) @@ -711,9 +711,10 @@ def test_sanity_qhull_nd(actx_factory, dim, order): logging.basicConfig(level=logging.INFO) actx = actx_factory() + rng = np.random.default_rng(seed=42) from scipy.spatial import Delaunay # pylint: disable=no-name-in-module - verts = np.random.rand(1000, dim) + verts = rng.random(size=(1000, dim)) dtri = Delaunay(verts) # pylint: disable=no-member @@ -782,7 +783,7 @@ def test_sanity_balls(actx_factory, src_file, dim, mesh_order, visualize=False): from meshmode.mesh.io import FileSource, generate_gmsh mesh = generate_gmsh( FileSource(src_file), dim, order=mesh_order, - other_options=["-string", "Mesh.CharacteristicLengthMax = %g;" % h], + other_options=["-string", f"Mesh.CharacteristicLengthMax = {h};"], force_ambient_dim=dim, target_unit="MM") @@ -885,7 +886,6 @@ def test_mesh_without_vertices(actx_factory): # create one without the vertices from dataclasses import replace - grp, = mesh.groups groups = [ replace(grp, nodes=grp.nodes, vertex_indices=None) for grp in mesh.groups] diff --git a/test/test_partition.py b/test/test_partition.py index f26cf098..e179aef3 100644 --- a/test/test_partition.py +++ b/test/test_partition.py @@ -68,8 +68,8 @@ def test_partition_interpolation(actx_factory, dim, mesh_pars, num_parts, num_groups, part_method): order = 4 + rng = np.random.default_rng(seed=42) - np.random.seed(42) group_factory = default_simplex_group_factory(base_dim=dim, order=order) actx = actx_factory() @@ -91,7 +91,7 @@ def f(x): mesh = base_mesh if part_method == "random": - part_per_element = np.random.randint(num_parts, size=mesh.nelements) + part_per_element = rng.integers(0, num_parts, size=mesh.nelements) else: pytest.importorskip("pymetis") @@ -211,7 +211,8 @@ def _check_for_cross_rank_adj(mesh, part_per_element): ]) @pytest.mark.parametrize("num_groups", [1, 2, 7]) def test_partition_mesh(mesh_size, num_parts, num_groups, dim, scramble_parts): - np.random.seed(42) + rng = np.random.default_rng(seed=42) + nelements_per_axis = (mesh_size,) * dim from meshmode.mesh.generation import generate_regular_rect_mesh meshes = [generate_regular_rect_mesh(a=(0 + i,) * dim, b=(1 + i,) * dim, @@ -221,7 +222,7 @@ def test_partition_mesh(mesh_size, num_parts, num_groups, dim, scramble_parts): mesh = merge_disjoint_meshes(meshes) if scramble_parts: - part_per_element = np.random.randint(num_parts, size=mesh.nelements) + part_per_element = rng.integers(0, num_parts, size=mesh.nelements) else: pytest.importorskip("pymetis") @@ -320,8 +321,8 @@ def test_partition_mesh(mesh_size, num_parts, num_groups, dim, scramble_parts): assert found_reverse_adj, ("InterPartAdjacencyGroup is not " "consistent") - p_grp_num = find_group_indices(mesh.groups, p_meshwide_elem) # pylint: disable=possibly-used-before-assignment # noqa: E501 - p_n_grp_num = find_group_indices(mesh.groups, p_meshwide_n_elem) # pylint: disable=possibly-used-before-assignment # noqa: E501 + p_grp_num = find_group_indices(mesh.groups, p_meshwide_elem) # pylint: disable=possibly-used-before-assignment + p_n_grp_num = find_group_indices(mesh.groups, p_meshwide_n_elem) # pylint: disable=possibly-used-before-assignment p_elem_base = mesh.base_element_nrs[p_grp_num] p_n_elem_base = mesh.base_element_nrs[p_n_grp_num] @@ -378,7 +379,8 @@ def _test_mpi_boundary_swap(dim, order, num_groups): mpi_comm = MPI.COMM_WORLD if mpi_comm.rank == 0: - np.random.seed(42) + rng = np.random.default_rng(seed=42) + from meshmode.mesh.generation import generate_warped_rect_mesh meshes = [generate_warped_rect_mesh(dim, order=order, nelements_side=4) for _ in range(num_groups)] @@ -389,9 +391,10 @@ def _test_mpi_boundary_swap(dim, order, num_groups): else: mesh = meshes[0] - part_id_to_part = partition_mesh(mesh, - membership_list_to_map( - np.random.randint(mpi_comm.size, size=mesh.nelements))) + part_id_to_part = partition_mesh( + mesh, + membership_list_to_map(rng.integers(0, mpi_comm.size, size=mesh.nelements)) + ) assert list(part_id_to_part.keys()) == list(range(mpi_comm.size)) parts = [part_id_to_part[i] for i in range(mpi_comm.size)] @@ -580,7 +583,7 @@ def f(x): from numpy.linalg import norm err = norm(true_local_f - local_f, np.inf) - assert err < 1e-11, "Error = %f is too large" % err + assert err < 1e-11, f"Error = {err:f} is too large" # }}} diff --git a/test/test_visualization.py b/test/test_visualization.py index 547a4013..0cd0f8fb 100644 --- a/test/test_visualization.py +++ b/test/test_visualization.py @@ -85,10 +85,10 @@ def test_parallel_vtk_file(actx_factory, dim): vis = make_visualizer(actx, discr, target_order) class FakeComm: - def Get_rank(self): # noqa: N802 + def Get_rank(self): return 0 - def Get_size(self): # noqa: N802 + def Get_size(self): return 2 file_name_pattern = f"visualizer_vtk_linear_{dim}_{{rank}}.vtu"