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,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)
|