sdf-xarray 0.3.0__tar.gz → 0.3.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/CITATION.cff +4 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/PKG-INFO +2 -2
- sdf_xarray-0.3.2/docs/tutorial_dataset_2d/0000.sdf +0 -0
- sdf_xarray-0.3.2/docs/tutorial_dataset_2d/0001.sdf +0 -0
- sdf_xarray-0.3.2/docs/tutorial_dataset_2d/0002.sdf +0 -0
- sdf_xarray-0.3.2/docs/tutorial_dataset_2d/0003.sdf +0 -0
- sdf_xarray-0.3.2/docs/tutorial_dataset_2d/0004.sdf +0 -0
- sdf_xarray-0.3.2/docs/tutorial_dataset_2d/0005.sdf +0 -0
- sdf_xarray-0.3.2/docs/tutorial_dataset_2d/input.deck +65 -0
- sdf_xarray-0.3.2/docs/unit_conversion.rst +228 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/pyproject.toml +1 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/src/sdf_xarray/__init__.py +113 -15
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/src/sdf_xarray/_version.py +3 -3
- sdf_xarray-0.3.2/src/sdf_xarray/dataset_accessor.py +73 -0
- sdf_xarray-0.3.2/tests/example_files_3D/0000.sdf +0 -0
- sdf_xarray-0.3.2/tests/example_files_3D/0001.sdf +0 -0
- sdf_xarray-0.3.2/tests/example_files_3D/input.deck +54 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/tests/test_basic.py +232 -1
- sdf_xarray-0.3.2/tests/test_epoch_dataset_accessor.py +146 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/uv.lock +481 -476
- sdf_xarray-0.3.0/docs/unit_conversion.rst +0 -175
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/.github/workflows/black.yml +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/.github/workflows/build_publish.yml +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/.github/workflows/lint.yml +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/.github/workflows/tests.yml +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/.gitignore +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/.gitmodules +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/.readthedocs.yaml +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/BEAM.png +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/CMakeLists.txt +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/CONTRIBUTING.md +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/LICENCE +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/PlasmaFAIR.svg +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/README.md +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/.gitignore +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/_templates/custom-class-template.rst +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/_templates/custom-module-template.rst +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/api.rst +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/conf.py +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/contributing.rst +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/getting_started.rst +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/index.rst +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/key_functionality.rst +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/known_issues.rst +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/make.bat +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0000.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0001.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0002.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0003.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0004.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0005.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0006.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0007.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0008.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0009.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0010.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0011.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0012.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0013.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0014.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0015.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0016.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0017.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0018.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0019.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0020.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0021.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0022.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0023.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0024.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0025.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0026.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0027.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0028.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0029.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0030.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0031.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0032.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0033.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0034.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0035.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0036.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0037.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0038.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0039.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0040.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/deck.status +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/epoch1d.dat +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/input.deck +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/normal.visit +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/restart.visit +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/src/sdf_xarray/csdf.pxd +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/src/sdf_xarray/plotting.py +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/src/sdf_xarray/sdf_interface.pyx +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/tests/example_array_no_grids/0000.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/tests/example_array_no_grids/0001.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/tests/example_array_no_grids/README.md +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/tests/example_array_no_grids/input.deck +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/tests/example_dist_fn/0000.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/tests/example_dist_fn/0001.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/tests/example_dist_fn/0002.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/tests/example_dist_fn/input.deck +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/tests/example_files_1D/0000.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/tests/example_files_1D/0001.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/tests/example_files_1D/0002.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/tests/example_files_1D/0003.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/tests/example_files_1D/0004.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/tests/example_files_1D/0005.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/tests/example_files_1D/0006.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/tests/example_files_1D/0007.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/tests/example_files_1D/0008.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/tests/example_files_1D/0009.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/tests/example_files_1D/0010.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/tests/example_files_1D/README.md +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/tests/example_files_1D/input.deck +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/tests/example_files_2D_moving_window/0000.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/tests/example_files_2D_moving_window/0001.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/tests/example_files_2D_moving_window/0002.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/tests/example_files_2D_moving_window/0003.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/tests/example_files_2D_moving_window/0004.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/tests/example_files_2D_moving_window/input.deck +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/tests/example_mismatched_files/0000.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/tests/example_mismatched_files/0001.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/tests/example_mismatched_files/0002.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/tests/example_two_probes_2D/0000.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/tests/example_two_probes_2D/0001.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/tests/example_two_probes_2D/0002.sdf +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/tests/example_two_probes_2D/input.deck +0 -0
- {sdf_xarray-0.3.0 → sdf_xarray-0.3.2}/tests/test_cython.py +0 -0
- /sdf_xarray-0.3.0/tests/test_epoch_accessor.py → /sdf_xarray-0.3.2/tests/test_epoch_dataarray_accessor.py +0 -0
|
@@ -16,5 +16,9 @@ authors:
|
|
|
16
16
|
given-names: Shaun
|
|
17
17
|
orcid: 'https://orcid.org/0009-0005-0693-030X'
|
|
18
18
|
affiliation: University of York
|
|
19
|
+
- family-names: Herdman
|
|
20
|
+
given-names: Chris
|
|
21
|
+
orcid: 'https://orcid.org/0000-0002-5159-0130'
|
|
22
|
+
affiliation: University of York
|
|
19
23
|
doi: 10.5281/zenodo.15351323
|
|
20
24
|
date-released: '2024-07-25'
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sdf-xarray
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.2
|
|
4
4
|
Summary: Provides a backend for xarray to read SDF files as created by the EPOCH plasma PIC code.
|
|
5
|
-
Author-Email: Peter Hill <peter.hill@york.ac.uk>, Joel Adams <joel.adams@york.ac.uk>, Shaun Doherty <shaun.doherty@york.ac.uk>
|
|
5
|
+
Author-Email: Peter Hill <peter.hill@york.ac.uk>, Joel Adams <joel.adams@york.ac.uk>, Shaun Doherty <shaun.doherty@york.ac.uk>, Chris Herdman <chris.herdman@york.ac.uk>
|
|
6
6
|
License-Expression: BSD-3-Clause
|
|
7
7
|
Classifier: Development Status :: 5 - Production/Stable
|
|
8
8
|
Classifier: Intended Audience :: Science/Research
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
begin:control
|
|
2
|
+
nx = 64
|
|
3
|
+
ny = 64
|
|
4
|
+
|
|
5
|
+
# Final time of simulation
|
|
6
|
+
t_end = 5 * femto
|
|
7
|
+
|
|
8
|
+
# Size of domain
|
|
9
|
+
x_min = 0
|
|
10
|
+
x_max = 6 * micron
|
|
11
|
+
|
|
12
|
+
y_min = 0
|
|
13
|
+
y_max = 6 * micron
|
|
14
|
+
|
|
15
|
+
stdout_frequency = 1
|
|
16
|
+
nparticles = nx * ny * 50
|
|
17
|
+
end:control
|
|
18
|
+
|
|
19
|
+
begin:constant
|
|
20
|
+
n_elec = 1000
|
|
21
|
+
L_target_x = 2 * micron
|
|
22
|
+
L_target_y = 4 * micron
|
|
23
|
+
|
|
24
|
+
x_center = (x_min + x_max) / 2
|
|
25
|
+
y_center = (y_min + y_max) / 2
|
|
26
|
+
|
|
27
|
+
density_profile = if( (abs(x - x_center) lt L_target_x/2), if( (abs(y - y_center) lt L_target_y/2), 1, 0), 0)
|
|
28
|
+
end:constant
|
|
29
|
+
|
|
30
|
+
begin:boundaries
|
|
31
|
+
bc_x_min = periodic
|
|
32
|
+
bc_x_max = periodic
|
|
33
|
+
bc_y_min = periodic
|
|
34
|
+
bc_y_max = periodic
|
|
35
|
+
end:boundaries
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
begin:species
|
|
39
|
+
name = Electron
|
|
40
|
+
frac = 0.5
|
|
41
|
+
number_density = n_elec * density_profile
|
|
42
|
+
identify:electron
|
|
43
|
+
end:species
|
|
44
|
+
|
|
45
|
+
begin:species
|
|
46
|
+
name = Ion
|
|
47
|
+
frac = 0.5
|
|
48
|
+
number_density = n_elec * density_profile
|
|
49
|
+
identify:proton
|
|
50
|
+
end:species
|
|
51
|
+
|
|
52
|
+
begin:output_global
|
|
53
|
+
force_last_to_be_restartable = F
|
|
54
|
+
end:output_global
|
|
55
|
+
|
|
56
|
+
begin:output
|
|
57
|
+
name = normal
|
|
58
|
+
|
|
59
|
+
dt_snapshot = 1 * femto
|
|
60
|
+
|
|
61
|
+
grid = always
|
|
62
|
+
number_density = always + species
|
|
63
|
+
|
|
64
|
+
end:output
|
|
65
|
+
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
.. _sec-unit-conversion:
|
|
2
|
+
|
|
3
|
+
===============
|
|
4
|
+
Unit Conversion
|
|
5
|
+
===============
|
|
6
|
+
|
|
7
|
+
The ``sdf-xarray`` package automatically extracts the units for each
|
|
8
|
+
coordinate/variable/constant from an SDF file and stores them as an :class:`xarray.Dataset`
|
|
9
|
+
attribute called ``"units"``. Sometimes we want to convert our data from one format to
|
|
10
|
+
another, e.g. converting the grid coordinates from meters to microns, time from seconds
|
|
11
|
+
to femto-seconds or particle energy from Joules to electron-volts.
|
|
12
|
+
|
|
13
|
+
.. ipython:: python
|
|
14
|
+
|
|
15
|
+
from sdf_xarray import open_mfdataset
|
|
16
|
+
import matplotlib.pyplot as plt
|
|
17
|
+
plt.rcParams.update({
|
|
18
|
+
"axes.labelsize": 16,
|
|
19
|
+
"xtick.labelsize": 14,
|
|
20
|
+
"ytick.labelsize": 14,
|
|
21
|
+
"axes.titlesize": 16
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
=====================
|
|
26
|
+
Rescaling Coordinates
|
|
27
|
+
=====================
|
|
28
|
+
|
|
29
|
+
For simple scaling and unit relabeling of coordinates (e.g., converting meters to microns),
|
|
30
|
+
the most straightforward approach is to use the ``rescale_coords()`` method
|
|
31
|
+
via the custom ``xarray.Dataset.epoch`` dataset accessor.
|
|
32
|
+
|
|
33
|
+
This method scales the coordinate values by a given multiplier and updates the ``"units"``
|
|
34
|
+
attribute in one step.
|
|
35
|
+
|
|
36
|
+
Rescaling Grid Coordinates
|
|
37
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
38
|
+
|
|
39
|
+
We can use the ``xarray.Dataset.epoch.rescale_coords()`` method to convert X, Y, and Z
|
|
40
|
+
coordinates from meters (m) to microns (µm) by applying a multiplier of ``1e6``.
|
|
41
|
+
|
|
42
|
+
.. ipython:: python
|
|
43
|
+
|
|
44
|
+
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(16, 6))
|
|
45
|
+
|
|
46
|
+
with open_mfdataset("tutorial_dataset_2d/*.sdf") as ds:
|
|
47
|
+
ds_in_microns = ds.epoch.rescale_coords(
|
|
48
|
+
multiplier=1e6,
|
|
49
|
+
unit_label="µm",
|
|
50
|
+
coord_names=["X_Grid_mid", "Y_Grid_mid"]
|
|
51
|
+
)
|
|
52
|
+
derived_number_density = ds["Derived_Number_Density_Electron"].isel(time=0).compute()
|
|
53
|
+
derived_number_density_microns = ds_in_microns["Derived_Number_Density_Electron"].isel(time=0).compute()
|
|
54
|
+
|
|
55
|
+
derived_number_density.plot(ax=ax1, x="X_Grid_mid", y="Y_Grid_mid")
|
|
56
|
+
ax1.set_title("Original X Coordinate (m)")
|
|
57
|
+
|
|
58
|
+
derived_number_density_microns.plot(ax=ax2, x="X_Grid_mid", y="Y_Grid_mid")
|
|
59
|
+
ax2.set_title("Rescaled X Coordinate (µm)")
|
|
60
|
+
|
|
61
|
+
@savefig coordinate_conversion.png width=9in
|
|
62
|
+
fig.tight_layout()
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
Rescaling Time Coordinate
|
|
66
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
67
|
+
|
|
68
|
+
We can also use the ``xarray.Dataset.epoch.rescale_coords()`` method to convert the time
|
|
69
|
+
coordinate from seconds (s) to femto-seconds (fs) by applying a multiplier of ``1e15``.
|
|
70
|
+
|
|
71
|
+
.. ipython:: python
|
|
72
|
+
|
|
73
|
+
with open_mfdataset("tutorial_dataset_2d/*.sdf") as ds:
|
|
74
|
+
ds_time_in_femto = ds.epoch.rescale_coords(
|
|
75
|
+
multiplier=1e15,
|
|
76
|
+
unit_label="fs",
|
|
77
|
+
coord_names="time"
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
print(f"[Original] units: {ds['time'].attrs['units']}, values: {ds['time'].values}")
|
|
81
|
+
print(f"[Rescaled] units: {ds_time_in_femto['time'].attrs['units']}, values: {ds_time_in_femto['time'].values}")
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
================================
|
|
85
|
+
Unit Conversion with pint-xarray
|
|
86
|
+
================================
|
|
87
|
+
|
|
88
|
+
While this is sufficient for most use cases, we can enhance this functionality
|
|
89
|
+
using the `pint <https://pint.readthedocs.io/en/stable/getting/index.html>`_ library.
|
|
90
|
+
Pint allows us to specify the units of a given array and convert them
|
|
91
|
+
to another, which is incredibly handy. We can take this a step further,
|
|
92
|
+
however, and utilize the `pint-xarray
|
|
93
|
+
<https://pint-xarray.readthedocs.io/en/latest/>`_ library. This library
|
|
94
|
+
allows us to infer units directly from an `xarray.Dataset.attrs` while
|
|
95
|
+
retaining all the information about the `xarray.Dataset`. This works
|
|
96
|
+
very similarly to taking a NumPy array and multiplying it by a constant or
|
|
97
|
+
another array, which returns a new array; however, this library will also
|
|
98
|
+
retain the unit logic (specifically the ``"units"`` information).
|
|
99
|
+
|
|
100
|
+
.. note::
|
|
101
|
+
Unit conversion is not supported on coordinates in ``pint-xarray`` which is due to an
|
|
102
|
+
underlying issue with how ``xarray`` implements indexes.
|
|
103
|
+
|
|
104
|
+
Installation
|
|
105
|
+
~~~~~~~~~~~~
|
|
106
|
+
|
|
107
|
+
To install the pint libraries you can simply run the following optional
|
|
108
|
+
dependency pip command which will install both the ``pint`` and ``pint-xarray``
|
|
109
|
+
libraries. You can install these optional dependencies via pip:
|
|
110
|
+
|
|
111
|
+
.. code:: console
|
|
112
|
+
|
|
113
|
+
$ pip install "sdf_xarray[pint]"
|
|
114
|
+
|
|
115
|
+
.. note::
|
|
116
|
+
Once you install ``pint-xarray`` it is automatically picked up and loaded
|
|
117
|
+
by the code so you should have access to the ``xarray.Dataset.pint`` accessor.
|
|
118
|
+
|
|
119
|
+
Quantifying Arrays
|
|
120
|
+
~~~~~~~~~~~~~~~~~~
|
|
121
|
+
|
|
122
|
+
When using ``pint-xarray``, the library attempts to infer units from the
|
|
123
|
+
``"units"`` attribute on each `xarray.DataArray`. Alternatively, you can
|
|
124
|
+
also specify the units yourself by passing a string into the
|
|
125
|
+
``xarray.Dataset.DataArray.pint.quantify()`` function call. Once the type is inferred
|
|
126
|
+
the original `xarray.DataArray` will be converted to a `pint.Quantity`
|
|
127
|
+
and the ``"units"`` attribute will
|
|
128
|
+
be removed.
|
|
129
|
+
|
|
130
|
+
In the following example we will extract the time-resolved total particle
|
|
131
|
+
energy of electrons which is measured in Joules and convert it to electron
|
|
132
|
+
volts.
|
|
133
|
+
|
|
134
|
+
.. ipython:: python
|
|
135
|
+
|
|
136
|
+
with open_mfdataset("tutorial_dataset_1d/*.sdf") as ds:
|
|
137
|
+
total_particle_energy = ds["Total_Particle_Energy_Electron"]
|
|
138
|
+
|
|
139
|
+
total_particle_energy
|
|
140
|
+
|
|
141
|
+
total_particle_energy = ds["Total_Particle_Energy_Electron"].pint.quantify()
|
|
142
|
+
|
|
143
|
+
total_particle_energy
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
Now that this dataset has been converted a `pint.Quantity`, we can check
|
|
147
|
+
it's units and dimensionality
|
|
148
|
+
|
|
149
|
+
.. ipython:: python
|
|
150
|
+
|
|
151
|
+
total_particle_energy.pint.units
|
|
152
|
+
total_particle_energy.pint.dimensionality
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
Converting Units
|
|
156
|
+
~~~~~~~~~~~~~~~~
|
|
157
|
+
|
|
158
|
+
We can now convert it to electron volts utilising the `pint.Quantity.to`
|
|
159
|
+
function
|
|
160
|
+
|
|
161
|
+
.. ipython:: python
|
|
162
|
+
|
|
163
|
+
total_particle_energy_ev = total_particle_energy.pint.to("eV")
|
|
164
|
+
|
|
165
|
+
Unit Propagation
|
|
166
|
+
~~~~~~~~~~~~~~~~
|
|
167
|
+
|
|
168
|
+
Suppose instead of converting to ``"eV"``, we want to convert to ``"W"``
|
|
169
|
+
(watts). To do this, we divide the total particle energy by time. However,
|
|
170
|
+
since coordinates in `xarray.Dataset` cannot be directly converted to
|
|
171
|
+
`pint.Quantity`, we must first extract the coordinate values manually
|
|
172
|
+
and create a new Pint quantity for time.
|
|
173
|
+
|
|
174
|
+
Once both arrays are quantified, Pint will automatically handle the unit
|
|
175
|
+
propagation when we perform arithmetic operations like division.
|
|
176
|
+
|
|
177
|
+
.. note::
|
|
178
|
+
Pint does not automatically simplify ``"J/s"`` to ``"W"``, so we use
|
|
179
|
+
`pint.Quantity.to` to convert the unit string. Since these units are
|
|
180
|
+
the same it will not change the underlying data, only the units. This is
|
|
181
|
+
only a small formatting choice and is not required.
|
|
182
|
+
|
|
183
|
+
.. ipython:: python
|
|
184
|
+
|
|
185
|
+
import pint
|
|
186
|
+
time_values = total_particle_energy.coords["time"].data
|
|
187
|
+
time = pint.Quantity(time_values, "s")
|
|
188
|
+
total_particle_energy_w = total_particle_energy / time
|
|
189
|
+
total_particle_energy_w.pint.units
|
|
190
|
+
total_particle_energy_w = total_particle_energy_w.pint.to("W")
|
|
191
|
+
total_particle_energy_w.pint.units
|
|
192
|
+
|
|
193
|
+
Dequantifying and Restoring Units
|
|
194
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
195
|
+
|
|
196
|
+
.. note::
|
|
197
|
+
If this function is not called prior to plotting then the ``units`` will be
|
|
198
|
+
inferred from the `pint.Quantity` array which will return the long
|
|
199
|
+
name of the units. i.e. instead of returning ``"eV"`` it will return
|
|
200
|
+
``"electron_volt"``.
|
|
201
|
+
|
|
202
|
+
The ``xarray.Dataset.DataArray.pint.dequantify`` function converts the data from
|
|
203
|
+
`pint.Quantity` back to the original `xarray.DataArray` and adds
|
|
204
|
+
the ``"units"`` attribute back in. It also has an optional ``format`` parameter
|
|
205
|
+
that allows you to specify the formatting type of ``"units"`` attribute. We
|
|
206
|
+
have used the ``format="~P"`` option as it shortens the unit to its
|
|
207
|
+
"short pretty" format (``"eV"``). For more options, see the `Pint formatting
|
|
208
|
+
documentation <https://pint.readthedocs.io/en/stable/user/formatting.html>`_.
|
|
209
|
+
|
|
210
|
+
.. ipython:: python
|
|
211
|
+
|
|
212
|
+
total_particle_energy_ev = total_particle_energy_ev.pint.dequantify(format="~P")
|
|
213
|
+
total_particle_energy_w = total_particle_energy_w.pint.dequantify(format="~P")
|
|
214
|
+
total_particle_energy_ev
|
|
215
|
+
|
|
216
|
+
To confirm the conversion has worked correctly, we can plot the original and
|
|
217
|
+
converted `xarray.Dataset` side by side:
|
|
218
|
+
|
|
219
|
+
.. ipython:: python
|
|
220
|
+
|
|
221
|
+
fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(16,8))
|
|
222
|
+
ds["Total_Particle_Energy_Electron"].plot(ax=ax1)
|
|
223
|
+
total_particle_energy_ev.plot(ax=ax2)
|
|
224
|
+
total_particle_energy_w.plot(ax=ax3)
|
|
225
|
+
ax4.set_visible(False)
|
|
226
|
+
fig.suptitle("Comparison of conversion from Joules to electron volts and watts", fontsize="18")
|
|
227
|
+
@savefig unit_conversion.png width=9in
|
|
228
|
+
fig.tight_layout()
|
|
@@ -16,6 +16,7 @@ authors = [
|
|
|
16
16
|
{ name = "Peter Hill", email = "peter.hill@york.ac.uk" },
|
|
17
17
|
{ name = "Joel Adams", email = "joel.adams@york.ac.uk" },
|
|
18
18
|
{ name = "Shaun Doherty", email = "shaun.doherty@york.ac.uk" },
|
|
19
|
+
{ name = "Chris Herdman", email = "chris.herdman@york.ac.uk" },
|
|
19
20
|
]
|
|
20
21
|
requires-python = ">=3.10,<3.14"
|
|
21
22
|
dependencies = ["numpy>=2.0.0", "xarray>=2024.1.0", "dask>=2024.7.1"]
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import contextlib
|
|
1
2
|
import os
|
|
2
3
|
import re
|
|
3
4
|
from collections import Counter, defaultdict
|
|
@@ -18,10 +19,16 @@ from xarray.core import indexing
|
|
|
18
19
|
from xarray.core.utils import close_on_error, try_read_magic_number_from_path
|
|
19
20
|
from xarray.core.variable import Variable
|
|
20
21
|
|
|
21
|
-
# NOTE: Do not delete
|
|
22
|
-
# imported when the user imports sdf_xarray
|
|
22
|
+
# NOTE: Do not delete these lines, otherwise the "epoch" dataset and dataarray
|
|
23
|
+
# accessors will not be imported when the user imports sdf_xarray
|
|
24
|
+
import sdf_xarray.dataset_accessor
|
|
23
25
|
import sdf_xarray.plotting # noqa: F401
|
|
24
26
|
|
|
27
|
+
# NOTE: This attempts to initialise with the "pint" accessor if the user
|
|
28
|
+
# has installed the package
|
|
29
|
+
with contextlib.suppress(ImportError):
|
|
30
|
+
import pint_xarray # noqa: F401
|
|
31
|
+
|
|
25
32
|
from .sdf_interface import Constant, SDFFile # type: ignore # noqa: PGH003
|
|
26
33
|
|
|
27
34
|
# TODO Remove this once the new kwarg options are fully implemented
|
|
@@ -77,8 +84,45 @@ def _resolve_glob(path_glob: PathLike | Iterable[PathLike]):
|
|
|
77
84
|
return paths
|
|
78
85
|
|
|
79
86
|
|
|
80
|
-
def
|
|
81
|
-
"""
|
|
87
|
+
def purge_unselected_data_vars(ds: xr.Dataset, data_vars: list[str]) -> xr.Dataset:
|
|
88
|
+
"""
|
|
89
|
+
If the user has exclusively requested only certain variables be
|
|
90
|
+
loaded in then we purge all other variables and dimensions
|
|
91
|
+
"""
|
|
92
|
+
existing_data_vars = set(ds.data_vars.keys())
|
|
93
|
+
vars_to_keep = set(data_vars) & existing_data_vars
|
|
94
|
+
vars_to_drop = existing_data_vars - vars_to_keep
|
|
95
|
+
ds = ds.drop_vars(vars_to_drop)
|
|
96
|
+
|
|
97
|
+
existing_dims = set(ds.sizes)
|
|
98
|
+
dims_to_keep = set()
|
|
99
|
+
for var in vars_to_keep:
|
|
100
|
+
dims_to_keep.update(ds[var].coords._names)
|
|
101
|
+
dims_to_keep.update(ds[var].dims)
|
|
102
|
+
|
|
103
|
+
coords_to_drop = existing_dims - dims_to_keep
|
|
104
|
+
return ds.drop_dims(coords_to_drop)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def combine_datasets(
|
|
108
|
+
path_glob: Iterable | str, data_vars: list[str], **kwargs
|
|
109
|
+
) -> xr.Dataset:
|
|
110
|
+
"""
|
|
111
|
+
Combine all datasets using a single time dimension, optionally extract
|
|
112
|
+
data from only the listed data_vars
|
|
113
|
+
"""
|
|
114
|
+
|
|
115
|
+
if data_vars is not None:
|
|
116
|
+
return xr.open_mfdataset(
|
|
117
|
+
path_glob,
|
|
118
|
+
join="outer",
|
|
119
|
+
coords="different",
|
|
120
|
+
compat="no_conflicts",
|
|
121
|
+
combine="nested",
|
|
122
|
+
concat_dim="time",
|
|
123
|
+
preprocess=SDFPreprocess(data_vars=data_vars),
|
|
124
|
+
**kwargs,
|
|
125
|
+
)
|
|
82
126
|
|
|
83
127
|
return xr.open_mfdataset(
|
|
84
128
|
path_glob,
|
|
@@ -97,6 +141,7 @@ def open_mfdataset(
|
|
|
97
141
|
separate_times: bool = False,
|
|
98
142
|
keep_particles: bool = False,
|
|
99
143
|
probe_names: list[str] | None = None,
|
|
144
|
+
data_vars: list[str] | None = None,
|
|
100
145
|
) -> xr.Dataset:
|
|
101
146
|
"""Open a set of EPOCH SDF files as one `xarray.Dataset`
|
|
102
147
|
|
|
@@ -128,19 +173,34 @@ def open_mfdataset(
|
|
|
128
173
|
If ``True``, also load particle data (this may use a lot of memory!)
|
|
129
174
|
probe_names :
|
|
130
175
|
List of EPOCH probe names
|
|
176
|
+
data_vars :
|
|
177
|
+
List of data vars to load in (If not specified loads in all variables)
|
|
131
178
|
"""
|
|
132
179
|
|
|
133
180
|
path_glob = _resolve_glob(path_glob)
|
|
181
|
+
|
|
134
182
|
if not separate_times:
|
|
135
183
|
return combine_datasets(
|
|
136
|
-
path_glob,
|
|
184
|
+
path_glob,
|
|
185
|
+
data_vars=data_vars,
|
|
186
|
+
keep_particles=keep_particles,
|
|
187
|
+
probe_names=probe_names,
|
|
137
188
|
)
|
|
138
189
|
|
|
139
190
|
_, var_times_map = make_time_dims(path_glob)
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
191
|
+
|
|
192
|
+
all_dfs = []
|
|
193
|
+
for f in path_glob:
|
|
194
|
+
ds = xr.open_dataset(f, keep_particles=keep_particles, probe_names=probe_names)
|
|
195
|
+
|
|
196
|
+
# If the data_vars are specified then only load them in and disregard the rest.
|
|
197
|
+
# If there are no remaining data variables then skip adding the dataset to list
|
|
198
|
+
if data_vars is not None:
|
|
199
|
+
ds = purge_unselected_data_vars(ds, data_vars)
|
|
200
|
+
if not ds.data_vars:
|
|
201
|
+
continue
|
|
202
|
+
|
|
203
|
+
all_dfs.append(ds)
|
|
144
204
|
|
|
145
205
|
for df in all_dfs:
|
|
146
206
|
for da in df:
|
|
@@ -158,7 +218,6 @@ def open_mfdataset(
|
|
|
158
218
|
|
|
159
219
|
return xr.combine_by_coords(
|
|
160
220
|
all_dfs,
|
|
161
|
-
data_vars="all",
|
|
162
221
|
coords="different",
|
|
163
222
|
combine_attrs="drop_conflicts",
|
|
164
223
|
join="outer",
|
|
@@ -516,10 +575,43 @@ class SDFEntrypoint(BackendEntrypoint):
|
|
|
516
575
|
|
|
517
576
|
|
|
518
577
|
class SDFPreprocess:
|
|
519
|
-
"""Preprocess SDF files for xarray ensuring matching job ids and sets
|
|
578
|
+
"""Preprocess SDF files for xarray ensuring matching job ids and sets
|
|
579
|
+
time dimension.
|
|
580
|
+
|
|
581
|
+
This class is used as a 'preprocess' function within ``xr.open_mfdataset``. It
|
|
582
|
+
performs three main duties on each individual file's Dataset:
|
|
583
|
+
|
|
584
|
+
1. Checks for a **matching job ID** across all files to ensure dataset consistency.
|
|
585
|
+
2. **Filters** the Dataset to keep only the variables specified in `data_vars`
|
|
586
|
+
and their required coordinates.
|
|
587
|
+
3. **Expands dimensions** to include a single 'time' coordinate, preparing the
|
|
588
|
+
Dataset for concatenation.
|
|
589
|
+
|
|
590
|
+
EPOCH can output variables at different intervals, so some SDF files
|
|
591
|
+
may not contain the requested variable. We combine this data into one
|
|
592
|
+
dataset by concatenating across the time dimension.
|
|
593
|
+
|
|
594
|
+
The combination is performed using ``join="outer"`` (in the calling ``open_mfdataset`` function),
|
|
595
|
+
meaning that the final combined dataset will contain the variable across the
|
|
596
|
+
entire time span, with NaNs filling the time steps where the variable was absent in
|
|
597
|
+
the individual file.
|
|
598
|
+
|
|
599
|
+
With large SDF files, this filtering method will save on memory consumption when
|
|
600
|
+
compared to loading all variables from all files before concatenation.
|
|
520
601
|
|
|
521
|
-
|
|
602
|
+
Parameters
|
|
603
|
+
----------
|
|
604
|
+
data_vars :
|
|
605
|
+
A list of data variables to load in (If not specified loads
|
|
606
|
+
in all variables)
|
|
607
|
+
"""
|
|
608
|
+
|
|
609
|
+
def __init__(
|
|
610
|
+
self,
|
|
611
|
+
data_vars: list[str] | None = None,
|
|
612
|
+
):
|
|
522
613
|
self.job_id: int | None = None
|
|
614
|
+
self.data_vars = data_vars
|
|
523
615
|
|
|
524
616
|
def __call__(self, ds: xr.Dataset) -> xr.Dataset:
|
|
525
617
|
if self.job_id is None:
|
|
@@ -530,17 +622,23 @@ class SDFPreprocess:
|
|
|
530
622
|
f"Mismatching job ids (got {ds.attrs['jobid1']}, expected {self.job_id})"
|
|
531
623
|
)
|
|
532
624
|
|
|
533
|
-
|
|
625
|
+
# If the user has exclusively requested only certain variables be
|
|
626
|
+
# loaded in then we purge all other variables and coordinates
|
|
627
|
+
if self.data_vars:
|
|
628
|
+
ds = purge_unselected_data_vars(ds, self.data_vars)
|
|
629
|
+
|
|
630
|
+
time_val = ds.attrs.get("time", np.nan)
|
|
631
|
+
ds = ds.expand_dims(time=[time_val])
|
|
534
632
|
ds = ds.assign_coords(
|
|
535
633
|
time=(
|
|
536
634
|
"time",
|
|
537
|
-
[
|
|
635
|
+
[time_val],
|
|
538
636
|
{"units": "s", "long_name": "Time", "full_name": "time"},
|
|
539
637
|
)
|
|
540
638
|
)
|
|
541
639
|
# Particles' spartial coordinates also evolve in time
|
|
542
640
|
for coord, value in ds.coords.items():
|
|
543
641
|
if value.attrs.get("point_data", False):
|
|
544
|
-
ds.coords[coord] = value.expand_dims(time=[
|
|
642
|
+
ds.coords[coord] = value.expand_dims(time=[time_val])
|
|
545
643
|
|
|
546
644
|
return ds
|
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '0.3.
|
|
32
|
-
__version_tuple__ = version_tuple = (0, 3,
|
|
31
|
+
__version__ = version = '0.3.2'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 3, 2)
|
|
33
33
|
|
|
34
|
-
__commit_id__ = commit_id = '
|
|
34
|
+
__commit_id__ = commit_id = 'g331520e50'
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
from typing import Union
|
|
2
|
+
|
|
3
|
+
import xarray as xr
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@xr.register_dataset_accessor("epoch")
|
|
7
|
+
class EpochAccessor:
|
|
8
|
+
def __init__(self, xarray_obj: xr.Dataset):
|
|
9
|
+
# The xarray object is the Dataset, which we store as self._ds
|
|
10
|
+
self._ds = xarray_obj
|
|
11
|
+
|
|
12
|
+
def rescale_coords(
|
|
13
|
+
self,
|
|
14
|
+
multiplier: float,
|
|
15
|
+
unit_label: str,
|
|
16
|
+
coord_names: Union[str, list[str]],
|
|
17
|
+
) -> xr.Dataset:
|
|
18
|
+
"""
|
|
19
|
+
Rescales specified X and Y coordinates in the Dataset by a given multiplier
|
|
20
|
+
and updates the unit label attribute.
|
|
21
|
+
|
|
22
|
+
Parameters
|
|
23
|
+
----------
|
|
24
|
+
multiplier : float
|
|
25
|
+
The factor by which to multiply the coordinate values (e.g., 1e6 for meters to microns).
|
|
26
|
+
unit_label : str
|
|
27
|
+
The new unit label for the coordinates (e.g., "µm").
|
|
28
|
+
coord_names : str or list of str
|
|
29
|
+
The name(s) of the coordinate variable(s) to rescale.
|
|
30
|
+
If a string, only that coordinate is rescaled.
|
|
31
|
+
If a list, all listed coordinates are rescaled.
|
|
32
|
+
|
|
33
|
+
Returns
|
|
34
|
+
-------
|
|
35
|
+
xr.Dataset
|
|
36
|
+
A new Dataset with the updated and rescaled coordinates.
|
|
37
|
+
|
|
38
|
+
Examples
|
|
39
|
+
--------
|
|
40
|
+
# Convert X, Y, and Z from meters to microns
|
|
41
|
+
>>> ds_in_microns = ds.epoch.rescale_coords(1e6, "µm", coord_names=["X_Grid", "Y_Grid", "Z_Grid"])
|
|
42
|
+
|
|
43
|
+
# Convert only X to millimeters
|
|
44
|
+
>>> ds_in_mm = ds.epoch.rescale_coords(1000, "mm", coord_names="X_Grid")
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
ds = self._ds
|
|
48
|
+
new_coords = {}
|
|
49
|
+
|
|
50
|
+
if isinstance(coord_names, str):
|
|
51
|
+
# Convert single string to a list
|
|
52
|
+
coords_to_process = [coord_names]
|
|
53
|
+
elif isinstance(coord_names, list):
|
|
54
|
+
# Use the provided list
|
|
55
|
+
coords_to_process = coord_names
|
|
56
|
+
else:
|
|
57
|
+
coords_to_process = list(coord_names)
|
|
58
|
+
|
|
59
|
+
for coord_name in coords_to_process:
|
|
60
|
+
if coord_name not in ds.coords:
|
|
61
|
+
raise ValueError(
|
|
62
|
+
f"Coordinate '{coord_name}' not found in the Dataset. Cannot rescale."
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
coord_original = ds[coord_name]
|
|
66
|
+
|
|
67
|
+
coord_rescaled = coord_original * multiplier
|
|
68
|
+
coord_rescaled.attrs = coord_original.attrs.copy()
|
|
69
|
+
coord_rescaled.attrs["units"] = unit_label
|
|
70
|
+
|
|
71
|
+
new_coords[coord_name] = coord_rescaled
|
|
72
|
+
|
|
73
|
+
return ds.assign_coords(new_coords)
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
begin:control
|
|
2
|
+
nx = 64
|
|
3
|
+
ny = 64
|
|
4
|
+
nz = 64
|
|
5
|
+
|
|
6
|
+
# Final time of simulation
|
|
7
|
+
t_end = 5 * femto
|
|
8
|
+
|
|
9
|
+
# Size of domain
|
|
10
|
+
x_min = 0
|
|
11
|
+
x_max = 5.0e5
|
|
12
|
+
|
|
13
|
+
y_min = 0
|
|
14
|
+
y_max = 5.0e5
|
|
15
|
+
|
|
16
|
+
z_min = 0
|
|
17
|
+
z_max = 5.0e5
|
|
18
|
+
|
|
19
|
+
stdout_frequency = 1
|
|
20
|
+
end:control
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
begin:boundaries
|
|
24
|
+
bc_x_min = periodic
|
|
25
|
+
bc_x_max = periodic
|
|
26
|
+
bc_y_min = periodic
|
|
27
|
+
bc_y_max = periodic
|
|
28
|
+
bc_z_min = periodic
|
|
29
|
+
bc_z_max = periodic
|
|
30
|
+
end:boundaries
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
begin:species
|
|
34
|
+
name = electron
|
|
35
|
+
charge = -1
|
|
36
|
+
mass = 1.0
|
|
37
|
+
temperature_x = 273
|
|
38
|
+
number_density = 10
|
|
39
|
+
nparticles = nx * ny * nz * 2
|
|
40
|
+
end:species
|
|
41
|
+
|
|
42
|
+
begin:output_global
|
|
43
|
+
force_last_to_be_restartable = F
|
|
44
|
+
end:output_global
|
|
45
|
+
|
|
46
|
+
begin:output
|
|
47
|
+
name = normal
|
|
48
|
+
|
|
49
|
+
dt_snapshot = 1 * femto
|
|
50
|
+
|
|
51
|
+
grid = always
|
|
52
|
+
|
|
53
|
+
end:output
|
|
54
|
+
|