sdf-xarray 0.2.3__cp312-cp312-win_amd64.whl → 0.2.5__cp312-cp312-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.
Potentially problematic release.
This version of sdf-xarray might be problematic. Click here for more details.
- lib/SDFC_14.4.7/sdfc.lib +0 -0
- sdf_xarray/__init__.py +12 -3
- sdf_xarray/_version.py +2 -2
- sdf_xarray/plotting.py +97 -76
- sdf_xarray/sdf_interface.cp312-win_amd64.pyd +0 -0
- sdf_xarray/sdf_interface.pyx +1 -1
- {sdf_xarray-0.2.3.dist-info → sdf_xarray-0.2.5.dist-info}/METADATA +2 -2
- {sdf_xarray-0.2.3.dist-info → sdf_xarray-0.2.5.dist-info}/RECORD +11 -11
- {sdf_xarray-0.2.3.dist-info → sdf_xarray-0.2.5.dist-info}/WHEEL +0 -0
- {sdf_xarray-0.2.3.dist-info → sdf_xarray-0.2.5.dist-info}/entry_points.txt +0 -0
- {sdf_xarray-0.2.3.dist-info → sdf_xarray-0.2.5.dist-info}/licenses/LICENCE +0 -0
lib/SDFC_14.4.7/sdfc.lib
CHANGED
|
Binary file
|
sdf_xarray/__init__.py
CHANGED
|
@@ -253,9 +253,18 @@ class SDFDataStore(AbstractDataStore):
|
|
|
253
253
|
def load(self): # noqa: PLR0912, PLR0915
|
|
254
254
|
# Drop any requested variables
|
|
255
255
|
if self.drop_variables:
|
|
256
|
+
# Build a mapping from underscored names to real variable names
|
|
257
|
+
name_map = {_rename_with_underscore(var): var for var in self.ds.variables}
|
|
258
|
+
|
|
256
259
|
for variable in self.drop_variables:
|
|
257
|
-
|
|
258
|
-
|
|
260
|
+
key = _rename_with_underscore(variable)
|
|
261
|
+
original_name = name_map.get(key)
|
|
262
|
+
|
|
263
|
+
if original_name is None:
|
|
264
|
+
raise KeyError(
|
|
265
|
+
f"Variable '{variable}' not found (interpreted as '{key}')."
|
|
266
|
+
)
|
|
267
|
+
self.ds.variables.pop(original_name)
|
|
259
268
|
|
|
260
269
|
# These two dicts are global metadata about the run or file
|
|
261
270
|
attrs = {**self.ds.header, **self.ds.run_info}
|
|
@@ -434,7 +443,7 @@ class SDFEntrypoint(BackendEntrypoint):
|
|
|
434
443
|
|
|
435
444
|
description = "Use .sdf files in Xarray"
|
|
436
445
|
|
|
437
|
-
url = "https://epochpic.github.io/documentation/visualising_output/
|
|
446
|
+
url = "https://epochpic.github.io/documentation/visualising_output/python_beam.html"
|
|
438
447
|
|
|
439
448
|
|
|
440
449
|
class SDFPreprocess:
|
sdf_xarray/_version.py
CHANGED
sdf_xarray/plotting.py
CHANGED
|
@@ -10,60 +10,82 @@ if TYPE_CHECKING:
|
|
|
10
10
|
from matplotlib.animation import FuncAnimation
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
def get_frame_title(
|
|
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:
|
|
14
19
|
"""Generate the title for a frame"""
|
|
15
|
-
|
|
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
|
|
16
23
|
time = data["time"][frame].to_numpy()
|
|
17
|
-
return f"t = {time:.2e}s{sdf_name}"
|
|
18
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}"
|
|
19
28
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
"""Calculate the moving window's velocity and initial edges.
|
|
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}"
|
|
24
32
|
|
|
25
|
-
1. Finds a lineout of the target atribute in the x coordinate of the first frame
|
|
26
|
-
2. Removes the NaN values to isolate the simulation window
|
|
27
|
-
3. Produces the index size of the window, indexed at zero
|
|
28
|
-
4. Uses distance moved and final time of the simulation to calculate velocity and initial xlims
|
|
29
|
-
"""
|
|
30
|
-
time_since_start = data["time"].values - data["time"].values[0]
|
|
31
|
-
initial_window_edge = (0, 0)
|
|
32
|
-
target_lineout = data.values[0, :, 0]
|
|
33
|
-
target_lineout_window = target_lineout[~np.isnan(target_lineout)]
|
|
34
|
-
x_grid = data[x_axis_coord].values
|
|
35
|
-
window_size_index = target_lineout_window.size - 1
|
|
36
33
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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
|
|
40
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
|
|
41
57
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
values_no_nan = data.values[~np.isnan(data.values)]
|
|
47
|
-
global_min = np.percentile(values_no_nan, 1)
|
|
48
|
-
global_max = np.percentile(values_no_nan, 99)
|
|
49
|
-
return global_min, global_max
|
|
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
|
|
50
62
|
|
|
51
63
|
|
|
52
|
-
def
|
|
53
|
-
|
|
54
|
-
|
|
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
|
+
"""
|
|
55
72
|
|
|
73
|
+
# Removes NaN values, needed for moving windows
|
|
74
|
+
values_no_nan = data.values[~np.isnan(data.values)]
|
|
56
75
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
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
|
|
60
80
|
|
|
61
81
|
|
|
62
|
-
def
|
|
82
|
+
def animate(
|
|
63
83
|
data: xr.DataArray,
|
|
84
|
+
fps: float = 10,
|
|
85
|
+
min_percentile: float = 0,
|
|
86
|
+
max_percentile: float = 100,
|
|
87
|
+
title: str | None = None,
|
|
64
88
|
display_sdf_name: bool = False,
|
|
65
|
-
fps: int = 10,
|
|
66
|
-
move_window: bool = False,
|
|
67
89
|
ax: plt.Axes | None = None,
|
|
68
90
|
**kwargs,
|
|
69
91
|
) -> FuncAnimation:
|
|
@@ -71,17 +93,18 @@ def generate_animation(
|
|
|
71
93
|
|
|
72
94
|
Parameters
|
|
73
95
|
---------
|
|
74
|
-
|
|
75
|
-
The
|
|
76
|
-
target_attribute
|
|
77
|
-
The attribute to plot for each timestep
|
|
78
|
-
display_sdf_name
|
|
79
|
-
Display the sdf file name in the animation title
|
|
96
|
+
data
|
|
97
|
+
The dataarray containing the target data
|
|
80
98
|
fps
|
|
81
99
|
Frames per second for the animation (default: 10)
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
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
|
|
85
108
|
ax
|
|
86
109
|
Matplotlib axes on which to plot.
|
|
87
110
|
kwargs
|
|
@@ -89,18 +112,28 @@ def generate_animation(
|
|
|
89
112
|
|
|
90
113
|
Examples
|
|
91
114
|
--------
|
|
92
|
-
>>>
|
|
115
|
+
>>> dataset["Derived_Number_Density_Electron"].epoch.animate()
|
|
93
116
|
"""
|
|
94
117
|
import matplotlib.pyplot as plt
|
|
95
118
|
from matplotlib.animation import FuncAnimation
|
|
96
119
|
|
|
120
|
+
kwargs_original = kwargs.copy()
|
|
121
|
+
|
|
97
122
|
if ax is None:
|
|
98
123
|
_, ax = plt.subplots()
|
|
99
124
|
|
|
100
125
|
N_frames = data["time"].size
|
|
101
|
-
global_min, global_max = compute_global_limits(data)
|
|
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)
|
|
102
134
|
|
|
103
|
-
|
|
135
|
+
# Initilise plot and set colour bar for 2D data
|
|
136
|
+
if data.ndim == 3:
|
|
104
137
|
kwargs["norm"] = plt.Normalize(vmin=global_min, vmax=global_max)
|
|
105
138
|
kwargs["add_colorbar"] = False
|
|
106
139
|
# Set default x and y coordinates for 2D data if not provided
|
|
@@ -109,44 +142,32 @@ def generate_animation(
|
|
|
109
142
|
|
|
110
143
|
# Initialize the plot with the first timestep
|
|
111
144
|
plot = data.isel(time=0).plot(ax=ax, **kwargs)
|
|
112
|
-
ax.set_title(get_frame_title(data, 0, display_sdf_name))
|
|
145
|
+
ax.set_title(get_frame_title(data, 0, display_sdf_name, title))
|
|
113
146
|
|
|
114
147
|
# Add colorbar
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
# Initialise plo and set y-limits for 1D data
|
|
120
|
-
if is_1d(data):
|
|
121
|
-
plot = data.isel(time=0).plot(ax=ax, **kwargs)
|
|
122
|
-
ax.set_title(get_frame_title(data, 0, display_sdf_name))
|
|
123
|
-
ax.set_ylim(global_min, global_max)
|
|
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}$]")
|
|
124
152
|
|
|
153
|
+
# check if there is a moving window by finding NaNs in the data
|
|
154
|
+
move_window = np.isnan(np.sum(data.values))
|
|
125
155
|
if move_window:
|
|
126
|
-
|
|
127
|
-
calculate_window_velocity_and_edges(data, kwargs["x"])
|
|
128
|
-
)
|
|
129
|
-
|
|
130
|
-
# User's choice for initial window edge supercides the one calculated
|
|
131
|
-
if "xlim" in kwargs:
|
|
132
|
-
window_initial_edge = kwargs["xlim"]
|
|
156
|
+
window_boundaries = calculate_window_boundaries(data, kwargs.get("xlim", False))
|
|
133
157
|
|
|
134
158
|
def update(frame):
|
|
135
159
|
# Set the xlim for each frame in the case of a moving window
|
|
136
160
|
if move_window:
|
|
137
|
-
kwargs["xlim"] =
|
|
138
|
-
window_initial_edge[0] + window_velocity * time_since_start[frame],
|
|
139
|
-
window_initial_edge[1] * 0.99
|
|
140
|
-
+ window_velocity * time_since_start[frame],
|
|
141
|
-
)
|
|
161
|
+
kwargs["xlim"] = window_boundaries[frame]
|
|
142
162
|
|
|
143
163
|
# Update plot for the new frame
|
|
144
164
|
ax.clear()
|
|
165
|
+
|
|
145
166
|
data.isel(time=frame).plot(ax=ax, **kwargs)
|
|
146
|
-
ax.set_title(get_frame_title(data, frame, display_sdf_name))
|
|
167
|
+
ax.set_title(get_frame_title(data, frame, display_sdf_name, title))
|
|
147
168
|
|
|
148
|
-
#
|
|
149
|
-
if
|
|
169
|
+
# Update y-limits for 1D data
|
|
170
|
+
if data.ndim == 2:
|
|
150
171
|
ax.set_ylim(global_min, global_max)
|
|
151
172
|
|
|
152
173
|
return FuncAnimation(
|
|
@@ -181,4 +202,4 @@ class EpochAccessor:
|
|
|
181
202
|
>>> ani = ds["Electric_Field_Ey"].epoch.animate()
|
|
182
203
|
>>> ani.save("myfile.mp4")
|
|
183
204
|
"""
|
|
184
|
-
return
|
|
205
|
+
return animate(self._obj, *args, **kwargs)
|
|
Binary file
|
sdf_xarray/sdf_interface.pyx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: sdf-xarray
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.5
|
|
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
|
|
@@ -45,7 +45,6 @@ Requires-Python: >=3.10
|
|
|
45
45
|
Requires-Dist: numpy>=2.0.0
|
|
46
46
|
Requires-Dist: xarray>=2024.1.0
|
|
47
47
|
Requires-Dist: dask>=2024.7.1
|
|
48
|
-
Requires-Dist: cython>=3.0
|
|
49
48
|
Provides-Extra: docs
|
|
50
49
|
Requires-Dist: sphinx>=5.3; extra == "docs"
|
|
51
50
|
Requires-Dist: sphinx_autodoc_typehints>=1.19; extra == "docs"
|
|
@@ -78,6 +77,7 @@ Description-Content-Type: text/markdown
|
|
|
78
77
|
|
|
79
78
|

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

|
|
82
82
|

|
|
83
83
|
[](https://sdf-xarray.readthedocs.io)
|
|
@@ -6,19 +6,19 @@ 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=oAlm-wrW-BWEKXekEtMJaxNttgOg8Oq-OigVpr0Lets,350410
|
|
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=MgATg9E6Jyo1fW3_li3lIEm-yxTHgJbNfZf5qeAvuyY,18073
|
|
15
|
+
sdf_xarray/_version.py,sha256=XjF4m8_cMkXrbRU7Rim3aBSkgXL9DCvwDPeFFTVyWd8,532
|
|
16
16
|
sdf_xarray/csdf.pxd,sha256=ADPjAuHsodAvdOz96Z_XlFF7VL3KmVaXcTifWDP3rK0,4205
|
|
17
|
-
sdf_xarray/plotting.py,sha256=
|
|
18
|
-
sdf_xarray/sdf_interface.cp312-win_amd64.pyd,sha256=
|
|
19
|
-
sdf_xarray/sdf_interface.pyx,sha256=
|
|
20
|
-
sdf_xarray-0.2.
|
|
21
|
-
sdf_xarray-0.2.
|
|
22
|
-
sdf_xarray-0.2.
|
|
23
|
-
sdf_xarray-0.2.
|
|
24
|
-
sdf_xarray-0.2.
|
|
17
|
+
sdf_xarray/plotting.py,sha256=ze1paC1Uw42WOWspdqkyNsUviDt-Z7AwQlPyO7JB90o,7007
|
|
18
|
+
sdf_xarray/sdf_interface.cp312-win_amd64.pyd,sha256=WEtMhheockF1eDMf7a0QjiFADlf2TTlaSVxjVlUihwY,359424
|
|
19
|
+
sdf_xarray/sdf_interface.pyx,sha256=PFC6upg14OZBqiGInLgBoxztIIKBk-HOh3WC9Ro4YUw,11975
|
|
20
|
+
sdf_xarray-0.2.5.dist-info/METADATA,sha256=ybk80dZjGpoDSonOcmjyIO5HdCP4zUJRbqWjuxBn68c,9129
|
|
21
|
+
sdf_xarray-0.2.5.dist-info/WHEEL,sha256=k3AOLK754NVb09U5k7PdROOgoHUP1Q4mZk2PKi14SoM,106
|
|
22
|
+
sdf_xarray-0.2.5.dist-info/entry_points.txt,sha256=gP7BIQpXNg6vIf7S7p-Rw_EJZTC1X50BsVTkK7dA7g0,57
|
|
23
|
+
sdf_xarray-0.2.5.dist-info/licenses/LICENCE,sha256=aHWuyELjtzIL1jTXFHTbI3tr9vyVyhnw3I9_QYPdEX8,1515
|
|
24
|
+
sdf_xarray-0.2.5.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|