From 6dc1723c4ccaedbe1e1edb0f6ce475a78bb17666 Mon Sep 17 00:00:00 2001 From: swapneelap Date: Tue, 1 Feb 2022 13:33:44 +0530 Subject: [PATCH 01/54] Feat(Field): add to_xarray method to_xarray returns field values as xarray.DataArray --- discretisedfield/field.py | 80 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/discretisedfield/field.py b/discretisedfield/field.py index dddf4045c..4804145c6 100644 --- a/discretisedfield/field.py +++ b/discretisedfield/field.py @@ -6,6 +6,7 @@ import h5py import numpy as np +import xarray as xr import pandas as pd import discretisedfield as df @@ -3475,3 +3476,82 @@ def __array_ufunc__(self, ufunc, method, *inputs, **kwargs): else: return self.__class__(mesh[0], dim=result.shape[-1], value=result, components=self.components) + + def to_xarray(self, name='field', units=None): + """Field value as ``xarray.DataArray``. + + The function returns a ``xarray.DataArray`` with dimensions ``x``, + ``y``, ``z``, and ``comp`` (only if vector field). The coordinate of + the geometric dimensions are derived from ``self.mesh.axis_points``, + and for vector field components from ``self.components``. The ``units`` + attribute of geometric dimensions is set to ``'m'``. + + The name and units of the field ``DataArray`` can be set by using + ``name`` and ``units``. If the type of value passed to any of the two + arguments is not string, then a TypeError is raised. + + Parameters + ---------- + name : str + + String to set name of the field ``DataArray`` + + units : str + + String to set units of the field ``DataArray`` + + Returns + ------- + xarray.DataArray + + Field values DataArray. + + Raises + ------ + TypeError + + If either ``name`` or ``units`` argument is not a string. + + Examples + -------- + # TODO: Examples that illustrate usability. + + """ + + if type(name) != str: + msg = "name argument must be a string." + raise TypeError(msg) + elif units is not None and type(units) != str: + msg = "units argument must be a string." + raise TypeError(msg) + + geo_dim = ['x', 'y', 'z'] + + data_array_coords = {dim: np.fromiter(self.mesh.axis_points(dim), + dtype=float) + for dim in geo_dim + } + + geo_units_dict = {dim: 'm' for dim in geo_dim} # fix units for geo + + if self.dim != 1: + data_array_dims = geo_dim + ['comp'] + data_array_coords['comp'] = self.components + field_array = self.array + else: + data_array_dims = geo_dim + field_array = np.squeeze(self.array, self.array.ndim - 1) + + data_array = xr.DataArray(field_array, + dims=data_array_dims, + coords=data_array_coords) + + for dim in geo_units_dict: + data_array[dim].attrs['units'] = geo_units_dict[dim] + + if units is not None: + data_array.attrs['units'] = units + + data_array.name = name + + return data_array From 57c5caaa2133959ed6b31817f52d88c568d0c903 Mon Sep 17 00:00:00 2001 From: swapneelap Date: Tue, 1 Feb 2022 17:01:50 +0530 Subject: [PATCH 02/54] Chore(Field): add examples to to_xarray docstring --- discretisedfield/field.py | 43 +++++++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/discretisedfield/field.py b/discretisedfield/field.py index 4804145c6..420fbd164 100644 --- a/discretisedfield/field.py +++ b/discretisedfield/field.py @@ -3492,11 +3492,11 @@ def to_xarray(self, name='field', units=None): Parameters ---------- - name : str + name : str, optional String to set name of the field ``DataArray`` - units : str + units : str, optional String to set units of the field ``DataArray`` @@ -3514,9 +3514,44 @@ def to_xarray(self, name='field', units=None): Examples -------- - # TODO: Examples that illustrate usability. + >>> import discretisedfield as df + ... + >>> p1 = (0, 0, 0) + >>> p2 = (10, 10, 10) + >>> cell = (1, 1, 1) + >>> mesh = df.Mesh(p1=p1, p2=p2, cell=cell) + >>> field = df.Field(mesh=mesh, dim=3, value=(1, 0, 0), norm=1.) + ... + >>> field + Field(...) + ... + >>> field.to_xarray() + + array[...] + Coordinates: + * x (x) float64 0.5 1.5 2.5 3.5 4.5 5.5 6.5 7.5 8.5 9.5 + * y (y) float64 0.5 1.5 2.5 3.5 4.5 5.5 6.5 7.5 8.5 9.5 + * z (z) float64 0.5 1.5 2.5 3.5 4.5 5.5 6.5 7.5 8.5 9.5 + * comp (comp) >> field.to_xarray().sel(comp='x') + + Coordinates: + * x (x) float64 0.5 1.5 2.5 3.5 4.5 5.5 6.5 7.5 8.5 9.5 + * y (y) float64 0.5 1.5 2.5 3.5 4.5 5.5 6.5 7.5 8.5 9.5 + * z (z) float64 0.5 1.5 2.5 3.5 4.5 5.5 6.5 7.5 8.5 9.5 + comp >> field.to_xarray(name=21) + Traceback (most recent call last): + ... + TypeError: name argument must be a string. + >>> field.to_xarray(units={'field': 'A/m'}) + Traceback (most recent call last): + ... + TypeError: units argument must be a string. - """ + """ if type(name) != str: msg = "name argument must be a string." From ee55f7753d9a3bbfc56072c7859b2521c838332f Mon Sep 17 00:00:00 2001 From: swapneelap Date: Tue, 1 Feb 2022 17:17:00 +0530 Subject: [PATCH 03/54] Chore(Field): fix to_xarray docstring --- discretisedfield/field.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/discretisedfield/field.py b/discretisedfield/field.py index 420fbd164..51925db99 100644 --- a/discretisedfield/field.py +++ b/discretisedfield/field.py @@ -3551,7 +3551,7 @@ def to_xarray(self, name='field', units=None): ... TypeError: units argument must be a string. - """ + """ if type(name) != str: msg = "name argument must be a string." From 8d1dc923159cd42ca53b47319ae09a3e66fe64bf Mon Sep 17 00:00:00 2001 From: Martin Lang <67915889+lang-m@users.noreply.github.com> Date: Tue, 1 Feb 2022 14:01:09 +0100 Subject: [PATCH 04/54] Update setup.cfg --- setup.cfg | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.cfg b/setup.cfg index e0863f877..c73b42548 100644 --- a/setup.cfg +++ b/setup.cfg @@ -34,6 +34,7 @@ install_requires = k3d>=2.11 scipy>=1.6 jinja2 + xarray include_package_data = True [options.entry_points] From baf6469e941d69da0d0a697c09c5f65011f40a73 Mon Sep 17 00:00:00 2001 From: Martin Lang <67915889+lang-m@users.noreply.github.com> Date: Tue, 1 Feb 2022 14:01:27 +0100 Subject: [PATCH 05/54] Update pyproject.toml --- pyproject.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index effb73c73..3ad0dc00c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,7 +43,8 @@ dependencies = [ "h5py>=3.1", "k3d>=2.11", "scipy>=1.6", - "jinja2" + "jinja2", + "xarray" ] [project.optional-dependencies] From e5ea0bca36962097a82f089c551e0b9214b047fd Mon Sep 17 00:00:00 2001 From: Martin Lang Date: Wed, 2 Feb 2022 07:59:28 +0100 Subject: [PATCH 06/54] Typos in docstring. --- discretisedfield/field.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/discretisedfield/field.py b/discretisedfield/field.py index 51925db99..bc6140622 100644 --- a/discretisedfield/field.py +++ b/discretisedfield/field.py @@ -3480,25 +3480,25 @@ def __array_ufunc__(self, ufunc, method, *inputs, **kwargs): def to_xarray(self, name='field', units=None): """Field value as ``xarray.DataArray``. - The function returns a ``xarray.DataArray`` with dimensions ``x``, - ``y``, ``z``, and ``comp`` (only if vector field). The coordinate of + The function returns an ``xarray.DataArray`` with dimensions ``x``, + ``y``, ``z``, and ``comp`` (only if vector field). The coordinates of the geometric dimensions are derived from ``self.mesh.axis_points``, and for vector field components from ``self.components``. The ``units`` attribute of geometric dimensions is set to ``'m'``. - The name and units of the field ``DataArray`` can be set by using + The name and units of the field ``DataArray`` can be set by passing ``name`` and ``units``. If the type of value passed to any of the two - arguments is not string, then a TypeError is raised. + arguments is not ``str``, then a ``TypeError`` is raised. Parameters ---------- name : str, optional - String to set name of the field ``DataArray`` + String to set name of the field ``DataArray``. units : str, optional - String to set units of the field ``DataArray`` + String to set units of the field ``DataArray``. Returns ------- @@ -3552,7 +3552,6 @@ def to_xarray(self, name='field', units=None): TypeError: units argument must be a string. """ - if type(name) != str: msg = "name argument must be a string." raise TypeError(msg) From bd312256eaf9341c1200543b134ccb0fc76cee06 Mon Sep 17 00:00:00 2001 From: Martin Lang Date: Wed, 2 Feb 2022 08:12:03 +0100 Subject: [PATCH 07/54] Change style for better readability. --- discretisedfield/field.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/discretisedfield/field.py b/discretisedfield/field.py index bc6140622..a94be9769 100644 --- a/discretisedfield/field.py +++ b/discretisedfield/field.py @@ -3561,10 +3561,10 @@ def to_xarray(self, name='field', units=None): geo_dim = ['x', 'y', 'z'] - data_array_coords = {dim: np.fromiter(self.mesh.axis_points(dim), - dtype=float) - for dim in geo_dim - } + data_array_coords = { + dim: np.fromiter(self.mesh.axis_points(dim), dtype=float) + for dim in geo_dim + } geo_units_dict = {dim: 'm' for dim in geo_dim} # fix units for geo From 896c8ef8bdc73e892bc6028a444d691cf0bbc51f Mon Sep 17 00:00:00 2001 From: Martin Lang Date: Wed, 2 Feb 2022 08:22:03 +0100 Subject: [PATCH 08/54] Fix doctests. --- discretisedfield/field.py | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/discretisedfield/field.py b/discretisedfield/field.py index a94be9769..fb995eef9 100644 --- a/discretisedfield/field.py +++ b/discretisedfield/field.py @@ -3524,24 +3524,22 @@ def to_xarray(self, name='field', units=None): ... >>> field Field(...) - ... >>> field.to_xarray() - array[...] - Coordinates: - * x (x) float64 0.5 1.5 2.5 3.5 4.5 5.5 6.5 7.5 8.5 9.5 - * y (y) float64 0.5 1.5 2.5 3.5 4.5 5.5 6.5 7.5 8.5 9.5 - * z (z) float64 0.5 1.5 2.5 3.5 4.5 5.5 6.5 7.5 8.5 9.5 - * comp (comp) >> field.to_xarray().sel(comp='x') - Coordinates: - * x (x) float64 0.5 1.5 2.5 3.5 4.5 5.5 6.5 7.5 8.5 9.5 - * y (y) float64 0.5 1.5 2.5 3.5 4.5 5.5 6.5 7.5 8.5 9.5 - * z (z) float64 0.5 1.5 2.5 3.5 4.5 5.5 6.5 7.5 8.5 9.5 - comp >> field.to_xarray(name=21) Traceback (most recent call last): ... From 5b26d110ed27c5098e77cfab39a7d52cb7d77048 Mon Sep 17 00:00:00 2001 From: swapneelap Date: Wed, 2 Feb 2022 16:16:24 +0530 Subject: [PATCH 09/54] Refactor(Field): address @lang-m comments --- discretisedfield/field.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/discretisedfield/field.py b/discretisedfield/field.py index fb995eef9..7058cf196 100644 --- a/discretisedfield/field.py +++ b/discretisedfield/field.py @@ -3481,10 +3481,11 @@ def to_xarray(self, name='field', units=None): """Field value as ``xarray.DataArray``. The function returns an ``xarray.DataArray`` with dimensions ``x``, - ``y``, ``z``, and ``comp`` (only if vector field). The coordinates of - the geometric dimensions are derived from ``self.mesh.axis_points``, + ``y``, ``z``, and ``comp`` (``only if field.dim > 1``). The coordinates + of the geometric dimensions are derived from ``self.mesh.axis_points``, and for vector field components from ``self.components``. The ``units`` - attribute of geometric dimensions is set to ``'m'``. + attribute of geometric dimensions is set to + ``self.mesh.attributes['unit']``. The name and units of the field ``DataArray`` can be set by passing ``name`` and ``units``. If the type of value passed to any of the two @@ -3550,10 +3551,11 @@ def to_xarray(self, name='field', units=None): TypeError: units argument must be a string. """ - if type(name) != str: + if not isinstance(name, str): msg = "name argument must be a string." raise TypeError(msg) - elif units is not None and type(units) != str: + + if units is not None and not isinstance(units, str): msg = "units argument must be a string." raise TypeError(msg) @@ -3564,7 +3566,7 @@ def to_xarray(self, name='field', units=None): for dim in geo_dim } - geo_units_dict = {dim: 'm' for dim in geo_dim} # fix units for geo + geo_units_dict = {dim: self.mesh.attributes['unit'] for dim in geo_dim} if self.dim != 1: data_array_dims = geo_dim + ['comp'] @@ -3572,7 +3574,7 @@ def to_xarray(self, name='field', units=None): field_array = self.array else: data_array_dims = geo_dim - field_array = np.squeeze(self.array, self.array.ndim - 1) + field_array = np.squeeze(self.array, axis=-1) data_array = xr.DataArray(field_array, dims=data_array_dims, From 9b003188377ddd8c3ddd4598339604bb72124fa1 Mon Sep 17 00:00:00 2001 From: swapneelap Date: Wed, 2 Feb 2022 16:23:53 +0530 Subject: [PATCH 10/54] Fix(Field): check field.components is not None Check `field.components` is not `None` before assigning it as `comp` co-ordinate values. Assigning `None` as a dimention co-ordinate throws an error. --- discretisedfield/field.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/discretisedfield/field.py b/discretisedfield/field.py index 7058cf196..6fdff0815 100644 --- a/discretisedfield/field.py +++ b/discretisedfield/field.py @@ -3570,7 +3570,8 @@ def to_xarray(self, name='field', units=None): if self.dim != 1: data_array_dims = geo_dim + ['comp'] - data_array_coords['comp'] = self.components + if self.components is not None: + data_array_coords['comp'] = self.components field_array = self.array else: data_array_dims = geo_dim From 4b5e33fb3e1d08c40f493ddd900abe0e16110030 Mon Sep 17 00:00:00 2001 From: swapneelap Date: Thu, 3 Feb 2022 09:09:27 +0530 Subject: [PATCH 11/54] Refactor(Field): address @marijanbeg comments --- discretisedfield/field.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/discretisedfield/field.py b/discretisedfield/field.py index 6fdff0815..a9d202ec2 100644 --- a/discretisedfield/field.py +++ b/discretisedfield/field.py @@ -3544,37 +3544,37 @@ def to_xarray(self, name='field', units=None): >>> field.to_xarray(name=21) Traceback (most recent call last): ... - TypeError: name argument must be a string. + TypeError: Name argument must be a string. >>> field.to_xarray(units={'field': 'A/m'}) Traceback (most recent call last): ... - TypeError: units argument must be a string. + TypeError: Units argument must be a string. """ if not isinstance(name, str): - msg = "name argument must be a string." + msg = "Name argument must be a string." raise TypeError(msg) if units is not None and not isinstance(units, str): - msg = "units argument must be a string." + msg = "Units argument must be a string." raise TypeError(msg) - geo_dim = ['x', 'y', 'z'] + axes = ['x', 'y', 'z'] data_array_coords = { - dim: np.fromiter(self.mesh.axis_points(dim), dtype=float) - for dim in geo_dim + axis: np.fromiter(self.mesh.axis_points(axis), dtype=float) + for axis in axes } - geo_units_dict = {dim: self.mesh.attributes['unit'] for dim in geo_dim} + geo_units_dict = {axis: self.mesh.attributes['unit'] for axis in axes} if self.dim != 1: - data_array_dims = geo_dim + ['comp'] + data_array_dims = axes + ['comp'] if self.components is not None: data_array_coords['comp'] = self.components field_array = self.array else: - data_array_dims = geo_dim + data_array_dims = axes field_array = np.squeeze(self.array, axis=-1) data_array = xr.DataArray(field_array, From c541737db6ab2d54e30b7ea5484aeaf20a6b265b Mon Sep 17 00:00:00 2001 From: Martin Lang <67915889+lang-m@users.noreply.github.com> Date: Thu, 3 Feb 2022 13:32:55 +0100 Subject: [PATCH 12/54] Update pyproject.toml --- pyproject.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 3ad0dc00c..e787c8349 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,8 @@ authors = [ {name = "Martin Lang"}, {name = "Samuel Holt"}, {name = "Ryan A. Pepper"}, - {name = "Hans Fangohr"} + {name = "Hans Fangohr"}, + {name = "Swapneel Amit Pathak"} ] classifiers = [ From 43719a5cd63f9e19d0cefa5c15c759483c4aa873 Mon Sep 17 00:00:00 2001 From: Martin Lang <67915889+lang-m@users.noreply.github.com> Date: Thu, 3 Feb 2022 15:48:33 +0100 Subject: [PATCH 13/54] Update pyproject.toml --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index e787c8349..9877a361a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,9 +15,9 @@ authors = [ {name = "Marijan Beg"}, {name = "Martin Lang"}, {name = "Samuel Holt"}, + {name = "Swapneel Amit Pathak"}, {name = "Ryan A. Pepper"}, - {name = "Hans Fangohr"}, - {name = "Swapneel Amit Pathak"} + {name = "Hans Fangohr"} ] classifiers = [ From 43c0ce0244f8c095f302392d45a519e16f2ab016 Mon Sep 17 00:00:00 2001 From: swapneelap Date: Fri, 4 Feb 2022 09:49:02 +0530 Subject: [PATCH 14/54] Refactor(Field): alter docstring following @fangohr comments --- discretisedfield/field.py | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/discretisedfield/field.py b/discretisedfield/field.py index a9d202ec2..98abed39f 100644 --- a/discretisedfield/field.py +++ b/discretisedfield/field.py @@ -3533,7 +3533,8 @@ def to_xarray(self, name='field', units=None): * y (y) float64 0.5 1.5 2.5 3.5 4.5 5.5 6.5 7.5 8.5 9.5 * z (z) float64 0.5 1.5 2.5 3.5 4.5 5.5 6.5 7.5 8.5 9.5 * comp (comp) >> field.to_xarray().sel(comp='x') + >>> xa = field.to_xarray() + >>> xa.sel(comp='x') ... Coordinates: @@ -3541,14 +3542,6 @@ def to_xarray(self, name='field', units=None): * y (y) float64 0.5 1.5 2.5 3.5 4.5 5.5 6.5 7.5 8.5 9.5 * z (z) float64 0.5 1.5 2.5 3.5 4.5 5.5 6.5 7.5 8.5 9.5 comp >> field.to_xarray(name=21) - Traceback (most recent call last): - ... - TypeError: Name argument must be a string. - >>> field.to_xarray(units={'field': 'A/m'}) - Traceback (most recent call last): - ... - TypeError: Units argument must be a string. """ if not isinstance(name, str): From ac4104f577b60469d88cfafc4aa0674f0a9df8a6 Mon Sep 17 00:00:00 2001 From: swapneelap Date: Mon, 7 Feb 2022 09:55:51 +0530 Subject: [PATCH 15/54] Test(Field): remove unused variable --- discretisedfield/tests/test_field.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/discretisedfield/tests/test_field.py b/discretisedfield/tests/test_field.py index c2644828b..63c50b5ce 100644 --- a/discretisedfield/tests/test_field.py +++ b/discretisedfield/tests/test_field.py @@ -107,8 +107,6 @@ def check_field(field): assert isinstance(curl, df.Field) assert curl.dim == 3 - field_plane = field.plane('z') - assert isinstance((field * df.dx).integral(), tuple) assert isinstance((field * df.dy).integral(), tuple) assert isinstance((field * df.dz).integral(), tuple) From 0961e6ee8b1dda78bcb81425d27137cf14ee7d75 Mon Sep 17 00:00:00 2001 From: swapneelap Date: Mon, 7 Feb 2022 18:35:54 +0530 Subject: [PATCH 16/54] Fix(Field): check if unit exists in mesh.attributes It is possible to create mesh where attributes donot have `unit` key which ultimately breaks to_xarray function --- discretisedfield/field.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/discretisedfield/field.py b/discretisedfield/field.py index 98abed39f..238dd25a2 100644 --- a/discretisedfield/field.py +++ b/discretisedfield/field.py @@ -3559,7 +3559,11 @@ def to_xarray(self, name='field', units=None): for axis in axes } - geo_units_dict = {axis: self.mesh.attributes['unit'] for axis in axes} + geo_units_dict = None + if 'unit' in self.mesh.attributes: + geo_units_dict = { + axis: self.mesh.attributes['unit'] for axis in axes + } if self.dim != 1: data_array_dims = axes + ['comp'] @@ -3574,8 +3578,9 @@ def to_xarray(self, name='field', units=None): dims=data_array_dims, coords=data_array_coords) - for dim in geo_units_dict: - data_array[dim].attrs['units'] = geo_units_dict[dim] + if geo_units_dict is not None: + for dim in geo_units_dict: + data_array[dim].attrs['units'] = geo_units_dict[dim] if units is not None: data_array.attrs['units'] = units From 9bd4a1e27fa73051d61aca09c76d0af5508f01ae Mon Sep 17 00:00:00 2001 From: swapneelap Date: Mon, 7 Feb 2022 18:45:20 +0530 Subject: [PATCH 17/54] Test(Field): add tests for to_xarray --- discretisedfield/tests/test_field.py | 76 ++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/discretisedfield/tests/test_field.py b/discretisedfield/tests/test_field.py index 63c50b5ce..cc05d2619 100644 --- a/discretisedfield/tests/test_field.py +++ b/discretisedfield/tests/test_field.py @@ -8,6 +8,7 @@ import tempfile import itertools import numpy as np +import xarray as xr import discretisedfield as df import matplotlib.pyplot as plt from .test_mesh import TestMesh, html_re as mesh_html_re @@ -2199,3 +2200,78 @@ def test_numpy_ufunc(self): value=lambda _: np.random.random(3)*2 - 1) assert np.allclose(np.exp(field.orientation).array, np.exp(field.orientation.array)) + + def test_to_xarray_valid_args(self): + for mesh in self.meshes: + for value, dtype in self.vfuncs: + f = df.Field(mesh, dim=3, value=value, dtype=dtype) + fxa = f.to_xarray() + assert f.dim == fxa['comp'].size + assert isinstance(fxa, xr.DataArray) + assert np.array_equal( + np.array(list(f.mesh.axis_points('x'))), + fxa.x.values + ) + assert np.array_equal( + np.array(list(f.mesh.axis_points('y'))), + fxa.y.values + ) + assert np.array_equal( + np.array(list(f.mesh.axis_points('z'))), + fxa.z.values + ) + assert np.array_equal(f.array, fxa.values) + assert all( + fxa[i].attrs['units'] == f.mesh.attributes['unit'] + for i in ['x', 'y', 'z'] + ) + assert all(fxa['comp'].values == f.components) + + for value, dtype in self.sfuncs: + f = df.Field(mesh, dim=1, value=value, dtype=dtype) + fxa = f.to_xarray() + assert isinstance(fxa, xr.DataArray) + assert np.array_equal( + np.array(list(f.mesh.axis_points('x'))), + fxa.x.values + ) + assert np.array_equal( + np.array(list(f.mesh.axis_points('y'))), + fxa.y.values + ) + assert np.array_equal( + np.array(list(f.mesh.axis_points('z'))), + fxa.z.values + ) + assert 'comp' not in fxa.dims + assert np.array_equal(f.array.squeeze(axis=-1), fxa.values) + assert all( + fxa[i].attrs['units'] == f.mesh.attributes['unit'] + for i in ['x', 'y', 'z'] + ) + + f6d = self.pf << self.pf + f6d_xa = f6d.to_xarray() + assert f6d_xa['comp'].size == 6 + + # test name and units defaults + f3d_xa = self.pf.to_xarray() + assert f3d_xa.name == 'field' + assert 'units' not in f3d_xa.attrs + + # test name and units + f3d_xa_2 = self.pf.to_xarray('m', 'A/m') + assert f3d_xa_2.name == 'm' + assert f3d_xa_2.attrs['units'] == 'A/m' + + def test_to_xarray_invalid_args(self): + args = [ + ['m', 42.0], [21.0, 42], [21, 'A/m'], + [{'name': 'm'}, {'units': 'A/m'}], [['m'], ['A/m']], + [['m', 'A/m'], None], [('m', 'A/m'), None], + [{'name': 'm', 'units': 'A/m'}, None] + ] + + for name, units in args: + with pytest.raises(TypeError): + fxa = self.pf.to_xarray(name, units) From 51d07ddaa2a02054db299706326b0c10aa951a96 Mon Sep 17 00:00:00 2001 From: Martin Lang Date: Mon, 7 Feb 2022 15:13:14 +0100 Subject: [PATCH 18/54] Minimal version of pre-commit config to make tests pass --- .pre-commit-config.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .pre-commit-config.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 000000000..762b6e18a --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,9 @@ +repos: +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.1.0 + hooks: + - id: check-merge-conflict # checks for files that contain merge conflict strings + - id: check-toml # checks toml files for parseable syntax + - id: debug-statements # checks for debugger imports and py37+ `breakpoint()` calls in python source + - id: trailing-whitespace + args: [--markdown-linebreak-ext=md] From 7bb29256ab031e145cb04ae9121c9ca2c70d3c4a Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 7 Feb 2022 14:13:56 +0000 Subject: [PATCH 19/54] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .../tests/test_sample/oommf-ovf1-bin4.omf | Bin 394289 -> 394277 bytes .../tests/test_sample/oommf-ovf1-bin8.omf | Bin 787509 -> 787461 bytes nbval.cfg | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) diff --git a/discretisedfield/tests/test_sample/oommf-ovf1-bin4.omf b/discretisedfield/tests/test_sample/oommf-ovf1-bin4.omf index c5005d05982e40c1bc0d843e679f7c02f8f18afa..469dc1c9f63cff7fb843d964a822fc57863b034e 100644 GIT binary patch delta 87 zcmV-d0I2`5h!~}a7=W|^T8y__i~(C8x3{YSBb>L}M*>?Yw>NMCuMM~7eF8%qw=0?g tf77?CZ3DX;w`Yn2PYt)Xmjk0Hw_Csi+ncvHTm+*ZhueDux7&LKR)|d#B^dw! delta 111 zcmZ45A+fPTqG1bTR1YKPb|4Wg52UxQW>lWT$i4lBJ5#gDajld}wv zR-MIEe;G(G$z|RR;>UL}`||?Tt((rg7^FV%0Q2qHKy!3rSQZ1#Yd>Gjvi*EDYgh*W DCNU+O diff --git a/discretisedfield/tests/test_sample/oommf-ovf1-bin8.omf b/discretisedfield/tests/test_sample/oommf-ovf1-bin8.omf index e5c8cff37846c8bfeeea1a829ce99dc64f495073..001b3cd99f1c0ede9692667cf612c607373fee07 100644 GIT binary patch delta 303 zcmV+~0nq-nh%kkSFtDL&v!ZIpQnPBkic`1s5CLHXw^tPb&L+1eJOPKyx2^~RSXhS# zVFI@YVFMZnw<2i+$5prLz5~)Ix4q{BEI_yFCj?m&w?sPxp&Ga5RRkaiw+CJX)DE}Y zYy?FUw<3T9(_**w;smV{x1{w1CJwjD0|kd5w^Jkq!g9A3mj$l^x5k+T(0jL+6$YLg zw>B{by-m0Deg^3ax88~dT^_eQsRkB0w^QQ=cOkdS1P9s_x272fdvCWQi3hn5x7?Wr zXEe7&&IhFsx9Z*pJV3W69|*M)x7{%a3>LTQM+ib5w=HG}Q8KrGmw`OGtP-Ta=$_cl($_kYZw@uj!cxt!CLkpt_w`xoaH&3^sn+p^Nx3{7Teqr@W Be4qdT delta 397 zcmZqeFxc8*uwh{qBlqToS;vEbRL0(}U`EdEp9B~aSs1yu2a7VEQ)A@Wu4u#9eg-JM zf`cg{f|0u|k!f2ZvlItVL@JZ{cqov5xR3dg29VzToLR>KsN=pmOQbN6Z(+@{P>NAu z`^``m1(5omu`E~kfb`iM7FS`QI-v%Z%Sk}~(?=|8g@E*=uPkbOK=nJAS=$wWw7m-J zp(3D57^kzYX9CJ^n8|vf8mO;9lx?0gkS}M*w$~TPzg@@nk{ifB(!~}l2jnZRWD~Oj z>NkJPR;~!7*RinQ5&_D0NU~Sw1Lc`J*>?&6`Fm!vr<(w2<#X&y1%Tow?y=iA0PSOu z=hzBz&rU-Q9x)(&)Sbf#WG;IeN1zdqA2EYt5j&9nHJ@WwG?3o%o1-HWsLv*qGa!|b xyS?WW=k}gcTvI`QQM}1jkp-k@I&&}P0IBieHune8#k09Z*nwuYFXFCC1ON(Qe1!l2 diff --git a/nbval.cfg b/nbval.cfg index 41a9ee889..cd491e902 100644 --- a/nbval.cfg +++ b/nbval.cfg @@ -1,6 +1,6 @@ [oommf runner] regex: \(\w+OOMMFRunner\) -replace: +replace: [timestamp] regex: \[\d{4}/\d{2}/\d{2} \d{2}:\d{2}\] From 86d68c79b23857bc18e6e378b16f434c2a13d6f2 Mon Sep 17 00:00:00 2001 From: Martin Lang Date: Mon, 7 Feb 2022 15:28:13 +0100 Subject: [PATCH 20/54] Revert "[pre-commit.ci] auto fixes from pre-commit.com hooks" This reverts commit 7bb29256ab031e145cb04ae9121c9ca2c70d3c4a. --- .../tests/test_sample/oommf-ovf1-bin4.omf | Bin 394277 -> 394289 bytes .../tests/test_sample/oommf-ovf1-bin8.omf | Bin 787461 -> 787509 bytes nbval.cfg | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) diff --git a/discretisedfield/tests/test_sample/oommf-ovf1-bin4.omf b/discretisedfield/tests/test_sample/oommf-ovf1-bin4.omf index 469dc1c9f63cff7fb843d964a822fc57863b034e..c5005d05982e40c1bc0d843e679f7c02f8f18afa 100644 GIT binary patch delta 111 zcmZ45A+fPTqG1bTR1YKPb|4Wg52UxQW>lWT$i4lBJ5#gDajld}wv zR-MIEe;G(G$z|RR;>UL}`||?Tt((rg7^FV%0Q2qHKy!3rSQZ1#Yd>Gjvi*EDYgh*W DCNU+O delta 87 zcmV-d0I2`5h!~}a7=W|^T8y__i~(C8x3{YSBb>L}M*>?Yw>NMCuMM~7eF8%qw=0?g tf77?CZ3DX;w`Yn2PYt)Xmjk0Hw_Csi+ncvHTm+*ZhueDux7&LKR)|d#B^dw! diff --git a/discretisedfield/tests/test_sample/oommf-ovf1-bin8.omf b/discretisedfield/tests/test_sample/oommf-ovf1-bin8.omf index 001b3cd99f1c0ede9692667cf612c607373fee07..e5c8cff37846c8bfeeea1a829ce99dc64f495073 100644 GIT binary patch delta 397 zcmZqeFxc8*uwh{qBlqToS;vEbRL0(}U`EdEp9B~aSs1yu2a7VEQ)A@Wu4u#9eg-JM zf`cg{f|0u|k!f2ZvlItVL@JZ{cqov5xR3dg29VzToLR>KsN=pmOQbN6Z(+@{P>NAu z`^``m1(5omu`E~kfb`iM7FS`QI-v%Z%Sk}~(?=|8g@E*=uPkbOK=nJAS=$wWw7m-J zp(3D57^kzYX9CJ^n8|vf8mO;9lx?0gkS}M*w$~TPzg@@nk{ifB(!~}l2jnZRWD~Oj z>NkJPR;~!7*RinQ5&_D0NU~Sw1Lc`J*>?&6`Fm!vr<(w2<#X&y1%Tow?y=iA0PSOu z=hzBz&rU-Q9x)(&)Sbf#WG;IeN1zdqA2EYt5j&9nHJ@WwG?3o%o1-HWsLv*qGa!|b xyS?WW=k}gcTvI`QQM}1jkp-k@I&&}P0IBieHune8#k09Z*nwuYFXFCC1ON(Qe1!l2 delta 303 zcmV+~0nq-nh%kkSFtDL&v!ZIpQnPBkic`1s5CLHXw^tPb&L+1eJOPKyx2^~RSXhS# zVFI@YVFMZnw<2i+$5prLz5~)Ix4q{BEI_yFCj?m&w?sPxp&Ga5RRkaiw+CJX)DE}Y zYy?FUw<3T9(_**w;smV{x1{w1CJwjD0|kd5w^Jkq!g9A3mj$l^x5k+T(0jL+6$YLg zw>B{by-m0Deg^3ax88~dT^_eQsRkB0w^QQ=cOkdS1P9s_x272fdvCWQi3hn5x7?Wr zXEe7&&IhFsx9Z*pJV3W69|*M)x7{%a3>LTQM+ib5w=HG}Q8KrGmw`OGtP-Ta=$_cl($_kYZw@uj!cxt!CLkpt_w`xoaH&3^sn+p^Nx3{7Teqr@W Be4qdT diff --git a/nbval.cfg b/nbval.cfg index cd491e902..41a9ee889 100644 --- a/nbval.cfg +++ b/nbval.cfg @@ -1,6 +1,6 @@ [oommf runner] regex: \(\w+OOMMFRunner\) -replace: +replace: [timestamp] regex: \[\d{4}/\d{2}/\d{2} \d{2}:\d{2}\] From 4184cf7cefc083f8e6f43760230d850bad591070 Mon Sep 17 00:00:00 2001 From: Martin Lang Date: Mon, 7 Feb 2022 15:30:39 +0100 Subject: [PATCH 21/54] fix pre-commit --- .pre-commit-config.yaml | 1 + nbval.cfg | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 762b6e18a..25427d5ba 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -7,3 +7,4 @@ repos: - id: debug-statements # checks for debugger imports and py37+ `breakpoint()` calls in python source - id: trailing-whitespace args: [--markdown-linebreak-ext=md] + exclude: 'discretisedfield/tests/test_sample/*' diff --git a/nbval.cfg b/nbval.cfg index 41a9ee889..cd491e902 100644 --- a/nbval.cfg +++ b/nbval.cfg @@ -1,6 +1,6 @@ [oommf runner] regex: \(\w+OOMMFRunner\) -replace: +replace: [timestamp] regex: \[\d{4}/\d{2}/\d{2} \d{2}:\d{2}\] From 271ac30d6dc3e85309472a48468cd93f52e4fb52 Mon Sep 17 00:00:00 2001 From: Martin Lang Date: Mon, 7 Feb 2022 15:31:52 +0100 Subject: [PATCH 22/54] regex for pre-commit --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 25427d5ba..6e2cf3d06 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -7,4 +7,4 @@ repos: - id: debug-statements # checks for debugger imports and py37+ `breakpoint()` calls in python source - id: trailing-whitespace args: [--markdown-linebreak-ext=md] - exclude: 'discretisedfield/tests/test_sample/*' + exclude: 'discretisedfield/tests/test_sample/.*' From 0b5cc13a0efbd5caa16a8bf4c746ebe096415ec8 Mon Sep 17 00:00:00 2001 From: swapneelap Date: Tue, 8 Feb 2022 12:05:21 +0530 Subject: [PATCH 23/54] Refactor(Field): address @lang-m and @marijanbeg comments --- discretisedfield/field.py | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/discretisedfield/field.py b/discretisedfield/field.py index 238dd25a2..71068b292 100644 --- a/discretisedfield/field.py +++ b/discretisedfield/field.py @@ -3559,13 +3559,12 @@ def to_xarray(self, name='field', units=None): for axis in axes } - geo_units_dict = None if 'unit' in self.mesh.attributes: - geo_units_dict = { - axis: self.mesh.attributes['unit'] for axis in axes - } + geo_units_dict = dict.fromkeys(axes, self.mesh.attributes['unit']) + else: + geo_units_dict = dict.fromkeys(axes, 'm') - if self.dim != 1: + if self.dim > 1: data_array_dims = axes + ['comp'] if self.components is not None: data_array_coords['comp'] = self.components @@ -3576,15 +3575,11 @@ def to_xarray(self, name='field', units=None): data_array = xr.DataArray(field_array, dims=data_array_dims, - coords=data_array_coords) - - if geo_units_dict is not None: - for dim in geo_units_dict: - data_array[dim].attrs['units'] = geo_units_dict[dim] - - if units is not None: - data_array.attrs['units'] = units + coords=data_array_coords, + name=name, + attrs=dict(units=units)) - data_array.name = name + for dim in geo_units_dict: + data_array[dim].attrs['units'] = geo_units_dict[dim] return data_array From 4931360092f37e69006386b1724dac4ae2ab39b0 Mon Sep 17 00:00:00 2001 From: swapneelap Date: Tue, 8 Feb 2022 12:06:59 +0530 Subject: [PATCH 24/54] Test(Field): address @lang-m and @marijanbeg comments --- discretisedfield/tests/test_field.py | 49 +++++++++------------------- 1 file changed, 15 insertions(+), 34 deletions(-) diff --git a/discretisedfield/tests/test_field.py b/discretisedfield/tests/test_field.py index cc05d2619..32e344be5 100644 --- a/discretisedfield/tests/test_field.py +++ b/discretisedfield/tests/test_field.py @@ -2208,56 +2208,37 @@ def test_to_xarray_valid_args(self): fxa = f.to_xarray() assert f.dim == fxa['comp'].size assert isinstance(fxa, xr.DataArray) - assert np.array_equal( - np.array(list(f.mesh.axis_points('x'))), - fxa.x.values - ) - assert np.array_equal( - np.array(list(f.mesh.axis_points('y'))), - fxa.y.values - ) - assert np.array_equal( - np.array(list(f.mesh.axis_points('z'))), - fxa.z.values - ) - assert np.array_equal(f.array, fxa.values) - assert all( - fxa[i].attrs['units'] == f.mesh.attributes['unit'] - for i in ['x', 'y', 'z'] - ) + for i in 'xyz': + assert np.array_equal( + np.array(list(f.mesh.axis_points(i))), + fxa[i].values + ) + assert fxa[i].attrs['units'] == f.mesh.attributes['unit'] assert all(fxa['comp'].values == f.components) + assert np.array_equal(f.array, fxa.values) for value, dtype in self.sfuncs: f = df.Field(mesh, dim=1, value=value, dtype=dtype) fxa = f.to_xarray() assert isinstance(fxa, xr.DataArray) - assert np.array_equal( - np.array(list(f.mesh.axis_points('x'))), - fxa.x.values - ) - assert np.array_equal( - np.array(list(f.mesh.axis_points('y'))), - fxa.y.values - ) - assert np.array_equal( - np.array(list(f.mesh.axis_points('z'))), - fxa.z.values - ) + for i in 'xyz': + assert np.array_equal( + np.array(list(f.mesh.axis_points(i))), + fxa[i].values + ) + assert fxa[i].attrs['units'] == f.mesh.attributes['unit'] assert 'comp' not in fxa.dims assert np.array_equal(f.array.squeeze(axis=-1), fxa.values) - assert all( - fxa[i].attrs['units'] == f.mesh.attributes['unit'] - for i in ['x', 'y', 'z'] - ) f6d = self.pf << self.pf f6d_xa = f6d.to_xarray() assert f6d_xa['comp'].size == 6 + assert 'comp' not in f6d_xa.coords # test name and units defaults f3d_xa = self.pf.to_xarray() assert f3d_xa.name == 'field' - assert 'units' not in f3d_xa.attrs + assert f3d_xa.attrs['units'] is None # test name and units f3d_xa_2 = self.pf.to_xarray('m', 'A/m') From ed29497d796a144bd8e2cb5475b94ef1cc525d50 Mon Sep 17 00:00:00 2001 From: swapneelap Date: Tue, 8 Feb 2022 14:02:19 +0530 Subject: [PATCH 25/54] Fix(Field): update docstring --- discretisedfield/field.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/discretisedfield/field.py b/discretisedfield/field.py index 71068b292..9ed4daf18 100644 --- a/discretisedfield/field.py +++ b/discretisedfield/field.py @@ -3525,7 +3525,8 @@ def to_xarray(self, name='field', units=None): ... >>> field Field(...) - >>> field.to_xarray() + >>> xa = field.to_xarray() + >>> xa ... Coordinates: @@ -3533,7 +3534,8 @@ def to_xarray(self, name='field', units=None): * y (y) float64 0.5 1.5 2.5 3.5 4.5 5.5 6.5 7.5 8.5 9.5 * z (z) float64 0.5 1.5 2.5 3.5 4.5 5.5 6.5 7.5 8.5 9.5 * comp (comp) >> xa = field.to_xarray() + Attributes: + units: None >>> xa.sel(comp='x') ... @@ -3542,6 +3544,8 @@ def to_xarray(self, name='field', units=None): * y (y) float64 0.5 1.5 2.5 3.5 4.5 5.5 6.5 7.5 8.5 9.5 * z (z) float64 0.5 1.5 2.5 3.5 4.5 5.5 6.5 7.5 8.5 9.5 comp Date: Tue, 8 Feb 2022 14:30:42 +0530 Subject: [PATCH 26/54] Refactor(Field): add docstring headings following @lang-m comments --- discretisedfield/field.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/discretisedfield/field.py b/discretisedfield/field.py index 9ed4daf18..cf41676dc 100644 --- a/discretisedfield/field.py +++ b/discretisedfield/field.py @@ -3515,6 +3515,8 @@ def to_xarray(self, name='field', units=None): Examples -------- + 1. Create a field + >>> import discretisedfield as df ... >>> p1 = (0, 0, 0) @@ -3525,6 +3527,9 @@ def to_xarray(self, name='field', units=None): ... >>> field Field(...) + + 2. Create `xarray.DataArray` from field + >>> xa = field.to_xarray() >>> xa @@ -3536,6 +3541,9 @@ def to_xarray(self, name='field', units=None): * comp (comp) >> xa.sel(comp='x') ... From 7389e8047ac903abbec6ff8f1a38924123f31a51 Mon Sep 17 00:00:00 2001 From: swapneelap Date: Wed, 16 Feb 2022 15:43:45 +0530 Subject: [PATCH 27/54] Test(Field): add tests for from_xarray class method --- discretisedfield/tests/test_field.py | 147 ++++++++++++++++++++++++++- 1 file changed, 146 insertions(+), 1 deletion(-) diff --git a/discretisedfield/tests/test_field.py b/discretisedfield/tests/test_field.py index 32e344be5..e8181899e 100644 --- a/discretisedfield/tests/test_field.py +++ b/discretisedfield/tests/test_field.py @@ -2241,7 +2241,7 @@ def test_to_xarray_valid_args(self): assert f3d_xa.attrs['units'] is None # test name and units - f3d_xa_2 = self.pf.to_xarray('m', 'A/m') + f3d_xa_2 = self.pf.to_xarray(name='m', units='A/m') assert f3d_xa_2.name == 'm' assert f3d_xa_2.attrs['units'] == 'A/m' @@ -2256,3 +2256,148 @@ def test_to_xarray_invalid_args(self): for name, units in args: with pytest.raises(TypeError): fxa = self.pf.to_xarray(name, units) + + def test_from_xarray_valid_args(self): + for mesh in self.meshes: + for value, dtype in self.vfuncs: + f = df.Field(mesh, dim=3, value=value, dtype=dtype) + fxa = f.to_xarray() + f_new = df.Field.from_xarray(fxa) + assert f_new == f # or use allclose() + + for value, dtype in self.sfuncs: + f = df.Field(mesh, dim=1, value=value, dtype=dtype) + fxa = f.to_xarray() + f_new = df.Field.from_xarray(fxa) + assert f_new == f # or use allclose() + + f_plane = self.pf.plane('z') + f_plane_xa = f_plane.to_xarray() + f_plane_new = df.Field.from_xarray(f_plane_xa) + assert f_plane_new == f_plane # or use allclose() + + f6d = self.pf << self.pf + f6d_xa = f6d.to_xarray() + f6d_new = df.Field.from_xarray(f6d_xa) + assert f6d_new == f6d # or use allclose() + + def test_from_xarray_invalid_args_and_DataArrays(self): + args = [int(), float(), str(), list(), dict(), xr.Dataset(), + np.empty((20, 20, 20, 3))] + bad_value1 = xr.DataArray(np.ones((20, 20, 5, 3), dtype=np.int8), + dims=['x', 'y', 'z', 'comp'], + coords=dict(x=np.arange(0, 20), + y=np.arange(0, 20), + z=np.arange(0, 5), + comp=['x', 'y', 'z']), + name='mag', + attrs=dict(units='A/m')) + + bad_value2 = xr.DataArray(np.ones((20, 20, 5, 3), dtype=str), + dims=['x', 'y', 'z', 'comp'], + coords=dict(x=np.arange(0, 20), + y=np.arange(0, 20), + z=np.arange(0, 5), + comp=['x', 'y', 'z']), + name='mag', + attrs=dict(units='A/m')) + + bad_dim_no = xr.DataArray(np.ones((20, 20, 20, 5, 3), dtype=float), + dims=['x', 'y', 'z', 'a', 'comp'], + coords=dict(x=np.arange(0, 20), + y=np.arange(0, 20), + z=np.arange(0, 20), + a=np.arange(0, 5), + comp=['x', 'y', 'z']), + name='mag', + attrs=dict(units='A/m')) + + bad_dim_no2 = xr.DataArray(np.ones((20, 20), dtype=float), + dims=['x', 'y'], + coords=dict(x=np.arange(0, 20), + y=np.arange(0, 20)), + name='mag', + attrs=dict(units='A/m')) + + bad_dim3 = xr.DataArray(np.ones((20, 20, 5), dtype=float), + dims=['a', 'b', 'c'], + coords=dict(a=np.arange(0, 20), + b=np.arange(0, 20), + c=np.arange(0, 5)), + name='mag', + attrs=dict(units='A/m')) + + bad_dim4 = xr.DataArray(np.ones((20, 20, 5, 3), dtype=float), + dims=['x', 'y', 'z', 'c'], + coords=dict(x=np.arange(0, 20), + y=np.arange(0, 20), + z=np.arange(0, 5), + c=['x', 'y', 'z']), + name='mag', + attrs=dict(units='A/m')) + + def bad_coord_gen(): + rng = np.random.default_rng() + for coord in 'xyz': + coord_dict = {coord: rng.normal(size=20)} + for other_coord in 'xyz'.translate({ord(coord): None}): + coord_dict[other_coord] = np.arange(0, 20) + coord_dict['comp'] = ['x', 'y', 'z'] + + yield xr.DataArray(np.ones((20, 20, 20, 3), dtype=float), + dims=['x', 'y', 'z', 'comp'], + coords=coord_dict, + name='mag', + attrs=dict(units='A/m')) + + bad_coord_comp1 = xr.DataArray(np.ones((20, 20, 20, 3), dtype=float), + dims=['x', 'y', 'z', 'comp'], + coords=dict(x=np.arange(0, 20), + y=np.arange(0, 20), + z=np.arange(0, 20), + comp=['x', 'x', 'z']), + name='mag', + attrs=dict(units='A/m')) + + bad_coord_comp2 = xr.DataArray(np.ones((20, 20, 20, 3), dtype=float), + dims=['x', 'y', 'z', 'comp'], + coords=dict(x=np.arange(0, 20), + y=np.arange(0, 20), + z=np.arange(0, 20), + comp=['a', 'b', 'c']), + name='mag', + attrs=dict(units='A/m')) + + bad_coord_comp3 = xr.DataArray(np.ones((20, 20, 20, 3), dtype=float), + dims=['x', 'y', 'z', 'comp'], + coords=dict(x=np.arange(0, 20), + y=np.arange(0, 20), + z=np.arange(0, 20), + comp=[1, 2, 3]), + name='mag', + attrs=dict(units='A/m')) + + for arg in args: + with pytest.raises(TypeError): + f = df.Field.from_xarray(arg) + with pytest.raises(ValueError): + f = df.Field.from_xarray(bad_value1) + with pytest.raises(ValueError): + f = df.Field.from_xarray(bad_value2) + with pytest.raises(ValueError): + f = df.Field.from_xarray(bad_dim_no) + with pytest.raises(ValueError): + f = df.Field.from_xarray(bad_dim_no2) + with pytest.raises(ValueError): + f = df.Field.from_xarray(bad_dim3) + with pytest.raises(ValueError): + f = df.Field.from_xarray(bad_dim4) + for bad_coord_geo in bad_coord_gen(): + with pytest.raises(ValueError): + f = df.Field.from_xarray(bad_coord_geo) + with pytest.raises(ValueError): + f = df.Field.from_xarray(bad_coord_comp1) + with pytest.raises(ValueError): + f = df.Field.from_xarray(bad_coord_comp2) + with pytest.raises(ValueError): + f = df.Field.from_xarray(bad_coord_comp3) From a064eff115f4563296843d74475350a1f88b33bb Mon Sep 17 00:00:00 2001 From: swapneelap Date: Wed, 16 Feb 2022 15:47:13 +0530 Subject: [PATCH 28/54] Feat(Field): add from_xarray class method --- discretisedfield/field.py | 89 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/discretisedfield/field.py b/discretisedfield/field.py index 131d42f02..4bf66e9a4 100644 --- a/discretisedfield/field.py +++ b/discretisedfield/field.py @@ -8,6 +8,7 @@ import numpy as np import xarray as xr import pandas as pd +import decimal as dc import discretisedfield as df import discretisedfield.plotting as dfp @@ -3599,3 +3600,91 @@ def to_xarray(self, name='field', units=None): data_array[dim].attrs['units'] = geo_units_dict[dim] return data_array + + @classmethod + def from_xarray(cls, xa): + if not isinstance(xa, xr.DataArray): + msg = "Argument must be a xr.DataArray." + raise TypeError(msg) + + if xa.ndim not in [3, 4]: + msg = "DataArray dimensions must be 3 or 4." + raise ValueError(msg) + + if xa.ndim == 3: + for dim in xa.dims: + if dim not in ['x', 'y', 'z']: + msg = "The dimensions must be either 'x', 'y', or 'z'." + raise ValueError(msg) + elif xa.ndim == 4: + for dim in xa.dims: + if dim not in ['x', 'y', 'z', 'comp']: + msg = "The dimensions must be either "\ + "'x', 'y', 'z' or 'comp'." + raise ValueError(msg) + if xa['comp'].values.size != len(set(xa['comp'].values)): + msg = "All the components should be unique." + raise ValueError(msg) + if 'comp' in xa.coords: + for comp in xa['comp'].values: + if not isinstance(comp, str): + msg = "The values of 'comp' must be a string." + raise ValueError(msg) + elif comp not in ['x', 'y', 'z']: + msg = "The values of 'comp' must be either "\ + "'x', 'y', or 'z'." + raise ValueError(msg) + + for i in 'xyz': + if xa[i].values.size != 1: + if not np.allclose(np.diff(xa[i].values), + np.diff(xa[i].values).mean()): + msg = f'Co-ordinates of {i} must be'\ + ' equally spaced.' + raise ValueError(msg) + + if xa.values.dtype not in [np.float64, np.complex128]: + msg = "DataArray values must be either "\ + "np.float64 or np.complex128." + raise ValueError(msg) + + cell = tuple() + p1 = tuple() + p2 = tuple() + for i in 'xyz': + dec = 5 # minimum decimal places to round to. + + if xa[i].values.size > 1: + diff = np.diff(xa[i].values).mean() + else: + diff = np.float64(1e-9) # imput value for cell dimension. + + exp = np.log10(np.abs(diff)) + if exp < 0: + dec = dec + int(np.abs(exp).round()) + + diff = diff.round(decimals=dec) + cell = cell + (abs(diff),) + p1 = p1 + ((xa[i].values[0] - diff * 0.5).round(decimals=dec),) + p2 = p2 + ((xa[i].values[-1] + diff * 0.5).round(decimals=dec),) + + mesh = df.Mesh(p1=p1, p2=p2, cell=cell, + attributes={'unit': xa['x'].attrs['units']}) + + if 'comp' in xa.coords: + return cls(mesh=mesh, + dim=xa['comp'].values.size, + value=xa.values, + components=xa['comp'].values, + dtype=xa.values.dtype) + elif xa.ndim == 3: + return cls(mesh=mesh, + dim=1, + value=np.expand_dims(xa.values, axis=-1), + dtype=xa.values.dtype) + + else: + return cls(mesh=mesh, + dim=xa['comp'].values.size, + value=xa.values, + dtype=xa.values.dtype) From 6bf86ff16b0387d8657236bfc6f82de6ec5ef426 Mon Sep 17 00:00:00 2001 From: swapneelap Date: Wed, 16 Feb 2022 16:09:35 +0530 Subject: [PATCH 29/54] Fix(Field): import decimal not required --- discretisedfield/field.py | 1 - 1 file changed, 1 deletion(-) diff --git a/discretisedfield/field.py b/discretisedfield/field.py index 4bf66e9a4..235468a9d 100644 --- a/discretisedfield/field.py +++ b/discretisedfield/field.py @@ -8,7 +8,6 @@ import numpy as np import xarray as xr import pandas as pd -import decimal as dc import discretisedfield as df import discretisedfield.plotting as dfp From f8d6b97358c8aea993806b8f54fe23e0dac95972 Mon Sep 17 00:00:00 2001 From: swapneelap Date: Thu, 17 Feb 2022 12:37:10 +0530 Subject: [PATCH 30/54] Refactor(Field): address @marijanbeg and @lang-m comments --- discretisedfield/field.py | 86 ++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 52 deletions(-) diff --git a/discretisedfield/field.py b/discretisedfield/field.py index 235468a9d..684e84248 100644 --- a/discretisedfield/field.py +++ b/discretisedfield/field.py @@ -3603,49 +3603,40 @@ def to_xarray(self, name='field', units=None): @classmethod def from_xarray(cls, xa): if not isinstance(xa, xr.DataArray): - msg = "Argument must be a xr.DataArray." - raise TypeError(msg) + raise TypeError("Argument must be a xr.DataArray.") if xa.ndim not in [3, 4]: - msg = "DataArray dimensions must be 3 or 4." - raise ValueError(msg) + raise ValueError("DataArray dimensions must be 3 for a scalar " + "and 4 for a vector field.") + + if xa.ndim == 3 and any(dim not in 'xyz' for dim in xa.dims): + raise ValueError("The dimensions must be 'x', 'y', and 'z'.") + elif (xa.ndim == 4 and + any(dim not in ['x', 'y', 'z', 'comp'] for dim in xa.dims)): + raise ValueError("The dimensions must be 'x', 'y', 'z'" + "and 'comp'.") - if xa.ndim == 3: - for dim in xa.dims: - if dim not in ['x', 'y', 'z']: - msg = "The dimensions must be either 'x', 'y', or 'z'." - raise ValueError(msg) - elif xa.ndim == 4: - for dim in xa.dims: - if dim not in ['x', 'y', 'z', 'comp']: - msg = "The dimensions must be either "\ - "'x', 'y', 'z' or 'comp'." - raise ValueError(msg) + if 'comp' in xa.coords: if xa['comp'].values.size != len(set(xa['comp'].values)): - msg = "All the components should be unique." - raise ValueError(msg) - if 'comp' in xa.coords: - for comp in xa['comp'].values: - if not isinstance(comp, str): - msg = "The values of 'comp' must be a string." - raise ValueError(msg) - elif comp not in ['x', 'y', 'z']: - msg = "The values of 'comp' must be either "\ - "'x', 'y', or 'z'." - raise ValueError(msg) + raise ValueError("All the components must be unique.") + + for comp in xa['comp'].values: + if not isinstance(comp, str): + raise ValueError("The values of 'comp' must be strings.") + elif comp not in 'xyz': + raise ValueError("The values of 'comp' must be either " + "'x', 'y', or 'z'.") for i in 'xyz': if xa[i].values.size != 1: if not np.allclose(np.diff(xa[i].values), np.diff(xa[i].values).mean()): - msg = f'Co-ordinates of {i} must be'\ - ' equally spaced.' - raise ValueError(msg) + raise ValueError(f'Co-ordinates of {i} must be' + ' equally spaced.') if xa.values.dtype not in [np.float64, np.complex128]: - msg = "DataArray values must be either "\ - "np.float64 or np.complex128." - raise ValueError(msg) + raise ValueError("DataArray values must be either " + "np.float64 or np.complex128.") cell = tuple() p1 = tuple() @@ -3656,7 +3647,7 @@ def from_xarray(cls, xa): if xa[i].values.size > 1: diff = np.diff(xa[i].values).mean() else: - diff = np.float64(1e-9) # imput value for cell dimension. + diff = np.float64(1e-9) # impute value for cell dimension. exp = np.log10(np.abs(diff)) if exp < 0: @@ -3668,22 +3659,13 @@ def from_xarray(cls, xa): p2 = p2 + ((xa[i].values[-1] + diff * 0.5).round(decimals=dec),) mesh = df.Mesh(p1=p1, p2=p2, cell=cell, - attributes={'unit': xa['x'].attrs['units']}) - - if 'comp' in xa.coords: - return cls(mesh=mesh, - dim=xa['comp'].values.size, - value=xa.values, - components=xa['comp'].values, - dtype=xa.values.dtype) - elif xa.ndim == 3: - return cls(mesh=mesh, - dim=1, - value=np.expand_dims(xa.values, axis=-1), - dtype=xa.values.dtype) - - else: - return cls(mesh=mesh, - dim=xa['comp'].values.size, - value=xa.values, - dtype=xa.values.dtype) + attributes={'unit': xa['z'].attrs['units']}) + + comp = xa.comp.values if 'comp' in xa.coords else None + val = np.expand_dims(xa.values, axis=-1) if xa.ndim == 3 else xa.values + dim = 1 if xa.ndim == 3 else val.shape[-1] + return cls(mesh=mesh, + dim=dim, + value=val, + components=comp, + dtype=xa.values.dtype) From 330f39b18910c32d55897ec14aee04100cef53ff Mon Sep 17 00:00:00 2001 From: swapneelap Date: Thu, 17 Feb 2022 19:07:33 +0530 Subject: [PATCH 31/54] Refactor(Field): address comments --- discretisedfield/field.py | 75 +++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 42 deletions(-) diff --git a/discretisedfield/field.py b/discretisedfield/field.py index 684e84248..98f361b58 100644 --- a/discretisedfield/field.py +++ b/discretisedfield/field.py @@ -3538,26 +3538,12 @@ def to_xarray(self, name='field', units=None): >>> xa ... - Coordinates: - * x (x) float64 0.5 1.5 2.5 3.5 4.5 5.5 6.5 7.5 8.5 9.5 - * y (y) float64 0.5 1.5 2.5 3.5 4.5 5.5 6.5 7.5 8.5 9.5 - * z (z) float64 0.5 1.5 2.5 3.5 4.5 5.5 6.5 7.5 8.5 9.5 - * comp (comp) >> xa.sel(comp='x') ... - Coordinates: - * x (x) float64 0.5 1.5 2.5 3.5 4.5 5.5 6.5 7.5 8.5 9.5 - * y (y) float64 0.5 1.5 2.5 3.5 4.5 5.5 6.5 7.5 8.5 9.5 - * z (z) float64 0.5 1.5 2.5 3.5 4.5 5.5 6.5 7.5 8.5 9.5 - comp 1: diff = np.diff(xa[i].values).mean() + if rounding: + diff = diff.round(decimals=dec) else: - diff = np.float64(1e-9) # impute value for cell dimension. + diff = xa.attrs['cell'][i] - exp = np.log10(np.abs(diff)) - if exp < 0: - dec = dec + int(np.abs(exp).round()) + p1_coord = (xa[i].values[0] - diff * 0.5) + p2_coord = (xa[i].values[-1] + diff * 0.5) + if rounding: + p1_coord = p1_coord.round(decimals=dec) + p2_coord = p2_coord.round(decimals=dec) - diff = diff.round(decimals=dec) cell = cell + (abs(diff),) - p1 = p1 + ((xa[i].values[0] - diff * 0.5).round(decimals=dec),) - p2 = p2 + ((xa[i].values[-1] + diff * 0.5).round(decimals=dec),) + p1 = p1 + (p1_coord,) + p2 = p2 + (p2_coord,) - mesh = df.Mesh(p1=p1, p2=p2, cell=cell, - attributes={'unit': xa['z'].attrs['units']}) + if any('units' not in xa[i].attrs for i in 'xyz'): + mesh = df.Mesh(p1=p1, p2=p2, cell=cell) + else: + mesh = df.Mesh(p1=p1, p2=p2, cell=cell, + attributes={'unit': xa['z'].attrs['units']}) comp = xa.comp.values if 'comp' in xa.coords else None val = np.expand_dims(xa.values, axis=-1) if xa.ndim == 3 else xa.values From fd963e3d75919653bac1e4f961c0ff49e5016ea4 Mon Sep 17 00:00:00 2001 From: swapneelap Date: Thu, 17 Feb 2022 19:08:43 +0530 Subject: [PATCH 32/54] Test(Field): address comments --- discretisedfield/tests/test_field.py | 87 +++++++++++----------------- 1 file changed, 33 insertions(+), 54 deletions(-) diff --git a/discretisedfield/tests/test_field.py b/discretisedfield/tests/test_field.py index e8181899e..1eb43fdc0 100644 --- a/discretisedfield/tests/test_field.py +++ b/discretisedfield/tests/test_field.py @@ -2281,26 +2281,31 @@ def test_from_xarray_valid_args(self): f6d_new = df.Field.from_xarray(f6d_xa) assert f6d_new == f6d # or use allclose() + good_darray1 = xr.DataArray(np.ones((20, 20, 5, 3)), + dims=['x', 'y', 'z', 'comp'], + coords=dict(x=np.arange(0, 20), + y=np.arange(0, 20), + z=np.arange(0, 5), + comp=['x', 'y', 'z']), + name='mag', + attrs=dict(units='A/m')) + + good_darray2 = xr.DataArray(np.ones((20, 20, 1, 3)), + dims=['x', 'y', 'z', 'comp'], + coords=dict(x=np.arange(0, 20), + y=np.arange(0, 20), + z=[5.0], + comp=['x', 'y', 'z']), + name='mag', + attrs=dict(units='A/m', + cell=dict(x=1., y=1., z=1.))) + + f = df.Field.from_xarray(good_darray1) + f = df.Field.from_xarray(good_darray2) + def test_from_xarray_invalid_args_and_DataArrays(self): args = [int(), float(), str(), list(), dict(), xr.Dataset(), np.empty((20, 20, 20, 3))] - bad_value1 = xr.DataArray(np.ones((20, 20, 5, 3), dtype=np.int8), - dims=['x', 'y', 'z', 'comp'], - coords=dict(x=np.arange(0, 20), - y=np.arange(0, 20), - z=np.arange(0, 5), - comp=['x', 'y', 'z']), - name='mag', - attrs=dict(units='A/m')) - - bad_value2 = xr.DataArray(np.ones((20, 20, 5, 3), dtype=str), - dims=['x', 'y', 'z', 'comp'], - coords=dict(x=np.arange(0, 20), - y=np.arange(0, 20), - z=np.arange(0, 5), - comp=['x', 'y', 'z']), - name='mag', - attrs=dict(units='A/m')) bad_dim_no = xr.DataArray(np.ones((20, 20, 20, 5, 3), dtype=float), dims=['x', 'y', 'z', 'a', 'comp'], @@ -2336,6 +2341,15 @@ def test_from_xarray_invalid_args_and_DataArrays(self): name='mag', attrs=dict(units='A/m')) + bad_attrs = xr.DataArray(np.ones((20, 20, 1, 3), dtype=float), + dims=['x', 'y', 'z', 'comp'], + coords=dict(x=np.arange(0, 20), + y=np.arange(0, 20), + z=[5.0], + comp=['x', 'y', 'z']), + name='mag', + attrs=dict(units='A/m')) + def bad_coord_gen(): rng = np.random.default_rng() for coord in 'xyz': @@ -2350,40 +2364,9 @@ def bad_coord_gen(): name='mag', attrs=dict(units='A/m')) - bad_coord_comp1 = xr.DataArray(np.ones((20, 20, 20, 3), dtype=float), - dims=['x', 'y', 'z', 'comp'], - coords=dict(x=np.arange(0, 20), - y=np.arange(0, 20), - z=np.arange(0, 20), - comp=['x', 'x', 'z']), - name='mag', - attrs=dict(units='A/m')) - - bad_coord_comp2 = xr.DataArray(np.ones((20, 20, 20, 3), dtype=float), - dims=['x', 'y', 'z', 'comp'], - coords=dict(x=np.arange(0, 20), - y=np.arange(0, 20), - z=np.arange(0, 20), - comp=['a', 'b', 'c']), - name='mag', - attrs=dict(units='A/m')) - - bad_coord_comp3 = xr.DataArray(np.ones((20, 20, 20, 3), dtype=float), - dims=['x', 'y', 'z', 'comp'], - coords=dict(x=np.arange(0, 20), - y=np.arange(0, 20), - z=np.arange(0, 20), - comp=[1, 2, 3]), - name='mag', - attrs=dict(units='A/m')) - for arg in args: with pytest.raises(TypeError): f = df.Field.from_xarray(arg) - with pytest.raises(ValueError): - f = df.Field.from_xarray(bad_value1) - with pytest.raises(ValueError): - f = df.Field.from_xarray(bad_value2) with pytest.raises(ValueError): f = df.Field.from_xarray(bad_dim_no) with pytest.raises(ValueError): @@ -2395,9 +2378,5 @@ def bad_coord_gen(): for bad_coord_geo in bad_coord_gen(): with pytest.raises(ValueError): f = df.Field.from_xarray(bad_coord_geo) - with pytest.raises(ValueError): - f = df.Field.from_xarray(bad_coord_comp1) - with pytest.raises(ValueError): - f = df.Field.from_xarray(bad_coord_comp2) - with pytest.raises(ValueError): - f = df.Field.from_xarray(bad_coord_comp3) + with pytest.raises(KeyError): + f = df.Field.from_xarray(bad_attrs) From dd0c59616ede6f7a5a6b96c2d9bc0c205deb889f Mon Sep 17 00:00:00 2001 From: Martin Lang Date: Thu, 17 Feb 2022 18:08:32 +0100 Subject: [PATCH 33/54] Rewrite creation of cell, p1, and p2. --- discretisedfield/field.py | 58 +++++++++++++++------------------------ 1 file changed, 22 insertions(+), 36 deletions(-) diff --git a/discretisedfield/field.py b/discretisedfield/field.py index 98f361b58..1a93a3204 100644 --- a/discretisedfield/field.py +++ b/discretisedfield/field.py @@ -3602,49 +3602,35 @@ def from_xarray(cls, xa): if xa.ndim == 3 and sorted(xa.dims) != ['x', 'y', 'z']: raise ValueError("The dimensions must be 'x', 'y', and 'z'.") elif xa.ndim == 4 and sorted(xa.dims) != ['comp', 'x', 'y', 'z']: - raise ValueError("The dimensions must be 'x', 'y', 'z'" + raise ValueError("The dimensions must be 'x', 'y', 'z'," "and 'comp'.") for i in 'xyz': - if xa[i].values.size != 1: - if not np.allclose(np.diff(xa[i].values), - np.diff(xa[i].values).mean()): - raise ValueError(f'Co-ordinates of {i} must be' - ' equally spaced.') - - if ( - any(i == 1 for i in xa.values.shape[:3]) and - 'cell' not in xa.attrs - ): - raise KeyError("DataArray must have a 'cell' attribute if any " - "of the geometric directions has a single cell.") - - cell = tuple() - p1 = tuple() - p2 = tuple() - for i in 'xyz': - rounding = True + if xa[i].values.size > 1 and not np.allclose( + np.diff(xa[i].values), np.diff(xa[i].values).mean()): + raise ValueError(f'Co-ordinates of {i} must be' + ' equally spaced.') + + def round_(value): try: - dec = np.finfo(xa[i].values.dtype).precision + dec = np.finfo(np.asarray(value).dtype).precision except ValueError: - rounding = False - - if xa[i].values.size > 1: - diff = np.diff(xa[i].values).mean() - if rounding: - diff = diff.round(decimals=dec) - else: - diff = xa.attrs['cell'][i] + return value + return np.round(value, dec) - p1_coord = (xa[i].values[0] - diff * 0.5) - p2_coord = (xa[i].values[-1] + diff * 0.5) - if rounding: - p1_coord = p1_coord.round(decimals=dec) - p2_coord = p2_coord.round(decimals=dec) + if any(len_ == 1 for len_ in xa.values.shape[:3]): + try: + cell = xa.attrs['cell'] + except KeyError: + raise KeyError( + "DataArray must have a 'cell' attribute if any " + "of the geometric directions has a single cell." + ) from None + else: + cell = [round_(np.diff(xa[i].values).mean()) for i in 'xyz'] - cell = cell + (abs(diff),) - p1 = p1 + (p1_coord,) - p2 = p2 + (p2_coord,) + p1 = round_([xa[i].values[0] - cell[i] / 2 for i in 'xyz']) + p2 = round_([xa[i].values[-1] + cell[i] / 2 for i in 'xyz']) if any('units' not in xa[i].attrs for i in 'xyz'): mesh = df.Mesh(p1=p1, p2=p2, cell=cell) From 41131c06a1d0f7f82bd8b8081ce3ec6efb417dda Mon Sep 17 00:00:00 2001 From: Martin Lang Date: Thu, 17 Feb 2022 18:23:07 +0100 Subject: [PATCH 34/54] Fix wrong indexing type. --- discretisedfield/field.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/discretisedfield/field.py b/discretisedfield/field.py index 1a93a3204..0941a953b 100644 --- a/discretisedfield/field.py +++ b/discretisedfield/field.py @@ -3629,8 +3629,10 @@ def round_(value): else: cell = [round_(np.diff(xa[i].values).mean()) for i in 'xyz'] - p1 = round_([xa[i].values[0] - cell[i] / 2 for i in 'xyz']) - p2 = round_([xa[i].values[-1] + cell[i] / 2 for i in 'xyz']) + p1 = round_([xa[d].values[0] - cell[i] / 2 + for i, d in enumerate('xyz')]) + p2 = round_([xa[d].values[-1] + cell[i] / 2 + for i, d in enumerate('xyz')]) if any('units' not in xa[i].attrs for i in 'xyz'): mesh = df.Mesh(p1=p1, p2=p2, cell=cell) From 6a461ca837604447e48c4471589457393e753919 Mon Sep 17 00:00:00 2001 From: Martin Lang Date: Thu, 17 Feb 2022 18:31:28 +0100 Subject: [PATCH 35/54] Store cell as-is instead of in a new dictionary. --- discretisedfield/field.py | 12 +++--------- discretisedfield/tests/test_field.py | 2 +- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/discretisedfield/field.py b/discretisedfield/field.py index 0941a953b..b56fd26c7 100644 --- a/discretisedfield/field.py +++ b/discretisedfield/field.py @@ -3555,10 +3555,6 @@ def to_xarray(self, name='field', units=None): raise TypeError(msg) axes = ['x', 'y', 'z'] - cell_attr = None - - if any(i == 1 for i in self.array.shape[:3]): - cell_attr = {axes[i]: self.mesh.cell[i] for i in range(3)} data_array_coords = { axis: np.fromiter(self.mesh.axis_points(axis), dtype=float) @@ -3583,7 +3579,7 @@ def to_xarray(self, name='field', units=None): dims=data_array_dims, coords=data_array_coords, name=name, - attrs=dict(units=units, cell=cell_attr)) + attrs=dict(units=units, cell=self.mesh.cell)) for dim in geo_units_dict: data_array[dim].attrs['units'] = geo_units_dict[dim] @@ -3629,10 +3625,8 @@ def round_(value): else: cell = [round_(np.diff(xa[i].values).mean()) for i in 'xyz'] - p1 = round_([xa[d].values[0] - cell[i] / 2 - for i, d in enumerate('xyz')]) - p2 = round_([xa[d].values[-1] + cell[i] / 2 - for i, d in enumerate('xyz')]) + p1 = round_([xa[i].values[0] - c / 2 for i, c in zip('xyz', cell)]) + p2 = round_([xa[i].values[-1] + c / 2 for i, c in zip('xyz', cell)]) if any('units' not in xa[i].attrs for i in 'xyz'): mesh = df.Mesh(p1=p1, p2=p2, cell=cell) diff --git a/discretisedfield/tests/test_field.py b/discretisedfield/tests/test_field.py index 1eb43fdc0..b29063685 100644 --- a/discretisedfield/tests/test_field.py +++ b/discretisedfield/tests/test_field.py @@ -2298,7 +2298,7 @@ def test_from_xarray_valid_args(self): comp=['x', 'y', 'z']), name='mag', attrs=dict(units='A/m', - cell=dict(x=1., y=1., z=1.))) + cell=[1., 1., 1.])) f = df.Field.from_xarray(good_darray1) f = df.Field.from_xarray(good_darray2) From deeaa46313dd13ae7ec66e355ec07b9c42fde4ab Mon Sep 17 00:00:00 2001 From: Martin Lang Date: Thu, 17 Feb 2022 18:32:48 +0100 Subject: [PATCH 36/54] Unused variable --- discretisedfield/tests/test_field.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/discretisedfield/tests/test_field.py b/discretisedfield/tests/test_field.py index b29063685..c8c7a7efe 100644 --- a/discretisedfield/tests/test_field.py +++ b/discretisedfield/tests/test_field.py @@ -2255,7 +2255,7 @@ def test_to_xarray_invalid_args(self): for name, units in args: with pytest.raises(TypeError): - fxa = self.pf.to_xarray(name, units) + self.pf.to_xarray(name, units) def test_from_xarray_valid_args(self): for mesh in self.meshes: From da4ea0d792bc594afc294f74ecd014b0115be18a Mon Sep 17 00:00:00 2001 From: swapneelap Date: Fri, 18 Feb 2022 11:59:45 +0530 Subject: [PATCH 37/54] Test(Field): add cell attribute tests for to_xarray --- discretisedfield/tests/test_field.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/discretisedfield/tests/test_field.py b/discretisedfield/tests/test_field.py index b29063685..144704391 100644 --- a/discretisedfield/tests/test_field.py +++ b/discretisedfield/tests/test_field.py @@ -2206,8 +2206,9 @@ def test_to_xarray_valid_args(self): for value, dtype in self.vfuncs: f = df.Field(mesh, dim=3, value=value, dtype=dtype) fxa = f.to_xarray() - assert f.dim == fxa['comp'].size assert isinstance(fxa, xr.DataArray) + assert f.dim == fxa['comp'].size + assert 'cell' in fxa.attrs for i in 'xyz': assert np.array_equal( np.array(list(f.mesh.axis_points(i))), @@ -2221,6 +2222,7 @@ def test_to_xarray_valid_args(self): f = df.Field(mesh, dim=1, value=value, dtype=dtype) fxa = f.to_xarray() assert isinstance(fxa, xr.DataArray) + assert 'cell' in fxa.attrs for i in 'xyz': assert np.array_equal( np.array(list(f.mesh.axis_points(i))), From 9b4bc595949e0f265a0d27840ea4460f237e121a Mon Sep 17 00:00:00 2001 From: swapneelap Date: Mon, 21 Feb 2022 11:00:51 +0530 Subject: [PATCH 38/54] Refactor(Field): update to_xarray and from_xarray Add p1 and p2 attributes to DataArray generated by to_xarray method and, by default, utilize them to recreate mesh in from_xarray. Also, remove rounding in from_xarray. --- discretisedfield/field.py | 41 +++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/discretisedfield/field.py b/discretisedfield/field.py index b56fd26c7..762224c31 100644 --- a/discretisedfield/field.py +++ b/discretisedfield/field.py @@ -3487,9 +3487,11 @@ def to_xarray(self, name='field', units=None): The function returns an ``xarray.DataArray`` with dimensions ``x``, ``y``, ``z``, and ``comp`` (``only if field.dim > 1``). The coordinates of the geometric dimensions are derived from ``self.mesh.axis_points``, - and for vector field components from ``self.components``. The ``units`` - attribute of geometric dimensions is set to - ``self.mesh.attributes['unit']``. + and for vector field components from ``self.components``. Addtionally, + the values of ``self.mesh.cell``, ``self.mesh.region.p1``, and + ``self.mesh.region.p2`` are stored as ``cell``, ``p1``, and ``p2`` + attributes of the DataArray. The ``units`` attribute of geometric + dimensions is set to ``self.mesh.attributes['unit']``. The name and units of the field ``DataArray`` can be set by passing ``name`` and ``units``. If the type of value passed to any of the two @@ -3579,7 +3581,10 @@ def to_xarray(self, name='field', units=None): dims=data_array_dims, coords=data_array_coords, name=name, - attrs=dict(units=units, cell=self.mesh.cell)) + attrs=dict(units=units, + cell=self.mesh.cell, + p1=self.mesh.region.p1, + p2=self.mesh.region.p2)) for dim in geo_units_dict: data_array[dim].attrs['units'] = geo_units_dict[dim] @@ -3604,17 +3609,13 @@ def from_xarray(cls, xa): for i in 'xyz': if xa[i].values.size > 1 and not np.allclose( np.diff(xa[i].values), np.diff(xa[i].values).mean()): - raise ValueError(f'Co-ordinates of {i} must be' + raise ValueError(f'Coordinates of {i} must be' ' equally spaced.') - def round_(value): - try: - dec = np.finfo(np.asarray(value).dtype).precision - except ValueError: - return value - return np.round(value, dec) - - if any(len_ == 1 for len_ in xa.values.shape[:3]): + if ( + 'cell' in xa.attrs or + any(len_ == 1 for len_ in xa.values.shape[:3]) + ): try: cell = xa.attrs['cell'] except KeyError: @@ -3623,10 +3624,16 @@ def round_(value): "of the geometric directions has a single cell." ) from None else: - cell = [round_(np.diff(xa[i].values).mean()) for i in 'xyz'] - - p1 = round_([xa[i].values[0] - c / 2 for i, c in zip('xyz', cell)]) - p2 = round_([xa[i].values[-1] + c / 2 for i, c in zip('xyz', cell)]) + cell = [np.diff(xa[i].values).mean() for i in 'xyz'] + + p1 = ( + xa.attrs['p1'] if 'p1' in xa.attrs else + [xa[i].values[0] - c / 2 for i, c in zip('xyz', cell)] + ) + p2 = ( + xa.attrs['p2'] if 'p2' in xa.attrs else + [xa[i].values[-1] + c / 2 for i, c in zip('xyz', cell)] + ) if any('units' not in xa[i].attrs for i in 'xyz'): mesh = df.Mesh(p1=p1, p2=p2, cell=cell) From b2e2a2fa04027604e80ce90430af4b1cd57c8a2d Mon Sep 17 00:00:00 2001 From: swapneelap Date: Mon, 21 Feb 2022 11:07:14 +0530 Subject: [PATCH 39/54] Test(Field): update test for to_xarray and from_xarray --- discretisedfield/tests/test_field.py | 30 ++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/discretisedfield/tests/test_field.py b/discretisedfield/tests/test_field.py index ffc21fae3..974f5eb42 100644 --- a/discretisedfield/tests/test_field.py +++ b/discretisedfield/tests/test_field.py @@ -2208,7 +2208,10 @@ def test_to_xarray_valid_args(self): fxa = f.to_xarray() assert isinstance(fxa, xr.DataArray) assert f.dim == fxa['comp'].size - assert 'cell' in fxa.attrs + assert sorted([*fxa.attrs]) == ['cell', 'p1', 'p2', 'units'] + assert fxa.attrs['cell'] == f.mesh.cell + assert fxa.attrs['p1'] == f.mesh.region.p1 + assert fxa.attrs['p2'] == f.mesh.region.p2 for i in 'xyz': assert np.array_equal( np.array(list(f.mesh.axis_points(i))), @@ -2222,7 +2225,10 @@ def test_to_xarray_valid_args(self): f = df.Field(mesh, dim=1, value=value, dtype=dtype) fxa = f.to_xarray() assert isinstance(fxa, xr.DataArray) - assert 'cell' in fxa.attrs + assert sorted([*fxa.attrs]) == ['cell', 'p1', 'p2', 'units'] + assert fxa.attrs['cell'] == f.mesh.cell + assert fxa.attrs['p1'] == f.mesh.region.p1 + assert fxa.attrs['p2'] == f.mesh.region.p2 for i in 'xyz': assert np.array_equal( np.array(list(f.mesh.axis_points(i))), @@ -2302,8 +2308,24 @@ def test_from_xarray_valid_args(self): attrs=dict(units='A/m', cell=[1., 1., 1.])) - f = df.Field.from_xarray(good_darray1) - f = df.Field.from_xarray(good_darray2) + good_darray3 = xr.DataArray(np.ones((20, 20, 1, 3)), + dims=['x', 'y', 'z', 'comp'], + coords=dict(x=np.arange(0, 20), + y=np.arange(0, 20), + z=[5.0], + comp=['x', 'y', 'z']), + name='mag', + attrs=dict(units='A/m', + cell=[1., 1., 1.], + p1=[1., 1., 1.], + p2=[21., 21., 2.])) + + fg_1 = df.Field.from_xarray(good_darray1) + check_field(fg_1) + fg_2 = df.Field.from_xarray(good_darray2) + check_field(fg_2) + fg_3 = df.Field.from_xarray(good_darray3) + check_field(fg_3) def test_from_xarray_invalid_args_and_DataArrays(self): args = [int(), float(), str(), list(), dict(), xr.Dataset(), From e3e4645e1a344b4765140ffb8138814d0ffbeba7 Mon Sep 17 00:00:00 2001 From: swapneelap Date: Mon, 21 Feb 2022 16:44:58 +0530 Subject: [PATCH 40/54] Chore(Field): add docstrings to from_xarray --- discretisedfield/field.py | 86 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/discretisedfield/field.py b/discretisedfield/field.py index 762224c31..e9e5c206a 100644 --- a/discretisedfield/field.py +++ b/discretisedfield/field.py @@ -3593,6 +3593,92 @@ def to_xarray(self, name='field', units=None): @classmethod def from_xarray(cls, xa): + """Create Field from ``xarray.DataArray`` + + The class method accepts an ``xarray.DataArray`` as an argument to + return a ``discretisedfield.Field`` object. The DataArray must have + either three (``x``, ``y``, and ``z`` for a scalar field) or four + (additionally ``comp`` for a vector field) dimensions corresponding to + geometric axes and components of the field, respectively. The + coordinates of the ``x``, ``y`` and ``z`` dimensions represent the + discretisation along the respective axis and must have equally spaced + values. The coordinates of ``comp`` represent the field components + (for eg. ['x', 'y', 'z']). + + The DataArray is expected to have ``cell``, ``p1`` and ``p2`` + attributes for creating ``discretisedfield.Mesh`` required by the + ``discretisedfield.Field`` object. However, in the absence of these + attributes, the coordinates of ``x``, ``y``, and ``z`` dimensions are + utilized. It should be noted that ``cell`` attribute is a must if any + of the geometric directions has only a single cell. + + Failing to meet the above mentioned conditions will lead to a KeyError + in the absence of ``cell`` attribute or a ValueError for the rest. + TypeError is raised if input argument is not an ``xarray.DataArray``. + + Parameters + ---------- + xa : xarray.DataArray + + DataArray to create Field. + + Returns + ------- + discretisedfield.Field + + Field created from DataArray. + + Raises + ------ + TypeError + + If argument is not ``xarray.DataArray``. + + KeyError + + If at least one of the geometric dimension has only a single cell + and ``cell`` attribute is absent. + + ValueError + + - If ``DataArray.ndim`` is not 3 or 4. + - If ``DataArray.dims`` are not either ``['x', 'y', 'z']`` or + ``['x', 'y', 'z', 'comp']`` + - If coordinates of any ``x``, ``y`` or ``z`` are not equally + spaced + + Examples + -------- + 1. Create a DataArray + + >>> import xarray as xr + >>> import numpy as np + ... + >>> xa = xr.DataArray(np.ones((20, 20, 20, 3), dtype=float), + ... dims = ['x', 'y', 'z', 'comp'], + ... coords = dict(x=np.arange(0, 20), + ... y=np.arange(0, 20), + ... z=np.arange(0, 20), + ... comp=['x', 'y', 'z']), + ... name = 'mag', + ... attrs = dict(cell=[1., 1., 1.], + ... p1=[1., 1., 1.], + ... p2=[21., 21., 21.])) + >>> xa + + ... + + 2. Create Field from DataArray + + >>> import discretisedfield as df + ... + >>> fld = df.Field.from_xarray(xa) + >>> fld + Field(...) + >>> fld.average + (1.0, 1.0, 1.0) + + """ if not isinstance(xa, xr.DataArray): raise TypeError("Argument must be a xr.DataArray.") From 98aa4f2d2f9d871651ee589befa7c7531de3c727 Mon Sep 17 00:00:00 2001 From: Martin Lang <67915889+lang-m@users.noreply.github.com> Date: Mon, 21 Feb 2022 13:38:11 +0100 Subject: [PATCH 41/54] Update field.py --- discretisedfield/field.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/discretisedfield/field.py b/discretisedfield/field.py index e9e5c206a..d93972259 100644 --- a/discretisedfield/field.py +++ b/discretisedfield/field.py @@ -3600,17 +3600,17 @@ def from_xarray(cls, xa): either three (``x``, ``y``, and ``z`` for a scalar field) or four (additionally ``comp`` for a vector field) dimensions corresponding to geometric axes and components of the field, respectively. The - coordinates of the ``x``, ``y`` and ``z`` dimensions represent the + coordinates of the ``x``, ``y``, and ``z`` dimensions represent the discretisation along the respective axis and must have equally spaced values. The coordinates of ``comp`` represent the field components (for eg. ['x', 'y', 'z']). - The DataArray is expected to have ``cell``, ``p1`` and ``p2`` + The ``DataArray`` is expected to have ``cell``, ``p1``, and ``p2`` attributes for creating ``discretisedfield.Mesh`` required by the ``discretisedfield.Field`` object. However, in the absence of these attributes, the coordinates of ``x``, ``y``, and ``z`` dimensions are - utilized. It should be noted that ``cell`` attribute is a must if any - of the geometric directions has only a single cell. + utilized. It should be noted that ``cell`` attribute is required if + any of the geometric directions has only a single cell. Failing to meet the above mentioned conditions will lead to a KeyError in the absence of ``cell`` attribute or a ValueError for the rest. @@ -3644,7 +3644,7 @@ def from_xarray(cls, xa): - If ``DataArray.ndim`` is not 3 or 4. - If ``DataArray.dims`` are not either ``['x', 'y', 'z']`` or ``['x', 'y', 'z', 'comp']`` - - If coordinates of any ``x``, ``y`` or ``z`` are not equally + - If coordinates of ``x``, ``y``, or ``z`` are not equally spaced Examples From 1c07e0492f605d73af0f698a1933d23c16e0cb70 Mon Sep 17 00:00:00 2001 From: swapneelap Date: Tue, 22 Feb 2022 11:02:54 +0530 Subject: [PATCH 42/54] Refactor(Field): address comments by @lang-m --- discretisedfield/field.py | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/discretisedfield/field.py b/discretisedfield/field.py index d93972259..66775d8ae 100644 --- a/discretisedfield/field.py +++ b/discretisedfield/field.py @@ -3593,7 +3593,7 @@ def to_xarray(self, name='field', units=None): @classmethod def from_xarray(cls, xa): - """Create Field from ``xarray.DataArray`` + """Create ``discretisedfield.Field`` from ``xarray.DataArray`` The class method accepts an ``xarray.DataArray`` as an argument to return a ``discretisedfield.Field`` object. The DataArray must have @@ -3603,7 +3603,7 @@ def from_xarray(cls, xa): coordinates of the ``x``, ``y``, and ``z`` dimensions represent the discretisation along the respective axis and must have equally spaced values. The coordinates of ``comp`` represent the field components - (for eg. ['x', 'y', 'z']). + (e.g. ['x', 'y', 'z']). The ``DataArray`` is expected to have ``cell``, ``p1``, and ``p2`` attributes for creating ``discretisedfield.Mesh`` required by the @@ -3612,10 +3612,6 @@ def from_xarray(cls, xa): utilized. It should be noted that ``cell`` attribute is required if any of the geometric directions has only a single cell. - Failing to meet the above mentioned conditions will lead to a KeyError - in the absence of ``cell`` attribute or a ValueError for the rest. - TypeError is raised if input argument is not an ``xarray.DataArray``. - Parameters ---------- xa : xarray.DataArray @@ -3636,8 +3632,8 @@ def from_xarray(cls, xa): KeyError - If at least one of the geometric dimension has only a single cell - and ``cell`` attribute is absent. + If at least one of the geometric dimension coordinates has a single + value and ``cell`` attribute is missing. ValueError @@ -3672,10 +3668,10 @@ def from_xarray(cls, xa): >>> import discretisedfield as df ... - >>> fld = df.Field.from_xarray(xa) - >>> fld + >>> field = df.Field.from_xarray(xa) + >>> field Field(...) - >>> fld.average + >>> field.average (1.0, 1.0, 1.0) """ @@ -3698,18 +3694,14 @@ def from_xarray(cls, xa): raise ValueError(f'Coordinates of {i} must be' ' equally spaced.') - if ( - 'cell' in xa.attrs or - any(len_ == 1 for len_ in xa.values.shape[:3]) - ): - try: - cell = xa.attrs['cell'] - except KeyError: + try: + cell = xa.attrs['cell'] + except KeyError: + if any(len_ == 1 for len_ in xa.values.shape[:3]): raise KeyError( "DataArray must have a 'cell' attribute if any " "of the geometric directions has a single cell." ) from None - else: cell = [np.diff(xa[i].values).mean() for i in 'xyz'] p1 = ( From 79aa86c4c2b78e3b7cd16a4ab4cf89b12bcd9a40 Mon Sep 17 00:00:00 2001 From: swapneelap Date: Tue, 22 Feb 2022 11:12:17 +0530 Subject: [PATCH 43/54] Refactor(Field): address additional comments by @lang-m --- discretisedfield/field.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/discretisedfield/field.py b/discretisedfield/field.py index 66775d8ae..e6fbf0e21 100644 --- a/discretisedfield/field.py +++ b/discretisedfield/field.py @@ -3603,7 +3603,7 @@ def from_xarray(cls, xa): coordinates of the ``x``, ``y``, and ``z`` dimensions represent the discretisation along the respective axis and must have equally spaced values. The coordinates of ``comp`` represent the field components - (e.g. ['x', 'y', 'z']). + (e.g. ['x', 'y', 'z'] for a 3D vector field). The ``DataArray`` is expected to have ``cell``, ``p1``, and ``p2`` attributes for creating ``discretisedfield.Mesh`` required by the From 812876dc5f4a30814ee2e6cdec5e961d0795092c Mon Sep 17 00:00:00 2001 From: swapneelap Date: Tue, 22 Feb 2022 11:37:18 +0530 Subject: [PATCH 44/54] Test(Field): address comments by @lang-m --- discretisedfield/tests/test_field.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/discretisedfield/tests/test_field.py b/discretisedfield/tests/test_field.py index 974f5eb42..436b9a383 100644 --- a/discretisedfield/tests/test_field.py +++ b/discretisedfield/tests/test_field.py @@ -2242,6 +2242,10 @@ def test_to_xarray_valid_args(self): f6d_xa = f6d.to_xarray() assert f6d_xa['comp'].size == 6 assert 'comp' not in f6d_xa.coords + f6d.components = ['a', 'c', 'b', 'e', 'd', 'f'] + f6d_xa2 = f6d.to_xarray() + assert 'comp' in f6d_xa2.coords + assert [*f6d_xa2['comp'].values] == ['a', 'c', 'b', 'e', 'd', 'f'] # test name and units defaults f3d_xa = self.pf.to_xarray() From 9d6c75e4da7e4aab52fca830adb6249093cf096f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 1 Mar 2022 18:46:59 +0000 Subject: [PATCH 45/54] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- discretisedfield/field.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/discretisedfield/field.py b/discretisedfield/field.py index 5d68ca5b2..8b51f410b 100644 --- a/discretisedfield/field.py +++ b/discretisedfield/field.py @@ -6,9 +6,9 @@ import h5py import numpy as np -import xarray as xr import pandas as pd import ubermagutil.typesystem as ts +import xarray as xr import discretisedfield as df import discretisedfield.plotting as dfp From 639f326175318b4e338cbb0e6bd90c268a4af7d1 Mon Sep 17 00:00:00 2001 From: Martin Lang Date: Tue, 1 Mar 2022 19:48:16 +0100 Subject: [PATCH 46/54] Remove unused variable names --- discretisedfield/tests/test_field.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/discretisedfield/tests/test_field.py b/discretisedfield/tests/test_field.py index 6be115392..fa7b40b66 100644 --- a/discretisedfield/tests/test_field.py +++ b/discretisedfield/tests/test_field.py @@ -2396,17 +2396,17 @@ def bad_coord_gen(): for arg in args: with pytest.raises(TypeError): - f = df.Field.from_xarray(arg) + df.Field.from_xarray(arg) with pytest.raises(ValueError): - f = df.Field.from_xarray(bad_dim_no) + df.Field.from_xarray(bad_dim_no) with pytest.raises(ValueError): - f = df.Field.from_xarray(bad_dim_no2) + df.Field.from_xarray(bad_dim_no2) with pytest.raises(ValueError): - f = df.Field.from_xarray(bad_dim3) + df.Field.from_xarray(bad_dim3) with pytest.raises(ValueError): - f = df.Field.from_xarray(bad_dim4) + df.Field.from_xarray(bad_dim4) for bad_coord_geo in bad_coord_gen(): with pytest.raises(ValueError): - f = df.Field.from_xarray(bad_coord_geo) + df.Field.from_xarray(bad_coord_geo) with pytest.raises(KeyError): - f = df.Field.from_xarray(bad_attrs) + df.Field.from_xarray(bad_attrs) From 89fb2e7fdbc9409721bdd64f946ca4584d8510ed Mon Sep 17 00:00:00 2001 From: swapneelap Date: Tue, 22 Mar 2022 11:50:05 +0530 Subject: [PATCH 47/54] Docs(xarray-usage): Add docs for `to_xarray` and `from_xarray` --- docs/xarray-usage.ipynb | 2685 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 2685 insertions(+) create mode 100644 docs/xarray-usage.ipynb diff --git a/docs/xarray-usage.ipynb b/docs/xarray-usage.ipynb new file mode 100644 index 000000000..76beedc94 --- /dev/null +++ b/docs/xarray-usage.ipynb @@ -0,0 +1,2685 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "8d04a175", + "metadata": {}, + "source": [ + "# Importing/Exporting field from/to `xarray.DataArray`\n", + "\n", + "[`xarray`](https://docs.xarray.dev/en/stable/) provides a convenient method to handle *labeled* multi-dimensional arrays. It integrates well with `numpy` and `pandas` for fast array manipulation, as well as `matplotlib` for visualization. This makes it a good candidate to carry `discretisedfield.Field` data and additional metadata such as field name and unit (which appear in the plots rendered by `matplotlib`).\n", + "\n", + "## Exporting `discretisedfield.Field` to `xarray.DataArray`\n", + "\n", + "`to_xarray` method of the `discretisedfield.Field` object is utilized to export the field data to a DataArray." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "756dbabb", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "Field\n", + "
    \n", + " \n", + "
  • Mesh\n", + "
      \n", + "
    • Region\n", + "
        \n", + "
      • p1 = (0, 0, 0)
      • \n", + "
      • p2 = (1e-08, 1e-08, 1e-08)
      • \n", + "
    • \n", + "
    • n = (2, 2, 2)
    • \n", + "
    • attributes:\n", + "
        \n", + "
      • unit: m
      • \n", + "
      • fourierspace: False
      • \n", + "
      • isplane: False
      • \n", + "
      \n", + "
    • \n", + "
  • \n", + "
  • dim = 3
  • \n", + "
  • components:\n", + "
    • x
    • \n", + "
    • y
    • \n", + "
    • z
    • \n", + "
    \n", + "
  • \n", + "
