Source code for pyNastran.converters.aflr.ugrid.ugrid_reader

"""
Defines the following classes:
    - UGRID

"""
import os
import sys
from struct import Struct, unpack
from pathlib import PurePath
from itertools import zip_longest
from typing import Union, Optional

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

PathLike = Union[str, PurePath]


[docs] def read_ugrid(ugrid_filename: Optional[PathLike]=None, encoding=None, log=None, debug: bool=True, read_shells: bool=True, read_solids: bool=True, check: bool=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: bool=False, read_shells: bool=True, read_solids: bool=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: Optional[PathLike], check: bool=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(f'nnodes={_to_unit(nnodes)} ntris={_to_unit(ntris)} ' f'nquads={_to_unit(nquads)} ntets={_to_unit(ntets)} ' f'npenta5s={_to_unit(npenta5s)} npenta6s={_to_unit(npenta6s)} ' f'nhexas={_to_unit(nhexas)}') nvolume_elements = ntets + npenta5s + npenta6s + nhexas self.log.info(f'nsurface_elements={_to_unit(npids)} ' f'nvolume_elements={_to_unit(nvolume_elements)}') # 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_cart3d(self, cart3d_filename: PathLike, float_fmt: str='%f', encoding=None, pids_to_remove=None, check: bool=True) -> None: self._check_node_ids() if pids_to_remove is None: pids_to_remove = [] if encoding is None: encoding = sys.getdefaultencoding() log = self.log float_fmts = float_fmt + ' ' + float_fmt + ' ' + float_fmt + '\n' #------------------------------------- # filter unwanted properties #pids_to_remove = [1] pid_check = np.ones(len(self.pids), dtype='bool') for pid in pids_to_remove: pid_check1 = (self.pids != pid) pid_check = np.logical_and(pid_check, pid_check1) pids = self.pids # slice the properties and slice the pid_check, to simplify writing ntri = len(self.tris) nquad = len(self.quads) pids_tri = pids[:ntri] pids_quad = pids[ntri:] pids_check_tri = pid_check[:ntri] pids_check_quad = pid_check[ntri:] # ntri2 = pids_check_tri.sum() nquad2 = pids_check_quad.sum() nelements = ntri2 + 2 * nquad2 if nelements == 0: msg = f'all elements have been filtered; ntri={ntri}; nquad={nquad} -> nelements={nelements}' log.error(msg) raise RuntimeError(msg) #------------------------------------- # filter unwanted nodes pids = self.pids nids_to_write_list = [] if len(self.tris): nids_to_write_list.append(self.tris[pids_check_tri, :].ravel()) if len(self.quads): nids_to_write_list.append(self.quads[pids_check_quad, :].ravel()) nids_to_write = np.unique(nids_to_write_list) del nids_to_write_list nnodes_all = nids_to_write.max() nnodes = len(nids_to_write) log.debug(f'nodes: min={nids_to_write.min()} max={nids_to_write.max()} len={nnodes}') assert nnodes > 0, nnodes all_nids = np.arange(nnodes_all, dtype='int32') + 1 # map the nodes/elements inid = np.searchsorted(all_nids, nids_to_write) tris = np.searchsorted(nids_to_write, self.tris) + 1 quads = np.searchsorted(nids_to_write, self.quads) + 1 nodes = self.nodes[inid, :] #------------------------------------- regions = [] log.debug(f'writing cart3d; ntri={ntri}; nquad={nquad} -> nnodes={nnodes} nelements={nelements}') with open(cart3d_filename, 'w', encoding=encoding) as cart3d_file: cart3d_file.write(f'{nnodes} {nelements}\n') for node in nodes: cart3d_file.write(float_fmts % tuple(node)) if pids_check_tri.sum(): tris2 = tris[pids_check_tri, :] pids2 = pids_tri[pids_check_tri] for element, pid in zip_longest(tris2, pids2): assert len(np.unique(element)) == 3, element cart3d_file.write('%-8i %-8i %-8i\n' % tuple(element)) regions.append(pid) if pids_check_quad.sum(): quads2 = quads[pids_check_quad, :] pids2 = pids_quad[pids_check_quad] for element, pid in zip_longest(quads2, pids2): cart3d_file.write('%-8i %-8i %-8i\n' % ( element[0], element[1], element[2])) cart3d_file.write('%-8i %-8i %-8i\n' % ( element[0], element[2], element[3])) regions.append(pid) regions.append(pid) for region in regions: cart3d_file.write(f'{region}\n') if check: # check we didn't lose nodes from pyNastran.converters.cart3d.cart3d import read_cart3d model = read_cart3d(cart3d_filename, log=self.log) assert model.get_area().sum() > 0 del model return
[docs] def write_bdf(self, bdf_filename: PathLike, include_shells: bool=True, include_solids: bool=True, convert_pyram_to_penta: bool=True, write_grids: bool=True, encoding=None, size: int=16, is_double: bool=False, check: bool=True) -> None: """ 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 mid = 1 write_grids = True log = self.log 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') bdf_file.write('MAT1, %i, 1.0e7,, 0.3\n' % mid) log.debug('writing GRIDs') 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]))) 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)) 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 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 = _write_bdf_solids( bdf_file, log, eid, pid, self.tets, self.penta5s, self.penta6s, self.hexas, convert_pyram_to_penta=convert_pyram_to_penta) bdf_file.write('ENDDATA\n')
[docs] def check_hanging_nodes(self, stop_on_diff: bool=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) -> None: 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: PathLike, 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 log = self.log if len(pids): log.info('nupids=%s min=%s max=%s' % (np.unique(pids), pids.min(), pids.max())) else: 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) 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 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 _to_unit(value: int) -> str: if value < 10_000: str_value = '%d' % value elif value < 1_000_000: str_value = '%.3fk' % (value / 1000.) else: str_value = '%.3fm' % (value / 1_000_000.) return str_value
[docs] def determine_dytpe_nfloat_endian_from_ugrid_filename(ugrid_filename: Optional[PathLike]=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 basename = os.path.basename(ugrid_filename) try: unused_base, file_format, ext = basename.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
[docs] def _write_bdf_solids(bdf_file, log, eid: int, pid: int, tets, penta5s, penta6s, hexas, convert_pyram_to_penta: bool=True): """writes the Nastran BDF solid elements""" #pid = 0 bdf_file.write('PSOLID,%i,1\n' % pid) log.debug('writing CTETRA') bdf_file.write('$ CTETRA\n') for element in 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 log.debug('writing CPYRAM as CPENTA with node6=node5') bdf_file.write('$ CPYRAM - CPENTA5\n') for element in 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: log.debug('writing CPYRAM') bdf_file.write('$ CPYRAM - CPENTA5\n') for element in 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 log.debug('writing CPENTA') bdf_file.write('$ CPENTA6\n') for element in 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 log.debug('writing CHEXA') bdf_file.write('$ CHEXA\n') for element in 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