diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 341f1f84d..f8278b353 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,8 @@ default_language_version: python: python3.8 +exclude: 'dev' + repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.4.0 @@ -12,26 +14,16 @@ repos: # args: [--markdown-linebreak-ext=md] # exclude: 'discretisedfield/tests/test_sample/.*' -- repo: https://github.com/pycqa/isort - rev: 5.12.0 - hooks: - - id: isort - -- repo: https://github.com/nbQA-dev/nbQA - rev: 1.7.0 - hooks: - - id: nbqa-isort # isort inside Jupyter notebooks - -- repo: https://github.com/PyCQA/flake8 - rev: 6.1.0 - hooks: - - id: flake8 - additional_dependencies: [flake8-rst-docstrings] #, flake8-docstrings] - -- repo: https://github.com/psf/black - rev: 23.9.1 +- repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.1.11 hooks: - - id: black-jupyter + # Run the linter. + - id: ruff + types_or: [ python, pyi, jupyter ] + args: [ --fix ] + # Run the formatter. + - id: ruff-format + types_or: [ python, pyi, jupyter ] # - repo: https://github.com/codespell-project/codespell # rev: v2.1.0 diff --git a/discretisedfield/__init__.py b/discretisedfield/__init__.py index 38ebf6e40..6251a1446 100644 --- a/discretisedfield/__init__.py +++ b/discretisedfield/__init__.py @@ -1,19 +1,18 @@ """Finite-difference fields.""" import importlib.metadata -import os import pathlib import matplotlib.pyplot as plt import pytest -from . import tools -from .field import Field -from .field_rotator import FieldRotator -from .interact import interact -from .line import Line -from .mesh import Mesh -from .operators import integrate -from .region import Region +from . import tools # noqa: F401 +from .field import Field # noqa: F401 +from .field_rotator import FieldRotator # noqa: F401 +from .interact import interact # noqa: F401 +from .line import Line # noqa: F401 +from .mesh import Mesh # noqa: F401 +from .operators import integrate # noqa: F401 +from .region import Region # noqa: F401 # Enable default plotting style. plt.style.use(pathlib.Path(__file__).parent / "plotting" / "plotting-style.mplstyle") diff --git a/discretisedfield/field.py b/discretisedfield/field.py index 507727371..ead7e122e 100644 --- a/discretisedfield/field.py +++ b/discretisedfield/field.py @@ -355,7 +355,7 @@ def update_field_values(self, value): .. seealso:: :py:func:`~discretisedfield.Field.array` """ - self.array = _as_array(value, self.mesh, self.nvdim, dtype=self.dtype) + self.array = self._as_array(value, self.mesh, self.nvdim, dtype=self.dtype) @property def vdims(self): @@ -457,7 +457,7 @@ def array(self): @array.setter def array(self, val): - self._array = _as_array(val, self.mesh, self.nvdim, dtype=self.dtype) + self._array = self._as_array(val, self.mesh, self.nvdim, dtype=self.dtype) @property def norm(self): @@ -539,7 +539,7 @@ def norm(self, val): out=np.zeros_like(self.array), where=self.norm.array != 0.0, ) - self.array *= _as_array(val, self.mesh, nvdim=1, dtype=None) + self.array *= self._as_array(val, self.mesh, nvdim=1, dtype=None) @property def valid(self): @@ -561,10 +561,10 @@ def valid(self, valid): valid = ~np.isclose(self.norm.array, 0) else: valid = True - # Using _as_array creates an array with shape (*mesh.n, 1). + # Using self._as_array creates an array with shape (*mesh.n, 1). # We only want a shape of mesh.n so we can directly use it # to index field.array i.e. field.array[field.valid]. - self._valid = _as_array(valid, self.mesh, nvdim=1, dtype=bool)[..., 0] + self._valid = self._as_array(valid, self.mesh, nvdim=1, dtype=bool)[..., 0] @property def _valid_as_field(self): @@ -3577,7 +3577,7 @@ def _hv_key_dims(self): key_dims = { dim: hv_key_dim(coords, unit) for dim, unit in zip(self.mesh.region.dims, self.mesh.region.units) - if len(coords := getattr(self.mesh.points, dim)) > 1 + if len(coords := getattr(self.mesh.cells, dim)) > 1 } if self.nvdim > 1: key_dims["vdims"] = hv_key_dim(self.vdims, "") @@ -4057,14 +4057,12 @@ def to_xarray(self, name="field", unit=None): >>> xa = field.to_xarray() >>> xa - - ... + ... 3. Select values of `x` component >>> xa.sel(vdims='x') - - ... + ... """ if not isinstance(name, str): @@ -4077,7 +4075,7 @@ def to_xarray(self, name="field", unit=None): axes = self.mesh.region.dims - data_array_coords = {axis: getattr(self.mesh.points, axis) for axis in axes} + data_array_coords = {axis: getattr(self.mesh.cells, axis) for axis in axes} geo_units_dict = dict(zip(axes, self.mesh.region.units)) @@ -4186,8 +4184,7 @@ def from_xarray(cls, xa): ... p2=[21., 21., 21.], ... nvdim=3),) >>> xa - - ... + ... 2. Create Field from DataArray @@ -4270,53 +4267,87 @@ def from_xarray(cls, xa): mesh=mesh, nvdim=nvdim, value=val, vdims=vdims, dtype=xa.values.dtype ) + @functools.singledispatchmethod + def _as_array(self, val, mesh, nvdim, dtype): + raise TypeError(f"Unsupported type {type(val)}.") -@functools.singledispatch -def _as_array(val, mesh, nvdim, dtype): - raise TypeError(f"Unsupported type {type(val)}.") - - -# to avoid str being interpreted as iterable -@_as_array.register(str) -def _(val, mesh, nvdim, dtype): - raise TypeError(f"Unsupported type {type(val)}.") + # to avoid str being interpreted as iterable + @_as_array.register(str) + def _(self, val, mesh, nvdim, dtype): + raise TypeError(f"Unsupported type {type(val)}.") + @_as_array.register(numbers.Complex) + @_as_array.register(collections.abc.Iterable) + def _(self, val, mesh, nvdim, dtype): + if isinstance(val, numbers.Complex) and nvdim > 1 and val != 0: + raise ValueError( + f"Wrong dimension 1 provided for value; expected dimension is {nvdim}" + ) -@_as_array.register(numbers.Complex) -@_as_array.register(collections.abc.Iterable) -def _(val, mesh, nvdim, dtype): - if isinstance(val, numbers.Complex) and nvdim > 1 and val != 0: - raise ValueError( - f"Wrong dimension 1 provided for value; expected dimension is {nvdim}" + if isinstance(val, collections.abc.Iterable): + if nvdim == 1 and np.array_equal(np.shape(val), mesh.n): + return np.expand_dims(val, axis=-1) + elif np.shape(val)[-1] != nvdim: + raise ValueError( + f"Wrong dimension {len(val)} provided for value; expected dimension" + f" is {nvdim}." + ) + dtype = dtype or max(np.asarray(val).dtype, np.float64) + return np.full((*mesh.n, nvdim), val, dtype=dtype) + + @_as_array.register(collections.abc.Callable) + def _(self, val, mesh, nvdim, dtype): + # will only be called on user input + # dtype must be specified by the user for complex values + array = np.empty((*mesh.n, nvdim), dtype=dtype) + for index, point in zip(mesh.indices, mesh): + # Conversion to array and reshaping is required for numpy >= 1.24 + # and for certain inputs, e.g. a tuple of numpy arrays which can e.g. occur + # for 1d vector fields. + array[index] = np.asarray(val(point)).reshape(nvdim) + return array + + @_as_array.register(dict) + def _(self, val, mesh, nvdim, dtype): + # will only be called on user input + # dtype must be specified by the user for complex values + dtype = dtype or np.float64 + fill_value = ( + val["default"] + if "default" in val and not callable(val["default"]) + else np.nan ) + array = np.full((*mesh.n, nvdim), fill_value, dtype=dtype) - if isinstance(val, collections.abc.Iterable): - if nvdim == 1 and np.array_equal(np.shape(val), mesh.n): - return np.expand_dims(val, axis=-1) - elif np.shape(val)[-1] != nvdim: - raise ValueError( - f"Wrong dimension {len(val)} provided for value; expected dimension is" - f" {nvdim}." - ) - dtype = dtype or max(np.asarray(val).dtype, np.float64) - return np.full((*mesh.n, nvdim), val, dtype=dtype) + for subregion in reversed(mesh.subregions.keys()): + # subregions can overlap, first subregion takes precedence + try: + submesh = mesh[subregion] + subval = val[subregion] + except KeyError: + continue # subregion not in val when implicitly set via "default" + else: + slices = mesh.region2slices(submesh.region) + array[slices] = self._as_array(subval, submesh, nvdim, dtype) + if np.any(np.isnan(array)): + # not all subregion keys specified and 'default' is missing or callable + if "default" not in val: + raise KeyError( + "Key 'default' required if not all subregion keys are specified." + ) + subval = val["default"] + for idx in np.argwhere(np.isnan(array[..., 0])): + # only spatial indices required -> array[..., 0] + # conversion to array and reshaping similar to "callable" implementation + array[idx] = np.asarray(subval(mesh.index2point(idx))).reshape(nvdim) -@_as_array.register(collections.abc.Callable) -def _(val, mesh, nvdim, dtype): - # will only be called on user input - # dtype must be specified by the user for complex values - array = np.empty((*mesh.n, nvdim), dtype=dtype) - for index, point in zip(mesh.indices, mesh): - # Conversion to array and reshaping is required for numpy >= 1.24 - # and for certain inputs, e.g. a tuple of numpy arrays which can e.g. occur - # for 1d vector fields. - array[index] = np.asarray(val(point)).reshape(nvdim) - return array + return array -@_as_array.register(Field) -def _(val, mesh, nvdim, dtype): +# We cannot register to self (or df.Field) inside the class +@Field._as_array.register(Field) +def _(self, val, mesh, nvdim, dtype): if mesh.region not in val.mesh.region: raise ValueError( f"{val.mesh.region} of the provided field does not " @@ -4326,7 +4357,7 @@ def _(val, mesh, nvdim, dtype): value = ( val.to_xarray() .sel( - **{dim: getattr(mesh.points, dim) for dim in mesh.region.dims}, + **{dim: getattr(mesh.cells, dim) for dim in mesh.region.dims}, method="nearest", ) .data @@ -4335,39 +4366,3 @@ def _(val, mesh, nvdim, dtype): # xarray dataarrays for scalar data are three dimensional return value.reshape(*mesh.n, -1) return value - - -@_as_array.register(dict) -def _(val, mesh, nvdim, dtype): - # will only be called on user input - # dtype must be specified by the user for complex values - dtype = dtype or np.float64 - fill_value = ( - val["default"] if "default" in val and not callable(val["default"]) else np.nan - ) - array = np.full((*mesh.n, nvdim), fill_value, dtype=dtype) - - for subregion in reversed(mesh.subregions.keys()): - # subregions can overlap, first subregion takes precedence - try: - submesh = mesh[subregion] - subval = val[subregion] - except KeyError: - continue # subregion not in val when implicitly set via "default" - else: - slices = mesh.region2slices(submesh.region) - array[slices] = _as_array(subval, submesh, nvdim, dtype) - - if np.any(np.isnan(array)): - # not all subregion keys specified and 'default' is missing or callable - if "default" not in val: - raise KeyError( - "Key 'default' required if not all subregion keys are specified." - ) - subval = val["default"] - for idx in np.argwhere(np.isnan(array[..., 0])): - # only spatial indices required -> array[..., 0] - # conversion to array and reshaping similar to "callable" implementation - array[idx] = np.asarray(subval(mesh.index2point(idx))).reshape(nvdim) - - return array diff --git a/discretisedfield/html/__init__.py b/discretisedfield/html/__init__.py index 599489cfc..805006db8 100644 --- a/discretisedfield/html/__init__.py +++ b/discretisedfield/html/__init__.py @@ -1,4 +1,3 @@ -import os import re import jinja2 diff --git a/discretisedfield/io/ovf.py b/discretisedfield/io/ovf.py index f310f450e..f1fb35ae7 100644 --- a/discretisedfield/io/ovf.py +++ b/discretisedfield/io/ovf.py @@ -147,9 +147,9 @@ def _from_ovf(cls, filename): ovf_v2 = b"2.0" in next(f) for line in f: line = line.decode("utf-8") - if line.startswith("# Begin: Data"): - mode = line.split()[3] - if mode == "Binary": + if line.lower().startswith("# begin: data"): + mode = line.split()[3].lower() + if mode == "binary": nbytes = int(line.split()[-1]) break information = line[1:].split(":") # remove leading `#` @@ -170,7 +170,7 @@ def _from_ovf(cls, filename): nodes = math.prod(int(header[f"{key}nodes"]) for key in "xyz") # >>> READ DATA <<< - if mode == "Binary": + if mode == "binary": # OVF2 uses little-endian and OVF1 uses big-endian format = f'{"<" if ovf_v2 else ">"}{"d" if nbytes == 8 else "f"}' diff --git a/discretisedfield/mesh.py b/discretisedfield/mesh.py index d0d6ec889..95c6bf711 100644 --- a/discretisedfield/mesh.py +++ b/discretisedfield/mesh.py @@ -170,7 +170,7 @@ class Mesh(_MeshIO): # removed attribute: new method/property # implemented in __getattr__ # to exclude methods from tap completion and documentation - _removed_attributes = {"midpoints": "points"} + _removed_attributes = {"midpoints": "cells", "points": "cells"} def __init__( self, @@ -487,12 +487,12 @@ def __iter__(self): yield from map(self.index2point, self.indices) @property - def points(self): - """Midpoints of the cells of the mesh along the three directions. + def cells(self): + """Midpoints of the cells of the mesh along the spatial directions. - This method returns a named tuple containing three numpy arrays with - midpoints of the cells along the three spatial directions. Individual directions - can be accessed from the tuple. + This method returns a named tuple containing numpy arrays with midpoints of the + cells along the spatial directions. Individual directions can be accessed from + the tuple. Returns ------- @@ -512,13 +512,13 @@ def points(self): >>> cell = (2, 1, 1) >>> mesh = df.Mesh(region=df.Region(p1=p1, p2=p2), cell=cell) ... - >>> mesh.points.x + >>> mesh.cells.x array([1., 3., 5., 7., 9.]) """ - points = collections.namedtuple("points", self.region.dims) + cells = collections.namedtuple("cells", self.region.dims) - return points( + return cells( *( np.linspace(pmin + cell / 2, pmax - cell / 2, n) for pmin, pmax, cell, n in zip( @@ -529,11 +529,11 @@ def points(self): @property def vertices(self): - """Vertices of the cells of the mesh along the three directions. + """Vertices of the cells of the mesh along the spatial directions. - This method returns a named tuple containing three numpy arrays with - vertices of the cells along the spatial directions. Individual directions can be - accessed from the tuple. + This method returns a named tuple containing numpy arrays with vertices of the + cells along the spatial directions. Individual directions can be accessed from + the tuple. Returns ------- @@ -2166,8 +2166,8 @@ def coordinate_field(self): vdim_mapping=dict(zip(self.region.dims, self.region.dims)), ) for i, dim in enumerate(self.region.dims): - points = self.points # avoid re-computing points - field.array[..., i] = getattr(points, dim).reshape( + cells = self.cells # avoid re-computing cells + field.array[..., i] = getattr(cells, dim).reshape( tuple(self.n[i] if i == j else 1 for j in range(self.region.ndim)) ) diff --git a/discretisedfield/plotting/__init__.py b/discretisedfield/plotting/__init__.py index 6b9b89ffe..3ad09ae32 100644 --- a/discretisedfield/plotting/__init__.py +++ b/discretisedfield/plotting/__init__.py @@ -1,4 +1,5 @@ """Matplotlib based plotting.""" +# ruff: noqa: F401 from discretisedfield.plotting import util from discretisedfield.plotting.hv import Hv from discretisedfield.plotting.k3d_field import K3dField diff --git a/discretisedfield/plotting/mpl_field.py b/discretisedfield/plotting/mpl_field.py index 7311a3d36..82a1cc4cf 100644 --- a/discretisedfield/plotting/mpl_field.py +++ b/discretisedfield/plotting/mpl_field.py @@ -630,8 +630,8 @@ def vector( multiplier = self._setup_multiplier(multiplier) - points1 = self.field.mesh.points[0] / multiplier - points2 = self.field.mesh.points[1] / multiplier + points1 = self.field.mesh.cells[0] / multiplier + points2 = self.field.mesh.cells[1] / multiplier values = self.field.array.copy() self._filter_values(self.field._valid_as_field, values) @@ -815,8 +815,8 @@ def contour( multiplier = self._setup_multiplier(multiplier) - points1 = self.field.mesh.points[0] / multiplier - points2 = self.field.mesh.points[1] / multiplier + points1 = self.field.mesh.cells[0] / multiplier + points2 = self.field.mesh.cells[1] / multiplier values = self.field.array.copy().reshape(self.field.mesh.n) diff --git a/discretisedfield/region.py b/discretisedfield/region.py index d7ddf27ad..46b639610 100644 --- a/discretisedfield/region.py +++ b/discretisedfield/region.py @@ -76,6 +76,7 @@ class Region(_RegionIO): ValueError: ... """ + __slots__ = ["_pmin", "_pmax", "_dims", "_units", "_tolerance_factor"] def __init__( diff --git a/discretisedfield/tests/test_field.py b/discretisedfield/tests/test_field.py index bdf823fba..343d7a6b7 100644 --- a/discretisedfield/tests/test_field.py +++ b/discretisedfield/tests/test_field.py @@ -96,9 +96,9 @@ def test_field(): # else: # return 0 def norm(points): - return np.where( - (points[..., 0] ** 2 + points[..., 1] ** 2) <= 5e-9**2, 1e5, 0 - )[..., np.newaxis] + return np.where((points[..., 0] ** 2 + points[..., 1] ** 2) <= 5e-9**2, 1e5, 0)[ + ..., np.newaxis + ] # Values are defined in numpy for performance reasons # We define vector fields with vx=0, vy=0, vz=+/-1 for x<0 / x>0 @@ -1859,10 +1859,10 @@ def test_diff_valid(): f = df.Field(mesh, nvdim=1, value=lambda p: p[0] ** 2, valid=valid) assert np.allclose(f.diff("x").array[:3], 0) - assert np.allclose(f.diff("x").array[3:6, 0], 2 * f.mesh.points[0][3:6]) + assert np.allclose(f.diff("x").array[3:6, 0], 2 * f.mesh.cells[0][3:6]) assert np.allclose(f.diff("x").array[6:], 0) assert np.allclose( - f.diff("x", restrict2valid=False).array[..., 0], 2 * f.mesh.points[0] + f.diff("x", restrict2valid=False).array[..., 0], 2 * f.mesh.cells[0] ) # 3d mesh @@ -2788,6 +2788,17 @@ def test_write_read_ovf(tmp_path): f_saved = df.Field(f_read.mesh, nvdim=3, value=(1, 0.1, 0), norm=1) assert f_saved.allclose(f_read) + # Read other ovf files that were reported as problematic by users + filenames = [ + "ovf2-bin8_different-case.ovf", # lower-case "Begin: data binary 8" + ] + for filename in filenames: + omffilename = os.path.join(dirname, filename) + f_read = df.Field.from_file(omffilename) + # test that some data has been read without errors; the exact content of the + # files can vary, so we cannot easily perform more thorough checks + assert f_read.array.nbytes > 0 + def test_write_read_vtk(tmp_path): filename = "testfile.vtk" @@ -4132,7 +4143,7 @@ def test_to_xarray_valid_args_vector(valid_mesh, value, dtype): assert np.allclose(fxa.attrs["pmax"], f.mesh.region.pmax) assert np.allclose(fxa.attrs["tolerance_factor"], f.mesh.region.tolerance_factor) for i in f.mesh.region.dims: - assert np.array_equal(getattr(f.mesh.points, i), fxa[i].values) + assert np.array_equal(getattr(f.mesh.cells, i), fxa[i].values) assert fxa[i].attrs["units"] == f.mesh.region.units[f.mesh.region.dims.index(i)] assert all(fxa["vdims"].values == f.vdims) assert np.array_equal(f.array, fxa.values) @@ -4156,7 +4167,7 @@ def test_to_xarray_valid_args_scalar(valid_mesh, value, dtype): assert np.allclose(fxa.attrs["pmax"], f.mesh.region.pmax) assert np.allclose(fxa.attrs["tolerance_factor"], f.mesh.region.tolerance_factor) for i in f.mesh.region.dims: - assert np.array_equal(getattr(f.mesh.points, i), fxa[i].values) + assert np.array_equal(getattr(f.mesh.cells, i), fxa[i].values) assert fxa[i].attrs["units"] == f.mesh.region.units[f.mesh.region.dims.index(i)] assert "vdims" not in fxa.dims assert np.array_equal(f.array.squeeze(axis=-1), fxa.values) diff --git a/discretisedfield/tests/test_mesh.py b/discretisedfield/tests/test_mesh.py index 06d8cd61e..9e8eabbff 100644 --- a/discretisedfield/tests/test_mesh.py +++ b/discretisedfield/tests/test_mesh.py @@ -866,14 +866,14 @@ def test_region2slice(): mesh.region2slices(df.Region(p1=(-1, 3), p2=(3, 5))) -def test_points(): +def test_cells(): # 1d example (ndim=1) p1 = 0 p2 = 10 cell = 2 mesh = df.Mesh(region=df.Region(p1=p1, p2=p2), cell=cell) - assert np.allclose(mesh.points.x, [1.0, 3.0, 5.0, 7.0, 9.0], atol=0) + assert np.allclose(mesh.cells.x, [1.0, 3.0, 5.0, 7.0, 9.0], atol=0) # 3d example (ndim=3) p1 = (0, 0, 4) @@ -881,9 +881,9 @@ def test_points(): cell = (2, 2, 1) mesh = df.Mesh(region=df.Region(p1=p1, p2=p2), cell=cell) - assert np.allclose(mesh.points.x, [1.0, 3.0, 5.0, 7.0, 9.0], atol=0) - assert np.allclose(mesh.points.y, [1.0, 3.0, 5.0], atol=0) - assert np.allclose(mesh.points.z, [0.5, 1.5, 2.5, 3.5], atol=0) + assert np.allclose(mesh.cells.x, [1.0, 3.0, 5.0, 7.0, 9.0], atol=0) + assert np.allclose(mesh.cells.y, [1.0, 3.0, 5.0], atol=0) + assert np.allclose(mesh.cells.z, [0.5, 1.5, 2.5, 3.5], atol=0) # 4d example (ndim=4) p1 = (0, 0, 4, 4) @@ -891,10 +891,10 @@ def test_points(): cell = (2, 2, 1, 1) mesh = df.Mesh(region=df.Region(p1=p1, p2=p2), cell=cell) - assert np.allclose(mesh.points.x0, [1.0, 3.0, 5.0, 7.0, 9.0], atol=0) - assert np.allclose(mesh.points.x1, [1.0, 3.0, 5.0], atol=0) - assert np.allclose(mesh.points.x2, [0.5, 1.5, 2.5, 3.5], atol=0) - assert np.allclose(mesh.points.x3, [0.5, 1.5, 2.5, 3.5], atol=0) + assert np.allclose(mesh.cells.x0, [1.0, 3.0, 5.0, 7.0, 9.0], atol=0) + assert np.allclose(mesh.cells.x1, [1.0, 3.0, 5.0], atol=0) + assert np.allclose(mesh.cells.x2, [0.5, 1.5, 2.5, 3.5], atol=0) + assert np.allclose(mesh.cells.x3, [0.5, 1.5, 2.5, 3.5], atol=0) def test_vertices(): @@ -1654,7 +1654,7 @@ def test_coordinate_field(valid_mesh): index[valid_mesh.region._dim2index(dim)] = slice(None) # extra index for vector dimension: vector component along the current direction index = tuple(index) + (valid_mesh.region._dim2index(dim),) - assert np.allclose(cfield.array[index], getattr(valid_mesh.points, dim), atol=0) + assert np.allclose(cfield.array[index], getattr(valid_mesh.cells, dim), atol=0) def test_sel_convert_intput(): diff --git a/discretisedfield/tests/test_sample/ovf2-bin8_different-case.ovf b/discretisedfield/tests/test_sample/ovf2-bin8_different-case.ovf new file mode 100644 index 000000000..464fc2ac1 Binary files /dev/null and b/discretisedfield/tests/test_sample/ovf2-bin8_different-case.ovf differ diff --git a/discretisedfield/tools/__init__.py b/discretisedfield/tools/__init__.py index c453505c4..d63619a6d 100644 --- a/discretisedfield/tools/__init__.py +++ b/discretisedfield/tools/__init__.py @@ -1,4 +1,5 @@ """Convenience tools""" +# ruff: noqa: F401 from .tools import ( count_bps, count_large_cell_angle_regions, diff --git a/discretisedfield/util/__init__.py b/discretisedfield/util/__init__.py index 03c00a2c8..ec30703ba 100644 --- a/discretisedfield/util/__init__.py +++ b/discretisedfield/util/__init__.py @@ -1 +1,2 @@ +# ruff: noqa: F401 from .util import array2tuple, assemble_index, bergluescher_angle, rescale_xarray diff --git a/docs/field-matplotlib-visualisation.ipynb b/docs/field-matplotlib-visualisation.ipynb index c802e752b..79a32b3c9 100644 --- a/docs/field-matplotlib-visualisation.ipynb +++ b/docs/field-matplotlib-visualisation.ipynb @@ -1729,7 +1729,9 @@ "cell = (1e-9, 1e-9, 1e-9)\n", "mesh = df.Mesh(p1=p1, p2=p2, cell=cell)\n", "\n", - "value_fun = lambda pos: (pos[0], pos[1], pos[2])\n", + "\n", + "def value_fun(pos):\n", + " return (pos[0], pos[1], pos[2])\n", "\n", "\n", "def norm_fun(pos):\n", diff --git a/docs/field-operations.ipynb b/docs/field-operations.ipynb index 67eea228a..8afc00b3b 100644 --- a/docs/field-operations.ipynb +++ b/docs/field-operations.ipynb @@ -518,7 +518,7 @@ "\n", "### Extracting field on any mesh\n", "\n", - "If we want to extact part of the field on any mesh which is contained inside the field, we do that by \"resampling\". We create a new field on a submesh and pass the field we want take subfield from as `value`." + "If we want to extract part of the field on any mesh which is contained inside the field, we do that by \"resampling\". We create a new field on a submesh and pass the field we want take subfield from as `value`." ] }, { @@ -802,7 +802,7 @@ "source": [ "## Selecting part of the field\n", "\n", - "We can also select part of the field using, `discretisedfield.Field.sel`. This will can be used to return a new field object which contains only discretisation cells in the specific region. The dimensionality of the field remains the same. The selections hat are allowed are the geometric axes. For instance, for a three-dimensional geometry, we can select the $x$-axis between -10 and 30. This can be written as\n", + "We can also select part of the field using, `discretisedfield.Field.sel`. This can be used to return a new field object which contains only discretisation cells in the specific region. The dimensionality of the field remains the same. The selections hat are allowed are the geometric axes. For instance, for a three-dimensional geometry, we can select the $x$-axis between -10 and 30. This can be written as\n", "\n", "$$x = (-10, 30)$$\n", "\n", @@ -815,7 +815,7 @@ "\n", "\n", "\n", - "If we select our lower point at $-10$ then the whole of `Cell 1` will be selected and if we select our upper point at $+10$ then the whole of `Cell 3` will be selected. All the cells between these teo points will also be selected." + "If we select our lower point at $-10$ then the whole of `Cell 1` will be selected and if we select our upper point at $+10$ then the whole of `Cell 3` will be selected. All the cells between these two points will also be selected." ] }, { @@ -2533,15 +2533,6 @@ "numpy universal functions can be applied to `discretisedfield.Field` objects. Below we show a different examples. For available functions please refer to the `numpy` [documentation](https://numpy.org/doc/stable/reference/ufuncs.html#available-ufuncs)." ] }, - { - "cell_type": "code", - "execution_count": 74, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np" - ] - }, { "cell_type": "code", "execution_count": 75, diff --git a/docs/mesh-basics.ipynb b/docs/mesh-basics.ipynb index 791199215..4fa4ef012 100644 --- a/docs/mesh-basics.ipynb +++ b/docs/mesh-basics.ipynb @@ -361,7 +361,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 14, @@ -564,7 +564,7 @@ } ], "source": [ - "list(mesh.points.x)" + "list(mesh.cells.x)" ] }, { @@ -584,7 +584,7 @@ } ], "source": [ - "list(mesh.points.y)" + "list(mesh.cells.y)" ] }, { @@ -1077,7 +1077,9 @@ { "cell_type": "code", "execution_count": 36, - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [ { "data": { @@ -1126,7 +1128,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.12" + "version": "3.8.17" }, "widgets": { "application/vnd.jupyter.widget-state+json": { diff --git a/pyproject.toml b/pyproject.toml index 1effdbd4b..f46a5d5e4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "discretisedfield" -version = "0.90.0" +version = "0.90.1" description = "Python package for the analysis and visualisation of finite-difference fields." readme = "README.md" requires-python = ">=3.8" @@ -68,16 +68,15 @@ repository = "https://github.com/ubermag/discretisedfield" [project.scripts] ovf2vtk = "discretisedfield.io.ovf2vtk:ovf2vtk" -[tool.black] -experimental-string-processing = true +[tool.ruff] +ignore-init-module-imports = true # do not remove unused imports in __init__ and warn instead + +[tool.ruff.per-file-ignores] +"*.ipynb" = ["F811"] # 'redefined-while-unused'; many false positives in notebooks because ipywidgets decorated functions are not recognised [tool.coverage.run] omit = ["discretisedfield/tests/*"] -[tool.isort] -profile = "black" -skip_gitignore = true # ignores files listed in .gitignore - [tool.setuptools.packages.find] include = ["discretisedfield*"]