sdf-xarray 0.2.2__tar.gz → 0.2.4__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.2.2 → sdf_xarray-0.2.4}/CITATION.cff +1 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/PKG-INFO +16 -3
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/README.md +6 -1
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/getting_started.rst +8 -1
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/key_functionality.rst +8 -5
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/pyproject.toml +13 -2
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/src/sdf_xarray/__init__.py +2 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/src/sdf_xarray/_version.py +2 -2
- sdf_xarray-0.2.4/src/sdf_xarray/plotting.py +205 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/src/sdf_xarray/sdf_interface.pyx +1 -1
- sdf_xarray-0.2.4/tests/example_dist_fn/0000.sdf +0 -0
- sdf_xarray-0.2.4/tests/example_dist_fn/0001.sdf +0 -0
- sdf_xarray-0.2.4/tests/example_dist_fn/0002.sdf +0 -0
- sdf_xarray-0.2.4/tests/example_dist_fn/input.deck +154 -0
- sdf_xarray-0.2.4/tests/example_files_2D_moving_window/0000.sdf +0 -0
- sdf_xarray-0.2.4/tests/example_files_2D_moving_window/0001.sdf +0 -0
- sdf_xarray-0.2.4/tests/example_files_2D_moving_window/0002.sdf +0 -0
- sdf_xarray-0.2.4/tests/example_files_2D_moving_window/0003.sdf +0 -0
- sdf_xarray-0.2.4/tests/example_files_2D_moving_window/0004.sdf +0 -0
- sdf_xarray-0.2.4/tests/example_files_2D_moving_window/input.deck +63 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/tests/test_basic.py +8 -1
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/tests/test_cython.py +1 -1
- sdf_xarray-0.2.4/tests/test_epoch_accessor.py +183 -0
- sdf_xarray-0.2.2/src/sdf_xarray/plotting.py +0 -184
- sdf_xarray-0.2.2/tests/test_epoch_accessor.py +0 -39
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/.github/workflows/black.yml +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/.github/workflows/build_publish.yml +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/.github/workflows/lint.yml +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/.github/workflows/tests.yml +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/.gitignore +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/.gitmodules +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/.readthedocs.yaml +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/BEAM.png +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/CMakeLists.txt +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/CONTRIBUTING.md +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/LICENCE +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/PlasmaFAIR.svg +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/.gitignore +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/_templates/custom-class-template.rst +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/_templates/custom-module-template.rst +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/api.rst +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/conf.py +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/contributing.rst +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/index.rst +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/make.bat +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/tutorial_dataset_1d/0000.sdf +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/tutorial_dataset_1d/0001.sdf +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/tutorial_dataset_1d/0002.sdf +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/tutorial_dataset_1d/0003.sdf +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/tutorial_dataset_1d/0004.sdf +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/tutorial_dataset_1d/0005.sdf +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/tutorial_dataset_1d/0006.sdf +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/tutorial_dataset_1d/0007.sdf +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/tutorial_dataset_1d/0008.sdf +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/tutorial_dataset_1d/0009.sdf +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/tutorial_dataset_1d/0010.sdf +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/tutorial_dataset_1d/0011.sdf +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/tutorial_dataset_1d/0012.sdf +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/tutorial_dataset_1d/0013.sdf +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/tutorial_dataset_1d/0014.sdf +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/tutorial_dataset_1d/0015.sdf +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/tutorial_dataset_1d/0016.sdf +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/tutorial_dataset_1d/0017.sdf +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/tutorial_dataset_1d/0018.sdf +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/tutorial_dataset_1d/0019.sdf +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/tutorial_dataset_1d/0020.sdf +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/tutorial_dataset_1d/0021.sdf +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/tutorial_dataset_1d/0022.sdf +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/tutorial_dataset_1d/0023.sdf +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/tutorial_dataset_1d/0024.sdf +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/tutorial_dataset_1d/0025.sdf +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/tutorial_dataset_1d/0026.sdf +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/tutorial_dataset_1d/0027.sdf +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/tutorial_dataset_1d/0028.sdf +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/tutorial_dataset_1d/0029.sdf +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/tutorial_dataset_1d/0030.sdf +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/tutorial_dataset_1d/0031.sdf +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/tutorial_dataset_1d/0032.sdf +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/tutorial_dataset_1d/0033.sdf +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/tutorial_dataset_1d/0034.sdf +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/tutorial_dataset_1d/0035.sdf +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/tutorial_dataset_1d/0036.sdf +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/tutorial_dataset_1d/0037.sdf +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/tutorial_dataset_1d/0038.sdf +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/tutorial_dataset_1d/0039.sdf +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/tutorial_dataset_1d/0040.sdf +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/tutorial_dataset_1d/deck.status +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/tutorial_dataset_1d/epoch1d.dat +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/tutorial_dataset_1d/input.deck +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/tutorial_dataset_1d/normal.visit +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/tutorial_dataset_1d/restart.visit +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/docs/unit_conversion.rst +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/src/sdf_xarray/csdf.pxd +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/tests/example_array_no_grids/0000.sdf +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/tests/example_array_no_grids/0001.sdf +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/tests/example_array_no_grids/README.md +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/tests/example_array_no_grids/input.deck +0 -0
- {sdf_xarray-0.2.2/tests/example_files → sdf_xarray-0.2.4/tests/example_files_1D}/0000.sdf +0 -0
- {sdf_xarray-0.2.2/tests/example_files → sdf_xarray-0.2.4/tests/example_files_1D}/0001.sdf +0 -0
- {sdf_xarray-0.2.2/tests/example_files → sdf_xarray-0.2.4/tests/example_files_1D}/0002.sdf +0 -0
- {sdf_xarray-0.2.2/tests/example_files → sdf_xarray-0.2.4/tests/example_files_1D}/0003.sdf +0 -0
- {sdf_xarray-0.2.2/tests/example_files → sdf_xarray-0.2.4/tests/example_files_1D}/0004.sdf +0 -0
- {sdf_xarray-0.2.2/tests/example_files → sdf_xarray-0.2.4/tests/example_files_1D}/0005.sdf +0 -0
- {sdf_xarray-0.2.2/tests/example_files → sdf_xarray-0.2.4/tests/example_files_1D}/0006.sdf +0 -0
- {sdf_xarray-0.2.2/tests/example_files → sdf_xarray-0.2.4/tests/example_files_1D}/0007.sdf +0 -0
- {sdf_xarray-0.2.2/tests/example_files → sdf_xarray-0.2.4/tests/example_files_1D}/0008.sdf +0 -0
- {sdf_xarray-0.2.2/tests/example_files → sdf_xarray-0.2.4/tests/example_files_1D}/0009.sdf +0 -0
- {sdf_xarray-0.2.2/tests/example_files → sdf_xarray-0.2.4/tests/example_files_1D}/0010.sdf +0 -0
- {sdf_xarray-0.2.2/tests/example_files → sdf_xarray-0.2.4/tests/example_files_1D}/README.md +0 -0
- {sdf_xarray-0.2.2/tests/example_files → sdf_xarray-0.2.4/tests/example_files_1D}/input.deck +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/tests/example_mismatched_files/0000.sdf +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/tests/example_mismatched_files/0001.sdf +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/tests/example_mismatched_files/0002.sdf +0 -0
- {sdf_xarray-0.2.2 → sdf_xarray-0.2.4}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: sdf-xarray
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.4
|
|
4
4
|
Summary: Provides a backend for xarray to read SDF files as created by the EPOCH plasma PIC code.
|
|
5
5
|
Author-Email: Peter Hill <peter.hill@york.ac.uk>, Joel Adams <joel.adams@york.ac.uk>, Shaun Doherty <shaun.doherty@york.ac.uk>
|
|
6
6
|
License: Copyright 2024, Peter Hill, Joel Adams, epochpic team
|
|
@@ -32,11 +32,19 @@ License: Copyright 2024, Peter Hill, Joel Adams, epochpic team
|
|
|
32
32
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
33
33
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
34
34
|
|
|
35
|
+
Classifier: Programming Language :: Python
|
|
36
|
+
Classifier: Programming Language :: Python :: 3
|
|
37
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
38
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
39
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
40
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
41
|
+
Classifier: Intended Audience :: Science/Research
|
|
42
|
+
Classifier: Topic :: Scientific/Engineering
|
|
43
|
+
Classifier: Operating System :: OS Independent
|
|
35
44
|
Requires-Python: >=3.10
|
|
36
45
|
Requires-Dist: numpy>=2.0.0
|
|
37
46
|
Requires-Dist: xarray>=2024.1.0
|
|
38
47
|
Requires-Dist: dask>=2024.7.1
|
|
39
|
-
Requires-Dist: cython>=3.0
|
|
40
48
|
Provides-Extra: docs
|
|
41
49
|
Requires-Dist: sphinx>=5.3; extra == "docs"
|
|
42
50
|
Requires-Dist: sphinx_autodoc_typehints>=1.19; extra == "docs"
|
|
@@ -67,9 +75,14 @@ Description-Content-Type: text/markdown
|
|
|
67
75
|
|
|
68
76
|
# sdf-xarray
|
|
69
77
|
|
|
70
|
-

