Esempio n. 1
0
def writenek(fname, data):
    """A function for writing binary data in the nek5000 binary format

	Parameters
	----------
	fname : str
		file name
	data : exadata
		data organised as readnek() output
	"""
    #
    try:
        outfile = open(fname, 'wb')
    except OSError as e:
        logger.critical(f'I/O error ({e.errno}): {e.strerror}')
        return -1
    #
    #---------------------------------------------------------------------------
    # WRITE HEADER
    #---------------------------------------------------------------------------
    #
    # multiple files (not implemented)
    fid = 0
    nf = 1
    nelf = data.nel
    #
    # get fields to be written
    vars = ''
    if (data.var[0] > 0): vars += 'X'
    if (data.var[1] > 0): vars += 'U'
    if (data.var[2] > 0): vars += 'P'
    if (data.var[3] > 0): vars += 'T'
    if (data.var[4] > 0):
        # TODO: check if header for scalars are written with zeros filled as S01
        vars += 'S{:02d}'.format(data.var[4])
    #
    # get word size
    if (data.wdsz == 4):
        logger.debug('Writing single-precision file')
    elif (data.wdsz == 8):
        logger.debug('Writing double-precision file')
    else:
        logger.error('Could not interpret real type (wdsz = %i)' % (data.wdsz))
        return -2
    #
    # generate header
    header = '#std %1i %2i %2i %2i %10i %10i %20.13E %9i %6i %6i %s' % (
        data.wdsz, data.lr1[0], data.lr1[1], data.lr1[2], data.nel, nelf,
        data.time, data.istep, fid, nf, vars)
    #
    # write header
    header = header.ljust(132)
    outfile.write(header.encode('utf-8'))
    #
    # decide endianness
    if data.endian in ('big', 'little'):
        byteswap = data.endian != sys.byteorder
        logger.debug(f'Writing {data.endian}-endian file')
    else:
        byteswap = False
        logger.warning(f'Unrecognized endianness {data.endian}, '
                       f'writing native {sys.byteorder}-endian file')
    #
    def correct_endianness(a):
        ''' Return the array with the requested endianness'''
        if byteswap:
            return a.byteswap()
        else:
            return a

    #
    # write tag (to specify endianness)
    endianbytes = np.array([6.54321], dtype=np.float32)
    correct_endianness(endianbytes).tofile(outfile)
    #
    # write element map for the file
    correct_endianness(data.elmap).tofile(outfile)
    #
    #---------------------------------------------------------------------------
    # WRITE DATA
    #---------------------------------------------------------------------------
    #
    # compute total number of points per element
    npel = data.lr1[0] * data.lr1[1] * data.lr1[2]

    #
    def write_ndarray_to_file(a):
        '''Write a data array to the output file in the requested precision and endianness'''
        if data.wdsz == 4:
            correct_endianness(a.astype(np.float32)).tofile(outfile)
        else:
            correct_endianness(a).tofile(outfile)

    #
    # write geometry
    for iel in data.elmap:
        for idim in range(
                data.var[0]):  # if var[0] == 0, geometry is not written
            write_ndarray_to_file(data.elem[iel - 1].pos[idim, :, :, :])
    #
    # write velocity
    for iel in data.elmap:
        for idim in range(
                data.var[1]):  # if var[1] == 0, velocity is not written
            write_ndarray_to_file(data.elem[iel - 1].vel[idim, :, :, :])
    #
    # write pressure
    for iel in data.elmap:
        for ivar in range(
                data.var[2]):  # if var[2] == 0, pressure is not written
            write_ndarray_to_file(data.elem[iel - 1].pres[ivar, :, :, :])
    #
    # write temperature
    for iel in data.elmap:
        for ivar in range(
                data.var[3]):  # if var[3] == 0, temperature is not written
            write_ndarray_to_file(data.elem[iel - 1].temp[ivar, :, :, :])
    #
    # write scalars
    #
    # 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(data.var[4]):  # if var[4] == 0, scalars are not written
        for iel in data.elmap:
            write_ndarray_to_file(data.elem[iel - 1].scal[ivar, :, :, :])
    #
    # write max and min of every field in every element (forced to single precision)
    if (data.ndim == 3):
        #
        for iel in data.elmap:
            for idim in range(data.var[0]):
                correct_endianness(
                    np.min(data.elem[iel - 1].pos[idim, :, :, :]).astype(
                        np.float32)).tofile(outfile)
                correct_endianness(
                    np.max(data.elem[iel - 1].pos[idim, :, :, :]).astype(
                        np.float32)).tofile(outfile)
        for iel in data.elmap:
            for idim in range(data.var[1]):
                correct_endianness(
                    np.min(data.elem[iel - 1].vel[idim, :, :, :]).astype(
                        np.float32)).tofile(outfile)
                correct_endianness(
                    np.max(data.elem[iel - 1].vel[idim, :, :, :]).astype(
                        np.float32)).tofile(outfile)
        for iel in data.elmap:
            for ivar in range(data.var[2]):
                correct_endianness(
                    np.min(data.elem[iel - 1].pres[ivar, :, :, :]).astype(
                        np.float32)).tofile(outfile)
                correct_endianness(
                    np.max(data.elem[iel - 1].pres[ivar, :, :, :]).astype(
                        np.float32)).tofile(outfile)
        for iel in data.elmap:
            for ivar in range(data.var[3]):
                correct_endianness(
                    np.min(data.elem[iel - 1].temp[ivar, :, :, :]).astype(
                        np.float32)).tofile(outfile)
                correct_endianness(
                    np.max(data.elem[iel - 1].temp[ivar, :, :, :]).astype(
                        np.float32)).tofile(outfile)
        for iel in data.elmap:
            for ivar in range(data.var[4]):
                correct_endianness(
                    np.min(data.elem[iel - 1].scal[ivar, :, :, :]).astype(
                        np.float32)).tofile(outfile)
                correct_endianness(
                    np.max(data.elem[iel - 1].scal[ivar, :, :, :]).astype(
                        np.float32)).tofile(outfile)

    # close file
    outfile.close()
    #
    # output
    return 0
