PyMHD 0.1.0__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.
- pymhd/__init__.py +31 -0
- pymhd/derivatives/TENO.py +278 -0
- pymhd/derivatives/WENO.py +323 -0
- pymhd/derivatives/__init__.py +24 -0
- pymhd/derivatives/compact.py +365 -0
- pymhd/derivatives/derivative.py +926 -0
- pymhd/numdiss.py +598 -0
- pymhd/plot/__init__.py +48 -0
- pymhd/plot/nd.py +1519 -0
- pymhd/plot/slc.py +648 -0
- pymhd/plot/spc.py +249 -0
- pymhd/preprocess/Athena.py +847 -0
- pymhd/preprocess/__init__.py +69 -0
- pymhd/preprocess/helper/NOTICE +42 -0
- pymhd/preprocess/helper/bin_convert.py +2000 -0
- pymhd/preprocess/helper/make_athdf.py +45 -0
- pymhd/spectra.py +376 -0
- pymhd/turbulence.py +917 -0
- pymhd-0.1.0.dist-info/METADATA +100 -0
- pymhd-0.1.0.dist-info/RECORD +22 -0
- pymhd-0.1.0.dist-info/WHEEL +4 -0
- pymhd-0.1.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,2000 @@
|
|
|
1
|
+
# Adapted from AthenaK (https://github.com/IAS-Astrophysics/athenak)
|
|
2
|
+
# Copyright (c) 2020, Institute for Advanced Study / High-Performance Computing / jmstone / Athena-Parthenon
|
|
3
|
+
# Licensed under BSD-3-Clause License
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
Functions to:
|
|
7
|
+
(1) convert bin --> Python dictionary
|
|
8
|
+
(2) convert Python dictionary --> athdf(xdmf) files
|
|
9
|
+
|
|
10
|
+
This module contains a collection of helper functions for readng and
|
|
11
|
+
writing athena file data formats. More information is provided in the
|
|
12
|
+
function docstrings.
|
|
13
|
+
|
|
14
|
+
----
|
|
15
|
+
|
|
16
|
+
In order to translate a binary file into athdf and corresponding xdmf
|
|
17
|
+
files, you could do the following:
|
|
18
|
+
|
|
19
|
+
import bin_convert
|
|
20
|
+
import os
|
|
21
|
+
|
|
22
|
+
binary_fname = "path/to/file.bin"
|
|
23
|
+
athdf_fname = binary_fname.replace(".bin", ".athdf")
|
|
24
|
+
xdmf_fname = athdf_fname + ".xdmf"
|
|
25
|
+
filedata = bin_convert.read_binary(binary_fname)
|
|
26
|
+
bin_convert.write_athdf(athdf_fname, filedata)
|
|
27
|
+
bin_convert.write_xdmf_for(xdmf_fname, os.path.basename(athdf_fname), filedata)
|
|
28
|
+
|
|
29
|
+
Notice that write_xdmf_for(...) function expects the relative path to
|
|
30
|
+
the athdf file from the xdmf, so please be aware of this requirement.
|
|
31
|
+
|
|
32
|
+
----
|
|
33
|
+
|
|
34
|
+
The read_*(...) functions return a filedata dictionary-like object with
|
|
35
|
+
|
|
36
|
+
filedata['header'] = array of strings
|
|
37
|
+
ordered array of header, including all the header information
|
|
38
|
+
filedata['time'] = float
|
|
39
|
+
time from input file
|
|
40
|
+
filedata['cycle'] = int
|
|
41
|
+
cycle from input file
|
|
42
|
+
filedata['var_names'] = array of strings
|
|
43
|
+
ordered array of variable names, like ['dens', 'eint', ...]
|
|
44
|
+
filedata['n_mbs'] = int
|
|
45
|
+
total number of meshblocks in the file
|
|
46
|
+
filedata['nx1_mb'] = int
|
|
47
|
+
number of cells in x1 direction in MeshBlock
|
|
48
|
+
filedata['nx2_mb'] = int
|
|
49
|
+
number of cells in x2 direction in MeshBlock
|
|
50
|
+
filedata['nx3_mb'] = int
|
|
51
|
+
number of cells in x3 direction in MeshBlock
|
|
52
|
+
filedata['nx1_out_mb'] = int
|
|
53
|
+
number of output cells in x1 direction in MeshBlock (useful for slicing)
|
|
54
|
+
filedata['nx2_out_mb'] = int
|
|
55
|
+
number of output cells in x2 direction in MeshBlock (useful for slicing)
|
|
56
|
+
filedata['nx3_out_mb'] = int
|
|
57
|
+
number of output cells in x3 direction in MeshBlock (useful for slicing)
|
|
58
|
+
filedata['Nx1'] = int
|
|
59
|
+
total number of cell in x1 direction in root grid
|
|
60
|
+
filedata['Nx2'] = int
|
|
61
|
+
total number of cell in x2 direction in root grid
|
|
62
|
+
filedata['Nx3'] = int
|
|
63
|
+
total number of cell in x3 direction in root grid
|
|
64
|
+
filedata['x1min'] = float
|
|
65
|
+
coordinate minimum of root grid in x1 direction
|
|
66
|
+
filedata['x1max'] = float
|
|
67
|
+
coordinate maximum of root grid in x1 direction
|
|
68
|
+
filedata['x2min'] = float
|
|
69
|
+
coordinate minimum of root grid in x2 direction
|
|
70
|
+
filedata['x2max'] = float
|
|
71
|
+
coordinate maximum of root grid in x2 direction
|
|
72
|
+
filedata['x3min'] = float
|
|
73
|
+
coordinate minimum of root grid in x3 direction
|
|
74
|
+
filedata['x3max'] = float
|
|
75
|
+
coordinate maximum of root grid in x3 direction
|
|
76
|
+
filedata['nvars'] = int
|
|
77
|
+
number of output variables (including magnetic field if it exists)
|
|
78
|
+
filedata['mb_index'] = array with shape [n_mbs, 6]
|
|
79
|
+
is,ie,js,je,ks,ke range for output MeshBlock indexing (useful for slicing)
|
|
80
|
+
filedata['mb_logical'] = array with shape [n_mbs, 4]
|
|
81
|
+
i,j,k,level coordinates for each MeshBlock
|
|
82
|
+
filedata['mb_geometry'] = array with shape [n_mbs, 6]
|
|
83
|
+
x1i,x2i,x3i,dx1,dx2,dx3 including cell-centered location of left-most
|
|
84
|
+
cell and offsets between cells
|
|
85
|
+
filedata['mb_data'] = dict of arrays with shape [n_mbs, nx3, nx2, nx1]
|
|
86
|
+
{'var1':var1_array, 'var2':var2_array, ...} dictionary of fluid data arrays
|
|
87
|
+
for each variable in var_names
|
|
88
|
+
"""
|
|
89
|
+
|
|
90
|
+
import numpy as np
|
|
91
|
+
import os
|
|
92
|
+
import h5py
|
|
93
|
+
import glob
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def read_binary(filename):
|
|
97
|
+
"""
|
|
98
|
+
Reads a bin file from filename to dictionary.
|
|
99
|
+
|
|
100
|
+
Originally written by Lev Arzamasskiy (leva@ias.edu) on 11/15/2021
|
|
101
|
+
Updated to support mesh refinement by George Wong (gnwong@ias.edu) on 01/27/2022
|
|
102
|
+
Made faster by Drummond Fielding on 09/09/2024
|
|
103
|
+
|
|
104
|
+
args:
|
|
105
|
+
filename - string
|
|
106
|
+
filename of bin file to read
|
|
107
|
+
|
|
108
|
+
returns:
|
|
109
|
+
filedata - dict
|
|
110
|
+
dictionary of fluid file data
|
|
111
|
+
"""
|
|
112
|
+
|
|
113
|
+
filedata = {}
|
|
114
|
+
|
|
115
|
+
# load file and get size
|
|
116
|
+
fp = open(filename, "rb")
|
|
117
|
+
fp.seek(0, 2)
|
|
118
|
+
filesize = fp.tell()
|
|
119
|
+
fp.seek(0, 0)
|
|
120
|
+
|
|
121
|
+
# load header information and validate file format
|
|
122
|
+
code_header = fp.readline().split()
|
|
123
|
+
if len(code_header) < 1:
|
|
124
|
+
raise TypeError("unknown file format")
|
|
125
|
+
if code_header[0] != b"Athena":
|
|
126
|
+
raise TypeError(
|
|
127
|
+
f"bad file format \"{code_header[0].decode('utf-8')}\" "
|
|
128
|
+
+ '(should be "Athena")'
|
|
129
|
+
)
|
|
130
|
+
version = code_header[-1].split(b"=")[-1]
|
|
131
|
+
if version != b"1.1":
|
|
132
|
+
raise TypeError(f"unsupported file format version {version.decode('utf-8')}")
|
|
133
|
+
|
|
134
|
+
pheader_count = int(fp.readline().split(b"=")[-1])
|
|
135
|
+
pheader = {}
|
|
136
|
+
for _ in range(pheader_count - 1):
|
|
137
|
+
key, val = [x.strip() for x in fp.readline().decode("utf-8").split("=")]
|
|
138
|
+
pheader[key] = val
|
|
139
|
+
time = float(pheader["time"])
|
|
140
|
+
cycle = int(pheader["cycle"])
|
|
141
|
+
locsizebytes = int(pheader["size of location"])
|
|
142
|
+
varsizebytes = int(pheader["size of variable"])
|
|
143
|
+
|
|
144
|
+
nvars = int(fp.readline().split(b"=")[-1])
|
|
145
|
+
var_list = [v.decode("utf-8") for v in fp.readline().split()[1:]]
|
|
146
|
+
header_size = int(fp.readline().split(b"=")[-1])
|
|
147
|
+
header = [
|
|
148
|
+
line.decode("utf-8").split("#")[0].strip()
|
|
149
|
+
for line in fp.read(header_size).split(b"\n")
|
|
150
|
+
]
|
|
151
|
+
header = [line for line in header if len(line) > 0]
|
|
152
|
+
|
|
153
|
+
if locsizebytes not in [4, 8]:
|
|
154
|
+
raise ValueError(f"unsupported location size (in bytes) {locsizebytes}")
|
|
155
|
+
if varsizebytes not in [4, 8]:
|
|
156
|
+
raise ValueError(f"unsupported variable size (in bytes) {varsizebytes}")
|
|
157
|
+
|
|
158
|
+
locfmt = "d" if locsizebytes == 8 else "f"
|
|
159
|
+
varfmt = "d" if varsizebytes == 8 else "f"
|
|
160
|
+
|
|
161
|
+
# load grid information from header and validate
|
|
162
|
+
def get_from_header(header, blockname, keyname):
|
|
163
|
+
blockname = blockname.strip()
|
|
164
|
+
keyname = keyname.strip()
|
|
165
|
+
if not blockname.startswith("<"):
|
|
166
|
+
blockname = "<" + blockname
|
|
167
|
+
if blockname[-1] != ">":
|
|
168
|
+
blockname += ">"
|
|
169
|
+
block = "<none>"
|
|
170
|
+
for line in [entry for entry in header]:
|
|
171
|
+
if line.startswith("<"):
|
|
172
|
+
block = line
|
|
173
|
+
continue
|
|
174
|
+
key, value = line.split("=")
|
|
175
|
+
if block == blockname and key.strip() == keyname:
|
|
176
|
+
return value
|
|
177
|
+
raise KeyError(f"no parameter called {blockname}/{keyname}")
|
|
178
|
+
|
|
179
|
+
Nx1 = int(get_from_header(header, "<mesh>", "nx1"))
|
|
180
|
+
Nx2 = int(get_from_header(header, "<mesh>", "nx2"))
|
|
181
|
+
Nx3 = int(get_from_header(header, "<mesh>", "nx3"))
|
|
182
|
+
nx1 = int(get_from_header(header, "<meshblock>", "nx1"))
|
|
183
|
+
nx2 = int(get_from_header(header, "<meshblock>", "nx2"))
|
|
184
|
+
nx3 = int(get_from_header(header, "<meshblock>", "nx3"))
|
|
185
|
+
|
|
186
|
+
nghost = int(get_from_header(header, "<mesh>", "nghost"))
|
|
187
|
+
|
|
188
|
+
x1min = float(get_from_header(header, "<mesh>", "x1min"))
|
|
189
|
+
x1max = float(get_from_header(header, "<mesh>", "x1max"))
|
|
190
|
+
x2min = float(get_from_header(header, "<mesh>", "x2min"))
|
|
191
|
+
x2max = float(get_from_header(header, "<mesh>", "x2max"))
|
|
192
|
+
x3min = float(get_from_header(header, "<mesh>", "x3min"))
|
|
193
|
+
x3max = float(get_from_header(header, "<mesh>", "x3max"))
|
|
194
|
+
|
|
195
|
+
# load data from each meshblock
|
|
196
|
+
n_vars = len(var_list)
|
|
197
|
+
mb_count = 0
|
|
198
|
+
|
|
199
|
+
mb_index = []
|
|
200
|
+
mb_logical = []
|
|
201
|
+
mb_geometry = []
|
|
202
|
+
|
|
203
|
+
mb_data = {}
|
|
204
|
+
for var in var_list:
|
|
205
|
+
mb_data[var] = []
|
|
206
|
+
while fp.tell() < filesize:
|
|
207
|
+
mb_index.append(
|
|
208
|
+
np.frombuffer(fp.read(24), dtype=np.int32).astype(np.int64) - nghost
|
|
209
|
+
)
|
|
210
|
+
nx1_out = (mb_index[mb_count][1] - mb_index[mb_count][0]) + 1
|
|
211
|
+
nx2_out = (mb_index[mb_count][3] - mb_index[mb_count][2]) + 1
|
|
212
|
+
nx3_out = (mb_index[mb_count][5] - mb_index[mb_count][4]) + 1
|
|
213
|
+
mb_logical.append(np.frombuffer(fp.read(16), dtype=np.int32))
|
|
214
|
+
mb_geometry.append(
|
|
215
|
+
np.frombuffer(
|
|
216
|
+
fp.read(6 * locsizebytes),
|
|
217
|
+
dtype=np.float64 if locfmt == "d" else np.float32,
|
|
218
|
+
)
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
data = np.fromfile(
|
|
222
|
+
fp,
|
|
223
|
+
dtype=np.float64 if varfmt == "d" else np.float32,
|
|
224
|
+
count=nx1_out * nx2_out * nx3_out * n_vars,
|
|
225
|
+
)
|
|
226
|
+
data = data.reshape(nvars, nx3_out, nx2_out, nx1_out)
|
|
227
|
+
for vari, var in enumerate(var_list):
|
|
228
|
+
mb_data[var].append(data[vari])
|
|
229
|
+
mb_count += 1
|
|
230
|
+
|
|
231
|
+
fp.close()
|
|
232
|
+
|
|
233
|
+
filedata["header"] = header
|
|
234
|
+
filedata["time"] = time
|
|
235
|
+
filedata["cycle"] = cycle
|
|
236
|
+
filedata["var_names"] = var_list
|
|
237
|
+
|
|
238
|
+
filedata["Nx1"] = Nx1
|
|
239
|
+
filedata["Nx2"] = Nx2
|
|
240
|
+
filedata["Nx3"] = Nx3
|
|
241
|
+
filedata["nvars"] = nvars
|
|
242
|
+
|
|
243
|
+
filedata["x1min"] = x1min
|
|
244
|
+
filedata["x1max"] = x1max
|
|
245
|
+
filedata["x2min"] = x2min
|
|
246
|
+
filedata["x2max"] = x2max
|
|
247
|
+
filedata["x3min"] = x3min
|
|
248
|
+
filedata["x3max"] = x3max
|
|
249
|
+
|
|
250
|
+
filedata["n_mbs"] = mb_count
|
|
251
|
+
filedata["nx1_mb"] = nx1
|
|
252
|
+
filedata["nx2_mb"] = nx2
|
|
253
|
+
filedata["nx3_mb"] = nx3
|
|
254
|
+
filedata["nx1_out_mb"] = (mb_index[0][1] - mb_index[0][0]) + 1
|
|
255
|
+
filedata["nx2_out_mb"] = (mb_index[0][3] - mb_index[0][2]) + 1
|
|
256
|
+
filedata["nx3_out_mb"] = (mb_index[0][5] - mb_index[0][4]) + 1
|
|
257
|
+
|
|
258
|
+
filedata["mb_index"] = np.array(mb_index)
|
|
259
|
+
filedata["mb_logical"] = np.array(mb_logical)
|
|
260
|
+
filedata["mb_geometry"] = np.array(mb_geometry)
|
|
261
|
+
filedata["mb_data"] = mb_data
|
|
262
|
+
|
|
263
|
+
return filedata
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def read_coarsened_binary(filename):
|
|
267
|
+
"""
|
|
268
|
+
Reads a coarsened bin file from filename to dictionary.
|
|
269
|
+
Originally written by Lev Arzamasskiy (leva@ias.edu) on 11/15/2021
|
|
270
|
+
Updated to support mesh refinement by George Wong (gnwong@ias.edu) on 01/27/2022
|
|
271
|
+
Updated to support coarsened outputs and for speed by Drummond Fielding on 09/09/2024
|
|
272
|
+
|
|
273
|
+
args:
|
|
274
|
+
filename - string
|
|
275
|
+
filename of bin file to read
|
|
276
|
+
|
|
277
|
+
returns:
|
|
278
|
+
filedata - dict
|
|
279
|
+
dictionary of fluid file data
|
|
280
|
+
"""
|
|
281
|
+
|
|
282
|
+
filedata = {}
|
|
283
|
+
|
|
284
|
+
# load file and get size
|
|
285
|
+
fp = open(filename, "rb")
|
|
286
|
+
fp.seek(0, 2)
|
|
287
|
+
filesize = fp.tell()
|
|
288
|
+
fp.seek(0, 0)
|
|
289
|
+
|
|
290
|
+
# load header information and validate file format
|
|
291
|
+
code_header = fp.readline().split()
|
|
292
|
+
if len(code_header) < 1:
|
|
293
|
+
raise TypeError("unknown file format")
|
|
294
|
+
if code_header[0] != b"Athena":
|
|
295
|
+
raise TypeError(
|
|
296
|
+
f"bad file format \"{code_header[0].decode('utf-8')}\" "
|
|
297
|
+
+ '(should be "Athena")'
|
|
298
|
+
)
|
|
299
|
+
version = code_header[-1].split(b"=")[-1]
|
|
300
|
+
if version != b"1.1":
|
|
301
|
+
raise TypeError(f"unsupported file format version {version.decode('utf-8')}")
|
|
302
|
+
|
|
303
|
+
pheader_count = int(fp.readline().split(b"=")[-1])
|
|
304
|
+
pheader = {}
|
|
305
|
+
for _ in range(pheader_count - 1):
|
|
306
|
+
key, val = [x.strip() for x in fp.readline().decode("utf-8").split("=")]
|
|
307
|
+
pheader[key] = val
|
|
308
|
+
time = float(pheader["time"])
|
|
309
|
+
cycle = int(pheader["cycle"])
|
|
310
|
+
locsizebytes = int(pheader["size of location"])
|
|
311
|
+
varsizebytes = int(pheader["size of variable"])
|
|
312
|
+
coarsen_factor = int(pheader["coarsening factor"])
|
|
313
|
+
|
|
314
|
+
nvars = int(fp.readline().split(b"=")[-1])
|
|
315
|
+
var_list = [v.decode("utf-8") for v in fp.readline().split()[1:]]
|
|
316
|
+
header_size = int(fp.readline().split(b"=")[-1])
|
|
317
|
+
header = [
|
|
318
|
+
line.decode("utf-8").split("#")[0].strip()
|
|
319
|
+
for line in fp.read(header_size).split(b"\n")
|
|
320
|
+
]
|
|
321
|
+
header = [line for line in header if len(line) > 0]
|
|
322
|
+
|
|
323
|
+
if locsizebytes not in [4, 8]:
|
|
324
|
+
raise ValueError(f"unsupported location size (in bytes) {locsizebytes}")
|
|
325
|
+
if varsizebytes not in [4, 8]:
|
|
326
|
+
raise ValueError(f"unsupported variable size (in bytes) {varsizebytes}")
|
|
327
|
+
|
|
328
|
+
locfmt = "d" if locsizebytes == 8 else "f"
|
|
329
|
+
varfmt = "d" if varsizebytes == 8 else "f"
|
|
330
|
+
|
|
331
|
+
# load grid information from header and validate
|
|
332
|
+
def get_from_header(header, blockname, keyname):
|
|
333
|
+
blockname = blockname.strip()
|
|
334
|
+
keyname = keyname.strip()
|
|
335
|
+
if not blockname.startswith("<"):
|
|
336
|
+
blockname = "<" + blockname
|
|
337
|
+
if blockname[-1] != ">":
|
|
338
|
+
blockname += ">"
|
|
339
|
+
block = "<none>"
|
|
340
|
+
for line in [entry for entry in header]:
|
|
341
|
+
if line.startswith("<"):
|
|
342
|
+
block = line
|
|
343
|
+
continue
|
|
344
|
+
key, value = line.split("=")
|
|
345
|
+
if block == blockname and key.strip() == keyname:
|
|
346
|
+
return value
|
|
347
|
+
raise KeyError(f"no parameter called {blockname}/{keyname}")
|
|
348
|
+
|
|
349
|
+
Nx1 = int(get_from_header(header, "<mesh>", "nx1"))
|
|
350
|
+
Nx2 = int(get_from_header(header, "<mesh>", "nx2"))
|
|
351
|
+
Nx3 = int(get_from_header(header, "<mesh>", "nx3"))
|
|
352
|
+
nx1 = int(get_from_header(header, "<meshblock>", "nx1"))
|
|
353
|
+
nx2 = int(get_from_header(header, "<meshblock>", "nx2"))
|
|
354
|
+
nx3 = int(get_from_header(header, "<meshblock>", "nx3"))
|
|
355
|
+
|
|
356
|
+
nghost = int(get_from_header(header, "<mesh>", "nghost"))
|
|
357
|
+
|
|
358
|
+
x1min = float(get_from_header(header, "<mesh>", "x1min"))
|
|
359
|
+
x1max = float(get_from_header(header, "<mesh>", "x1max"))
|
|
360
|
+
x2min = float(get_from_header(header, "<mesh>", "x2min"))
|
|
361
|
+
x2max = float(get_from_header(header, "<mesh>", "x2max"))
|
|
362
|
+
x3min = float(get_from_header(header, "<mesh>", "x3min"))
|
|
363
|
+
x3max = float(get_from_header(header, "<mesh>", "x3max"))
|
|
364
|
+
|
|
365
|
+
# load data from each meshblock
|
|
366
|
+
n_vars = len(var_list)
|
|
367
|
+
mb_count = 0
|
|
368
|
+
|
|
369
|
+
mb_index = []
|
|
370
|
+
mb_logical = []
|
|
371
|
+
mb_geometry = []
|
|
372
|
+
|
|
373
|
+
mb_data = {}
|
|
374
|
+
for var in var_list:
|
|
375
|
+
mb_data[var] = []
|
|
376
|
+
while fp.tell() < filesize:
|
|
377
|
+
mb_index_i = (
|
|
378
|
+
np.frombuffer(fp.read(24), dtype=np.int32).astype(np.int64) - nghost
|
|
379
|
+
)
|
|
380
|
+
mb_index.append(mb_index_i)
|
|
381
|
+
nx1_out = (mb_index_i[1] - mb_index_i[0]) + 1
|
|
382
|
+
nx2_out = (mb_index_i[3] - mb_index_i[2]) + 1
|
|
383
|
+
nx3_out = (mb_index_i[5] - mb_index_i[4]) + 1
|
|
384
|
+
|
|
385
|
+
mb_logical.append(np.frombuffer(fp.read(16), dtype=np.int32))
|
|
386
|
+
mb_geometry.append(
|
|
387
|
+
np.frombuffer(
|
|
388
|
+
fp.read(6 * locsizebytes),
|
|
389
|
+
dtype=np.float64 if locfmt == "d" else np.float32,
|
|
390
|
+
)
|
|
391
|
+
)
|
|
392
|
+
|
|
393
|
+
data = np.fromfile(
|
|
394
|
+
fp,
|
|
395
|
+
dtype=np.float64 if varfmt == "d" else np.float32,
|
|
396
|
+
count=nx1_out * nx2_out * nx3_out * n_vars,
|
|
397
|
+
)
|
|
398
|
+
data = data.reshape(nvars, nx3_out, nx2_out, nx1_out)
|
|
399
|
+
for vari, var in enumerate(var_list):
|
|
400
|
+
mb_data[var].append(data[vari])
|
|
401
|
+
mb_count += 1
|
|
402
|
+
|
|
403
|
+
fp.close()
|
|
404
|
+
|
|
405
|
+
filedata["header"] = header
|
|
406
|
+
filedata["time"] = time
|
|
407
|
+
filedata["cycle"] = cycle
|
|
408
|
+
filedata["var_names"] = var_list
|
|
409
|
+
|
|
410
|
+
filedata["Nx1"] = Nx1 // coarsen_factor
|
|
411
|
+
filedata["Nx2"] = Nx2 // coarsen_factor
|
|
412
|
+
filedata["Nx3"] = Nx3 // coarsen_factor
|
|
413
|
+
filedata["nvars"] = nvars
|
|
414
|
+
filedata["number_of_moments"] = int(pheader["number of moments"])
|
|
415
|
+
|
|
416
|
+
filedata["x1min"] = x1min
|
|
417
|
+
filedata["x1max"] = x1max
|
|
418
|
+
filedata["x2min"] = x2min
|
|
419
|
+
filedata["x2max"] = x2max
|
|
420
|
+
filedata["x3min"] = x3min
|
|
421
|
+
filedata["x3max"] = x3max
|
|
422
|
+
|
|
423
|
+
filedata["n_mbs"] = mb_count
|
|
424
|
+
filedata["nx1_mb"] = nx1 // coarsen_factor
|
|
425
|
+
filedata["nx2_mb"] = nx2 // coarsen_factor
|
|
426
|
+
filedata["nx3_mb"] = nx3 // coarsen_factor
|
|
427
|
+
filedata["nx1_out_mb"] = (mb_index[0][1] - mb_index[0][0]) + 1
|
|
428
|
+
filedata["nx2_out_mb"] = (mb_index[0][3] - mb_index[0][2]) + 1
|
|
429
|
+
filedata["nx3_out_mb"] = (mb_index[0][5] - mb_index[0][4]) + 1
|
|
430
|
+
|
|
431
|
+
filedata["mb_index"] = np.array(mb_index)
|
|
432
|
+
filedata["mb_logical"] = np.array(mb_logical)
|
|
433
|
+
filedata["mb_geometry"] = np.array(mb_geometry)
|
|
434
|
+
filedata["mb_data"] = mb_data
|
|
435
|
+
|
|
436
|
+
return filedata
|
|
437
|
+
|
|
438
|
+
|
|
439
|
+
def read_all_ranks_binary(rank0_filename):
|
|
440
|
+
"""
|
|
441
|
+
Reads binary files from all ranks and combines them into a single dictionary.
|
|
442
|
+
|
|
443
|
+
args:
|
|
444
|
+
rank0_filename - string
|
|
445
|
+
filename of the rank 0 binary file
|
|
446
|
+
|
|
447
|
+
returns:
|
|
448
|
+
combined_filedata - dict
|
|
449
|
+
dictionary of combined fluid file data from all ranks
|
|
450
|
+
"""
|
|
451
|
+
# Determine the directory and base filename pattern
|
|
452
|
+
# rank0_dir = os.path.dirname(rank0_filename)
|
|
453
|
+
# rank0_base = os.path.basename(rank0_filename).replace("rank_00000000", "rank_*")
|
|
454
|
+
# Find all rank files
|
|
455
|
+
rank_files = sorted(
|
|
456
|
+
glob.glob(
|
|
457
|
+
os.path.dirname(rank0_filename).replace("rank_00000000", "rank_*")
|
|
458
|
+
+ "/"
|
|
459
|
+
+ os.path.basename(rank0_filename)
|
|
460
|
+
)
|
|
461
|
+
)
|
|
462
|
+
file_sizes = np.array([os.path.getsize(file) for file in rank_files])
|
|
463
|
+
if len(np.unique(file_sizes)) > 1:
|
|
464
|
+
unique_file_sizes = np.unique(file_sizes)
|
|
465
|
+
larger_file_size = max(unique_file_sizes)
|
|
466
|
+
rank_files = [
|
|
467
|
+
file
|
|
468
|
+
for file, size in zip(rank_files, file_sizes)
|
|
469
|
+
if size == larger_file_size
|
|
470
|
+
]
|
|
471
|
+
|
|
472
|
+
# Read the rank 0 file to get the metadata
|
|
473
|
+
rank0_filedata = read_binary(rank_files[0])
|
|
474
|
+
|
|
475
|
+
# Initialize combined filedata with rank 0 data
|
|
476
|
+
combined_filedata = rank0_filedata.copy()
|
|
477
|
+
|
|
478
|
+
# Initialize lists to hold combined data
|
|
479
|
+
combined_filedata["mb_index"] = []
|
|
480
|
+
combined_filedata["mb_logical"] = []
|
|
481
|
+
combined_filedata["mb_geometry"] = []
|
|
482
|
+
combined_filedata["mb_data"] = {var: [] for var in rank0_filedata["var_names"]}
|
|
483
|
+
|
|
484
|
+
# Read data from all ranks
|
|
485
|
+
for rank_filename in rank_files:
|
|
486
|
+
rank_filedata = read_binary(rank_filename)
|
|
487
|
+
|
|
488
|
+
combined_filedata["mb_index"].extend(rank_filedata["mb_index"])
|
|
489
|
+
combined_filedata["mb_logical"].extend(rank_filedata["mb_logical"])
|
|
490
|
+
combined_filedata["mb_geometry"].extend(rank_filedata["mb_geometry"])
|
|
491
|
+
for var in rank0_filedata["var_names"]:
|
|
492
|
+
combined_filedata["mb_data"][var].extend(rank_filedata["mb_data"][var])
|
|
493
|
+
|
|
494
|
+
# Convert lists to numpy arrays
|
|
495
|
+
combined_filedata["mb_index"] = np.array(combined_filedata["mb_index"])
|
|
496
|
+
combined_filedata["mb_logical"] = np.array(combined_filedata["mb_logical"])
|
|
497
|
+
combined_filedata["mb_geometry"] = np.array(combined_filedata["mb_geometry"])
|
|
498
|
+
for var in rank0_filedata["var_names"]:
|
|
499
|
+
combined_filedata["mb_data"][var] = np.array(combined_filedata["mb_data"][var])
|
|
500
|
+
|
|
501
|
+
# Ensure all relevant fields are stored
|
|
502
|
+
combined_filedata["header"] = rank0_filedata["header"]
|
|
503
|
+
combined_filedata["time"] = rank0_filedata["time"]
|
|
504
|
+
combined_filedata["cycle"] = rank0_filedata["cycle"]
|
|
505
|
+
combined_filedata["var_names"] = rank0_filedata["var_names"]
|
|
506
|
+
combined_filedata["Nx1"] = rank0_filedata["Nx1"]
|
|
507
|
+
combined_filedata["Nx2"] = rank0_filedata["Nx2"]
|
|
508
|
+
combined_filedata["Nx3"] = rank0_filedata["Nx3"]
|
|
509
|
+
combined_filedata["nvars"] = rank0_filedata["nvars"]
|
|
510
|
+
combined_filedata["x1min"] = rank0_filedata["x1min"]
|
|
511
|
+
combined_filedata["x1max"] = rank0_filedata["x1max"]
|
|
512
|
+
combined_filedata["x2min"] = rank0_filedata["x2min"]
|
|
513
|
+
combined_filedata["x2max"] = rank0_filedata["x2max"]
|
|
514
|
+
combined_filedata["x3min"] = rank0_filedata["x3min"]
|
|
515
|
+
combined_filedata["x3max"] = rank0_filedata["x3max"]
|
|
516
|
+
combined_filedata["n_mbs"] = len(combined_filedata["mb_index"])
|
|
517
|
+
combined_filedata["nx1_mb"] = rank0_filedata["nx1_mb"]
|
|
518
|
+
combined_filedata["nx2_mb"] = rank0_filedata["nx2_mb"]
|
|
519
|
+
combined_filedata["nx3_mb"] = rank0_filedata["nx3_mb"]
|
|
520
|
+
combined_filedata["nx1_out_mb"] = rank0_filedata["nx1_out_mb"]
|
|
521
|
+
combined_filedata["nx2_out_mb"] = rank0_filedata["nx2_out_mb"]
|
|
522
|
+
combined_filedata["nx3_out_mb"] = rank0_filedata["nx3_out_mb"]
|
|
523
|
+
|
|
524
|
+
return combined_filedata
|
|
525
|
+
|
|
526
|
+
|
|
527
|
+
def read_all_ranks_coarsened_binary(rank0_filename):
|
|
528
|
+
"""
|
|
529
|
+
Reads binary files from all ranks and combines them into a single dictionary.
|
|
530
|
+
|
|
531
|
+
args:
|
|
532
|
+
rank0_filename - string
|
|
533
|
+
filename of the rank 0 binary file
|
|
534
|
+
|
|
535
|
+
returns:
|
|
536
|
+
combined_filedata - dict
|
|
537
|
+
dictionary of combined fluid file data from all ranks
|
|
538
|
+
"""
|
|
539
|
+
# Determine the directory and base filename pattern
|
|
540
|
+
# rank0_dir = os.path.dirname(rank0_filename)
|
|
541
|
+
# rank0_base = os.path.basename(rank0_filename).replace("rank_00000000", "rank_*")
|
|
542
|
+
|
|
543
|
+
# Find all rank files
|
|
544
|
+
rank_files = sorted(
|
|
545
|
+
glob.glob(
|
|
546
|
+
os.path.dirname(rank0_filename).replace("rank_00000000", "rank_*")
|
|
547
|
+
+ "/"
|
|
548
|
+
+ os.path.basename(rank0_filename)
|
|
549
|
+
)
|
|
550
|
+
)
|
|
551
|
+
# print(rank_files)
|
|
552
|
+
|
|
553
|
+
# Read the rank 0 file to get the metadata
|
|
554
|
+
rank0_filedata = read_coarsened_binary(rank0_filename)
|
|
555
|
+
|
|
556
|
+
# Initialize combined filedata with rank 0 data
|
|
557
|
+
combined_filedata = rank0_filedata.copy()
|
|
558
|
+
|
|
559
|
+
# Initialize lists to hold combined data
|
|
560
|
+
combined_filedata["mb_index"] = []
|
|
561
|
+
combined_filedata["mb_logical"] = []
|
|
562
|
+
combined_filedata["mb_geometry"] = []
|
|
563
|
+
combined_filedata["mb_data"] = {var: [] for var in rank0_filedata["var_names"]}
|
|
564
|
+
|
|
565
|
+
# Read data from all ranks
|
|
566
|
+
for rank_filename in rank_files:
|
|
567
|
+
rank_filedata = read_coarsened_binary(rank_filename)
|
|
568
|
+
|
|
569
|
+
combined_filedata["mb_index"].extend(rank_filedata["mb_index"])
|
|
570
|
+
combined_filedata["mb_logical"].extend(rank_filedata["mb_logical"])
|
|
571
|
+
combined_filedata["mb_geometry"].extend(rank_filedata["mb_geometry"])
|
|
572
|
+
for var in rank0_filedata["var_names"]:
|
|
573
|
+
combined_filedata["mb_data"][var].extend(rank_filedata["mb_data"][var])
|
|
574
|
+
|
|
575
|
+
# Convert lists to numpy arrays
|
|
576
|
+
combined_filedata["mb_index"] = np.array(combined_filedata["mb_index"])
|
|
577
|
+
combined_filedata["mb_logical"] = np.array(combined_filedata["mb_logical"])
|
|
578
|
+
combined_filedata["mb_geometry"] = np.array(combined_filedata["mb_geometry"])
|
|
579
|
+
for var in rank0_filedata["var_names"]:
|
|
580
|
+
combined_filedata["mb_data"][var] = np.array(combined_filedata["mb_data"][var])
|
|
581
|
+
|
|
582
|
+
# Ensure all relevant fields are stored
|
|
583
|
+
combined_filedata["header"] = rank0_filedata["header"]
|
|
584
|
+
combined_filedata["time"] = rank0_filedata["time"]
|
|
585
|
+
combined_filedata["cycle"] = rank0_filedata["cycle"]
|
|
586
|
+
combined_filedata["var_names"] = rank0_filedata["var_names"]
|
|
587
|
+
combined_filedata["Nx1"] = rank0_filedata["Nx1"]
|
|
588
|
+
combined_filedata["Nx2"] = rank0_filedata["Nx2"]
|
|
589
|
+
combined_filedata["Nx3"] = rank0_filedata["Nx3"]
|
|
590
|
+
combined_filedata["nvars"] = rank0_filedata["nvars"]
|
|
591
|
+
combined_filedata["x1min"] = rank0_filedata["x1min"]
|
|
592
|
+
combined_filedata["x1max"] = rank0_filedata["x1max"]
|
|
593
|
+
combined_filedata["x2min"] = rank0_filedata["x2min"]
|
|
594
|
+
combined_filedata["x2max"] = rank0_filedata["x2max"]
|
|
595
|
+
combined_filedata["x3min"] = rank0_filedata["x3min"]
|
|
596
|
+
combined_filedata["x3max"] = rank0_filedata["x3max"]
|
|
597
|
+
combined_filedata["n_mbs"] = len(combined_filedata["mb_index"])
|
|
598
|
+
combined_filedata["nx1_mb"] = rank0_filedata["nx1_mb"]
|
|
599
|
+
combined_filedata["nx2_mb"] = rank0_filedata["nx2_mb"]
|
|
600
|
+
combined_filedata["nx3_mb"] = rank0_filedata["nx3_mb"]
|
|
601
|
+
combined_filedata["nx1_out_mb"] = rank0_filedata["nx1_out_mb"]
|
|
602
|
+
combined_filedata["nx2_out_mb"] = rank0_filedata["nx2_out_mb"]
|
|
603
|
+
combined_filedata["nx3_out_mb"] = rank0_filedata["nx3_out_mb"]
|
|
604
|
+
|
|
605
|
+
return combined_filedata
|
|
606
|
+
|
|
607
|
+
|
|
608
|
+
def read_binary_as_athdf(
|
|
609
|
+
filename,
|
|
610
|
+
raw=False,
|
|
611
|
+
data=None,
|
|
612
|
+
quantities=None,
|
|
613
|
+
dtype=None,
|
|
614
|
+
level=None,
|
|
615
|
+
return_levels=False,
|
|
616
|
+
subsample=False,
|
|
617
|
+
fast_restrict=False,
|
|
618
|
+
x1_min=None,
|
|
619
|
+
x1_max=None,
|
|
620
|
+
x2_min=None,
|
|
621
|
+
x2_max=None,
|
|
622
|
+
x3_min=None,
|
|
623
|
+
x3_max=None,
|
|
624
|
+
vol_func=None,
|
|
625
|
+
vol_params=None,
|
|
626
|
+
face_func_1=None,
|
|
627
|
+
face_func_2=None,
|
|
628
|
+
face_func_3=None,
|
|
629
|
+
center_func_1=None,
|
|
630
|
+
center_func_2=None,
|
|
631
|
+
center_func_3=None,
|
|
632
|
+
num_ghost=0,
|
|
633
|
+
):
|
|
634
|
+
"""
|
|
635
|
+
Reads a bin file and organizes data similar to athdf format without writing to file.
|
|
636
|
+
"""
|
|
637
|
+
# Step 1: Read binary data
|
|
638
|
+
filedata = read_binary(filename)
|
|
639
|
+
|
|
640
|
+
# Step 2: Organize data similar to athdf
|
|
641
|
+
if raw:
|
|
642
|
+
return filedata
|
|
643
|
+
|
|
644
|
+
# Prepare dictionary for results
|
|
645
|
+
if data is None:
|
|
646
|
+
data = {}
|
|
647
|
+
new_data = True
|
|
648
|
+
else:
|
|
649
|
+
new_data = False
|
|
650
|
+
|
|
651
|
+
# Extract size information
|
|
652
|
+
max_level = max(filedata["mb_logical"][:, 3])
|
|
653
|
+
if level is None:
|
|
654
|
+
level = max_level
|
|
655
|
+
block_size = [
|
|
656
|
+
filedata["nx1_out_mb"],
|
|
657
|
+
filedata["nx2_out_mb"],
|
|
658
|
+
filedata["nx3_out_mb"],
|
|
659
|
+
]
|
|
660
|
+
root_grid_size = [filedata["Nx1"], filedata["Nx2"], filedata["Nx3"]]
|
|
661
|
+
levels = filedata["mb_logical"][:, 3]
|
|
662
|
+
logical_locations = filedata["mb_logical"][:, :3]
|
|
663
|
+
if dtype is None:
|
|
664
|
+
dtype = np.float32
|
|
665
|
+
|
|
666
|
+
# Calculate nx_vals
|
|
667
|
+
nx_vals = []
|
|
668
|
+
for d in range(3):
|
|
669
|
+
if block_size[d] == 1 and root_grid_size[d] > 1: # sum or slice
|
|
670
|
+
other_locations = [
|
|
671
|
+
location
|
|
672
|
+
for location in zip(
|
|
673
|
+
levels,
|
|
674
|
+
logical_locations[:, (d + 1) % 3],
|
|
675
|
+
logical_locations[:, (d + 2) % 3],
|
|
676
|
+
)
|
|
677
|
+
]
|
|
678
|
+
if len(set(other_locations)) == len(other_locations): # effective slice
|
|
679
|
+
nx_vals.append(1)
|
|
680
|
+
else: # nontrivial sum
|
|
681
|
+
num_blocks_this_dim = 0
|
|
682
|
+
for level_this_dim, loc_this_dim in zip(
|
|
683
|
+
levels, logical_locations[:, d]
|
|
684
|
+
):
|
|
685
|
+
if level_this_dim <= level:
|
|
686
|
+
possible_max = (loc_this_dim + 1) * 2 ** (
|
|
687
|
+
level - level_this_dim
|
|
688
|
+
)
|
|
689
|
+
num_blocks_this_dim = max(num_blocks_this_dim, possible_max)
|
|
690
|
+
else:
|
|
691
|
+
possible_max = (loc_this_dim + 1) // 2 ** (
|
|
692
|
+
level_this_dim - level
|
|
693
|
+
)
|
|
694
|
+
num_blocks_this_dim = max(num_blocks_this_dim, possible_max)
|
|
695
|
+
nx_vals.append(num_blocks_this_dim)
|
|
696
|
+
elif block_size[d] == 1: # singleton dimension
|
|
697
|
+
nx_vals.append(1)
|
|
698
|
+
else: # normal case
|
|
699
|
+
nx_vals.append(root_grid_size[d] * 2**level + 2 * num_ghost)
|
|
700
|
+
nx1, nx2, nx3 = nx_vals
|
|
701
|
+
lx1, lx2, lx3 = [nx // bs for nx, bs in zip(nx_vals, block_size)]
|
|
702
|
+
|
|
703
|
+
# Set coordinate system and related functions
|
|
704
|
+
# coord = "cartesian" # Adjust based on your data
|
|
705
|
+
if vol_func is None:
|
|
706
|
+
|
|
707
|
+
def vol_func(xm, xp, ym, yp, zm, zp):
|
|
708
|
+
return (xp - xm) * (yp - ym) * (zp - zm)
|
|
709
|
+
|
|
710
|
+
# Define center functions if not provided
|
|
711
|
+
if center_func_1 is None:
|
|
712
|
+
|
|
713
|
+
def center_func_1(xm, xp):
|
|
714
|
+
return 0.5 * (xm + xp)
|
|
715
|
+
|
|
716
|
+
if center_func_2 is None:
|
|
717
|
+
|
|
718
|
+
def center_func_2(xm, xp):
|
|
719
|
+
return 0.5 * (xm + xp)
|
|
720
|
+
|
|
721
|
+
if center_func_3 is None:
|
|
722
|
+
|
|
723
|
+
def center_func_3(xm, xp):
|
|
724
|
+
return 0.5 * (xm + xp)
|
|
725
|
+
|
|
726
|
+
# Populate coordinate arrays
|
|
727
|
+
center_funcs = [center_func_1, center_func_2, center_func_3]
|
|
728
|
+
for d in range(1, 4):
|
|
729
|
+
xf = f"x{d}f"
|
|
730
|
+
xv = f"x{d}v"
|
|
731
|
+
nx = nx_vals[d - 1]
|
|
732
|
+
if nx == 1:
|
|
733
|
+
xmin = filedata[f"x{d}min"]
|
|
734
|
+
xmax = filedata[f"x{d}max"]
|
|
735
|
+
data[xf] = np.array([xmin, xmax], dtype=dtype)
|
|
736
|
+
else:
|
|
737
|
+
xmin = filedata[f"x{d}min"]
|
|
738
|
+
xmax = filedata[f"x{d}max"]
|
|
739
|
+
data[xf] = np.linspace(xmin, xmax, nx + 1, dtype=dtype)
|
|
740
|
+
data[xv] = np.empty(nx, dtype=dtype)
|
|
741
|
+
for i in range(nx):
|
|
742
|
+
data[xv][i] = center_funcs[d - 1](data[xf][i], data[xf][i + 1])
|
|
743
|
+
|
|
744
|
+
# Create list of quantities
|
|
745
|
+
if quantities is None:
|
|
746
|
+
quantities = filedata["var_names"]
|
|
747
|
+
|
|
748
|
+
# Account for selection
|
|
749
|
+
i_min, i_max = 0, nx1
|
|
750
|
+
j_min, j_max = 0, nx2
|
|
751
|
+
k_min, k_max = 0, nx3
|
|
752
|
+
if x1_min is not None:
|
|
753
|
+
i_min = max(i_min, np.searchsorted(data["x1f"], x1_min))
|
|
754
|
+
if x1_max is not None:
|
|
755
|
+
i_max = min(i_max, np.searchsorted(data["x1f"], x1_max))
|
|
756
|
+
if x2_min is not None:
|
|
757
|
+
j_min = max(j_min, np.searchsorted(data["x2f"], x2_min))
|
|
758
|
+
if x2_max is not None:
|
|
759
|
+
j_max = min(j_max, np.searchsorted(data["x2f"], x2_max))
|
|
760
|
+
if x3_min is not None:
|
|
761
|
+
k_min = max(k_min, np.searchsorted(data["x3f"], x3_min))
|
|
762
|
+
if x3_max is not None:
|
|
763
|
+
k_max = min(k_max, np.searchsorted(data["x3f"], x3_max))
|
|
764
|
+
|
|
765
|
+
# Prepare arrays for data and bookkeeping
|
|
766
|
+
if new_data:
|
|
767
|
+
for q in quantities:
|
|
768
|
+
data[q] = np.zeros(
|
|
769
|
+
(k_max - k_min, j_max - j_min, i_max - i_min), dtype=dtype
|
|
770
|
+
)
|
|
771
|
+
if return_levels:
|
|
772
|
+
data["Levels"] = np.empty(
|
|
773
|
+
(k_max - k_min, j_max - j_min, i_max - i_min), dtype=np.int32
|
|
774
|
+
)
|
|
775
|
+
else:
|
|
776
|
+
for q in quantities:
|
|
777
|
+
data[q].fill(0.0)
|
|
778
|
+
if not subsample and not fast_restrict and max_level > level:
|
|
779
|
+
restricted_data = np.zeros((lx3, lx2, lx1), dtype=bool)
|
|
780
|
+
|
|
781
|
+
# Step 3: Process each block
|
|
782
|
+
for block_num in range(filedata["n_mbs"]):
|
|
783
|
+
block_level = levels[block_num]
|
|
784
|
+
block_location = logical_locations[block_num]
|
|
785
|
+
|
|
786
|
+
# Implement logic for prolongation, restriction, subsampling
|
|
787
|
+
if block_level <= level:
|
|
788
|
+
s = 2 ** (level - block_level)
|
|
789
|
+
il_d = block_location[0] * block_size[0] * s if nx1 > 1 else 0
|
|
790
|
+
jl_d = block_location[1] * block_size[1] * s if nx2 > 1 else 0
|
|
791
|
+
kl_d = block_location[2] * block_size[2] * s if nx3 > 1 else 0
|
|
792
|
+
iu_d = il_d + block_size[0] * s if nx1 > 1 else 1
|
|
793
|
+
ju_d = jl_d + block_size[1] * s if nx2 > 1 else 1
|
|
794
|
+
ku_d = kl_d + block_size[2] * s if nx3 > 1 else 1
|
|
795
|
+
|
|
796
|
+
il_s = max(il_d, i_min) - il_d
|
|
797
|
+
jl_s = max(jl_d, j_min) - jl_d
|
|
798
|
+
kl_s = max(kl_d, k_min) - kl_d
|
|
799
|
+
iu_s = min(iu_d, i_max) - il_d
|
|
800
|
+
ju_s = min(ju_d, j_max) - jl_d
|
|
801
|
+
ku_s = min(ku_d, k_max) - kl_d
|
|
802
|
+
|
|
803
|
+
if il_s >= iu_s or jl_s >= ju_s or kl_s >= ku_s:
|
|
804
|
+
continue
|
|
805
|
+
|
|
806
|
+
il_d = max(il_d, i_min) - i_min
|
|
807
|
+
jl_d = max(jl_d, j_min) - j_min
|
|
808
|
+
kl_d = max(kl_d, k_min) - k_min
|
|
809
|
+
iu_d = min(iu_d, i_max) - i_min
|
|
810
|
+
ju_d = min(ju_d, j_max) - j_min
|
|
811
|
+
ku_d = min(ku_d, k_max) - k_min
|
|
812
|
+
|
|
813
|
+
for q in quantities:
|
|
814
|
+
block_data = filedata["mb_data"][q][block_num]
|
|
815
|
+
if s > 1:
|
|
816
|
+
block_data = np.repeat(
|
|
817
|
+
np.repeat(np.repeat(block_data, s, axis=2), s, axis=1),
|
|
818
|
+
s,
|
|
819
|
+
axis=0,
|
|
820
|
+
)
|
|
821
|
+
data[q][kl_d:ku_d, jl_d:ju_d, il_d:iu_d] = block_data[
|
|
822
|
+
kl_s:ku_s, jl_s:ju_s, il_s:iu_s
|
|
823
|
+
]
|
|
824
|
+
else:
|
|
825
|
+
# Implement restriction logic here (similar to athdf function)
|
|
826
|
+
pass
|
|
827
|
+
|
|
828
|
+
if return_levels:
|
|
829
|
+
data["Levels"][kl_d:ku_d, jl_d:ju_d, il_d:iu_d] = block_level
|
|
830
|
+
|
|
831
|
+
# Step 4: Finalize data
|
|
832
|
+
if level < max_level and not subsample and not fast_restrict:
|
|
833
|
+
# Remove volume factors from restricted data
|
|
834
|
+
for loc3 in range(lx3):
|
|
835
|
+
for loc2 in range(lx2):
|
|
836
|
+
for loc1 in range(lx1):
|
|
837
|
+
if restricted_data[loc3, loc2, loc1]:
|
|
838
|
+
il = loc1 * block_size[0]
|
|
839
|
+
jl = loc2 * block_size[1]
|
|
840
|
+
kl = loc3 * block_size[2]
|
|
841
|
+
iu = il + block_size[0]
|
|
842
|
+
ju = jl + block_size[1]
|
|
843
|
+
ku = kl + block_size[2]
|
|
844
|
+
il = max(il, i_min) - i_min
|
|
845
|
+
jl = max(jl, j_min) - j_min
|
|
846
|
+
kl = max(kl, k_min) - k_min
|
|
847
|
+
iu = min(iu, i_max) - i_min
|
|
848
|
+
ju = min(ju, j_max) - j_min
|
|
849
|
+
ku = min(ku, k_max) - k_min
|
|
850
|
+
for k in range(kl, ku):
|
|
851
|
+
for j in range(jl, ju):
|
|
852
|
+
for i in range(il, iu):
|
|
853
|
+
x1m, x1p = data["x1f"][i], data["x1f"][i + 1]
|
|
854
|
+
x2m, x2p = data["x2f"][j], data["x2f"][j + 1]
|
|
855
|
+
x3m, x3p = data["x3f"][k], data["x3f"][k + 1]
|
|
856
|
+
vol = vol_func(x1m, x1p, x2m, x2p, x3m, x3p)
|
|
857
|
+
for q in quantities:
|
|
858
|
+
data[q][k, j, i] /= vol
|
|
859
|
+
|
|
860
|
+
# Add metadata
|
|
861
|
+
data["Time"] = filedata["time"]
|
|
862
|
+
data["NumCycles"] = filedata["cycle"]
|
|
863
|
+
data["MaxLevel"] = max_level
|
|
864
|
+
|
|
865
|
+
return data
|
|
866
|
+
|
|
867
|
+
|
|
868
|
+
def read_all_ranks_binary_as_athdf(
|
|
869
|
+
rank0_filename,
|
|
870
|
+
raw=False,
|
|
871
|
+
data=None,
|
|
872
|
+
quantities=None,
|
|
873
|
+
dtype=None,
|
|
874
|
+
level=None,
|
|
875
|
+
return_levels=False,
|
|
876
|
+
subsample=False,
|
|
877
|
+
fast_restrict=False,
|
|
878
|
+
x1_min=None,
|
|
879
|
+
x1_max=None,
|
|
880
|
+
x2_min=None,
|
|
881
|
+
x2_max=None,
|
|
882
|
+
x3_min=None,
|
|
883
|
+
x3_max=None,
|
|
884
|
+
vol_func=None,
|
|
885
|
+
vol_params=None,
|
|
886
|
+
face_func_1=None,
|
|
887
|
+
face_func_2=None,
|
|
888
|
+
face_func_3=None,
|
|
889
|
+
center_func_1=None,
|
|
890
|
+
center_func_2=None,
|
|
891
|
+
center_func_3=None,
|
|
892
|
+
num_ghost=0,
|
|
893
|
+
):
|
|
894
|
+
"""
|
|
895
|
+
Reads a bin file and organizes data similar to athdf format without writing to file.
|
|
896
|
+
"""
|
|
897
|
+
# Step 1: Read binary data
|
|
898
|
+
filedata = read_all_ranks_binary(rank0_filename)
|
|
899
|
+
|
|
900
|
+
# Step 2: Organize data similar to athdf
|
|
901
|
+
if raw:
|
|
902
|
+
return filedata
|
|
903
|
+
|
|
904
|
+
# Prepare dictionary for results
|
|
905
|
+
if data is None:
|
|
906
|
+
data = {}
|
|
907
|
+
new_data = True
|
|
908
|
+
else:
|
|
909
|
+
new_data = False
|
|
910
|
+
|
|
911
|
+
# Extract size information
|
|
912
|
+
max_level = max(filedata["mb_logical"][:, 3])
|
|
913
|
+
if level is None:
|
|
914
|
+
level = max_level
|
|
915
|
+
block_size = [
|
|
916
|
+
filedata["nx1_out_mb"],
|
|
917
|
+
filedata["nx2_out_mb"],
|
|
918
|
+
filedata["nx3_out_mb"],
|
|
919
|
+
]
|
|
920
|
+
root_grid_size = [filedata["Nx1"], filedata["Nx2"], filedata["Nx3"]]
|
|
921
|
+
levels = filedata["mb_logical"][:, 3]
|
|
922
|
+
logical_locations = filedata["mb_logical"][:, :3]
|
|
923
|
+
if dtype is None:
|
|
924
|
+
dtype = np.float32
|
|
925
|
+
|
|
926
|
+
# Calculate nx_vals
|
|
927
|
+
nx_vals = []
|
|
928
|
+
for d in range(3):
|
|
929
|
+
if block_size[d] == 1 and root_grid_size[d] > 1: # sum or slice
|
|
930
|
+
other_locations = [
|
|
931
|
+
location
|
|
932
|
+
for location in zip(
|
|
933
|
+
levels,
|
|
934
|
+
logical_locations[:, (d + 1) % 3],
|
|
935
|
+
logical_locations[:, (d + 2) % 3],
|
|
936
|
+
)
|
|
937
|
+
]
|
|
938
|
+
if len(set(other_locations)) == len(other_locations): # effective slice
|
|
939
|
+
nx_vals.append(1)
|
|
940
|
+
else: # nontrivial sum
|
|
941
|
+
num_blocks_this_dim = 0
|
|
942
|
+
for level_this_dim, loc_this_dim in zip(
|
|
943
|
+
levels, logical_locations[:, d]
|
|
944
|
+
):
|
|
945
|
+
if level_this_dim <= level:
|
|
946
|
+
possible_max = (loc_this_dim + 1) * 2 ** (
|
|
947
|
+
level - level_this_dim
|
|
948
|
+
)
|
|
949
|
+
num_blocks_this_dim = max(num_blocks_this_dim, possible_max)
|
|
950
|
+
else:
|
|
951
|
+
possible_max = (loc_this_dim + 1) // 2 ** (
|
|
952
|
+
level_this_dim - level
|
|
953
|
+
)
|
|
954
|
+
num_blocks_this_dim = max(num_blocks_this_dim, possible_max)
|
|
955
|
+
nx_vals.append(num_blocks_this_dim)
|
|
956
|
+
elif block_size[d] == 1: # singleton dimension
|
|
957
|
+
nx_vals.append(1)
|
|
958
|
+
else: # normal case
|
|
959
|
+
nx_vals.append(root_grid_size[d] * 2**level + 2 * num_ghost)
|
|
960
|
+
nx1, nx2, nx3 = nx_vals
|
|
961
|
+
lx1, lx2, lx3 = [nx // bs for nx, bs in zip(nx_vals, block_size)]
|
|
962
|
+
# Set coordinate system and related functions
|
|
963
|
+
# coord = "cartesian" # Adjust based on your data
|
|
964
|
+
if vol_func is None:
|
|
965
|
+
|
|
966
|
+
def vol_func(xm, xp, ym, yp, zm, zp):
|
|
967
|
+
return (xp - xm) * (yp - ym) * (zp - zm)
|
|
968
|
+
|
|
969
|
+
# Define center functions if not provided
|
|
970
|
+
if center_func_1 is None:
|
|
971
|
+
|
|
972
|
+
def center_func_1(xm, xp):
|
|
973
|
+
return 0.5 * (xm + xp)
|
|
974
|
+
|
|
975
|
+
if center_func_2 is None:
|
|
976
|
+
|
|
977
|
+
def center_func_2(xm, xp):
|
|
978
|
+
return 0.5 * (xm + xp)
|
|
979
|
+
|
|
980
|
+
if center_func_3 is None:
|
|
981
|
+
|
|
982
|
+
def center_func_3(xm, xp):
|
|
983
|
+
return 0.5 * (xm + xp)
|
|
984
|
+
|
|
985
|
+
# Populate coordinate arrays
|
|
986
|
+
center_funcs = [center_func_1, center_func_2, center_func_3]
|
|
987
|
+
for d in range(1, 4):
|
|
988
|
+
xf = f"x{d}f"
|
|
989
|
+
xv = f"x{d}v"
|
|
990
|
+
nx = nx_vals[d - 1]
|
|
991
|
+
if nx == 1:
|
|
992
|
+
xmin = filedata[f"x{d}min"]
|
|
993
|
+
xmax = filedata[f"x{d}max"]
|
|
994
|
+
data[xf] = np.array([xmin, xmax], dtype=dtype)
|
|
995
|
+
else:
|
|
996
|
+
xmin = filedata[f"x{d}min"]
|
|
997
|
+
xmax = filedata[f"x{d}max"]
|
|
998
|
+
data[xf] = np.linspace(xmin, xmax, nx + 1, dtype=dtype)
|
|
999
|
+
data[xv] = np.empty(nx, dtype=dtype)
|
|
1000
|
+
for i in range(nx):
|
|
1001
|
+
data[xv][i] = center_funcs[d - 1](data[xf][i], data[xf][i + 1])
|
|
1002
|
+
|
|
1003
|
+
# Create list of quantities
|
|
1004
|
+
if quantities is None:
|
|
1005
|
+
quantities = filedata["var_names"]
|
|
1006
|
+
|
|
1007
|
+
# Account for selection
|
|
1008
|
+
i_min, i_max = 0, nx1
|
|
1009
|
+
j_min, j_max = 0, nx2
|
|
1010
|
+
k_min, k_max = 0, nx3
|
|
1011
|
+
if x1_min is not None:
|
|
1012
|
+
i_min = max(i_min, np.searchsorted(data["x1f"], x1_min))
|
|
1013
|
+
if x1_max is not None:
|
|
1014
|
+
i_max = min(i_max, np.searchsorted(data["x1f"], x1_max))
|
|
1015
|
+
if x2_min is not None:
|
|
1016
|
+
j_min = max(j_min, np.searchsorted(data["x2f"], x2_min))
|
|
1017
|
+
if x2_max is not None:
|
|
1018
|
+
j_max = min(j_max, np.searchsorted(data["x2f"], x2_max))
|
|
1019
|
+
if x3_min is not None:
|
|
1020
|
+
k_min = max(k_min, np.searchsorted(data["x3f"], x3_min))
|
|
1021
|
+
if x3_max is not None:
|
|
1022
|
+
k_max = min(k_max, np.searchsorted(data["x3f"], x3_max))
|
|
1023
|
+
|
|
1024
|
+
# Prepare arrays for data and bookkeeping
|
|
1025
|
+
if new_data:
|
|
1026
|
+
for q in quantities:
|
|
1027
|
+
data[q] = np.zeros(
|
|
1028
|
+
(k_max - k_min, j_max - j_min, i_max - i_min), dtype=dtype
|
|
1029
|
+
)
|
|
1030
|
+
if return_levels:
|
|
1031
|
+
data["Levels"] = np.empty(
|
|
1032
|
+
(k_max - k_min, j_max - j_min, i_max - i_min), dtype=np.int32
|
|
1033
|
+
)
|
|
1034
|
+
else:
|
|
1035
|
+
for q in quantities:
|
|
1036
|
+
data[q].fill(0.0)
|
|
1037
|
+
if not subsample and not fast_restrict and max_level > level:
|
|
1038
|
+
restricted_data = np.zeros((lx3, lx2, lx1), dtype=bool)
|
|
1039
|
+
|
|
1040
|
+
# Step 3: Process each block
|
|
1041
|
+
for block_num in range(filedata["n_mbs"]):
|
|
1042
|
+
block_level = levels[block_num]
|
|
1043
|
+
block_location = logical_locations[block_num]
|
|
1044
|
+
|
|
1045
|
+
# Implement logic for prolongation, restriction, subsampling
|
|
1046
|
+
if block_level <= level:
|
|
1047
|
+
s = 2 ** (level - block_level)
|
|
1048
|
+
il_d = block_location[0] * block_size[0] * s if nx1 > 1 else 0
|
|
1049
|
+
jl_d = block_location[1] * block_size[1] * s if nx2 > 1 else 0
|
|
1050
|
+
kl_d = block_location[2] * block_size[2] * s if nx3 > 1 else 0
|
|
1051
|
+
iu_d = il_d + block_size[0] * s if nx1 > 1 else 1
|
|
1052
|
+
ju_d = jl_d + block_size[1] * s if nx2 > 1 else 1
|
|
1053
|
+
ku_d = kl_d + block_size[2] * s if nx3 > 1 else 1
|
|
1054
|
+
|
|
1055
|
+
il_s = max(il_d, i_min) - il_d
|
|
1056
|
+
jl_s = max(jl_d, j_min) - jl_d
|
|
1057
|
+
kl_s = max(kl_d, k_min) - kl_d
|
|
1058
|
+
iu_s = min(iu_d, i_max) - il_d
|
|
1059
|
+
ju_s = min(ju_d, j_max) - jl_d
|
|
1060
|
+
ku_s = min(ku_d, k_max) - kl_d
|
|
1061
|
+
|
|
1062
|
+
if il_s >= iu_s or jl_s >= ju_s or kl_s >= ku_s:
|
|
1063
|
+
continue
|
|
1064
|
+
|
|
1065
|
+
il_d = max(il_d, i_min) - i_min
|
|
1066
|
+
jl_d = max(jl_d, j_min) - j_min
|
|
1067
|
+
kl_d = max(kl_d, k_min) - k_min
|
|
1068
|
+
iu_d = min(iu_d, i_max) - i_min
|
|
1069
|
+
ju_d = min(ju_d, j_max) - j_min
|
|
1070
|
+
ku_d = min(ku_d, k_max) - k_min
|
|
1071
|
+
|
|
1072
|
+
for q in quantities:
|
|
1073
|
+
block_data = filedata["mb_data"][q][block_num]
|
|
1074
|
+
if s > 1:
|
|
1075
|
+
block_data = np.repeat(
|
|
1076
|
+
np.repeat(np.repeat(block_data, s, axis=2), s, axis=1),
|
|
1077
|
+
s,
|
|
1078
|
+
axis=0,
|
|
1079
|
+
)
|
|
1080
|
+
data[q][kl_d:ku_d, jl_d:ju_d, il_d:iu_d] = block_data[
|
|
1081
|
+
kl_s:ku_s, jl_s:ju_s, il_s:iu_s
|
|
1082
|
+
]
|
|
1083
|
+
else:
|
|
1084
|
+
# Implement restriction logic here (similar to athdf function)
|
|
1085
|
+
pass
|
|
1086
|
+
|
|
1087
|
+
if return_levels:
|
|
1088
|
+
data["Levels"][kl_d:ku_d, jl_d:ju_d, il_d:iu_d] = block_level
|
|
1089
|
+
|
|
1090
|
+
# Step 4: Finalize data
|
|
1091
|
+
if level < max_level and not subsample and not fast_restrict:
|
|
1092
|
+
# Remove volume factors from restricted data
|
|
1093
|
+
for loc3 in range(lx3):
|
|
1094
|
+
for loc2 in range(lx2):
|
|
1095
|
+
for loc1 in range(lx1):
|
|
1096
|
+
if restricted_data[loc3, loc2, loc1]:
|
|
1097
|
+
il = loc1 * block_size[0]
|
|
1098
|
+
jl = loc2 * block_size[1]
|
|
1099
|
+
kl = loc3 * block_size[2]
|
|
1100
|
+
iu = il + block_size[0]
|
|
1101
|
+
ju = jl + block_size[1]
|
|
1102
|
+
ku = kl + block_size[2]
|
|
1103
|
+
il = max(il, i_min) - i_min
|
|
1104
|
+
jl = max(jl, j_min) - j_min
|
|
1105
|
+
kl = max(kl, k_min) - k_min
|
|
1106
|
+
iu = min(iu, i_max) - i_min
|
|
1107
|
+
ju = min(ju, j_max) - j_min
|
|
1108
|
+
ku = min(ku, k_max) - k_min
|
|
1109
|
+
for k in range(kl, ku):
|
|
1110
|
+
for j in range(jl, ju):
|
|
1111
|
+
for i in range(il, iu):
|
|
1112
|
+
x1m, x1p = data["x1f"][i], data["x1f"][i + 1]
|
|
1113
|
+
x2m, x2p = data["x2f"][j], data["x2f"][j + 1]
|
|
1114
|
+
x3m, x3p = data["x3f"][k], data["x3f"][k + 1]
|
|
1115
|
+
vol = vol_func(x1m, x1p, x2m, x2p, x3m, x3p)
|
|
1116
|
+
for q in quantities:
|
|
1117
|
+
data[q][k, j, i] /= vol
|
|
1118
|
+
|
|
1119
|
+
# Add metadata
|
|
1120
|
+
data["Time"] = filedata["time"]
|
|
1121
|
+
data["NumCycles"] = filedata["cycle"]
|
|
1122
|
+
data["MaxLevel"] = max_level
|
|
1123
|
+
|
|
1124
|
+
return data
|
|
1125
|
+
|
|
1126
|
+
|
|
1127
|
+
def read_all_ranks_coarsened_binary_as_athdf(
|
|
1128
|
+
rank0_filename,
|
|
1129
|
+
raw=False,
|
|
1130
|
+
data=None,
|
|
1131
|
+
quantities=None,
|
|
1132
|
+
dtype=None,
|
|
1133
|
+
level=None,
|
|
1134
|
+
return_levels=False,
|
|
1135
|
+
subsample=False,
|
|
1136
|
+
fast_restrict=False,
|
|
1137
|
+
x1_min=None,
|
|
1138
|
+
x1_max=None,
|
|
1139
|
+
x2_min=None,
|
|
1140
|
+
x2_max=None,
|
|
1141
|
+
x3_min=None,
|
|
1142
|
+
x3_max=None,
|
|
1143
|
+
vol_func=None,
|
|
1144
|
+
vol_params=None,
|
|
1145
|
+
face_func_1=None,
|
|
1146
|
+
face_func_2=None,
|
|
1147
|
+
face_func_3=None,
|
|
1148
|
+
center_func_1=None,
|
|
1149
|
+
center_func_2=None,
|
|
1150
|
+
center_func_3=None,
|
|
1151
|
+
num_ghost=0,
|
|
1152
|
+
):
|
|
1153
|
+
"""
|
|
1154
|
+
Reads a bin file and organizes data similar to athdf format without writing to file.
|
|
1155
|
+
"""
|
|
1156
|
+
# Step 1: Read binary data
|
|
1157
|
+
filedata = read_all_ranks_coarsened_binary(rank0_filename)
|
|
1158
|
+
|
|
1159
|
+
# Step 2: Organize data similar to athdf
|
|
1160
|
+
if raw:
|
|
1161
|
+
return filedata
|
|
1162
|
+
|
|
1163
|
+
# Prepare dictionary for results
|
|
1164
|
+
if data is None:
|
|
1165
|
+
data = {}
|
|
1166
|
+
new_data = True
|
|
1167
|
+
else:
|
|
1168
|
+
new_data = False
|
|
1169
|
+
|
|
1170
|
+
# Extract size information
|
|
1171
|
+
max_level = max(filedata["mb_logical"][:, 3])
|
|
1172
|
+
if level is None:
|
|
1173
|
+
level = max_level
|
|
1174
|
+
block_size = [filedata["nx1_mb"], filedata["nx2_mb"], filedata["nx3_mb"]]
|
|
1175
|
+
root_grid_size = [filedata["Nx1"], filedata["Nx2"], filedata["Nx3"]]
|
|
1176
|
+
levels = filedata["mb_logical"][:, 3]
|
|
1177
|
+
logical_locations = filedata["mb_logical"][:, :3]
|
|
1178
|
+
if dtype is None:
|
|
1179
|
+
dtype = np.float32
|
|
1180
|
+
|
|
1181
|
+
# Calculate nx_vals
|
|
1182
|
+
nx_vals = []
|
|
1183
|
+
for d in range(3):
|
|
1184
|
+
if block_size[d] == 1 and root_grid_size[d] > 1:
|
|
1185
|
+
# Implement logic for sum or slice as in athdf
|
|
1186
|
+
nx_vals.append(root_grid_size[d] * 2**level)
|
|
1187
|
+
elif block_size[d] == 1:
|
|
1188
|
+
nx_vals.append(1)
|
|
1189
|
+
else:
|
|
1190
|
+
nx_vals.append(root_grid_size[d] * 2**level + 2 * num_ghost)
|
|
1191
|
+
nx1, nx2, nx3 = nx_vals
|
|
1192
|
+
lx1, lx2, lx3 = [nx // bs for nx, bs in zip(nx_vals, block_size)]
|
|
1193
|
+
|
|
1194
|
+
# Set coordinate system and related functions
|
|
1195
|
+
# coord = "cartesian" # Adjust based on your data
|
|
1196
|
+
if vol_func is None:
|
|
1197
|
+
|
|
1198
|
+
def vol_func(xm, xp, ym, yp, zm, zp):
|
|
1199
|
+
return (xp - xm) * (yp - ym) * (zp - zm)
|
|
1200
|
+
|
|
1201
|
+
# Define center functions if not provided
|
|
1202
|
+
if center_func_1 is None:
|
|
1203
|
+
|
|
1204
|
+
def center_func_1(xm, xp):
|
|
1205
|
+
return 0.5 * (xm + xp)
|
|
1206
|
+
|
|
1207
|
+
if center_func_2 is None:
|
|
1208
|
+
|
|
1209
|
+
def center_func_2(xm, xp):
|
|
1210
|
+
return 0.5 * (xm + xp)
|
|
1211
|
+
|
|
1212
|
+
if center_func_3 is None:
|
|
1213
|
+
|
|
1214
|
+
def center_func_3(xm, xp):
|
|
1215
|
+
return 0.5 * (xm + xp)
|
|
1216
|
+
|
|
1217
|
+
# Populate coordinate arrays
|
|
1218
|
+
center_funcs = [center_func_1, center_func_2, center_func_3]
|
|
1219
|
+
for d in range(1, 4):
|
|
1220
|
+
xf = f"x{d}f"
|
|
1221
|
+
xv = f"x{d}v"
|
|
1222
|
+
nx = nx_vals[d - 1]
|
|
1223
|
+
if nx == 1:
|
|
1224
|
+
xmin = filedata[f"x{d}min"]
|
|
1225
|
+
xmax = filedata[f"x{d}max"]
|
|
1226
|
+
data[xf] = np.array([xmin, xmax], dtype=dtype)
|
|
1227
|
+
else:
|
|
1228
|
+
xmin = filedata[f"x{d}min"]
|
|
1229
|
+
xmax = filedata[f"x{d}max"]
|
|
1230
|
+
data[xf] = np.linspace(xmin, xmax, nx + 1, dtype=dtype)
|
|
1231
|
+
data[xv] = np.empty(nx, dtype=dtype)
|
|
1232
|
+
for i in range(nx):
|
|
1233
|
+
data[xv][i] = center_funcs[d - 1](data[xf][i], data[xf][i + 1])
|
|
1234
|
+
|
|
1235
|
+
# Create list of quantities
|
|
1236
|
+
if quantities is None:
|
|
1237
|
+
quantities = filedata["var_names"]
|
|
1238
|
+
|
|
1239
|
+
# Account for selection
|
|
1240
|
+
i_min, i_max = 0, nx1
|
|
1241
|
+
j_min, j_max = 0, nx2
|
|
1242
|
+
k_min, k_max = 0, nx3
|
|
1243
|
+
if x1_min is not None:
|
|
1244
|
+
i_min = max(i_min, np.searchsorted(data["x1f"], x1_min))
|
|
1245
|
+
if x1_max is not None:
|
|
1246
|
+
i_max = min(i_max, np.searchsorted(data["x1f"], x1_max))
|
|
1247
|
+
if x2_min is not None:
|
|
1248
|
+
j_min = max(j_min, np.searchsorted(data["x2f"], x2_min))
|
|
1249
|
+
if x2_max is not None:
|
|
1250
|
+
j_max = min(j_max, np.searchsorted(data["x2f"], x2_max))
|
|
1251
|
+
if x3_min is not None:
|
|
1252
|
+
k_min = max(k_min, np.searchsorted(data["x3f"], x3_min))
|
|
1253
|
+
if x3_max is not None:
|
|
1254
|
+
k_max = min(k_max, np.searchsorted(data["x3f"], x3_max))
|
|
1255
|
+
|
|
1256
|
+
# Prepare arrays for data and bookkeeping
|
|
1257
|
+
if new_data:
|
|
1258
|
+
for q in quantities:
|
|
1259
|
+
data[q] = np.zeros(
|
|
1260
|
+
(k_max - k_min, j_max - j_min, i_max - i_min), dtype=dtype
|
|
1261
|
+
)
|
|
1262
|
+
if return_levels:
|
|
1263
|
+
data["Levels"] = np.empty(
|
|
1264
|
+
(k_max - k_min, j_max - j_min, i_max - i_min), dtype=np.int32
|
|
1265
|
+
)
|
|
1266
|
+
else:
|
|
1267
|
+
for q in quantities:
|
|
1268
|
+
data[q].fill(0.0)
|
|
1269
|
+
if not subsample and not fast_restrict and max_level > level:
|
|
1270
|
+
restricted_data = np.zeros((lx3, lx2, lx1), dtype=bool)
|
|
1271
|
+
|
|
1272
|
+
# Step 3: Process each block
|
|
1273
|
+
for block_num in range(filedata["n_mbs"]):
|
|
1274
|
+
block_level = levels[block_num]
|
|
1275
|
+
block_location = logical_locations[block_num]
|
|
1276
|
+
|
|
1277
|
+
# Implement logic for prolongation, restriction, subsampling
|
|
1278
|
+
if block_level <= level:
|
|
1279
|
+
s = 2 ** (level - block_level)
|
|
1280
|
+
il_d = block_location[0] * block_size[0] * s if nx1 > 1 else 0
|
|
1281
|
+
jl_d = block_location[1] * block_size[1] * s if nx2 > 1 else 0
|
|
1282
|
+
kl_d = block_location[2] * block_size[2] * s if nx3 > 1 else 0
|
|
1283
|
+
iu_d = il_d + block_size[0] * s if nx1 > 1 else 1
|
|
1284
|
+
ju_d = jl_d + block_size[1] * s if nx2 > 1 else 1
|
|
1285
|
+
ku_d = kl_d + block_size[2] * s if nx3 > 1 else 1
|
|
1286
|
+
|
|
1287
|
+
il_s = max(il_d, i_min) - il_d
|
|
1288
|
+
jl_s = max(jl_d, j_min) - jl_d
|
|
1289
|
+
kl_s = max(kl_d, k_min) - kl_d
|
|
1290
|
+
iu_s = min(iu_d, i_max) - il_d
|
|
1291
|
+
ju_s = min(ju_d, j_max) - jl_d
|
|
1292
|
+
ku_s = min(ku_d, k_max) - kl_d
|
|
1293
|
+
|
|
1294
|
+
if il_s >= iu_s or jl_s >= ju_s or kl_s >= ku_s:
|
|
1295
|
+
continue
|
|
1296
|
+
|
|
1297
|
+
il_d = max(il_d, i_min) - i_min
|
|
1298
|
+
jl_d = max(jl_d, j_min) - j_min
|
|
1299
|
+
kl_d = max(kl_d, k_min) - k_min
|
|
1300
|
+
iu_d = min(iu_d, i_max) - i_min
|
|
1301
|
+
ju_d = min(ju_d, j_max) - j_min
|
|
1302
|
+
ku_d = min(ku_d, k_max) - k_min
|
|
1303
|
+
|
|
1304
|
+
for q in quantities:
|
|
1305
|
+
block_data = filedata["mb_data"][q][block_num]
|
|
1306
|
+
if s > 1:
|
|
1307
|
+
block_data = np.repeat(
|
|
1308
|
+
np.repeat(np.repeat(block_data, s, axis=2), s, axis=1),
|
|
1309
|
+
s,
|
|
1310
|
+
axis=0,
|
|
1311
|
+
)
|
|
1312
|
+
data[q][kl_d:ku_d, jl_d:ju_d, il_d:iu_d] = block_data[
|
|
1313
|
+
kl_s:ku_s, jl_s:ju_s, il_s:iu_s
|
|
1314
|
+
]
|
|
1315
|
+
else:
|
|
1316
|
+
# Implement restriction logic here (similar to athdf function)
|
|
1317
|
+
pass
|
|
1318
|
+
|
|
1319
|
+
if return_levels:
|
|
1320
|
+
data["Levels"][kl_d:ku_d, jl_d:ju_d, il_d:iu_d] = block_level
|
|
1321
|
+
|
|
1322
|
+
# Step 4: Finalize data
|
|
1323
|
+
if level < max_level and not subsample and not fast_restrict:
|
|
1324
|
+
# Remove volume factors from restricted data
|
|
1325
|
+
for loc3 in range(lx3):
|
|
1326
|
+
for loc2 in range(lx2):
|
|
1327
|
+
for loc1 in range(lx1):
|
|
1328
|
+
if restricted_data[loc3, loc2, loc1]:
|
|
1329
|
+
il = loc1 * block_size[0]
|
|
1330
|
+
jl = loc2 * block_size[1]
|
|
1331
|
+
kl = loc3 * block_size[2]
|
|
1332
|
+
iu = il + block_size[0]
|
|
1333
|
+
ju = jl + block_size[1]
|
|
1334
|
+
ku = kl + block_size[2]
|
|
1335
|
+
il = max(il, i_min) - i_min
|
|
1336
|
+
jl = max(jl, j_min) - j_min
|
|
1337
|
+
kl = max(kl, k_min) - k_min
|
|
1338
|
+
iu = min(iu, i_max) - i_min
|
|
1339
|
+
ju = min(ju, j_max) - j_min
|
|
1340
|
+
ku = min(ku, k_max) - k_min
|
|
1341
|
+
for k in range(kl, ku):
|
|
1342
|
+
for j in range(jl, ju):
|
|
1343
|
+
for i in range(il, iu):
|
|
1344
|
+
x1m, x1p = data["x1f"][i], data["x1f"][i + 1]
|
|
1345
|
+
x2m, x2p = data["x2f"][j], data["x2f"][j + 1]
|
|
1346
|
+
x3m, x3p = data["x3f"][k], data["x3f"][k + 1]
|
|
1347
|
+
vol = vol_func(x1m, x1p, x2m, x2p, x3m, x3p)
|
|
1348
|
+
for q in quantities:
|
|
1349
|
+
data[q][k, j, i] /= vol
|
|
1350
|
+
|
|
1351
|
+
# Add metadata
|
|
1352
|
+
data["Time"] = filedata["time"]
|
|
1353
|
+
data["NumCycles"] = filedata["cycle"]
|
|
1354
|
+
data["MaxLevel"] = max_level
|
|
1355
|
+
|
|
1356
|
+
return data
|
|
1357
|
+
|
|
1358
|
+
|
|
1359
|
+
def read_single_rank_binary_as_athdf(
|
|
1360
|
+
filename,
|
|
1361
|
+
raw=False,
|
|
1362
|
+
data=None,
|
|
1363
|
+
quantities=None,
|
|
1364
|
+
dtype=None,
|
|
1365
|
+
return_levels=False,
|
|
1366
|
+
x1_min=None,
|
|
1367
|
+
x1_max=None,
|
|
1368
|
+
x2_min=None,
|
|
1369
|
+
x2_max=None,
|
|
1370
|
+
x3_min=None,
|
|
1371
|
+
x3_max=None,
|
|
1372
|
+
vol_func=None,
|
|
1373
|
+
center_func_1=None,
|
|
1374
|
+
center_func_2=None,
|
|
1375
|
+
center_func_3=None,
|
|
1376
|
+
):
|
|
1377
|
+
"""
|
|
1378
|
+
Reads a single rank binary file and organizes data similar to
|
|
1379
|
+
athdf format without writing to file.
|
|
1380
|
+
"""
|
|
1381
|
+
# Step 1: Read binary data for a single rank
|
|
1382
|
+
filedata = read_binary(filename)
|
|
1383
|
+
|
|
1384
|
+
if raw:
|
|
1385
|
+
return filedata
|
|
1386
|
+
|
|
1387
|
+
# Prepare dictionary for results
|
|
1388
|
+
if data is None:
|
|
1389
|
+
data = {}
|
|
1390
|
+
new_data = True
|
|
1391
|
+
else:
|
|
1392
|
+
new_data = False
|
|
1393
|
+
|
|
1394
|
+
# Extract size information
|
|
1395
|
+
block_size = [filedata["nx1_mb"], filedata["nx2_mb"], filedata["nx3_mb"]]
|
|
1396
|
+
if dtype is None:
|
|
1397
|
+
dtype = np.float32
|
|
1398
|
+
|
|
1399
|
+
# Set coordinate system and related functions
|
|
1400
|
+
if vol_func is None:
|
|
1401
|
+
|
|
1402
|
+
def vol_func(xm, xp, ym, yp, zm, zp):
|
|
1403
|
+
return (xp - xm) * (yp - ym) * (zp - zm)
|
|
1404
|
+
|
|
1405
|
+
if center_func_1 is None:
|
|
1406
|
+
|
|
1407
|
+
def center_func_1(xm, xp):
|
|
1408
|
+
return 0.5 * (xm + xp)
|
|
1409
|
+
|
|
1410
|
+
if center_func_2 is None:
|
|
1411
|
+
|
|
1412
|
+
def center_func_2(xm, xp):
|
|
1413
|
+
return 0.5 * (xm + xp)
|
|
1414
|
+
|
|
1415
|
+
if center_func_3 is None:
|
|
1416
|
+
|
|
1417
|
+
def center_func_3(xm, xp):
|
|
1418
|
+
return 0.5 * (xm + xp)
|
|
1419
|
+
|
|
1420
|
+
# Populate coordinate arrays
|
|
1421
|
+
center_funcs = [center_func_1, center_func_2, center_func_3]
|
|
1422
|
+
for d in range(1, 4):
|
|
1423
|
+
xf = f"x{d}f"
|
|
1424
|
+
xv = f"x{d}v"
|
|
1425
|
+
nx = block_size[d - 1]
|
|
1426
|
+
|
|
1427
|
+
# Use the meshblock geometry for local min and max
|
|
1428
|
+
xmin = filedata["mb_geometry"][0, (d - 1) * 2]
|
|
1429
|
+
xmax = filedata["mb_geometry"][0, (d - 1) * 2 + 1]
|
|
1430
|
+
|
|
1431
|
+
data[xf] = np.linspace(xmin, xmax, nx + 1, dtype=dtype)
|
|
1432
|
+
data[xv] = np.empty(nx, dtype=dtype)
|
|
1433
|
+
for i in range(nx):
|
|
1434
|
+
data[xv][i] = center_funcs[d - 1](data[xf][i], data[xf][i + 1])
|
|
1435
|
+
|
|
1436
|
+
# Create list of quantities
|
|
1437
|
+
if quantities is None:
|
|
1438
|
+
quantities = filedata["var_names"]
|
|
1439
|
+
|
|
1440
|
+
# Account for selection
|
|
1441
|
+
i_min, i_max = 0, block_size[0]
|
|
1442
|
+
j_min, j_max = 0, block_size[1]
|
|
1443
|
+
k_min, k_max = 0, block_size[2]
|
|
1444
|
+
if x1_min is not None:
|
|
1445
|
+
i_min = max(i_min, np.searchsorted(data["x1f"], x1_min))
|
|
1446
|
+
if x1_max is not None:
|
|
1447
|
+
i_max = min(i_max, np.searchsorted(data["x1f"], x1_max))
|
|
1448
|
+
if x2_min is not None:
|
|
1449
|
+
j_min = max(j_min, np.searchsorted(data["x2f"], x2_min))
|
|
1450
|
+
if x2_max is not None:
|
|
1451
|
+
j_max = min(j_max, np.searchsorted(data["x2f"], x2_max))
|
|
1452
|
+
if x3_min is not None:
|
|
1453
|
+
k_min = max(k_min, np.searchsorted(data["x3f"], x3_min))
|
|
1454
|
+
if x3_max is not None:
|
|
1455
|
+
k_max = min(k_max, np.searchsorted(data["x3f"], x3_max))
|
|
1456
|
+
|
|
1457
|
+
# Prepare arrays for data
|
|
1458
|
+
if new_data:
|
|
1459
|
+
for q in quantities:
|
|
1460
|
+
data[q] = np.zeros(
|
|
1461
|
+
(k_max - k_min, j_max - j_min, i_max - i_min), dtype=dtype
|
|
1462
|
+
)
|
|
1463
|
+
if return_levels:
|
|
1464
|
+
data["Levels"] = np.empty(
|
|
1465
|
+
(k_max - k_min, j_max - j_min, i_max - i_min), dtype=np.int32
|
|
1466
|
+
)
|
|
1467
|
+
else:
|
|
1468
|
+
for q in quantities:
|
|
1469
|
+
data[q].fill(0.0)
|
|
1470
|
+
|
|
1471
|
+
# Process the single block
|
|
1472
|
+
for q in quantities:
|
|
1473
|
+
block_data = filedata["mb_data"][q][0] # Single rank, so only one block
|
|
1474
|
+
data[q] = block_data[k_min:k_max, j_min:j_max, i_min:i_max]
|
|
1475
|
+
|
|
1476
|
+
if return_levels:
|
|
1477
|
+
data["Levels"].fill(filedata["mb_logical"][0, 3]) # Level of the single block
|
|
1478
|
+
|
|
1479
|
+
# Add metadata
|
|
1480
|
+
data["Time"] = filedata["time"]
|
|
1481
|
+
data["NumCycles"] = filedata["cycle"]
|
|
1482
|
+
data["MaxLevel"] = filedata["mb_logical"][0, 3]
|
|
1483
|
+
|
|
1484
|
+
return data
|
|
1485
|
+
|
|
1486
|
+
|
|
1487
|
+
def read_coarsened_binary_as_athdf(
|
|
1488
|
+
filename,
|
|
1489
|
+
raw=False,
|
|
1490
|
+
data=None,
|
|
1491
|
+
quantities=None,
|
|
1492
|
+
dtype=None,
|
|
1493
|
+
level=None,
|
|
1494
|
+
return_levels=False,
|
|
1495
|
+
subsample=False,
|
|
1496
|
+
fast_restrict=False,
|
|
1497
|
+
x1_min=None,
|
|
1498
|
+
x1_max=None,
|
|
1499
|
+
x2_min=None,
|
|
1500
|
+
x2_max=None,
|
|
1501
|
+
x3_min=None,
|
|
1502
|
+
x3_max=None,
|
|
1503
|
+
vol_func=None,
|
|
1504
|
+
vol_params=None,
|
|
1505
|
+
face_func_1=None,
|
|
1506
|
+
face_func_2=None,
|
|
1507
|
+
face_func_3=None,
|
|
1508
|
+
center_func_1=None,
|
|
1509
|
+
center_func_2=None,
|
|
1510
|
+
center_func_3=None,
|
|
1511
|
+
num_ghost=0,
|
|
1512
|
+
):
|
|
1513
|
+
"""
|
|
1514
|
+
Reads a bin file and organizes data similar to athdf format without writing to file.
|
|
1515
|
+
"""
|
|
1516
|
+
# Step 1: Read binary data
|
|
1517
|
+
filedata = read_coarsened_binary(filename)
|
|
1518
|
+
|
|
1519
|
+
# Step 2: Organize data similar to athdf
|
|
1520
|
+
if raw:
|
|
1521
|
+
return filedata
|
|
1522
|
+
|
|
1523
|
+
# Prepare dictionary for results
|
|
1524
|
+
if data is None:
|
|
1525
|
+
data = {}
|
|
1526
|
+
new_data = True
|
|
1527
|
+
else:
|
|
1528
|
+
new_data = False
|
|
1529
|
+
|
|
1530
|
+
# Extract size information
|
|
1531
|
+
max_level = max(filedata["mb_logical"][:, 3])
|
|
1532
|
+
if level is None:
|
|
1533
|
+
level = max_level
|
|
1534
|
+
block_size = [filedata["nx1_mb"], filedata["nx2_mb"], filedata["nx3_mb"]]
|
|
1535
|
+
root_grid_size = [filedata["Nx1"], filedata["Nx2"], filedata["Nx3"]]
|
|
1536
|
+
levels = filedata["mb_logical"][:, 3]
|
|
1537
|
+
logical_locations = filedata["mb_logical"][:, :3]
|
|
1538
|
+
if dtype is None:
|
|
1539
|
+
dtype = np.float32
|
|
1540
|
+
|
|
1541
|
+
# Calculate nx_vals
|
|
1542
|
+
nx_vals = []
|
|
1543
|
+
for d in range(3):
|
|
1544
|
+
if block_size[d] == 1 and root_grid_size[d] > 1:
|
|
1545
|
+
# Implement logic for sum or slice as in athdf
|
|
1546
|
+
nx_vals.append(root_grid_size[d] * 2**level)
|
|
1547
|
+
elif block_size[d] == 1:
|
|
1548
|
+
nx_vals.append(1)
|
|
1549
|
+
else:
|
|
1550
|
+
nx_vals.append(root_grid_size[d] * 2**level + 2 * num_ghost)
|
|
1551
|
+
nx1, nx2, nx3 = nx_vals
|
|
1552
|
+
lx1, lx2, lx3 = [nx // bs for nx, bs in zip(nx_vals, block_size)]
|
|
1553
|
+
|
|
1554
|
+
# Set coordinate system and related functions
|
|
1555
|
+
# coord = "cartesian" # Adjust based on your data
|
|
1556
|
+
if vol_func is None:
|
|
1557
|
+
|
|
1558
|
+
def vol_func(xm, xp, ym, yp, zm, zp):
|
|
1559
|
+
return (xp - xm) * (yp - ym) * (zp - zm)
|
|
1560
|
+
|
|
1561
|
+
# Define center functions if not provided
|
|
1562
|
+
if center_func_1 is None:
|
|
1563
|
+
|
|
1564
|
+
def center_func_1(xm, xp):
|
|
1565
|
+
return 0.5 * (xm + xp)
|
|
1566
|
+
|
|
1567
|
+
if center_func_2 is None:
|
|
1568
|
+
|
|
1569
|
+
def center_func_2(xm, xp):
|
|
1570
|
+
return 0.5 * (xm + xp)
|
|
1571
|
+
|
|
1572
|
+
if center_func_3 is None:
|
|
1573
|
+
|
|
1574
|
+
def center_func_3(xm, xp):
|
|
1575
|
+
return 0.5 * (xm + xp)
|
|
1576
|
+
|
|
1577
|
+
# Populate coordinate arrays
|
|
1578
|
+
center_funcs = [center_func_1, center_func_2, center_func_3]
|
|
1579
|
+
for d in range(1, 4):
|
|
1580
|
+
xf = f"x{d}f"
|
|
1581
|
+
xv = f"x{d}v"
|
|
1582
|
+
nx = nx_vals[d - 1]
|
|
1583
|
+
if nx == 1:
|
|
1584
|
+
xmin = filedata[f"x{d}min"]
|
|
1585
|
+
xmax = filedata[f"x{d}max"]
|
|
1586
|
+
data[xf] = np.array([xmin, xmax], dtype=dtype)
|
|
1587
|
+
else:
|
|
1588
|
+
xmin = filedata[f"x{d}min"]
|
|
1589
|
+
xmax = filedata[f"x{d}max"]
|
|
1590
|
+
data[xf] = np.linspace(xmin, xmax, nx + 1, dtype=dtype)
|
|
1591
|
+
data[xv] = np.empty(nx, dtype=dtype)
|
|
1592
|
+
for i in range(nx):
|
|
1593
|
+
data[xv][i] = center_funcs[d - 1](data[xf][i], data[xf][i + 1])
|
|
1594
|
+
|
|
1595
|
+
# Create list of quantities
|
|
1596
|
+
if quantities is None:
|
|
1597
|
+
quantities = filedata["var_names"]
|
|
1598
|
+
|
|
1599
|
+
# Account for selection
|
|
1600
|
+
i_min, i_max = 0, nx1
|
|
1601
|
+
j_min, j_max = 0, nx2
|
|
1602
|
+
k_min, k_max = 0, nx3
|
|
1603
|
+
if x1_min is not None:
|
|
1604
|
+
i_min = max(i_min, np.searchsorted(data["x1f"], x1_min))
|
|
1605
|
+
if x1_max is not None:
|
|
1606
|
+
i_max = min(i_max, np.searchsorted(data["x1f"], x1_max))
|
|
1607
|
+
if x2_min is not None:
|
|
1608
|
+
j_min = max(j_min, np.searchsorted(data["x2f"], x2_min))
|
|
1609
|
+
if x2_max is not None:
|
|
1610
|
+
j_max = min(j_max, np.searchsorted(data["x2f"], x2_max))
|
|
1611
|
+
if x3_min is not None:
|
|
1612
|
+
k_min = max(k_min, np.searchsorted(data["x3f"], x3_min))
|
|
1613
|
+
if x3_max is not None:
|
|
1614
|
+
k_max = min(k_max, np.searchsorted(data["x3f"], x3_max))
|
|
1615
|
+
|
|
1616
|
+
# Prepare arrays for data and bookkeeping
|
|
1617
|
+
if new_data:
|
|
1618
|
+
for q in quantities:
|
|
1619
|
+
data[q] = np.zeros(
|
|
1620
|
+
(k_max - k_min, j_max - j_min, i_max - i_min), dtype=dtype
|
|
1621
|
+
)
|
|
1622
|
+
if return_levels:
|
|
1623
|
+
data["Levels"] = np.empty(
|
|
1624
|
+
(k_max - k_min, j_max - j_min, i_max - i_min), dtype=np.int32
|
|
1625
|
+
)
|
|
1626
|
+
else:
|
|
1627
|
+
for q in quantities:
|
|
1628
|
+
data[q].fill(0.0)
|
|
1629
|
+
if not subsample and not fast_restrict and max_level > level:
|
|
1630
|
+
restricted_data = np.zeros((lx3, lx2, lx1), dtype=bool)
|
|
1631
|
+
|
|
1632
|
+
# Step 3: Process each block
|
|
1633
|
+
for block_num in range(filedata["n_mbs"]):
|
|
1634
|
+
block_level = levels[block_num]
|
|
1635
|
+
block_location = logical_locations[block_num]
|
|
1636
|
+
|
|
1637
|
+
# Implement logic for prolongation, restriction, subsampling
|
|
1638
|
+
if block_level <= level:
|
|
1639
|
+
s = 2 ** (level - block_level)
|
|
1640
|
+
il_d = block_location[0] * block_size[0] * s if nx1 > 1 else 0
|
|
1641
|
+
jl_d = block_location[1] * block_size[1] * s if nx2 > 1 else 0
|
|
1642
|
+
kl_d = block_location[2] * block_size[2] * s if nx3 > 1 else 0
|
|
1643
|
+
iu_d = il_d + block_size[0] * s if nx1 > 1 else 1
|
|
1644
|
+
ju_d = jl_d + block_size[1] * s if nx2 > 1 else 1
|
|
1645
|
+
ku_d = kl_d + block_size[2] * s if nx3 > 1 else 1
|
|
1646
|
+
|
|
1647
|
+
il_s = max(il_d, i_min) - il_d
|
|
1648
|
+
jl_s = max(jl_d, j_min) - jl_d
|
|
1649
|
+
kl_s = max(kl_d, k_min) - kl_d
|
|
1650
|
+
iu_s = min(iu_d, i_max) - il_d
|
|
1651
|
+
ju_s = min(ju_d, j_max) - jl_d
|
|
1652
|
+
ku_s = min(ku_d, k_max) - kl_d
|
|
1653
|
+
|
|
1654
|
+
if il_s >= iu_s or jl_s >= ju_s or kl_s >= ku_s:
|
|
1655
|
+
continue
|
|
1656
|
+
|
|
1657
|
+
il_d = max(il_d, i_min) - i_min
|
|
1658
|
+
jl_d = max(jl_d, j_min) - j_min
|
|
1659
|
+
kl_d = max(kl_d, k_min) - k_min
|
|
1660
|
+
iu_d = min(iu_d, i_max) - i_min
|
|
1661
|
+
ju_d = min(ju_d, j_max) - j_min
|
|
1662
|
+
ku_d = min(ku_d, k_max) - k_min
|
|
1663
|
+
|
|
1664
|
+
for q in quantities:
|
|
1665
|
+
block_data = filedata["mb_data"][q][block_num]
|
|
1666
|
+
if s > 1:
|
|
1667
|
+
block_data = np.repeat(
|
|
1668
|
+
np.repeat(np.repeat(block_data, s, axis=2), s, axis=1),
|
|
1669
|
+
s,
|
|
1670
|
+
axis=0,
|
|
1671
|
+
)
|
|
1672
|
+
data[q][kl_d:ku_d, jl_d:ju_d, il_d:iu_d] = block_data[
|
|
1673
|
+
kl_s:ku_s, jl_s:ju_s, il_s:iu_s
|
|
1674
|
+
]
|
|
1675
|
+
else:
|
|
1676
|
+
# Implement restriction logic here (similar to athdf function)
|
|
1677
|
+
pass
|
|
1678
|
+
|
|
1679
|
+
if return_levels:
|
|
1680
|
+
data["Levels"][kl_d:ku_d, jl_d:ju_d, il_d:iu_d] = block_level
|
|
1681
|
+
|
|
1682
|
+
# Step 4: Finalize data
|
|
1683
|
+
if level < max_level and not subsample and not fast_restrict:
|
|
1684
|
+
# Remove volume factors from restricted data
|
|
1685
|
+
for loc3 in range(lx3):
|
|
1686
|
+
for loc2 in range(lx2):
|
|
1687
|
+
for loc1 in range(lx1):
|
|
1688
|
+
if restricted_data[loc3, loc2, loc1]:
|
|
1689
|
+
il = loc1 * block_size[0]
|
|
1690
|
+
jl = loc2 * block_size[1]
|
|
1691
|
+
kl = loc3 * block_size[2]
|
|
1692
|
+
iu = il + block_size[0]
|
|
1693
|
+
ju = jl + block_size[1]
|
|
1694
|
+
ku = kl + block_size[2]
|
|
1695
|
+
il = max(il, i_min) - i_min
|
|
1696
|
+
jl = max(jl, j_min) - j_min
|
|
1697
|
+
kl = max(kl, k_min) - k_min
|
|
1698
|
+
iu = min(iu, i_max) - i_min
|
|
1699
|
+
ju = min(ju, j_max) - j_min
|
|
1700
|
+
ku = min(ku, k_max) - k_min
|
|
1701
|
+
for k in range(kl, ku):
|
|
1702
|
+
for j in range(jl, ju):
|
|
1703
|
+
for i in range(il, iu):
|
|
1704
|
+
x1m, x1p = data["x1f"][i], data["x1f"][i + 1]
|
|
1705
|
+
x2m, x2p = data["x2f"][j], data["x2f"][j + 1]
|
|
1706
|
+
x3m, x3p = data["x3f"][k], data["x3f"][k + 1]
|
|
1707
|
+
vol = vol_func(x1m, x1p, x2m, x2p, x3m, x3p)
|
|
1708
|
+
for q in quantities:
|
|
1709
|
+
data[q][k, j, i] /= vol
|
|
1710
|
+
|
|
1711
|
+
# Add metadata
|
|
1712
|
+
data["Time"] = filedata["time"]
|
|
1713
|
+
data["NumCycles"] = filedata["cycle"]
|
|
1714
|
+
data["MaxLevel"] = max_level
|
|
1715
|
+
|
|
1716
|
+
return data
|
|
1717
|
+
|
|
1718
|
+
|
|
1719
|
+
def write_athdf(filename, fdata, varsize_bytes=4, locsize_bytes=8):
|
|
1720
|
+
"""
|
|
1721
|
+
Writes an athdf (hdf5) file from a loaded python filedata object.
|
|
1722
|
+
|
|
1723
|
+
args:
|
|
1724
|
+
filename - string
|
|
1725
|
+
filename for output athdf (hdf5) file
|
|
1726
|
+
fdata - dict
|
|
1727
|
+
dictionary of fluid file data, e.g., as loaded from read_binary(...)
|
|
1728
|
+
varsize_bytes - int (default=4, options=4,8)
|
|
1729
|
+
number of bytes to use for output variable data
|
|
1730
|
+
locsize_bytes - int (default=8, options=4,8)
|
|
1731
|
+
number of bytes to use for output location data
|
|
1732
|
+
"""
|
|
1733
|
+
|
|
1734
|
+
if varsize_bytes not in [4, 8]:
|
|
1735
|
+
raise ValueError(f"varsizebytes must be 4 or 8, not {varsize_bytes}")
|
|
1736
|
+
if locsize_bytes not in [4, 8]:
|
|
1737
|
+
raise ValueError(f"locsizebytes must be 4 or 8, not {locsize_bytes}")
|
|
1738
|
+
locfmt = "<f4" if locsize_bytes == 4 else "<f8"
|
|
1739
|
+
varfmt = "<f4" if varsize_bytes == 4 else "<f8"
|
|
1740
|
+
|
|
1741
|
+
# extract Mesh/MeshBlock parameters
|
|
1742
|
+
nmb = fdata["n_mbs"]
|
|
1743
|
+
Nx1 = fdata["Nx1"] # noqa: F841
|
|
1744
|
+
Nx2 = fdata["Nx2"]
|
|
1745
|
+
Nx3 = fdata["Nx3"]
|
|
1746
|
+
nx1 = fdata["nx1_mb"]
|
|
1747
|
+
nx2 = fdata["nx2_mb"]
|
|
1748
|
+
nx3 = fdata["nx3_mb"]
|
|
1749
|
+
nx1_out = fdata["nx1_out_mb"]
|
|
1750
|
+
nx2_out = fdata["nx2_out_mb"]
|
|
1751
|
+
nx3_out = fdata["nx3_out_mb"]
|
|
1752
|
+
|
|
1753
|
+
number_of_moments = fdata.get("number_of_moments", 1)
|
|
1754
|
+
|
|
1755
|
+
# check dimensionality/slicing
|
|
1756
|
+
two_d = Nx2 != 1 and Nx3 == 1
|
|
1757
|
+
three_d = Nx3 != 1
|
|
1758
|
+
x1slice = nx1_out == 1
|
|
1759
|
+
x2slice = nx2_out == 1 and (two_d or three_d)
|
|
1760
|
+
x3slice = nx3_out == 1 and three_d
|
|
1761
|
+
|
|
1762
|
+
# keep variable order but separate out magnetic field
|
|
1763
|
+
vars_without_b = [v for v in fdata["var_names"] if "bcc" not in v]
|
|
1764
|
+
vars_only_b = [v for v in fdata["var_names"] if v not in vars_without_b]
|
|
1765
|
+
|
|
1766
|
+
if len(vars_only_b) > 0:
|
|
1767
|
+
B = np.zeros((3 * number_of_moments, nmb, nx3_out, nx2_out, nx1_out))
|
|
1768
|
+
Levels = np.zeros(nmb)
|
|
1769
|
+
LogicalLocations = np.zeros((nmb, 3))
|
|
1770
|
+
uov = np.zeros((len(vars_without_b), nmb, nx3_out, nx2_out, nx1_out))
|
|
1771
|
+
x1f = np.zeros((nmb, nx1_out + 1))
|
|
1772
|
+
x1v = np.zeros((nmb, nx1_out))
|
|
1773
|
+
x2f = np.zeros((nmb, nx2_out + 1))
|
|
1774
|
+
x2v = np.zeros((nmb, nx2_out))
|
|
1775
|
+
x3f = np.zeros((nmb, nx3_out + 1))
|
|
1776
|
+
x3v = np.zeros((nmb, nx3_out))
|
|
1777
|
+
|
|
1778
|
+
for ivar, var in enumerate(vars_without_b):
|
|
1779
|
+
uov[ivar] = fdata["mb_data"][var]
|
|
1780
|
+
for ibvar, bvar in enumerate(vars_only_b):
|
|
1781
|
+
B[ibvar] = fdata["mb_data"][bvar]
|
|
1782
|
+
|
|
1783
|
+
for mb in range(nmb):
|
|
1784
|
+
logical = fdata["mb_logical"][mb]
|
|
1785
|
+
LogicalLocations[mb] = logical[:3]
|
|
1786
|
+
Levels[mb] = logical[-1]
|
|
1787
|
+
geometry = fdata["mb_geometry"][mb]
|
|
1788
|
+
mb_x1f = np.linspace(geometry[0], geometry[1], nx1 + 1)
|
|
1789
|
+
mb_x1v = 0.5 * (mb_x1f[1:] + mb_x1f[:-1])
|
|
1790
|
+
mb_x2f = np.linspace(geometry[2], geometry[3], nx2 + 1)
|
|
1791
|
+
mb_x2v = 0.5 * (mb_x2f[1:] + mb_x2f[:-1])
|
|
1792
|
+
mb_x3f = np.linspace(geometry[4], geometry[5], nx3 + 1)
|
|
1793
|
+
mb_x3v = 0.5 * (mb_x3f[1:] + mb_x3f[:-1])
|
|
1794
|
+
if x1slice:
|
|
1795
|
+
x1f[mb] = np.array(
|
|
1796
|
+
mb_x1f[(fdata["mb_index"][mb][0]): (fdata["mb_index"][mb][0] + 2)]
|
|
1797
|
+
)
|
|
1798
|
+
x1v[mb] = np.array([np.average(mb_x1f)])
|
|
1799
|
+
else:
|
|
1800
|
+
x1f[mb] = mb_x1f
|
|
1801
|
+
x1v[mb] = mb_x1v
|
|
1802
|
+
if x2slice:
|
|
1803
|
+
x2f[mb] = np.array(
|
|
1804
|
+
mb_x2f[(fdata["mb_index"][mb][2]): (fdata["mb_index"][mb][2] + 2)]
|
|
1805
|
+
)
|
|
1806
|
+
x2v[mb] = np.array([np.average(x2f[mb])])
|
|
1807
|
+
else:
|
|
1808
|
+
x2f[mb] = mb_x2f
|
|
1809
|
+
x2v[mb] = mb_x2v
|
|
1810
|
+
if x3slice:
|
|
1811
|
+
x3f[mb] = np.array(
|
|
1812
|
+
mb_x3f[(fdata["mb_index"][mb][4]): (fdata["mb_index"][mb][4] + 2)]
|
|
1813
|
+
)
|
|
1814
|
+
x3v[mb] = np.array([np.average(x3f[mb])])
|
|
1815
|
+
else:
|
|
1816
|
+
x3f[mb] = mb_x3f
|
|
1817
|
+
x3v[mb] = mb_x3v
|
|
1818
|
+
|
|
1819
|
+
# set dataset names and number of variables
|
|
1820
|
+
dataset_names = [np.array("uov", dtype="|S21")]
|
|
1821
|
+
dataset_nvars = [len(vars_without_b)]
|
|
1822
|
+
if len(vars_only_b) > 0:
|
|
1823
|
+
dataset_names.append(np.array("B", dtype="|S21"))
|
|
1824
|
+
dataset_nvars.append(len(vars_only_b))
|
|
1825
|
+
|
|
1826
|
+
# Set Attributes
|
|
1827
|
+
hfp = h5py.File(filename, "w")
|
|
1828
|
+
hfp.attrs["Header"] = fdata["header"]
|
|
1829
|
+
hfp.attrs["Time"] = fdata["time"]
|
|
1830
|
+
hfp.attrs["NumCycles"] = fdata["cycle"]
|
|
1831
|
+
hfp.attrs["Coordinates"] = np.array("cartesian", dtype="|S11")
|
|
1832
|
+
hfp.attrs["NumMeshBlocks"] = fdata["n_mbs"]
|
|
1833
|
+
hfp.attrs["MaxLevel"] = int(max(Levels))
|
|
1834
|
+
hfp.attrs["MeshBlockSize"] = [
|
|
1835
|
+
fdata["nx1_out_mb"],
|
|
1836
|
+
fdata["nx2_out_mb"],
|
|
1837
|
+
fdata["nx3_out_mb"],
|
|
1838
|
+
]
|
|
1839
|
+
hfp.attrs["RootGridSize"] = [fdata["Nx1"], fdata["Nx2"], fdata["Nx3"]]
|
|
1840
|
+
hfp.attrs["RootGridX1"] = [fdata["x1min"], fdata["x1max"], 1.0]
|
|
1841
|
+
hfp.attrs["RootGridX2"] = [fdata["x2min"], fdata["x2max"], 1.0]
|
|
1842
|
+
hfp.attrs["RootGridX3"] = [fdata["x3min"], fdata["x3max"], 1.0]
|
|
1843
|
+
hfp.attrs["DatasetNames"] = dataset_names
|
|
1844
|
+
hfp.attrs["NumVariables"] = dataset_nvars
|
|
1845
|
+
hfp.attrs["VariableNames"] = [
|
|
1846
|
+
np.array(i, dtype="|S21") for i in (vars_without_b + vars_only_b)
|
|
1847
|
+
]
|
|
1848
|
+
|
|
1849
|
+
# Create Datasets
|
|
1850
|
+
if len(vars_only_b) > 0:
|
|
1851
|
+
hfp.create_dataset("B", data=B, dtype=varfmt)
|
|
1852
|
+
hfp.create_dataset("Levels", data=Levels, dtype=">i4")
|
|
1853
|
+
hfp.create_dataset("LogicalLocations", data=LogicalLocations, dtype=">i8")
|
|
1854
|
+
hfp.create_dataset("uov", data=uov, dtype=varfmt)
|
|
1855
|
+
hfp.create_dataset("x1f", data=x1f, dtype=locfmt)
|
|
1856
|
+
hfp.create_dataset("x1v", data=x1v, dtype=locfmt)
|
|
1857
|
+
hfp.create_dataset("x2f", data=x2f, dtype=locfmt)
|
|
1858
|
+
hfp.create_dataset("x2v", data=x2v, dtype=locfmt)
|
|
1859
|
+
hfp.create_dataset("x3f", data=x3f, dtype=locfmt)
|
|
1860
|
+
hfp.create_dataset("x3v", data=x3v, dtype=locfmt)
|
|
1861
|
+
hfp.close()
|
|
1862
|
+
|
|
1863
|
+
|
|
1864
|
+
def write_xdmf_for(xdmfname, dumpname, fdata, mode="auto"):
|
|
1865
|
+
"""
|
|
1866
|
+
Writes an xdmf file for a fluid snapshot file.
|
|
1867
|
+
|
|
1868
|
+
args:
|
|
1869
|
+
xdmfname - string
|
|
1870
|
+
name of xdmf file
|
|
1871
|
+
dumpname - string
|
|
1872
|
+
location of fluid data file relative to xdmfname directory
|
|
1873
|
+
fdata - dict
|
|
1874
|
+
dictionary of fluid file data, e.g., as loaded from read_binary(...)
|
|
1875
|
+
mode - string (unimplemented)
|
|
1876
|
+
force xdmf for format (auto sets by extension)
|
|
1877
|
+
"""
|
|
1878
|
+
|
|
1879
|
+
fp = open(xdmfname, "w")
|
|
1880
|
+
|
|
1881
|
+
def write_meshblock(fp, mb, nx1, nx2, nx3, nmb, dumpname, vars_no_b, vars_w_b):
|
|
1882
|
+
fp.write(f""" <Grid Name="MeshBlock{mb}" GridType="Uniform">\n""")
|
|
1883
|
+
fp.write(""" <Topology TopologyType="3DRectMesh" """)
|
|
1884
|
+
fp.write(f""" NumberOfElements="{nx3+1} {nx2+1} {nx1+1}"/>\n""")
|
|
1885
|
+
fp.write(""" <Geometry GeometryType="VXVYVZ">\n""")
|
|
1886
|
+
fp.write(
|
|
1887
|
+
f""" <DataItem ItemType="HyperSlab" Dimensions="{nx1+1}">
|
|
1888
|
+
<DataItem Dimensions="3 2" NumberType="Int"> {mb} 0 1 1 1 {nx1+1} </DataItem>
|
|
1889
|
+
<DataItem Dimensions="{nmb} {nx1+1}" Format="HDF"> {dumpname}:/x1f </DataItem>
|
|
1890
|
+
</DataItem>
|
|
1891
|
+
<DataItem ItemType="HyperSlab" Dimensions="{nx2+1}">
|
|
1892
|
+
<DataItem Dimensions="3 2" NumberType="Int"> {mb} 0 1 1 1 {nx2+1} </DataItem>
|
|
1893
|
+
<DataItem Dimensions="{nmb} {nx2+1}" Format="HDF"> {dumpname}:/x2f </DataItem>
|
|
1894
|
+
</DataItem>
|
|
1895
|
+
<DataItem ItemType="HyperSlab" Dimensions="{nx3+1}">
|
|
1896
|
+
<DataItem Dimensions="3 2" NumberType="Int"> {mb} 0 1 1 1 {nx3+1} </DataItem>
|
|
1897
|
+
<DataItem Dimensions="{nmb} {nx3+1}" Format="HDF"> {dumpname}:/x3f </DataItem>
|
|
1898
|
+
</DataItem>
|
|
1899
|
+
</Geometry>\n"""
|
|
1900
|
+
)
|
|
1901
|
+
|
|
1902
|
+
nvar_no_b = len(vars_no_b)
|
|
1903
|
+
for vi, var_name in enumerate(vars_no_b):
|
|
1904
|
+
fp.write(
|
|
1905
|
+
f""" <Attribute Name="{var_name}" Center="Cell">
|
|
1906
|
+
<DataItem ItemType="HyperSlab" Dimensions="{nx3} {nx2} {nx1}">
|
|
1907
|
+
<DataItem Dimensions="3 5" NumberType="Int">
|
|
1908
|
+
{vi} {mb} 0 0 0 1 1 1 1 1 1 1 {nx3} {nx2} {nx1}
|
|
1909
|
+
</DataItem>
|
|
1910
|
+
<DataItem Dimensions="{nvar_no_b} {nmb} {nx3} {nx2} {nx1}" Format="HDF">
|
|
1911
|
+
{dumpname}:/uov
|
|
1912
|
+
</DataItem>
|
|
1913
|
+
</DataItem>
|
|
1914
|
+
</Attribute>\n"""
|
|
1915
|
+
)
|
|
1916
|
+
|
|
1917
|
+
nvar_w_b = len(vars_w_b)
|
|
1918
|
+
if nvar_w_b > 0:
|
|
1919
|
+
for vi, var_name in enumerate(vars_w_b):
|
|
1920
|
+
fp.write(
|
|
1921
|
+
f""" <Attribute Name="{var_name}" Center="Cell">
|
|
1922
|
+
<DataItem ItemType="HyperSlab" Dimensions="{nx3} {nx2} {nx1}">
|
|
1923
|
+
<DataItem Dimensions="3 5" NumberType="Int">
|
|
1924
|
+
{vi} {mb} 0 0 0 1 1 1 1 1 1 1 {nx3} {nx2} {nx1}
|
|
1925
|
+
</DataItem>
|
|
1926
|
+
<DataItem Dimensions="{nvar_w_b} {nmb} {nx3} {nx2} {nx1}" Format="HDF">
|
|
1927
|
+
{dumpname}:/B
|
|
1928
|
+
</DataItem>
|
|
1929
|
+
</DataItem>
|
|
1930
|
+
</Attribute>\n"""
|
|
1931
|
+
)
|
|
1932
|
+
|
|
1933
|
+
fp.write(""" </Grid>\n""")
|
|
1934
|
+
|
|
1935
|
+
fp.write(
|
|
1936
|
+
"""<?xml version="1.0" ?>
|
|
1937
|
+
<!DOCTYPE Xdmf SYSTEM "Xdmf.dtd" []>
|
|
1938
|
+
<Xdmf Version="2.0">
|
|
1939
|
+
<Information Name="TimeVaryingMetaData" Value="True"/>\n"""
|
|
1940
|
+
)
|
|
1941
|
+
fp.write("""<Domain>\n""")
|
|
1942
|
+
fp.write("""<Grid Name="Mesh" GridType="Collection">\n""")
|
|
1943
|
+
fp.write(f""" <Time Value="{fdata['time']}"/>\n""")
|
|
1944
|
+
|
|
1945
|
+
vars_without_b = [v for v in fdata["var_names"] if "bcc" not in v]
|
|
1946
|
+
vars_only_b = [v for v in fdata["var_names"] if v not in vars_without_b]
|
|
1947
|
+
|
|
1948
|
+
nx1 = fdata["nx1_out_mb"]
|
|
1949
|
+
nx2 = fdata["nx2_out_mb"]
|
|
1950
|
+
nx3 = fdata["nx3_out_mb"]
|
|
1951
|
+
nmb = fdata["n_mbs"]
|
|
1952
|
+
|
|
1953
|
+
for mb in range(nmb):
|
|
1954
|
+
write_meshblock(
|
|
1955
|
+
fp, mb, nx1, nx2, nx3, nmb, dumpname, vars_without_b, vars_only_b
|
|
1956
|
+
)
|
|
1957
|
+
|
|
1958
|
+
fp.write("""</Grid>\n""")
|
|
1959
|
+
fp.write("""</Domain>\n""")
|
|
1960
|
+
fp.write("""</Xdmf>\n""")
|
|
1961
|
+
|
|
1962
|
+
fp.close()
|
|
1963
|
+
|
|
1964
|
+
|
|
1965
|
+
def convert_file(binary_fname):
|
|
1966
|
+
"""
|
|
1967
|
+
Converts a single file.
|
|
1968
|
+
|
|
1969
|
+
args:
|
|
1970
|
+
binary_filename - string
|
|
1971
|
+
filename of bin file to convert
|
|
1972
|
+
|
|
1973
|
+
This will create new files "binary_data.bin" -> "binary_data.athdf" and
|
|
1974
|
+
"binary_data.athdf.xdmf"
|
|
1975
|
+
"""
|
|
1976
|
+
athdf_fname = binary_fname.replace(".bin", "") + ".athdf"
|
|
1977
|
+
xdmf_fname = athdf_fname + ".xdmf"
|
|
1978
|
+
filedata = read_binary(binary_fname)
|
|
1979
|
+
write_athdf(athdf_fname, filedata)
|
|
1980
|
+
write_xdmf_for(xdmf_fname, os.path.basename(athdf_fname), filedata)
|
|
1981
|
+
|
|
1982
|
+
|
|
1983
|
+
if __name__ == "__main__":
|
|
1984
|
+
import sys
|
|
1985
|
+
|
|
1986
|
+
try:
|
|
1987
|
+
from tqdm import tqdm
|
|
1988
|
+
except ModuleNotFoundError:
|
|
1989
|
+
|
|
1990
|
+
def tqdm(L):
|
|
1991
|
+
for x in L:
|
|
1992
|
+
print(x)
|
|
1993
|
+
yield x
|
|
1994
|
+
|
|
1995
|
+
if len(sys.argv) < 2:
|
|
1996
|
+
print(f"Usage: {sys.argv[0]} output_file_1.bin [output_file_2.bin [...]]")
|
|
1997
|
+
exit(1)
|
|
1998
|
+
|
|
1999
|
+
for binary_fname in tqdm(sys.argv[1:]):
|
|
2000
|
+
convert_file(binary_fname)
|