osiris-utils 1.1.2__tar.gz → 1.1.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. {osiris_utils-1.1.2/osiris_utils.egg-info → osiris_utils-1.1.4}/PKG-INFO +20 -2
  2. {osiris_utils-1.1.2 → osiris_utils-1.1.4}/README.rst +18 -0
  3. osiris_utils-1.1.4/osiris_utils/__init__.py +28 -0
  4. osiris_utils-1.1.4/osiris_utils/data/__init__.py +0 -0
  5. osiris_utils-1.1.4/osiris_utils/data/data.py +418 -0
  6. osiris_utils-1.1.4/osiris_utils/data/diagnostic.py +979 -0
  7. osiris_utils-1.1.4/osiris_utils/data/simulation.py +203 -0
  8. osiris_utils-1.1.4/osiris_utils/decks/__init__.py +0 -0
  9. osiris_utils-1.1.4/osiris_utils/decks/decks.py +288 -0
  10. osiris_utils-1.1.4/osiris_utils/decks/species.py +55 -0
  11. osiris_utils-1.1.4/osiris_utils/gui/__init__.py +0 -0
  12. osiris_utils-1.1.4/osiris_utils/gui/gui.py +266 -0
  13. osiris_utils-1.1.4/osiris_utils/postprocessing/__init__.py +0 -0
  14. osiris_utils-1.1.4/osiris_utils/postprocessing/derivative.py +243 -0
  15. osiris_utils-1.1.4/osiris_utils/postprocessing/fft.py +240 -0
  16. osiris_utils-1.1.4/osiris_utils/postprocessing/mft.py +348 -0
  17. osiris_utils-1.1.4/osiris_utils/postprocessing/mft_for_gridfile.py +52 -0
  18. osiris_utils-1.1.4/osiris_utils/postprocessing/postprocess.py +42 -0
  19. {osiris_utils-1.1.2 → osiris_utils-1.1.4}/osiris_utils/utils.py +1 -40
  20. {osiris_utils-1.1.2 → osiris_utils-1.1.4/osiris_utils.egg-info}/PKG-INFO +20 -2
  21. osiris_utils-1.1.4/osiris_utils.egg-info/SOURCES.txt +28 -0
  22. {osiris_utils-1.1.2 → osiris_utils-1.1.4}/setup.py +2 -2
  23. osiris_utils-1.1.2/osiris_utils/__init__.py +0 -15
  24. osiris_utils-1.1.2/osiris_utils.egg-info/SOURCES.txt +0 -13
  25. {osiris_utils-1.1.2 → osiris_utils-1.1.4}/LICENSE.txt +0 -0
  26. {osiris_utils-1.1.2 → osiris_utils-1.1.4}/MANIFEST.in +0 -0
  27. {osiris_utils-1.1.2 → osiris_utils-1.1.4}/osiris_utils.egg-info/dependency_links.txt +0 -0
  28. {osiris_utils-1.1.2 → osiris_utils-1.1.4}/osiris_utils.egg-info/requires.txt +0 -0
  29. {osiris_utils-1.1.2 → osiris_utils-1.1.4}/osiris_utils.egg-info/top_level.txt +0 -0
  30. {osiris_utils-1.1.2 → osiris_utils-1.1.4}/pyproject.toml +0 -0
  31. {osiris_utils-1.1.2 → osiris_utils-1.1.4}/requirements.txt +0 -0
  32. {osiris_utils-1.1.2 → osiris_utils-1.1.4}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: osiris_utils
3
- Version: 1.1.2
3
+ Version: 1.1.4
4
4
  Summary: Utilities to manipulate and visualize OSIRIS framework output data
5
5
  Author: ['João Pedro Ferreira Biu', 'João Cândido', 'Diogo Carvalho']
6
6
  Author-email: ['joaopedrofbiu@tecnico.ulisboa.pt']
@@ -19,7 +19,7 @@ Classifier: Programming Language :: Python :: 3.10
19
19
  Classifier: Programming Language :: Python :: 3.11
20
20
  Classifier: Programming Language :: Python :: 3.12
21
21
  Classifier: Topic :: Scientific/Engineering
22
- Requires-Python: >=3.11
22
+ Requires-Python: >=3.10
23
23
  Description-Content-Type: text/x-rst
24
24
  License-File: LICENSE.txt
25
25
  Requires-Dist: numpy
@@ -48,6 +48,10 @@ OSIRIS_UTILS
48
48
  |Pypi|
