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.
Files changed (73) hide show
  1. pyPLUTO/__init__.py +22 -0
  2. pyPLUTO/amr.py +745 -0
  3. pyPLUTO/baseloadmixin.py +258 -0
  4. pyPLUTO/baseloadstate.py +45 -0
  5. pyPLUTO/codes/echo_load.py +161 -0
  6. pyPLUTO/configure.py +261 -0
  7. pyPLUTO/gui/config.py +174 -0
  8. pyPLUTO/gui/custom_var.py +435 -0
  9. pyPLUTO/gui/globals.py +108 -0
  10. pyPLUTO/gui/main.py +17 -0
  11. pyPLUTO/gui/main_window.py +177 -0
  12. pyPLUTO/gui/panels.py +66 -0
  13. pyPLUTO/gui/utils.py +273 -0
  14. pyPLUTO/h_pypluto.py +84 -0
  15. pyPLUTO/image.py +302 -0
  16. pyPLUTO/imagefuncs/colorbar.py +240 -0
  17. pyPLUTO/imagefuncs/contour.py +254 -0
  18. pyPLUTO/imagefuncs/create_axes.py +464 -0
  19. pyPLUTO/imagefuncs/display.py +306 -0
  20. pyPLUTO/imagefuncs/figure.py +395 -0
  21. pyPLUTO/imagefuncs/imagetools.py +487 -0
  22. pyPLUTO/imagefuncs/interactive.py +403 -0
  23. pyPLUTO/imagefuncs/legend.py +250 -0
  24. pyPLUTO/imagefuncs/plot.py +311 -0
  25. pyPLUTO/imagefuncs/range.py +242 -0
  26. pyPLUTO/imagefuncs/scatter.py +270 -0
  27. pyPLUTO/imagefuncs/set_axis.py +497 -0
  28. pyPLUTO/imagefuncs/streamplot.py +297 -0
  29. pyPLUTO/imagefuncs/zoom.py +428 -0
  30. pyPLUTO/imagemixin.py +259 -0
  31. pyPLUTO/imagestate.py +45 -0
  32. pyPLUTO/load.py +447 -0
  33. pyPLUTO/loadfuncs/baseloadtools.py +71 -0
  34. pyPLUTO/loadfuncs/codeselection.py +48 -0
  35. pyPLUTO/loadfuncs/defpluto.py +123 -0
  36. pyPLUTO/loadfuncs/descriptor.py +102 -0
  37. pyPLUTO/loadfuncs/findfiles.py +182 -0
  38. pyPLUTO/loadfuncs/findformat.py +245 -0
  39. pyPLUTO/loadfuncs/initload.py +203 -0
  40. pyPLUTO/loadfuncs/loadvars.py +227 -0
  41. pyPLUTO/loadfuncs/offsetdata.py +87 -0
  42. pyPLUTO/loadfuncs/offsetfluid.py +408 -0
  43. pyPLUTO/loadfuncs/read_files.py +213 -0
  44. pyPLUTO/loadfuncs/readdata.py +619 -0
  45. pyPLUTO/loadfuncs/readdata_old.py +567 -0
  46. pyPLUTO/loadfuncs/readdefplini.py +101 -0
  47. pyPLUTO/loadfuncs/readfluid.py +479 -0
  48. pyPLUTO/loadfuncs/readformat.py +277 -0
  49. pyPLUTO/loadfuncs/readgridalone.py +224 -0
  50. pyPLUTO/loadfuncs/readgridfile.py +255 -0
  51. pyPLUTO/loadfuncs/readgridout.py +451 -0
  52. pyPLUTO/loadfuncs/readpart.py +419 -0
  53. pyPLUTO/loadfuncs/readtab.py +105 -0
  54. pyPLUTO/loadfuncs/write_files.py +283 -0
  55. pyPLUTO/loadmixin.py +419 -0
  56. pyPLUTO/loadpart.py +233 -0
  57. pyPLUTO/loadstate.py +68 -0
  58. pyPLUTO/newload.py +81 -0
  59. pyPLUTO/pytools.py +145 -0
  60. pyPLUTO/toolfuncs/findlines.py +551 -0
  61. pyPLUTO/toolfuncs/fourier.py +149 -0
  62. pyPLUTO/toolfuncs/nabla.py +676 -0
  63. pyPLUTO/toolfuncs/parttools.py +152 -0
  64. pyPLUTO/toolfuncs/transform.py +638 -0
  65. pyPLUTO/utils/annotator.py +27 -0
  66. pyPLUTO/utils/inspector.py +145 -0
  67. pyPLUTO/utils/make_docstrings.py +3 -0
  68. py_pluto-1.1.4.dist-info/METADATA +218 -0
  69. py_pluto-1.1.4.dist-info/RECORD +73 -0
  70. py_pluto-1.1.4.dist-info/WHEEL +5 -0
  71. py_pluto-1.1.4.dist-info/entry_points.txt +2 -0
  72. py_pluto-1.1.4.dist-info/licenses/LICENSE +27 -0
  73. 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])