sdf-xarray 0.3.2__cp311-cp311-win_amd64.whl → 0.4.0__cp311-cp311-win_amd64.whl
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.
- lib/SDFC_14.4.7/sdfc.lib +0 -0
- sdf_xarray/__init__.py +1 -0
- sdf_xarray/_version.py +3 -3
- sdf_xarray/dataset_accessor.py +1 -3
- sdf_xarray/download.py +87 -0
- sdf_xarray/plotting.py +137 -49
- sdf_xarray/sdf_interface.cp311-win_amd64.pyd +0 -0
- sdf_xarray/sdf_interface.pyx +4 -2
- {sdf_xarray-0.3.2.dist-info → sdf_xarray-0.4.0.dist-info}/METADATA +24 -49
- {sdf_xarray-0.3.2.dist-info → sdf_xarray-0.4.0.dist-info}/RECORD +13 -12
- {sdf_xarray-0.3.2.dist-info → sdf_xarray-0.4.0.dist-info}/WHEEL +0 -0
- {sdf_xarray-0.3.2.dist-info → sdf_xarray-0.4.0.dist-info}/entry_points.txt +0 -0
- {sdf_xarray-0.3.2.dist-info → sdf_xarray-0.4.0.dist-info}/licenses/LICENCE +0 -0
lib/SDFC_14.4.7/sdfc.lib
CHANGED
|
Binary file
|
sdf_xarray/__init__.py
CHANGED
|
@@ -22,6 +22,7 @@ from xarray.core.variable import Variable
|
|
|
22
22
|
# NOTE: Do not delete these lines, otherwise the "epoch" dataset and dataarray
|
|
23
23
|
# accessors will not be imported when the user imports sdf_xarray
|
|
24
24
|
import sdf_xarray.dataset_accessor
|
|
25
|
+
import sdf_xarray.download
|
|
25
26
|
import sdf_xarray.plotting # noqa: F401
|
|
26
27
|
|
|
27
28
|
# NOTE: This attempts to initialise with the "pint" accessor if the user
|
sdf_xarray/_version.py
CHANGED
|
@@ -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.
|
|
32
|
-
__version_tuple__ = version_tuple = (0,
|
|
31
|
+
__version__ = version = '0.4.0'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 4, 0)
|
|
33
33
|
|
|
34
|
-
__commit_id__ = commit_id = '
|
|
34
|
+
__commit_id__ = commit_id = 'gc5cdb3bf9'
|
sdf_xarray/dataset_accessor.py
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
from typing import Union
|
|
2
|
-
|
|
3
1
|
import xarray as xr
|
|
4
2
|
|
|
5
3
|
|
|
@@ -13,7 +11,7 @@ class EpochAccessor:
|
|
|
13
11
|
self,
|
|
14
12
|
multiplier: float,
|
|
15
13
|
unit_label: str,
|
|
16
|
-
coord_names:
|
|
14
|
+
coord_names: str | list[str],
|
|
17
15
|
) -> xr.Dataset:
|
|
18
16
|
"""
|
|
19
17
|
Rescales specified X and Y coordinates in the Dataset by a given multiplier
|
sdf_xarray/download.py
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from shutil import move
|
|
3
|
+
from typing import TYPE_CHECKING, Literal, TypeAlias
|
|
4
|
+
|
|
5
|
+
if TYPE_CHECKING:
|
|
6
|
+
import pooch # noqa: F401
|
|
7
|
+
|
|
8
|
+
DatasetName: TypeAlias = Literal[
|
|
9
|
+
"test_array_no_grids",
|
|
10
|
+
"test_dist_fn",
|
|
11
|
+
"test_files_1D",
|
|
12
|
+
"test_files_2D_moving_window",
|
|
13
|
+
"test_files_3D",
|
|
14
|
+
"test_mismatched_files",
|
|
15
|
+
"test_two_probes_2D",
|
|
16
|
+
"tutorial_dataset_1d",
|
|
17
|
+
"tutorial_dataset_2d",
|
|
18
|
+
"tutorial_dataset_2d_moving_window",
|
|
19
|
+
"tutorial_dataset_3d",
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def fetch_dataset(
|
|
24
|
+
dataset_name: DatasetName, save_path: Path | str | None = None
|
|
25
|
+
) -> Path:
|
|
26
|
+
"""
|
|
27
|
+
Downloads the specified dataset from its Zenodo URL. If it is already
|
|
28
|
+
downloaded, then the path to the cached, unzipped directory is returned.
|
|
29
|
+
|
|
30
|
+
Parameters
|
|
31
|
+
---------
|
|
32
|
+
dataset_name
|
|
33
|
+
The name of the dataset to download
|
|
34
|
+
save_path
|
|
35
|
+
The directory to save the dataset to (defaults to the cache folder ``"sdf_datasets"``.
|
|
36
|
+
See `pooch.os_cache` for details on how the cache works)
|
|
37
|
+
|
|
38
|
+
Returns
|
|
39
|
+
-------
|
|
40
|
+
Path
|
|
41
|
+
The path to the directory containing the unzipped dataset files
|
|
42
|
+
|
|
43
|
+
Examples
|
|
44
|
+
--------
|
|
45
|
+
>>> # Assuming the dataset has not been downloaded yet
|
|
46
|
+
>>> path = fetch_dataset("tutorial_dataset_1d")
|
|
47
|
+
Downloading file 'tutorial_dataset_1d.zip' ...
|
|
48
|
+
Unzipping contents of '.../sdf_datasets/tutorial_dataset_1d.zip' to '.../sdf_datasets/tutorial_dataset_1d'
|
|
49
|
+
>>> path
|
|
50
|
+
'.../sdf_datasets/tutorial_dataset_1d'
|
|
51
|
+
"""
|
|
52
|
+
import pooch # noqa: PLC0415
|
|
53
|
+
|
|
54
|
+
logger = pooch.get_logger()
|
|
55
|
+
datasets = pooch.create(
|
|
56
|
+
path=pooch.os_cache("sdf_datasets"),
|
|
57
|
+
base_url="doi:10.5281/zenodo.17618510",
|
|
58
|
+
registry={
|
|
59
|
+
"test_array_no_grids.zip": "md5:583c85ed8c31d0e34e7766b6d9f2d6da",
|
|
60
|
+
"test_dist_fn.zip": "md5:a582ff5e8c59bad62fe4897f65fc7a11",
|
|
61
|
+
"test_files_1D.zip": "md5:42e53b229556c174c538c5481c4d596a",
|
|
62
|
+
"test_files_2D_moving_window.zip": "md5:3744483bbf416936ad6df8847c54dad1",
|
|
63
|
+
"test_files_3D.zip": "md5:a679e71281bab1d373dc4980e6da1a7c",
|
|
64
|
+
"test_mismatched_files.zip": "md5:710fdc94666edf7777523e8fc9dd1bd4",
|
|
65
|
+
"test_two_probes_2D.zip": "md5:0f2a4fefe84a15292d066b3320d4d533",
|
|
66
|
+
"tutorial_dataset_1d.zip": "md5:7fad744d8b8b2b84bba5c0e705fdef7b",
|
|
67
|
+
"tutorial_dataset_2d.zip": "md5:1945ecdbc1ac1798164f83ea2b3d1b31",
|
|
68
|
+
"tutorial_dataset_2d_moving_window.zip": "md5:a795f40d18df69263842055de4559501",
|
|
69
|
+
"tutorial_dataset_3d.zip": "md5:d9254648867016292440fdb028f717f7",
|
|
70
|
+
},
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
datasets.fetch(
|
|
74
|
+
f"{dataset_name}.zip", processor=pooch.Unzip(extract_dir="."), progressbar=True
|
|
75
|
+
)
|
|
76
|
+
cache_path = Path(datasets.path) / dataset_name
|
|
77
|
+
|
|
78
|
+
if save_path is not None:
|
|
79
|
+
save_path = Path(save_path)
|
|
80
|
+
logger.info(
|
|
81
|
+
"Moving contents of '%s' to '%s'",
|
|
82
|
+
cache_path,
|
|
83
|
+
save_path / dataset_name,
|
|
84
|
+
)
|
|
85
|
+
return move(cache_path, save_path / dataset_name)
|
|
86
|
+
|
|
87
|
+
return cache_path
|
sdf_xarray/plotting.py
CHANGED
|
@@ -9,37 +9,69 @@ if TYPE_CHECKING:
|
|
|
9
9
|
import matplotlib.pyplot as plt
|
|
10
10
|
from matplotlib.animation import FuncAnimation
|
|
11
11
|
|
|
12
|
+
from types import MethodType
|
|
13
|
+
|
|
12
14
|
|
|
13
15
|
def get_frame_title(
|
|
14
16
|
data: xr.DataArray,
|
|
15
17
|
frame: int,
|
|
16
18
|
display_sdf_name: bool = False,
|
|
17
19
|
title_custom: str | None = None,
|
|
20
|
+
t: str = "time",
|
|
18
21
|
) -> str:
|
|
19
|
-
"""Generate the title for a frame
|
|
22
|
+
"""Generate the title for a frame
|
|
23
|
+
|
|
24
|
+
Parameters
|
|
25
|
+
----------
|
|
26
|
+
data
|
|
27
|
+
DataArray containing the target data
|
|
28
|
+
frame
|
|
29
|
+
Frame number
|
|
30
|
+
display_sdf_name
|
|
31
|
+
Display the sdf file name in the animation title
|
|
32
|
+
title_custom
|
|
33
|
+
Custom title to add to the plot
|
|
34
|
+
t
|
|
35
|
+
Time coordinate
|
|
36
|
+
"""
|
|
37
|
+
|
|
20
38
|
# Adds custom text to the start of the title, if specified
|
|
21
39
|
title_custom = "" if title_custom is None else f"{title_custom}, "
|
|
22
|
-
# Adds the time and associated units to the title
|
|
23
|
-
|
|
40
|
+
# Adds the time axis and associated units to the title
|
|
41
|
+
t_axis_value = data[t][frame].values
|
|
24
42
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
43
|
+
t_axis_units = data[t].attrs.get("units", False)
|
|
44
|
+
t_axis_units_formatted = f" [{t_axis_units}]" if t_axis_units else ""
|
|
45
|
+
title_t_axis = f"{data[t].long_name} = {t_axis_value:.2e}{t_axis_units_formatted}"
|
|
28
46
|
|
|
29
47
|
# Adds sdf name to the title, if specifed
|
|
30
48
|
title_sdf = f", {frame:04d}.sdf" if display_sdf_name else ""
|
|
31
|
-
return f"{title_custom}{
|
|
49
|
+
return f"{title_custom}{title_t_axis}{title_sdf}"
|
|
32
50
|
|
|
33
51
|
|
|
34
52
|
def calculate_window_boundaries(
|
|
35
|
-
data: xr.DataArray,
|
|
53
|
+
data: xr.DataArray,
|
|
54
|
+
xlim: tuple[float, float] | None = None,
|
|
55
|
+
x_axis_name: str = "X_Grid_mid",
|
|
56
|
+
t: str = "time",
|
|
36
57
|
) -> np.ndarray:
|
|
37
58
|
"""Calculate the bounderies a moving window frame. If the user specifies xlim, this will
|
|
38
59
|
be used as the initial bounderies and the window will move along acordingly.
|
|
60
|
+
|
|
61
|
+
Parameters
|
|
62
|
+
----------
|
|
63
|
+
data
|
|
64
|
+
DataArray containing the target data
|
|
65
|
+
xlim
|
|
66
|
+
x limits
|
|
67
|
+
x_axis_name
|
|
68
|
+
Name of coordinate to assign to the x-axis
|
|
69
|
+
t
|
|
70
|
+
Time coordinate
|
|
39
71
|
"""
|
|
40
|
-
x_grid = data[
|
|
72
|
+
x_grid = data[x_axis_name].values
|
|
41
73
|
x_half_cell = (x_grid[1] - x_grid[0]) / 2
|
|
42
|
-
N_frames = data[
|
|
74
|
+
N_frames = data[t].size
|
|
43
75
|
|
|
44
76
|
# Find the window bounderies by finding the first and last non-NaN values in the 0th lineout
|
|
45
77
|
# along the x-axis.
|
|
@@ -56,7 +88,7 @@ def calculate_window_boundaries(
|
|
|
56
88
|
window_boundaries[i, 1] = x_grid_non_nan[-1] + x_half_cell
|
|
57
89
|
|
|
58
90
|
# User's choice for initial window edge supercides the one calculated
|
|
59
|
-
if xlim:
|
|
91
|
+
if xlim is not None:
|
|
60
92
|
window_boundaries = window_boundaries + xlim - window_boundaries[0]
|
|
61
93
|
return window_boundaries
|
|
62
94
|
|
|
@@ -68,6 +100,15 @@ def compute_global_limits(
|
|
|
68
100
|
) -> tuple[float, float]:
|
|
69
101
|
"""Remove all NaN values from the target data to calculate the global minimum and maximum of the data.
|
|
70
102
|
User defined percentiles can remove extreme outliers.
|
|
103
|
+
|
|
104
|
+
Parameters
|
|
105
|
+
----------
|
|
106
|
+
data
|
|
107
|
+
DataArray containing the target data
|
|
108
|
+
min_percentile
|
|
109
|
+
Minimum percentile of the data
|
|
110
|
+
max_percentile
|
|
111
|
+
Maximum percentile of the data
|
|
71
112
|
"""
|
|
72
113
|
|
|
73
114
|
# Removes NaN values, needed for moving windows
|
|
@@ -86,74 +127,103 @@ def animate(
|
|
|
86
127
|
max_percentile: float = 100,
|
|
87
128
|
title: str | None = None,
|
|
88
129
|
display_sdf_name: bool = False,
|
|
130
|
+
t: str | None = None,
|
|
89
131
|
ax: plt.Axes | None = None,
|
|
90
132
|
**kwargs,
|
|
91
133
|
) -> FuncAnimation:
|
|
92
|
-
"""Generate an animation
|
|
134
|
+
"""Generate an animation using an xarray.DataArray
|
|
93
135
|
|
|
94
136
|
Parameters
|
|
95
137
|
---------
|
|
96
138
|
data
|
|
97
|
-
|
|
139
|
+
DataArray containing the target data
|
|
98
140
|
fps
|
|
99
|
-
Frames per second for the animation
|
|
141
|
+
Frames per second for the animation
|
|
100
142
|
min_percentile
|
|
101
|
-
Minimum percentile of the data
|
|
143
|
+
Minimum percentile of the data
|
|
102
144
|
max_percentile
|
|
103
|
-
Maximum percentile of the data
|
|
145
|
+
Maximum percentile of the data
|
|
104
146
|
title
|
|
105
|
-
Custom title to add to the plot
|
|
147
|
+
Custom title to add to the plot
|
|
106
148
|
display_sdf_name
|
|
107
149
|
Display the sdf file name in the animation title
|
|
150
|
+
t
|
|
151
|
+
Coordinate for t axis (the coordinate which will be animated over). If `None`, use data.dims[0]
|
|
108
152
|
ax
|
|
109
|
-
Matplotlib axes on which to plot
|
|
153
|
+
Matplotlib axes on which to plot
|
|
110
154
|
kwargs
|
|
111
|
-
Keyword arguments to be passed to matplotlib
|
|
155
|
+
Keyword arguments to be passed to matplotlib
|
|
112
156
|
|
|
113
157
|
Examples
|
|
114
158
|
--------
|
|
115
|
-
>>>
|
|
159
|
+
>>> ds["Derived_Number_Density_Electron"].epoch.animate()
|
|
116
160
|
"""
|
|
117
161
|
import matplotlib.pyplot as plt # noqa: PLC0415
|
|
118
162
|
from matplotlib.animation import FuncAnimation # noqa: PLC0415
|
|
119
163
|
|
|
120
164
|
kwargs_original = kwargs.copy()
|
|
121
165
|
|
|
166
|
+
# Create plot if no ax is provided
|
|
122
167
|
if ax is None:
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
168
|
+
fig, ax = plt.subplots()
|
|
169
|
+
# Prevents figure from prematurely displaying in Jupyter notebook
|
|
170
|
+
plt.close(fig)
|
|
171
|
+
|
|
172
|
+
# Sets the animation coordinate (t) for iteration. If time is in the coords
|
|
173
|
+
# then it will set time to be t. If it is not it will fallback to the last
|
|
174
|
+
# coordinate passed in. By default coordinates are passed in from xarray in
|
|
175
|
+
# the form x, y, z so in order to preserve the x and y being on their
|
|
176
|
+
# respective axes we animate over the final coordinate that is passed in
|
|
177
|
+
# which in this example is z
|
|
178
|
+
coord_names = list(data.dims)
|
|
179
|
+
if t is None:
|
|
180
|
+
t = "time" if "time" in coord_names else coord_names[-1]
|
|
181
|
+
coord_names.remove(t)
|
|
182
|
+
|
|
183
|
+
N_frames = data[t].size
|
|
127
184
|
|
|
128
|
-
# Initialise plot and set y-limits for 1D data
|
|
129
185
|
if data.ndim == 2:
|
|
130
|
-
kwargs.setdefault("x",
|
|
131
|
-
plot = data.isel(
|
|
132
|
-
ax.set_title(get_frame_title(data, 0, display_sdf_name, title))
|
|
186
|
+
kwargs.setdefault("x", coord_names[0])
|
|
187
|
+
plot = data.isel({t: 0}).plot(ax=ax, **kwargs)
|
|
188
|
+
ax.set_title(get_frame_title(data, 0, display_sdf_name, title, t))
|
|
189
|
+
global_min, global_max = compute_global_limits(
|
|
190
|
+
data, min_percentile, max_percentile
|
|
191
|
+
)
|
|
133
192
|
ax.set_ylim(global_min, global_max)
|
|
134
193
|
|
|
135
|
-
# Initilise plot and set colour bar for 2D data
|
|
136
194
|
if data.ndim == 3:
|
|
137
|
-
|
|
195
|
+
if "norm" not in kwargs:
|
|
196
|
+
global_min, global_max = compute_global_limits(
|
|
197
|
+
data, min_percentile, max_percentile
|
|
198
|
+
)
|
|
199
|
+
kwargs["norm"] = plt.Normalize(vmin=global_min, vmax=global_max)
|
|
138
200
|
kwargs["add_colorbar"] = False
|
|
139
|
-
# Set default x and y coordinates for
|
|
140
|
-
kwargs.setdefault("x",
|
|
141
|
-
kwargs.setdefault("y",
|
|
201
|
+
# Set default x and y coordinates for 3D data if not provided
|
|
202
|
+
kwargs.setdefault("x", coord_names[0])
|
|
203
|
+
kwargs.setdefault("y", coord_names[1])
|
|
142
204
|
|
|
143
|
-
#
|
|
144
|
-
|
|
145
|
-
|
|
205
|
+
# Finds the time step with the minimum data value
|
|
206
|
+
# This is needed so that the animation can use the correct colour bar
|
|
207
|
+
argmin_time = np.unravel_index(data.argmin(), data.shape)[0]
|
|
208
|
+
|
|
209
|
+
# Initialize the plot, the final output will still start at the first time step
|
|
210
|
+
plot = data.isel({t: argmin_time}).plot(ax=ax, **kwargs)
|
|
211
|
+
ax.set_title(get_frame_title(data, 0, display_sdf_name, title, t))
|
|
212
|
+
kwargs["cmap"] = plot.cmap
|
|
146
213
|
|
|
147
214
|
# Add colorbar
|
|
148
215
|
if kwargs_original.get("add_colorbar", True):
|
|
149
216
|
long_name = data.attrs.get("long_name")
|
|
150
217
|
units = data.attrs.get("units")
|
|
151
|
-
|
|
218
|
+
fig = plot.get_figure()
|
|
219
|
+
fig.colorbar(plot, ax=ax, label=f"{long_name} [{units}]")
|
|
152
220
|
|
|
153
221
|
# check if there is a moving window by finding NaNs in the data
|
|
154
222
|
move_window = np.isnan(np.sum(data.values))
|
|
155
223
|
if move_window:
|
|
156
|
-
window_boundaries = calculate_window_boundaries(
|
|
224
|
+
window_boundaries = calculate_window_boundaries(
|
|
225
|
+
data, kwargs.get("xlim"), kwargs["x"]
|
|
226
|
+
)
|
|
157
227
|
|
|
158
228
|
def update(frame):
|
|
159
229
|
# Set the xlim for each frame in the case of a moving window
|
|
@@ -163,12 +233,12 @@ def animate(
|
|
|
163
233
|
# Update plot for the new frame
|
|
164
234
|
ax.clear()
|
|
165
235
|
|
|
166
|
-
data.isel(
|
|
167
|
-
ax.set_title(get_frame_title(data, frame, display_sdf_name, title))
|
|
236
|
+
plot = data.isel({t: frame}).plot(ax=ax, **kwargs)
|
|
237
|
+
ax.set_title(get_frame_title(data, frame, display_sdf_name, title, t))
|
|
168
238
|
|
|
169
|
-
# Update y-limits for 1D data
|
|
170
239
|
if data.ndim == 2:
|
|
171
240
|
ax.set_ylim(global_min, global_max)
|
|
241
|
+
return plot
|
|
172
242
|
|
|
173
243
|
return FuncAnimation(
|
|
174
244
|
ax.get_figure(),
|
|
@@ -179,6 +249,19 @@ def animate(
|
|
|
179
249
|
)
|
|
180
250
|
|
|
181
251
|
|
|
252
|
+
def show(anim):
|
|
253
|
+
"""Shows the FuncAnimation in a Jupyter notebook.
|
|
254
|
+
|
|
255
|
+
Parameters
|
|
256
|
+
----------
|
|
257
|
+
anim
|
|
258
|
+
`matplotlib.animation.FuncAnimation`
|
|
259
|
+
"""
|
|
260
|
+
from IPython.display import HTML # noqa: PLC0415
|
|
261
|
+
|
|
262
|
+
return HTML(anim.to_jshtml())
|
|
263
|
+
|
|
264
|
+
|
|
182
265
|
@xr.register_dataarray_accessor("epoch")
|
|
183
266
|
class EpochAccessor:
|
|
184
267
|
def __init__(self, xarray_obj):
|
|
@@ -190,16 +273,21 @@ class EpochAccessor:
|
|
|
190
273
|
Parameters
|
|
191
274
|
----------
|
|
192
275
|
args
|
|
193
|
-
Positional arguments passed to :func:`
|
|
276
|
+
Positional arguments passed to :func:`animation`.
|
|
194
277
|
kwargs
|
|
195
|
-
Keyword arguments passed to :func:`
|
|
278
|
+
Keyword arguments passed to :func:`animation`.
|
|
196
279
|
|
|
197
280
|
Examples
|
|
198
281
|
--------
|
|
199
|
-
>>>
|
|
200
|
-
>>>
|
|
201
|
-
>>>
|
|
202
|
-
>>>
|
|
203
|
-
>>> ani.save("myfile.mp4")
|
|
282
|
+
>>> anim = ds["Electric_Field_Ey"].epoch.animate()
|
|
283
|
+
>>> anim.save("myfile.mp4")
|
|
284
|
+
>>> # Or in a jupyter notebook:
|
|
285
|
+
>>> anim.show()
|
|
204
286
|
"""
|
|
205
|
-
|
|
287
|
+
|
|
288
|
+
# Add anim.show() functionality
|
|
289
|
+
# anim.show() will display the animation in a jupyter notebook
|
|
290
|
+
anim = animate(self._obj, *args, **kwargs)
|
|
291
|
+
anim.show = MethodType(show, anim)
|
|
292
|
+
|
|
293
|
+
return anim
|
|
Binary file
|
sdf_xarray/sdf_interface.pyx
CHANGED
|
@@ -110,12 +110,12 @@ _CONSTANT_UNITS_RE = re.compile(r"(?P<name>.*) \((?P<units>.*)\)$")
|
|
|
110
110
|
cdef class Constant:
|
|
111
111
|
_id: str
|
|
112
112
|
name: str
|
|
113
|
-
data: int | str | float
|
|
113
|
+
data: int | str | float | bool
|
|
114
114
|
units: str | None
|
|
115
115
|
|
|
116
116
|
@staticmethod
|
|
117
117
|
cdef Constant from_block(str name, csdf.sdf_block_t* block):
|
|
118
|
-
data: int | str | float | double
|
|
118
|
+
data: int | str | float | double | bool
|
|
119
119
|
|
|
120
120
|
if block.datatype == csdf.SDF_DATATYPE_REAL4:
|
|
121
121
|
data = (<float*>block.const_value)[0]
|
|
@@ -125,6 +125,8 @@ cdef class Constant:
|
|
|
125
125
|
data = (<csdf.int32_t*>block.const_value)[0]
|
|
126
126
|
if block.datatype == csdf.SDF_DATATYPE_INTEGER8:
|
|
127
127
|
data = (<csdf.int64_t*>block.const_value)[0]
|
|
128
|
+
if block.datatype == csdf.SDF_DATATYPE_LOGICAL:
|
|
129
|
+
data = (<bint*>block.const_value)[0]
|
|
128
130
|
|
|
129
131
|
# There's no metadata with e.g. units, but there's a
|
|
130
132
|
# convention to put one in brackets at the end of the name,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sdf-xarray
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
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>, Chris Herdman <chris.herdman@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>, Liam Pattinson <liam.pattinson@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
|
|
@@ -14,30 +14,11 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.11
|
|
15
15
|
Classifier: Programming Language :: Python :: 3.12
|
|
16
16
|
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
-
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
18
|
+
Requires-Python: <3.15,>=3.10
|
|
18
19
|
Requires-Dist: numpy>=2.0.0
|
|
19
20
|
Requires-Dist: xarray>=2024.1.0
|
|
20
21
|
Requires-Dist: dask>=2024.7.1
|
|
21
|
-
Provides-Extra: docs
|
|
22
|
-
Requires-Dist: sphinx>=5.3; extra == "docs"
|
|
23
|
-
Requires-Dist: sphinx_autodoc_typehints>=1.19; extra == "docs"
|
|
24
|
-
Requires-Dist: sphinx-book-theme>=0.4.0rc1; extra == "docs"
|
|
25
|
-
Requires-Dist: sphinx-argparse-cli>=1.10.0; extra == "docs"
|
|
26
|
-
Requires-Dist: sphinx-inline-tabs; extra == "docs"
|
|
27
|
-
Requires-Dist: pickleshare; extra == "docs"
|
|
28
|
-
Requires-Dist: ipython; extra == "docs"
|
|
29
|
-
Requires-Dist: matplotlib; extra == "docs"
|
|
30
|
-
Requires-Dist: pint; extra == "docs"
|
|
31
|
-
Requires-Dist: pint-xarray; extra == "docs"
|
|
32
|
-
Requires-Dist: myst-parser; extra == "docs"
|
|
33
|
-
Provides-Extra: test
|
|
34
|
-
Requires-Dist: pytest>=3.3.0; extra == "test"
|
|
35
|
-
Requires-Dist: dask[complete]; extra == "test"
|
|
36
|
-
Requires-Dist: matplotlib; extra == "test"
|
|
37
|
-
Provides-Extra: lint
|
|
38
|
-
Requires-Dist: ruff; extra == "lint"
|
|
39
|
-
Provides-Extra: build
|
|
40
|
-
Requires-Dist: cibuildwheel[uv]; extra == "build"
|
|
41
22
|
Provides-Extra: jupyter
|
|
42
23
|
Requires-Dist: dask[diagnostics]; extra == "jupyter"
|
|
43
24
|
Requires-Dist: ipykernel>=6.29.5; extra == "jupyter"
|
|
@@ -61,28 +42,21 @@ sdf-xarray provides a backend for [xarray](https://xarray.dev) to read SDF files
|
|
|
61
42
|
[EPOCH](https://epochpic.github.io) using the [SDF-C](https://github.com/epochpic/SDF_C) library.
|
|
62
43
|
Part of [BEAM](#broad-epoch-analysis-modules-beam) (Broad EPOCH Analysis Modules).
|
|
63
44
|
|
|
45
|
+
## Installation
|
|
46
|
+
|
|
64
47
|
> [!IMPORTANT]
|
|
65
48
|
> To install this package make sure you are using one of the Python versions listed above.
|
|
66
49
|
|
|
67
|
-
## Installation
|
|
68
|
-
|
|
69
50
|
Install from PyPI with:
|
|
70
51
|
|
|
71
52
|
```bash
|
|
72
53
|
pip install sdf-xarray
|
|
73
54
|
```
|
|
74
55
|
|
|
75
|
-
|
|
76
|
-
> For use within jupyter notebooks, run this additional command after installation:
|
|
77
|
-
>
|
|
78
|
-
> ```bash
|
|
79
|
-
> pip install "sdf-xarray[jupyter]"
|
|
80
|
-
> ```
|
|
81
|
-
|
|
82
|
-
or from a local checkout:
|
|
56
|
+
or download this code locally:
|
|
83
57
|
|
|
84
58
|
```bash
|
|
85
|
-
git clone https://github.com/epochpic/sdf-xarray.git
|
|
59
|
+
git clone --recursive https://github.com/epochpic/sdf-xarray.git
|
|
86
60
|
cd sdf-xarray
|
|
87
61
|
pip install .
|
|
88
62
|
```
|
|
@@ -91,6 +65,9 @@ We recommend switching to [uv](https://docs.astral.sh/uv/) to manage packages.
|
|
|
91
65
|
|
|
92
66
|
## Usage
|
|
93
67
|
|
|
68
|
+
Below are some simple examples to get you started. Please read the full
|
|
69
|
+
documentation here <https://sdf-xarray.readthedocs.io>.
|
|
70
|
+
|
|
94
71
|
### Single file loading
|
|
95
72
|
|
|
96
73
|
```python
|
|
@@ -111,15 +88,22 @@ print(df["Electric_Field_Ex"])
|
|
|
111
88
|
|
|
112
89
|
### Multi-file loading
|
|
113
90
|
|
|
114
|
-
|
|
115
|
-
|
|
91
|
+
You can open all the SDF files for a given simulation by calling the `open_mfdataset`
|
|
92
|
+
function from `sdf_xarray`. This will additionally add a time dimension using the `"time"`
|
|
93
|
+
value stored in each files attributes.
|
|
94
|
+
|
|
95
|
+
> [!IMPORTANT]
|
|
96
|
+
> If your simulation has multiple `output` blocks so that not all variables are
|
|
97
|
+
> output at every time step, then at the timesteps where those variables are not
|
|
98
|
+
> present they will have have a value of nan. To clean your dataset by removing
|
|
99
|
+
> these nan values we suggest using the `xarray.DataArray.dropna` function or
|
|
100
|
+
> loading sparse data along separate time dimensions using `separate_times=True`.
|
|
116
101
|
|
|
117
102
|
```python
|
|
118
|
-
|
|
119
|
-
from sdf_xarray import SDFPreprocess
|
|
103
|
+
from sdf_xarray import open_mfdataset
|
|
120
104
|
|
|
121
|
-
|
|
122
|
-
|
|
105
|
+
ds = open_mfdataset("*.sdf")
|
|
106
|
+
print(ds)
|
|
123
107
|
|
|
124
108
|
# Dimensions:
|
|
125
109
|
# time: 301, X_Grid_mid: 128, ...
|
|
@@ -129,15 +113,6 @@ with xr.open_mfdataset("*.sdf", preprocess=SDFPreprocess()) as ds:
|
|
|
129
113
|
# Attributes: (22) ...
|
|
130
114
|
```
|
|
131
115
|
|
|
132
|
-
`SDFPreprocess` checks that all the files are from the same simulation, as
|
|
133
|
-
ensures there's a `time` dimension so the files are correctly concatenated.
|
|
134
|
-
|
|
135
|
-
If your simulation has multiple `output` blocks so that not all variables are
|
|
136
|
-
output at every time step, then those variables will have `NaN` values at the
|
|
137
|
-
corresponding time points.
|
|
138
|
-
|
|
139
|
-
For more in depth documentation please visit: <https://sdf-xarray.readthedocs.io/>
|
|
140
|
-
|
|
141
116
|
## Citing
|
|
142
117
|
|
|
143
118
|
If sdf-xarray contributes to a project that leads to publication, please acknowledge this by citing sdf-xarray. This can be done by clicking the "cite this repository" button located near the top right of this page.
|
|
@@ -6,20 +6,21 @@ include/SDFC_14.4.7/sdf_list_type.h,sha256=Quu8v0-SEsQuJpGtEZnm09tAyXqWNitx0sXl5
|
|
|
6
6
|
include/SDFC_14.4.7/sdf_vector_type.h,sha256=dbKjhzRRsvhzrnTwVjtVlvnuisEnRMKY-vvdm94ok_Q,1595
|
|
7
7
|
include/SDFC_14.4.7/stack_allocator.h,sha256=L7U9vmGiVSw3VQLIv9EzTaVq7JbFxs9aNonKStTkUSg,1335
|
|
8
8
|
include/SDFC_14.4.7/uthash.h,sha256=rIyy_-ylY6S_7WaZCCC3VtvXaC9q37rFyA0f1U9xc4w,63030
|
|
9
|
-
lib/SDFC_14.4.7/sdfc.lib,sha256=
|
|
9
|
+
lib/SDFC_14.4.7/sdfc.lib,sha256=ZhhC5S7yHBXQwkey_wOemw7Cw-iik423_0nVcmM_P7c,350158
|
|
10
10
|
lib/SDFC_14.4.7/SDFCConfig.cmake,sha256=IOA1eusC-KvUK4LNTEiOAmEdaPH1ZvNvbYPgiG1oZio,802
|
|
11
11
|
lib/SDFC_14.4.7/SDFCConfigVersion.cmake,sha256=pN7Qqyf04s3izw7PYQ0XK6imvmhaVegSdR_nEl3Ok_o,2830
|
|
12
12
|
lib/SDFC_14.4.7/SDFCTargets-release.cmake,sha256=G4zdx5PyjePigeD_a6rmZAxbk7L8Nf0klUnV78Lm2fI,828
|
|
13
13
|
lib/SDFC_14.4.7/SDFCTargets.cmake,sha256=OVt1Gm8n7Ew4fiTmA9yHoef3vIIGwsXUZfqeG9p9Bys,4152
|
|
14
|
-
sdf_xarray/__init__.py,sha256=
|
|
15
|
-
sdf_xarray/_version.py,sha256=
|
|
14
|
+
sdf_xarray/__init__.py,sha256=OAihj1CQVqoVvf-eEmwIttedjyplcoiTOfXpDafNqT8,24229
|
|
15
|
+
sdf_xarray/_version.py,sha256=q0PPvfDga48CLepNF0cz12bk-1nMuF8tgn-8a0yG_w4,746
|
|
16
16
|
sdf_xarray/csdf.pxd,sha256=ADPjAuHsodAvdOz96Z_XlFF7VL3KmVaXcTifWDP3rK0,4205
|
|
17
|
-
sdf_xarray/dataset_accessor.py,sha256=
|
|
18
|
-
sdf_xarray/
|
|
19
|
-
sdf_xarray/
|
|
20
|
-
sdf_xarray/sdf_interface.
|
|
21
|
-
sdf_xarray
|
|
22
|
-
sdf_xarray-0.
|
|
23
|
-
sdf_xarray-0.
|
|
24
|
-
sdf_xarray-0.
|
|
25
|
-
sdf_xarray-0.
|
|
17
|
+
sdf_xarray/dataset_accessor.py,sha256=IhROgmqgdD5SvuMbpZz-G6WoTre06-SOYgXVQSb7VAY,2450
|
|
18
|
+
sdf_xarray/download.py,sha256=yT_z5q8KuGKe3yha_t7JW39IZjzdN2wczqRl8FIhgRA,3123
|
|
19
|
+
sdf_xarray/plotting.py,sha256=FNaptcnHzvwY462JyfXSy9tMKNtuerKNn9A0sD8vbe4,9550
|
|
20
|
+
sdf_xarray/sdf_interface.cp311-win_amd64.pyd,sha256=wTBhhdcptwjeXuCgeGJrJ966f6i4aoRqYbEKQ0VOH7w,339456
|
|
21
|
+
sdf_xarray/sdf_interface.pyx,sha256=j0BpaltExUI_T-DMQvWaavKSrq9vqHkrmkJMJfCwDsA,12096
|
|
22
|
+
sdf_xarray-0.4.0.dist-info/METADATA,sha256=9EoUJ22i_txDaZAX6ZIgnaQdogVv88M-L2VFIZDHofQ,6921
|
|
23
|
+
sdf_xarray-0.4.0.dist-info/WHEEL,sha256=oXhHG6ewLm-FNdEna2zwgy-K0KEl4claZ1ztR4VTx0I,106
|
|
24
|
+
sdf_xarray-0.4.0.dist-info/entry_points.txt,sha256=gP7BIQpXNg6vIf7S7p-Rw_EJZTC1X50BsVTkK7dA7g0,57
|
|
25
|
+
sdf_xarray-0.4.0.dist-info/licenses/LICENCE,sha256=aHWuyELjtzIL1jTXFHTbI3tr9vyVyhnw3I9_QYPdEX8,1515
|
|
26
|
+
sdf_xarray-0.4.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|