49
49
 
50
50
  This package contains a set of utilities to open and analyze OSIRIS output files, using Python. All the methods implemented are fully integrated with `NumPy`, and use `np.ndarray` as the main data structure.
51
+ High-level functions are provided to manipulate data from OSIRIS, from reading the data of the diagnostics, to making post-processing calculations.
52
+
53
+ All code is written in Python. To contact the dev team, please send an email to João Biu: `joaopedrofbiu@tecnico.ulisboa.pt <mailto:joaopedrofbiu@tecnico.ulisboa.pt>`_.
54
+ The full dev team can be found below in the Authors and Contributors section.
51
55
 
52
56
  How to install it?
53
57
  ------------------
@@ -58,6 +62,12 @@ To install this package, you can use `pip`::
58
62
 
59
63
  To install it from source, you can clone this repository and run (in the folder containing ``setup.py``)::
60
64
 
65
+ git clone https://github.com/joaopedrobiu6/osiris_utils.git
66
+ pip install .
67
+
68
+ Finally, you can install it in editor mode if you want to contribute to the code::
69
+
70
+ git clone https://github.com/joaopedrobiu6/osiris_utils.git
61
71
  pip install -e .
62
72
 
63
73
  Documentation
@@ -69,3 +79,11 @@ The documentation is available at https://osiris-utils.readthedocs.io or via thi
69
79
  :target: https://pypi.org/project/osiris-utils/
70
80
  :alt: Pypi
71
81
 
82
+ .. _authors:
83
+
84
+ Authors and Contributors
85
+ ------------------------
86
+
87
+ - João Biu
88
+ - João Cândido
89
+ - Diogo Carvalho
@@ -3,6 +3,10 @@ OSIRIS_UTILS
3
3
  |Pypi|
4
4
 
5
5
  This package contains a set of utilities to open and analyze OSIRIS output files, using Python. All the methods implemented are fully integrated with `NumPy`, and use `np.ndarray` as the main data structure.
6
+ High-level functions are provided to manipulate data from OSIRIS, from reading the data of the diagnostics, to making post-processing calculations.
7
+
8
+ All code is written in Python. To contact the dev team, please send an email to João Biu: `joaopedrofbiu@tecnico.ulisboa.pt <mailto:joaopedrofbiu@tecnico.ulisboa.pt>`_.
9
+ The full dev team can be found below in the Authors and Contributors section.
6
10
 
7
11
  How to install it?
8
12
  ------------------
@@ -13,6 +17,12 @@ To install this package, you can use `pip`::
13
17
 
14
18
  To install it from source, you can clone this repository and run (in the folder containing ``setup.py``)::
15
19
 
20
+ git clone https://github.com/joaopedrobiu6/osiris_utils.git
21
+ pip install .
22
+
23
+ Finally, you can install it in editor mode if you want to contribute to the code::
24
+
25
+ git clone https://github.com/joaopedrobiu6/osiris_utils.git
16
26
  pip install -e .
17
27
 
18
28
  Documentation
@@ -24,3 +34,11 @@ The documentation is available at https://osiris-utils.readthedocs.io or via thi
24
34
  :target: https://pypi.org/project/osiris-utils/
25
35
  :alt: Pypi
26
36
 
37
+ .. _authors:
38
+
39
+ Authors and Contributors
40
+ ------------------------
41
+
42
+ - João Biu
43
+ - João Cândido
44
+ - Diogo Carvalho
@@ -0,0 +1,28 @@
1
+ from .utils import (
2
+ time_estimation,
3
+ filesize_estimation,
4
+ transverse_average,
5
+ integrate,
6
+ save_data,
7
+ read_data,
8
+ courant2D,
9
+ )
10
+ from .gui.gui import LAVA_Qt, LAVA
11
+ from .data.data import OsirisGridFile, OsirisRawFile, OsirisData, OsirisHIST
12
+ from .data.simulation import Simulation, Species_Handler
13
+ from .data.diagnostic import Diagnostic
14
+
15
+ from .decks.decks import InputDeckIO
16
+ from .decks.species import Specie
17
+
18
+ from .postprocessing.postprocess import PostProcess
19
+ from .postprocessing.derivative import Derivative_Simulation, Derivative_Diagnostic
20
+ from .postprocessing.fft import FFT_Diagnostic, FastFourierTransform_Simulation
21
+
22
+ from .postprocessing.mft_for_gridfile import MFT_Single
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