Esempio n. 2
0
def writenek(fname, data):
	"""A function for writing binary data in the nek5000 binary format

	Parameters
	----------
	fname : str
		file name
	data : exadata
		data organised as readnek() output
	"""
	#
	try:
		outfile = open(fname, 'wb')
	except IOError as e:
		logger.critical('I/O error ({0}): {1}'.format(e.errno, e.strerror))
		return -1
	#
	#---------------------------------------------------------------------------
	# WRITE HEADER
	#---------------------------------------------------------------------------
	#
	# multiple files (not implemented)
	fid = 0
	nf = 1
	nelf = data.nel
	#
	# get fields to be written
	vars = ''
	if (data.var[0] > 0): vars += 'X'
	if (data.var[1] > 0): vars += 'U'
	if (data.var[2] > 0): vars += 'P'
	if (data.var[3] > 0): vars += 'T'
	if (data.var[4] > 0):
		logger.warning("Writing scalar variables is an experimental feature")
		# TODO: check if header for scalars are written with zeros filled as S01
		vars += 'S{:02d}'.format(data.var[4])
	#
	# get word size
	if (data.wdsz == 4):
		realtype = 'f'
	elif (data.wdsz == 8):
		realtype = 'd'
	else:
		logger.error('Could not interpret real type (wdsz = %i)' % (data.wdsz))
		return -2
	#
	# generate header
	header = '#std %1i %2i %2i %2i %10i %10i %20.13E %9i %6i %6i %s\n' %(
		data.wdsz, data.lr1[0], data.lr1[1], data.lr1[2], data.nel, nelf,
		data.time, data.istep, fid, nf, vars)
	#
	# write header
	header = header.ljust(132)
	outfile.write(header.encode('utf-8'))
	#
	# write tag (to specify endianness)
	endianbytes = np.array([6.54321], dtype=np.float32)
	endianbytes.tofile(outfile)
	#
	# generate and write element map for the file
	elmap = np.linspace(1, data.nel, data.nel, dtype=np.int32)
	elmap.tofile(outfile)
	#
	#---------------------------------------------------------------------------
	# WRITE DATA
	#---------------------------------------------------------------------------
	#
	# compute total number of points per element
	npel = data.lr1[0] * data.lr1[1] * data.lr1[2]
	#
	def write_ndarray_to_file(a):
		if data.wdsz == 4:
			np.float32(a).tofile(outfile)
		else:
			a.tofile(outfile)
	#
	# write geometry
	for iel in elmap:
		for idim in range(data.var[0]): # if var[0] == 0, geometry is not written
			write_ndarray_to_file(data.elem[iel-1].pos[idim, :, :, :])
	#
	# write velocity
	for iel in elmap:
		for idim in range(data.var[1]): # if var[1] == 0, velocity is not written
			write_ndarray_to_file(data.elem[iel-1].vel[idim, :, :, :])
	#
	# write pressure
	for iel in elmap:
		for ivar in range(data.var[2]): # if var[2] == 0, pressure is not written
			write_ndarray_to_file(data.elem[iel-1].pres[ivar, :, :, :])
	#
	# write temperature
	for iel in elmap:
		for ivar in range(data.var[3]): # if var[3] == 0, temperature is not written
			write_ndarray_to_file(data.elem[iel-1].temp[ivar, :, :, :])
	#
	# write scalars
	#
	# 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(data.var[4]): # if var[4] == 0, scalars are not written
		for iel in elmap:
			write_ndarray_to_file(data.elem[iel-1].scal[ivar, :, :, :])
	#
	# write max and min of every field in every element (forced to single precision)
	if (data.ndim==3):
		#
		for iel in elmap:
			for idim in range(data.var[0]):
				np.min(data.elem[iel-1].pos[idim, :,:,:]).tofile(outfile)
				np.max(data.elem[iel-1].pos[idim, :,:,:]).tofile(outfile)
			for idim in range(data.var[1]):
				np.min(data.elem[iel-1].vel[idim, :,:,:]).tofile(outfile)
				np.max(data.elem[iel-1].vel[idim, :,:,:]).tofile(outfile)
			for idim in range(data.var[2]):
				np.min(data.elem[iel-1].pres[idim, :,:,:]).tofile(outfile)
				np.max(data.elem[iel-1].pres[idim, :,:,:]).tofile(outfile)
			for idim in range(data.var[3]):
				np.min(data.elem[iel-1].temp[idim, :,:,:]).tofile(outfile)
				np.max(data.elem[iel-1].temp[idim, :,:,:]).tofile(outfile)

	# close file
	outfile.close()
	#
	# output
	return 0