|
|
79
|
+
[](https://pypi.org/project/sdf-xarray/)
|
|
80
|
+
[](https://doi.org/10.5281/zenodo.15351323)
|
|
71
81
|

|
|
72
82
|

|
|
83
|
+
[](https://sdf-xarray.readthedocs.io)
|
|
84
|
+
[](https://github.com/python/black)
|
|
85
|
+
|
|
73
86
|
|
|
74
87
|
sdf-xarray provides a backend for [xarray](https://xarray.dev) to read SDF files as created by
|
|
75
88
|
[EPOCH](https://epochpic.github.io) using the [SDF-C](https://github.com/epochpic/SDF_C) library.
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
# sdf-xarray
|
|
2
2
|
|
|
3
|
-

|
|
4
|
+
[](https://pypi.org/project/sdf-xarray/)
|
|
5
|
+
[](https://doi.org/10.5281/zenodo.15351323)
|
|
4
6
|

|
|
5
7
|

|
|
8
|
+
[](https://sdf-xarray.readthedocs.io)
|
|
9
|
+
[](https://github.com/python/black)
|
|
10
|
+
|
|
6
11
|
|
|
7
12
|
sdf-xarray provides a backend for [xarray](https://xarray.dev) to read SDF files as created by
|
|
8
13
|
[EPOCH](https://epochpic.github.io) using the [SDF-C](https://github.com/epochpic/SDF_C) library.
|
|
@@ -25,7 +25,14 @@ Usage
|
|
|
25
25
|
-----
|
|
26
26
|
|
|
27
27
|
``sdf-xarray`` is a backend for xarray, and so is usable directly from
|
|
28
|
-
`xarray`.
|
|
28
|
+
`xarray`. There are several ways to load SDF files:
|
|
29
|
+
|
|
30
|
+
- To load a single file, use :func:`xarray.open_dataset`.
|
|
31
|
+
- To load multiple files, use :func:`xarray.open_mfdataset` or :func:`sdf_xarray.open_mfdataset`.
|
|
32
|
+
- To access the raw contents of a single SDF file, use :func:`sdf_xarray.sdf_interface.SDFFile`.
|
|
33
|
+
|
|
34
|
+
.. note::
|
|
35
|
+
When loading ``*.sdf`` files, variables related to ``boundaries``, ``cpu`` and ``output file`` are excluded as they are problematic.
|
|
29
36
|
|
|
30
37
|
Single file loading
|
|
31
38
|
~~~~~~~~~~~~~~~~~~~
|
|
@@ -13,11 +13,14 @@ Key Functionality
|
|
|
13
13
|
|
|
14
14
|
Loading SDF Files
|
|
15
15
|
-----------------
|
|
16
|
-
There are several ways to load
|
|
17
|
-
|
|
18
|
-
load
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
There are several ways to load SDF files:
|
|
17
|
+
|
|
18
|
+
- To load a single file, use :func:`xarray.open_dataset`.
|
|
19
|
+
- To load multiple files, use :func:`xarray.open_mfdataset` or :func:`sdf_xarray.open_mfdataset`.
|
|
20
|
+
- To access the raw contents of a single SDF file, use :func:`sdf_xarray.sdf_interface.SDFFile`.
|
|
21
|
+
|
|
22
|
+
.. note::
|
|
23
|
+
When loading ``*.sdf`` files, variables related to ``boundaries``, ``cpu`` and ``output file`` are excluded as they are problematic.
|
|
21
24
|
|
|
22
25
|
Loading a Single SDF File
|
|
23
26
|
~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
@@ -3,7 +3,7 @@ requires = [
|
|
|
3
3
|
"scikit-build-core>=0.3",
|
|
4
4
|
"setuptools_scm",
|
|
5
5
|
"numpy>=2.0.0",
|
|
6
|
-
"cython
|
|
6
|
+
"cython~=3.0",
|
|
7
7
|
]
|
|
8
8
|
build-backend = "scikit_build_core.build"
|
|
9
9
|
|
|
@@ -22,9 +22,19 @@ dependencies = [
|
|
|
22
22
|
"numpy>=2.0.0",
|
|
23
23
|
"xarray>=2024.1.0",
|
|
24
24
|
"dask>=2024.7.1",
|
|
25
|
-
"cython>=3.0",
|
|
26
25
|
]
|
|
27
26
|
description = "Provides a backend for xarray to read SDF files as created by the EPOCH plasma PIC code."
|
|
27
|
+
classifiers = [
|
|
28
|
+
"Programming Language :: Python",
|
|
29
|
+
"Programming Language :: Python :: 3",
|
|
30
|
+
"Programming Language :: Python :: 3.10",
|
|
31
|
+
"Programming Language :: Python :: 3.11",
|
|
32
|
+
"Programming Language :: Python :: 3.12",
|
|
33
|
+
"Programming Language :: Python :: 3.13",
|
|
34
|
+
"Intended Audience :: Science/Research",
|
|
35
|
+
"Topic :: Scientific/Engineering",
|
|
36
|
+
"Operating System :: OS Independent",
|
|
37
|
+
]
|
|
28
38
|
|
|
29
39
|
[project.optional-dependencies]
|
|
30
40
|
docs = [
|
|
@@ -94,4 +104,5 @@ extend-select = [
|
|
|
94
104
|
ignore = [
|
|
95
105
|
"PLR2004", # magic-comparison
|
|
96
106
|
"B9", # flake8-bugbear opinionated warnings
|
|
107
|
+
"PLR0913", # remove maximum number of arguments in a function
|
|
97
108
|
]
|
|
@@ -310,6 +310,8 @@ class SDFDataStore(AbstractDataStore):
|
|
|
310
310
|
# Had some problems with these variables, so just ignore them for now
|
|
311
311
|
if "cpu" in key.lower():
|
|
312
312
|
continue
|
|
313
|
+
if "boundary" in key.lower():
|
|
314
|
+
continue
|
|
313
315
|
if "output file" in key.lower():
|
|
314
316
|
continue
|
|
315
317
|
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
import xarray as xr
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
import matplotlib.pyplot as plt
|
|
10
|
+
from matplotlib.animation import FuncAnimation
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def get_frame_title(
|
|
14
|
+
data: xr.DataArray,
|
|
15
|
+
frame: int,
|
|
16
|
+
display_sdf_name: bool = False,
|
|
17
|
+
title_custom: str | None = None,
|
|
18
|
+
) -> str:
|
|
19
|
+
"""Generate the title for a frame"""
|
|
20
|
+
# Adds custom text to the start of the title, if specified
|
|
21
|
+
title_custom = "" if title_custom is None else f"{title_custom}, "
|
|
22
|
+
# Adds the time and associated units to the title
|
|
23
|
+
time = data["time"][frame].to_numpy()
|
|
24
|
+
|
|
25
|
+
time_units = data["time"].attrs.get("units", False)
|
|
26
|
+
time_units_formatted = f" [{time_units}]" if time_units else ""
|
|
27
|
+
title_time = f"time = {time:.2e}{time_units_formatted}"
|
|
28
|
+
|
|
29
|
+
# Adds sdf name to the title, if specifed
|
|
30
|
+
title_sdf = f", {frame:04d}.sdf" if display_sdf_name else ""
|
|
31
|
+
return f"{title_custom}{title_time}{title_sdf}"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def calculate_window_boundaries(
|
|
35
|
+
data: xr.DataArray, xlim: tuple[float, float] | False = False
|
|
36
|
+
) -> np.ndarray:
|
|
37
|
+
"""Calculate the bounderies a moving window frame. If the user specifies xlim, this will
|
|
38
|
+
be used as the initial bounderies and the window will move along acordingly.
|
|
39
|
+
"""
|
|
40
|
+
x_grid = data["X_Grid_mid"].values
|
|
41
|
+
x_half_cell = (x_grid[1] - x_grid[0]) / 2
|
|
42
|
+
N_frames = data["time"].size
|
|
43
|
+
|
|
44
|
+
# Find the window bounderies by finding the first and last non-NaN values in the 0th lineout
|
|
45
|
+
# along the x-axis.
|
|
46
|
+
window_boundaries = np.zeros((N_frames, 2))
|
|
47
|
+
for i in range(N_frames):
|
|
48
|
+
# Check if data is 1D
|
|
49
|
+
if data.ndim == 2:
|
|
50
|
+
target_lineout = data[i].values
|
|
51
|
+
# Check if data is 2D
|
|
52
|
+
if data.ndim == 3:
|
|
53
|
+
target_lineout = data[i, :, 0].values
|
|
54
|
+
x_grid_non_nan = x_grid[~np.isnan(target_lineout)]
|
|
55
|
+
window_boundaries[i, 0] = x_grid_non_nan[0] - x_half_cell
|
|
56
|
+
window_boundaries[i, 1] = x_grid_non_nan[-1] + x_half_cell
|
|
57
|
+
|
|
58
|
+
# User's choice for initial window edge supercides the one calculated
|
|
59
|
+
if xlim:
|
|
60
|
+
window_boundaries = window_boundaries + xlim - window_boundaries[0]
|
|
61
|
+
return window_boundaries
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def compute_global_limits(
|
|
65
|
+
data: xr.DataArray,
|
|
66
|
+
min_percentile: float = 0,
|
|
67
|
+
max_percentile: float = 100,
|
|
68
|
+
) -> tuple[float, float]:
|
|
69
|
+
"""Remove all NaN values from the target data to calculate the global minimum and maximum of the data.
|
|
70
|
+
User defined percentiles can remove extreme outliers.
|
|
71
|
+
"""
|
|
72
|
+
|
|
73
|
+
# Removes NaN values, needed for moving windows
|
|
74
|
+
values_no_nan = data.values[~np.isnan(data.values)]
|
|
75
|
+
|
|
76
|
+
# Finds the global minimum and maximum of the plot, based on the percentile of the data
|
|
77
|
+
global_min = np.percentile(values_no_nan, min_percentile)
|
|
78
|
+
global_max = np.percentile(values_no_nan, max_percentile)
|
|
79
|
+
return global_min, global_max
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def animate(
|
|
83
|
+
data: xr.DataArray,
|
|
84
|
+
fps: float = 10,
|
|
85
|
+
min_percentile: float = 0,
|
|
86
|
+
max_percentile: float = 100,
|
|
87
|
+
title: str | None = None,
|
|
88
|
+
display_sdf_name: bool = False,
|
|
89
|
+
ax: plt.Axes | None = None,
|
|
90
|
+
**kwargs,
|
|
91
|
+
) -> FuncAnimation:
|
|
92
|
+
"""Generate an animation
|
|
93
|
+
|
|
94
|
+
Parameters
|
|
95
|
+
---------
|
|
96
|
+
data
|
|
97
|
+
The dataarray containing the target data
|
|
98
|
+
fps
|
|
99
|
+
Frames per second for the animation (default: 10)
|
|
100
|
+
min_percentile
|
|
101
|
+
Minimum percentile of the data (default: 0)
|
|
102
|
+
max_percentile
|
|
103
|
+
Maximum percentile of the data (default: 100)
|
|
104
|
+
title
|
|
105
|
+
Custom title to add to the plot.
|
|
106
|
+
display_sdf_name
|
|
107
|
+
Display the sdf file name in the animation title
|
|
108
|
+
ax
|
|
109
|
+
Matplotlib axes on which to plot.
|
|
110
|
+
kwargs
|
|
111
|
+
Keyword arguments to be passed to matplotlib.
|
|
112
|
+
|
|
113
|
+
Examples
|
|
114
|
+
--------
|
|
115
|
+
>>> dataset["Derived_Number_Density_Electron"].epoch.animate()
|
|
116
|
+
"""
|
|
117
|
+
import matplotlib.pyplot as plt
|
|
118
|
+
from matplotlib.animation import FuncAnimation
|
|
119
|
+
|
|
120
|
+
kwargs_original = kwargs.copy()
|
|
121
|
+
|
|
122
|
+
if ax is None:
|
|
123
|
+
_, ax = plt.subplots()
|
|
124
|
+
|
|
125
|
+
N_frames = data["time"].size
|
|
126
|
+
global_min, global_max = compute_global_limits(data, min_percentile, max_percentile)
|
|
127
|
+
|
|
128
|
+
# Initialise plot and set y-limits for 1D data
|
|
129
|
+
if data.ndim == 2:
|
|
130
|
+
kwargs.setdefault("x", "X_Grid_mid")
|
|
131
|
+
plot = data.isel(time=0).plot(ax=ax, **kwargs)
|
|
132
|
+
ax.set_title(get_frame_title(data, 0, display_sdf_name, title))
|
|
133
|
+
ax.set_ylim(global_min, global_max)
|
|
134
|
+
|
|
135
|
+
# Initilise plot and set colour bar for 2D data
|
|
136
|
+
if data.ndim == 3:
|
|
137
|
+
kwargs["norm"] = plt.Normalize(vmin=global_min, vmax=global_max)
|
|
138
|
+
kwargs["add_colorbar"] = False
|
|
139
|
+
# Set default x and y coordinates for 2D data if not provided
|
|
140
|
+
kwargs.setdefault("x", "X_Grid_mid")
|
|
141
|
+
kwargs.setdefault("y", "Y_Grid_mid")
|
|
142
|
+
|
|
143
|
+
# Initialize the plot with the first timestep
|
|
144
|
+
plot = data.isel(time=0).plot(ax=ax, **kwargs)
|
|
145
|
+
ax.set_title(get_frame_title(data, 0, display_sdf_name, title))
|
|
146
|
+
|
|
147
|
+
# Add colorbar
|
|
148
|
+
if kwargs_original.get("add_colorbar", True):
|
|
149
|
+
long_name = data.attrs.get("long_name")
|
|
150
|
+
units = data.attrs.get("units")
|
|
151
|
+
plt.colorbar(plot, ax=ax, label=f"{long_name} [${units}$]")
|
|
152
|
+
|
|
153
|
+
# check if there is a moving window by finding NaNs in the data
|
|
154
|
+
move_window = np.isnan(np.sum(data.values))
|
|
155
|
+
if move_window:
|
|
156
|
+
window_boundaries = calculate_window_boundaries(data, kwargs.get("xlim", False))
|
|
157
|
+
|
|
158
|
+
def update(frame):
|
|
159
|
+
# Set the xlim for each frame in the case of a moving window
|
|
160
|
+
if move_window:
|
|
161
|
+
kwargs["xlim"] = window_boundaries[frame]
|
|
162
|
+
|
|
163
|
+
# Update plot for the new frame
|
|
164
|
+
ax.clear()
|
|
165
|
+
|
|
166
|
+
data.isel(time=frame).plot(ax=ax, **kwargs)
|
|
167
|
+
ax.set_title(get_frame_title(data, frame, display_sdf_name, title))
|
|
168
|
+
|
|
169
|
+
# Update y-limits for 1D data
|
|
170
|
+
if data.ndim == 2:
|
|
171
|
+
ax.set_ylim(global_min, global_max)
|
|
172
|
+
|
|
173
|
+
return FuncAnimation(
|
|
174
|
+
ax.get_figure(),
|
|
175
|
+
update,
|
|
176
|
+
frames=range(N_frames),
|
|
177
|
+
interval=1000 / fps,
|
|
178
|
+
repeat=True,
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
@xr.register_dataarray_accessor("epoch")
|
|
183
|
+
class EpochAccessor:
|
|
184
|
+
def __init__(self, xarray_obj):
|
|
185
|
+
self._obj = xarray_obj
|
|
186
|
+
|
|
187
|
+
def animate(self, *args, **kwargs) -> FuncAnimation:
|
|
188
|
+
"""Generate animations of Epoch data.
|
|
189
|
+
|
|
190
|
+
Parameters
|
|
191
|
+
----------
|
|
192
|
+
args
|
|
193
|
+
Positional arguments passed to :func:`generate_animation`.
|
|
194
|
+
kwargs
|
|
195
|
+
Keyword arguments passed to :func:`generate_animation`.
|
|
196
|
+
|
|
197
|
+
Examples
|
|
198
|
+
--------
|
|
199
|
+
>>> import xarray as xr
|
|
200
|
+
>>> from sdf_xarray import SDFPreprocess
|
|
201
|
+
>>> ds = xr.open_mfdataset("*.sdf", preprocess=SDFPreprocess())
|
|
202
|
+
>>> ani = ds["Electric_Field_Ey"].epoch.animate()
|
|
203
|
+
>>> ani.save("myfile.mp4")
|
|
204
|
+
"""
|
|
205
|
+
return animate(self._obj, *args, **kwargs)
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
begin:control
|
|
2
|
+
|
|
3
|
+
# global number of gridpoints
|
|
4
|
+
# Divide nx and ny by 2 from 40 to 20
|
|
5
|
+
nx = 16 # in x
|
|
6
|
+
ny = 8
|
|
7
|
+
nparticles = nx * ny * 4
|
|
8
|
+
|
|
9
|
+
# maximum number of iterations
|
|
10
|
+
# set to -1 to run until finished
|
|
11
|
+
nsteps = -1
|
|
12
|
+
|
|
13
|
+
# final time of simulation
|
|
14
|
+
t_end = 200e-15
|
|
15
|
+
|
|
16
|
+
# size of domain
|
|
17
|
+
x_min = 0e-6
|
|
18
|
+
x_max = 40e-6
|
|
19
|
+
y_min = -10e-6
|
|
20
|
+
y_max = -y_min
|
|
21
|
+
|
|
22
|
+
dt_multiplier = 0.8
|
|
23
|
+
dlb_threshold = 0.8
|
|
24
|
+
|
|
25
|
+
end:control
|
|
26
|
+
|
|
27
|
+
begin:laser
|
|
28
|
+
|
|
29
|
+
boundary = x_min
|
|
30
|
+
intensity_w_cm2 = 1.0e23
|
|
31
|
+
lambda = 1e-6
|
|
32
|
+
phase = 0.0
|
|
33
|
+
t_profile = gauss(time, 40.0e-15, 30.0e-15) # This profile means your laser pulse has a maximum intensity at t=40 fs, and the intensity will smoothly decrease as time moves away from this point, with a width parameter of 30 fs.
|
|
34
|
+
t_start = 0.0
|
|
35
|
+
t_end = end
|
|
36
|
+
end:laser
|
|
37
|
+
|
|
38
|
+
begin:collisions
|
|
39
|
+
|
|
40
|
+
use_collisions = T
|
|
41
|
+
coulomb_log = auto
|
|
42
|
+
collide = all
|
|
43
|
+
|
|
44
|
+
end:collisions
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
begin:boundaries
|
|
48
|
+
|
|
49
|
+
bc_x_min = simple_laser
|
|
50
|
+
bc_x_max = open
|
|
51
|
+
bc_y_min = periodic
|
|
52
|
+
bc_y_max = periodic
|
|
53
|
+
|
|
54
|
+
end:boundaries
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
begin:species
|
|
58
|
+
|
|
59
|
+
# electrons
|
|
60
|
+
name = Electron
|
|
61
|
+
fraction = 0.5
|
|
62
|
+
dump = T
|
|
63
|
+
|
|
64
|
+
temperature = 0
|
|
65
|
+
number_density = if ((x gt 10e-6) and (x lt 30e-6), 1e22, 0)
|
|
66
|
+
number_density_min = 1
|
|
67
|
+
|
|
68
|
+
identify:electron
|
|
69
|
+
|
|
70
|
+
end:species
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
begin:output_global
|
|
74
|
+
|
|
75
|
+
force_final_to_be_restartable = F
|
|
76
|
+
|
|
77
|
+
end:output_global
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
begin:output
|
|
81
|
+
|
|
82
|
+
name = normal
|
|
83
|
+
|
|
84
|
+
# If use_offset_grid is true then the code dumps a grid which displays
|
|
85
|
+
# positions relative to the left hand edge of the window
|
|
86
|
+
use_offset_grid = F
|
|
87
|
+
|
|
88
|
+
# number of timesteps between output dumps
|
|
89
|
+
dt_snapshot = 100.0e-15 # 100.0e-15 / 100.0
|
|
90
|
+
|
|
91
|
+
# Properties at particle positions
|
|
92
|
+
particles = never
|
|
93
|
+
px = never
|
|
94
|
+
py = never
|
|
95
|
+
pz = never
|
|
96
|
+
vx = never
|
|
97
|
+
vy = never
|
|
98
|
+
vz = never
|
|
99
|
+
charge = never
|
|
100
|
+
mass = never
|
|
101
|
+
particle_weight = never
|
|
102
|
+
species_id = never
|
|
103
|
+
|
|
104
|
+
# Properties on grid
|
|
105
|
+
grid = always
|
|
106
|
+
ex = never
|
|
107
|
+
ey = always
|
|
108
|
+
ez = never
|
|
109
|
+
bx = never
|
|
110
|
+
by = never
|
|
111
|
+
bz = never
|
|
112
|
+
jx = never
|
|
113
|
+
jy = never
|
|
114
|
+
jz = never
|
|
115
|
+
poynt_flux = always
|
|
116
|
+
average_particle_energy = never
|
|
117
|
+
mass_density = never
|
|
118
|
+
charge_density = never
|
|
119
|
+
number_density = never
|
|
120
|
+
temperature = never
|
|
121
|
+
|
|
122
|
+
# extended io
|
|
123
|
+
distribution_functions = always
|
|
124
|
+
particle_probes = never
|
|
125
|
+
absorption = never
|
|
126
|
+
total_energy_sum = never
|
|
127
|
+
|
|
128
|
+
end:output
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
begin:dist_fn
|
|
132
|
+
|
|
133
|
+
name = x_px_py
|
|
134
|
+
ndims = 3
|
|
135
|
+
dumpmask = always
|
|
136
|
+
|
|
137
|
+
direction1 = dir_x
|
|
138
|
+
direction2 = dir_px
|
|
139
|
+
direction3 = dir_py
|
|
140
|
+
|
|
141
|
+
# range is ignored for spatial coordinates
|
|
142
|
+
range1 = (1, 1)
|
|
143
|
+
range2 = (1.6e-20, 1.6e-19)
|
|
144
|
+
range3 = (1.6e-20, 1.6e-19)
|
|
145
|
+
|
|
146
|
+
# resolution is ignored for spatial coordinates
|
|
147
|
+
resolution1 = 1
|
|
148
|
+
resolution2 = 20
|
|
149
|
+
resolution3 = 20
|
|
150
|
+
|
|
151
|
+
#include_species:Photon
|
|
152
|
+
include_species:Electron
|
|
153
|
+
|
|
154
|
+
end:dist_fn
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
begin:control
|
|
2
|
+
nx = 100
|
|
3
|
+
ny = 100
|
|
4
|
+
|
|
5
|
+
# final time of simulation
|
|
6
|
+
t_end = 10e-9
|
|
7
|
+
|
|
8
|
+
# size of domain
|
|
9
|
+
x_min = 0
|
|
10
|
+
x_end = 1
|
|
11
|
+
|
|
12
|
+
y_min = 0
|
|
13
|
+
y_max = 1
|
|
14
|
+
|
|
15
|
+
stdout_frequency = 10
|
|
16
|
+
end:control
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
begin:boundaries
|
|
20
|
+
bc_x_min = simple_outflow
|
|
21
|
+
bc_x_max = simple_outflow
|
|
22
|
+
bc_y_min = periodic
|
|
23
|
+
bc_y_max = periodic
|
|
24
|
+
end:boundaries
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
begin:window
|
|
28
|
+
move_window = T
|
|
29
|
+
window_start_time = 0
|
|
30
|
+
bc_x_min_after_move = simple_outflow
|
|
31
|
+
bc_x_max_after_move = simple_outflow
|
|
32
|
+
window_v_x = 2e8
|
|
33
|
+
end:window
|
|
34
|
+
|
|
35
|
+
begin:constant
|
|
36
|
+
x0 = 1.31
|
|
37
|
+
y0 = 0.5
|
|
38
|
+
r0 = 0.4^2
|
|
39
|
+
r2 = (x - x0)^2 + (y - y0)^2
|
|
40
|
+
end:constant
|
|
41
|
+
|
|
42
|
+
begin:species
|
|
43
|
+
# electron
|
|
44
|
+
name = electron
|
|
45
|
+
charge = -1.0
|
|
46
|
+
mass = 1.0
|
|
47
|
+
nparticles_per_cell = 5
|
|
48
|
+
|
|
49
|
+
number_density = if(abs(x-x0) lt 0.3, 2, 1)
|
|
50
|
+
number_density = if(abs(y-y0) lt 0.2, number_density(electron), 1)
|
|
51
|
+
|
|
52
|
+
temperature_ev = 0
|
|
53
|
+
end:species
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
begin:output
|
|
57
|
+
name = normal
|
|
58
|
+
dt_snapshot = 10e-9/4
|
|
59
|
+
|
|
60
|
+
# Properties on grid
|
|
61
|
+
grid = always
|
|
62
|
+
number_density = always + species + no_sum
|
|
63
|
+
end:output
|
|
@@ -5,11 +5,12 @@ import xarray as xr
|
|
|
5
5
|
|
|
6
6
|
from sdf_xarray import SDFPreprocess, _process_latex_name, open_mfdataset
|
|
7
7
|
|
|
8
|
-
EXAMPLE_FILES_DIR = pathlib.Path(__file__).parent / "
|
|
8
|
+
EXAMPLE_FILES_DIR = pathlib.Path(__file__).parent / "example_files_1D"
|
|
9
9
|
EXAMPLE_MISMATCHED_FILES_DIR = (
|
|
10
10
|
pathlib.Path(__file__).parent / "example_mismatched_files"
|
|
11
11
|
)
|
|
12
12
|
EXAMPLE_ARRAYS_DIR = pathlib.Path(__file__).parent / "example_array_no_grids"
|
|
13
|
+
EXAMPLE_3D_DIST_FN = pathlib.Path(__file__).parent / "example_dist_fn"
|
|
13
14
|
|
|
14
15
|
|
|
15
16
|
def test_basic():
|
|
@@ -178,3 +179,9 @@ def test_arrays_with_no_grids_multifile():
|
|
|
178
179
|
random_states = "Random_States"
|
|
179
180
|
assert random_states in df
|
|
180
181
|
assert df[random_states].shape == (2, 8)
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def test_3d_distribution_function():
|
|
185
|
+
with xr.open_dataset(EXAMPLE_3D_DIST_FN / "0000.sdf") as df:
|
|
186
|
+
distribution_function = "dist_fn_x_px_py_Electron"
|
|
187
|
+
assert df[distribution_function].shape == (16, 20, 20)
|