osiris-utils 1.0.9__tar.gz → 1.1.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.
- {osiris_utils-1.0.9/osiris_utils.egg-info → osiris_utils-1.1.2}/PKG-INFO +33 -4
- osiris_utils-1.1.2/osiris_utils/__init__.py +15 -0
- {osiris_utils-1.0.9 → osiris_utils-1.1.2}/osiris_utils/utils.py +0 -1
- {osiris_utils-1.0.9 → osiris_utils-1.1.2/osiris_utils.egg-info}/PKG-INFO +33 -4
- {osiris_utils-1.0.9 → osiris_utils-1.1.2}/osiris_utils.egg-info/SOURCES.txt +0 -4
- {osiris_utils-1.0.9 → osiris_utils-1.1.2}/setup.py +6 -6
- osiris_utils-1.0.9/osiris_utils/__init__.py +0 -6
- osiris_utils-1.0.9/osiris_utils/data.py +0 -477
- osiris_utils-1.0.9/osiris_utils/data_readers.py +0 -119
- osiris_utils-1.0.9/osiris_utils/gui.py +0 -266
- osiris_utils-1.0.9/osiris_utils/mean_field_theory.py +0 -52
- {osiris_utils-1.0.9 → osiris_utils-1.1.2}/LICENSE.txt +0 -0
- {osiris_utils-1.0.9 → osiris_utils-1.1.2}/MANIFEST.in +0 -0
- {osiris_utils-1.0.9 → osiris_utils-1.1.2}/README.rst +0 -0
- {osiris_utils-1.0.9 → osiris_utils-1.1.2}/osiris_utils.egg-info/dependency_links.txt +0 -0
- {osiris_utils-1.0.9 → osiris_utils-1.1.2}/osiris_utils.egg-info/requires.txt +0 -0
- {osiris_utils-1.0.9 → osiris_utils-1.1.2}/osiris_utils.egg-info/top_level.txt +0 -0
- {osiris_utils-1.0.9 → osiris_utils-1.1.2}/pyproject.toml +0 -0
- {osiris_utils-1.0.9 → osiris_utils-1.1.2}/requirements.txt +0 -0
- {osiris_utils-1.0.9 → osiris_utils-1.1.2}/setup.cfg +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: osiris_utils
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.1.2
|
|
4
4
|
Summary: Utilities to manipulate and visualize OSIRIS framework output data
|
|
5
|
-
Author: ['João Pedro Ferreira Biu', 'João Cândido']
|
|
5
|
+
Author: ['João Pedro Ferreira Biu', 'João Cândido', 'Diogo Carvalho']
|
|
6
6
|
Author-email: ['joaopedrofbiu@tecnico.ulisboa.pt']
|
|
7
7
|
License: MIT
|
|
8
8
|
Project-URL: Issues Tracker, https://github.com/joaopedrobiu6/osiris_utils/issues
|
|
@@ -20,7 +20,7 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
20
20
|
Classifier: Programming Language :: Python :: 3.12
|
|
21
21
|
Classifier: Topic :: Scientific/Engineering
|
|
22
22
|
Requires-Python: >=3.11
|
|
23
|
-
Description-Content-Type: text/
|
|
23
|
+
Description-Content-Type: text/x-rst
|
|
24
24
|
License-File: LICENSE.txt
|
|
25
25
|
Requires-Dist: numpy
|
|
26
26
|
Requires-Dist: matplotlib
|
|
@@ -33,10 +33,39 @@ Requires-Dist: tqdm
|
|
|
33
33
|
Dynamic: author
|
|
34
34
|
Dynamic: author-email
|
|
35
35
|
Dynamic: classifier
|
|
36
|
+
Dynamic: description
|
|
36
37
|
Dynamic: description-content-type
|
|
37
38
|
Dynamic: keywords
|
|
38
39
|
Dynamic: license
|
|
40
|
+
Dynamic: license-file
|
|
39
41
|
Dynamic: project-url
|
|
40
42
|
Dynamic: requires-dist
|
|
41
43
|
Dynamic: requires-python
|
|
42
44
|
Dynamic: summary
|
|
45
|
+
|
|
46
|
+
OSIRIS_UTILS
|
|
47
|
+
============
|
|
48
|
+
|Pypi|
|
|
49
|
+
|
|
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
|
+
|
|
52
|
+
How to install it?
|
|
53
|
+
------------------
|
|
54
|
+
|
|
55
|
+
To install this package, you can use `pip`::
|
|
56
|
+
|
|
57
|
+
pip install osiris_utils
|
|
58
|
+
|
|
59
|
+
To install it from source, you can clone this repository and run (in the folder containing ``setup.py``)::
|
|
60
|
+
|
|
61
|
+
pip install -e .
|
|
62
|
+
|
|
63
|
+
Documentation
|
|
64
|
+
-------------
|
|
65
|
+
|
|
66
|
+
The documentation is available at https://osiris-utils.readthedocs.io or via this link: `osiris-utils.readthedocs.io <https://osiris-utils.readthedocs.io>`_.
|
|
67
|
+
|
|
68
|
+
.. |Pypi| image:: https://img.shields.io/pypi/v/osiris-utils
|
|
69
|
+
:target: https://pypi.org/project/osiris-utils/
|
|
70
|
+
:alt: Pypi
|
|
71
|
+
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from .utils import (time_estimation, filesize_estimation, transverse_average, integrate, animate_2D,
|
|
2
|
+
save_data, read_data, courant2D)
|
|
3
|
+
from .gui.gui import LAVA_Qt, LAVA
|
|
4
|
+
from .data.data import OsirisGridFile, OsirisRawFile, OsirisData, OsirisHIST
|
|
5
|
+
from .data.simulation import Simulation
|
|
6
|
+
from .data.diagnostic import Diagnostic
|
|
7
|
+
|
|
8
|
+
from .postprocessing.postprocess import PostProcess
|
|
9
|
+
from .postprocessing.derivative import Derivative, Derivative_Diagnostic
|
|
10
|
+
from .postprocessing.fft import FFT_Diagnostic, FastFourierTransform
|
|
11
|
+
|
|
12
|
+
from .postprocessing.mean_field_theory_single import MFT_Single
|
|
13
|
+
from .postprocessing.mean_field_theory import MeanFieldTheory_Diagnostic
|
|
14
|
+
|
|
15
|
+
# true div not working because of rtruediv - division is not commutative
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: osiris_utils
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.1.2
|
|
4
4
|
Summary: Utilities to manipulate and visualize OSIRIS framework output data
|
|
5
|
-
Author: ['João Pedro Ferreira Biu', 'João Cândido']
|
|
5
|
+
Author: ['João Pedro Ferreira Biu', 'João Cândido', 'Diogo Carvalho']
|
|
6
6
|
Author-email: ['joaopedrofbiu@tecnico.ulisboa.pt']
|
|
7
7
|
License: MIT
|
|
8
8
|
Project-URL: Issues Tracker, https://github.com/joaopedrobiu6/osiris_utils/issues
|
|
@@ -20,7 +20,7 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
20
20
|
Classifier: Programming Language :: Python :: 3.12
|
|
21
21
|
Classifier: Topic :: Scientific/Engineering
|
|
22
22
|
Requires-Python: >=3.11
|
|
23
|
-
Description-Content-Type: text/
|
|
23
|
+
Description-Content-Type: text/x-rst
|
|
24
24
|
License-File: LICENSE.txt
|
|
25
25
|
Requires-Dist: numpy
|
|
26
26
|
Requires-Dist: matplotlib
|
|
@@ -33,10 +33,39 @@ Requires-Dist: tqdm
|
|
|
33
33
|
Dynamic: author
|
|
34
34
|
Dynamic: author-email
|
|
35
35
|
Dynamic: classifier
|
|
36
|
+
Dynamic: description
|
|
36
37
|
Dynamic: description-content-type
|
|
37
38
|
Dynamic: keywords
|
|
38
39
|
Dynamic: license
|
|
40
|
+
Dynamic: license-file
|
|
39
41
|
Dynamic: project-url
|
|
40
42
|
Dynamic: requires-dist
|
|
41
43
|
Dynamic: requires-python
|
|
42
44
|
Dynamic: summary
|
|
45
|
+
|
|
46
|
+
OSIRIS_UTILS
|
|
47
|
+
============
|
|
48
|
+
|Pypi|
|
|
49
|
+
|
|
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
|
+
|
|
52
|
+
How to install it?
|
|
53
|
+
------------------
|
|
54
|
+
|
|
55
|
+
To install this package, you can use `pip`::
|
|
56
|
+
|
|
57
|
+
pip install osiris_utils
|
|
58
|
+
|
|
59
|
+
To install it from source, you can clone this repository and run (in the folder containing ``setup.py``)::
|
|
60
|
+
|
|
61
|
+
pip install -e .
|
|
62
|
+
|
|
63
|
+
Documentation
|
|
64
|
+
-------------
|
|
65
|
+
|
|
66
|
+
The documentation is available at https://osiris-utils.readthedocs.io or via this link: `osiris-utils.readthedocs.io <https://osiris-utils.readthedocs.io>`_.
|
|
67
|
+
|
|
68
|
+
.. |Pypi| image:: https://img.shields.io/pypi/v/osiris-utils
|
|
69
|
+
:target: https://pypi.org/project/osiris-utils/
|
|
70
|
+
:alt: Pypi
|
|
71
|
+
|
|
@@ -5,10 +5,6 @@ pyproject.toml
|
|
|
5
5
|
requirements.txt
|
|
6
6
|
setup.py
|
|
7
7
|
osiris_utils/__init__.py
|
|
8
|
-
osiris_utils/data.py
|
|
9
|
-
osiris_utils/data_readers.py
|
|
10
|
-
osiris_utils/gui.py
|
|
11
|
-
osiris_utils/mean_field_theory.py
|
|
12
8
|
osiris_utils/utils.py
|
|
13
9
|
osiris_utils.egg-info/PKG-INFO
|
|
14
10
|
osiris_utils.egg-info/SOURCES.txt
|
|
@@ -7,19 +7,19 @@ from setuptools import find_packages, setup
|
|
|
7
7
|
here = os.path.abspath(os.path.dirname(__file__))
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
with open(os.path.join(here, 'README.rst'), encoding='utf-8') as f:
|
|
11
|
+
long_description = f.read()
|
|
12
12
|
|
|
13
13
|
with open(os.path.join(here, 'requirements.txt'), encoding='utf-8') as f:
|
|
14
14
|
requirements = f.read().splitlines()
|
|
15
15
|
|
|
16
16
|
setup(
|
|
17
17
|
name='osiris_utils',
|
|
18
|
-
version='v1.
|
|
18
|
+
version='v1.1.2',
|
|
19
19
|
description=('Utilities to manipulate and visualize OSIRIS framework output data'),
|
|
20
|
-
|
|
21
|
-
long_description_content_type='text/
|
|
22
|
-
author=['João Pedro Ferreira Biu', 'João Cândido'],
|
|
20
|
+
long_description=long_description,
|
|
21
|
+
long_description_content_type='text/x-rst',
|
|
22
|
+
author=['João Pedro Ferreira Biu', 'João Cândido', 'Diogo Carvalho'],
|
|
23
23
|
author_email=['joaopedrofbiu@tecnico.ulisboa.pt'],
|
|
24
24
|
license='MIT',
|
|
25
25
|
classifiers=[
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
from .utils import (time_estimation, filesize_estimation, transverse_average, integrate, animate_2D,
|
|
2
|
-
save_data, read_data, courant2D)
|
|
3
|
-
from .data_readers import open1D, open2D, open3D, read_osiris_file
|
|
4
|
-
from .gui import LAVA_Qt, LAVA
|
|
5
|
-
from .data import OsirisGridFile, OsirisRawFile, OsirisData
|
|
6
|
-
from .mean_field_theory import MeanFieldTheory
|
|
@@ -1,477 +0,0 @@
|
|
|
1
|
-
import numpy as np
|
|
2
|
-
import h5py
|
|
3
|
-
|
|
4
|
-
class OsirisData():
|
|
5
|
-
'''
|
|
6
|
-
Parent class for Osiris data files.
|
|
7
|
-
|
|
8
|
-
Input:
|
|
9
|
-
------
|
|
10
|
-
- filename: the path to the HDF5 file
|
|
11
|
-
Attributes:
|
|
12
|
-
----------
|
|
13
|
-
- filename - the path to the HDF5 file
|
|
14
|
-
str
|
|
15
|
-
- file - the HDF5 file
|
|
16
|
-
h5py.File
|
|
17
|
-
- verbose - if True, the class will print messages
|
|
18
|
-
bool
|
|
19
|
-
- dt - the time step
|
|
20
|
-
float
|
|
21
|
-
- dim - the number of dimensions
|
|
22
|
-
int
|
|
23
|
-
- time - the time and its units
|
|
24
|
-
list [time, units]
|
|
25
|
-
list [float, str]
|
|
26
|
-
- iter - the iteration number
|
|
27
|
-
int
|
|
28
|
-
- name - the name of the data
|
|
29
|
-
str
|
|
30
|
-
- type - the type of data
|
|
31
|
-
str
|
|
32
|
-
'''
|
|
33
|
-
def __init__(self, filename):
|
|
34
|
-
self._filename = filename
|
|
35
|
-
self._file = None
|
|
36
|
-
|
|
37
|
-
self._verbose = False
|
|
38
|
-
|
|
39
|
-
self._open_file(self._filename)
|
|
40
|
-
self._load_basic_attributes(self._file)
|
|
41
|
-
|
|
42
|
-
def _load_basic_attributes(self, f: h5py.File) -> None:
|
|
43
|
-
'''Load common attributes from HDF5 file'''
|
|
44
|
-
self._dt = float(f['SIMULATION'].attrs['DT'][0])
|
|
45
|
-
self._dim = int(f['SIMULATION'].attrs['NDIMS'][0])
|
|
46
|
-
self._time = [float(f.attrs['TIME'][0]), f.attrs['TIME UNITS'][0].decode('utf-8')]
|
|
47
|
-
self._iter = int(f.attrs['ITER'][0])
|
|
48
|
-
self._name = f.attrs['NAME'][0].decode('utf-8')
|
|
49
|
-
self._type = f.attrs['TYPE'][0].decode('utf-8')
|
|
50
|
-
|
|
51
|
-
def verbose(self, verbose: bool = True):
|
|
52
|
-
'''
|
|
53
|
-
Set the verbosity of the class
|
|
54
|
-
|
|
55
|
-
Parameters
|
|
56
|
-
----------
|
|
57
|
-
verbose : bool, optional
|
|
58
|
-
If True, the class will print messages, by default True when calling (False when not calling)
|
|
59
|
-
'''
|
|
60
|
-
self._verbose = verbose
|
|
61
|
-
|
|
62
|
-
def _open_file(self, filename):
|
|
63
|
-
'''
|
|
64
|
-
Open the HDF5 file.
|
|
65
|
-
|
|
66
|
-
Parameters
|
|
67
|
-
----------
|
|
68
|
-
filename : str
|
|
69
|
-
The path to the HDF5 file.
|
|
70
|
-
'''
|
|
71
|
-
if self._verbose: print(f'Opening file > {filename}')
|
|
72
|
-
self._file = h5py.File(self._filename, 'r')
|
|
73
|
-
|
|
74
|
-
def _close_file(self):
|
|
75
|
-
'''
|
|
76
|
-
Close the HDF5 file.
|
|
77
|
-
'''
|
|
78
|
-
if self._verbose: print('Closing file')
|
|
79
|
-
if self._file:
|
|
80
|
-
self._file.close()
|
|
81
|
-
|
|
82
|
-
@property
|
|
83
|
-
def dt(self):
|
|
84
|
-
'''
|
|
85
|
-
Returns
|
|
86
|
-
-------
|
|
87
|
-
float
|
|
88
|
-
The time step
|
|
89
|
-
'''
|
|
90
|
-
return self._dt
|
|
91
|
-
@property
|
|
92
|
-
def dim(self):
|
|
93
|
-
'''
|
|
94
|
-
Returns
|
|
95
|
-
-------
|
|
96
|
-
int
|
|
97
|
-
The number of dimensions
|
|
98
|
-
'''
|
|
99
|
-
return self._dim
|
|
100
|
-
@property
|
|
101
|
-
def time(self):
|
|
102
|
-
'''
|
|
103
|
-
Returns
|
|
104
|
-
-------
|
|
105
|
-
list
|
|
106
|
-
The time and its units
|
|
107
|
-
'''
|
|
108
|
-
return self._time
|
|
109
|
-
@property
|
|
110
|
-
def iter(self):
|
|
111
|
-
'''
|
|
112
|
-
Returns
|
|
113
|
-
-------
|
|
114
|
-
int
|
|
115
|
-
The iteration number
|
|
116
|
-
'''
|
|
117
|
-
return self._iter
|
|
118
|
-
@property
|
|
119
|
-
def name(self):
|
|
120
|
-
'''
|
|
121
|
-
Returns
|
|
122
|
-
-------
|
|
123
|
-
str
|
|
124
|
-
The name of the data
|
|
125
|
-
'''
|
|
126
|
-
return self._name
|
|
127
|
-
@property
|
|
128
|
-
def type(self):
|
|
129
|
-
'''
|
|
130
|
-
Returns
|
|
131
|
-
-------
|
|
132
|
-
str
|
|
133
|
-
The type of data
|
|
134
|
-
'''
|
|
135
|
-
return self._type
|
|
136
|
-
|
|
137
|
-
class OsirisGridFile(OsirisData):
|
|
138
|
-
'''
|
|
139
|
-
Class to read the grid data from an OSIRIS HDF5 file.
|
|
140
|
-
|
|
141
|
-
Input:
|
|
142
|
-
-----
|
|
143
|
-
- filename: the path to the HDF5 file
|
|
144
|
-
|
|
145
|
-
Attributes:
|
|
146
|
-
----------
|
|
147
|
-
- filename - the path to the HDF5 file
|
|
148
|
-
str
|
|
149
|
-
- file - the HDF5 file
|
|
150
|
-
h5py.File
|
|
151
|
-
- verbose - if True, the class will print messages
|
|
152
|
-
bool
|
|
153
|
-
- dt - the time step
|
|
154
|
-
float
|
|
155
|
-
- dim - the number of dimensions
|
|
156
|
-
int
|
|
157
|
-
- time - the time and its units
|
|
158
|
-
list [time, units]
|
|
159
|
-
list [float, str]
|
|
160
|
-
- iter - the iteration number
|
|
161
|
-
int
|
|
162
|
-
- name - the name of the data
|
|
163
|
-
str
|
|
164
|
-
- type - the type of data
|
|
165
|
-
str
|
|
166
|
-
- grid - the grid data ((x1.min, x1.max), (x2.min, x2.max), (x3.min, x3.max))
|
|
167
|
-
numpy.ndarray
|
|
168
|
-
- nx - the number of grid points (nx1, nx2, nx3)
|
|
169
|
-
numpy.ndarray
|
|
170
|
-
- dx - the grid spacing (dx1, dx2, dx3)
|
|
171
|
-
numpy.ndarray
|
|
172
|
-
- axis - the axis data [(name_x1, units_x1, long_name_x1, type_x1), ...]
|
|
173
|
-
list of dictionaries
|
|
174
|
-
- data: the data (numpy array) with shape (nx1, nx2, nx3) (Transpose to use `plt.imshow`)
|
|
175
|
-
numpy.ndarray
|
|
176
|
-
- units - the units of the data
|
|
177
|
-
str
|
|
178
|
-
- label - the label of the data (LaTeX formatted)
|
|
179
|
-
|
|
180
|
-
'''
|
|
181
|
-
def __init__(self, filename):
|
|
182
|
-
super().__init__(filename)
|
|
183
|
-
|
|
184
|
-
variable_key = self._get_variable_key(self._file)
|
|
185
|
-
|
|
186
|
-
self._units = self._file.attrs['UNITS'][0].decode('utf-8')
|
|
187
|
-
self._label = self._file.attrs['LABEL'][0].decode('utf-8')
|
|
188
|
-
self._FFTdata = None
|
|
189
|
-
|
|
190
|
-
data = np.array(self._file[variable_key][:])
|
|
191
|
-
|
|
192
|
-
axis = list(self._file['AXIS'].keys())
|
|
193
|
-
if len(axis) == 1:
|
|
194
|
-
self._grid = self._file['AXIS/' + axis[0]][()]
|
|
195
|
-
self._nx = len(data)
|
|
196
|
-
self._dx = (self.grid[1] - self.grid[0] ) / self.nx
|
|
197
|
-
self._x = np.arange(self.grid[0], self.grid[1], self.dx)
|
|
198
|
-
else:
|
|
199
|
-
grid = []
|
|
200
|
-
for ax in axis: grid.append(self._file['AXIS/' + ax][()])
|
|
201
|
-
self._grid = np.array(grid)
|
|
202
|
-
self._nx = self._file[variable_key][()].transpose().shape
|
|
203
|
-
self._dx = (self.grid[:, 1] - self.grid[:, 0])/self.nx
|
|
204
|
-
self._x = [np.arange(self.grid[i, 0], self.grid[i, 1], self.dx[i]) for i in range(self.dim)]
|
|
205
|
-
|
|
206
|
-
self._axis = []
|
|
207
|
-
for ax in axis:
|
|
208
|
-
axis_data = {
|
|
209
|
-
'name': self._file['AXIS/'+ax].attrs['NAME'][0].decode('utf-8'),
|
|
210
|
-
'units': self._file['AXIS/'+ax].attrs['UNITS'][0].decode('utf-8'),
|
|
211
|
-
'long_name': self._file['AXIS/'+ax].attrs['LONG_NAME'][0].decode('utf-8'),
|
|
212
|
-
'type': self._file['AXIS/'+ax].attrs['TYPE'][0].decode('utf-8'),
|
|
213
|
-
'plot_label': rf'${self._file["AXIS/"+ax].attrs["LONG_NAME"][0].decode("utf-8")}$ $[{self._file["AXIS/"+ax].attrs["UNITS"][0].decode("utf-8")}]$',
|
|
214
|
-
}
|
|
215
|
-
self._axis.append(axis_data)
|
|
216
|
-
|
|
217
|
-
self._data = np.ascontiguousarray(data.T)
|
|
218
|
-
|
|
219
|
-
self._close_file()
|
|
220
|
-
|
|
221
|
-
def _load_basic_attributes(self, f: h5py.File) -> None:
|
|
222
|
-
'''Load common attributes from HDF5 file'''
|
|
223
|
-
self._dt = float(f['SIMULATION'].attrs['DT'][0])
|
|
224
|
-
self._dim = int(f['SIMULATION'].attrs['NDIMS'][0])
|
|
225
|
-
self._time = [float(f.attrs['TIME'][0]), f.attrs['TIME UNITS'][0].decode('utf-8')]
|
|
226
|
-
self._iter = int(f.attrs['ITER'][0])
|
|
227
|
-
self._name = f.attrs['NAME'][0].decode('utf-8')
|
|
228
|
-
self._type = f.attrs['TYPE'][0].decode('utf-8')
|
|
229
|
-
|
|
230
|
-
def _get_variable_key(self, f: h5py.File) -> str:
|
|
231
|
-
return next(k for k in f.keys() if k not in {'AXIS', 'SIMULATION'})
|
|
232
|
-
|
|
233
|
-
# Getters
|
|
234
|
-
@property
|
|
235
|
-
def grid(self):
|
|
236
|
-
'''
|
|
237
|
-
Returns
|
|
238
|
-
-------
|
|
239
|
-
numpy.ndarray
|
|
240
|
-
The grid data ((x1.min, x1.max), (x2.min, x2.max), (x3.min, x3.max
|
|
241
|
-
'''
|
|
242
|
-
return self._grid
|
|
243
|
-
@property
|
|
244
|
-
def nx(self):
|
|
245
|
-
'''
|
|
246
|
-
Returns
|
|
247
|
-
-------
|
|
248
|
-
numpy.ndarray
|
|
249
|
-
The number of grid points (nx1, nx2, nx3)
|
|
250
|
-
'''
|
|
251
|
-
return self._nx
|
|
252
|
-
@property
|
|
253
|
-
def dx(self):
|
|
254
|
-
'''
|
|
255
|
-
Returns
|
|
256
|
-
-------
|
|
257
|
-
numpy.ndarray
|
|
258
|
-
The grid spacing (dx1, dx2, dx3)
|
|
259
|
-
'''
|
|
260
|
-
return self._dx
|
|
261
|
-
@property
|
|
262
|
-
def x(self):
|
|
263
|
-
'''
|
|
264
|
-
Returns
|
|
265
|
-
-------
|
|
266
|
-
numpy.ndarray
|
|
267
|
-
The grid points in each axis
|
|
268
|
-
'''
|
|
269
|
-
return self._x
|
|
270
|
-
@property
|
|
271
|
-
def axis(self):
|
|
272
|
-
'''
|
|
273
|
-
Returns
|
|
274
|
-
-------
|
|
275
|
-
list of dictionaries
|
|
276
|
-
The axis data [(name_x1, units_x1, long_name_x1, type_x1), ...]
|
|
277
|
-
'''
|
|
278
|
-
return self._axis
|
|
279
|
-
@property
|
|
280
|
-
def data(self):
|
|
281
|
-
'''
|
|
282
|
-
Returns
|
|
283
|
-
-------
|
|
284
|
-
numpy.ndarray
|
|
285
|
-
The data (numpy array) with shape (nx1, nx2, nx3) (Transpose to use `plt.imshow`)
|
|
286
|
-
'''
|
|
287
|
-
return self._data
|
|
288
|
-
@property
|
|
289
|
-
def units(self):
|
|
290
|
-
'''
|
|
291
|
-
Returns
|
|
292
|
-
-------
|
|
293
|
-
str
|
|
294
|
-
The units of the data (LaTeX formatted)
|
|
295
|
-
'''
|
|
296
|
-
return self._units
|
|
297
|
-
@property
|
|
298
|
-
def label(self):
|
|
299
|
-
'''
|
|
300
|
-
Returns
|
|
301
|
-
-------
|
|
302
|
-
str
|
|
303
|
-
The label of the data (LaTeX formatted)
|
|
304
|
-
'''
|
|
305
|
-
return self._label
|
|
306
|
-
@property
|
|
307
|
-
def FFTdata(self):
|
|
308
|
-
'''
|
|
309
|
-
Returns
|
|
310
|
-
-------
|
|
311
|
-
numpy.ndarray
|
|
312
|
-
The FFT of the data
|
|
313
|
-
'''
|
|
314
|
-
if self._FFTdata is None:
|
|
315
|
-
raise ValueError('The FFT of the data has not been computed yet. Compute it using the FFT method.')
|
|
316
|
-
return self._FFTdata
|
|
317
|
-
# Setters
|
|
318
|
-
@data.setter
|
|
319
|
-
def data(self, data):
|
|
320
|
-
'''
|
|
321
|
-
Set the data attribute
|
|
322
|
-
'''
|
|
323
|
-
self._data = data
|
|
324
|
-
|
|
325
|
-
def __str__(self):
|
|
326
|
-
# write me a template to print with the name, label, units, time, iter, grid, nx, dx, axis, dt, dim in a logical way
|
|
327
|
-
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'
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
def __array__(self):
|
|
331
|
-
return np.asarray(self.data)
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
def _yeeToCellCorner1d(self, boundary):
|
|
335
|
-
'''
|
|
336
|
-
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])
|
|
337
|
-
'''
|
|
338
|
-
|
|
339
|
-
if self.name.lower() in ['b2', 'b3', 'e1']:
|
|
340
|
-
if boundary == 'periodic': return 0.5 * (np.roll(self.data, shift=1) + self.data)
|
|
341
|
-
else: return 0.5 * (self.data[1:] + self.data[:-1])
|
|
342
|
-
elif self.name.lower() in ['b1', 'e2', 'e3']:
|
|
343
|
-
if boundary == 'periodic': return self.data
|
|
344
|
-
else: return self.data[1:]
|
|
345
|
-
else:
|
|
346
|
-
raise TypeError(f'This method expects magnetic or electric field grid data but received \'{self.name}\' instead')
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
def _yeeToCellCorner2d(self, boundary):
|
|
350
|
-
'''
|
|
351
|
-
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])
|
|
352
|
-
'''
|
|
353
|
-
|
|
354
|
-
if self.name.lower() in ['e1', 'b2']:
|
|
355
|
-
if boundary == 'periodic': return 0.5 * (np.roll(self.data, shift=1, axis=0) + self.data)
|
|
356
|
-
else: return 0.5 * (self.data[1:, 1:] + self.data[:-1, 1:])
|
|
357
|
-
elif self.name.lower() in ['e2', 'b1']:
|
|
358
|
-
if boundary == 'periodic': return 0.5 * (np.roll(self.data, shift=1, axis=1) + self.data)
|
|
359
|
-
else: return 0.5 * (self.data[1:, 1:] + self.data[1:, :-1])
|
|
360
|
-
elif self.name.lower() in ['b3']:
|
|
361
|
-
if boundary == 'periodic':
|
|
362
|
-
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)))
|
|
363
|
-
else:
|
|
364
|
-
return 0.25 * (self.data[1:, 1:] + self.data[:-1, 1:] + self.data[1:, :-1] + self.data[:-1, :-1])
|
|
365
|
-
elif self.name.lower() in ['e3']:
|
|
366
|
-
if boundary == 'periodic': return self.data
|
|
367
|
-
else: return self.data[1:, 1:]
|
|
368
|
-
else:
|
|
369
|
-
raise TypeError(f'This method expects magnetic or electric field grid data but received \'{self.name}\' instead')
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
def _yeeToCellCorner3d(self, boundary):
|
|
373
|
-
'''
|
|
374
|
-
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])
|
|
375
|
-
'''
|
|
376
|
-
if boundary == 'periodic':
|
|
377
|
-
raise ValueError('Centering field from 3D simulations considering periodic boundary conditions is not implemented yet')
|
|
378
|
-
if self.name.lower() == 'b1':
|
|
379
|
-
return 0.25 * (self.data[1:, 1:, 1:] + self.data[1:, :-1, 1:] + self.data[1:, 1:, :-1] + self.data[1:, :-1, :-1])
|
|
380
|
-
elif self.name.lower() == 'b2':
|
|
381
|
-
return 0.25 * (self.data[1:, 1:, 1:] + self.data[:-1, 1:, 1:] + self.data[1:, 1:, :-1] + self.data[:-1, 1:, :-1])
|
|
382
|
-
elif self.name.lower() == 'b3':
|
|
383
|
-
return 0.25 * (self.data[1:, 1:, 1:] + self.data[:-1, 1:, 1:] + self.data[1:, :-1, 1:] + self.data[:-1, :-1, 1:])
|
|
384
|
-
elif self.name.lower() == 'e1':
|
|
385
|
-
return 0.5 * (self.data[1:, 1:, 1:] + self.data[:-1, 1:, 1:])
|
|
386
|
-
elif self.name.lower() == 'e2':
|
|
387
|
-
return 0.5 * (self.data[1:, 1:, 1:] + self.data[1:, :-1, 1:])
|
|
388
|
-
elif self.name.lower() == 'e3':
|
|
389
|
-
return 0.5 * (self.data[1:, 1:, 1:] + self.data[1:, 1:, :-1])
|
|
390
|
-
else:
|
|
391
|
-
raise TypeError(f'This method expects magnetic or electric field grid data but received \'{self.name}\' instead')
|
|
392
|
-
|
|
393
|
-
def yeeToCellCorner(self, boundary=None):
|
|
394
|
-
''''
|
|
395
|
-
Converts EM fields from a staggered Yee mesh to a grid with field values centered on the corner of the cell.'
|
|
396
|
-
Can be used for 1D, 2D and 3D simulations.'
|
|
397
|
-
Creates a new attribute `data_centered` with the centered data.'
|
|
398
|
-
'''
|
|
399
|
-
|
|
400
|
-
cases = {'b1', 'b2', 'b3', 'e1', 'e2', 'e3'}
|
|
401
|
-
if self.name not in cases:
|
|
402
|
-
raise TypeError(f'This method expects magnetic or electric field grid data but received \'{self.name}\' instead')
|
|
403
|
-
|
|
404
|
-
if self.dim == 1:
|
|
405
|
-
self.data_centered = self._yeeToCellCorner1d(boundary)
|
|
406
|
-
return self.data_centered
|
|
407
|
-
elif self.dim == 2:
|
|
408
|
-
self.data_centered = self._yeeToCellCorner2d(boundary)
|
|
409
|
-
return self.data_centered
|
|
410
|
-
elif self.dim == 3:
|
|
411
|
-
self.data_centered = self._yeeToCellCorner3d(boundary)
|
|
412
|
-
return self.data_centered
|
|
413
|
-
else:
|
|
414
|
-
raise ValueError(f'Dimension {self.dim} is not supported')
|
|
415
|
-
|
|
416
|
-
def FFT(self, axis=(0, )):
|
|
417
|
-
'''
|
|
418
|
-
Computes the Fast Fourier Transform of the data along the specified axis and shifts the zero frequency to the center.
|
|
419
|
-
Transforms the data to the frequency domain. A(x, y, z) -> A(kx, ky, kz)
|
|
420
|
-
'''
|
|
421
|
-
datafft = np.fft.fftn(self.data, axes=axis)
|
|
422
|
-
self._FFTdata = np.fft.fftshift(datafft, axes=axis)
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
class OsirisRawFile(OsirisData):
|
|
427
|
-
'''
|
|
428
|
-
Class to read the raw data from an OSIRIS HDF5 file.
|
|
429
|
-
|
|
430
|
-
Input:
|
|
431
|
-
- filename: the path to the HDF5 file
|
|
432
|
-
|
|
433
|
-
Attributes:
|
|
434
|
-
- axis - a dictionary where each key is a dataset name, and each value is another dictionary containing
|
|
435
|
-
name (str): The name of the quantity (e.g., r'x1', r'ene').
|
|
436
|
-
units (str): The units associated with that dataset in LaTeX (e.g., r'c/\\omega_p', r'm_e c^2').
|
|
437
|
-
long_name (str): The name of the quantity in LaTeX (e.g., r'x_1', r'En2').
|
|
438
|
-
dictionary of dictionaries
|
|
439
|
-
- data - a dictionary where each key is a dataset name, and each value is the data
|
|
440
|
-
dictionary of np.arrays
|
|
441
|
-
- dim - the number of dimensions
|
|
442
|
-
int
|
|
443
|
-
- dt - the time step
|
|
444
|
-
float
|
|
445
|
-
- grid - maximum and minimum coordinates of the box, for each axis
|
|
446
|
-
numpy.ndarray(dim,2)
|
|
447
|
-
- iter - the iteration number
|
|
448
|
-
int
|
|
449
|
-
- name - the name of the species
|
|
450
|
-
str
|
|
451
|
-
- time - the time and its units
|
|
452
|
-
list [time, units]
|
|
453
|
-
list [float, str]
|
|
454
|
-
- type - type of data (particles in the case of raw files)
|
|
455
|
-
str
|
|
456
|
-
|
|
457
|
-
'''
|
|
458
|
-
|
|
459
|
-
def __init__(self, filename):
|
|
460
|
-
super().__init__(filename)
|
|
461
|
-
|
|
462
|
-
self.grid = np.array([self._file['SIMULATION'].attrs['XMIN'], self._file['SIMULATION'].attrs['XMAX']]).T
|
|
463
|
-
|
|
464
|
-
self.data = {}
|
|
465
|
-
self.axis = {}
|
|
466
|
-
for key in self._file.keys():
|
|
467
|
-
if key == 'SIMULATION': continue
|
|
468
|
-
|
|
469
|
-
self.data[key] = np.array(self._file[key][()])
|
|
470
|
-
|
|
471
|
-
idx = np.where(self._file.attrs['QUANTS'] == str(key).encode('utf-8'))
|
|
472
|
-
axis_data = {
|
|
473
|
-
'name': self._file.attrs['QUANTS'][idx][0].decode('utf-8'),
|
|
474
|
-
'units': self._file.attrs['UNITS'][idx][0].decode('utf-8'),
|
|
475
|
-
'long_name': self._file.attrs['LABELS'][idx][0].decode('utf-8'),
|
|
476
|
-
}
|
|
477
|
-
self.axis[key] = axis_data
|
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
'''
|
|
2
|
-
This file contains methods to create datasets to train the neural network.
|
|
3
|
-
'''
|
|
4
|
-
|
|
5
|
-
import numpy as np
|
|
6
|
-
from .utils import *
|
|
7
|
-
import os
|
|
8
|
-
import h5py
|
|
9
|
-
|
|
10
|
-
def read_osiris_file(filename, pressure = False):
|
|
11
|
-
f = h5py.File(filename, 'r+')
|
|
12
|
-
atr = f.attrs
|
|
13
|
-
k = [key for key in f.keys()]
|
|
14
|
-
if 'SIMULATION' in k:
|
|
15
|
-
attrs1 = atr
|
|
16
|
-
attrs2 = f['SIMULATION'].attrs
|
|
17
|
-
attrs = {}
|
|
18
|
-
for i in range(len(attrs1)):
|
|
19
|
-
attrs[[key for key in attrs1][i]] = [value for value in attrs1.values()][i]
|
|
20
|
-
for i in range(len(attrs2)):
|
|
21
|
-
attrs[[key for key in attrs2][i]] = [value for value in attrs2.values()][i]
|
|
22
|
-
ax = f.get([key for key in f.keys()][0])
|
|
23
|
-
leanx = len(ax)
|
|
24
|
-
axis = []
|
|
25
|
-
for i in range(leanx):
|
|
26
|
-
axis.append(ax.get([key for key in ax.keys()][i]))
|
|
27
|
-
if 'SIMULATION' in k and pressure == False:
|
|
28
|
-
data = f.get([key for key in f.keys()][2])
|
|
29
|
-
data.attrs['UNITS'] = attrs1['UNITS']
|
|
30
|
-
data.attrs['LONG_NAME'] = attrs1['LABEL']
|
|
31
|
-
elif 'SIMULATION' in k and pressure == True:
|
|
32
|
-
data = f.get([key for key in f.keys()][1])
|
|
33
|
-
data.attrs['UNITS'] = attrs1['UNITS']
|
|
34
|
-
data.attrs['LONG_NAME'] = attrs1['LABEL']
|
|
35
|
-
else:
|
|
36
|
-
data = f.get([key for key in f.keys()][1])
|
|
37
|
-
|
|
38
|
-
return attrs, axis, data
|
|
39
|
-
|
|
40
|
-
def open1D(filename, pressure = False):
|
|
41
|
-
'''
|
|
42
|
-
Open a 1D OSIRIS file and return the x axis and the data array.
|
|
43
|
-
|
|
44
|
-
Parameters
|
|
45
|
-
----------
|
|
46
|
-
filename : str
|
|
47
|
-
The path to the file.
|
|
48
|
-
|
|
49
|
-
Returns
|
|
50
|
-
-------
|
|
51
|
-
x : numpy.ndarray
|
|
52
|
-
The x axis.
|
|
53
|
-
data_array : numpy.ndarray
|
|
54
|
-
The data array.
|
|
55
|
-
'''
|
|
56
|
-
attrs, axes, data = read_osiris_file(filename, pressure)
|
|
57
|
-
datash = data.shape
|
|
58
|
-
ax1 = axes[0]
|
|
59
|
-
x = np.linspace(ax1[0], ax1[1], datash[0])
|
|
60
|
-
data_array = data[:]
|
|
61
|
-
return x, data_array, [attrs, axes, data]
|
|
62
|
-
|
|
63
|
-
def open2D(filename, pressure = False):
|
|
64
|
-
'''
|
|
65
|
-
Open a 2D OSIRIS file and return the x and y axes and the data array.
|
|
66
|
-
|
|
67
|
-
Parameters
|
|
68
|
-
----------
|
|
69
|
-
filename : str
|
|
70
|
-
The path to the file.
|
|
71
|
-
|
|
72
|
-
Returns
|
|
73
|
-
-------
|
|
74
|
-
x : numpy.ndarray
|
|
75
|
-
The x axis.
|
|
76
|
-
y : numpy.ndarray
|
|
77
|
-
The y axis.
|
|
78
|
-
data_array : numpy.ndarray
|
|
79
|
-
The data array.
|
|
80
|
-
'''
|
|
81
|
-
attrs, axes, data = read_osiris_file(filename, pressure)
|
|
82
|
-
datash = data.shape
|
|
83
|
-
ax1 = axes[0]
|
|
84
|
-
ax2 = axes[1]
|
|
85
|
-
x = np.linspace(ax1[0], ax1[1], datash[-1])
|
|
86
|
-
y = np.linspace(ax2[0], ax2[1], datash[-2])
|
|
87
|
-
data_array = data[:]
|
|
88
|
-
return x, y, data_array, [attrs, axes, data]
|
|
89
|
-
|
|
90
|
-
def open3D(filename):
|
|
91
|
-
'''
|
|
92
|
-
Open a 3D OSIRIS file and return the x, y and z axes and the data array.
|
|
93
|
-
|
|
94
|
-
Parameters
|
|
95
|
-
----------
|
|
96
|
-
filename : str
|
|
97
|
-
The path to the file.
|
|
98
|
-
|
|
99
|
-
Returns
|
|
100
|
-
-------
|
|
101
|
-
x : numpy.ndarray
|
|
102
|
-
The x axis.
|
|
103
|
-
y : numpy.ndarray
|
|
104
|
-
The y axis.
|
|
105
|
-
z : numpy.ndarray
|
|
106
|
-
The z axis.
|
|
107
|
-
data_array : numpy.ndarray
|
|
108
|
-
The data array.
|
|
109
|
-
'''
|
|
110
|
-
attrs, axes, data = read_osiris_file(filename)
|
|
111
|
-
datash = data.shape
|
|
112
|
-
ax1 = axes[0]
|
|
113
|
-
ax2 = axes[1]
|
|
114
|
-
ax3 = axes[2]
|
|
115
|
-
x = np.linspace(ax1[0], ax1[1], datash[-1])
|
|
116
|
-
y = np.linspace(ax2[0], ax2[1], datash[-2])
|
|
117
|
-
z = np.linspace(ax3[0], ax3[1], datash[-3])
|
|
118
|
-
data_array = data[:]
|
|
119
|
-
return x, y, z, data_array, [attrs, axes, data]
|
|
@@ -1,266 +0,0 @@
|
|
|
1
|
-
import sys
|
|
2
|
-
import os
|
|
3
|
-
from PySide6.QtWidgets import (QApplication, QMainWindow, QWidget, QPushButton,
|
|
4
|
-
QFileDialog, QMessageBox, QComboBox, QHBoxLayout,
|
|
5
|
-
QVBoxLayout, QLabel, QLineEdit, QFrame, QDoubleSpinBox)
|
|
6
|
-
from PySide6.QtCore import Qt
|
|
7
|
-
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
|
|
8
|
-
import matplotlib.pyplot as plt
|
|
9
|
-
from matplotlib.colors import LogNorm
|
|
10
|
-
import numpy as np
|
|
11
|
-
from .data import OsirisGridFile # Update import as needed
|
|
12
|
-
from .utils import integrate, transverse_average # Update import as needed
|
|
13
|
-
|
|
14
|
-
class LAVA_Qt(QMainWindow):
|
|
15
|
-
def __init__(self):
|
|
16
|
-
super().__init__()
|
|
17
|
-
self.setWindowTitle('LAVA (LabAstro Visualization Assistant) - OSIRIS Data Grid Viewer')
|
|
18
|
-
self.setGeometry(100, 100, 1000, 600)
|
|
19
|
-
|
|
20
|
-
# Initialize data
|
|
21
|
-
self.data_info = None
|
|
22
|
-
self.dims = 0
|
|
23
|
-
self.current_ax = None
|
|
24
|
-
self.current_folder = None
|
|
25
|
-
|
|
26
|
-
# Main widget and layout
|
|
27
|
-
self.main_widget = QWidget()
|
|
28
|
-
self.setCentralWidget(self.main_widget)
|
|
29
|
-
self.main_layout = QVBoxLayout(self.main_widget)
|
|
30
|
-
|
|
31
|
-
# Create UI elements
|
|
32
|
-
self.create_controls()
|
|
33
|
-
self.create_labels_section()
|
|
34
|
-
self.create_plot_area()
|
|
35
|
-
|
|
36
|
-
def create_controls(self):
|
|
37
|
-
# Control buttons frame
|
|
38
|
-
control_frame = QWidget()
|
|
39
|
-
control_layout = QHBoxLayout(control_frame)
|
|
40
|
-
|
|
41
|
-
# Buttons
|
|
42
|
-
self.browse_btn = QPushButton('Browse Folder')
|
|
43
|
-
self.browse_btn.clicked.connect(self.load_folder)
|
|
44
|
-
self.save_btn = QPushButton('Save Plot')
|
|
45
|
-
self.save_btn.clicked.connect(self.save_plot)
|
|
46
|
-
|
|
47
|
-
# File selector
|
|
48
|
-
self.file_selector = QComboBox()
|
|
49
|
-
self.file_selector.setPlaceholderText('Select file...')
|
|
50
|
-
self.file_selector.currentIndexChanged.connect(self.file_selection_changed)
|
|
51
|
-
self.file_selector.view().setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
|
|
52
|
-
self.file_selector.setSizeAdjustPolicy(QComboBox.AdjustToContents)
|
|
53
|
-
|
|
54
|
-
# Plot type combo box
|
|
55
|
-
self.plot_combo = QComboBox()
|
|
56
|
-
self.plot_combo.addItem('Select Plot Type')
|
|
57
|
-
self.plot_combo.currentTextChanged.connect(self.plot_data)
|
|
58
|
-
|
|
59
|
-
control_layout.addWidget(self.browse_btn)
|
|
60
|
-
control_layout.addWidget(self.save_btn)
|
|
61
|
-
control_layout.addWidget(QLabel('Files:'))
|
|
62
|
-
control_layout.addWidget(self.file_selector)
|
|
63
|
-
control_layout.addWidget(QLabel('Plot Type:'))
|
|
64
|
-
control_layout.addWidget(self.plot_combo)
|
|
65
|
-
self.main_layout.addWidget(control_frame)
|
|
66
|
-
|
|
67
|
-
def create_labels_section(self):
|
|
68
|
-
# Labels frame
|
|
69
|
-
labels_frame = QWidget()
|
|
70
|
-
labels_layout = QHBoxLayout(labels_frame)
|
|
71
|
-
|
|
72
|
-
# Title and labels
|
|
73
|
-
self.title_edit = QLineEdit()
|
|
74
|
-
self.xlabel_edit = QLineEdit()
|
|
75
|
-
self.ylabel_edit = QLineEdit()
|
|
76
|
-
|
|
77
|
-
# Connect text changes
|
|
78
|
-
self.title_edit.textChanged.connect(self.update_plot_labels)
|
|
79
|
-
self.xlabel_edit.textChanged.connect(self.update_plot_labels)
|
|
80
|
-
self.ylabel_edit.textChanged.connect(self.update_plot_labels)
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
labels_layout.addWidget(QLabel('Title:'))
|
|
84
|
-
labels_layout.addWidget(self.title_edit)
|
|
85
|
-
labels_layout.addWidget(QLabel('X Label:'))
|
|
86
|
-
labels_layout.addWidget(self.xlabel_edit)
|
|
87
|
-
labels_layout.addWidget(QLabel('Y Label:'))
|
|
88
|
-
labels_layout.addWidget(self.ylabel_edit)
|
|
89
|
-
|
|
90
|
-
# define the size of the labels frame
|
|
91
|
-
self.main_layout.addWidget(labels_frame)
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
def load_folder(self):
|
|
95
|
-
folder_dialog = QFileDialog()
|
|
96
|
-
folderpath = folder_dialog.getExistingDirectory(
|
|
97
|
-
self, 'Select Folder with HDF5 Files'
|
|
98
|
-
)
|
|
99
|
-
|
|
100
|
-
if not folderpath:
|
|
101
|
-
return
|
|
102
|
-
|
|
103
|
-
try:
|
|
104
|
-
self.current_folder = folderpath
|
|
105
|
-
self.file_selector.clear()
|
|
106
|
-
|
|
107
|
-
# Find all .h5 files
|
|
108
|
-
h5_files = [f for f in os.listdir(folderpath) if f.endswith('.h5')]
|
|
109
|
-
# all the files end with xxxxxx.h5 so we can use this to order them by the number
|
|
110
|
-
def sort_key(filename):
|
|
111
|
-
try:
|
|
112
|
-
# Split filename into parts and get the numeric portion
|
|
113
|
-
base = os.path.splitext(filename)[0] # Remove .h5
|
|
114
|
-
numeric_part = base.split('-')[-1] # Get last part after -
|
|
115
|
-
return int(numeric_part)
|
|
116
|
-
except (IndexError, ValueError):
|
|
117
|
-
return 0 # Fallback for malformed filenames
|
|
118
|
-
|
|
119
|
-
h5_files.sort(key=sort_key)
|
|
120
|
-
|
|
121
|
-
if not h5_files:
|
|
122
|
-
raise ValueError('No HDF5 files found in selected folder')
|
|
123
|
-
|
|
124
|
-
self.file_selector.addItems(h5_files)
|
|
125
|
-
self.file_selector.setCurrentIndex(0)
|
|
126
|
-
|
|
127
|
-
except Exception as e:
|
|
128
|
-
QMessageBox.critical(self, 'Error', str(e))
|
|
129
|
-
|
|
130
|
-
def file_selection_changed(self, index):
|
|
131
|
-
'''Handle file selection change in the combo box'''
|
|
132
|
-
if index >= 0 and self.current_folder:
|
|
133
|
-
filename = self.file_selector.itemText(index)
|
|
134
|
-
self.process_file(filename)
|
|
135
|
-
|
|
136
|
-
def process_file(self, filename):
|
|
137
|
-
try:
|
|
138
|
-
filepath = os.path.join(self.current_folder, filename)
|
|
139
|
-
gridfile = OsirisGridFile(filepath)
|
|
140
|
-
self.dims = len(gridfile.axis)
|
|
141
|
-
self.type = gridfile.type
|
|
142
|
-
|
|
143
|
-
if self.type == 'grid':
|
|
144
|
-
if self.dims == 1:
|
|
145
|
-
x = np.arange(gridfile.grid[0], gridfile.grid[1], gridfile.dx)
|
|
146
|
-
self.xlabel_edit.setText(r'$%s$ [$%s$]' % (gridfile.axis[0]['long_name'], gridfile.axis[0]['units']))
|
|
147
|
-
self.ylabel_edit.setText(r'$%s$ [$%s$]' % (gridfile.label, gridfile.units))
|
|
148
|
-
self.data_info = (x, gridfile.data)
|
|
149
|
-
elif self.dims == 2:
|
|
150
|
-
x = np.arange(gridfile.grid[0][0], gridfile.grid[0][1], gridfile.dx[0])
|
|
151
|
-
y = np.arange(gridfile.grid[1][0], gridfile.grid[1][1], gridfile.dx[1])
|
|
152
|
-
self.xlabel_edit.setText(r'$%s$ [$%s$]' % (gridfile.axis[0]['long_name'], gridfile.axis[0]['units']))
|
|
153
|
-
self.ylabel_edit.setText(r'$%s$ [$%s$]' % (gridfile.axis[1]['long_name'], gridfile.axis[1]['units']))
|
|
154
|
-
self.data_info = (x, y, gridfile.data)
|
|
155
|
-
elif self.dims == 3:
|
|
156
|
-
raise ValueError('3D not supported yet')
|
|
157
|
-
else:
|
|
158
|
-
raise ValueError('Unsupported dimensionality')
|
|
159
|
-
|
|
160
|
-
self.title_edit.setText(r'$%s$ [$%s$]' %( gridfile.label, gridfile.units))
|
|
161
|
-
self.update_plot_menu()
|
|
162
|
-
self.plot_data()
|
|
163
|
-
|
|
164
|
-
else:
|
|
165
|
-
QMessageBox.information(self, 'Info', f'{self.type} data not supported yet')
|
|
166
|
-
|
|
167
|
-
except Exception as e:
|
|
168
|
-
QMessageBox.critical(self, 'Error', str(e))
|
|
169
|
-
|
|
170
|
-
def create_plot_area(self):
|
|
171
|
-
# Matplotlib figure and canvas
|
|
172
|
-
self.figure = plt.figure(figsize=(8, 6))
|
|
173
|
-
self.canvas = FigureCanvas(self.figure)
|
|
174
|
-
self.main_layout.addWidget(self.canvas)
|
|
175
|
-
|
|
176
|
-
def update_plot_labels(self):
|
|
177
|
-
if self.current_ax:
|
|
178
|
-
self.current_ax.set_xlabel(self.xlabel_edit.text())
|
|
179
|
-
self.current_ax.set_ylabel(self.ylabel_edit.text())
|
|
180
|
-
self.figure.suptitle(self.title_edit.text())
|
|
181
|
-
self.canvas.draw()
|
|
182
|
-
|
|
183
|
-
def plot_data(self):
|
|
184
|
-
self.figure.clear()
|
|
185
|
-
if self.dims == 1:
|
|
186
|
-
self.plot_1d()
|
|
187
|
-
elif self.dims == 2:
|
|
188
|
-
self.plot_2d()
|
|
189
|
-
self.update_plot_labels()
|
|
190
|
-
self.canvas.draw()
|
|
191
|
-
|
|
192
|
-
def plot_1d(self):
|
|
193
|
-
x, data = self.data_info
|
|
194
|
-
self.current_ax = self.figure.add_subplot(111)
|
|
195
|
-
plot_type = self.plot_combo.currentText()
|
|
196
|
-
|
|
197
|
-
if 'Line' in plot_type:
|
|
198
|
-
self.current_ax.plot(x, data)
|
|
199
|
-
elif 'Scatter' in plot_type:
|
|
200
|
-
self.current_ax.scatter(x, data)
|
|
201
|
-
|
|
202
|
-
self.current_ax.set_xlabel(self.xlabel_edit.text())
|
|
203
|
-
self.current_ax.set_ylabel(self.ylabel_edit.text())
|
|
204
|
-
self.figure.suptitle(self.title_edit.text())
|
|
205
|
-
|
|
206
|
-
def plot_2d(self):
|
|
207
|
-
x, y, data = self.data_info
|
|
208
|
-
self.current_ax = self.figure.add_subplot(111)
|
|
209
|
-
plot_type = self.plot_combo.currentText()
|
|
210
|
-
|
|
211
|
-
if 'Quantity' in plot_type:
|
|
212
|
-
img = self.current_ax.imshow(data.T, extent=(x[0], x[-1], y[0], y[-1]), origin='lower', aspect='auto')
|
|
213
|
-
self.figure.colorbar(img)
|
|
214
|
-
elif 'Integral' in plot_type:
|
|
215
|
-
avg = integrate(transverse_average(data), x[-1]/len(x))
|
|
216
|
-
self.current_ax.plot(x, avg)
|
|
217
|
-
elif 'Transverse' in plot_type:
|
|
218
|
-
avg = transverse_average(data)
|
|
219
|
-
self.current_ax.plot(x, avg)
|
|
220
|
-
elif 'Phase' in plot_type:
|
|
221
|
-
img = self.current_ax.imshow(np.abs(-data.T), extent=(x[0], x[-1], y[0], y[-1]), origin='lower', aspect='auto', norm=LogNorm())
|
|
222
|
-
self.figure.colorbar(img)
|
|
223
|
-
|
|
224
|
-
self.current_ax.set_xlabel(self.xlabel_edit.text())
|
|
225
|
-
self.current_ax.set_ylabel(self.ylabel_edit.text())
|
|
226
|
-
self.figure.suptitle(self.title_edit.text())
|
|
227
|
-
|
|
228
|
-
def update_plot_menu(self):
|
|
229
|
-
|
|
230
|
-
# Save current plot type before clearing
|
|
231
|
-
current_plot_type = self.plot_combo.currentText()
|
|
232
|
-
self.plot_combo.clear()
|
|
233
|
-
|
|
234
|
-
# Determine items based on dimensions
|
|
235
|
-
if self.dims == 1:
|
|
236
|
-
items = ['Line Plot', 'Scatter Plot']
|
|
237
|
-
elif self.dims == 2:
|
|
238
|
-
items = ['Quantity Plot', 'T. Average Integral', 'Transverse Average', 'Phase Space']
|
|
239
|
-
else:
|
|
240
|
-
items = []
|
|
241
|
-
|
|
242
|
-
self.plot_combo.addItems(items)
|
|
243
|
-
|
|
244
|
-
# Restore previous selection if possible
|
|
245
|
-
if current_plot_type in items:
|
|
246
|
-
self.plot_combo.setCurrentText(current_plot_type)
|
|
247
|
-
else:
|
|
248
|
-
self.plot_combo.setCurrentIndex(0 if items else -1)
|
|
249
|
-
|
|
250
|
-
def save_plot(self):
|
|
251
|
-
file_dialog = QFileDialog()
|
|
252
|
-
filepath, _ = file_dialog.getSaveFileName(
|
|
253
|
-
self, 'Save Plot', '', 'PNG Files (*.png);;PDF Files (*.pdf)'
|
|
254
|
-
)
|
|
255
|
-
|
|
256
|
-
if filepath:
|
|
257
|
-
self.figure.savefig(filepath, dpi=800, bbox_inches='tight')
|
|
258
|
-
|
|
259
|
-
def LAVA():
|
|
260
|
-
app = QApplication(sys.argv)
|
|
261
|
-
window = LAVA_Qt()
|
|
262
|
-
window.show()
|
|
263
|
-
sys.exit(app.exec())
|
|
264
|
-
|
|
265
|
-
if __name__ == '__main__':
|
|
266
|
-
LAVA()
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import numpy as np
|
|
2
|
-
from .data import OsirisGridFile
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
class MeanFieldTheory(OsirisGridFile):
|
|
6
|
-
'''
|
|
7
|
-
Class to handle the mean field theory on data. Inherits from OsirisGridFile.
|
|
8
|
-
|
|
9
|
-
Parameters
|
|
10
|
-
----------
|
|
11
|
-
source : str or OsirisGridFile
|
|
12
|
-
The filename or an OsirisGridFile object.
|
|
13
|
-
axis : int
|
|
14
|
-
The axis to average over.
|
|
15
|
-
'''
|
|
16
|
-
def __init__(self, source, axis=1):
|
|
17
|
-
if isinstance(source, OsirisGridFile):
|
|
18
|
-
self.__dict__.update(source.__dict__)
|
|
19
|
-
else:
|
|
20
|
-
super().__init__(source)
|
|
21
|
-
self._compute_mean_field(axis=axis)
|
|
22
|
-
|
|
23
|
-
def _compute_mean_field(self, axis=1):
|
|
24
|
-
self._average = np.expand_dims(np.mean(self.data, axis=axis), axis=axis)
|
|
25
|
-
self._fluctuations = self.data - self._average
|
|
26
|
-
|
|
27
|
-
def __array__(self):
|
|
28
|
-
return self.data
|
|
29
|
-
|
|
30
|
-
@property
|
|
31
|
-
def average(self):
|
|
32
|
-
return self._average
|
|
33
|
-
|
|
34
|
-
@property
|
|
35
|
-
def delta(self):
|
|
36
|
-
return self._fluctuations
|
|
37
|
-
|
|
38
|
-
def __str__(self):
|
|
39
|
-
return super().__str__() + f'\nAverage: {self.average.shape}\nDelta: {self.delta.shape}'
|
|
40
|
-
|
|
41
|
-
def derivative(self, field, axis=0):
|
|
42
|
-
'''
|
|
43
|
-
Compute the derivative of the average or the fluctuations.
|
|
44
|
-
|
|
45
|
-
Parameters
|
|
46
|
-
----------
|
|
47
|
-
field : MeanFieldTheory.average or MeanFieldTheory.delta
|
|
48
|
-
The field to compute the derivative.
|
|
49
|
-
axis : int
|
|
50
|
-
The axis to compute the derivative.
|
|
51
|
-
'''
|
|
52
|
-
return np.gradient(field, self.dx[axis], axis=0)
|
|
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
|