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,419 @@
1
+ import mmap
2
+
3
+ import numpy as np
4
+
5
+
6
+ def _inspect_bin(self, i: int, endian: str | None) -> None:
7
+ """Routine to inspect the binary file and find the variables, the
8
+ offset and the shape. The routine loops over the lines of the file
9
+ and finds the relevant information. The routine then creates a key
10
+ 'tot' in the offset and shape dictionaries, which contains the
11
+ offset and shape of the whole data.
12
+
13
+ Returns
14
+ -------
15
+ - None
16
+
17
+ Parameters
18
+ ----------
19
+ - endian: str | None
20
+ The endianess of the files.
21
+ - i: int
22
+ The index of the file to be loaded.
23
+
24
+ ----
25
+
26
+ Examples
27
+ --------
28
+ - Example #1: Inspect the binary file
29
+
30
+ >>> _inspect_bin(0, "big")
31
+
32
+ """
33
+ # Initialize the offset, shape arrays and dimensions dictionary
34
+ self._offset, self._shape, self._dictdim = ({}, {}, {})
35
+
36
+ # Open the file and read the lines
37
+ f = open(self._filepath, "rb")
38
+ for line in f:
39
+ # Split the lines (unsplit are binary data)
40
+ try:
41
+ _, spl1, spl2 = line.split()[0:3]
42
+ except ValueError:
43
+ break
44
+
45
+ # Find the dimensions of the domain
46
+ if spl1 == b"dimensions":
47
+ self.dim = int(spl2)
48
+
49
+ # Find the endianess of the file and compute the binary format
50
+ elif spl1 == b"endianity":
51
+ self._d_info["endianess"][i] = ">" if endian == b"big" else "<"
52
+ self._d_info["endianess"][i] = (
53
+ self._d_end[endian]
54
+ if endian is not None
55
+ else self._d_info["endianess"][i]
56
+ )
57
+
58
+ scrh = "f" if self._charsize == 4 else "d"
59
+ self._d_info["binformat"][i] = self._d_info["endianess"][i] + scrh
60
+
61
+ # Find the number of particles in the datafile and the maximum
62
+ # number of particles in the simulation
63
+ elif spl1 == b"nparticles":
64
+ self.nshp = int(line.split()[2])
65
+ # self.npart = self.nshp
66
+
67
+ # To be fixed (multiple loading)
68
+ elif spl1 == b"idCounter":
69
+ self.maxpart = np.max([int(line.split()[2]), self.maxpart])
70
+
71
+ # Find the time information
72
+ elif spl1 == b"time":
73
+ self.ntime[i] = float(spl2)
74
+
75
+ # Find the variable names
76
+ elif spl1 == b"field_names":
77
+ self._d_info["varskeys"][i] = [
78
+ elem.decode() for elem in line.split()[2:]
79
+ ]
80
+ self._d_info["varslist"][i] = ["tot"]
81
+
82
+ # Find the variable dimensions
83
+ elif spl1 == b"field_dim":
84
+ self._vardim = np.array(
85
+ [int(elem.decode()) for elem in line.split()[2:]]
86
+ )
87
+ self._offset["tot"] = f.tell()
88
+ self._shape["tot"] = (self.nshp, np.sum(self._vardim))
89
+ # To be fixed (multiple loading)
90
+ # self._shape['tot'] = (self.maxpart,np.sum(self.vardim))
91
+
92
+ f.close()
93
+
94
+ # Create the key variables in the vars dictionary
95
+ for ind, j in enumerate(self._d_info["varskeys"][i]):
96
+ self._shape[j] = self.nshp
97
+ self._dictdim[j] = self._vardim[ind]
98
+
99
+
100
+ def _inspect_vtk(self, i: int, endian: str | None) -> None:
101
+ """Routine to inspect the vtk file and find the variables, the
102
+ offset and the shape. The routine loops over the lines of the file
103
+ and finds the relevant information. The routine also finds the time
104
+ information if the file is standalone. The routine also finds the
105
+ coordinates if the file is standalone and cartesian.
106
+
107
+ Returns
108
+ -------
109
+ - None
110
+
111
+ Parameters
112
+ ----------
113
+ - endian (not optional): str | None
114
+ The endianess of the files.
115
+ - i (not optional): int
116
+ The index of the file to be loaded.
117
+
118
+ ----
119
+
120
+ Examples
121
+ --------
122
+ - Example #1: Inspect the vtk file
123
+
124
+ >>> _inspect_vtk(0, "big")
125
+
126
+ """
127
+ # Initialize the offset and shape arrays, the endianess and the coordinates dictionary
128
+ self._offset, self._shape = ({}, {})
129
+
130
+ endl = self._d_info["endianess"][i] = (
131
+ ">" if endian is None else self._d_end[endian]
132
+ )
133
+ if endl is None:
134
+ raise ValueError("Error: Wrong endianess in vtk file.")
135
+
136
+ # Open the file and read the lines
137
+ f = open(self._filepath, "rb")
138
+
139
+ # This is a crude implementation to find the variables and their
140
+ # offsets in the vtk file. The routine loops over the lines of the
141
+ # file and finds the relevant information. The routine also finds
142
+ # the time information if the file is standalone. The routine also
143
+ # finds the coordinates if the file is standalone and cartesian.
144
+ # The routine is (unfortunately) very slow since the file is read
145
+ # line by line.
146
+ """
147
+ for l in f:
148
+
149
+ # Split the lines (unsplit are binary data)
150
+ try:
151
+ spl0, spl1, _ = l.split()[0:3]
152
+
153
+ except:
154
+ continue
155
+
156
+ # Find the number of points and store it
157
+ if spl0 == b'POINTS':
158
+ self.dim = int(spl1)
159
+ self._offset['points'] = f.tell()
160
+ self._shape['points'] = (self.dim,3)
161
+
162
+ #elif spl1 == b'Identity':
163
+ # f.readline()
164
+ # self._offset['id'] = f.tell()
165
+ # self._shape['id'] = self.dim
166
+
167
+ #elif spl1 == b'tinj':
168
+ # f.readline()
169
+ # self._offset['tinj'] = f.tell()
170
+ # self._shape['tinj'] = self.dim
171
+
172
+ elif spl0 == b'SCALARS':
173
+ var = spl1.decode()
174
+ f.readline()
175
+ self._offset[var] = f.tell()
176
+ self._shape[var] = self.dim
177
+ continue
178
+
179
+ elif spl0 == b'VECTORS':
180
+ var = spl1.decode()
181
+ self._shape[var] = (self.dim,int(l.split()[3]))
182
+ self._offset[var] = f.tell()
183
+
184
+ print(self._offset, self._shape)
185
+ """
186
+
187
+ mmapped_file = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
188
+
189
+ search_pos = 0
190
+
191
+ while True:
192
+ # Find the next occurrence of the header
193
+ points_pos = mmapped_file.find(b"POINTS", search_pos)
194
+
195
+ # Determine the closest header found
196
+ if points_pos == -1: # and scalars_pos == -1 and vectors_pos == -1:
197
+ break # No more headers found
198
+
199
+ # min_pos = min((pos for pos in [points_pos, scalars_pos, vectors_pos] if pos != -1))
200
+
201
+ # if min_pos == points_pos:
202
+ # Handle POINTS
203
+ line_end = mmapped_file.find(b"\n", points_pos)
204
+ line = mmapped_file[points_pos:line_end:1]
205
+ parts = line.split()
206
+ self.dim = int(parts[1])
207
+
208
+ offset = line_end + 1
209
+ self._offset["points"] = offset
210
+ self._shape["points"] = (self.dim, 3)
211
+
212
+ search_pos = line_end + 3 * 4 * self.dim + 1
213
+
214
+ while True:
215
+ # Find the next occurrence of the header
216
+ # points_pos = mmapped_file.find(b'POINTS', search_pos)
217
+ scalars_pos = mmapped_file.find(b"SCALARS", search_pos)
218
+ # vectors_pos = -1#mmapped_file.find(b'VECTORS', search_pos)
219
+
220
+ # Determine the closest header found
221
+ if scalars_pos == -1: # and scalars_pos == -1 and vectors_pos == -1:
222
+ break # No more headers found
223
+
224
+ # Move to the end of the 'SCALARS' line
225
+ line_end = mmapped_file.find(b"\n", scalars_pos)
226
+ line = mmapped_file[scalars_pos:line_end]
227
+ parts = line.split()
228
+ var = parts[1].decode()
229
+
230
+ # Move to the start of the scalar data
231
+ lookup_table_pos = mmapped_file.find(b"LOOKUP_TABLE default", line_end)
232
+ self._offset[var] = mmapped_file.find(b"\n", lookup_table_pos) + 1
233
+ self._shape[var] = self.dim
234
+
235
+ search_pos = line_end + 4 * self.dim + 1
236
+
237
+ while True:
238
+ vectors_pos = mmapped_file.find(b"VECTORS", search_pos)
239
+
240
+ # Determine the closest header found
241
+ if vectors_pos == -1: # and scalars_pos == -1 and vectors_pos == -1:
242
+ break # No more headers found
243
+ # elif min_pos == vectors_pos:
244
+ # Handle VECTORS
245
+ line_end = mmapped_file.find(b"\n", vectors_pos)
246
+ line = mmapped_file[vectors_pos:line_end]
247
+ parts = line.split()
248
+ var = parts[1].decode()
249
+
250
+ self._shape[var] = (self.dim, int(parts[3]))
251
+ self._offset[var] = line_end + 1
252
+
253
+ search_pos = line_end + self.dim * int(parts[3]) * 4 + 1
254
+
255
+ mmapped_file.close()
256
+
257
+ # Find the variables and store them
258
+ self._d_info["binformat"][i] = self._d_info["endianess"][i] + "f4"
259
+ self._d_info["varslist"][i] = np.array(list(self._offset.keys()))
260
+
261
+ f.close()
262
+
263
+ # Create the key variables in the vars dictionary
264
+ for ind, j in enumerate(self._d_info["varskeys"][i]):
265
+ self._shape[j] = self.nshp
266
+ self._dictdim[j] = self._vardim[ind]
267
+ self._init_vardict(j)
268
+
269
+
270
+ def _store_bin_particles(self, i: int) -> None:
271
+ """Routine to store the particles data. The routine loops over the
272
+ variables and stores the data in the dictionary from the 'tot' key.
273
+ Then the 'tot' keyword is removed from the dictionary for memory and
274
+ clarity reasons.
275
+
276
+ Returns
277
+ -------
278
+ - None
279
+
280
+ Parameters
281
+ ----------
282
+ - i (not optional): int
283
+ The index of the file to be loaded.
284
+
285
+ ----
286
+
287
+ Examples
288
+ --------
289
+ - Example 1: Store the data
290
+
291
+ >>> _store_bin_particles(0)
292
+
293
+ """
294
+ # Mask the array (to be fixed for multiple loadings)
295
+ # masked_array = np.ma.masked_array(self._d_vars['tot'][0].astype('int'),
296
+ # np.isnan(self._d_vars['tot'][0]))
297
+
298
+ # Start with column 0 (id) and loop over the variable names
299
+ ncol = 0
300
+ for j, var in enumerate(self._d_info["varskeys"][i]):
301
+ # Compute the size of the variable and store the data
302
+ szvar = self._vardim[j]
303
+ index = ncol if szvar == 1 else slice(ncol, ncol + szvar)
304
+ if self._lennout != 1:
305
+ # To be fixed for multiple loadings
306
+ raise NotImplementedError("multiple loading not implemented yet")
307
+ # self._d_vars[var][i] = self._d_vars['tot'][index]
308
+ else:
309
+ self._d_vars[var] = self._d_vars["tot"][index]
310
+
311
+ # Update the column counter
312
+ ncol += szvar
313
+
314
+ # Remove the 'tot' key from the dictionary
315
+ del self._d_vars["tot"]
316
+
317
+
318
+ def _store_vtk_particles(self, i: int) -> None:
319
+ """Routine to store the particles data. Since positions and
320
+ velocities are stored in 2d arrays, the routine splits the data in
321
+ the different components and stores them in the dictionary.
322
+
323
+ Returns
324
+ -------
325
+ - None
326
+
327
+ Parameters
328
+ ----------
329
+ - i (not optional): int
330
+ The index of the file to be loaded.
331
+
332
+ ----
333
+
334
+ Examples
335
+ --------
336
+ - Example 1: Store the data
337
+
338
+ >>> _store_vtk_particles(0)
339
+
340
+ """
341
+ vardict = {
342
+ "points": ["x1", "x2", "x3"],
343
+ "Velocity": ["vx1", "vx2", "vx3"],
344
+ "Four-Velocity": ["vx1", "vx2", "vx3"],
345
+ }
346
+
347
+ # Store the position in the dictionary
348
+ for var in vardict:
349
+ if var in self._d_vars:
350
+ for i, j in enumerate(vardict[var]):
351
+ self._d_vars[j] = self._d_vars[var][i]
352
+ del self._d_vars[var]
353
+
354
+ # Store the id in the dictionary
355
+ if "Identity" in self._d_vars:
356
+ self._d_vars["id"] = self._d_vars["Identity"]
357
+ del self._d_vars["Identity"]
358
+
359
+ # Store the position in the dictionary (old way)
360
+ # if 'points' in self._d_vars:
361
+ # self._d_vars['x1'] = self._d_vars['points'][0]
362
+ # self._d_vars['x2'] = self._d_vars['points'][1]
363
+ # self._d_vars['x3'] = self._d_vars['points'][2]
364
+ # del self._d_vars['points']
365
+
366
+ # Store the velocity in the dictionary
367
+ # if 'Four-Velocity' in self._d_vars:
368
+ # self._d_vars['vx1'] = self._d_vars['Four-Velocity'][0]
369
+ # self._d_vars['vx2'] = self._d_vars['Four-Velocity'][1]
370
+ # self._d_vars['vx3'] = self._d_vars['Four-Velocity'][2]
371
+ # del self._d_vars['Four-Velocity']
372
+ # elif 'Velocity' in self._d_vars:
373
+ # self._d_vars['vx1'] = self._d_vars['Velocity'][0]
374
+ # self._d_vars['vx2'] = self._d_vars['Velocity'][1]
375
+ # self._d_vars['vx3'] = self._d_vars['Velocity'][2]
376
+ # del self._d_vars['Velocity']
377
+ # elif 'vel' in self._d_vars:
378
+ # self._d_vars['vx1'] = self._d_vars['vel'][0]
379
+ # self._d_vars['vx2'] = self._d_vars['vel'][1]
380
+ # self._d_vars['vx3'] = self._d_vars['vel'][2]
381
+ # del self._d_vars['vel']
382
+
383
+
384
+ def _compute_offset(
385
+ self, i: int, endian: str | None, exout: int, var: str | None
386
+ ) -> None:
387
+ """Routine to compute the offset and shape of the variables to be
388
+ loaded. The routine calls different functions depending on the file
389
+ format.
390
+
391
+ Returns
392
+ -------
393
+ - None
394
+
395
+ Parameters
396
+ ----------
397
+ - endian (not optional): str | None
398
+ The endianess of the files.
399
+ - exout (not optional): int
400
+ The index of the output to be loaded.
401
+ - i (not optional): int
402
+ The index of the file to be loaded.
403
+ - var (not optional): str | None
404
+ The variable to be loaded.
405
+
406
+ ----
407
+
408
+ Examples
409
+ --------
410
+ - Example #1: Load all the variables
411
+
412
+ >>> _compute_offset(0, None, 0, True)
413
+
414
+ """
415
+ # Depending on the file calls different routines
416
+ if self.format == "vtk":
417
+ self._inspect_vtk(i, endian)
418
+ else:
419
+ self._inspect_bin(i, endian)
@@ -0,0 +1,105 @@
1
+ """Docstring for pyPLUTO.loadfuncs.readtab."""
2
+
3
+ import io
4
+ import mmap
5
+
6
+ import numpy as np
7
+
8
+ from pyPLUTO.loadmixin import LoadMixin
9
+ from pyPLUTO.loadstate import LoadState
10
+
11
+
12
+ class ReadtabManager(LoadMixin):
13
+ """Class that manages the reading of tabular data."""
14
+
15
+ def __init__(self, state: LoadState) -> None:
16
+ self.state = state
17
+
18
+ def read_tab(
19
+ self, i: int, var: str | None, exout: int, mm: mmap.mmap
20
+ ) -> None:
21
+ """Read the data.****.tab file and stores the relevant information.
22
+
23
+ Such information are the grid variables, the output variables and the
24
+ output time.
25
+
26
+ Returns
27
+ -------
28
+ - None
29
+
30
+ Parameters
31
+ ----------
32
+ - i (not optional): int
33
+ The index of the file to be loaded.
34
+
35
+ ----
36
+
37
+ Examples
38
+ --------
39
+ - Example #1: Read the data.0000.tab file
40
+
41
+ >>> _read_tabfile(0)
42
+
43
+ """
44
+ Dict_tab = {}
45
+
46
+ # Read entire mmap in one call
47
+ mm.seek(0)
48
+ raw = mm.read()
49
+
50
+ # Normalize line endings so grid detection is consistent across OSes.
51
+ # On Windows checkouts, lines can be CRLF and blank rows are \r\n\r\n.
52
+ raw = raw.replace(b"\r\n", b"\n").replace(b"\r", b"\n")
53
+
54
+ # Count empty lines via C-level bytes.count — no Python loop needed.
55
+ # \n\n indicates a blank line between two newlines.
56
+ empty_lines = raw.count(b"\n\n")
57
+
58
+ # np.loadtxt skips blank lines natively and parses entirely in C
59
+ data = np.loadtxt(io.BytesIO(raw), dtype=np.float64)
60
+
61
+ if data.size == 0:
62
+ return
63
+
64
+ # Ensure 2D even for single-row files
65
+ if data.ndim == 1:
66
+ data = data[np.newaxis, :]
67
+
68
+ num_rows, num_cols = data.shape
69
+
70
+ # Grid detection
71
+ if empty_lines > 0:
72
+ if not hasattr(self, "dim"):
73
+ self.nx1 = empty_lines
74
+ self.nx2 = num_rows // empty_lines
75
+ self.dim = 2
76
+ self.nshp = (self.nx1, self.nx2)
77
+ elif not hasattr(self, "dim"):
78
+ self.nx1 = num_rows
79
+ self.nx2 = 1
80
+ self.dim = 1
81
+ self.nshp = self.nx1
82
+
83
+ if self.infogrid is True:
84
+ self.x1 = data[:, 1].reshape(self.nx1, self.nx2)
85
+ self.x2 = data[:, 0].reshape(self.nx1, self.nx2)
86
+ # if self.nx2 == 1:
87
+ # self.x1 = self.x2[0]
88
+
89
+ # Variable names
90
+ if len(self.d_info["varslist"][exout]) == 0:
91
+ self.d_info["varslist"][exout] = [
92
+ f"var{k + 1}" for k in range(num_cols - 2)
93
+ ]
94
+ self.load_vars = self.d_info["varslist"][exout]
95
+
96
+ # Store variables — pure numpy column slices (views, zero-copy)
97
+ num_cols_iter = num_cols
98
+ for j in range(2, num_cols_iter):
99
+ var = self.d_info["varslist"][exout][j - 2]
100
+ col = data[:, j]
101
+ if empty_lines > 0:
102
+ col = col.reshape(self.nx1, self.nx2)
103
+ Dict_tab[var] = col
104
+ if var in self.load_vars:
105
+ setattr(self.state, var, col)