" + ], + "text/plain": [ + "Field(Mesh(Region(p1=(0, 0, 0), p2=(1e-08, 1e-08, 1e-08)), n=(2, 2, 2), attributes: (unit: m, fourierspace: False, isplane: False)), dim=3, components: (x, y, z))" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import discretisedfield as df\n", + "\n", + "\n", + "p1 = (0, 0, 0)\n", + "p2 = (10e-9, 10e-9, 10e-9)\n", + "cell = (5e-9, 5e-9, 5e-9)\n", + "\n", + "mesh = df.Mesh(p1=p1, p2=p2, cell=cell)\n", + "field = df.Field(mesh=mesh, dim=3, value=(0, 0, 1))\n", + "field" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "705c72bc", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
<xarray.DataArray 'field' (x: 2, y: 2, z: 2, comp: 3)>\n",
+       "array([[[[0., 0., 1.],\n",
+       "         [0., 0., 1.]],\n",
+       "\n",
+       "        [[0., 0., 1.],\n",
+       "         [0., 0., 1.]]],\n",
+       "\n",
+       "\n",
+       "       [[[0., 0., 1.],\n",
+       "         [0., 0., 1.]],\n",
+       "\n",
+       "        [[0., 0., 1.],\n",
+       "         [0., 0., 1.]]]])\n",
+       "Coordinates:\n",
+       "  * x        (x) float64 2.5e-09 7.5e-09\n",
+       "  * y        (y) float64 2.5e-09 7.5e-09\n",
+       "  * z        (z) float64 2.5e-09 7.5e-09\n",
+       "  * comp     (comp) <U1 'x' 'y' 'z'\n",
+       "Attributes:\n",
+       "    units:    None\n",
+       "    cell:     (5e-09, 5e-09, 5e-09)\n",
+       "    p1:       (0, 0, 0)\n",
+       "    p2:       (1e-08, 1e-08, 1e-08)
" + ], + "text/plain": [ + "\n", + "array([[[[0., 0., 1.],\n", + " [0., 0., 1.]],\n", + "\n", + " [[0., 0., 1.],\n", + " [0., 0., 1.]]],\n", + "\n", + "\n", + " [[[0., 0., 1.],\n", + " [0., 0., 1.]],\n", + "\n", + " [[0., 0., 1.],\n", + " [0., 0., 1.]]]])\n", + "Coordinates:\n", + " * x (x) float64 2.5e-09 7.5e-09\n", + " * y (y) float64 2.5e-09 7.5e-09\n", + " * z (z) float64 2.5e-09 7.5e-09\n", + " * comp (comp) \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
<xarray.DataArray 'field' (y: 2, z: 2, comp: 3)>\n",
+       "array([[[0., 0., 1.],\n",
+       "        [0., 0., 1.]],\n",
+       "\n",
+       "       [[0., 0., 1.],\n",
+       "        [0., 0., 1.]]])\n",
+       "Coordinates:\n",
+       "    x        float64 2.5e-09\n",
+       "  * y        (y) float64 2.5e-09 7.5e-09\n",
+       "  * z        (z) float64 2.5e-09 7.5e-09\n",
+       "  * comp     (comp) <U1 'x' 'y' 'z'\n",
+       "Attributes:\n",
+       "    units:    None\n",
+       "    cell:     (5e-09, 5e-09, 5e-09)\n",
+       "    p1:       (0, 0, 0)\n",
+       "    p2:       (1e-08, 1e-08, 1e-08)
" + ], + "text/plain": [ + "\n", + "array([[[0., 0., 1.],\n", + " [0., 0., 1.]],\n", + "\n", + " [[0., 0., 1.],\n", + " [0., 0., 1.]]])\n", + "Coordinates:\n", + " x float64 2.5e-09\n", + " * y (y) float64 2.5e-09 7.5e-09\n", + " * z (z) float64 2.5e-09 7.5e-09\n", + " * comp (comp) \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
<xarray.DataArray 'field' (x: 2, y: 2, z: 2)>\n",
+       "array([[[1., 1.],\n",
+       "        [1., 1.]],\n",
+       "\n",
+       "       [[1., 1.],\n",
+       "        [1., 1.]]])\n",
+       "Coordinates:\n",
+       "  * x        (x) float64 2.5e-09 7.5e-09\n",
+       "  * y        (y) float64 2.5e-09 7.5e-09\n",
+       "  * z        (z) float64 2.5e-09 7.5e-09\n",
+       "    comp     <U1 'z'\n",
+       "Attributes:\n",
+       "    units:    None\n",
+       "    cell:     (5e-09, 5e-09, 5e-09)\n",
+       "    p1:       (0, 0, 0)\n",
+       "    p2:       (1e-08, 1e-08, 1e-08)
" + ], + "text/plain": [ + "\n", + "array([[[1., 1.],\n", + " [1., 1.]],\n", + "\n", + " [[1., 1.],\n", + " [1., 1.]]])\n", + "Coordinates:\n", + " * x (x) float64 2.5e-09 7.5e-09\n", + " * y (y) float64 2.5e-09 7.5e-09\n", + " * z (z) float64 2.5e-09 7.5e-09\n", + " comp \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
<xarray.DataArray 'field' (y: 2, z: 2)>\n",
+       "array([[1., 1.],\n",
+       "       [1., 1.]])\n",
+       "Coordinates:\n",
+       "    x        float64 2.5e-09\n",
+       "  * y        (y) float64 2.5e-09 7.5e-09\n",
+       "  * z        (z) float64 2.5e-09 7.5e-09\n",
+       "    comp     <U1 'z'\n",
+       "Attributes:\n",
+       "    units:    None\n",
+       "    cell:     (5e-09, 5e-09, 5e-09)\n",
+       "    p1:       (0, 0, 0)\n",
+       "    p2:       (1e-08, 1e-08, 1e-08)
" + ], + "text/plain": [ + "\n", + "array([[1., 1.],\n", + " [1., 1.]])\n", + "Coordinates:\n", + " x float64 2.5e-09\n", + " * y (y) float64 2.5e-09 7.5e-09\n", + " * z (z) float64 2.5e-09 7.5e-09\n", + " comp " + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "xarray.sel(comp='z').sel(x=2e-9, method=\"nearest\").plot()" + ] + }, + { + "cell_type": "markdown", + "id": "fafc118b", + "metadata": {}, + "source": [ + "Notice that proper units and labels on the plot are displayed by default. The full list of `xarray.DataArray` methods can be found in the [API reference](https://docs.xarray.dev/en/stable/api.html)." + ] + }, + { + "cell_type": "markdown", + "id": "fac0b5cc", + "metadata": {}, + "source": [ + "### `to_xarray` exceptions\n", + "\n", + "The `to_xarray` method raises `TypeError` if either `name` or `units` arguments are not strings." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "869e7773", + "metadata": {}, + "outputs": [ + { + "ename": "TypeError", + "evalue": "Name argument must be a string.", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", + "Input \u001b[0;32mIn [14]\u001b[0m, in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mfield\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mto_xarray\u001b[49m\u001b[43m(\u001b[49m\u001b[43mname\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;241;43m3\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43munits\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mA/m\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/Projects/ubermag-devtools/repos/discretisedfield/discretisedfield/field.py:3555\u001b[0m, in \u001b[0;36mField.to_xarray\u001b[0;34m(self, name, units)\u001b[0m\n\u001b[1;32m 3553\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(name, \u001b[38;5;28mstr\u001b[39m):\n\u001b[1;32m 3554\u001b[0m msg \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mName argument must be a string.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m-> 3555\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mTypeError\u001b[39;00m(msg)\n\u001b[1;32m 3557\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m units \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(units, \u001b[38;5;28mstr\u001b[39m):\n\u001b[1;32m 3558\u001b[0m msg \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mUnits argument must be a string.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n", + "\u001b[0;31mTypeError\u001b[0m: Name argument must be a string." + ] + } + ], + "source": [ + "field.to_xarray(name=3, units='A/m')" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "0c966a39", + "metadata": {}, + "outputs": [ + { + "ename": "TypeError", + "evalue": "Units argument must be a string.", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", + "Input \u001b[0;32mIn [15]\u001b[0m, in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mfield\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mto_xarray\u001b[49m\u001b[43m(\u001b[49m\u001b[43mname\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mm\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43munits\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;241;43m1e8\u001b[39;49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/Projects/ubermag-devtools/repos/discretisedfield/discretisedfield/field.py:3559\u001b[0m, in \u001b[0;36mField.to_xarray\u001b[0;34m(self, name, units)\u001b[0m\n\u001b[1;32m 3557\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m units \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(units, \u001b[38;5;28mstr\u001b[39m):\n\u001b[1;32m 3558\u001b[0m msg \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mUnits argument must be a string.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m-> 3559\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mTypeError\u001b[39;00m(msg)\n\u001b[1;32m 3561\u001b[0m axes \u001b[38;5;241m=\u001b[39m [\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mx\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124my\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mz\u001b[39m\u001b[38;5;124m'\u001b[39m]\n\u001b[1;32m 3563\u001b[0m data_array_coords \u001b[38;5;241m=\u001b[39m {\n\u001b[1;32m 3564\u001b[0m axis: np\u001b[38;5;241m.\u001b[39mfromiter(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mmesh\u001b[38;5;241m.\u001b[39maxis_points(axis), dtype\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mfloat\u001b[39m)\n\u001b[1;32m 3565\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m axis \u001b[38;5;129;01min\u001b[39;00m axes\n\u001b[1;32m 3566\u001b[0m }\n", + "\u001b[0;31mTypeError\u001b[0m: Units argument must be a string." + ] + } + ], + "source": [ + "field.to_xarray(name='m', units=1e8)" + ] + }, + { + "cell_type": "markdown", + "id": "7d7623ea", + "metadata": {}, + "source": [ + "\n", + "## Importing `discretisedfield.Field` from `xarray.DataArray`" + ] + }, + { + "cell_type": "markdown", + "id": "a7a16de3", + "metadata": {}, + "source": [ + "It is possible to create a `discretisedfield.Field` from an `xarray.DataArray` with the help of class method `from_xarray`. As a first step, we convert the `xarray.DataArray` created by `to_xarray` method to a new `discretisedfield.Field`." + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "3953428f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "Field\n", + "
    \n", + " \n", + "
  • Mesh\n", + "
      \n", + "
    • Region\n", + "
        \n", + "
      • p1 = (0, 0, 0)
      • \n", + "
      • p2 = (1e-08, 1e-08, 1e-08)
      • \n", + "
    • \n", + "
    • n = (2, 2, 2)
    • \n", + "
    • attributes:\n", + "
        \n", + "
      • unit: m
      • \n", + "
      • fourierspace: False
      • \n", + "
      • isplane: False
      • \n", + "
      \n", + "
    • \n", + "
  • \n", + "
  • dim = 3
  • \n", + "
  • components:\n", + "
    • x
    • \n", + "
    • y
    • \n", + "
    • z
    • \n", + "
    \n", + "
  • \n", + "
" + ], + "text/plain": [ + "Field(Mesh(Region(p1=(0, 0, 0), p2=(1e-08, 1e-08, 1e-08)), n=(2, 2, 2), attributes: (unit: m, fourierspace: False, isplane: False)), dim=3, components: (x, y, z))" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "field_new = df.Field.from_xarray(xarray)\n", + "field_new" + ] + }, + { + "cell_type": "markdown", + "id": "97a32e8c", + "metadata": {}, + "source": [ + "One can also first define an `xarray.DataArray` and then convert it to `discretisedfield.Field`." + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "7dc09fa2", + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
<xarray.DataArray 'mag' (x: 2, y: 2, z: 2, comp: 3)>\n",
+       "array([[[[1., 1., 1.],\n",
+       "         [1., 1., 1.]],\n",
+       "\n",
+       "        [[1., 1., 1.],\n",
+       "         [1., 1., 1.]]],\n",
+       "\n",
+       "\n",
+       "       [[[1., 1., 1.],\n",
+       "         [1., 1., 1.]],\n",
+       "\n",
+       "        [[1., 1., 1.],\n",
+       "         [1., 1., 1.]]]])\n",
+       "Coordinates:\n",
+       "  * x        (x) float64 2.5e-09 7.5e-09\n",
+       "  * y        (y) float64 2.5e-09 7.5e-09\n",
+       "  * z        (z) float64 2.5e-09 7.5e-09\n",
+       "  * comp     (comp) <U1 'x' 'y' 'z'\n",
+       "Attributes:\n",
+       "    cell:     [5e-09, 5e-09, 5e-09]\n",
+       "    p1:       [0.0, 0.0, 0.0]\n",
+       "    p2:       [1e-08, 1e-08, 1e-08]
" + ], + "text/plain": [ + "\n", + "array([[[[1., 1., 1.],\n", + " [1., 1., 1.]],\n", + "\n", + " [[1., 1., 1.],\n", + " [1., 1., 1.]]],\n", + "\n", + "\n", + " [[[1., 1., 1.],\n", + " [1., 1., 1.]],\n", + "\n", + " [[1., 1., 1.],\n", + " [1., 1., 1.]]]])\n", + "Coordinates:\n", + " * x (x) float64 2.5e-09 7.5e-09\n", + " * y (y) float64 2.5e-09 7.5e-09\n", + " * z (z) float64 2.5e-09 7.5e-09\n", + " * comp (comp) Field\n", + "
    \n", + " \n", + "
  • Mesh\n", + "
      \n", + "
    • Region\n", + "
        \n", + "
      • p1 = (0.0, 0.0, 0.0)
      • \n", + "
      • p2 = (1e-08, 1e-08, 1e-08)
      • \n", + "
    • \n", + "
    • n = (2, 2, 2)
    • \n", + "
    • attributes:\n", + "
        \n", + "
      • unit: m
      • \n", + "
      • fourierspace: False
      • \n", + "
      • isplane: False
      • \n", + "
      \n", + "
    • \n", + "
  • \n", + "
  • dim = 3
  • \n", + "
  • components:\n", + "
    • x
    • \n", + "
    • y
    • \n", + "
    • z
    • \n", + "
    \n", + "
  • \n", + "
" + ], + "text/plain": [ + "Field(Mesh(Region(p1=(0.0, 0.0, 0.0), p2=(1e-08, 1e-08, 1e-08)), n=(2, 2, 2), attributes: (unit: m, fourierspace: False, isplane: False)), dim=3, components: (x, y, z))" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "field_xdr = df.Field.from_xarray(xdr)\n", + "field_xdr" + ] + }, + { + "cell_type": "markdown", + "id": "c040b8a9", + "metadata": {}, + "source": [ + "### `from_xarray` exceptions and expected properties of input `xarray.DataArray`\n", + "\n", + "The input argument of `from_xarray` must be an `xarray.DataArray`. If not, a `TypeError` is raised." + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "351d75ba", + "metadata": {}, + "outputs": [ + { + "ename": "TypeError", + "evalue": "Argument must be a xr.DataArray.", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", + "Input \u001b[0;32mIn [23]\u001b[0m, in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mdf\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mField\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mfrom_xarray\u001b[49m\u001b[43m(\u001b[49m\u001b[43mnp\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mones\u001b[49m\u001b[43m(\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m2\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m2\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m2\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m3\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdtype\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mfloat\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/Projects/ubermag-devtools/repos/discretisedfield/discretisedfield/field.py:3681\u001b[0m, in \u001b[0;36mField.from_xarray\u001b[0;34m(cls, xa)\u001b[0m\n\u001b[1;32m 3598\u001b[0m \u001b[38;5;124;03m\"\"\"Create ``discretisedfield.Field`` from ``xarray.DataArray``\u001b[39;00m\n\u001b[1;32m 3599\u001b[0m \n\u001b[1;32m 3600\u001b[0m \u001b[38;5;124;03mThe class method accepts an ``xarray.DataArray`` as an argument to\u001b[39;00m\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 3678\u001b[0m \n\u001b[1;32m 3679\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 3680\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(xa, xr\u001b[38;5;241m.\u001b[39mDataArray):\n\u001b[0;32m-> 3681\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mTypeError\u001b[39;00m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mArgument must be a xr.DataArray.\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 3683\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m xa\u001b[38;5;241m.\u001b[39mndim \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m [\u001b[38;5;241m3\u001b[39m, \u001b[38;5;241m4\u001b[39m]:\n\u001b[1;32m 3684\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mDataArray dimensions must be 3 for a scalar \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 3685\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mand 4 for a vector field.\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n", + "\u001b[0;31mTypeError\u001b[0m: Argument must be a xr.DataArray." + ] + } + ], + "source": [ + "df.Field.from_xarray(np.ones((2, 2, 2, 3), dtype=float))" + ] + }, + { + "cell_type": "markdown", + "id": "adc0f88a", + "metadata": {}, + "source": [ + "The dimensions of the input `DataArray` must be either three or four depending on whether the field is scalar or vector. If not, a `ValueError` is raised." + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "ae26fdc7", + "metadata": {}, + "outputs": [ + { + "ename": "ValueError", + "evalue": "DataArray dimensions must be 3 for a scalar and 4 for a vector field.", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", + "Input \u001b[0;32mIn [25]\u001b[0m, in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m bad_dim_no \u001b[38;5;241m=\u001b[39m xr\u001b[38;5;241m.\u001b[39mDataArray(np\u001b[38;5;241m.\u001b[39mones((\u001b[38;5;241m20\u001b[39m, \u001b[38;5;241m20\u001b[39m, \u001b[38;5;241m20\u001b[39m, \u001b[38;5;241m5\u001b[39m, \u001b[38;5;241m3\u001b[39m), dtype\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mfloat\u001b[39m),\n\u001b[1;32m 2\u001b[0m dims\u001b[38;5;241m=\u001b[39m[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mx\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124my\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mz\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124ma\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mcomp\u001b[39m\u001b[38;5;124m'\u001b[39m],\n\u001b[1;32m 3\u001b[0m coords\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mdict\u001b[39m(x\u001b[38;5;241m=\u001b[39mnp\u001b[38;5;241m.\u001b[39marange(\u001b[38;5;241m0\u001b[39m, \u001b[38;5;241m20\u001b[39m),\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 8\u001b[0m name\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mmag\u001b[39m\u001b[38;5;124m'\u001b[39m,\n\u001b[1;32m 9\u001b[0m attrs\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mdict\u001b[39m(units\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mA/m\u001b[39m\u001b[38;5;124m'\u001b[39m))\n\u001b[0;32m---> 11\u001b[0m \u001b[43mdf\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mField\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mfrom_xarray\u001b[49m\u001b[43m(\u001b[49m\u001b[43mbad_dim_no\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/Projects/ubermag-devtools/repos/discretisedfield/discretisedfield/field.py:3684\u001b[0m, in \u001b[0;36mField.from_xarray\u001b[0;34m(cls, xa)\u001b[0m\n\u001b[1;32m 3681\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mTypeError\u001b[39;00m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mArgument must be a xr.DataArray.\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 3683\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m xa\u001b[38;5;241m.\u001b[39mndim \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m [\u001b[38;5;241m3\u001b[39m, \u001b[38;5;241m4\u001b[39m]:\n\u001b[0;32m-> 3684\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mDataArray dimensions must be 3 for a scalar \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 3685\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mand 4 for a vector field.\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 3687\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m xa\u001b[38;5;241m.\u001b[39mndim \u001b[38;5;241m==\u001b[39m \u001b[38;5;241m3\u001b[39m \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;28msorted\u001b[39m(xa\u001b[38;5;241m.\u001b[39mdims) \u001b[38;5;241m!=\u001b[39m [\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mx\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124my\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mz\u001b[39m\u001b[38;5;124m'\u001b[39m]:\n\u001b[1;32m 3688\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mThe dimensions must be \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mx\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m, \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124my\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m, and \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mz\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m.\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n", + "\u001b[0;31mValueError\u001b[0m: DataArray dimensions must be 3 for a scalar and 4 for a vector field." + ] + } + ], + "source": [ + "bad_dim_no = xr.DataArray(np.ones((20, 20, 20, 5, 3), dtype=float),\n", + " dims=['x', 'y', 'z', 'a', 'comp'],\n", + " coords=dict(x=np.arange(0, 20),\n", + " y=np.arange(0, 20),\n", + " z=np.arange(0, 20),\n", + " a=np.arange(0, 5),\n", + " comp=['x', 'y', 'z']),\n", + " name='mag',\n", + " attrs=dict(units='A/m'))\n", + "\n", + "df.Field.from_xarray(bad_dim_no)" + ] + }, + { + "cell_type": "markdown", + "id": "b80267ea", + "metadata": {}, + "source": [ + "Further the name of the dimensions must be `x`, `y`, `z`, and `comp` (if a vector field). If not, a `ValueError` is raised." + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "cecad650", + "metadata": {}, + "outputs": [ + { + "ename": "ValueError", + "evalue": "The dimensions must be 'x', 'y', 'z',and 'comp'.", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", + "Input \u001b[0;32mIn [26]\u001b[0m, in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m bad_dim_names \u001b[38;5;241m=\u001b[39m xr\u001b[38;5;241m.\u001b[39mDataArray(np\u001b[38;5;241m.\u001b[39mones((\u001b[38;5;241m20\u001b[39m, \u001b[38;5;241m20\u001b[39m, \u001b[38;5;241m5\u001b[39m, \u001b[38;5;241m3\u001b[39m), dtype\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mfloat\u001b[39m),\n\u001b[1;32m 2\u001b[0m dims\u001b[38;5;241m=\u001b[39m[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mx\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124my\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mz\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mc\u001b[39m\u001b[38;5;124m'\u001b[39m],\n\u001b[1;32m 3\u001b[0m coords\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mdict\u001b[39m(x\u001b[38;5;241m=\u001b[39mnp\u001b[38;5;241m.\u001b[39marange(\u001b[38;5;241m0\u001b[39m, \u001b[38;5;241m20\u001b[39m),\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 7\u001b[0m name\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mmag\u001b[39m\u001b[38;5;124m'\u001b[39m,\n\u001b[1;32m 8\u001b[0m attrs\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mdict\u001b[39m(units\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mA/m\u001b[39m\u001b[38;5;124m'\u001b[39m))\n\u001b[0;32m---> 10\u001b[0m \u001b[43mdf\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mField\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mfrom_xarray\u001b[49m\u001b[43m(\u001b[49m\u001b[43mbad_dim_names\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/Projects/ubermag-devtools/repos/discretisedfield/discretisedfield/field.py:3690\u001b[0m, in \u001b[0;36mField.from_xarray\u001b[0;34m(cls, xa)\u001b[0m\n\u001b[1;32m 3688\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mThe dimensions must be \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mx\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m, \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124my\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m, and \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mz\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m.\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 3689\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m xa\u001b[38;5;241m.\u001b[39mndim \u001b[38;5;241m==\u001b[39m \u001b[38;5;241m4\u001b[39m \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;28msorted\u001b[39m(xa\u001b[38;5;241m.\u001b[39mdims) \u001b[38;5;241m!=\u001b[39m [\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mcomp\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mx\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124my\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mz\u001b[39m\u001b[38;5;124m'\u001b[39m]:\n\u001b[0;32m-> 3690\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mThe dimensions must be \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mx\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m, \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124my\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m, \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mz\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m,\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 3691\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mand \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mcomp\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m.\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 3693\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m i \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mxyz\u001b[39m\u001b[38;5;124m'\u001b[39m:\n\u001b[1;32m 3694\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m xa[i]\u001b[38;5;241m.\u001b[39mvalues\u001b[38;5;241m.\u001b[39msize \u001b[38;5;241m>\u001b[39m \u001b[38;5;241m1\u001b[39m \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m np\u001b[38;5;241m.\u001b[39mallclose(\n\u001b[1;32m 3695\u001b[0m np\u001b[38;5;241m.\u001b[39mdiff(xa[i]\u001b[38;5;241m.\u001b[39mvalues), np\u001b[38;5;241m.\u001b[39mdiff(xa[i]\u001b[38;5;241m.\u001b[39mvalues)\u001b[38;5;241m.\u001b[39mmean()):\n", + "\u001b[0;31mValueError\u001b[0m: The dimensions must be 'x', 'y', 'z',and 'comp'." + ] + } + ], + "source": [ + "bad_dim_names = xr.DataArray(np.ones((20, 20, 5, 3), dtype=float),\n", + " dims=['x', 'y', 'z', 'c'],\n", + " coords=dict(x=np.arange(0, 20),\n", + " y=np.arange(0, 20),\n", + " z=np.arange(0, 5),\n", + " c=['x', 'y', 'z']),\n", + " name='mag',\n", + " attrs=dict(units='A/m'))\n", + "\n", + "df.Field.from_xarray(bad_dim_names)" + ] + }, + { + "cell_type": "markdown", + "id": "9e43649c", + "metadata": {}, + "source": [ + "The coordinates of the `x`, `y`, and `z` dimensions must be equally spaced. If not, a `ValueError` is raised." + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "7f28572e", + "metadata": {}, + "outputs": [ + { + "ename": "ValueError", + "evalue": "Coordinates of x must be equally spaced.", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", + "Input \u001b[0;32mIn [27]\u001b[0m, in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m rng \u001b[38;5;241m=\u001b[39m np\u001b[38;5;241m.\u001b[39mrandom\u001b[38;5;241m.\u001b[39mdefault_rng()\n\u001b[1;32m 3\u001b[0m bad_spacing \u001b[38;5;241m=\u001b[39m xr\u001b[38;5;241m.\u001b[39mDataArray(np\u001b[38;5;241m.\u001b[39mones((\u001b[38;5;241m20\u001b[39m, \u001b[38;5;241m20\u001b[39m, \u001b[38;5;241m20\u001b[39m, \u001b[38;5;241m3\u001b[39m), dtype\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mfloat\u001b[39m),\n\u001b[1;32m 4\u001b[0m dims\u001b[38;5;241m=\u001b[39m[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mx\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124my\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mz\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mcomp\u001b[39m\u001b[38;5;124m'\u001b[39m],\n\u001b[1;32m 5\u001b[0m coords\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mdict\u001b[39m(x\u001b[38;5;241m=\u001b[39mrng\u001b[38;5;241m.\u001b[39mnormal(size\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m20\u001b[39m),\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 8\u001b[0m name\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mmag\u001b[39m\u001b[38;5;124m'\u001b[39m,\n\u001b[1;32m 9\u001b[0m attrs\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mdict\u001b[39m(units\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mA/m\u001b[39m\u001b[38;5;124m'\u001b[39m))\n\u001b[0;32m---> 11\u001b[0m \u001b[43mdf\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mField\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mfrom_xarray\u001b[49m\u001b[43m(\u001b[49m\u001b[43mbad_spacing\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/Projects/ubermag-devtools/repos/discretisedfield/discretisedfield/field.py:3696\u001b[0m, in \u001b[0;36mField.from_xarray\u001b[0;34m(cls, xa)\u001b[0m\n\u001b[1;32m 3693\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m i \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mxyz\u001b[39m\u001b[38;5;124m'\u001b[39m:\n\u001b[1;32m 3694\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m xa[i]\u001b[38;5;241m.\u001b[39mvalues\u001b[38;5;241m.\u001b[39msize \u001b[38;5;241m>\u001b[39m \u001b[38;5;241m1\u001b[39m \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m np\u001b[38;5;241m.\u001b[39mallclose(\n\u001b[1;32m 3695\u001b[0m np\u001b[38;5;241m.\u001b[39mdiff(xa[i]\u001b[38;5;241m.\u001b[39mvalues), np\u001b[38;5;241m.\u001b[39mdiff(xa[i]\u001b[38;5;241m.\u001b[39mvalues)\u001b[38;5;241m.\u001b[39mmean()):\n\u001b[0;32m-> 3696\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mCoordinates of \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mi\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m must be\u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[1;32m 3697\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124m equally spaced.\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 3699\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 3700\u001b[0m cell \u001b[38;5;241m=\u001b[39m xa\u001b[38;5;241m.\u001b[39mattrs[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mcell\u001b[39m\u001b[38;5;124m'\u001b[39m]\n", + "\u001b[0;31mValueError\u001b[0m: Coordinates of x must be equally spaced." + ] + } + ], + "source": [ + "rng = np.random.default_rng()\n", + "\n", + "bad_spacing = xr.DataArray(np.ones((20, 20, 20, 3), dtype=float),\n", + " dims=['x', 'y', 'z', 'comp'],\n", + " coords=dict(x=rng.normal(size=20),\n", + " y=np.arange(0, 20),\n", + " z=np.arange(0, 20)),\n", + " name='mag',\n", + " attrs=dict(units='A/m'))\n", + "\n", + "df.Field.from_xarray(bad_spacing)" + ] + }, + { + "cell_type": "markdown", + "id": "9670755a", + "metadata": {}, + "source": [ + "Lastly, **it is strongly advised that the input `xarray.DataArray` should have `p1`, `p2`, and `cell` attributes** required for the reconstruction of the mesh." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From ef1f0644bf2588aa60ad8300662b0a831f52f602 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 22 Mar 2022 06:15:14 +0000 Subject: [PATCH 48/54] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- docs/xarray-usage.ipynb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/xarray-usage.ipynb b/docs/xarray-usage.ipynb index 76beedc94..dae0a8f07 100644 --- a/docs/xarray-usage.ipynb +++ b/docs/xarray-usage.ipynb @@ -63,7 +63,6 @@ "source": [ "import discretisedfield as df\n", "\n", - "\n", "p1 = (0, 0, 0)\n", "p2 = (10e-9, 10e-9, 10e-9)\n", "cell = (5e-9, 5e-9, 5e-9)\n", @@ -2429,9 +2428,8 @@ } ], "source": [ - "import xarray as xr\n", "import numpy as np\n", - "\n", + "import xarray as xr\n", "\n", "xdr = xr.DataArray(np.ones((2, 2, 2, 3), dtype=float),\n", " dims = ['x', 'y', 'z', 'comp'],\n", From 80883fdcc421ab285afd3f017d7c16e6cf60d606 Mon Sep 17 00:00:00 2001 From: swapneelap Date: Tue, 22 Mar 2022 17:03:39 +0530 Subject: [PATCH 49/54] Docs,Refactor,Fix(xarray-usage): remove exception cases - Remove cells showing raised exceptions from `to_xarray` and `from_xarray` for better readability. - Add `print()` to display `xarray.DataArray` as the html representation gives `pytest` errors with nbval. --- docs/xarray-usage.ipynb | 2483 +++------------------------------------ 1 file changed, 193 insertions(+), 2290 deletions(-) diff --git a/docs/xarray-usage.ipynb b/docs/xarray-usage.ipynb index dae0a8f07..dc07ec760 100644 --- a/docs/xarray-usage.ipynb +++ b/docs/xarray-usage.ipynb @@ -16,7 +16,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 22, "id": "756dbabb", "metadata": {}, "outputs": [ @@ -55,7 +55,7 @@ "Field(Mesh(Region(p1=(0, 0, 0), p2=(1e-08, 1e-08, 1e-08)), n=(2, 2, 2), attributes: (unit: m, fourierspace: False, isplane: False)), dim=3, components: (x, y, z))" ] }, - "execution_count": 1, + "execution_count": 22, "metadata": {}, "output_type": "execute_result" } @@ -74,433 +74,43 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 43, "id": "705c72bc", "metadata": {}, "outputs": [ { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
<xarray.DataArray 'field' (x: 2, y: 2, z: 2, comp: 3)>\n",
-       "array([[[[0., 0., 1.],\n",
-       "         [0., 0., 1.]],\n",
-       "\n",
-       "        [[0., 0., 1.],\n",
-       "         [0., 0., 1.]]],\n",
-       "\n",
-       "\n",
-       "       [[[0., 0., 1.],\n",
-       "         [0., 0., 1.]],\n",
-       "\n",
-       "        [[0., 0., 1.],\n",
-       "         [0., 0., 1.]]]])\n",
-       "Coordinates:\n",
-       "  * x        (x) float64 2.5e-09 7.5e-09\n",
-       "  * y        (y) float64 2.5e-09 7.5e-09\n",
-       "  * z        (z) float64 2.5e-09 7.5e-09\n",
-       "  * comp     (comp) <U1 'x' 'y' 'z'\n",
-       "Attributes:\n",
-       "    units:    None\n",
-       "    cell:     (5e-09, 5e-09, 5e-09)\n",
-       "    p1:       (0, 0, 0)\n",
-       "    p2:       (1e-08, 1e-08, 1e-08)
" - ], - "text/plain": [ - "\n", - "array([[[[0., 0., 1.],\n", - " [0., 0., 1.]],\n", - "\n", - " [[0., 0., 1.],\n", - " [0., 0., 1.]]],\n", - "\n", - "\n", - " [[[0., 0., 1.],\n", - " [0., 0., 1.]],\n", - "\n", - " [[0., 0., 1.],\n", - " [0., 0., 1.]]]])\n", - "Coordinates:\n", - " * x (x) float64 2.5e-09 7.5e-09\n", - " * y (y) float64 2.5e-09 7.5e-09\n", - " * z (z) float64 2.5e-09 7.5e-09\n", - " * comp (comp) \n", + "array([[[[0., 0., 1.],\n", + " [0., 0., 1.]],\n", + "\n", + " [[0., 0., 1.],\n", + " [0., 0., 1.]]],\n", + "\n", + "\n", + " [[[0., 0., 1.],\n", + " [0., 0., 1.]],\n", + "\n", + " [[0., 0., 1.],\n", + " [0., 0., 1.]]]])\n", + "Coordinates:\n", + " * x (x) float64 2.5e-09 7.5e-09\n", + " * y (y) float64 2.5e-09 7.5e-09\n", + " * z (z) float64 2.5e-09 7.5e-09\n", + " * comp (comp) \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
<xarray.DataArray 'field' (y: 2, z: 2, comp: 3)>\n",
-       "array([[[0., 0., 1.],\n",
-       "        [0., 0., 1.]],\n",
-       "\n",
-       "       [[0., 0., 1.],\n",
-       "        [0., 0., 1.]]])\n",
-       "Coordinates:\n",
-       "    x        float64 2.5e-09\n",
-       "  * y        (y) float64 2.5e-09 7.5e-09\n",
-       "  * z        (z) float64 2.5e-09 7.5e-09\n",
-       "  * comp     (comp) <U1 'x' 'y' 'z'\n",
-       "Attributes:\n",
-       "    units:    None\n",
-       "    cell:     (5e-09, 5e-09, 5e-09)\n",
-       "    p1:       (0, 0, 0)\n",
-       "    p2:       (1e-08, 1e-08, 1e-08)
" - ], - "text/plain": [ - "\n", - "array([[[0., 0., 1.],\n", - " [0., 0., 1.]],\n", - "\n", - " [[0., 0., 1.],\n", - " [0., 0., 1.]]])\n", - "Coordinates:\n", - " x float64 2.5e-09\n", - " * y (y) float64 2.5e-09 7.5e-09\n", - " * z (z) float64 2.5e-09 7.5e-09\n", - " * comp (comp) \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
<xarray.DataArray 'field' (x: 2, y: 2, z: 2)>\n",
-       "array([[[1., 1.],\n",
-       "        [1., 1.]],\n",
-       "\n",
-       "       [[1., 1.],\n",
-       "        [1., 1.]]])\n",
-       "Coordinates:\n",
-       "  * x        (x) float64 2.5e-09 7.5e-09\n",
-       "  * y        (y) float64 2.5e-09 7.5e-09\n",
-       "  * z        (z) float64 2.5e-09 7.5e-09\n",
-       "    comp     <U1 'z'\n",
-       "Attributes:\n",
-       "    units:    None\n",
-       "    cell:     (5e-09, 5e-09, 5e-09)\n",
-       "    p1:       (0, 0, 0)\n",
-       "    p2:       (1e-08, 1e-08, 1e-08)
" - ], - "text/plain": [ - "\n", - "array([[[1., 1.],\n", - " [1., 1.]],\n", - "\n", - " [[1., 1.],\n", - " [1., 1.]]])\n", - "Coordinates:\n", - " * x (x) float64 2.5e-09 7.5e-09\n", - " * y (y) float64 2.5e-09 7.5e-09\n", - " * z (z) float64 2.5e-09 7.5e-09\n", - " comp \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
<xarray.DataArray 'field' (y: 2, z: 2)>\n",
-       "array([[1., 1.],\n",
-       "       [1., 1.]])\n",
-       "Coordinates:\n",
-       "    x        float64 2.5e-09\n",
-       "  * y        (y) float64 2.5e-09 7.5e-09\n",
-       "  * z        (z) float64 2.5e-09 7.5e-09\n",
-       "    comp     <U1 'z'\n",
-       "Attributes:\n",
-       "    units:    None\n",
-       "    cell:     (5e-09, 5e-09, 5e-09)\n",
-       "    p1:       (0, 0, 0)\n",
-       "    p2:       (1e-08, 1e-08, 1e-08)
" - ], - "text/plain": [ - "\n", - "array([[1., 1.],\n", - " [1., 1.]])\n", - "Coordinates:\n", - " x float64 2.5e-09\n", - " * y (y) float64 2.5e-09 7.5e-09\n", - " * z (z) float64 2.5e-09 7.5e-09\n", - " comp \n", + "array([[[0., 0., 1.],\n", + " [0., 0., 1.]],\n", + "\n", + " [[0., 0., 1.],\n", + " [0., 0., 1.]]])\n", + "Coordinates:\n", + " x float64 2.5e-09\n", + " * y (y) float64 2.5e-09 7.5e-09\n", + " * z (z) float64 2.5e-09 7.5e-09\n", + " * comp (comp) \n", + "array([[[1., 1.],\n", + " [1., 1.]],\n", + "\n", + " [[1., 1.],\n", + " [1., 1.]]])\n", + "Coordinates:\n", + " * x (x) float64 2.5e-09 7.5e-09\n", + " * y (y) float64 2.5e-09 7.5e-09\n", + " * z (z) float64 2.5e-09 7.5e-09\n", + " comp \n", + "array([[1., 1.],\n", + " [1., 1.]])\n", + "Coordinates:\n", + " x float64 2.5e-09\n", + " * y (y) float64 2.5e-09 7.5e-09\n", + " * z (z) float64 2.5e-09 7.5e-09\n", + " comp " - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - }, { "data": { "image/png": "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\n", @@ -1858,7 +336,7 @@ } ], "source": [ - "xarray.sel(comp='z').sel(x=2e-9, method=\"nearest\").plot()" + "xarray.sel(comp='z').sel(x=2e-9, method=\"nearest\").plot();" ] }, { @@ -1879,52 +357,6 @@ "The `to_xarray` method raises `TypeError` if either `name` or `units` arguments are not strings." ] }, - { - "cell_type": "code", - "execution_count": 14, - "id": "869e7773", - "metadata": {}, - "outputs": [ - { - "ename": "TypeError", - "evalue": "Name argument must be a string.", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", - "Input \u001b[0;32mIn [14]\u001b[0m, in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mfield\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mto_xarray\u001b[49m\u001b[43m(\u001b[49m\u001b[43mname\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;241;43m3\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43munits\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mA/m\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m)\u001b[49m\n", - "File \u001b[0;32m~/Projects/ubermag-devtools/repos/discretisedfield/discretisedfield/field.py:3555\u001b[0m, in \u001b[0;36mField.to_xarray\u001b[0;34m(self, name, units)\u001b[0m\n\u001b[1;32m 3553\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(name, \u001b[38;5;28mstr\u001b[39m):\n\u001b[1;32m 3554\u001b[0m msg \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mName argument must be a string.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m-> 3555\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mTypeError\u001b[39;00m(msg)\n\u001b[1;32m 3557\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m units \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(units, \u001b[38;5;28mstr\u001b[39m):\n\u001b[1;32m 3558\u001b[0m msg \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mUnits argument must be a string.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n", - "\u001b[0;31mTypeError\u001b[0m: Name argument must be a string." - ] - } - ], - "source": [ - "field.to_xarray(name=3, units='A/m')" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "id": "0c966a39", - "metadata": {}, - "outputs": [ - { - "ename": "TypeError", - "evalue": "Units argument must be a string.", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", - "Input \u001b[0;32mIn [15]\u001b[0m, in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mfield\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mto_xarray\u001b[49m\u001b[43m(\u001b[49m\u001b[43mname\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mm\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43munits\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;241;43m1e8\u001b[39;49m\u001b[43m)\u001b[49m\n", - "File \u001b[0;32m~/Projects/ubermag-devtools/repos/discretisedfield/discretisedfield/field.py:3559\u001b[0m, in \u001b[0;36mField.to_xarray\u001b[0;34m(self, name, units)\u001b[0m\n\u001b[1;32m 3557\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m units \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(units, \u001b[38;5;28mstr\u001b[39m):\n\u001b[1;32m 3558\u001b[0m msg \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mUnits argument must be a string.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m-> 3559\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mTypeError\u001b[39;00m(msg)\n\u001b[1;32m 3561\u001b[0m axes \u001b[38;5;241m=\u001b[39m [\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mx\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124my\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mz\u001b[39m\u001b[38;5;124m'\u001b[39m]\n\u001b[1;32m 3563\u001b[0m data_array_coords \u001b[38;5;241m=\u001b[39m {\n\u001b[1;32m 3564\u001b[0m axis: np\u001b[38;5;241m.\u001b[39mfromiter(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mmesh\u001b[38;5;241m.\u001b[39maxis_points(axis), dtype\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mfloat\u001b[39m)\n\u001b[1;32m 3565\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m axis \u001b[38;5;129;01min\u001b[39;00m axes\n\u001b[1;32m 3566\u001b[0m }\n", - "\u001b[0;31mTypeError\u001b[0m: Units argument must be a string." - ] - } - ], - "source": [ - "field.to_xarray(name='m', units=1e8)" - ] - }, { "cell_type": "markdown", "id": "7d7623ea", @@ -1944,7 +376,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 32, "id": "3953428f", "metadata": {}, "outputs": [ @@ -1983,7 +415,7 @@ "Field(Mesh(Region(p1=(0, 0, 0), p2=(1e-08, 1e-08, 1e-08)), n=(2, 2, 2), attributes: (unit: m, fourierspace: False, isplane: False)), dim=3, components: (x, y, z))" ] }, - "execution_count": 17, + "execution_count": 32, "metadata": {}, "output_type": "execute_result" } @@ -2001,430 +433,49 @@ "One can also first define an `xarray.DataArray` and then convert it to `discretisedfield.Field`." ] }, + { + "cell_type": "markdown", + "id": "6db802ff", + "metadata": {}, + "source": [ + "" + ] + }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 45, "id": "7dc09fa2", "metadata": { "scrolled": false }, "outputs": [ { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
<xarray.DataArray 'mag' (x: 2, y: 2, z: 2, comp: 3)>\n",
-       "array([[[[1., 1., 1.],\n",
-       "         [1., 1., 1.]],\n",
-       "\n",
-       "        [[1., 1., 1.],\n",
-       "         [1., 1., 1.]]],\n",
-       "\n",
-       "\n",
-       "       [[[1., 1., 1.],\n",
-       "         [1., 1., 1.]],\n",
-       "\n",
-       "        [[1., 1., 1.],\n",
-       "         [1., 1., 1.]]]])\n",
-       "Coordinates:\n",
-       "  * x        (x) float64 2.5e-09 7.5e-09\n",
-       "  * y        (y) float64 2.5e-09 7.5e-09\n",
-       "  * z        (z) float64 2.5e-09 7.5e-09\n",
-       "  * comp     (comp) <U1 'x' 'y' 'z'\n",
-       "Attributes:\n",
-       "    cell:     [5e-09, 5e-09, 5e-09]\n",
-       "    p1:       [0.0, 0.0, 0.0]\n",
-       "    p2:       [1e-08, 1e-08, 1e-08]
" - ], - "text/plain": [ - "\n", - "array([[[[1., 1., 1.],\n", - " [1., 1., 1.]],\n", - "\n", - " [[1., 1., 1.],\n", - " [1., 1., 1.]]],\n", - "\n", - "\n", - " [[[1., 1., 1.],\n", - " [1., 1., 1.]],\n", - "\n", - " [[1., 1., 1.],\n", - " [1., 1., 1.]]]])\n", - "Coordinates:\n", - " * x (x) float64 2.5e-09 7.5e-09\n", - " * y (y) float64 2.5e-09 7.5e-09\n", - " * z (z) float64 2.5e-09 7.5e-09\n", - " * comp (comp) \n", + "array([[[[1., 1., 1.],\n", + " [1., 1., 1.]],\n", + "\n", + " [[1., 1., 1.],\n", + " [1., 1., 1.]]],\n", + "\n", + "\n", + " [[[1., 1., 1.],\n", + " [1., 1., 1.]],\n", + "\n", + " [[1., 1., 1.],\n", + " [1., 1., 1.]]]])\n", + "Coordinates:\n", + " * x (x) float64 2.5e-09 7.5e-09\n", + " * y (y) float64 2.5e-09 7.5e-09\n", + " * z (z) float64 2.5e-09 7.5e-09\n", + " * comp (comp) \u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mdf\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mField\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mfrom_xarray\u001b[49m\u001b[43m(\u001b[49m\u001b[43mnp\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mones\u001b[49m\u001b[43m(\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m2\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m2\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m2\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m3\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdtype\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mfloat\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m)\u001b[49m\n", - "File \u001b[0;32m~/Projects/ubermag-devtools/repos/discretisedfield/discretisedfield/field.py:3681\u001b[0m, in \u001b[0;36mField.from_xarray\u001b[0;34m(cls, xa)\u001b[0m\n\u001b[1;32m 3598\u001b[0m \u001b[38;5;124;03m\"\"\"Create ``discretisedfield.Field`` from ``xarray.DataArray``\u001b[39;00m\n\u001b[1;32m 3599\u001b[0m \n\u001b[1;32m 3600\u001b[0m \u001b[38;5;124;03mThe class method accepts an ``xarray.DataArray`` as an argument to\u001b[39;00m\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 3678\u001b[0m \n\u001b[1;32m 3679\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 3680\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(xa, xr\u001b[38;5;241m.\u001b[39mDataArray):\n\u001b[0;32m-> 3681\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mTypeError\u001b[39;00m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mArgument must be a xr.DataArray.\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 3683\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m xa\u001b[38;5;241m.\u001b[39mndim \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m [\u001b[38;5;241m3\u001b[39m, \u001b[38;5;241m4\u001b[39m]:\n\u001b[1;32m 3684\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mDataArray dimensions must be 3 for a scalar \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 3685\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mand 4 for a vector field.\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n", - "\u001b[0;31mTypeError\u001b[0m: Argument must be a xr.DataArray." - ] - } - ], - "source": [ - "df.Field.from_xarray(np.ones((2, 2, 2, 3), dtype=float))" - ] - }, - { - "cell_type": "markdown", - "id": "adc0f88a", - "metadata": {}, - "source": [ - "The dimensions of the input `DataArray` must be either three or four depending on whether the field is scalar or vector. If not, a `ValueError` is raised." - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "id": "ae26fdc7", - "metadata": {}, - "outputs": [ - { - "ename": "ValueError", - "evalue": "DataArray dimensions must be 3 for a scalar and 4 for a vector field.", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", - "Input \u001b[0;32mIn [25]\u001b[0m, in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m bad_dim_no \u001b[38;5;241m=\u001b[39m xr\u001b[38;5;241m.\u001b[39mDataArray(np\u001b[38;5;241m.\u001b[39mones((\u001b[38;5;241m20\u001b[39m, \u001b[38;5;241m20\u001b[39m, \u001b[38;5;241m20\u001b[39m, \u001b[38;5;241m5\u001b[39m, \u001b[38;5;241m3\u001b[39m), dtype\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mfloat\u001b[39m),\n\u001b[1;32m 2\u001b[0m dims\u001b[38;5;241m=\u001b[39m[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mx\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124my\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mz\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124ma\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mcomp\u001b[39m\u001b[38;5;124m'\u001b[39m],\n\u001b[1;32m 3\u001b[0m coords\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mdict\u001b[39m(x\u001b[38;5;241m=\u001b[39mnp\u001b[38;5;241m.\u001b[39marange(\u001b[38;5;241m0\u001b[39m, \u001b[38;5;241m20\u001b[39m),\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 8\u001b[0m name\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mmag\u001b[39m\u001b[38;5;124m'\u001b[39m,\n\u001b[1;32m 9\u001b[0m attrs\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mdict\u001b[39m(units\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mA/m\u001b[39m\u001b[38;5;124m'\u001b[39m))\n\u001b[0;32m---> 11\u001b[0m \u001b[43mdf\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mField\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mfrom_xarray\u001b[49m\u001b[43m(\u001b[49m\u001b[43mbad_dim_no\u001b[49m\u001b[43m)\u001b[49m\n", - "File \u001b[0;32m~/Projects/ubermag-devtools/repos/discretisedfield/discretisedfield/field.py:3684\u001b[0m, in \u001b[0;36mField.from_xarray\u001b[0;34m(cls, xa)\u001b[0m\n\u001b[1;32m 3681\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mTypeError\u001b[39;00m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mArgument must be a xr.DataArray.\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 3683\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m xa\u001b[38;5;241m.\u001b[39mndim \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m [\u001b[38;5;241m3\u001b[39m, \u001b[38;5;241m4\u001b[39m]:\n\u001b[0;32m-> 3684\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mDataArray dimensions must be 3 for a scalar \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 3685\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mand 4 for a vector field.\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 3687\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m xa\u001b[38;5;241m.\u001b[39mndim \u001b[38;5;241m==\u001b[39m \u001b[38;5;241m3\u001b[39m \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;28msorted\u001b[39m(xa\u001b[38;5;241m.\u001b[39mdims) \u001b[38;5;241m!=\u001b[39m [\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mx\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124my\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mz\u001b[39m\u001b[38;5;124m'\u001b[39m]:\n\u001b[1;32m 3688\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mThe dimensions must be \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mx\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m, \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124my\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m, and \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mz\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m.\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n", - "\u001b[0;31mValueError\u001b[0m: DataArray dimensions must be 3 for a scalar and 4 for a vector field." - ] - } - ], - "source": [ - "bad_dim_no = xr.DataArray(np.ones((20, 20, 20, 5, 3), dtype=float),\n", - " dims=['x', 'y', 'z', 'a', 'comp'],\n", - " coords=dict(x=np.arange(0, 20),\n", - " y=np.arange(0, 20),\n", - " z=np.arange(0, 20),\n", - " a=np.arange(0, 5),\n", - " comp=['x', 'y', 'z']),\n", - " name='mag',\n", - " attrs=dict(units='A/m'))\n", - "\n", - "df.Field.from_xarray(bad_dim_no)" - ] - }, - { - "cell_type": "markdown", - "id": "b80267ea", - "metadata": {}, - "source": [ - "Further the name of the dimensions must be `x`, `y`, `z`, and `comp` (if a vector field). If not, a `ValueError` is raised." - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "id": "cecad650", - "metadata": {}, - "outputs": [ - { - "ename": "ValueError", - "evalue": "The dimensions must be 'x', 'y', 'z',and 'comp'.", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", - "Input \u001b[0;32mIn [26]\u001b[0m, in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m bad_dim_names \u001b[38;5;241m=\u001b[39m xr\u001b[38;5;241m.\u001b[39mDataArray(np\u001b[38;5;241m.\u001b[39mones((\u001b[38;5;241m20\u001b[39m, \u001b[38;5;241m20\u001b[39m, \u001b[38;5;241m5\u001b[39m, \u001b[38;5;241m3\u001b[39m), dtype\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mfloat\u001b[39m),\n\u001b[1;32m 2\u001b[0m dims\u001b[38;5;241m=\u001b[39m[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mx\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124my\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mz\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mc\u001b[39m\u001b[38;5;124m'\u001b[39m],\n\u001b[1;32m 3\u001b[0m coords\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mdict\u001b[39m(x\u001b[38;5;241m=\u001b[39mnp\u001b[38;5;241m.\u001b[39marange(\u001b[38;5;241m0\u001b[39m, \u001b[38;5;241m20\u001b[39m),\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 7\u001b[0m name\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mmag\u001b[39m\u001b[38;5;124m'\u001b[39m,\n\u001b[1;32m 8\u001b[0m attrs\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mdict\u001b[39m(units\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mA/m\u001b[39m\u001b[38;5;124m'\u001b[39m))\n\u001b[0;32m---> 10\u001b[0m \u001b[43mdf\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mField\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mfrom_xarray\u001b[49m\u001b[43m(\u001b[49m\u001b[43mbad_dim_names\u001b[49m\u001b[43m)\u001b[49m\n", - "File \u001b[0;32m~/Projects/ubermag-devtools/repos/discretisedfield/discretisedfield/field.py:3690\u001b[0m, in \u001b[0;36mField.from_xarray\u001b[0;34m(cls, xa)\u001b[0m\n\u001b[1;32m 3688\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mThe dimensions must be \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mx\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m, \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124my\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m, and \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mz\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m.\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 3689\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m xa\u001b[38;5;241m.\u001b[39mndim \u001b[38;5;241m==\u001b[39m \u001b[38;5;241m4\u001b[39m \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;28msorted\u001b[39m(xa\u001b[38;5;241m.\u001b[39mdims) \u001b[38;5;241m!=\u001b[39m [\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mcomp\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mx\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124my\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mz\u001b[39m\u001b[38;5;124m'\u001b[39m]:\n\u001b[0;32m-> 3690\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mThe dimensions must be \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mx\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m, \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124my\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m, \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mz\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m,\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 3691\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mand \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mcomp\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m.\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 3693\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m i \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mxyz\u001b[39m\u001b[38;5;124m'\u001b[39m:\n\u001b[1;32m 3694\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m xa[i]\u001b[38;5;241m.\u001b[39mvalues\u001b[38;5;241m.\u001b[39msize \u001b[38;5;241m>\u001b[39m \u001b[38;5;241m1\u001b[39m \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m np\u001b[38;5;241m.\u001b[39mallclose(\n\u001b[1;32m 3695\u001b[0m np\u001b[38;5;241m.\u001b[39mdiff(xa[i]\u001b[38;5;241m.\u001b[39mvalues), np\u001b[38;5;241m.\u001b[39mdiff(xa[i]\u001b[38;5;241m.\u001b[39mvalues)\u001b[38;5;241m.\u001b[39mmean()):\n", - "\u001b[0;31mValueError\u001b[0m: The dimensions must be 'x', 'y', 'z',and 'comp'." - ] - } - ], - "source": [ - "bad_dim_names = xr.DataArray(np.ones((20, 20, 5, 3), dtype=float),\n", - " dims=['x', 'y', 'z', 'c'],\n", - " coords=dict(x=np.arange(0, 20),\n", - " y=np.arange(0, 20),\n", - " z=np.arange(0, 5),\n", - " c=['x', 'y', 'z']),\n", - " name='mag',\n", - " attrs=dict(units='A/m'))\n", - "\n", - "df.Field.from_xarray(bad_dim_names)" - ] - }, - { - "cell_type": "markdown", - "id": "9e43649c", - "metadata": {}, - "source": [ - "The coordinates of the `x`, `y`, and `z` dimensions must be equally spaced. If not, a `ValueError` is raised." - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "id": "7f28572e", - "metadata": {}, - "outputs": [ - { - "ename": "ValueError", - "evalue": "Coordinates of x must be equally spaced.", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", - "Input \u001b[0;32mIn [27]\u001b[0m, in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m rng \u001b[38;5;241m=\u001b[39m np\u001b[38;5;241m.\u001b[39mrandom\u001b[38;5;241m.\u001b[39mdefault_rng()\n\u001b[1;32m 3\u001b[0m bad_spacing \u001b[38;5;241m=\u001b[39m xr\u001b[38;5;241m.\u001b[39mDataArray(np\u001b[38;5;241m.\u001b[39mones((\u001b[38;5;241m20\u001b[39m, \u001b[38;5;241m20\u001b[39m, \u001b[38;5;241m20\u001b[39m, \u001b[38;5;241m3\u001b[39m), dtype\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mfloat\u001b[39m),\n\u001b[1;32m 4\u001b[0m dims\u001b[38;5;241m=\u001b[39m[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mx\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124my\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mz\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mcomp\u001b[39m\u001b[38;5;124m'\u001b[39m],\n\u001b[1;32m 5\u001b[0m coords\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mdict\u001b[39m(x\u001b[38;5;241m=\u001b[39mrng\u001b[38;5;241m.\u001b[39mnormal(size\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m20\u001b[39m),\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 8\u001b[0m name\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mmag\u001b[39m\u001b[38;5;124m'\u001b[39m,\n\u001b[1;32m 9\u001b[0m attrs\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mdict\u001b[39m(units\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mA/m\u001b[39m\u001b[38;5;124m'\u001b[39m))\n\u001b[0;32m---> 11\u001b[0m \u001b[43mdf\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mField\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mfrom_xarray\u001b[49m\u001b[43m(\u001b[49m\u001b[43mbad_spacing\u001b[49m\u001b[43m)\u001b[49m\n", - "File \u001b[0;32m~/Projects/ubermag-devtools/repos/discretisedfield/discretisedfield/field.py:3696\u001b[0m, in \u001b[0;36mField.from_xarray\u001b[0;34m(cls, xa)\u001b[0m\n\u001b[1;32m 3693\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m i \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mxyz\u001b[39m\u001b[38;5;124m'\u001b[39m:\n\u001b[1;32m 3694\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m xa[i]\u001b[38;5;241m.\u001b[39mvalues\u001b[38;5;241m.\u001b[39msize \u001b[38;5;241m>\u001b[39m \u001b[38;5;241m1\u001b[39m \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m np\u001b[38;5;241m.\u001b[39mallclose(\n\u001b[1;32m 3695\u001b[0m np\u001b[38;5;241m.\u001b[39mdiff(xa[i]\u001b[38;5;241m.\u001b[39mvalues), np\u001b[38;5;241m.\u001b[39mdiff(xa[i]\u001b[38;5;241m.\u001b[39mvalues)\u001b[38;5;241m.\u001b[39mmean()):\n\u001b[0;32m-> 3696\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mCoordinates of \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mi\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m must be\u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[1;32m 3697\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124m equally spaced.\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 3699\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 3700\u001b[0m cell \u001b[38;5;241m=\u001b[39m xa\u001b[38;5;241m.\u001b[39mattrs[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mcell\u001b[39m\u001b[38;5;124m'\u001b[39m]\n", - "\u001b[0;31mValueError\u001b[0m: Coordinates of x must be equally spaced." - ] - } - ], - "source": [ - "rng = np.random.default_rng()\n", - "\n", - "bad_spacing = xr.DataArray(np.ones((20, 20, 20, 3), dtype=float),\n", - " dims=['x', 'y', 'z', 'comp'],\n", - " coords=dict(x=rng.normal(size=20),\n", - " y=np.arange(0, 20),\n", - " z=np.arange(0, 20)),\n", - " name='mag',\n", - " attrs=dict(units='A/m'))\n", + "The input argument of `from_xarray` must be an `xarray.DataArray`, otherwise a `TypeError` is raised. Further, the input `xarray.DataArray` must have following properties in order to obtain a `discretisedfield.Field`:\n", + "1. The dimensions must be either three or four depending on whether the field is scalar or vector. If not, a `ValueError` is raised.\n", + "2. The name of the dimensions must be `x`, `y`, `z`, and `comp` (if a vector field). If not, a `ValueError` is raised.\n", + "3. The coordinates of the `x`, `y`, and `z` dimensions must be equally spaced. If not, a `ValueError` is raised.\n", "\n", - "df.Field.from_xarray(bad_spacing)" - ] - }, - { - "cell_type": "markdown", - "id": "9670755a", - "metadata": {}, - "source": [ - "Lastly, **it is strongly advised that the input `xarray.DataArray` should have `p1`, `p2`, and `cell` attributes** required for the reconstruction of the mesh." + "Lastly, **it is strongly advised that the input `xarray.DataArray` should have `p1`, `p2`, and `cell` attributes** required for the reconstruction of the mesh. The `xarray.DataArray` in the [above example](#good_xarray) has all these properties." ] } ], From 48f662e8436e9bcee2186b3c8dccbcf133333a53 Mon Sep 17 00:00:00 2001 From: Martin Lang Date: Tue, 22 Mar 2022 16:32:33 +0100 Subject: [PATCH 50/54] British english spelling and typos --- docs/xarray-usage.ipynb | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/docs/xarray-usage.ipynb b/docs/xarray-usage.ipynb index dc07ec760..dba00f60b 100644 --- a/docs/xarray-usage.ipynb +++ b/docs/xarray-usage.ipynb @@ -11,7 +11,7 @@ "\n", "## Exporting `discretisedfield.Field` to `xarray.DataArray`\n", "\n", - "`to_xarray` method of the `discretisedfield.Field` object is utilized to export the field data to a DataArray." + "`to_xarray` method of the `discretisedfield.Field` object is utilised to export the field data to a DataArray." ] }, { @@ -118,7 +118,7 @@ "id": "74b90652", "metadata": {}, "source": [ - "The `DataArray` has four dimensions. Dimensions `x`, `y`, and `z` represents the geometric axes and their respective coordinates store the midpoints of cell edges along respective axes, while `comp` represents the components of the *field*. There will be no `comp` dimension if the stored field is a scalar field.\n", + "The `DataArray` has four dimensions. Dimensions `x`, `y`, and `z` represent the geometric axes and their respective coordinates store the midpoints of cell edges along respective axes, while `comp` represents the components of the *field*. There will be no `comp` dimension if the stored field is a scalar field.\n", "\n", "By default, the `DataArray` has four attributes, namely `units`, `cell`, `p1`, and `p2`. The last three attributes store the information about the mesh, and they prove useful for mesh reconstruction [from a `DataArray`](#from_xarray) object. The `units` attribute stores the unit of the field. \n", "\n", @@ -193,7 +193,7 @@ "id": "548e904a", "metadata": {}, "source": [ - "It is possible to select the cross-section of the magnetization along a particular axis as:" + "It is possible to select the cross-section of the magnetisation along a particular axis as:" ] }, { @@ -234,7 +234,7 @@ "id": "099a58c4", "metadata": {}, "source": [ - "The `DataArray.sel` method returns a new `DataArray` with only one coordinate along x-axis and hence a cross-section. The `method=\"nearest\"` argument matches the value along x-axis with the nearest midpoint.\n", + "The `DataArray.sel` method returns a new `DataArray` with only one coordinate along x axis and hence a cross-section. The `method=\"nearest\"` argument matches the value along x axis with the nearest midpoint.\n", "\n", "Similarly, one can also obtain a desired component of the field as:" ] @@ -445,9 +445,7 @@ "cell_type": "code", "execution_count": 45, "id": "7dc09fa2", - "metadata": { - "scrolled": false - }, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -579,6 +577,13 @@ "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.12" + }, + "widgets": { + "application/vnd.jupyter.widget-state+json": { + "state": {}, + "version_major": 2, + "version_minor": 0 + } } }, "nbformat": 4, From eb5ee0ccc5c5d81a3e5fa5e9f1082e2d89647d22 Mon Sep 17 00:00:00 2001 From: Martin Lang Date: Tue, 22 Mar 2022 16:37:42 +0100 Subject: [PATCH 51/54] Remove print around xarray in favor of html To avoid problems with nbval all cells that contain xarray html output are tagged with nbval-ignore-output. That way we do not compare the actual html representation (which we don't need to) but we would still notice when the cell execution fails. --- docs/xarray-usage.ipynb | 2193 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 2057 insertions(+), 136 deletions(-) diff --git a/docs/xarray-usage.ipynb b/docs/xarray-usage.ipynb index dba00f60b..f653ede7f 100644 --- a/docs/xarray-usage.ipynb +++ b/docs/xarray-usage.ipynb @@ -16,7 +16,7 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 1, "id": "756dbabb", "metadata": {}, "outputs": [ @@ -55,7 +55,7 @@ "Field(Mesh(Region(p1=(0, 0, 0), p2=(1e-08, 1e-08, 1e-08)), n=(2, 2, 2), attributes: (unit: m, fourierspace: False, isplane: False)), dim=3, components: (x, y, z))" ] }, - "execution_count": 22, + "execution_count": 1, "metadata": {}, "output_type": "execute_result" } @@ -74,43 +74,437 @@ }, { "cell_type": "code", - "execution_count": 43, + "execution_count": 2, "id": "705c72bc", - "metadata": {}, + "metadata": { + "tags": [ + "nbval-ignore-output" + ] + }, "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "array([[[[0., 0., 1.],\n", - " [0., 0., 1.]],\n", - "\n", - " [[0., 0., 1.],\n", - " [0., 0., 1.]]],\n", - "\n", - "\n", - " [[[0., 0., 1.],\n", - " [0., 0., 1.]],\n", - "\n", - " [[0., 0., 1.],\n", - " [0., 0., 1.]]]])\n", - "Coordinates:\n", - " * x (x) float64 2.5e-09 7.5e-09\n", - " * y (y) float64 2.5e-09 7.5e-09\n", - " * z (z) float64 2.5e-09 7.5e-09\n", - " * comp (comp) \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
<xarray.DataArray 'field' (x: 2, y: 2, z: 2, comp: 3)>\n",
+       "array([[[[0., 0., 1.],\n",
+       "         [0., 0., 1.]],\n",
+       "\n",
+       "        [[0., 0., 1.],\n",
+       "         [0., 0., 1.]]],\n",
+       "\n",
+       "\n",
+       "       [[[0., 0., 1.],\n",
+       "         [0., 0., 1.]],\n",
+       "\n",
+       "        [[0., 0., 1.],\n",
+       "         [0., 0., 1.]]]])\n",
+       "Coordinates:\n",
+       "  * x        (x) float64 2.5e-09 7.5e-09\n",
+       "  * y        (y) float64 2.5e-09 7.5e-09\n",
+       "  * z        (z) float64 2.5e-09 7.5e-09\n",
+       "  * comp     (comp) <U1 'x' 'y' 'z'\n",
+       "Attributes:\n",
+       "    units:    None\n",
+       "    cell:     (5e-09, 5e-09, 5e-09)\n",
+       "    p1:       (0, 0, 0)\n",
+       "    p2:       (1e-08, 1e-08, 1e-08)
" + ], + "text/plain": [ + "\n", + "array([[[[0., 0., 1.],\n", + " [0., 0., 1.]],\n", + "\n", + " [[0., 0., 1.],\n", + " [0., 0., 1.]]],\n", + "\n", + "\n", + " [[[0., 0., 1.],\n", + " [0., 0., 1.]],\n", + "\n", + " [[0., 0., 1.],\n", + " [0., 0., 1.]]]])\n", + "Coordinates:\n", + " * x (x) float64 2.5e-09 7.5e-09\n", + " * y (y) float64 2.5e-09 7.5e-09\n", + " * z (z) float64 2.5e-09 7.5e-09\n", + " * comp (comp) \n", - "array([[[0., 0., 1.],\n", - " [0., 0., 1.]],\n", - "\n", - " [[0., 0., 1.],\n", - " [0., 0., 1.]]])\n", - "Coordinates:\n", - " x float64 2.5e-09\n", - " * y (y) float64 2.5e-09 7.5e-09\n", - " * z (z) float64 2.5e-09 7.5e-09\n", - " * comp (comp) \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
<xarray.DataArray 'field' (y: 2, z: 2, comp: 3)>\n",
+       "array([[[0., 0., 1.],\n",
+       "        [0., 0., 1.]],\n",
+       "\n",
+       "       [[0., 0., 1.],\n",
+       "        [0., 0., 1.]]])\n",
+       "Coordinates:\n",
+       "    x        float64 2.5e-09\n",
+       "  * y        (y) float64 2.5e-09 7.5e-09\n",
+       "  * z        (z) float64 2.5e-09 7.5e-09\n",
+       "  * comp     (comp) <U1 'x' 'y' 'z'\n",
+       "Attributes:\n",
+       "    units:    None\n",
+       "    cell:     (5e-09, 5e-09, 5e-09)\n",
+       "    p1:       (0, 0, 0)\n",
+       "    p2:       (1e-08, 1e-08, 1e-08)
" + ], + "text/plain": [ + "\n", + "array([[[0., 0., 1.],\n", + " [0., 0., 1.]],\n", + "\n", + " [[0., 0., 1.],\n", + " [0., 0., 1.]]])\n", + "Coordinates:\n", + " x float64 2.5e-09\n", + " * y (y) float64 2.5e-09 7.5e-09\n", + " * z (z) float64 2.5e-09 7.5e-09\n", + " * comp (comp) \n", - "array([[[1., 1.],\n", - " [1., 1.]],\n", - "\n", - " [[1., 1.],\n", - " [1., 1.]]])\n", - "Coordinates:\n", - " * x (x) float64 2.5e-09 7.5e-09\n", - " * y (y) float64 2.5e-09 7.5e-09\n", - " * z (z) float64 2.5e-09 7.5e-09\n", - " comp \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
<xarray.DataArray 'field' (x: 2, y: 2, z: 2)>\n",
+       "array([[[1., 1.],\n",
+       "        [1., 1.]],\n",
+       "\n",
+       "       [[1., 1.],\n",
+       "        [1., 1.]]])\n",
+       "Coordinates:\n",
+       "  * x        (x) float64 2.5e-09 7.5e-09\n",
+       "  * y        (y) float64 2.5e-09 7.5e-09\n",
+       "  * z        (z) float64 2.5e-09 7.5e-09\n",
+       "    comp     <U1 'z'\n",
+       "Attributes:\n",
+       "    units:    None\n",
+       "    cell:     (5e-09, 5e-09, 5e-09)\n",
+       "    p1:       (0, 0, 0)\n",
+       "    p2:       (1e-08, 1e-08, 1e-08)
" + ], + "text/plain": [ + "\n", + "array([[[1., 1.],\n", + " [1., 1.]],\n", + "\n", + " [[1., 1.],\n", + " [1., 1.]]])\n", + "Coordinates:\n", + " * x (x) float64 2.5e-09 7.5e-09\n", + " * y (y) float64 2.5e-09 7.5e-09\n", + " * z (z) float64 2.5e-09 7.5e-09\n", + " comp \n", - "array([[1., 1.],\n", - " [1., 1.]])\n", - "Coordinates:\n", - " x float64 2.5e-09\n", - " * y (y) float64 2.5e-09 7.5e-09\n", - " * z (z) float64 2.5e-09 7.5e-09\n", - " comp \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
<xarray.DataArray 'field' (y: 2, z: 2)>\n",
+       "array([[1., 1.],\n",
+       "       [1., 1.]])\n",
+       "Coordinates:\n",
+       "    x        float64 2.5e-09\n",
+       "  * y        (y) float64 2.5e-09 7.5e-09\n",
+       "  * z        (z) float64 2.5e-09 7.5e-09\n",
+       "    comp     <U1 'z'\n",
+       "Attributes:\n",
+       "    units:    None\n",
+       "    cell:     (5e-09, 5e-09, 5e-09)\n",
+       "    p1:       (0, 0, 0)\n",
+       "    p2:       (1e-08, 1e-08, 1e-08)
" + ], + "text/plain": [ + "\n", + "array([[1., 1.],\n", + " [1., 1.]])\n", + "Coordinates:\n", + " x float64 2.5e-09\n", + " * y (y) float64 2.5e-09 7.5e-09\n", + " * z (z) float64 2.5e-09 7.5e-09\n", + " comp " ] @@ -376,7 +1904,7 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 9, "id": "3953428f", "metadata": {}, "outputs": [ @@ -415,7 +1943,7 @@ "Field(Mesh(Region(p1=(0, 0, 0), p2=(1e-08, 1e-08, 1e-08)), n=(2, 2, 2), attributes: (unit: m, fourierspace: False, isplane: False)), dim=3, components: (x, y, z))" ] }, - "execution_count": 32, + "execution_count": 9, "metadata": {}, "output_type": "execute_result" } @@ -443,37 +1971,430 @@ }, { "cell_type": "code", - "execution_count": 45, + "execution_count": 10, "id": "7dc09fa2", - "metadata": {}, + "metadata": { + "tags": [ + "nbval-ignore-output" + ] + }, "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "array([[[[1., 1., 1.],\n", - " [1., 1., 1.]],\n", - "\n", - " [[1., 1., 1.],\n", - " [1., 1., 1.]]],\n", - "\n", - "\n", - " [[[1., 1., 1.],\n", - " [1., 1., 1.]],\n", - "\n", - " [[1., 1., 1.],\n", - " [1., 1., 1.]]]])\n", - "Coordinates:\n", - " * x (x) float64 2.5e-09 7.5e-09\n", - " * y (y) float64 2.5e-09 7.5e-09\n", - " * z (z) float64 2.5e-09 7.5e-09\n", - " * comp (comp) \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
<xarray.DataArray 'mag' (x: 2, y: 2, z: 2, comp: 3)>\n",
+       "array([[[[1., 1., 1.],\n",
+       "         [1., 1., 1.]],\n",
+       "\n",
+       "        [[1., 1., 1.],\n",
+       "         [1., 1., 1.]]],\n",
+       "\n",
+       "\n",
+       "       [[[1., 1., 1.],\n",
+       "         [1., 1., 1.]],\n",
+       "\n",
+       "        [[1., 1., 1.],\n",
+       "         [1., 1., 1.]]]])\n",
+       "Coordinates:\n",
+       "  * x        (x) float64 2.5e-09 7.5e-09\n",
+       "  * y        (y) float64 2.5e-09 7.5e-09\n",
+       "  * z        (z) float64 2.5e-09 7.5e-09\n",
+       "  * comp     (comp) <U1 'x' 'y' 'z'\n",
+       "Attributes:\n",
+       "    cell:     [5e-09, 5e-09, 5e-09]\n",
+       "    p1:       [0.0, 0.0, 0.0]\n",
+       "    p2:       [1e-08, 1e-08, 1e-08]
" + ], + "text/plain": [ + "\n", + "array([[[[1., 1., 1.],\n", + " [1., 1., 1.]],\n", + "\n", + " [[1., 1., 1.],\n", + " [1., 1., 1.]]],\n", + "\n", + "\n", + " [[[1., 1., 1.],\n", + " [1., 1., 1.]],\n", + "\n", + " [[1., 1., 1.],\n", + " [1., 1., 1.]]]])\n", + "Coordinates:\n", + " * x (x) float64 2.5e-09 7.5e-09\n", + " * y (y) float64 2.5e-09 7.5e-09\n", + " * z (z) float64 2.5e-09 7.5e-09\n", + " * comp (comp) Date: Tue, 22 Mar 2022 16:40:54 +0100 Subject: [PATCH 52/54] Use code-like str instead of the word string. --- docs/xarray-usage.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/xarray-usage.ipynb b/docs/xarray-usage.ipynb index f653ede7f..01d1fc894 100644 --- a/docs/xarray-usage.ipynb +++ b/docs/xarray-usage.ipynb @@ -1882,7 +1882,7 @@ "source": [ "### `to_xarray` exceptions\n", "\n", - "The `to_xarray` method raises `TypeError` if either `name` or `units` arguments are not strings." + "The `to_xarray` method raises `TypeError` if either `name` or `units` arguments are not `str`." ] }, { From 2cac3d5a6d514ada20a34819fdd28a0d4af13970 Mon Sep 17 00:00:00 2001 From: swapneelap Date: Wed, 23 Mar 2022 15:43:44 +0530 Subject: [PATCH 53/54] Fix(Field): update `to_xarray` to use `mesh.midpoints` --- discretisedfield/field.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/discretisedfield/field.py b/discretisedfield/field.py index d358801a6..b3f50d47d 100644 --- a/discretisedfield/field.py +++ b/discretisedfield/field.py @@ -3553,7 +3553,7 @@ def to_xarray(self, name='field', units=None): The function returns an ``xarray.DataArray`` with dimensions ``x``, ``y``, ``z``, and ``comp`` (``only if field.dim > 1``). The coordinates - of the geometric dimensions are derived from ``self.mesh.axis_points``, + of the geometric dimensions are derived from ``self.mesh.midpoints``, and for vector field components from ``self.components``. Addtionally, the values of ``self.mesh.cell``, ``self.mesh.region.p1``, and ``self.mesh.region.p2`` are stored as ``cell``, ``p1``, and ``p2`` @@ -3626,7 +3626,7 @@ def to_xarray(self, name='field', units=None): axes = ['x', 'y', 'z'] data_array_coords = { - axis: np.fromiter(self.mesh.axis_points(axis), dtype=float) + axis: getattr(self.mesh.midpoints, axis) for axis in axes } From 9f9dca311098c2ad3e198702cc6a5f6de49b8db7 Mon Sep 17 00:00:00 2001 From: swapneelap Date: Wed, 23 Mar 2022 15:45:42 +0530 Subject: [PATCH 54/54] Test(test_field): update tests to use `mesh.midpoints` --- discretisedfield/tests/test_field.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/discretisedfield/tests/test_field.py b/discretisedfield/tests/test_field.py index 48de5abb3..31a3590c5 100644 --- a/discretisedfield/tests/test_field.py +++ b/discretisedfield/tests/test_field.py @@ -2251,7 +2251,7 @@ def test_to_xarray_valid_args(self): assert fxa.attrs['p2'] == f.mesh.region.p2 for i in 'xyz': assert np.array_equal( - np.array(list(f.mesh.axis_points(i))), + getattr(f.mesh.midpoints, i), fxa[i].values ) assert fxa[i].attrs['units'] == f.mesh.attributes['unit'] @@ -2268,7 +2268,7 @@ def test_to_xarray_valid_args(self): assert fxa.attrs['p2'] == f.mesh.region.p2 for i in 'xyz': assert np.array_equal( - np.array(list(f.mesh.axis_points(i))), + getattr(f.mesh.midpoints, i), fxa[i].values ) assert fxa[i].attrs['units'] == f.mesh.attributes['unit']