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,479 @@
1
+ import mmap
2
+ import struct
3
+
4
+ import h5py
5
+ import numpy as np
6
+ import pandas as pd
7
+
8
+
9
+ def _read_tabfile(self, i: int) -> None:
10
+ """Reads the data.****.tab file and stores the relevant information
11
+ within the class. Such information are the grid variables, the
12
+ output variables and the output time.
13
+
14
+ Returns
15
+ -------
16
+ - None
17
+
18
+ Parameters
19
+ ----------
20
+ - i (not optional): int
21
+ The index of the file to be loaded.
22
+
23
+ ----
24
+
25
+ Examples
26
+ --------
27
+ - Example #1: Read the data.0000.tab file
28
+
29
+ >>> _read_tabfile(0)
30
+
31
+ """
32
+ # Initialize the dictionary
33
+ Dict_tab = {}
34
+
35
+ # Open and read the data.****.tab file, computing the empty lines
36
+ vfp = pd.read_csv(
37
+ str(self._filepath), sep=r"\s+", header=None, skip_blank_lines=False
38
+ )
39
+
40
+ # Find the empty lines
41
+ scrhlines = vfp.isnull().all(axis=1)
42
+ empty_lines = vfp[scrhlines].shape[0]
43
+
44
+ # If the file is empty the grid is 1D, otherwise 2D
45
+ if empty_lines > 0:
46
+ # Remove the empty lines
47
+ vfp["block"] = scrhlines.cumsum()
48
+ vfp = vfp[~scrhlines]
49
+
50
+ # Store the grid variables if not present
51
+ if not hasattr(self, "dim"):
52
+ lines_in_block = vfp.groupby("block").size()
53
+
54
+ # Store the gridsize
55
+ self.nx1 = empty_lines
56
+ self.nx2 = len(lines_in_block)
57
+ self.dim = 2
58
+ self.nshp = (self.nx1, self.nx2)
59
+
60
+ # If the file is empty the grid is 1D, ostore grid vars if not present
61
+ elif not hasattr(self, "dim"):
62
+ self.nx1 = vfp.shape[0]
63
+ self.nx2 = 1
64
+ self.dim = 1
65
+ self.nshp = self.nx1
66
+
67
+ # Store the grid variables
68
+ self.x1 = np.array(vfp.iloc[:, 1]).reshape(self.nx2, self.nx1)
69
+ self.x2 = np.array(vfp.iloc[:, 0]).reshape(self.nx2, self.nx1)
70
+ num_cols = len(vfp.columns)
71
+
72
+ if self.nx2 == 1:
73
+ self.x1 = self.x2[0]
74
+
75
+ # Create the variable names if not present
76
+ if len(self._d_info["varslist"][i]) == 0:
77
+ self._d_info["varslist"][i] = [f"var{i}" for i in range(num_cols - 2)]
78
+ self._load_vars = self._d_info["varslist"][i]
79
+
80
+ # Store the variables
81
+ num_cols = num_cols - 1 if self.nx2 > 1 else num_cols
82
+ for j in range(2, num_cols):
83
+ var: str = self._d_info["varslist"][i][j - 2]
84
+ Dict_tab[var] = np.array(vfp.iloc[:, j])
85
+ if empty_lines > 0:
86
+ Dict_tab[var] = Dict_tab[var].reshape(self.nx2, self.nx1)
87
+ if var in self._load_vars:
88
+ setattr(self, var, Dict_tab[var])
89
+
90
+
91
+ def _inspect_vtk(self, i: int, endian: str | None, varmult: str | None) -> None:
92
+ """Routine to inspect the vtk file and find the variables, the
93
+ offset and the shape. The routine loops over the lines of the file
94
+ and finds the relevant information. The routine also finds the time
95
+ information if the file is standalone. The routine also finds the
96
+ coordinates if the file is standalone and cartesian.
97
+
98
+ Returns
99
+ -------
100
+ - None
101
+
102
+ Parameters
103
+ ----------
104
+ - endian (not optional): str | None
105
+ The endianess of the files.
106
+ - i (not optional): int
107
+ The index of the file to be loaded.
108
+ - varmult (not optional): str | None
109
+ If None the data are loaded as single files, otherwise the data are
110
+ loaded as multiple files. In single files, an adaptive strategy can be
111
+ used to speed up the offset computation without reading the entire file.
112
+
113
+ ----
114
+
115
+ Examples
116
+ --------
117
+ - Example #1: Inspect the vtk file
118
+
119
+ >>> _inspect_vtk(0, "big")
120
+
121
+ - Example #2: Inspect the vtk file
122
+
123
+ >>> _inspect_vtk(0, "little")
124
+
125
+ """
126
+ dir_map: dict[str, str] = {}
127
+ gridvars: list[str] = []
128
+
129
+ # Initialize the offset and shape arrays, the endianess and the coordinates
130
+ # dictionary
131
+ self._offset, self._shape = ({}, {})
132
+ endl = self._d_info["endianess"][i] = (
133
+ ">" if endian is None else self._d_end[endian]
134
+ )
135
+ if endl is None:
136
+ raise ValueError("Error: Wrong endianess in vtk file.")
137
+ if self._info is True:
138
+ self.nshp = 0
139
+ if self._alone is True:
140
+ self._d_info["binformat"][i] = (
141
+ f"{self._d_info['endianess'][i]}f{self._charsize}"
142
+ )
143
+
144
+ # Open the file and read the lines
145
+ f = open(self._filepath, "rb")
146
+
147
+ for line in f:
148
+ # Split the lines (unsplit are binary data or useless lines)
149
+ try:
150
+ spl0, spl1, spl2 = line.split()[0:3]
151
+ except ValueError:
152
+ continue
153
+
154
+ # Find the coordinates and store them
155
+ if (
156
+ spl0 in [j + b"_COORDINATES" for j in [b"X", b"Y", b"Z"]]
157
+ and self._info is True
158
+ ):
159
+ self.geom = "CARTESIAN"
160
+ var_sel = spl0.decode()[0]
161
+ binf = endl + "d" if spl2.decode() == "double" else endl + "f"
162
+ offset = f.tell()
163
+ print(offset)
164
+ shape = int(spl1)
165
+ scrh = np.memmap(
166
+ self._filepath,
167
+ dtype=binf,
168
+ mode="r",
169
+ offset=offset,
170
+ shape=shape,
171
+ )
172
+ exec(f"{dir_map[var_sel]} = scrh")
173
+
174
+ # Find the dimensions and store them, computing the variables shape
175
+ elif spl0 == b"DIMENSIONS" and self._info is True:
176
+ nshp_grid = [int(i) for i in line.split()[1:4]]
177
+ self.nx1, self.nx2, self.nx3 = [
178
+ max(int(i) - 1, 1) for i in line.split()[1:4]
179
+ ]
180
+ if self.nx3 == 1 and self.nx2 == 1:
181
+ self.dim = 1
182
+ self.nshp = self.nx1
183
+ self.gridsize = self.nx1
184
+ nshp_grid = self.nx1 + 1
185
+ gridvars = ["self.x1r", "self.x2", "self.x3"]
186
+ elif self.nx3 == 1:
187
+ self.dim = 2
188
+ self.nshp = (self.nx2, self.nx1)
189
+ self.gridsize = self.nx1 * self.nx2
190
+ nshp_grid = (self.nx2 + 1, self.nx1 + 1)
191
+ gridvars = ["self.x1r", "self.x2r", "self.x3"]
192
+ else:
193
+ self.dim = 3
194
+ self.nshp = (self.nx3, self.nx2, self.nx1)
195
+ self.gridsize = self.nx1 * self.nx2 * self.nx3
196
+ nshp_grid = (self.nx3 + 1, self.nx2 + 1, self.nx1 + 1)
197
+ gridvars = ["self.x1r", "self.x2r", "self.x3r"]
198
+ dir_map = {"X": gridvars[0], "Y": gridvars[1], "Z": gridvars[2]}
199
+
200
+ elif spl0 == b"POINTS" and self._info is True:
201
+ binf = endl + "d" if spl2.decode() == "double" else endl + "f"
202
+ offset = f.tell()
203
+ shape = int(spl1)
204
+ scrh = np.memmap(
205
+ self._filepath,
206
+ dtype=binf,
207
+ mode="r",
208
+ offset=offset,
209
+ shape=3 * shape,
210
+ )
211
+
212
+ for j in range(self.dim):
213
+ exec(f"{gridvars[j]} = scrh[{j}::3]")
214
+ exec(f"{gridvars[j]} = {gridvars[j]}.reshape({nshp_grid})")
215
+ self.geom = "UNKNOWN"
216
+
217
+ # Find the scalars and compute their offset
218
+ elif spl0 == b"SCALARS":
219
+ break
220
+
221
+ # var = spl1.decode()
222
+ # f.readline()
223
+ # self._offset[var] = f.tell()
224
+ # self._shape[var] = self.nshp
225
+
226
+ # Compute the time information
227
+ elif spl0 == b"TIME" and self._alone is True:
228
+ try:
229
+ binf = 8 if line.split()[3].decode() == "double" else 4
230
+ f.tell()
231
+ data = f.read(binf)
232
+ self.ntime[i] = struct.unpack(endl + "d", data)[0]
233
+ except:
234
+ pass
235
+
236
+ # New memmap strategy for vtk files
237
+ mmapped_file = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
238
+ search_pos = 0
239
+ while True:
240
+ scalars_pos = mmapped_file.find(b"SCALARS", search_pos)
241
+ if scalars_pos == -1:
242
+ break # No more occurrences found
243
+
244
+ # Move to the end of the 'SCALARS' line
245
+ line_end = mmapped_file.find(b"\n", scalars_pos)
246
+ line = mmapped_file[scalars_pos:line_end]
247
+ parts = line.split()
248
+ var = parts[1].decode()
249
+
250
+ # Move to the start of the scalar data
251
+ lookup_table_pos = mmapped_file.find(b"LOOKUP_TABLE default", line_end)
252
+ offset = mmapped_file.find(b"\n", lookup_table_pos) + 1
253
+
254
+ if (
255
+ self._info is not True
256
+ and varmult is None
257
+ and self._alone is False
258
+ and self._fastvtk is not False
259
+ ):
260
+ scrh = offset - scalars_pos + self.gridsize * 4 + 1
261
+ for ind, var in enumerate(self._d_info["varslist"][i]):
262
+ self._offset[var] = offset
263
+ self._shape[var] = self.nshp
264
+ lenvar = (
265
+ len(self._d_info["varslist"][i][0])
266
+ if ind == len(self._d_info["varslist"][i]) - 1
267
+ else len(self._d_info["varslist"][i][ind + 1])
268
+ )
269
+ offset = (
270
+ offset + scrh + lenvar - len(self._d_info["varslist"][i][0])
271
+ )
272
+ break
273
+ else:
274
+ self._offset[var] = offset
275
+ self._shape[var] = self.nshp
276
+ if varmult is not None:
277
+ break
278
+
279
+ search_pos = (
280
+ line_end + 1 + self.gridsize * 4
281
+ ) # Continue searching after the current line
282
+
283
+ mmapped_file.close()
284
+
285
+ # Find the variables and store them (only if single_file)
286
+ if self._d_info["typefile"][i] == "single_file" and self._alone is True:
287
+ self._d_info["varslist"][i] = np.array(list(self._offset.keys()))
288
+
289
+ # Compute the centered coordinates if the file is standalone and cartesian
290
+ if self._info is True:
291
+ self._read_grid_vtk(gridvars)
292
+ self._info = False
293
+
294
+ # Close the file
295
+ f.close()
296
+
297
+
298
+ def _inspect_h5(self, i: int, exout: int) -> None:
299
+ """Inspects the h5 files (static grid) in order to find offset and
300
+ shape of the different variables. If the files are standalone, the
301
+ routine also finds the coordinates.
302
+
303
+ Returns
304
+ -------
305
+ - None
306
+
307
+ Parameters
308
+ ----------
309
+ - exout (not optional): int
310
+ The index of the output to be loaded.
311
+ - i (not optional): int
312
+ The index of the file to be loaded.
313
+
314
+ ----
315
+
316
+ Examples
317
+ --------
318
+ - Example #1: Load all the variables
319
+
320
+ >>> _inspect_h5(0, 0)
321
+
322
+ """
323
+ # Initialize the offset and shape arrays
324
+ self._offset, self._shape = ({}, {})
325
+
326
+ # Open the file with the h5py library
327
+ h5file = h5py.File(self._filepath, "r")
328
+
329
+ # Selects the binformat
330
+ self._d_info["binformat"][i] = "d" if self.format == "dbl.h5" else "f"
331
+
332
+ try:
333
+ cellvs = h5file[f"Timestep_{exout}"]["vars"]
334
+ except KeyError:
335
+ cellvs = {}
336
+ try:
337
+ stagvs = h5file[f"Timestep_{exout}"]["stag_vars"]
338
+ except KeyError:
339
+ stagvs = {}
340
+
341
+ # If standalone file, finds the variables to be loaded, else
342
+ # remove variables in the .out file that are not present in the actual file
343
+ if self._alone is True:
344
+ self._d_info["varslist"][i] = set(cellvs.keys()) | set(stagvs.keys())
345
+ else:
346
+ self._d_info["varslist"][i] = set(self.varsh5)
347
+
348
+ # Loop over the variables and store the offset and shape
349
+ for j in self._d_info["varslist"][i]:
350
+ if j in cellvs:
351
+ self._offset[j] = cellvs[j].id.get_offset()
352
+ self._shape[j] = cellvs[j].shape
353
+ elif j in stagvs:
354
+ self._offset[j] = stagvs[j].id.get_offset()
355
+ self._shape[j] = stagvs[j].shape
356
+ else:
357
+ raise ValueError(f"Error: Variable {j} not found in the HDF5 file.")
358
+
359
+ # If standalone file, finds the coordinates
360
+ if self._info is True:
361
+ self.x1 = h5file["cell_coords"]["X"][:]
362
+ self.x2 = h5file["cell_coords"]["Y"][:]
363
+ self.x3 = h5file["cell_coords"]["Z"][:]
364
+ self.x1r = h5file["node_coords"]["X"][:]
365
+ self.x2r = h5file["node_coords"]["Y"][:]
366
+ self.x3r = h5file["node_coords"]["Z"][:]
367
+ self._read_grid_h5()
368
+ self._info = False
369
+
370
+ # Close the file
371
+ h5file.close()
372
+
373
+
374
+ def _compute_offset(
375
+ self, i: int, endian: str | None, exout: int, var: str | None
376
+ ) -> None:
377
+ """Routine to compute the offset and shape of the variables to be
378
+ loaded. The routine calls different functions depending on the file
379
+ format.
380
+
381
+ Returns
382
+ -------
383
+ - None
384
+
385
+ Parameters
386
+ ----------
387
+ - endian (not optional): str | None
388
+ The endianess of the files.
389
+ - exout (not optional): int
390
+ The index of the output to be loaded.
391
+ - i (not optional): int
392
+ The index of the file to be loaded.
393
+ - var (not optional): str | None
394
+ The variable to be loaded.
395
+
396
+ ----
397
+
398
+ Examples
399
+ --------
400
+ - Example #1: Load all the variables
401
+
402
+ >>> _compute_offset(0, True, 0, True)
403
+
404
+ """
405
+ if self._alone is not True:
406
+ # Read the grid file
407
+ self._read_gridfile()
408
+
409
+ # Depending on the file calls different routines
410
+ if self.format == "tab":
411
+ self._read_tabfile(i)
412
+ elif self.format == "vtk":
413
+ self._inspect_vtk(i, endian, var)
414
+ elif self.format in {"dbl.h5", "flt.h5"}:
415
+ self._inspect_h5(i, exout)
416
+ elif self.format == "hdf5":
417
+ self._inspect_hdf5(i, exout)
418
+ else:
419
+ self._offset_bin(i, var)
420
+
421
+
422
+ def _offset_bin(self, i: int, var: str | None) -> None:
423
+ """Routine to compute the offset and shape of the variables to be
424
+ loaded. The routine, knowing the grid shape, computes the offset and
425
+ stores the shape dependng on wether the variable is staggered or
426
+ not.
427
+
428
+ Returns
429
+ -------
430
+ - None
431
+
432
+ Parameters
433
+ ----------
434
+ - i (not optional): int
435
+ The index of the file to be loaded.
436
+ - var (not optional): str
437
+ The variable to be loaded.
438
+
439
+ ----
440
+
441
+ Examples
442
+ --------
443
+ - Example #1: Load all the variables
444
+
445
+ >>> _offset_bin(0, True)
446
+
447
+ """
448
+ # Read the grid file if not already read
449
+ if self._info is True:
450
+ self._read_gridfile()
451
+ self._info = False
452
+
453
+ # Initialize the offset and shape dictionaries and the offset starting point
454
+ self._offset, self._shape = ({}, {})
455
+ off_start = 0
456
+
457
+ # Define the staggered variables shape (Magnetic and electric field)
458
+ grid_sizes = {
459
+ "Bx1s": [self._nshp_st1, self._gridsize_st1],
460
+ "Ex1s": [self._nshp_st1, self._gridsize_st1],
461
+ "Bx2s": [self._nshp_st2, self._gridsize_st2],
462
+ "Ex2s": [self._nshp_st2, self._gridsize_st2],
463
+ "Bx3s": [self._nshp_st3, self._gridsize_st3],
464
+ "Ex3s": [self._nshp_st3, self._gridsize_st3],
465
+ }
466
+
467
+ # Loop over the variables to be loaded (None for single files)
468
+ varloop = self._d_info["varslist"][i] if var is None else [var]
469
+
470
+ for var in varloop:
471
+ # Get the grid shape and size (centered or staggered)
472
+ grid_size = grid_sizes.get(var, [self.nshp, self.gridsize])
473
+ self._shape[var] = grid_size[0]
474
+ # Assign the offset
475
+ self._offset[var] = off_start
476
+ # Move to next variable
477
+ off_start += grid_size[1] * self._charsize
478
+
479
+ # End of function