Esempio n. 3
0
def writere2(fname, data):
    """A function for writing binary .re2 files for nek5000

	Parameters
	----------
	fname : str
		file name
	data : exadata
		data organised as in exadata.py
	"""
    #
    #---------------------------------------------------------------------------
    # CHECK INPUT DATA
    #---------------------------------------------------------------------------
    #
    # We could extract the corners, but for now just return an error if lr1 is too large
    if data.lr1 != [2, 2, data.ndim - 1]:
        logger.critical(
            'wrong element dimensions for re2 file! {} != {}'.format(
                data.lr1, [2, 2, data.ndim - 1]))
        return -2
    #
    if data.var[0] != data.ndim:
        logger.critical(
            'wrong number of geometric variables for re2 file! expected {}, found {}'
            .format(data.ndim, data.var[0]))
        return -3
    #
    # Open file
    try:
        outfile = open(fname, 'wb')
    except OSError as e:
        logger.critical(f'I/O error ({e.errno}): {e.strerror}')
        return -1
    #
    #---------------------------------------------------------------------------
    # WRITE HEADER
    #---------------------------------------------------------------------------
    #
    # always double precision
    wdsz = 8
    realtype = 'd'
    nel = data.nel
    ndim = data.ndim
    header = f'#v002{nel:9d}{ndim:3d}{nel:9d} this is the hdr'
    header = header.ljust(80)
    outfile.write(header.encode('utf-8'))
    #
    # decide endianness
    if data.endian in ('big', 'little'):
        byteswap = data.endian != sys.byteorder
        logger.debug(f'Writing {data.endian}-endian file')
    else:
        byteswap = False
        logger.warning(f'Unrecognized endianness {data.endian}, '
                       f'writing native {sys.byteorder}-endian file')
    #
    def correct_endianness(a):
        ''' Return the array with the requested endianness'''
        if byteswap:
            return a.byteswap()
        else:
            return a

    #
    # write tag (to specify endianness)
    endianbytes = np.array([6.54321], dtype=np.float32)
    correct_endianness(endianbytes).tofile(outfile)
    #
    #---------------------------------------------------------------------------
    # WRITE DATA
    #---------------------------------------------------------------------------
    #
    # compute total number of points per element
    npel = 2**ndim

    #
    def write_data_to_file(a):
        '''Write the geometry of an element to the output file in double precision'''
        correct_endianness(a).tofile(outfile)

    #
    # write geometry (adding eight bytes of zeros before each element)
    xyz = np.zeros(
        (npel * ndim + 1, )
    )  # array storing reordered geometry data (with a zero in the first position)
    for el in data.elem:
        # 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
                xyz[npel * idim + 4 * iz + 1] = el.pos[idim, iz, 0, 0]
                xyz[npel * idim + 4 * iz + 2] = el.pos[idim, iz, 0, 1]
                xyz[npel * idim + 4 * iz + 3] = el.pos[idim, iz, 1, 1]
                xyz[npel * idim + 4 * iz + 4] = el.pos[idim, iz, 1, 0]
        write_data_to_file(xyz)
    #
    # write curve sides data
    # locate curved edges
    curved_edges = []
    for (iel, el) in enumerate(data.elem):
        for iedge in range(12):
            if el.ccurv[iedge] != '':
                curved_edges.append((iel, iedge))
    # write number of curved edges
    ncurv = len(curved_edges)
    if ncurv != data.ncurv:
        logger.warning(
            f'wrong number of curved edges: expected {data.ncurv}, found {ncurv}'
        )
    ncurvf = np.array([ncurv], dtype=np.float64)
    write_data_to_file(ncurvf)
    # format curve data
    cdata = np.zeros((ncurv, ), dtype='f8, f8, f8, f8, f8, f8, f8, S8')
    for (cdat, (iel, iedge)) in zip(cdata, curved_edges):
        el = data.elem[iel]
        cdat[0] = iel + 1
        cdat[1] = iedge + 1
        # curve parameters
        for j in range(5):
            cdat[2 + j] = el.curv[iedge, j]
        # encode the string as a byte array padded with spaces
        cdat[7] = el.ccurv[iedge].encode('utf-8')
    # write to file
    write_data_to_file(cdata)
    #
    # write boundary conditions for each field
    for ifield in range(data.nbc):
        # locate faces with boundary conditions
        bc_faces = []
        for (iel, el) in enumerate(data.elem):
            for iface in range(2 * ndim):
                bctype = el.bcs[ifield, iface][0]
                # internal boundary conditions are not written to .re2 files by reatore2
                # and are apparently ignored by Nek5000 even in .rea files
                if bctype != '' and bctype != 'E':
                    bc_faces.append((iel, iface))
        nbcs = len(bc_faces)
        nbcsf = np.array([nbcs], dtype=np.float64)
        write_data_to_file(nbcsf)
        # initialize and format data
        bcdata = np.zeros((nbcs, ), dtype='f8, f8, f8, f8, f8, f8, f8, S8')
        for (bc, (iel, iface)) in zip(bcdata, bc_faces):
            el = data.elem[iel]
            bc[0] = iel + 1
            bc[1] = iface + 1
            for j in range(5):
                bc[2 + j] = el.bcs[ifield, iface][3 + j]
            # encode the string as a byte array padded with spaces
            bc[7] = el.bcs[ifield, iface][0].encode('utf-8').ljust(8)
        # write to file
        write_data_to_file(bcdata)
    #
    # close file
    outfile.close()
    # rerurn
    return 0
Esempio n. 4
0
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 IOError as e:
		logger.critical('I/O error ({0}): {1}'.format(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("Variables: {}".format(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'):
			logger.warning("Reading scalar variables is an experimental feature")
			# 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
	if (emode == '<'):
		data.endian = 'little'
	elif (emode == '>'):
		data.endian = 'big'
	#
	def read_file_into_data(elem, index_var, name_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)

		# Fetch elem array, for example `data.elem.pos`
		data_var = getattr(elem, name_var)

		# 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, idim, 'pos')
	#
	# 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, idim, 'vel')
	#
	# 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, ivar, 'pres')
	#
	# 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, ivar, 'temp')
	#
	# 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, ivar, 'scal')
	#
	#
	# close file
	infile.close()
	#
	# output
	return data