"""
Defines the following classes:
- UGRID
"""
import os
from struct import Struct, unpack
import sys
import numpy as np
from numpy import zeros, unique, array
from numpy import arange, hstack, setdiff1d, union1d
from cpylog import get_logger
#from pyNastran.bdf.field_writer_double import print_card_double
#from pyNastran.bdf.field_writer_16 import print_card_16
#from pyNastran.bdf.field_writer_8 import print_card_8
from pyNastran.bdf.field_writer_8 import print_float_8
from pyNastran.bdf.field_writer_16 import print_float_16
[docs]def read_ugrid(ugrid_filename=None,
encoding=None, log=None, debug=True,
read_shells=True, read_solids=True, check=True):
"""
Creates the UGRID object
Parameters
----------
ugrid_filename : str (default=None -> popup)
the ugrid filename
debug : bool/None
used to set the logger if no logger is passed in
True: logs debug/info/error messages
False: logs info/error messages
None: logs error messages
log : logging module object / None
if log is set, debug is ignored and uses the
settings the logging object has
encoding : str; default=None
is this used?
Returns
-------
model : UGRID()
an UGRID object
"""
ugrid_model = UGRID(log=log, debug=debug,
read_shells=read_shells, read_solids=read_solids)
ugrid_model.read_ugrid(ugrid_filename, check=check)
return ugrid_model
[docs]class UGRID:
"""
Interface to the AFLR UGrid format.
"""
def __init__(self, log=None, debug=False, read_shells=True, read_solids=True):
self.log = get_logger(log, 'debug' if debug else 'info')
self.debug = debug
self.n = 0
self.nodes = array([], dtype='float32')
self.tris = array([], dtype='int32')
self.quads = array([], dtype='int32')
self.pids = array([], dtype='int32')
self.tets = array([], dtype='int32')
self.penta5s = array([], dtype='int32')
self.penta6s = array([], dtype='int32')
self.hexas = array([], dtype='int32')
self.read_shells = read_shells
self.read_solids = read_solids
self.isort = None
[docs] def read_ugrid(self, ugrid_filename, check=True):
"""
$
$ NASTRAN INPUT DECK GENERATED BY UG_IO
$
BEGIN BULK
$UG_IO_ Data
$Number_of_BL_Vol_Tets 2426
$UG_IO_ Data
$Number_of_Bnd_Nodes 34350
$UG_IO_ Data
$Number_of_Nodes 399036
$UG_IO_ Data
$Number_of_Surf_Quads 20665
$UG_IO_ Data
$Number_of_Surf_Trias 27870
$UG_IO_ Data
$Number_of_Vol_Hexs 163670
$UG_IO_ Data
$Number_of_Vol_Pents_5 27875
$UG_IO_ Data
$Number_of_Vol_Pents_6 67892
$UG_IO_ Data
$Number_of_Vol_Tets 1036480
"""
out = determine_dytpe_nfloat_endian_from_ugrid_filename(ugrid_filename)
ndarray_float, float_fmt, nfloat, endian, ugrid_filename = out
# more for documentation than anything else
assert ndarray_float in ['float32', 'float64'], ndarray_float
assert float_fmt in ['f', 'd'], float_fmt
assert nfloat in [4, 8], nfloat
assert endian in ['<', '>'], ndarray_float
with open(ugrid_filename, 'rb') as ugrid_file:
data = ugrid_file.read(7 * 4)
self.n += 7 * 4
nnodes, ntris, nquads, ntets, npenta5s, npenta6s, nhexas = unpack(endian + '7i', data)
npids = nquads + ntris
nvol_elements = ntets + npenta5s + npenta6s + nhexas
self.log.info('nnodes=%.3fm ntris=%s nquads=%s ntets=%.3fm'
' npenta5s=%.3fm npenta6s=%.3fm nhexas=%.3fm' % (
nnodes / 1e6, ntris, nquads,
ntets / 1e6, npenta5s / 1e6, npenta6s / 1e6, nhexas / 1e6))
nvolume_elements = ntets + npenta5s + npenta6s + nhexas
self.log.info('nsurface_elements=%s nvolume_elements=%.3f Million' % (
npids, nvolume_elements / 1e6))
# we know the shapes of nodes (e.g. Nx3), but we want to directly
# unpack the data into the array, so we shape it as N*3, load the
# data and and then do a reshape
self.log.debug('ndarray_float=%s' % (ndarray_float))
#nodes = zeros(nnodes * 3, dtype=ndarray_float)
tris = array([], dtype='int32')
quads = array([], dtype='int32')
#pids = zeros(npids, dtype='int32')
#nodes = array([], dtype='float32')
## NODES
nbytes_expected = nnodes * 3 * nfloat
data = ugrid_file.read(nbytes_expected)
self.n += nbytes_expected
dtype = endian + float_fmt
nodes = np.frombuffer(data, dtype=dtype).reshape((nnodes, 3)).copy()
#print('min xyz value = ' , nodes.min())
#print('max xyz value = ' , nodes.max())
## CTRIA3
dtype = endian + 'i'
if ntris:
data = ugrid_file.read(ntris * 3 * 4)
tris = np.frombuffer(data, dtype=dtype).reshape((ntris, 3)).copy()
self.n += ntris * 3 * 4
#print('min tris value = ' , tris.min())
#print('max tris value = ' , tris.max())
## CQUAD4
if nquads:
nbytes_expected = nquads * 4 * 4
data = ugrid_file.read(nbytes_expected)
self.n += nbytes_expected
assert len(data) == nbytes_expected, 'ndata=%s nbytes_expected=%s nquads_actual=%g nquads=%s' % (
len(data), nbytes_expected, len(data)/16., nquads)
quads = np.frombuffer(data, dtype=dtype).reshape((nquads, 4)).copy()
#print('min quads value = ' , quads.min())
#print('max quads value = ' , quads.max())
if npids:
nbytes_expected = npids * 4
data = ugrid_file.read(nbytes_expected)
assert len(data) == nbytes_expected, 'len(data)=%s' % (len(data))
self.n += nbytes_expected
pids = np.frombuffer(data, dtype=dtype).copy()
self.pids = pids
#print('min pids value = ' , pids.min())
#print('max pids value = ' , pids.max())
self.nodes = nodes
self.tris = tris
self.quads = quads
#==========================================
# solids
if not self.read_solids:
#nids = np.unique(np.hstack([self.quads.ravel(), self.tris.ravel()]))
#inid = np.searchsorted(np.arange(self.nodes.size), nids)
#self.nodes = self.nodes[inid]
return
tets = zeros(ntets * 4, dtype='int32')
penta5s = zeros(npenta5s * 5, dtype='int32')
penta6s = zeros(npenta6s * 6, dtype='int32')
hexas = zeros(nhexas * 8, dtype='int32')
if ntets:
## CTETRA
nbytes_expected = ntets * 4 * 4
data = ugrid_file.read(nbytes_expected)
tets = np.frombuffer(data, dtype=dtype).reshape((ntets, 4)).copy()
self.n += nbytes_expected
#print('min tets value = ' , tets.min())
#print('max tets value = ' , tets.max())
if npenta5s:
## CPYRAM
nbytes_expected = npenta5s * 5 * 4
data = ugrid_file.read(nbytes_expected)
penta5s = np.frombuffer(data, dtype=dtype).reshape((npenta5s, 5)).copy()
self.n += nbytes_expected
#print('min penta5s value = ' , penta5s.min())
#print('max penta5s value = ' , penta5s.max())
if npenta6s:
## CPENTA
nbytes_expected = npenta6s * 6 * 4
data = ugrid_file.read(nbytes_expected)
penta6s = np.frombuffer(data, dtype=dtype).reshape((npenta6s, 6)).copy()
self.n += nbytes_expected
#print('min penta6s value = ' , penta6s.min())
#print('max penta6s value = ' , penta6s.max())
if nhexas:
## CHEXA
nbytes_expected = nhexas * 8 * 4
data = ugrid_file.read(nbytes_expected)
ndata = len(data)
assert ndata == nbytes_expected, 'ndata=%s nbytes_expected=%s nhexas_actual=%g nhexas=%s' % (
ndata, nbytes_expected, ndata/32., nhexas)
hexas = np.frombuffer(data, dtype=dtype).reshape((nhexas, 8)).copy()
self.n += nhexas * 8 * 4
#print('min hexas value = ' , hexas.min())
#print('max hexas value = ' , hexas.max())
self.tets = tets
self.penta5s = penta5s
self.penta6s = penta6s
self.hexas = hexas
if check:
self.check_hanging_nodes()
[docs] def write_bdf(self, bdf_filename, include_shells=True, include_solids=True,
convert_pyram_to_penta=True, write_grids=True, encoding=None,
size=16, is_double=False, check=True):
"""
writes a Nastran BDF
Parameters
----------
size : int; {8, 16}; default=16
the bdf write precision
is_double : bool; default=False
the field precision to write
"""
self._check_node_ids()
if encoding is None:
encoding = sys.getdefaultencoding()
#assert encoding.lower() in ['ascii', 'latin1', 'utf8'], encoding
with open(bdf_filename, 'w', encoding=encoding) as bdf_file:
#bdf_file.write('CEND\n')
#bdf_file.write('BEGIN BULK\n')
bdf_file.write('$ pyNastran: punch=True\n')
bdf_file.write('$ pyNastran: encoding=utf-8\n')
mid = 1
bdf_file.write('MAT1, %i, 1.0e7,, 0.3\n' % mid)
self.log.debug('writing GRIDs')
write_grids = True
if write_grids:
if not self.read_solids:
nids_to_write = np.unique(np.hstack([self.quads.ravel(), self.tris.ravel()]))
nnodes = self.nodes.shape[0]
all_nids = np.arange(nnodes, dtype='int32')
inid = np.searchsorted(all_nids, nids_to_write)
unused_nodes = self.nodes[inid, :]
if size == 8:
for i, nid in enumerate(nids_to_write):
if i % 200000: # pragma: no cover
print(' i = %s' % i)
node = self.nodes[i, :]
bdf_file.write('GRID %8i%8s%s%s%s\n' % (
nid, '',
print_float_8(node[0]),
print_float_8(node[1]),
print_float_8(node[2])))
else:
for i, nid in enumerate(nids_to_write):
if i % 200000: # pragma: no cover
print(' i = %s' % i)
node = self.nodes[i, :]
bdf_file.write('GRID* %16i%16s%16s%16s\n'
'* %16s\n' % (
nid,
'',
print_float_16(node[0]),
print_float_16(node[1]),
print_float_16(node[2])))
else:
if check:
self.check_hanging_nodes()
if size == 8:
for i, node in enumerate(self.nodes):
node = self.nodes[i, :]
bdf_file.write('GRID %8i%8s%s%s%s\n' % (
i + 1, '',
print_float_8(node[0]),
print_float_8(node[1]),
print_float_8(node[2])))
else:
for i, node in enumerate(self.nodes):
node = self.nodes[i, :]
bdf_file.write('GRID* %16i%16s%16s%16s\n'
'* %16s\n' % (
i + 1,
'',
print_float_16(node[0]),
print_float_16(node[1]),
print_float_16(node[2])))
self.log.debug('finished writing GRIDs')
eid = 1
pids = self.pids #+ 1
if include_shells:
upids = unique(pids) # auto-sorts
for pid in upids:
bdf_file.write('PSHELL,%i,%i, 0.1\n' % (pid, mid))
self.log.debug('writing CTRIA3')
for element in self.tris:
assert len(np.unique(element)) == 3, element
bdf_file.write('CTRIA3 %-8i%-8i%-8i%-8i%-8i\n' % (
eid, pids[eid-1], element[0], element[1], element[2]))
eid += 1
self.log.debug('writing CQUAD4')
for element in self.quads:
assert len(np.unique(element)) == 4, element
bdf_file.write('CQUAD4 %-8i%-8i%-8i%-8i%-8i%-8i\n' % (
eid, pids[eid-1], element[0], element[1], element[2], element[3]))
eid += 1
else:
ntris = self.tris.shape[0]
nquads = self.quads.shape[0]
eid += ntris + nquads
if len(pids) == 0:
max_pid = 1
else:
max_pid = pids.max()
#==========================================
# solids
if include_solids:
pid = max_pid + 1
eid, pid = self._write_bdf_solids(
bdf_file, eid, pid, convert_pyram_to_penta=convert_pyram_to_penta)
bdf_file.write('ENDDATA\n')
[docs] def check_hanging_nodes(self, stop_on_diff=True):
"""verifies that all nodes are used"""
self.log.debug('checking hanging nodes')
self._check_node_ids()
tris = self.tris
quads = self.quads
unused_pids = self.pids
nnodes = self.nodes.shape[0]
ntris = tris.shape[0]
nquads = quads.shape[0]
if self.read_solids:
tets = self.tets
pyrams = self.penta5s
pentas = self.penta6s
hexas = self.hexas
ntets = tets.shape[0]
npyramids = pyrams.shape[0]
npentas = pentas.shape[0]
nhexas = hexas.shape[0]
else:
ntets = 0
npyramids = 0
npentas = 0
nhexas = 0
nids = []
if ntris:
nids.append(unique(tris.ravel()))
if nquads:
nids.append(unique(quads.ravel()))
if ntets:
nids.append(unique(tets.ravel()))
if npyramids:
nids.append(unique(pyrams.ravel()))
if npentas:
nids.append(unique(pentas.ravel()))
if nhexas:
nids.append(unique(hexas.ravel()))
if len(nids) == 0:
raise RuntimeError('there are no solid nodes; nids=%s' % nids)
elif len(nids) == 1:
nids = nids[0]
else:
nids = unique(hstack(nids))
diff = []
if nnodes != len(nids):
expected = arange(1, nnodes + 1, dtype='int32')
print('expected = %s' % expected)
print('actual = %s' % nids)
diff = setdiff1d(expected, nids)
diff2 = setdiff1d(nids, expected)
diff = union1d(diff, diff2)
msg = 'nnodes=%i len(actual)=%s expected-actual=%s (n=%s) actual-expected=%s (n=%s)' % (
nnodes, len(nids),
diff, len(diff),
diff2, len(diff),
)
print(msg)
print('nids = %s' % nids)
if stop_on_diff:
raise RuntimeError(msg)
# check unique node ids
for tri in tris:
assert len(unique(tri)) == 3, tri
for quad in quads:
# assert len(unique(quad)) == 4, quad
if len(unique(quad)) != 4:
print(quad)
for tet in tets:
assert len(unique(tet)) == 4, tet
for pyram in pyrams:
assert len(unique(pyram)) == 5, pyram
for penta in pentas:
assert len(unique(penta)) == 6, penta
for hexa in hexas:
assert len(unique(hexa)) == 8, hexa
return diff
[docs] def _check_node_ids(self):
tris = self.tris
quads = self.quads
pids = self.pids
tets = self.tets
pyrams = self.penta5s
pentas = self.penta6s
hexas = self.hexas
if len(tris):
assert tris.min() >= 1, tris.min()
if len(quads):
assert quads.min() >= 1, quads.min()
if len(tets):
assert tets.min() >= 1, tets.min()
if len(pyrams):
assert pyrams.min() >= 1, pyrams.min()
if len(pentas):
assert pentas.min() >= 1, pentas.min()
if len(hexas):
assert hexas.min() >= 1, hexas.min()
[docs] def write_ugrid(self, ugrid_filename_out, check_shells=True, check_solids=True, check=True):
"""writes a UGrid model"""
outi = determine_dytpe_nfloat_endian_from_ugrid_filename(ugrid_filename_out)
unused_ndarray_float, float_fmt, unused_nfloat, endian, ugrid_filename = outi
nodes = self.nodes
nnodes = nodes.shape[0]
tris = self.tris
quads = self.quads
pids = self.pids
if len(pids):
self.log.info('nupids=%s min=%s max=%s' % (np.unique(pids), pids.min(), pids.max()))
else:
self.log.warning('no surface_ids were found')
tets = self.tets
pyrams = self.penta5s
pentas = self.penta6s
hexas = self.hexas
self._check_node_ids()
ntris = tris.shape[0]
nquads = quads.shape[0]
npids = pids.shape[0]
#print('ntris=%s nquads=%s' % (ntris, nquads))
ntets = tets.shape[0]
npyramids = pyrams.shape[0]
npentas = pentas.shape[0]
nhexas = hexas.shape[0]
nshells = ntris + nquads
assert nshells == npids, 'ntris=%s nquads=%s nshells=%s npids=%s' % (ntris, nquads, nshells, npids)
if ntris:
assert tris.shape[1] == 3, tris.shape
if nquads:
assert quads.shape[1] == 4, quads.shape
nsolids = ntets + npyramids + npentas + nhexas
if check_shells:
assert nshells > 0, 'nquads=%s ntris=%s' % (nquads, ntris)
if nsolids == 0 and check_solids:
msg = 'ntets=%s npyramids=%s npentas=%s nhexas=%s' % (
ntets, npyramids, npentas, nhexas)
raise RuntimeError(msg)
self.log.debug('writing ugrid=%r' % ugrid_filename)
with open(ugrid_filename, 'wb') as f_ugrid:
sfmt = Struct(endian + '7i')
f_ugrid.write(sfmt.pack(nnodes, ntris, nquads, ntets, npyramids, npentas, nhexas))
#def _write(f_ugrid, nodes_array, endian):
#if endian == '<':
#f_ugrid.write(nodes_array.ravel().tobytes())
#else:
#nodes_array = nodes_array.byteswap()
#f_ugrid.write(nodes_array.ravel().tobytes())
#_write(f_ugrid, nodes, endian)
#_write(f_ugrid, nodes, endian)
#_write(f_ugrid, tris, endian)
#_write(f_ugrid, quads, endian)
#_write(f_ugrid, pids, endian)
#_write(f_ugrid, tets, endian)
#_write(f_ugrid, pyrams, endian)
#_write(f_ugrid, pentas, endian)
#_write(f_ugrid, hexas, endian)
# %3f or %3d
fmt = endian + '%i%s' % (nnodes * 3, float_fmt) # len(x,y,z) = 3
sfmt = Struct(fmt)
f_ugrid.write(sfmt.pack(*nodes.ravel()))
# TODO: speed up with numpy
if ntris:
# CTRIA3
fmt = endian + '%ii' % (ntris * 3)
sfmt = Struct(fmt)
f_ugrid.write(sfmt.pack(*tris.ravel()))
if nquads:
# QUAD4
fmt = endian + '%ii' % (nquads * 4)
sfmt = Struct(fmt)
f_ugrid.write(sfmt.pack(*quads.ravel()))
# PSHELL
if nshells:
fmt = endian + '%ii' % (nshells)
sfmt = Struct(fmt)
f_ugrid.write(sfmt.pack(*pids.ravel()))
if ntets:
# CTETRA
fmt = endian + '%ii' % (ntets * 4)
sfmt = Struct(fmt)
f_ugrid.write(sfmt.pack(*tets.ravel()))
if npyramids:
# CPYRAM
fmt = endian + '%ii' % (npyramids * 5)
sfmt = Struct(fmt)
f_ugrid.write(sfmt.pack(*pyrams.ravel()))
if npentas:
# CPENTA
fmt = endian + '%ii' % (npentas * 6)
sfmt = Struct(fmt)
f_ugrid.write(sfmt.pack(*pentas.ravel()))
if nhexas:
# CHEXA
fmt = endian + '%ii' % (nhexas * 8)
sfmt = Struct(fmt)
f_ugrid.write(sfmt.pack(*hexas.ravel()))
if check:
self.check_hanging_nodes()
[docs] def _write_bdf_solids(self, bdf_file, eid, pid, convert_pyram_to_penta=True):
"""writes the Nastran BDF solid elements"""
#pid = 0
bdf_file.write('PSOLID,%i,1\n' % pid)
self.log.debug('writing CTETRA')
bdf_file.write('$ CTETRA\n')
for element in self.tets:
#card = ['CTETRA', eid, pid] + list(element)
#f.write(print_int_card(card))
bdf_file.write('CTETRA %-8i%-8i%-8i%-8i%-8i%-8i\n' % (
eid, pid, element[0], element[1], element[2], element[3]))
eid += 1
if convert_pyram_to_penta:
# skipping the penta5s
self.log.debug('writing CPYRAM as CPENTA with node6=node5')
bdf_file.write('$ CPYRAM - CPENTA5\n')
for element in self.penta5s:
bdf_file.write('CPENTA %-8i%-8i%-8i%-8i%-8i%-8i%-8i%-8i\n' % (
eid, pid, element[0], element[1], element[2], element[3],
element[4], element[4]))
eid += 1
else:
self.log.debug('writing CPYRAM')
bdf_file.write('$ CPYRAM - CPENTA5\n')
for element in self.penta5s:
bdf_file.write('CPYRAM %-8i%-8i%-8i%-8i%-8i%-8i%-8i\n' % (
eid, pid, element[0], element[1], element[2], element[3], element[4]))
eid += 1
self.log.debug('writing CPENTA')
bdf_file.write('$ CPENTA6\n')
for element in self.penta6s:
#card = ['CPENTA', eid, pid] + list(element)
#f.write(print_int_card(card))
bdf_file.write('CPENTA %-8i%-8i%-8i%-8i%-8i%-8i%-8i%-8i\n' % (
eid, pid, element[0], element[1], element[2], element[3], element[4], element[5]))
eid += 1
self.log.debug('writing CHEXA')
bdf_file.write('$ CHEXA\n')
for element in self.hexas:
#card = ['CHEXA', eid, pid] + list(element)
bdf_file.write('CHEXA %-8i%-8i%-8i%-8i%-8i%-8i%-8i%-8i\n %-8i%-8i\n' % (
eid, pid, element[0], element[1], element[2], element[3],
element[4], element[5], element[6], element[7]))
#f.write(print_int_card(card))
eid += 1
return eid, pid
[docs] def skin_solids(self):
"""Finds the CTRIA3s and CQUAD4 elements on the surface of the solid"""
tris = []
quads = []
nhexas = self.hexas.shape[0]
npenta6s = self.penta6s.shape[0]
npenta5s = self.penta5s.shape[0]
ntets = self.tets.shape[0]
nquads = nhexas * 6 + npenta5s + 3 * npenta6s
ntris = npenta5s * 4 + npenta6s * 2 + ntets * 4
self.log.info('ntris=%s nquads=%s' % (ntris, nquads))
if ntris:
tris = zeros((ntris, 3), dtype='int32')
if nquads:
quads = zeros((nquads, 4), dtype='int32')
ntri_start = 0
nquad_start = 0
if ntets:
faces1 = self.tets[:, [0, 1, 2]]
faces2 = self.tets[:, [0, 1, 3]]
faces3 = self.tets[:, [1, 2, 3]]
faces4 = self.tets[:, [0, 2, 3]]
tris[:ntets] = faces1
tris[ntets:2*ntets] = faces2
tris[2*ntets:3*ntets] = faces3
tris[3*ntets:4*ntets] = faces4
ntri_start += 4*ntets
if nhexas:
# btm (1-2-3-4)
# top (5-6-7-8)
# left (1-4-8-5
# right (2-3-7-6)
# front (1-2-6-5)
# back (4-3-7-8)
faces1 = self.hexas[:, [0, 1, 2, 3]] # 1,2,3,4
faces2 = self.hexas[:, [4, 5, 6, 7]] # 5,6,7,8
faces3 = self.hexas[:, [0, 3, 7, 4]]
faces4 = self.hexas[:, [1, 2, 6, 5]]
faces5 = self.hexas[:, [0, 1, 5, 4]]
faces6 = self.hexas[:, [3, 2, 6, 7]]
quads[: nhexas] = faces1
quads[nhexas:2*nhexas] = faces2
quads[2*nhexas:3*nhexas] = faces3
quads[3*nhexas:4*nhexas] = faces4
quads[4*nhexas:5*nhexas] = faces5
quads[5*nhexas:6*nhexas] = faces6
nquad_start += 6*nhexas
if npenta5s:
faces1 = self.penta5s[:, [0, 1, 2, 3]] # 1,2,3,4
quads[nquad_start:nquad_start+npenta5s] = faces1
faces2 = self.penta5s[:, [0, 1, 4]]
faces3 = self.penta5s[:, [1, 2, 4]]
faces4 = self.penta5s[:, [2, 3, 4]]
faces5 = self.penta5s[:, [3, 0, 4]]
tris[ntri_start :ntri_start+ npenta5s] = faces2
tris[ntri_start+ npenta5s:ntri_start+2*npenta5s] = faces3
tris[ntri_start+2*npenta5s:ntri_start+3*npenta5s] = faces4
tris[ntri_start+3*npenta5s:ntri_start+4*npenta5s] = faces5
ntri_start += 4*npenta5s
if npenta6s:
faces1 = self.penta5s[:, [0, 1, 2]]
faces2 = self.penta5s[:, [3, 4, 5]]
quads[nquad_start :nquad_start+ npenta5s] = faces1
quads[nquad_start+npenta5s:nquad_start+2*npenta5s] = faces2
faces3 = self.penta5s[:, [1, 4, 5, 3]]
faces4 = self.penta5s[:, [0, 1, 4, 3]]
faces5 = self.penta5s[:, [5, 3, 0, 2]]
tris[ntri_start :ntri_start+ npenta6s] = faces3
tris[ntri_start+ npenta6s:ntri_start+2*npenta6s] = faces4
tris[ntri_start+2*npenta6s:ntri_start+3*npenta6s] = faces5
#from numpy.lib.arraysetops import unique
#from numpy import lexsort
#-----------------------------------------
# we have two merged triangle faces of two neighboring TETRAs
# and we need to merge them
#
# this could likely be much, much more efficient
tri_array = np.array(tris)
quad_array = np.array(quads)
if 0:
if ntris:
#print(tris)
#tris = tris.sort()
#print(tris)
tri_set = set()
#tris = tris.sort()
for tri in tris:
tri_set.add(tuple(tri))
tri_array = array(list(tri_set))
else:
tri_array = np.array([])
if nquads:
quads.sort()
unused_quad_set = set()
# if tris:
# tris = vstack(tris)
# tris.sort(axis=0)
# tris = unique_rows(tris)
# if quads:
# quads = vstack(quads)
# quads.sort(axis=0)
# quads = unique_rows(tris)
raise NotImplementedError()
else:
quad_array = np.array(quads)
#print(tris)
#print(quads)
return tris, quad_array
[docs]def determine_dytpe_nfloat_endian_from_ugrid_filename(ugrid_filename=None):
"""figures out what the format of the binary data is based on the filename"""
if ugrid_filename is None:
from pyNastran.utils.gui_io import load_file_dialog
wildcard_wx = "AFLR3 UGRID (*.ugrid)|" \
"*.ugrid|" \
"All files (*.*)|*.*"
wildcard_qt = "AFLR3 UGRID (*.ugrid);;All files (*)"
title = 'Please select an AFLR3 UGRID to load'
ugrid_filename = load_file_dialog(title, wildcard_wx, wildcard_qt)[0]
assert ugrid_filename is not None, ugrid_filename
try:
unused_base, file_format, ext = os.path.basename(ugrid_filename).split('.')
except ValueError:
msg = ('expected file of the form "model.b8.ugrid" '
'or "model.lb4.ugrid"; actual=%r' % ugrid_filename)
raise ValueError(msg)
assert ext == 'ugrid', 'extension=%r' % ext
if '8' in file_format:
ndarray_float = 'float64'
float_fmt = 'd'
nfloat = 8
elif '4' in file_format:
ndarray_float = 'float32'
float_fmt = 'f'
nfloat = 4
else: # ???
msg = 'file_format=%r ugrid_filename=%s' % (file_format, ugrid_filename)
raise NotImplementedError(msg)
if 'lb' in file_format: # C binary, little endian
endian = '<'
elif 'b' in file_format: # C binary, big endian
endian = '>'
#elif 'lr' in file_format: # Fortran unformatted binary, little endian
#endian = '>'
#elif 'r' in file_format: # Fortran unformatted binary, big endian
#endian = '>'
else: # fortran unformatted
msg = 'file_format=%r ugrid_filename=%s' % (file_format, ugrid_filename)
raise NotImplementedError(msg)
return ndarray_float, float_fmt, nfloat, endian, ugrid_filename