py-pluto 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.
- pyPLUTO/__init__.py +22 -0
- pyPLUTO/amr.py +745 -0
- pyPLUTO/baseloadmixin.py +258 -0
- pyPLUTO/baseloadstate.py +45 -0
- pyPLUTO/codes/echo_load.py +161 -0
- pyPLUTO/configure.py +261 -0
- pyPLUTO/gui/config.py +174 -0
- pyPLUTO/gui/custom_var.py +435 -0
- pyPLUTO/gui/globals.py +108 -0
- pyPLUTO/gui/main.py +17 -0
- pyPLUTO/gui/main_window.py +177 -0
- pyPLUTO/gui/panels.py +66 -0
- pyPLUTO/gui/utils.py +273 -0
- pyPLUTO/h_pypluto.py +84 -0
- pyPLUTO/image.py +302 -0
- pyPLUTO/imagefuncs/colorbar.py +240 -0
- pyPLUTO/imagefuncs/contour.py +254 -0
- pyPLUTO/imagefuncs/create_axes.py +464 -0
- pyPLUTO/imagefuncs/display.py +306 -0
- pyPLUTO/imagefuncs/figure.py +395 -0
- pyPLUTO/imagefuncs/imagetools.py +487 -0
- pyPLUTO/imagefuncs/interactive.py +403 -0
- pyPLUTO/imagefuncs/legend.py +250 -0
- pyPLUTO/imagefuncs/plot.py +311 -0
- pyPLUTO/imagefuncs/range.py +242 -0
- pyPLUTO/imagefuncs/scatter.py +270 -0
- pyPLUTO/imagefuncs/set_axis.py +497 -0
- pyPLUTO/imagefuncs/streamplot.py +297 -0
- pyPLUTO/imagefuncs/zoom.py +428 -0
- pyPLUTO/imagemixin.py +259 -0
- pyPLUTO/imagestate.py +45 -0
- pyPLUTO/load.py +447 -0
- pyPLUTO/loadfuncs/baseloadtools.py +71 -0
- pyPLUTO/loadfuncs/codeselection.py +48 -0
- pyPLUTO/loadfuncs/defpluto.py +123 -0
- pyPLUTO/loadfuncs/descriptor.py +102 -0
- pyPLUTO/loadfuncs/findfiles.py +182 -0
- pyPLUTO/loadfuncs/findformat.py +245 -0
- pyPLUTO/loadfuncs/initload.py +203 -0
- pyPLUTO/loadfuncs/loadvars.py +227 -0
- pyPLUTO/loadfuncs/offsetdata.py +87 -0
- pyPLUTO/loadfuncs/offsetfluid.py +408 -0
- pyPLUTO/loadfuncs/read_files.py +213 -0
- pyPLUTO/loadfuncs/readdata.py +619 -0
- pyPLUTO/loadfuncs/readdata_old.py +567 -0
- pyPLUTO/loadfuncs/readdefplini.py +101 -0
- pyPLUTO/loadfuncs/readfluid.py +479 -0
- pyPLUTO/loadfuncs/readformat.py +277 -0
- pyPLUTO/loadfuncs/readgridalone.py +224 -0
- pyPLUTO/loadfuncs/readgridfile.py +255 -0
- pyPLUTO/loadfuncs/readgridout.py +451 -0
- pyPLUTO/loadfuncs/readpart.py +419 -0
- pyPLUTO/loadfuncs/readtab.py +105 -0
- pyPLUTO/loadfuncs/write_files.py +283 -0
- pyPLUTO/loadmixin.py +419 -0
- pyPLUTO/loadpart.py +233 -0
- pyPLUTO/loadstate.py +68 -0
- pyPLUTO/newload.py +81 -0
- pyPLUTO/pytools.py +145 -0
- pyPLUTO/toolfuncs/findlines.py +551 -0
- pyPLUTO/toolfuncs/fourier.py +149 -0
- pyPLUTO/toolfuncs/nabla.py +676 -0
- pyPLUTO/toolfuncs/parttools.py +152 -0
- pyPLUTO/toolfuncs/transform.py +638 -0
- pyPLUTO/utils/annotator.py +27 -0
- pyPLUTO/utils/inspector.py +145 -0
- pyPLUTO/utils/make_docstrings.py +3 -0
- py_pluto-1.1.4.dist-info/METADATA +218 -0
- py_pluto-1.1.4.dist-info/RECORD +73 -0
- py_pluto-1.1.4.dist-info/WHEEL +5 -0
- py_pluto-1.1.4.dist-info/entry_points.txt +2 -0
- py_pluto-1.1.4.dist-info/licenses/LICENSE +27 -0
- py_pluto-1.1.4.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
"""Docstring for pyPLUTO.loadfuncs.baseloadtools module."""
|
|
2
|
+
|
|
3
|
+
import contextlib
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
|
|
8
|
+
from ..loadmixin import LoadMixin
|
|
9
|
+
from ..loadstate import LoadState
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class GridFileManager(LoadMixin):
|
|
13
|
+
"""Docstring for BaseLoadTools class."""
|
|
14
|
+
|
|
15
|
+
def __init__(self, state: LoadState) -> None:
|
|
16
|
+
"""Initialize the BaseLoadTools class."""
|
|
17
|
+
self.state: LoadState = state
|
|
18
|
+
|
|
19
|
+
def read_gridfile(self) -> None:
|
|
20
|
+
"""Read the file grid.out is read and store all the grid information.
|
|
21
|
+
|
|
22
|
+
Such information are the dimensions, the geometry, the center and edges
|
|
23
|
+
of each cell, the grid shape and size and, in case of non cartesian
|
|
24
|
+
coordinates, the transformed cartesian coordinates (only 2D for now).
|
|
25
|
+
The full non-cartesian 3D transformations have not been implemented yet.
|
|
26
|
+
|
|
27
|
+
Returns
|
|
28
|
+
-------
|
|
29
|
+
- None
|
|
30
|
+
|
|
31
|
+
Parameters
|
|
32
|
+
----------
|
|
33
|
+
- None
|
|
34
|
+
|
|
35
|
+
----
|
|
36
|
+
|
|
37
|
+
Examples
|
|
38
|
+
--------
|
|
39
|
+
- Example #1: read the grid file
|
|
40
|
+
|
|
41
|
+
>>> _read_gridfile()
|
|
42
|
+
|
|
43
|
+
"""
|
|
44
|
+
# Initialize relevant lists
|
|
45
|
+
nmax: list[int] = []
|
|
46
|
+
xL: list[float] = []
|
|
47
|
+
xR: list[float] = []
|
|
48
|
+
|
|
49
|
+
# Open and read the gridfile
|
|
50
|
+
with open(file=self.pathdir / Path("grid.out")) as gfp:
|
|
51
|
+
for i in gfp.readlines():
|
|
52
|
+
self.split_gridfile(i, xL, xR, nmax)
|
|
53
|
+
|
|
54
|
+
# Compute nx1, nx2, nx3
|
|
55
|
+
self.state.nx1, self.nx2, self.nx3 = nmax
|
|
56
|
+
nx1p2: int = self.nx1 + self.nx2
|
|
57
|
+
nx1p3: int = self.nx1 + self.nx2 + self.nx3
|
|
58
|
+
|
|
59
|
+
# Define grid shapes based on dimensions
|
|
60
|
+
"""
|
|
61
|
+
nx1s, nx2s, nx3s = self.nx1 + 1, self.nx2 + 1, self.nx3 + 1
|
|
62
|
+
GRID_SHAPES = {
|
|
63
|
+
1: lambda nx1, _, __: (nx1, nx1s, None, None),
|
|
64
|
+
2: lambda nx1, nx2, _: ((nx2, nx1), (nx2, nx1s), (nx2s, nx1), None),
|
|
65
|
+
3: lambda nx1, nx2, nx3: (
|
|
66
|
+
(nx3, nx2, nx1),
|
|
67
|
+
(nx3, nx2, nx1s),
|
|
68
|
+
(nx3, nx2s, nx1),
|
|
69
|
+
(nx3s, nx2, nx1),
|
|
70
|
+
),
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
# Determine grid shape based on dimension
|
|
74
|
+
(self.nshp, self.nshp_st1, self.nshp_st2, self.nshp_st3) = GRID_SHAPES[
|
|
75
|
+
self.dim
|
|
76
|
+
](self.nx1, self.nx2, self.nx3)
|
|
77
|
+
"""
|
|
78
|
+
nx1s, nx2s, nx3s = self.nx1 + 1, self.nx2 + 1, self.nx3 + 1
|
|
79
|
+
oned, twod, threed = 1, 2, 3
|
|
80
|
+
|
|
81
|
+
if self.dim == oned:
|
|
82
|
+
self.nshp = self.nx1
|
|
83
|
+
self.nshp_st1 = nx1s
|
|
84
|
+
self.nshp_st2 = None
|
|
85
|
+
self.state.nshp_st3 = None
|
|
86
|
+
|
|
87
|
+
elif self.dim == twod:
|
|
88
|
+
self.nshp = (self.nx2, self.nx1)
|
|
89
|
+
self.nshp_st1 = (self.nx2, nx1s)
|
|
90
|
+
self.nshp_st2 = (nx2s, self.nx1)
|
|
91
|
+
self.nshp_st3 = None
|
|
92
|
+
|
|
93
|
+
elif self.dim == threed:
|
|
94
|
+
self.nshp = (self.nx3, self.nx2, self.nx1)
|
|
95
|
+
self.nshp_st1 = (self.nx3, self.nx2, nx1s)
|
|
96
|
+
self.nshp_st2 = (self.nx3, nx2s, self.nx1)
|
|
97
|
+
self.state.nshp_st3 = (
|
|
98
|
+
nx3s,
|
|
99
|
+
self.nx2,
|
|
100
|
+
self.nx1,
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
else:
|
|
104
|
+
raise ValueError(f"dim must be 1..3, got {self.dim}")
|
|
105
|
+
|
|
106
|
+
# Compute the centered and staggered grid values
|
|
107
|
+
self.x1r = np.array([*xL[0 : self.nx1], xR[self.nx1 - 1]])
|
|
108
|
+
self.x1 = 0.5 * (self.x1r[:-1] + self.x1r[1:])
|
|
109
|
+
self.dx1 = self.x1r[1:] - self.x1r[:-1]
|
|
110
|
+
|
|
111
|
+
self.x2r = np.array([*xL[self.nx1 : nx1p2], xR[nx1p2 - 1]])
|
|
112
|
+
self.x2 = 0.5 * (self.x2r[:-1] + self.x2r[1:])
|
|
113
|
+
self.dx2 = self.x2r[1:] - self.x2r[:-1]
|
|
114
|
+
|
|
115
|
+
self.x3r = np.array([*xL[nx1p2:nx1p3], xR[nx1p3 - 1]])
|
|
116
|
+
self.x3 = 0.5 * (self.x3r[:-1] + self.x3r[1:])
|
|
117
|
+
self.dx3 = self.x3r[1:] - self.x3r[:-1]
|
|
118
|
+
|
|
119
|
+
self.check_geometry()
|
|
120
|
+
|
|
121
|
+
self.gridsize = self.nx1 * self.nx2 * self.nx3
|
|
122
|
+
self.gridsize_st1 = nx1s * self.nx2 * self.nx3
|
|
123
|
+
self.gridsize_st2 = self.nx1 * nx2s * self.nx3
|
|
124
|
+
self.gridsize_st3 = self.nx1 * self.nx2 * nx3s
|
|
125
|
+
|
|
126
|
+
def split_gridfile(
|
|
127
|
+
self, i: str, xL: list[float], xR: list[float], nmax: list[int]
|
|
128
|
+
) -> None:
|
|
129
|
+
"""Split the gridfile, storing the info in the function variables.
|
|
130
|
+
|
|
131
|
+
Dimensions and geometry are stored in the class.
|
|
132
|
+
|
|
133
|
+
Return
|
|
134
|
+
------
|
|
135
|
+
|
|
136
|
+
- None
|
|
137
|
+
|
|
138
|
+
Parameters
|
|
139
|
+
----------
|
|
140
|
+
- i (not optional): str
|
|
141
|
+
The line of the gridfile.
|
|
142
|
+
- nmax (not optional): list[int]
|
|
143
|
+
The number of the cells in the grid.
|
|
144
|
+
- xL (not optional): list[float]
|
|
145
|
+
The list of the left cell boundaries values.
|
|
146
|
+
- xR (not optional): list[float]
|
|
147
|
+
The list of the right cell boundaries values.
|
|
148
|
+
|
|
149
|
+
----
|
|
150
|
+
|
|
151
|
+
Examples
|
|
152
|
+
--------
|
|
153
|
+
- Example #1: Split the gridfile
|
|
154
|
+
|
|
155
|
+
>>> _split_gridfile(i, xL, xR, nmax)
|
|
156
|
+
|
|
157
|
+
"""
|
|
158
|
+
three_number = 3
|
|
159
|
+
# If the splitted line has only one string, try to convert it
|
|
160
|
+
# to an integer (number of cells in a dimension).
|
|
161
|
+
if len(i.split()) == 1:
|
|
162
|
+
with contextlib.suppress(ValueError):
|
|
163
|
+
nmax.append(int(i.split(maxsplit=1)[0]))
|
|
164
|
+
|
|
165
|
+
# Check if the splitted line has three strings
|
|
166
|
+
if len(i.split()) == three_number:
|
|
167
|
+
# Try to convert the first string to an int (cell number in a
|
|
168
|
+
# dimension) and the other two to floats (left and right cell
|
|
169
|
+
# boundaries)
|
|
170
|
+
try:
|
|
171
|
+
int(i.split(maxsplit=1)[0])
|
|
172
|
+
xL.append(float(i.split()[1]))
|
|
173
|
+
xR.append(float(i.split()[2]))
|
|
174
|
+
|
|
175
|
+
# Check if the keyword is geometry or dimensions and
|
|
176
|
+
# store the information in the class
|
|
177
|
+
except ValueError:
|
|
178
|
+
if i.split()[1] == "GEOMETRY:":
|
|
179
|
+
self.geom = i.split()[2]
|
|
180
|
+
if i.split()[1] == "DIMENSIONS:":
|
|
181
|
+
self.dim = int(i.split()[2])
|
|
182
|
+
|
|
183
|
+
def check_geometry(self) -> None:
|
|
184
|
+
"""Check the geometry of the grid and set full3D attribute.
|
|
185
|
+
|
|
186
|
+
The function checks the geometry of the grid and sets the full3D
|
|
187
|
+
attribute accordingly. If the geometry is cartesian, full3D is set to
|
|
188
|
+
True. If the geometry is cylindrical or spherical, full3D is set to
|
|
189
|
+
False.
|
|
190
|
+
|
|
191
|
+
Returns
|
|
192
|
+
-------
|
|
193
|
+
- None
|
|
194
|
+
|
|
195
|
+
Parameters
|
|
196
|
+
----------
|
|
197
|
+
- None
|
|
198
|
+
|
|
199
|
+
----
|
|
200
|
+
|
|
201
|
+
Examples
|
|
202
|
+
--------
|
|
203
|
+
- Example #1: Check geometry for cartesian grid
|
|
204
|
+
|
|
205
|
+
>>> _check_geometry()
|
|
206
|
+
|
|
207
|
+
- Example #2: Check geometry for cylindrical grid
|
|
208
|
+
|
|
209
|
+
>>> _check_geometry()
|
|
210
|
+
|
|
211
|
+
"""
|
|
212
|
+
threed = 3
|
|
213
|
+
if self.geom in {"POLAR", "CYLINDRICAL"}:
|
|
214
|
+
x1_2D, x2_2D = np.meshgrid(self.x1, self.x2, indexing="ij")
|
|
215
|
+
x1r_2D, x2r_2D = np.meshgrid(self.x1r, self.x2r, indexing="ij")
|
|
216
|
+
|
|
217
|
+
self.x1c = (np.cos(x2_2D) * x1_2D).T
|
|
218
|
+
self.x2c = (np.sin(x2_2D) * x1_2D).T
|
|
219
|
+
self.x1rc = (np.cos(x2r_2D) * x1r_2D).T
|
|
220
|
+
self.x2rc = (np.sin(x2r_2D) * x1r_2D).T
|
|
221
|
+
del x1_2D, x2_2D, x1r_2D, x2r_2D
|
|
222
|
+
elif self.geom == "SPHERICAL":
|
|
223
|
+
x1_2D, x2_2D = np.meshgrid(self.x1, self.x2, indexing="ij")
|
|
224
|
+
x1r_2D, x2r_2D = np.meshgrid(self.x1r, self.x2r, indexing="ij")
|
|
225
|
+
|
|
226
|
+
self.x1p = (np.sin(x2_2D) * x1_2D).T
|
|
227
|
+
self.x2p = (np.cos(x2_2D) * x1_2D).T
|
|
228
|
+
self.x1rp = (np.sin(x2r_2D) * x1r_2D).T
|
|
229
|
+
self.x2rp = (np.cos(x2r_2D) * x1r_2D).T
|
|
230
|
+
|
|
231
|
+
x1_2D, x3_2D = np.meshgrid(self.x1, self.x3, indexing="ij")
|
|
232
|
+
x1r_2D, x3r_2D = np.meshgrid(self.x1r, self.x3r, indexing="ij")
|
|
233
|
+
|
|
234
|
+
self.x1t = (np.cos(x3_2D) * x1_2D).T
|
|
235
|
+
self.x3t = (np.sin(x3_2D) * x1_2D).T
|
|
236
|
+
self.x1rt = (np.cos(x3r_2D) * x1r_2D).T
|
|
237
|
+
self.x3rt = (np.sin(x3r_2D) * x1r_2D).T
|
|
238
|
+
|
|
239
|
+
del x1_2D, x2_2D, x1r_2D, x2r_2D, x3_2D, x3r_2D
|
|
240
|
+
if self.dim == threed and self.full3D is True:
|
|
241
|
+
x1_3D, x2_3D, x3_3D = np.meshgrid(
|
|
242
|
+
self.x1, self.x2, self.x3, indexing="ij"
|
|
243
|
+
)
|
|
244
|
+
x1r_3D, x2r_3D, x3r_3D = np.meshgrid(
|
|
245
|
+
self.x1r, self.x2r, self.x3r, indexing="ij"
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
self.x1c = (np.sin(x2_3D) * np.cos(x3_3D) * x1_3D).T
|
|
249
|
+
self.x2c = (np.sin(x2_3D) * np.sin(x3_3D) * x1_3D).T
|
|
250
|
+
self.x3c = (np.cos(x2_3D) * x1_3D).T
|
|
251
|
+
self.x1rc = (np.sin(x2r_3D) * np.cos(x3r_3D) * x1r_3D).T
|
|
252
|
+
self.x2rc = (np.sin(x2r_3D) * np.sin(x3r_3D) * x1r_3D).T
|
|
253
|
+
self.x3rc = (np.cos(x2r_3D) * x1r_3D).T
|
|
254
|
+
|
|
255
|
+
del x1_3D, x2_3D, x3_3D, x1r_3D, x2r_3D, x3r_3D
|
|
@@ -0,0 +1,451 @@
|
|
|
1
|
+
import warnings
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
import pandas as pd
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def _read_grid_h5(self) -> None:
|
|
8
|
+
"""Read the grid from a .h5 file.
|
|
9
|
+
|
|
10
|
+
Returns
|
|
11
|
+
-------
|
|
12
|
+
- None
|
|
13
|
+
|
|
14
|
+
Parameters
|
|
15
|
+
----------
|
|
16
|
+
- None
|
|
17
|
+
|
|
18
|
+
----
|
|
19
|
+
|
|
20
|
+
Examples
|
|
21
|
+
--------
|
|
22
|
+
- Example #1: Read the grid from a .h5 file
|
|
23
|
+
|
|
24
|
+
>>> _read_grid_h5()
|
|
25
|
+
|
|
26
|
+
"""
|
|
27
|
+
# Variables that we already have: x1 x2 x3 x1r x2r x3r
|
|
28
|
+
# Variables that we need: nx1 nx2 nx3 nshp nx1s nx2s nx3s dim
|
|
29
|
+
# nshp_st1 nshp_st2 nshp_st3
|
|
30
|
+
# gridsize gridsize_st1 gridsize_st2 gridsize_st3
|
|
31
|
+
self.nshp = np.shape(self.x1)
|
|
32
|
+
self.dim = len(self.nshp)
|
|
33
|
+
self.geom = "UNKNOWN"
|
|
34
|
+
self.nx1, self.nx2, self.nx3 = (self.nshp + (1, 1, 1))[:3]
|
|
35
|
+
nx1s, nx2s, nx3s = self.nx1 + 1, self.nx2 + 1, self.nx3 + 1
|
|
36
|
+
|
|
37
|
+
GRID_SHAPES = {
|
|
38
|
+
1: lambda nx1, _, __: (nx1s, None, None),
|
|
39
|
+
2: lambda nx1, nx2, _: ((nx2, nx1s), (nx2s, nx1), None),
|
|
40
|
+
3: lambda nx1, nx2, nx3: (
|
|
41
|
+
(nx3, nx2, nx1s),
|
|
42
|
+
(nx3, nx2s, nx1),
|
|
43
|
+
(nx3s, nx2, nx1),
|
|
44
|
+
),
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
# Determine grid shape based on dimension
|
|
48
|
+
(self._nshp_st1, self._nshp_st2, self._nshp_st3) = GRID_SHAPES[self.dim](
|
|
49
|
+
self.nx1, self.nx2, self.nx3
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
# Grid spacing has been removed from the .h5 file
|
|
53
|
+
"""
|
|
54
|
+
self.dx1 = self.x1r[1:] - self.x1r[:-1]
|
|
55
|
+
self.dx1 = 0.5*(self.dx1[:, 1:] + self.dx1[:, :-1]) if self.dim > 1 else self.dx1
|
|
56
|
+
self.dx1 = 0.5*(self.dx1[:, :, 1:] + self.dx1[:, :, :-1]) if self.dim > 2 else self.dx1
|
|
57
|
+
|
|
58
|
+
self.dx2 = self.x2r[1:] - self.x2r[:-1]
|
|
59
|
+
self.dx2 = 0.5*(self.dx2[:, 1:] + self.dx2[:, :-1]) if self.dim > 1 else self.dx2
|
|
60
|
+
self.dx2 = 0.5*(self.dx2[:, :, 1:] + self.dx2[:, :, :-1]) if self.dim > 2 else self.dx2
|
|
61
|
+
|
|
62
|
+
self.dx3 = self.x3r[1:] - self.x3r[:-1]
|
|
63
|
+
self.dx3 = 0.5*(self.dx3[:, 1:] + self.dx3[:, :-1]) if self.dim > 1 else self.dx3
|
|
64
|
+
self.dx3 = 0.5*(self.dx3[:, :, 1:] + self.dx3[:, :, :-1]) if self.dim > 2 else self.dx3
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
# Compute the gridsize both centered and staggered
|
|
68
|
+
self.gridsize = self.nx1 * self.nx2 * self.nx3
|
|
69
|
+
self._gridsize_st1 = nx1s * self.nx2 * self.nx3
|
|
70
|
+
self._gridsize_st2 = self.nx1 * nx2s * self.nx3
|
|
71
|
+
self._gridsize_st3 = self.nx1 * self.nx2 * nx3s
|
|
72
|
+
|
|
73
|
+
warn = (
|
|
74
|
+
"The geometry is unknown, therefore the grid spacing has not been "
|
|
75
|
+
"computed. \nFor a more accurate grid analysis, the loading with "
|
|
76
|
+
"the .out file is recommended.\n"
|
|
77
|
+
)
|
|
78
|
+
warnings.warn(warn, UserWarning)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def _read_grid_vtk(self, gridvars) -> None:
|
|
82
|
+
"""Read the grid from a .vtk file.
|
|
83
|
+
|
|
84
|
+
Returns
|
|
85
|
+
-------
|
|
86
|
+
- None
|
|
87
|
+
|
|
88
|
+
Parameters
|
|
89
|
+
----------
|
|
90
|
+
- gridvars (not optional): list[str]
|
|
91
|
+
The list of grid variables.
|
|
92
|
+
|
|
93
|
+
----
|
|
94
|
+
|
|
95
|
+
Examples
|
|
96
|
+
--------
|
|
97
|
+
- Example #1: Read the grid from a vtk file
|
|
98
|
+
|
|
99
|
+
>>> _read_grid_vtk(["self.x1r", "self.x2r", "self.x3r"])
|
|
100
|
+
|
|
101
|
+
"""
|
|
102
|
+
# - RECTILINEAR GRID
|
|
103
|
+
# Variables that we already have: x1r x2r x3r nshp dim nx1 nx2 nx3
|
|
104
|
+
# Variables that we need: x1 x2 x3 dx1 dx2 dx3 gridsize
|
|
105
|
+
|
|
106
|
+
self.gridsize = self.nx1 * self.nx2 * self.nx3
|
|
107
|
+
|
|
108
|
+
if self.geom == "UNKNOWN":
|
|
109
|
+
if gridvars[0] == "self.x1r":
|
|
110
|
+
self.x1 = 0.5 * (self.x1r[1:] + self.x1r[:-1])
|
|
111
|
+
self.x1 = (
|
|
112
|
+
0.5 * (self.x1[:, 1:] + self.x1[:, :-1])
|
|
113
|
+
if self.dim > 1
|
|
114
|
+
else self.x1
|
|
115
|
+
)
|
|
116
|
+
self.x1 = (
|
|
117
|
+
0.5 * (self.x1[:, :, 1:] + self.x1[:, :, :-1])
|
|
118
|
+
if self.dim > 2
|
|
119
|
+
else self.x1
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
# self.dx1 = self.x1r[1:] - self.x1r[:-1]
|
|
123
|
+
# self.dx1 = 0.5*(self.dx1[:, 1:] + self.dx1[:, :-1]) if self.dim > 1 else self.dx1
|
|
124
|
+
# self.dx1 = 0.5*(self.dx1[:, :, 1:] + self.dx1[:, :, :-1]) if self.dim > 2 else self.dx1
|
|
125
|
+
|
|
126
|
+
if gridvars[1] == "self.x2r":
|
|
127
|
+
self.x2 = 0.5 * (self.x2r[1:] + self.x2r[:-1])
|
|
128
|
+
self.x2 = 0.5 * (self.x2[:, 1:] + self.x2[:, :-1])
|
|
129
|
+
self.x2 = (
|
|
130
|
+
0.5 * (self.x2[:, :, 1:] + self.x2[:, :, :-1])
|
|
131
|
+
if self.dim > 2
|
|
132
|
+
else self.x2
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
# self.dx2 = self.x2r[1:] - self.x2r[:-1]
|
|
136
|
+
# self.dx2 = 0.5*(self.dx2[:, 1:] + self.dx2[:, :-1])
|
|
137
|
+
# self.dx2 = 0.5*(self.dx2[:, :, 1:] + self.dx2[:, :, :-1]) if self.dim > 2 else self.dx2
|
|
138
|
+
|
|
139
|
+
if gridvars[2] == "self.x3r":
|
|
140
|
+
self.x3 = 0.5 * (self.x3r[1:] + self.x3r[:-1])
|
|
141
|
+
self.x3 = 0.5 * (self.x3[:, 1:] + self.x3[:, :-1])
|
|
142
|
+
self.x3 = 0.5 * (self.x3[:, :, 1:] + self.x3[:, :, :-1])
|
|
143
|
+
|
|
144
|
+
# self.dx3 = self.x3r[1:] - self.x3r[:-1]
|
|
145
|
+
# self.dx3 = 0.5*(self.dx3[:, 1:] + self.dx3[:, :-1])
|
|
146
|
+
# self.dx3 = 0.5*(self.dx3[:, :, 1:] + self.dx3[:, :, :-1])
|
|
147
|
+
|
|
148
|
+
warn = (
|
|
149
|
+
"The geometry is unknown, therefore the grid spacing has not been "
|
|
150
|
+
"computed. \nFor a more accurate grid analysis, the loading with "
|
|
151
|
+
"the .out file is recommended.\n"
|
|
152
|
+
)
|
|
153
|
+
warnings.warn(warn, UserWarning)
|
|
154
|
+
|
|
155
|
+
return None
|
|
156
|
+
|
|
157
|
+
if gridvars[0] == "self.x1r":
|
|
158
|
+
self.x1 = 0.5 * (self.x1r[:-1] + self.x1r[1:])
|
|
159
|
+
self.dx1 = self.x1r[1:] - self.x1r[:-1]
|
|
160
|
+
if gridvars[1] == "self.x2r":
|
|
161
|
+
self.x2 = 0.5 * (self.x2r[:-1] + self.x2r[1:])
|
|
162
|
+
self.dx2 = self.x2r[1:] - self.x2r[:-1]
|
|
163
|
+
if gridvars[2] == "self.x3r":
|
|
164
|
+
self.x3 = 0.5 * (self.x3r[:-1] + self.x3r[1:])
|
|
165
|
+
self.dx3 = self.x3r[1:] - self.x3r[:-1]
|
|
166
|
+
|
|
167
|
+
return None
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def _read_gridfile(self) -> None:
|
|
171
|
+
"""The file grid.out is read and all the grid information are stored
|
|
172
|
+
in the Load class. Such information are the dimensions, the
|
|
173
|
+
geometry, the center and edges of each cell, the grid shape and size
|
|
174
|
+
and, in case of non cartesian coordinates, the transformed cartesian
|
|
175
|
+
coordinates (only 2D for now).bThe full non-cartesian 3D
|
|
176
|
+
transformations have not been implemented yet.
|
|
177
|
+
|
|
178
|
+
Returns
|
|
179
|
+
-------
|
|
180
|
+
- None
|
|
181
|
+
|
|
182
|
+
Parameters
|
|
183
|
+
----------
|
|
184
|
+
- None
|
|
185
|
+
|
|
186
|
+
----
|
|
187
|
+
|
|
188
|
+
Examples
|
|
189
|
+
--------
|
|
190
|
+
- Example #1: read the grid file
|
|
191
|
+
|
|
192
|
+
>>> _read_gridfile()
|
|
193
|
+
|
|
194
|
+
"""
|
|
195
|
+
# Initialize relevant lists
|
|
196
|
+
nmax, xL, xR = [], [], []
|
|
197
|
+
|
|
198
|
+
# Open and read the gridfile
|
|
199
|
+
with open(self._pathgrid) as gfp:
|
|
200
|
+
for i in gfp.readlines():
|
|
201
|
+
self._split_gridfile(i, xL, xR, nmax)
|
|
202
|
+
|
|
203
|
+
# Compute nx1, nx2, nx3
|
|
204
|
+
self.nx1, self.nx2, self.nx3 = nmax
|
|
205
|
+
nx1p2 = self.nx1 + self.nx2
|
|
206
|
+
nx1p3 = self.nx1 + self.nx2 + self.nx3
|
|
207
|
+
|
|
208
|
+
# Define grid shapes based on dimensions
|
|
209
|
+
nx1s, nx2s, nx3s = self.nx1 + 1, self.nx2 + 1, self.nx3 + 1
|
|
210
|
+
GRID_SHAPES = {
|
|
211
|
+
1: lambda nx1, _, __: (nx1, nx1s, None, None),
|
|
212
|
+
2: lambda nx1, nx2, _: ((nx2, nx1), (nx2, nx1s), (nx2s, nx1), None),
|
|
213
|
+
3: lambda nx1, nx2, nx3: (
|
|
214
|
+
(nx3, nx2, nx1),
|
|
215
|
+
(nx3, nx2, nx1s),
|
|
216
|
+
(nx3, nx2s, nx1),
|
|
217
|
+
(nx3s, nx2, nx1),
|
|
218
|
+
),
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
# Determine grid shape based on dimension
|
|
222
|
+
(self.nshp, self._nshp_st1, self._nshp_st2, self._nshp_st3) = GRID_SHAPES[
|
|
223
|
+
self.dim
|
|
224
|
+
](self.nx1, self.nx2, self.nx3)
|
|
225
|
+
|
|
226
|
+
# Compute the centered and staggered grid values
|
|
227
|
+
self.x1r = np.array(xL[0 : self.nx1] + [xR[self.nx1 - 1]])
|
|
228
|
+
self.x1 = 0.5 * (self.x1r[:-1] + self.x1r[1:])
|
|
229
|
+
self.dx1 = self.x1r[1:] - self.x1r[:-1]
|
|
230
|
+
|
|
231
|
+
self.x2r = np.array(xL[self.nx1 : nx1p2] + [xR[nx1p2 - 1]])
|
|
232
|
+
self.x2 = 0.5 * (self.x2r[:-1] + self.x2r[1:])
|
|
233
|
+
self.dx2 = self.x2r[1:] - self.x2r[:-1]
|
|
234
|
+
|
|
235
|
+
self.x3r = np.array(xL[nx1p2:nx1p3] + [xR[nx1p3 - 1]])
|
|
236
|
+
self.x3 = 0.5 * (self.x3r[:-1] + self.x3r[1:])
|
|
237
|
+
self.dx3 = self.x3r[1:] - self.x3r[:-1]
|
|
238
|
+
|
|
239
|
+
# Compute the cartesian grid coordinates (non-cartesian geometry)
|
|
240
|
+
|
|
241
|
+
if self.geom == "POLAR" or self.geom == "CYLINDRICAL":
|
|
242
|
+
x1_2D, x2_2D = np.meshgrid(self.x1, self.x2, indexing="ij")
|
|
243
|
+
x1r_2D, x2r_2D = np.meshgrid(self.x1r, self.x2r, indexing="ij")
|
|
244
|
+
|
|
245
|
+
self.x1c = (np.cos(x2_2D) * x1_2D).T
|
|
246
|
+
self.x2c = (np.sin(x2_2D) * x1_2D).T
|
|
247
|
+
self.x1rc = (np.cos(x2r_2D) * x1r_2D).T
|
|
248
|
+
self.x2rc = (np.sin(x2r_2D) * x1r_2D).T
|
|
249
|
+
|
|
250
|
+
self.gridlist3 = ["x1c", "x2c", "x1rc", "x2rc"]
|
|
251
|
+
del x1_2D, x2_2D, x1r_2D, x2r_2D
|
|
252
|
+
elif self.geom == "SPHERICAL":
|
|
253
|
+
x1_2D, x2_2D = np.meshgrid(self.x1, self.x2, indexing="ij")
|
|
254
|
+
x1r_2D, x2r_2D = np.meshgrid(self.x1r, self.x2r, indexing="ij")
|
|
255
|
+
|
|
256
|
+
self.x1p = (np.sin(x2_2D) * x1_2D).T
|
|
257
|
+
self.x2p = (np.cos(x2_2D) * x1_2D).T
|
|
258
|
+
self.x1rp = (np.sin(x2r_2D) * x1r_2D).T
|
|
259
|
+
self.x2rp = (np.cos(x2r_2D) * x1r_2D).T
|
|
260
|
+
|
|
261
|
+
x1_2D, x3_2D = np.meshgrid(self.x1, self.x3, indexing="ij")
|
|
262
|
+
x1r_2D, x3r_2D = np.meshgrid(self.x1r, self.x3r, indexing="ij")
|
|
263
|
+
|
|
264
|
+
self.x1t = (np.cos(x3_2D) * x1_2D).T
|
|
265
|
+
self.x3t = (np.sin(x3_2D) * x1_2D).T
|
|
266
|
+
self.x1rt = (np.cos(x3r_2D) * x1r_2D).T
|
|
267
|
+
self.x3rt = (np.sin(x3r_2D) * x1r_2D).T
|
|
268
|
+
|
|
269
|
+
self.gridlist3 = [
|
|
270
|
+
"x1p",
|
|
271
|
+
"x2p",
|
|
272
|
+
"x1rp",
|
|
273
|
+
"x2rp",
|
|
274
|
+
"x1t",
|
|
275
|
+
"x3t",
|
|
276
|
+
"x1rt",
|
|
277
|
+
"x3rt",
|
|
278
|
+
]
|
|
279
|
+
|
|
280
|
+
del x1_2D, x2_2D, x1r_2D, x2r_2D, x3_2D, x3r_2D
|
|
281
|
+
|
|
282
|
+
if self.dim == 3 and self._full3d is True:
|
|
283
|
+
x1_3D, x2_3D, x3_3D = np.meshgrid(
|
|
284
|
+
self.x1, self.x2, self.x3, indexing="ij"
|
|
285
|
+
)
|
|
286
|
+
x1r_3D, x2r_3D, x3r_3D = np.meshgrid(
|
|
287
|
+
self.x1r, self.x2r, self.x3r, indexing="ij"
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
self.x1c = (np.sin(x2_3D) * np.cos(x3_3D) * x1_3D).T
|
|
291
|
+
self.x2c = (np.sin(x2_3D) * np.sin(x3_3D) * x1_3D).T
|
|
292
|
+
self.x3c = (np.cos(x2_3D) * x1_3D).T
|
|
293
|
+
self.x1rc = (np.sin(x2r_3D) * np.cos(x3r_3D) * x1r_3D).T
|
|
294
|
+
self.x2rc = (np.sin(x2r_3D) * np.sin(x3r_3D) * x1r_3D).T
|
|
295
|
+
self.x3rc = (np.cos(x2r_3D) * x1r_3D).T
|
|
296
|
+
|
|
297
|
+
self.gridlist3.extend(["x1c", "x2c", "x3c", "x1rc", "x2rc", "x3rc"])
|
|
298
|
+
|
|
299
|
+
del x1_3D, x2_3D, x3_3D, x1r_3D, x2r_3D, x3r_3D
|
|
300
|
+
else:
|
|
301
|
+
pass
|
|
302
|
+
# self.x1c = np.zeros((self.nx1,self.nx2,self.nx3))
|
|
303
|
+
# print(np.shape(self.x1c))
|
|
304
|
+
# self.pippo = np.meshgrid(self.x2, self.x3, indexing='xy')
|
|
305
|
+
# print(np.shape(self.pippo))
|
|
306
|
+
|
|
307
|
+
# Compute the gridsize both centered and staggered
|
|
308
|
+
self.gridsize = self.nx1 * self.nx2 * self.nx3
|
|
309
|
+
self._gridsize_st1 = nx1s * self.nx2 * self.nx3
|
|
310
|
+
self._gridsize_st2 = self.nx1 * nx2s * self.nx3
|
|
311
|
+
self._gridsize_st3 = self.nx1 * self.nx2 * nx3s
|
|
312
|
+
|
|
313
|
+
self._info = False
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
def _read_outfile(self, nout: int, endian: str) -> None:
|
|
317
|
+
"""Reads the datatype.out file and stores the relevant information
|
|
318
|
+
within the class. Such information are the time array, the output
|
|
319
|
+
variables, the file type (single or multiples), the endianess, the
|
|
320
|
+
simulation path and the bin format. All these information are
|
|
321
|
+
relevant in order to open the output files and access the data.
|
|
322
|
+
|
|
323
|
+
Returns
|
|
324
|
+
-------
|
|
325
|
+
- None
|
|
326
|
+
|
|
327
|
+
Parameters
|
|
328
|
+
----------
|
|
329
|
+
- endian (not optional): str
|
|
330
|
+
The endianess of the files.
|
|
331
|
+
- nout (not optional): int
|
|
332
|
+
The output file to be opened. If default ('last'), the code assumes the
|
|
333
|
+
last file should be opened. Other options available are 'last' (all the
|
|
334
|
+
files should be opened) and -1 (same as 'last').
|
|
335
|
+
|
|
336
|
+
----
|
|
337
|
+
|
|
338
|
+
Examples
|
|
339
|
+
--------
|
|
340
|
+
- Example #1: Read the 'filetype'.out file
|
|
341
|
+
|
|
342
|
+
>>> _read_outfile(0, "big")
|
|
343
|
+
|
|
344
|
+
"""
|
|
345
|
+
# Open and read the 'filetype'.out file
|
|
346
|
+
# with open(self._pathdata) as f:
|
|
347
|
+
# max_fields = max(len(line.split()) for line in f if line.strip())
|
|
348
|
+
vfp = pd.read_csv(
|
|
349
|
+
str(self._pathdata),
|
|
350
|
+
sep=r"\s+",
|
|
351
|
+
header=None,
|
|
352
|
+
# engine="python",
|
|
353
|
+
# names=list(range(max_fields)),
|
|
354
|
+
)
|
|
355
|
+
# FIX FOR DIFFERENT NUMBER OF COLUMNS IN THE .OUT FILE
|
|
356
|
+
|
|
357
|
+
# Store the output and the time full list
|
|
358
|
+
self.outlist = np.array(vfp.iloc[:, 0], dtype="int")
|
|
359
|
+
self.timelist = np.array(vfp.iloc[:, 1])
|
|
360
|
+
|
|
361
|
+
# Check the output lines
|
|
362
|
+
self._check_nout(nout)
|
|
363
|
+
self.ntime = self.timelist[self.nout]
|
|
364
|
+
self._lennout = len(self.nout)
|
|
365
|
+
|
|
366
|
+
# Initialize the info dictionary
|
|
367
|
+
self._d_info = {
|
|
368
|
+
"typefile": np.array(vfp.iloc[self.nout, 4]),
|
|
369
|
+
"endianess": np.where(vfp.iloc[self.nout, 5] == "big", ">", "<"),
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
# Compute the endianess (vtk have always big endianess).
|
|
373
|
+
# If endian is given, it is used instead of the one in the file.
|
|
374
|
+
self._d_info["endianess"][:] = (
|
|
375
|
+
">" if self.format == "vtk" else self._d_info["endianess"]
|
|
376
|
+
)
|
|
377
|
+
self._d_info["endianess"][:] = (
|
|
378
|
+
self._d_end[endian] if endian is not None else self._d_info["endianess"]
|
|
379
|
+
)
|
|
380
|
+
|
|
381
|
+
# Store the variables list
|
|
382
|
+
if self.format not in {"dbl.h5", "flt.h5"}:
|
|
383
|
+
self._d_info["varslist"] = np.array(vfp.iloc[self.nout, 6:])
|
|
384
|
+
else:
|
|
385
|
+
self.varsh5 = np.array(vfp.iloc[self.nout, 6:])[0]
|
|
386
|
+
self._d_info["varslist"] = [[] for _ in range(self._lennout)]
|
|
387
|
+
|
|
388
|
+
# Compute binformat and endpath
|
|
389
|
+
self._d_info["binformat"] = np.char.add(
|
|
390
|
+
self._d_info["endianess"], "f" + str(self._charsize)
|
|
391
|
+
)
|
|
392
|
+
format_string = f".%04d.{self.format}"
|
|
393
|
+
self._d_info["endpath"] = np.char.mod(format_string, self.nout)
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
def _split_gridfile(
|
|
397
|
+
self, i: str, xL: list[float], xR: list[float], nmax: list[int]
|
|
398
|
+
) -> None:
|
|
399
|
+
"""Splits the gridfile, storing the information in the variables
|
|
400
|
+
passed by the function. Dimensions and geometry are stored in the
|
|
401
|
+
class.
|
|
402
|
+
|
|
403
|
+
Return
|
|
404
|
+
------
|
|
405
|
+
|
|
406
|
+
- None
|
|
407
|
+
|
|
408
|
+
Parameters
|
|
409
|
+
----------
|
|
410
|
+
- i (not optional): str
|
|
411
|
+
The line of the gridfile.
|
|
412
|
+
- nmax (not optional): list[int]
|
|
413
|
+
The number of the cells in the grid.
|
|
414
|
+
- xL (not optional): list[float]
|
|
415
|
+
The list of the left cell boundaries values.
|
|
416
|
+
- xR (not optional): list[float]
|
|
417
|
+
The list of the right cell boundaries values.
|
|
418
|
+
|
|
419
|
+
----
|
|
420
|
+
|
|
421
|
+
Examples
|
|
422
|
+
--------
|
|
423
|
+
- Example #1: Split the gridfile
|
|
424
|
+
|
|
425
|
+
>>> _split_gridfile(i, xL, xR, nmax)
|
|
426
|
+
|
|
427
|
+
"""
|
|
428
|
+
# If the splitted line has only one string, try to convert it
|
|
429
|
+
# to an integer (number of cells in a dimension).
|
|
430
|
+
if len(i.split()) == 1:
|
|
431
|
+
try:
|
|
432
|
+
nmax.append(int(i.split(maxsplit=1)[0]))
|
|
433
|
+
except ValueError:
|
|
434
|
+
pass
|
|
435
|
+
|
|
436
|
+
# Check if the splitted line has three strings
|
|
437
|
+
if len(i.split()) == 3:
|
|
438
|
+
# Try to convert the first string to an int (cell number in a dimension)
|
|
439
|
+
# and the other two to floats (left and right cell boundaries)
|
|
440
|
+
try:
|
|
441
|
+
int(i.split(maxsplit=1)[0])
|
|
442
|
+
xL.append(float(i.split()[1]))
|
|
443
|
+
xR.append(float(i.split()[2]))
|
|
444
|
+
|
|
445
|
+
# Check if the keyword is geometry or dimensions and
|
|
446
|
+
# store the information in the class
|
|
447
|
+
except ValueError:
|
|
448
|
+
if i.split()[1] == "GEOMETRY:":
|
|
449
|
+
self.geom = i.split()[2]
|
|
450
|
+
if i.split()[1] == "DIMENSIONS:":
|
|
451
|
+
self.dim = int(i.split()[2])
|