osiris-utils 1.1.3__py3-none-any.whl → 1.1.4__py3-none-any.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.
- osiris_utils/__init__.py +19 -6
- osiris_utils/data/__init__.py +0 -0
- osiris_utils/data/data.py +418 -0
- osiris_utils/data/diagnostic.py +979 -0
- osiris_utils/data/simulation.py +203 -0
- osiris_utils/decks/__init__.py +0 -0
- osiris_utils/decks/decks.py +288 -0
- osiris_utils/decks/species.py +55 -0
- osiris_utils/gui/__init__.py +0 -0
- osiris_utils/gui/gui.py +266 -0
- osiris_utils/postprocessing/__init__.py +0 -0
- osiris_utils/postprocessing/derivative.py +243 -0
- osiris_utils/postprocessing/fft.py +240 -0
- osiris_utils/postprocessing/mft.py +348 -0
- osiris_utils/postprocessing/mft_for_gridfile.py +52 -0
- osiris_utils/postprocessing/postprocess.py +42 -0
- osiris_utils/utils.py +1 -40
- {osiris_utils-1.1.3.dist-info → osiris_utils-1.1.4.dist-info}/METADATA +20 -2
- osiris_utils-1.1.4.dist-info/RECORD +22 -0
- {osiris_utils-1.1.3.dist-info → osiris_utils-1.1.4.dist-info}/WHEEL +1 -1
- osiris_utils-1.1.3.dist-info/RECORD +0 -7
- {osiris_utils-1.1.3.dist-info → osiris_utils-1.1.4.dist-info}/licenses/LICENSE.txt +0 -0
- {osiris_utils-1.1.3.dist-info → osiris_utils-1.1.4.dist-info}/top_level.txt +0 -0
osiris_utils/__init__.py
CHANGED
|
@@ -1,15 +1,28 @@
|
|
|
1
|
-
from .utils import (
|
|
2
|
-
|
|
1
|
+
from .utils import (
|
|
2
|
+
time_estimation,
|
|
3
|
+
filesize_estimation,
|
|
4
|
+
transverse_average,
|
|
5
|
+
integrate,
|
|
6
|
+
save_data,
|
|
7
|
+
read_data,
|
|
8
|
+
courant2D,
|
|
9
|
+
)
|
|
3
10
|
from .gui.gui import LAVA_Qt, LAVA
|
|
4
11
|
from .data.data import OsirisGridFile, OsirisRawFile, OsirisData, OsirisHIST
|
|
5
|
-
from .data.simulation import Simulation
|
|
12
|
+
from .data.simulation import Simulation, Species_Handler
|
|
6
13
|
from .data.diagnostic import Diagnostic
|
|
7
14
|
|
|
15
|
+
from .decks.decks import InputDeckIO
|
|
16
|
+
from .decks.species import Specie
|
|
17
|
+
|
|
8
18
|
from .postprocessing.postprocess import PostProcess
|
|
9
19
|
from .postprocessing.derivative import Derivative_Simulation, Derivative_Diagnostic
|
|
10
20
|
from .postprocessing.fft import FFT_Diagnostic, FastFourierTransform_Simulation
|
|
11
21
|
|
|
12
22
|
from .postprocessing.mft_for_gridfile import MFT_Single
|
|
13
|
-
from .postprocessing.mft import
|
|
14
|
-
|
|
15
|
-
|
|
23
|
+
from .postprocessing.mft import (
|
|
24
|
+
MeanFieldTheory_Simulation,
|
|
25
|
+
MFT_Diagnostic,
|
|
26
|
+
MFT_Diagnostic_Average,
|
|
27
|
+
MFT_Diagnostic_Fluctuations,
|
|
28
|
+
)
|
|
File without changes
|
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import pandas as pd
|
|
3
|
+
import h5py
|
|
4
|
+
|
|
5
|
+
class OsirisData():
|
|
6
|
+
"""
|
|
7
|
+
Base class for handling OSIRIS simulation data files (HDF5 and HIST formats).
|
|
8
|
+
|
|
9
|
+
This class provides common functionality for reading and managing basic attributes
|
|
10
|
+
from OSIRIS output files. It serves as the parent class for specialized data handlers.
|
|
11
|
+
|
|
12
|
+
Parameters
|
|
13
|
+
----------
|
|
14
|
+
filename : str
|
|
15
|
+
Path to the data file. Supported formats:
|
|
16
|
+
- HDF5 files (.h5 extension)
|
|
17
|
+
- HIST files (ending with _ene)
|
|
18
|
+
|
|
19
|
+
Attributes
|
|
20
|
+
----------
|
|
21
|
+
dt : float
|
|
22
|
+
Time step of the simulation [simulation units]
|
|
23
|
+
dim : int
|
|
24
|
+
Number of dimensions in the simulation (1, 2, or 3)
|
|
25
|
+
time : list[float, str]
|
|
26
|
+
Current simulation time and units as [value, unit_string]
|
|
27
|
+
iter : int
|
|
28
|
+
Current iteration number
|
|
29
|
+
name : str
|
|
30
|
+
Name identifier of the data field
|
|
31
|
+
type : str
|
|
32
|
+
Type of data (e.g., 'grid', 'particles')
|
|
33
|
+
verbose : bool
|
|
34
|
+
Verbosity flag controlling diagnostic messages (default: False)
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
def __init__(self, filename):
|
|
38
|
+
self._filename = str(filename)
|
|
39
|
+
# self._file = None
|
|
40
|
+
|
|
41
|
+
self._verbose = False
|
|
42
|
+
|
|
43
|
+
if self._filename.endswith('.h5'):
|
|
44
|
+
self._open_file_hdf5(self._filename)
|
|
45
|
+
self._load_basic_attributes(self._file)
|
|
46
|
+
elif self._filename.endswith('_ene'):
|
|
47
|
+
self._open_hist_file(self._filename)
|
|
48
|
+
else:
|
|
49
|
+
raise ValueError('The file should be an HDF5 file with the extension .h5, or a HIST file ending with _ene.')
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _load_basic_attributes(self, f: h5py.File) -> None:
|
|
53
|
+
'''Load common attributes from HDF5 file'''
|
|
54
|
+
self._dt = float(f['SIMULATION'].attrs['DT'][0])
|
|
55
|
+
self._dim = int(f['SIMULATION'].attrs['NDIMS'][0])
|
|
56
|
+
self._time = [float(f.attrs['TIME'][0]), f.attrs['TIME UNITS'][0].decode('utf-8')]
|
|
57
|
+
self._iter = int(f.attrs['ITER'][0])
|
|
58
|
+
self._name = f.attrs['NAME'][0].decode('utf-8')
|
|
59
|
+
self._type = f.attrs['TYPE'][0].decode('utf-8')
|
|
60
|
+
|
|
61
|
+
def verbose(self, verbose: bool = True):
|
|
62
|
+
'''
|
|
63
|
+
Set the verbosity of the class
|
|
64
|
+
|
|
65
|
+
Parameters
|
|
66
|
+
----------
|
|
67
|
+
verbose : bool, optional
|
|
68
|
+
If True, the class will print messages, by default True when calling (False when not calling)
|
|
69
|
+
'''
|
|
70
|
+
self._verbose = verbose
|
|
71
|
+
|
|
72
|
+
def _open_file_hdf5(self, filename):
|
|
73
|
+
'''
|
|
74
|
+
Open the OSIRIS output file. Usually an HDF5 file or txt.
|
|
75
|
+
|
|
76
|
+
Parameters
|
|
77
|
+
----------
|
|
78
|
+
filename : str
|
|
79
|
+
The path to the HDF5 file.
|
|
80
|
+
'''
|
|
81
|
+
if self._verbose: print(f'Opening file > {filename}')
|
|
82
|
+
|
|
83
|
+
if filename.endswith('.h5'):
|
|
84
|
+
self._file = h5py.File(filename, 'r')
|
|
85
|
+
else:
|
|
86
|
+
raise ValueError('The file should be an HDF5 file with the extension .h5')
|
|
87
|
+
|
|
88
|
+
def _open_hist_file(self, filename):
|
|
89
|
+
self._df = pd.read_csv(filename, sep=r'\s+', comment='!', header=0, engine='python')
|
|
90
|
+
|
|
91
|
+
def _close_file(self):
|
|
92
|
+
'''
|
|
93
|
+
Close the HDF5 file.
|
|
94
|
+
'''
|
|
95
|
+
if self._verbose: print('Closing file')
|
|
96
|
+
if self._file:
|
|
97
|
+
self._file.close()
|
|
98
|
+
|
|
99
|
+
@property
|
|
100
|
+
def dt(self):
|
|
101
|
+
return self._dt
|
|
102
|
+
@property
|
|
103
|
+
def dim(self):
|
|
104
|
+
return self._dim
|
|
105
|
+
@property
|
|
106
|
+
def time(self):
|
|
107
|
+
return self._time
|
|
108
|
+
@property
|
|
109
|
+
def iter(self):
|
|
110
|
+
return self._iter
|
|
111
|
+
@property
|
|
112
|
+
def name(self):
|
|
113
|
+
return self._name
|
|
114
|
+
@property
|
|
115
|
+
def type(self):
|
|
116
|
+
return self._type
|
|
117
|
+
|
|
118
|
+
class OsirisGridFile(OsirisData):
|
|
119
|
+
"""
|
|
120
|
+
Handles structured grid data from OSIRIS HDF5 simulations, including electromagnetic fields.
|
|
121
|
+
|
|
122
|
+
Parameters
|
|
123
|
+
----------
|
|
124
|
+
filename : str
|
|
125
|
+
Path to OSIRIS HDF5 grid file (.h5 extension)
|
|
126
|
+
|
|
127
|
+
Attributes
|
|
128
|
+
----------
|
|
129
|
+
grid : np.ndarray
|
|
130
|
+
Grid boundaries as ((x1_min, x1_max), (x2_min, x2_max), ...)
|
|
131
|
+
nx : tuple
|
|
132
|
+
Number of grid points per dimension (nx1, nx2, nx3)
|
|
133
|
+
dx : np.ndarray
|
|
134
|
+
Grid spacing per dimension (dx1, dx2, dx3)
|
|
135
|
+
x : list[np.ndarray]
|
|
136
|
+
Spatial coordinates arrays for each dimension
|
|
137
|
+
axis : list[dict]
|
|
138
|
+
Axis metadata with keys:
|
|
139
|
+
- 'name': Axis identifier (e.g., 'x1')
|
|
140
|
+
- 'units': Physical units (LaTeX formatted)
|
|
141
|
+
- 'long_name': Descriptive name (LaTeX formatted)
|
|
142
|
+
- 'type': Axis type (e.g., 'SPATIAL')
|
|
143
|
+
- 'plot_label': Combined label for plotting
|
|
144
|
+
data : np.ndarray
|
|
145
|
+
Raw field data array (shape depends on simulation dimensions)
|
|
146
|
+
units : str
|
|
147
|
+
Field units (LaTeX formatted)
|
|
148
|
+
label : str
|
|
149
|
+
Field label/name (LaTeX formatted, e.g., r'$E_x$')
|
|
150
|
+
FFTdata : np.ndarray
|
|
151
|
+
Fourier-transformed data (available after calling FFT())
|
|
152
|
+
"""
|
|
153
|
+
|
|
154
|
+
def __init__(self, filename):
|
|
155
|
+
super().__init__(filename)
|
|
156
|
+
|
|
157
|
+
variable_key = self._get_variable_key(self._file)
|
|
158
|
+
|
|
159
|
+
self._units = self._file.attrs['UNITS'][0].decode('utf-8')
|
|
160
|
+
self._label = self._file.attrs['LABEL'][0].decode('utf-8')
|
|
161
|
+
self._FFTdata = None
|
|
162
|
+
|
|
163
|
+
data = np.array(self._file[variable_key][:])
|
|
164
|
+
|
|
165
|
+
axis = list(self._file['AXIS'].keys())
|
|
166
|
+
if len(axis) == 1:
|
|
167
|
+
self._grid = self._file['AXIS/' + axis[0]][()]
|
|
168
|
+
self._nx = len(data)
|
|
169
|
+
self._dx = (self.grid[1] - self.grid[0] ) / self.nx
|
|
170
|
+
self._x = np.arange(self.grid[0], self.grid[1], self.dx)
|
|
171
|
+
else:
|
|
172
|
+
grid = []
|
|
173
|
+
for ax in axis: grid.append(self._file['AXIS/' + ax][()])
|
|
174
|
+
self._grid = np.array(grid)
|
|
175
|
+
self._nx = self._file[variable_key][()].transpose().shape
|
|
176
|
+
self._dx = (self.grid[:, 1] - self.grid[:, 0])/self.nx
|
|
177
|
+
self._x = [np.arange(self.grid[i, 0], self.grid[i, 1], self.dx[i]) for i in range(self.dim)]
|
|
178
|
+
|
|
179
|
+
self._axis = []
|
|
180
|
+
for ax in axis:
|
|
181
|
+
axis_data = {
|
|
182
|
+
'name': self._file['AXIS/'+ax].attrs['NAME'][0].decode('utf-8'),
|
|
183
|
+
'units': self._file['AXIS/'+ax].attrs['UNITS'][0].decode('utf-8'),
|
|
184
|
+
'long_name': self._file['AXIS/'+ax].attrs['LONG_NAME'][0].decode('utf-8'),
|
|
185
|
+
'type': self._file['AXIS/'+ax].attrs['TYPE'][0].decode('utf-8'),
|
|
186
|
+
'plot_label': rf'${self._file["AXIS/"+ax].attrs["LONG_NAME"][0].decode("utf-8")}$ $[{self._file["AXIS/"+ax].attrs["UNITS"][0].decode("utf-8")}]$',
|
|
187
|
+
}
|
|
188
|
+
self._axis.append(axis_data)
|
|
189
|
+
|
|
190
|
+
self._data = np.ascontiguousarray(data.T)
|
|
191
|
+
|
|
192
|
+
self._close_file()
|
|
193
|
+
|
|
194
|
+
def _load_basic_attributes(self, f: h5py.File) -> None:
|
|
195
|
+
'''Load common attributes from HDF5 file'''
|
|
196
|
+
self._dt = float(f['SIMULATION'].attrs['DT'][0])
|
|
197
|
+
self._dim = int(f['SIMULATION'].attrs['NDIMS'][0])
|
|
198
|
+
self._time = [float(f.attrs['TIME'][0]), f.attrs['TIME UNITS'][0].decode('utf-8')]
|
|
199
|
+
self._iter = int(f.attrs['ITER'][0])
|
|
200
|
+
self._name = f.attrs['NAME'][0].decode('utf-8')
|
|
201
|
+
self._type = f.attrs['TYPE'][0].decode('utf-8')
|
|
202
|
+
|
|
203
|
+
def _get_variable_key(self, f: h5py.File) -> str:
|
|
204
|
+
return next(k for k in f.keys() if k not in {'AXIS', 'SIMULATION'})
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def _yeeToCellCorner1d(self, boundary):
|
|
209
|
+
'''
|
|
210
|
+
Converts 1d EM fields from a staggered Yee mesh to a grid with field values centered on the corner of the cell (the corner of the cell [1] has coordinates [1])
|
|
211
|
+
'''
|
|
212
|
+
|
|
213
|
+
if self.name.lower() in ['b2', 'b3', 'e1']:
|
|
214
|
+
if boundary == 'periodic': return 0.5 * (np.roll(self.data, shift=1) + self.data)
|
|
215
|
+
else: return 0.5 * (self.data[1:] + self.data[:-1])
|
|
216
|
+
elif self.name.lower() in ['b1', 'e2', 'e3']:
|
|
217
|
+
if boundary == 'periodic': return self.data
|
|
218
|
+
else: return self.data[1:]
|
|
219
|
+
else:
|
|
220
|
+
raise TypeError(f'This method expects magnetic or electric field grid data but received \'{self.name}\' instead')
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def _yeeToCellCorner2d(self, boundary):
|
|
224
|
+
'''
|
|
225
|
+
Converts 2d EM fields from a staggered Yee mesh to a grid with field values centered on the corner of the cell (the corner of the cell [1,1] has coordinates [1,1])
|
|
226
|
+
'''
|
|
227
|
+
|
|
228
|
+
if self.name.lower() in ['e1', 'b2']:
|
|
229
|
+
if boundary == 'periodic': return 0.5 * (np.roll(self.data, shift=1, axis=0) + self.data)
|
|
230
|
+
else: return 0.5 * (self.data[1:, 1:] + self.data[:-1, 1:])
|
|
231
|
+
elif self.name.lower() in ['e2', 'b1']:
|
|
232
|
+
if boundary == 'periodic': return 0.5 * (np.roll(self.data, shift=1, axis=1) + self.data)
|
|
233
|
+
else: return 0.5 * (self.data[1:, 1:] + self.data[1:, :-1])
|
|
234
|
+
elif self.name.lower() in ['b3']:
|
|
235
|
+
if boundary == 'periodic':
|
|
236
|
+
return 0.5 * (np.roll((0.5 * (np.roll(self.data, shift=1, axis=0) + self.data)), shift=1, axis=1) + (0.5 * (np.roll(self.data, shift=1, axis=0) + self.data)))
|
|
237
|
+
else:
|
|
238
|
+
return 0.25 * (self.data[1:, 1:] + self.data[:-1, 1:] + self.data[1:, :-1] + self.data[:-1, :-1])
|
|
239
|
+
elif self.name.lower() in ['e3']:
|
|
240
|
+
if boundary == 'periodic': return self.data
|
|
241
|
+
else: return self.data[1:, 1:]
|
|
242
|
+
else:
|
|
243
|
+
raise TypeError(f'This method expects magnetic or electric field grid data but received \'{self.name}\' instead')
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def _yeeToCellCorner3d(self, boundary):
|
|
247
|
+
'''
|
|
248
|
+
Converts 3d EM fields from a staggered Yee mesh to a grid with field values centered on the corner of the cell (the corner of the cell [1,1,1] has coordinates [1,1,1])
|
|
249
|
+
'''
|
|
250
|
+
if boundary == 'periodic':
|
|
251
|
+
raise ValueError('Centering field from 3D simulations considering periodic boundary conditions is not implemented yet')
|
|
252
|
+
if self.name.lower() == 'b1':
|
|
253
|
+
return 0.25 * (self.data[1:, 1:, 1:] + self.data[1:, :-1, 1:] + self.data[1:, 1:, :-1] + self.data[1:, :-1, :-1])
|
|
254
|
+
elif self.name.lower() == 'b2':
|
|
255
|
+
return 0.25 * (self.data[1:, 1:, 1:] + self.data[:-1, 1:, 1:] + self.data[1:, 1:, :-1] + self.data[:-1, 1:, :-1])
|
|
256
|
+
elif self.name.lower() == 'b3':
|
|
257
|
+
return 0.25 * (self.data[1:, 1:, 1:] + self.data[:-1, 1:, 1:] + self.data[1:, :-1, 1:] + self.data[:-1, :-1, 1:])
|
|
258
|
+
elif self.name.lower() == 'e1':
|
|
259
|
+
return 0.5 * (self.data[1:, 1:, 1:] + self.data[:-1, 1:, 1:])
|
|
260
|
+
elif self.name.lower() == 'e2':
|
|
261
|
+
return 0.5 * (self.data[1:, 1:, 1:] + self.data[1:, :-1, 1:])
|
|
262
|
+
elif self.name.lower() == 'e3':
|
|
263
|
+
return 0.5 * (self.data[1:, 1:, 1:] + self.data[1:, 1:, :-1])
|
|
264
|
+
else:
|
|
265
|
+
raise TypeError(f'This method expects magnetic or electric field grid data but received \'{self.name}\' instead')
|
|
266
|
+
|
|
267
|
+
def yeeToCellCorner(self, boundary=None):
|
|
268
|
+
''''
|
|
269
|
+
Converts EM fields from a staggered Yee mesh to a grid with field values centered on the corner of the cell.'
|
|
270
|
+
Can be used for 1D, 2D and 3D simulations.'
|
|
271
|
+
Creates a new attribute `data_centered` with the centered data.'
|
|
272
|
+
'''
|
|
273
|
+
|
|
274
|
+
cases = {'b1', 'b2', 'b3', 'e1', 'e2', 'e3'}
|
|
275
|
+
if self.name not in cases:
|
|
276
|
+
raise TypeError(f'This method expects magnetic or electric field grid data but received \'{self.name}\' instead')
|
|
277
|
+
|
|
278
|
+
if self.dim == 1:
|
|
279
|
+
self.data_centered = self._yeeToCellCorner1d(boundary)
|
|
280
|
+
return self.data_centered
|
|
281
|
+
elif self.dim == 2:
|
|
282
|
+
self.data_centered = self._yeeToCellCorner2d(boundary)
|
|
283
|
+
return self.data_centered
|
|
284
|
+
elif self.dim == 3:
|
|
285
|
+
self.data_centered = self._yeeToCellCorner3d(boundary)
|
|
286
|
+
return self.data_centered
|
|
287
|
+
else:
|
|
288
|
+
raise ValueError(f'Dimension {self.dim} is not supported')
|
|
289
|
+
|
|
290
|
+
def FFT(self, axis=(0, )):
|
|
291
|
+
'''
|
|
292
|
+
Computes the Fast Fourier Transform of the data along the specified axis and shifts the zero frequency to the center.
|
|
293
|
+
Transforms the data to the frequency domain. A(x, y, z) -> A(kx, ky, kz)
|
|
294
|
+
'''
|
|
295
|
+
datafft = np.fft.fftn(self.data, axes=axis)
|
|
296
|
+
self._FFTdata = np.fft.fftshift(datafft, axes=axis)
|
|
297
|
+
|
|
298
|
+
# Getters
|
|
299
|
+
@property
|
|
300
|
+
def grid(self):
|
|
301
|
+
return self._grid
|
|
302
|
+
@property
|
|
303
|
+
def nx(self):
|
|
304
|
+
return self._nx
|
|
305
|
+
@property
|
|
306
|
+
def dx(self):
|
|
307
|
+
return self._dx
|
|
308
|
+
@property
|
|
309
|
+
def x(self):
|
|
310
|
+
return self._x
|
|
311
|
+
@property
|
|
312
|
+
def axis(self):
|
|
313
|
+
return self._axis
|
|
314
|
+
@property
|
|
315
|
+
def data(self):
|
|
316
|
+
return self._data
|
|
317
|
+
@property
|
|
318
|
+
def units(self):
|
|
319
|
+
return self._units
|
|
320
|
+
@property
|
|
321
|
+
def label(self):
|
|
322
|
+
return self._label
|
|
323
|
+
@property
|
|
324
|
+
def FFTdata(self):
|
|
325
|
+
if self._FFTdata is None:
|
|
326
|
+
raise ValueError('The FFT of the data has not been computed yet. Compute it using the FFT method.')
|
|
327
|
+
return self._FFTdata
|
|
328
|
+
# Setters
|
|
329
|
+
@data.setter
|
|
330
|
+
def data(self, data):
|
|
331
|
+
self._data = data
|
|
332
|
+
|
|
333
|
+
def __str__(self):
|
|
334
|
+
# write me a template to print with the name, label, units, time, iter, grid, nx, dx, axis, dt, dim in a logical way
|
|
335
|
+
return rf'{self.name}' + f'\n' + rf'Time: [{self.time[0]} {self.time[1]}], dt = {self.dt}' + f'\n' + f'Iteration: {self.iter}' + f'\n' + f'Grid: {self.grid}' + f'\n' + f'dx: {self.dx}' + f'\n' + f'Dimensions: {self.dim}D'
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
def __array__(self):
|
|
339
|
+
return np.asarray(self.data)
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
class OsirisRawFile(OsirisData):
|
|
343
|
+
'''
|
|
344
|
+
Class to read the raw data from an OSIRIS HDF5 file.
|
|
345
|
+
|
|
346
|
+
Input:
|
|
347
|
+
- filename: the path to the HDF5 file
|
|
348
|
+
|
|
349
|
+
Attributes:
|
|
350
|
+
- axis - a dictionary where each key is a dataset name, and each value is another dictionary containing
|
|
351
|
+
name (str): The name of the quantity (e.g., r'x1', r'ene').
|
|
352
|
+
units (str): The units associated with that dataset in LaTeX (e.g., r'c/\\omega_p', r'm_e c^2').
|
|
353
|
+
long_name (str): The name of the quantity in LaTeX (e.g., r'x_1', r'En2').
|
|
354
|
+
dictionary of dictionaries
|
|
355
|
+
- data - a dictionary where each key is a dataset name, and each value is the data
|
|
356
|
+
dictionary of np.arrays
|
|
357
|
+
- dim - the number of dimensions
|
|
358
|
+
int
|
|
359
|
+
- dt - the time step
|
|
360
|
+
float
|
|
361
|
+
- grid - maximum and minimum coordinates of the box, for each axis
|
|
362
|
+
numpy.ndarray(dim,2)
|
|
363
|
+
- iter - the iteration number
|
|
364
|
+
int
|
|
365
|
+
- name - the name of the species
|
|
366
|
+
str
|
|
367
|
+
- time - the time and its units
|
|
368
|
+
list [time, units]
|
|
369
|
+
list [float, str]
|
|
370
|
+
- type - type of data (particles in the case of raw files)
|
|
371
|
+
str
|
|
372
|
+
|
|
373
|
+
'''
|
|
374
|
+
|
|
375
|
+
def __init__(self, filename):
|
|
376
|
+
super().__init__(filename)
|
|
377
|
+
|
|
378
|
+
self.grid = np.array([self._file['SIMULATION'].attrs['XMIN'], self._file['SIMULATION'].attrs['XMAX']]).T
|
|
379
|
+
|
|
380
|
+
self.data = {}
|
|
381
|
+
self.axis = {}
|
|
382
|
+
for key in self._file.keys():
|
|
383
|
+
if key == 'SIMULATION': continue
|
|
384
|
+
|
|
385
|
+
self.data[key] = np.array(self._file[key][()])
|
|
386
|
+
|
|
387
|
+
idx = np.where(self._file.attrs['QUANTS'] == str(key).encode('utf-8'))
|
|
388
|
+
axis_data = {
|
|
389
|
+
'name': self._file.attrs['QUANTS'][idx][0].decode('utf-8'),
|
|
390
|
+
'units': self._file.attrs['UNITS'][idx][0].decode('utf-8'),
|
|
391
|
+
'long_name': self._file.attrs['LABELS'][idx][0].decode('utf-8'),
|
|
392
|
+
}
|
|
393
|
+
self.axis[key] = axis_data
|
|
394
|
+
|
|
395
|
+
class OsirisHIST(OsirisData):
|
|
396
|
+
''''
|
|
397
|
+
Class to read the data from an OSIRIS HIST file.'
|
|
398
|
+
|
|
399
|
+
Input:
|
|
400
|
+
- filename: the path to the HIST file
|
|
401
|
+
|
|
402
|
+
Attributes:
|
|
403
|
+
- filename - the path to the file
|
|
404
|
+
str
|
|
405
|
+
- verbose - if True, the class will print messages
|
|
406
|
+
bool
|
|
407
|
+
- df - the data in a pandas DataFrame
|
|
408
|
+
pandas.DataFrame
|
|
409
|
+
'''
|
|
410
|
+
def __init__(self, filename):
|
|
411
|
+
super().__init__(filename)
|
|
412
|
+
|
|
413
|
+
@property
|
|
414
|
+
def df(self):
|
|
415
|
+
"""
|
|
416
|
+
Returns the data in a pandas DataFrame
|
|
417
|
+
"""
|
|
418
|
+
return self._df
|