sdf-xarray 0.3.1__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.1 → sdf_xarray-0.3.2}/CITATION.cff +4 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/PKG-INFO +2 -2
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/pyproject.toml +1 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/src/sdf_xarray/__init__.py +104 -13
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/src/sdf_xarray/_version.py +3 -3
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/tests/test_basic.py +232 -1
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/.github/workflows/black.yml +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/.github/workflows/build_publish.yml +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/.github/workflows/lint.yml +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/.github/workflows/tests.yml +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/.gitignore +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/.gitmodules +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/.readthedocs.yaml +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/BEAM.png +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/CMakeLists.txt +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/CONTRIBUTING.md +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/LICENCE +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/PlasmaFAIR.svg +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/README.md +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/.gitignore +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/_templates/custom-class-template.rst +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/_templates/custom-module-template.rst +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/api.rst +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/conf.py +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/contributing.rst +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/getting_started.rst +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/index.rst +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/key_functionality.rst +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/known_issues.rst +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/make.bat +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0000.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0001.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0002.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0003.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0004.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0005.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0006.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0007.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0008.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0009.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0010.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0011.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0012.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0013.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0014.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0015.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0016.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0017.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0018.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0019.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0020.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0021.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0022.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0023.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0024.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0025.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0026.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0027.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0028.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0029.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0030.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0031.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0032.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0033.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0034.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0035.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0036.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0037.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0038.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0039.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/0040.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/deck.status +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/epoch1d.dat +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/input.deck +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/normal.visit +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_1d/restart.visit +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_2d/0000.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_2d/0001.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_2d/0002.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_2d/0003.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_2d/0004.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_2d/0005.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/tutorial_dataset_2d/input.deck +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/docs/unit_conversion.rst +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/src/sdf_xarray/csdf.pxd +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/src/sdf_xarray/dataset_accessor.py +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/src/sdf_xarray/plotting.py +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/src/sdf_xarray/sdf_interface.pyx +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/tests/example_array_no_grids/0000.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/tests/example_array_no_grids/0001.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/tests/example_array_no_grids/README.md +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/tests/example_array_no_grids/input.deck +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/tests/example_dist_fn/0000.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/tests/example_dist_fn/0001.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/tests/example_dist_fn/0002.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/tests/example_dist_fn/input.deck +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/tests/example_files_1D/0000.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/tests/example_files_1D/0001.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/tests/example_files_1D/0002.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/tests/example_files_1D/0003.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/tests/example_files_1D/0004.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/tests/example_files_1D/0005.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/tests/example_files_1D/0006.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/tests/example_files_1D/0007.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/tests/example_files_1D/0008.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/tests/example_files_1D/0009.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/tests/example_files_1D/0010.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/tests/example_files_1D/README.md +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/tests/example_files_1D/input.deck +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/tests/example_files_2D_moving_window/0000.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/tests/example_files_2D_moving_window/0001.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/tests/example_files_2D_moving_window/0002.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/tests/example_files_2D_moving_window/0003.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/tests/example_files_2D_moving_window/0004.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/tests/example_files_2D_moving_window/input.deck +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/tests/example_files_3D/0000.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/tests/example_files_3D/0001.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/tests/example_files_3D/input.deck +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/tests/example_mismatched_files/0000.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/tests/example_mismatched_files/0001.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/tests/example_mismatched_files/0002.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/tests/example_two_probes_2D/0000.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/tests/example_two_probes_2D/0001.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/tests/example_two_probes_2D/0002.sdf +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/tests/example_two_probes_2D/input.deck +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/tests/test_cython.py +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/tests/test_epoch_dataarray_accessor.py +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/tests/test_epoch_dataset_accessor.py +0 -0
- {sdf_xarray-0.3.1 → sdf_xarray-0.3.2}/uv.lock +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
|
|
@@ -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"]
|
|
@@ -84,8 +84,45 @@ def _resolve_glob(path_glob: PathLike | Iterable[PathLike]):
|
|
|
84
84
|
return paths
|
|
85
85
|
|
|
86
86
|
|
|
87
|
-
def
|
|
88
|
-
"""
|
|
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
|
+
)
|
|
89
126
|
|
|
90
127
|
return xr.open_mfdataset(
|
|
91
128
|
path_glob,
|
|
@@ -104,6 +141,7 @@ def open_mfdataset(
|
|
|
104
141
|
separate_times: bool = False,
|
|
105
142
|
keep_particles: bool = False,
|
|
106
143
|
probe_names: list[str] | None = None,
|
|
144
|
+
data_vars: list[str] | None = None,
|
|
107
145
|
) -> xr.Dataset:
|
|
108
146
|
"""Open a set of EPOCH SDF files as one `xarray.Dataset`
|
|
109
147
|
|
|
@@ -135,19 +173,34 @@ def open_mfdataset(
|
|
|
135
173
|
If ``True``, also load particle data (this may use a lot of memory!)
|
|
136
174
|
probe_names :
|
|
137
175
|
List of EPOCH probe names
|
|
176
|
+
data_vars :
|
|
177
|
+
List of data vars to load in (If not specified loads in all variables)
|
|
138
178
|
"""
|
|
139
179
|
|
|
140
180
|
path_glob = _resolve_glob(path_glob)
|
|
181
|
+
|
|
141
182
|
if not separate_times:
|
|
142
183
|
return combine_datasets(
|
|
143
|
-
path_glob,
|
|
184
|
+
path_glob,
|
|
185
|
+
data_vars=data_vars,
|
|
186
|
+
keep_particles=keep_particles,
|
|
187
|
+
probe_names=probe_names,
|
|
144
188
|
)
|
|
145
189
|
|
|
146
190
|
_, var_times_map = make_time_dims(path_glob)
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
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)
|
|
151
204
|
|
|
152
205
|
for df in all_dfs:
|
|
153
206
|
for da in df:
|
|
@@ -165,7 +218,6 @@ def open_mfdataset(
|
|
|
165
218
|
|
|
166
219
|
return xr.combine_by_coords(
|
|
167
220
|
all_dfs,
|
|
168
|
-
data_vars="all",
|
|
169
221
|
coords="different",
|
|
170
222
|
combine_attrs="drop_conflicts",
|
|
171
223
|
join="outer",
|
|
@@ -523,10 +575,43 @@ class SDFEntrypoint(BackendEntrypoint):
|
|
|
523
575
|
|
|
524
576
|
|
|
525
577
|
class SDFPreprocess:
|
|
526
|
-
"""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.
|
|
527
601
|
|
|
528
|
-
|
|
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
|
+
):
|
|
529
613
|
self.job_id: int | None = None
|
|
614
|
+
self.data_vars = data_vars
|
|
530
615
|
|
|
531
616
|
def __call__(self, ds: xr.Dataset) -> xr.Dataset:
|
|
532
617
|
if self.job_id is None:
|
|
@@ -537,17 +622,23 @@ class SDFPreprocess:
|
|
|
537
622
|
f"Mismatching job ids (got {ds.attrs['jobid1']}, expected {self.job_id})"
|
|
538
623
|
)
|
|
539
624
|
|
|
540
|
-
|
|
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])
|
|
541
632
|
ds = ds.assign_coords(
|
|
542
633
|
time=(
|
|
543
634
|
"time",
|
|
544
|
-
[
|
|
635
|
+
[time_val],
|
|
545
636
|
{"units": "s", "long_name": "Time", "full_name": "time"},
|
|
546
637
|
)
|
|
547
638
|
)
|
|
548
639
|
# Particles' spartial coordinates also evolve in time
|
|
549
640
|
for coord, value in ds.coords.items():
|
|
550
641
|
if value.attrs.get("point_data", False):
|
|
551
|
-
ds.coords[coord] = value.expand_dims(time=[
|
|
642
|
+
ds.coords[coord] = value.expand_dims(time=[time_val])
|
|
552
643
|
|
|
553
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'
|
|
@@ -5,7 +5,12 @@ import numpy.testing as npt
|
|
|
5
5
|
import pytest
|
|
6
6
|
import xarray as xr
|
|
7
7
|
|
|
8
|
-
from sdf_xarray import
|
|
8
|
+
from sdf_xarray import (
|
|
9
|
+
SDFPreprocess,
|
|
10
|
+
_process_latex_name,
|
|
11
|
+
_resolve_glob,
|
|
12
|
+
open_mfdataset,
|
|
13
|
+
)
|
|
9
14
|
|
|
10
15
|
EXAMPLE_FILES_DIR = pathlib.Path(__file__).parent / "example_files_1D"
|
|
11
16
|
EXAMPLE_MISMATCHED_FILES_DIR = (
|
|
@@ -454,3 +459,229 @@ def test_xr_oading_one_probe_drop_second_probe():
|
|
|
454
459
|
assert "X_Probe_Electron_Front_Probe" in df.coords
|
|
455
460
|
assert "ID_Electron_Front_Probe_Px" in df.dims
|
|
456
461
|
assert "ID_Electron_Back_Probe_Px" not in df.dims
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
def test_open_mfdataset_data_vars_single():
|
|
465
|
+
with open_mfdataset(
|
|
466
|
+
EXAMPLE_FILES_DIR.glob("*.sdf"),
|
|
467
|
+
data_vars=["Electric_Field_Ex"],
|
|
468
|
+
) as df:
|
|
469
|
+
ex_field = "Electric_Field_Ex"
|
|
470
|
+
x_coord = "X_Grid_mid"
|
|
471
|
+
assert ex_field in df
|
|
472
|
+
assert x_coord in df[ex_field].coords
|
|
473
|
+
assert "time" in df[ex_field].coords
|
|
474
|
+
assert df[x_coord].attrs["long_name"] == "X"
|
|
475
|
+
|
|
476
|
+
assert "Electric_Field_Ey" not in df
|
|
477
|
+
|
|
478
|
+
|
|
479
|
+
def test_open_mfdataset_data_vars_multiple():
|
|
480
|
+
with open_mfdataset(
|
|
481
|
+
EXAMPLE_FILES_DIR.glob("*.sdf"),
|
|
482
|
+
data_vars=["Electric_Field_Ex", "Electric_Field_Ey"],
|
|
483
|
+
) as df:
|
|
484
|
+
ex_field = "Electric_Field_Ex"
|
|
485
|
+
x_coord = "X_Grid_mid"
|
|
486
|
+
assert ex_field in df
|
|
487
|
+
assert x_coord in df[ex_field].coords
|
|
488
|
+
assert "time" in df[ex_field].coords
|
|
489
|
+
assert df[x_coord].attrs["long_name"] == "X"
|
|
490
|
+
|
|
491
|
+
ey_field = "Electric_Field_Ey"
|
|
492
|
+
x_coord = "X_Grid_mid"
|
|
493
|
+
assert ey_field in df
|
|
494
|
+
assert x_coord in df[ey_field].coords
|
|
495
|
+
assert "time" in df[ey_field].coords
|
|
496
|
+
assert df[x_coord].attrs["long_name"] == "X"
|
|
497
|
+
|
|
498
|
+
|
|
499
|
+
def test_open_mfdataset_data_vars_sparse_multiple():
|
|
500
|
+
with open_mfdataset(
|
|
501
|
+
EXAMPLE_FILES_DIR.glob("*.sdf"),
|
|
502
|
+
keep_particles=True,
|
|
503
|
+
data_vars=[
|
|
504
|
+
"Particles_Particles_Per_Cell_proton",
|
|
505
|
+
"Electric_Field_Ez",
|
|
506
|
+
"dist_fn_x_px_proton",
|
|
507
|
+
],
|
|
508
|
+
) as df:
|
|
509
|
+
ppc_proton = "Particles_Particles_Per_Cell_proton"
|
|
510
|
+
assert ppc_proton in df
|
|
511
|
+
assert "time" in df[ppc_proton].coords
|
|
512
|
+
assert (
|
|
513
|
+
df[ppc_proton].attrs["long_name"] == "Particles Particles Per Cell proton"
|
|
514
|
+
)
|
|
515
|
+
|
|
516
|
+
ez_field = "Electric_Field_Ez"
|
|
517
|
+
assert ez_field in df
|
|
518
|
+
assert len(df[ez_field].coords) == 2
|
|
519
|
+
assert "time" in df[ez_field].coords
|
|
520
|
+
assert "X_Grid_mid" in df[ez_field].coords
|
|
521
|
+
assert df[ez_field].attrs["long_name"] == "Electric Field $E_z$"
|
|
522
|
+
|
|
523
|
+
dist_fn = "dist_fn_x_px_proton"
|
|
524
|
+
assert dist_fn in df
|
|
525
|
+
assert len(df[dist_fn].coords) == 3
|
|
526
|
+
assert "time" in df[dist_fn].coords
|
|
527
|
+
assert "X_x_px_proton" in df[dist_fn].coords
|
|
528
|
+
assert "Px_x_px_proton" in df[dist_fn].coords
|
|
529
|
+
|
|
530
|
+
assert df["time"].size == 11
|
|
531
|
+
|
|
532
|
+
|
|
533
|
+
def test_open_mfdataset_data_vars_invalid_var():
|
|
534
|
+
with open_mfdataset(
|
|
535
|
+
EXAMPLE_FILES_DIR.glob("*.sdf"),
|
|
536
|
+
data_vars=["Electric_Field"],
|
|
537
|
+
) as df:
|
|
538
|
+
assert len(df.variables.keys()) == 1
|
|
539
|
+
assert df["time"].size == 11
|
|
540
|
+
|
|
541
|
+
|
|
542
|
+
def test_open_mfdataset_data_vars_time():
|
|
543
|
+
with open_mfdataset(
|
|
544
|
+
EXAMPLE_FILES_DIR.glob("*.sdf"),
|
|
545
|
+
data_vars=["Electric_Field_Ex"],
|
|
546
|
+
) as df:
|
|
547
|
+
time = df["time"]
|
|
548
|
+
assert time.units == "s"
|
|
549
|
+
assert time.long_name == "Time"
|
|
550
|
+
assert time.full_name == "time"
|
|
551
|
+
|
|
552
|
+
time_values = np.array(
|
|
553
|
+
[
|
|
554
|
+
5.466993e-14,
|
|
555
|
+
2.417504e-10,
|
|
556
|
+
4.833915e-10,
|
|
557
|
+
7.251419e-10,
|
|
558
|
+
9.667830e-10,
|
|
559
|
+
1.208533e-09,
|
|
560
|
+
1.450175e-09,
|
|
561
|
+
1.691925e-09,
|
|
562
|
+
1.933566e-09,
|
|
563
|
+
2.175316e-09,
|
|
564
|
+
2.416958e-09,
|
|
565
|
+
]
|
|
566
|
+
)
|
|
567
|
+
|
|
568
|
+
npt.assert_allclose(time_values, time.values, rtol=1e-6)
|
|
569
|
+
|
|
570
|
+
|
|
571
|
+
def test_open_mfdataset_data_vars_sparse_time():
|
|
572
|
+
with open_mfdataset(
|
|
573
|
+
EXAMPLE_FILES_DIR.glob("*.sdf"),
|
|
574
|
+
data_vars=["Particles_Particles_Per_Cell_proton"],
|
|
575
|
+
) as df:
|
|
576
|
+
time = df["time"]
|
|
577
|
+
assert time.units == "s"
|
|
578
|
+
assert time.long_name == "Time"
|
|
579
|
+
assert time.full_name == "time"
|
|
580
|
+
|
|
581
|
+
time_values = np.array(
|
|
582
|
+
[
|
|
583
|
+
5.466993e-14,
|
|
584
|
+
2.417504e-10,
|
|
585
|
+
4.833915e-10,
|
|
586
|
+
7.251419e-10,
|
|
587
|
+
9.667830e-10,
|
|
588
|
+
1.208533e-09,
|
|
589
|
+
1.450175e-09,
|
|
590
|
+
1.691925e-09,
|
|
591
|
+
1.933566e-09,
|
|
592
|
+
2.175316e-09,
|
|
593
|
+
2.416958e-09,
|
|
594
|
+
]
|
|
595
|
+
)
|
|
596
|
+
|
|
597
|
+
npt.assert_allclose(time_values, time.values, rtol=1e-6)
|
|
598
|
+
|
|
599
|
+
|
|
600
|
+
def test_open_mfdataset_data_vars_separate_times_single():
|
|
601
|
+
with open_mfdataset(
|
|
602
|
+
EXAMPLE_FILES_DIR.glob("*.sdf"),
|
|
603
|
+
data_vars=["Electric_Field_Ex"],
|
|
604
|
+
separate_times=True,
|
|
605
|
+
) as df:
|
|
606
|
+
coords = df.coords.sizes
|
|
607
|
+
assert len(coords) == 2
|
|
608
|
+
assert coords["time0"] == 11
|
|
609
|
+
assert coords["X_Grid_mid"] == 16
|
|
610
|
+
|
|
611
|
+
elec_x = "Electric_Field_Ex"
|
|
612
|
+
elec_x_coords = df[elec_x].coords.sizes
|
|
613
|
+
assert elec_x in df
|
|
614
|
+
assert len(elec_x_coords) == 2
|
|
615
|
+
assert "time0" in elec_x_coords
|
|
616
|
+
assert "X_Grid_mid" in elec_x_coords
|
|
617
|
+
|
|
618
|
+
assert elec_x_coords["time0"] == 11
|
|
619
|
+
assert elec_x_coords["X_Grid_mid"] == 16
|
|
620
|
+
|
|
621
|
+
|
|
622
|
+
def test_open_mfdataset_data_vars_separate_times_multiple():
|
|
623
|
+
with open_mfdataset(
|
|
624
|
+
EXAMPLE_FILES_DIR.glob("*.sdf"),
|
|
625
|
+
data_vars=["Electric_Field_Ex", "Electric_Field_Ey"],
|
|
626
|
+
separate_times=True,
|
|
627
|
+
) as df:
|
|
628
|
+
coords = df.coords.sizes
|
|
629
|
+
assert len(coords) == 2
|
|
630
|
+
assert coords["time0"] == 11
|
|
631
|
+
assert coords["X_Grid_mid"] == 16
|
|
632
|
+
|
|
633
|
+
elec_x = "Electric_Field_Ex"
|
|
634
|
+
elec_x_coords = df[elec_x].coords.sizes
|
|
635
|
+
assert elec_x in df
|
|
636
|
+
assert len(elec_x_coords) == 2
|
|
637
|
+
assert "time0" in elec_x_coords
|
|
638
|
+
assert "X_Grid_mid" in elec_x_coords
|
|
639
|
+
|
|
640
|
+
assert elec_x_coords["time0"] == 11
|
|
641
|
+
assert elec_x_coords["X_Grid_mid"] == 16
|
|
642
|
+
|
|
643
|
+
elec_y = "Electric_Field_Ey"
|
|
644
|
+
elec_y_coords = df[elec_y].coords.sizes
|
|
645
|
+
assert elec_y in df
|
|
646
|
+
assert len(elec_y_coords) == 2
|
|
647
|
+
assert "time0" in elec_y_coords
|
|
648
|
+
assert "X_Grid_mid" in elec_y_coords
|
|
649
|
+
|
|
650
|
+
assert elec_y_coords["time0"] == 11
|
|
651
|
+
assert elec_y_coords["X_Grid_mid"] == 16
|
|
652
|
+
|
|
653
|
+
|
|
654
|
+
def test_open_mfdataset_data_vars_separate_times_multiple_times_keep_particles():
|
|
655
|
+
with open_mfdataset(
|
|
656
|
+
EXAMPLE_FILES_DIR.glob("*.sdf"),
|
|
657
|
+
data_vars=["Electric_Field_Ex", "Particles_Px_electron_beam"],
|
|
658
|
+
separate_times=True,
|
|
659
|
+
keep_particles=True,
|
|
660
|
+
) as df:
|
|
661
|
+
coords = df.coords.sizes
|
|
662
|
+
assert len(coords) == 5
|
|
663
|
+
assert coords["time0"] == 11
|
|
664
|
+
assert coords["time1"] == 1
|
|
665
|
+
assert coords["time2"] == 1
|
|
666
|
+
assert coords["X_Grid_mid"] == 16
|
|
667
|
+
assert coords["ID_electron_beam"] == 1440
|
|
668
|
+
|
|
669
|
+
elec_x = "Electric_Field_Ex"
|
|
670
|
+
elec_x_coords = df[elec_x].coords.sizes
|
|
671
|
+
assert elec_x in df
|
|
672
|
+
assert len(elec_x_coords) == 2
|
|
673
|
+
assert "time0" in elec_x_coords
|
|
674
|
+
assert "X_Grid_mid" in elec_x_coords
|
|
675
|
+
|
|
676
|
+
assert elec_x_coords["time0"] == 11
|
|
677
|
+
assert elec_x_coords["X_Grid_mid"] == 16
|
|
678
|
+
|
|
679
|
+
particle_px = "Particles_Px_electron_beam"
|
|
680
|
+
particle_px_coords = df[particle_px].coords.sizes
|
|
681
|
+
assert particle_px in df
|
|
682
|
+
assert len(particle_px_coords) == 2
|
|
683
|
+
assert "time2" in particle_px_coords
|
|
684
|
+
assert "ID_electron_beam" in particle_px_coords
|
|
685
|
+
|
|
686
|
+
assert particle_px_coords["time2"] == 1
|
|
687
|
+
assert particle_px_coords["ID_electron_beam"] == 1440
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|