def readre2(fname): """A function for reading .re2 files for nek5000 Parameters ---------- fname : str file name """ # try: infile = open(fname, 'rb') except OSError as e: logger.critical(f'I/O error ({e.errno}): {e.strerror}') return -1 # the header for re2 files is 80 ASCII bytes, something like # #v002 18669 2 18669 this is the hdr % header = infile.read(80).split() nel = int(header[1]) ndim = int(header[2]) # always double precision wdsz = 8 realtype = 'd' # detect endianness etagb = infile.read(4) etagL = struct.unpack('<f', etagb)[0] etagL = int(etagL * 1e5) / 1e5 etagB = struct.unpack('>f', etagb)[0] etagB = int(etagB * 1e5) / 1e5 if (etagL == 6.54321): logger.debug('Reading little-endian file\n') emode = '<' endian = 'little' elif (etagB == 6.54321): logger.debug('Reading big-endian file\n') emode = '>' endian = 'big' else: logger.error('Could not interpret endianness') return -3 # # there are no GLL points here, only quad/hex vertices lr1 = [2, 2, ndim - 1] npel = 2**ndim # the file only contains geometry var = [ndim, 0, 0, 0, 0] # allocate structure data = exdat.exadata(ndim, nel, lr1, var, 1) # # some metadata data.wdsz = wdsz data.endian = endian # # read the whole geometry into a buffer # for some reason each element is prefixed with 8 bytes of zeros, it's not clear to me why. # This is the reason for the +1 here, then the first number is ignored. buf = infile.read((ndim * npel + 1) * wdsz * nel) elem_shape = [ndim, ndim - 1, 2, 2] # nvar, lz, ly, lx for (iel, el) in enumerate(data.elem): fi = np.frombuffer(buf, dtype=emode + realtype, count=ndim * npel + 1, offset=(ndim * npel + 1) * wdsz * iel) # the data is stored in the following order (2D|3D): # x1, x2, x4, x3; | x5, x6, x8, x7; # y1, y2, y4, y3; | y5, y6, y8, y7; # ---------------- # z1, z2, z4, z3; z5, z6, z8, z7; # where 1-8 is the ordering of the points in memory for idim in range(ndim): # x, y, [z] for iz in range( ndim - 1 ): # this does only one iteration in 2D, and in 3D does one iteration for 1-4 and one for 5-8 el.pos[idim, iz, 0, 0] = fi[npel * idim + 4 * iz + 1] el.pos[idim, iz, 0, 1] = fi[npel * idim + 4 * iz + 2] el.pos[idim, iz, 1, 1] = fi[npel * idim + 4 * iz + 3] el.pos[idim, iz, 1, 0] = fi[npel * idim + 4 * iz + 4] # # read curved sides # the number of curved sides is stored as a double, # then each curved side is 64 bytes: # iel iface p1 p2 p3 p4 p5 ctype # where p1-5 are f64 parameters and ctype is the type of curvature in ASCII ncparam = 8 buf = infile.read(wdsz) ncurv = int(np.frombuffer(buf)[0]) logger.debug(f'Found {ncurv} curved sides') data.ncurv = ncurv buf = infile.read(wdsz * (ncparam * ncurv)) for icurv in range(ncurv): # interpret the data curv = np.frombuffer(buf, dtype=emode + realtype, count=ncparam, offset=icurv * ncparam * wdsz) iel = int(curv[0]) - 1 iedge = int(curv[1]) - 1 cparams = curv[2:7] # select only the first byte, because it turns out the later bytes may contain garbage. # typically, it's b'C\x00\x00\x00\x00\x00\x00\x00' or b'C\x00\x00\x00\x00\x00\xe0?'. # AFAIK the curvature types are always one character long anyway. ctype = curv[7].tobytes()[:1].decode('utf-8') # fill in the data structure data.elem[iel].curv[iedge, :] = cparams data.elem[iel].ccurv[iedge] = ctype # # read boundary conditions # there can be more than one field, and we won't know until we'vre reached the end nbcparam = 8 buf = infile.read(wdsz) ifield = 0 while buf != b'': # the data is initialized with one BC field, we might need to allocate another if ifield > 0: data.nbc = data.nbc + 1 for el in data.elem: empty_bcs = np.zeros(el.bcs[:1, :].shape, dtype=el.bcs.dtype) el.bcs = np.concatenate((el.bcs, empty_bcs)) nbclines = int(np.frombuffer(buf)[0]) logger.debug( f'Found {nbclines} external boundary conditions for field {ifield}' ) buf = infile.read(wdsz * (nbcparam * nbclines)) for ibc in range(nbclines): # interpret the data bc = np.frombuffer(buf, dtype=emode + realtype, count=nbcparam, offset=ibc * nbcparam * wdsz) iel = int(bc[0]) - 1 iface = int(bc[1]) - 1 bcparams = bc[2:7] bctype = bc[7].tobytes().decode( 'utf-8').rstrip() # remove trailing spaces # fill in the data structure data.elem[iel].bcs[ifield, iface][0] = bctype data.elem[iel].bcs[ifield, iface][1] = iel + 1 data.elem[iel].bcs[ifield, iface][2] = iface + 1 for ipar in range(5): data.elem[iel].bcs[ifield, iface][3 + ipar] = bcparams[ipar] ifield = ifield + 1 # try reading the number of conditions in the next field buf = infile.read(wdsz) infile.close() return data
def readnek(fname): """A function for reading binary data from the nek5000 binary format Parameters ---------- fname : str file name """ # try: infile = open(fname, 'rb') except OSError as e: logger.critical(f'I/O error ({e.errno}): {e.strerror}') return -1 # #--------------------------------------------------------------------------- # READ HEADER #--------------------------------------------------------------------------- # # read header header = infile.read(132).split() logger.debug('Header: {}'.format(b' '.join(header).decode('utf-8'))) # get word size: single or double precision wdsz = int(header[1]) if (wdsz == 4): realtype = 'f' elif (wdsz == 8): realtype = 'd' else: logger.error('Could not interpret real type (wdsz = %i)' % (wdsz)) return -2 # # get polynomial order lr1 = [int(header[2]), int(header[3]), int(header[4])] # # compute total number of points per element npel = lr1[0] * lr1[1] * lr1[2] # # get number of physical dimensions ndim = 2 + (lr1[2] > 1) # # get number of elements nel = int(header[5]) # # get number of elements in the file nelf = int(header[6]) # # get current time time = float(header[7]) # # get current time step istep = int(header[8]) # # get file id fid = int(header[9]) # # get tot number of files nf = int(header[10]) # # get variables [XUPTS[01-99]] variables = header[11].decode('utf-8') logger.debug(f"Variables: {variables}") var = [0 for i in range(5)] for v in variables: if (v == 'X'): var[0] = ndim elif (v == 'U'): var[1] = ndim elif (v == 'P'): var[2] = 1 elif (v == 'T'): var[3] = 1 elif (v == 'S'): # For example: variables = 'XS44' index_s = variables.index('S') nb_scalars = int(variables[index_s + 1:]) var[4] = nb_scalars # # identify endian encoding etagb = infile.read(4) etagL = struct.unpack('<f', etagb)[0] etagL = int(etagL * 1e5) / 1e5 etagB = struct.unpack('>f', etagb)[0] etagB = int(etagB * 1e5) / 1e5 if (etagL == 6.54321): logger.debug('Reading little-endian file\n') emode = '<' elif (etagB == 6.54321): logger.debug('Reading big-endian file\n') emode = '>' else: logger.error('Could not interpret endianness') return -3 # # read element map for the file elmap = infile.read(4 * nelf) elmap = list(struct.unpack(emode + nelf * 'i', elmap)) # #--------------------------------------------------------------------------- # READ DATA #--------------------------------------------------------------------------- # # initialize data structure data = exdat.exadata(ndim, nel, lr1, var, 0) data.time = time data.istep = istep data.wdsz = wdsz data.elmap = np.array(elmap, dtype=np.int32) if (emode == '<'): data.endian = 'little' elif (emode == '>'): data.endian = 'big' # def read_file_into_data(data_var, index_var): """Read binary file into an array attribute of ``data.elem``""" fi = infile.read(npel * wdsz) fi = np.frombuffer(fi, dtype=emode + realtype, count=npel) # Replace elem array in-place with # array read from file after reshaping as elem_shape = lr1[::-1] # lz, ly, lx data_var[index_var, ...] = fi.reshape(elem_shape) # # read geometry for iel in elmap: el = data.elem[iel - 1] for idim in range(var[0]): # if var[0] == 0, geometry is not read read_file_into_data(el.pos, idim) # # read velocity for iel in elmap: el = data.elem[iel - 1] for idim in range(var[1]): # if var[1] == 0, velocity is not read read_file_into_data(el.vel, idim) # # read pressure for iel in elmap: el = data.elem[iel - 1] for ivar in range(var[2]): # if var[2] == 0, pressure is not read read_file_into_data(el.pres, ivar) # # read temperature for iel in elmap: el = data.elem[iel - 1] for ivar in range(var[3]): # if var[3] == 0, temperature is not read read_file_into_data(el.temp, ivar) # # read scalar fields # # NOTE: This is not a bug! # Unlike other variables, scalars are in the outer loop and elements # are in the inner loop # for ivar in range(var[4]): # if var[4] == 0, scalars are not read for iel in elmap: el = data.elem[iel - 1] read_file_into_data(el.scal, ivar) # # # close file infile.close() # # output return data
def readrea(fname): """A function for reading .rea files for nek5000 Parameters ---------- fname : str file name """ # try: infile = open(fname) except OSError as e: logger.critical(f'I/O error ({e.errno}): {e.strerror}') #return -1 # #--------------------------------------------------------------------------- # count the number of boundary conditions # (it's too dangerous to infer it from the header) #--------------------------------------------------------------------------- # nbc = 0 for line in infile: line_split = line.split() if 'BOUNDARY' in line_split[2:] and not 'NO' in line_split: nbc = nbc + 1 infile.seek(0) # #--------------------------------------------------------------------------- # READ HEADER (2 lines) + ndim + number of parameters #--------------------------------------------------------------------------- # infile.readline() infile.readline() ndim = int(infile.readline().split()[0]) npar = int(infile.readline().split()[0]) # nface = 2 * ndim # #--------------------------------------------------------------------------- # READ parameters #--------------------------------------------------------------------------- # param = np.zeros((npar, 1)) for ipar in range(npar): param[ipar] = float(infile.readline().split()[0]) # #--------------------------------------------------------------------------- # skip passive scalars #--------------------------------------------------------------------------- # npscal_data = int(infile.readline().split()[0]) for ipscal in range(npscal_data): infile.readline() # #--------------------------------------------------------------------------- # skip logical switches #--------------------------------------------------------------------------- # nswitch = int(infile.readline().split()[0]) for iswitch in range(nswitch): infile.readline() # #--------------------------------------------------------------------------- # skip XFAC,YFAC,XZERO,YZERO #--------------------------------------------------------------------------- # infile.readline() # #--------------------------------------------------------------------------- # READ MESH #--------------------------------------------------------------------------- # infile.readline() nel = int(infile.readline().split()[0]) # # initialize data structure lr1 = [2, 2, ndim - 1] var = [ndim, 0, 0, 0, 0] # data = exdat.exadata(ndim, nel, lr1, var, nbc) # # read geometry for iel in range(nel): # skip element number and group infile.readline() for idim in range(var[0] - 1): # if ndim == 3 do this twice for jdim in range(var[0]): fi = infile.readline().split() data.elem[iel].pos[jdim, idim, 0, 0] = float(fi[0]) data.elem[iel].pos[jdim, idim, 0, 1] = float(fi[1]) data.elem[iel].pos[jdim, idim, 1, 1] = float(fi[2]) data.elem[iel].pos[jdim, idim, 1, 0] = float(fi[3]) # #--------------------------------------------------------------------------- # CURVED SIDE DATA #--------------------------------------------------------------------------- # infile.readline() ncurved = int(infile.readline().split()[0]) data.ncurv = ncurved for icurved in range(ncurved): line = infile.readline() if (nel < 1e3): iedge = int(line[0:3]) - 1 iel = int(line[3:6]) - 1 data.elem[iel].curv[iedge][0] = float(line[6:20]) data.elem[iel].curv[iedge][1] = float(line[20:34]) data.elem[iel].curv[iedge][2] = float(line[34:48]) data.elem[iel].curv[iedge][3] = float(line[48:62]) data.elem[iel].curv[iedge][4] = float(line[62:76]) data.elem[iel].ccurv[iedge] = line[76:79].split()[0] elif (nel < 1e6): iedge = int(line[0:2]) - 1 iel = int(line[2:8]) - 1 data.elem[iel].curv[iedge][0] = float(line[8:22]) data.elem[iel].curv[iedge][1] = float(line[22:36]) data.elem[iel].curv[iedge][2] = float(line[36:50]) data.elem[iel].curv[iedge][3] = float(line[50:64]) data.elem[iel].curv[iedge][4] = float(line[64:78]) data.elem[iel].ccurv[iedge] = line[78:81].split()[0] else: iedge = int(line[0:2]) - 1 iel = int(line[2:12]) - 1 data.elem[iel].curv[iedge][0] = float(line[12:26]) data.elem[iel].curv[iedge][1] = float(line[26:40]) data.elem[iel].curv[iedge][2] = float(line[40:54]) data.elem[iel].curv[iedge][3] = float(line[54:68]) data.elem[iel].curv[iedge][4] = float(line[68:82]) data.elem[iel].ccurv[iedge] = line[82:85].split()[0] # #--------------------------------------------------------------------------- # BOUNDARY CONDITIONS #--------------------------------------------------------------------------- # infile.readline() # ***** BOUNDARY CONDITIONS ***** for ibc in range(nbc): infile.readline( ) # ***** FLUID BOUNDARY CONDITIONS ***** [or similar] for iel in range(nel): for iface in range(nface): line = infile.readline() if (nel < 1e3): data.elem[iel].bcs[ibc, iface][0] = line[1:3].strip() data.elem[iel].bcs[ibc, iface][1] = int(line[4:7]) data.elem[iel].bcs[ibc, iface][2] = int(line[7:10]) data.elem[iel].bcs[ibc, iface][3] = float(line[10:24]) data.elem[iel].bcs[ibc, iface][4] = float(line[24:38]) data.elem[iel].bcs[ibc, iface][5] = float(line[38:52]) data.elem[iel].bcs[ibc, iface][6] = float(line[52:66]) data.elem[iel].bcs[ibc, iface][7] = float(line[66:80]) elif (nel < 1e6): data.elem[iel].bcs[ibc, iface][0] = line[1:3].strip() data.elem[iel].bcs[ibc, iface][1] = iel + 1 data.elem[iel].bcs[ibc, iface][2] = iface + 1 data.elem[iel].bcs[ibc, iface][3] = float(line[10:24]) data.elem[iel].bcs[ibc, iface][4] = float(line[24:38]) data.elem[iel].bcs[ibc, iface][5] = float(line[38:52]) data.elem[iel].bcs[ibc, iface][6] = float(line[52:66]) data.elem[iel].bcs[ibc, iface][7] = float(line[66:80]) else: data.elem[iel].bcs[ibc, iface][0] = line[1:3].strip() data.elem[iel].bcs[ibc, iface][1] = int(line[4:15]) data.elem[iel].bcs[ibc, iface][2] = int(line[15:16]) data.elem[iel].bcs[ibc, iface][3] = float(line[16:34]) data.elem[iel].bcs[ibc, iface][4] = float(line[34:52]) data.elem[iel].bcs[ibc, iface][5] = float(line[52:70]) data.elem[iel].bcs[ibc, iface][6] = float(line[70:88]) data.elem[iel].bcs[ibc, iface][7] = float(line[88:106]) # ignore some invalid internal 'E' conditions. # They are typically written this way by re2torea and Nek5000 ignores them. if data.elem[iel].bcs[ibc, iface][0] == 'E' and data.elem[iel].bcs[ ibc, iface][3] == 0.: data.elem[iel].bcs[ibc, iface][0] = '' for j in range(1, 8): data.elem[iel].bcs[ibc, iface][j] = 0 ibc = ibc + 1 # #--------------------------------------------------------------------------- # FORGET ABOUT WHAT FOLLOWS #--------------------------------------------------------------------------- # # # close file infile.close() # # output return data
def readdns(fname): """A function for reading binary data from the SIMSON binary format Parameters ---------- fname : str file name """ # try: infile = open(fname, "rb") except OSError as e: print(f"I/O error ({e.errno}): {e.strerror}") return -1 # # --------------------------------------------------------------------------- # READ HEADER # --------------------------------------------------------------------------- wdsz = 8 realtype = "d" # # identify endian encoding (and number passive scalar) etagb = infile.read(4) etagL = struct.unpack("<i", etagb)[0] etagB = struct.unpack(">i", etagb)[0] # 1644 = 44 + (2*8) * 100 means a maximum of 100 passive scalars if (etagL >= 44) & (etagL <= 1644): # print('Reading little-endian file\n') emode = "<" nscal = int((etagL - 44) / (2 * wdsz)) elif (etagB >= 44) & (etagB <= 1644): # print('Reading big-endian file\n') emode = ">" nscal = int((etagB - 44) / (2 * wdsz)) else: print("ERROR: could not initerpret endianness") return -3 # # Reynolds Number Re = infile.read(wdsz) Re = struct.unpack(emode + realtype, Re)[0] # # Poiseuille/Couette flag [deprecated] PouCou = infile.read(4) PouCou = struct.unpack(emode + "i", PouCou)[0] # # physical box size (here x and z only) boxsz = [0 for i in range(3)] dum = infile.read(2 * wdsz) dum = list(struct.unpack(emode + 2 * realtype, dum)) boxsz[0] = dum[0] boxsz[2] = dum[1] # # time time = infile.read(wdsz) time = struct.unpack(emode + realtype, time)[0] # # dummy variable dum = infile.read(wdsz) # # passive scalar(s) (not tested) pr = np.zeros(nscal) m = np.zeros(nscal) for i in range(nscal): pr[i] = infile.read(wdsz) pr[i] = struct.unpack(emode + realtype, pr[i])[0] m[i] = infile.read(wdsz) m[i] = struct.unpack(emode + realtype, m[i])[0] # # end-of-line eol = infile.read(8) # # box size lr1 = infile.read(3 * 4) lr1 = list(struct.unpack(emode + 3 * "i", lr1)) # # nfzsym (z-symmetry flag) nfzsym = infile.read(4) nfzsym = list(struct.unpack(emode + "i", nfzsym))[0] # # end-of-line eol = infile.read(8) # # compute total number of points per element # npel = lr1[0] * lr1[1] * lr1[2] # # get number of pysical dimensions ndim = 2 + (lr1[2] > 1) # # flow type fltype = infile.read(4) fltype = struct.unpack(emode + "i", fltype)[0] # # delta star (and boxsz along y-direction) dstar = infile.read(wdsz) dstar = struct.unpack(emode + realtype, dstar)[0] boxsz[1] = 2 / dstar # # end-of-line eol = infile.read(8) # # flow-type dependent quantities # if fltype == -1: rlam = infile.read(wdsz) rlam = struct.unpack(emode + realtype, rlam)[0] eol = infile.read(8) if fltype == -2: rlam = infile.read(wdsz) rlam = struct.unpack(emode + realtype, rlam)[0] spanv = infile.read(wdsz) spanv = struct.unpack(emode + realtype, spanv)[0] eol = infile.read(8) if (fltype == 4) or (fltype == 5): bstart = infile.read(wdsz) bstart = struct.unpack(emode + realtype, bstart)[0] blength = infile.read(wdsz) blength = struct.unpack(emode + realtype, blength)[0] eol = infile.read(8) if (fltype >= 4) and (fltype <= 9): bstart = infile.read(wdsz) bstart = struct.unpack(emode + realtype, bstart)[0] blength = infile.read(wdsz) blength = struct.unpack(emode + realtype, blength)[0] rlam = infile.read(wdsz) rlam = struct.unpack(emode + realtype, rlam)[0] spanv = infile.read(wdsz) spanv = struct.unpack(emode + realtype, spanv)[0] eol = infile.read(8) if abs(fltype) == 20: gr = infile.read(nscal * wdsz) gr = struct.unpack(emode + nscal * realtype, gr) eol = infile.read(8) # # get variables var = [0 for i in range(5)] var[0] = ndim # position var[1] = ndim # velocity var[2] = 0 # pressure is not saved (SIMSON) var[3] = 0 # temperature is treated like a scalar (SIMSON) var[4] = nscal # scalars # # --------------------------------------------------------------------------- # READ DATA # --------------------------------------------------------------------------- # # number of points # npel = lr1[0]*lr1[1]*lr1[2] # # number of points per plane nppl = lr1[0] * lr1[2] # # reading buffer in fourier space fou = np.zeros((lr1[2], lr1[1], lr1[0] // 2 + 1)) + 1j * np.zeros( (lr1[2], lr1[1], lr1[0] // 2 + 1)) # # initialize data structure data = exdat.exadata(ndim, 1, lr1, var) data.time = time data.wdsz = wdsz if emode == "<": data.endian = "little" elif emode == ">": data.endian = "big" # # generate geometry # - x-direction dx = boxsz[0] / lr1[0] for ix in range(lr1[0]): data.elem[0].pos[0, :, :, ix] = dx * ix # - y-direction dy = np.arccos(-1.0) / (lr1[1] - 1) for iy in range(lr1[1]): data.elem[0].pos[1, :, iy, :] = boxsz[1] * (1 - np.cos(dy * iy)) / 2 # - z-direction dz = boxsz[2] / lr1[2] for iz in range(lr1[2]): data.elem[0].pos[2, iz, :, :] = dz * (iz - lr1[2] / 2) # # read velocity and transform in physical space for idim in range(3): for iz in range(lr1[2]): if iz <= lr1[2] / 2: izf = iz else: izf = lr1[2] // 2 * 3 - (iz + 1) for iy in range(lr1[1]): fi = infile.read(lr1[0] * wdsz) fi = list(struct.unpack(emode + lr1[0] * realtype, fi)) ip = 0 for ix in range(int(lr1[0] // 2)): fou[izf, iy, ix] = (fi[ip] + 1j * fi[ip + 1]) * nppl * (-1)**idim ip += 2 # end-of-line eol = infile.read(8) # # back to physical space data.elem[0].vel[idim, :, :, :] = np.fft.irfft2( fou, (lr1[0], lr1[2]), (2, 0)) # # read scalars and transform in physical space for ivar in range(var[4]): for iz in range(lr1[2]): if iz <= lr1[2] / 2: izf = iz else: izf = lr1[2] // 2 * 3 - (iz + 1) for iy in range(lr1[1]): fi = infile.read(lr1[0] * wdsz) fi = list(struct.unpack(emode + lr1[0] * realtype, fi)) ip = 0 for ix in range(int(lr1[0] // 2)): fou[izf, iy, ix] = (fi[ip] + 1j * fi[ip + 1]) * nppl ip += 2 # end-of-line eol = infile.read(8) # noqa: F841 # required for reading # # back to physical space data.elem[0].scal[ivar, :, :, :] = np.fft.irfft2( fou, (lr1[0], lr1[2]), (2, 0)) # # --------------------------------------------------------------------------- # CLOSE FILE # --------------------------------------------------------------------------- # # close file infile.close() # # output return data