Source code for pyNastran.op2.op2_interface.op2_reader

"""
Defines various tables that don't fit in other sections:
  - OP2Reader
    - read_cmodeext(self)
    - read_cmodeext_helper(self)
    - read_aemonpt(self)
    - read_monitor(self)
    - read_r1tabrg(self)
    - read_hisadd(self)

    - read_cstm(self)
    - read_dit(self)
    - read_extdb(self)
    - read_fol(self)
    - read_frl(self)
    - read_gpl(self)
    - read_ibulk(self)
    - read_intmod(self)
    - read_meff(self)
    - read_omm2(self)
    - read_sdf(self)
    - read_tol(self)
    - _skip_pcompts(self)
    - _read_pcompts(self)

  - Matrix
    - _get_matrix_row_fmt_nterms_nfloats(self, nvalues, tout)
    - _skip_matrix_mat(self)
    - read_matrix(self, table_name)
    - _read_matpool_matrix(self)
    - _read_matrix_mat(self)
    - grids_comp_array_to_index(grids1, comps1, grids2, comps2,
                                make_matrix_symmetric)

  - Others
    - _get_marker_n(self, nmarkers)
    - read_markers(self)
    - _skip_subtables(self)
    - _skip_table_helper(self)
    - _print_month(self, month, day, year, zero, one)
    - read_results_table(self)

"""
from __future__ import annotations
import os
import sys
from copy import deepcopy
from itertools import count
from struct import unpack, Struct, error as struct_error
from typing import Tuple, Optional, Callable, TYPE_CHECKING

import numpy as np
import scipy  # type: ignore

from cpylog import SimpleLogger
from pyNastran.utils.numpy_utils import integer_types
from pyNastran.f06.errors import FatalError
from pyNastran.op2.errors import FortranMarkerError, SortCodeError
from pyNastran.op2.result_objects.gpdt import GPDT, BGPDT
from pyNastran.op2.result_objects.eqexin import EQEXIN
from pyNastran.op2.result_objects.matrix import Matrix, MatrixDict
from pyNastran.op2.result_objects.design_response import DSCMCOL
from pyNastran.op2.op2_interface.nx_tables import NX_VERSIONS

from pyNastran.op2.op2_interface.utils import (
    mapfmt, reshape_bytes_block,
    reshape_bytes_block_size)


from pyNastran.op2.result_objects.design_response import (
    WeightResponse, DisplacementResponse, StressResponse, StrainResponse, ForceResponse,
    FlutterResponse, FractionalMassResponse, Convergence, Desvars, DSCMCOL)
if TYPE_CHECKING:  # pragma: no cover
    from pyNastran.op2.op2 import OP2

IS_TESTING = True

#class MinorTables:
    #def __init__(self, op2_reader):
        #self.op2_reader = op2_reader

[docs]class SubTableReadError(Exception): pass
MSC_LONG_VERSION = [ b'XXXXXXXX20140', b'XXXXXXXX20141', b'XXXXXXXX20142', b'XXXXXXXX20150', b'XXXXXXXX20151', b'XXXXXXXX20152', b'XXXXXXXX20160', b'XXXXXXXX20161', b'XXXXXXXX20162', b'XXXXXXXX20170', b'XXXXXXXX20171', b'XXXXXXXX20172', b'XXXXXXXX20180', b'XXXXXXXX20181', b'XXXXXXXX20182', ] DENSE_MATRICES = [ b'KELM', b'MELM', b'BELM', b'KELMP', b'MELMP', ] OPTISTRUCT_VERSIONS = [ b'OS11XXXX', b'OS12.210', b'OS14.210', b'OS2017.1', b'OS2017.2', b'OS2018.1', ]
[docs]class OP2Reader: """Stores methods that aren't useful to an end user""" def __init__(self, op2: OP2): #: should an h5_file be created self.load_as_h5 = False #: the h5 file object used to reduce memory usage self.h5_file = None self.size = 4 # Hack to dump the IBULK/CASECC decks in reverse order # It's in reverse because that's how Nastran writes it. # # We could write it correctly, but there's a chance the # deck could crash. self._dump_deck = False self.op2 = op2 # type: OP2 self.mapped_tables = { b'GPL' : self.read_gpl, b'GPLS' : self.read_gpls, # GPDT - Grid point definition table b'GPDT' : self.read_gpdt, b'GPDTS' : self.read_gpdt, # BGPDT - Basic grid point definition table. b'BGPDT' : self.read_bgpdt, b'BGPDTS' : self.read_bgpdt, b'BGPDTOLD' : self.read_bgpdt, b'BGPDTVU' : self.read_bgpdt, # optimization b'DESCYC' : self.read_descyc, b'DBCOPT' : self.read_dbcopt, b'DSCMCOL' : self.read_dscmcol, b'DESTAB' : self._read_destab, #b'MEFF' : self.read_meff, b'INTMOD' : self.read_intmod, b'HISADD' : self.read_hisadd, b'EXTDB' : self.read_extdb, b'OMM2' : self.read_omm2, b'STDISP' : self.read_stdisp, b'TOL' : self.read_tol, b'PCOMPT' : self._read_pcompts, b'PCOMPTS' : self._read_pcompts, b'MONITOR' : self.read_monitor, b'AEMONPT' : self.read_aemonpt, b'FOL' : self.read_fol, # frequency response list b'FRL' : self.read_frl, # frequency response list b'SDF' : self.read_sdf, b'IBULK' : self.read_ibulk, b'ICASE' : self.read_icase, b'CDDATA' : self.read_cddata, b'CMODEXT' : self._read_cmodext, # element matrices #b'KELM' : self._read_element_matrix, #b'MELM' : self._read_element_matrix, #b'BELM' : self._read_element_matrix, #b'KELMP' : self._read_element_matrix, #b'MELMP' : self._read_element_matrix, # element dictionaries b'KDICT' : self._read_dict, b'MDICT' : self._read_dict, b'BDICT' : self._read_dict, b'KDICTP' : self._read_dict, b'MDICTP' : self._read_dict, b'KDICTDS' : self._read_dict, b'KDICTX' : self._read_dict, b'XDICT' : self._read_dict, b'XDICTB' : self._read_dict, b'XDICTDS' : self._read_dict, b'XDICTX' : self._read_dict, # coordinate system transformation matrices b'CSTM' : self.read_cstm, b'CSTMS' : self.read_cstm, b'R1TABRG': self.read_r1tabrg, # Qualifier info table??? b'QUALINFO' : self.read_qualinfo, # Equivalence between external and internal grid/scalar numbers b'EQEXIN' : self.read_eqexin, b'EQEXINS' : self.read_eqexin, b'XSOP2DIR' : self.read_xsop2dir, }
[docs] def read_nastran_version(self, mode: str): """ reads the version header ints = (3, 4, 12, 1, 28, 12, 12, 4, 7, 4, 28, 1414742350, 541999442, 1414680390, 1346458656, 1145643077, 1146045216, 539828293, 28, 4, 2, 4, 8, 1482184792, 1482184792, 8, 4, -1, 4, 4, 0, 4, 4, 2, 4, 8, 1297040711, 538976305, 8, 4, -1 """ #try: op2 = self.op2 markers = self.get_nmarkers(1, rewind=True) #except Exception: #self._goto(0) #try: #self.f.read(4) #except Exception: #raise FatalError("The OP2 is empty.") #raise if self.is_debug_file: if self.read_mode == 1: self.binary_debug.write('read_mode = %s (vectorized; 1st pass)\n' % self.read_mode) elif self.read_mode == 2: self.binary_debug.write('read_mode = %s (vectorized; 2nd pass)\n' % self.read_mode) if markers == [3,]: # PARAM, POST, -1 if self.is_debug_file: self.binary_debug.write('marker = 3 -> PARAM,POST,-1?\n') if op2.post is None: op2.post = -1 self.read_markers([3]) data = self.read_block() # TODO: is this the date...pretty sure at least for MSC ndata = len(data) if ndata == 4: one = Struct(self._endian + b'i').unpack(data)[0] assert one == 1, one elif ndata == 12: date = self.op2.struct_3i.unpack(data) op2.log.debug(f'date = {date}') elif ndata == 24: date = self.op2.struct_3q.unpack(data) op2.log.debug(f'date = {date}') else: #self.show_data(data, types='ifsqd', endian=None, force=False) assert ndata in [4, 12, 24], f'ndata={ndata} data={data}' self.read_markers([7]) data = self.read_string_block() # 'NASTRAN FORT TAPE ID CODE - ' if data == b'NASTRAN FORT TAPE ID CODE - ': macro_version = 'nastran' elif b'IMAT v' in data: imat_version = data[6:11].encode('utf8') macro_version = 'IMAT %s' % imat_version mode = 'msc' else: version_ints = Struct(self._endian + b'7i').unpack(data) if version_ints == (1, 2, 3, 4, 5, 6, 7): macro_version = 'MSFC' mode = 'msc' else: self.show_data(data) raise NotImplementedError(data) if self.is_debug_file: self.binary_debug.write('%r\n' % data) #print('macro_version = %r' % macro_version) data = self._read_record() if self.is_debug_file: self.binary_debug.write('%r\n' % data) version = data.strip() #version_str = version.decode(self._encoding) #print('version = %r' % version_str) if macro_version == 'nastran': mode = _parse_nastran_version( data, version, self._encoding, self.op2.log) elif macro_version.startswith('IMAT'): assert version.startswith(b'ATA'), version op2._nastran_format = macro_version elif macro_version == 'MSFC': op2._nastran_format = macro_version #self.show_data(version) #assert version.startswith(b'ATA'), version if self.is_debug_file: self.binary_debug.write(data.decode(self._encoding) + '\n') self.read_markers([-1, 0]) elif markers == [2,]: # PARAM, POST, -2 if self.is_debug_file: self.binary_debug.write('marker = 2 -> PARAM,POST,-2?\n') if op2.post is None: op2.post = -2 else: raise NotImplementedError(markers) if op2._nastran_format == 'autodesk': op2.post = -4 mode = 'autodesk' elif op2._nastran_format == 'nasa95': op2.post = -4 mode = 'nasa95' elif isinstance(op2._nastran_format, str): if op2._nastran_format not in ['msc', 'nx', 'optistruct']: raise RuntimeError(f'nastran_format={op2._nastran_format} mode={mode} and must be "msc", "nx", "optistruct", or "autodesk"') mode = op2._nastran_format elif mode is None: self.log.warning("No mode was set, assuming 'msc'") mode = 'msc' self.log.debug(f'mode = {mode!r}') self.op2.set_mode(mode) self.op2.set_table_type()
[docs] def read_xsop2dir(self): """ Matrix datablocks are named with the matrix name, and they contain only the matrices with no row and column DOF information. External superelements are written to the OP2 in the XSOP2DIR datablock which contains the directory of matrices, and multiple EXTDB datablocks that contain these matrices. The information in XSOP2DIR can be used to rename the EXTDB datablocks to their corresponding matrix name. The MATPOOL datablock contains matrices of several different formats. MATPOOL matrices are DMIG-formatted matrices. Matrices from all of these sources can be stored as structured array. """ # C:\MSC.Software\simcenter_nastran_2019.2\tpl_post1\extse04c_cnv1_0.op2 # C:\MSC.Software\simcenter_nastran_2019.2\tpl_post2\extse04c_cnv1_0.op2 # C:\MSC.Software\simcenter_nastran_2019.2\tpl_post1\atv005mat.op2 if self.read_mode == 2: table_name = self._read_table_name(rewind=True) self._skip_table(table_name, warn=False) return #op2 = self.op2 unused_table_name = self._read_table_name(rewind=False) self.read_markers([-1]) # (101, 14, 0, 0, 0, 0, 0) data = self._read_record() #self.read_3_markers([-2, 1, 0]) #data = self._read_record() itable = -2 self.read_3_markers([itable, 1, 0]) marker = self.get_marker1(rewind=True, macro_rewind=False) if self.size == 4: struct_8s = Struct(self._endian + b'8s') while marker != 0: itable -= 1 data = self._read_record() name = struct_8s.unpack(data)[0] self.log.warning(name) self.read_3_markers4([itable, 1, 0]) marker = self.get_marker1_4(rewind=True, macro_rewind=False) else: struct_16s = Struct(self._endian + b'16s') while marker != 0: itable -= 1 data = self._read_record() name = struct_16s.unpack(data)[0] name = reshape_bytes_block(name) self.log.warning(name) self.read_3_markers([itable, 1, 0]) marker = self.get_marker1_8(rewind=True, macro_rewind=False) self.read_markers([0])
#b'XSOP2DIR', #b'PVT0 ' #b'GEOM1EX ' # b'GEOM2EX ' # b'GEOM4EX ' # b'GEOM1EXA' #b'MATK ' #b'MATM ' #b'MATV ' #b'TUG1 ' #b'MUG1 ' #b'TES1 ' #b'MES1 '
[docs] def read_eqexin(self): """isat_random.op2""" op2 = self.op2 unused_table_name = self._read_table_name(rewind=False) self.read_markers([-1]) data = self._read_record() fmt1 = mapfmt(self._endian + b'7i', self.size) idata = unpack(fmt1, data) assert idata[0] == 101, idata unused_nnodes = idata[1] assert idata[2] == 0, idata assert idata[3] == 0, idata assert idata[4] == 0, idata assert idata[5] == 0, idata assert idata[6] == 0, idata #print('----------------------') self.read_3_markers([-2, 1, 0]) self.read_table_name(['EQEXIN', 'EQEXINS', 'EQEXNOUT', 'SAEQEXIN']) #print('----------------------') # ints - sort order self.read_3_markers([-3, 1, 0]) data = self._read_record() eqexin1 = np.frombuffer(data, dtype=op2.idtype) # ints - nid, dof_type self.read_3_markers([-4, 1, 0]) data = self._read_record() eqexin2 = np.frombuffer(data, dtype=op2.idtype) self.read_markers([-5, 1, 0, 0]) nid, dof, doftype = eqexin_to_nid_dof_doftype(eqexin1, eqexin2) op2.op2_results.eqexin = EQEXIN(nid, dof, doftype)
#print('nid = %s' % nid.tolist()) [1,2,3,...] #print('dof = %s' % dof.tolist()) [1,7,13,...] #print('doftype = %s' % doftype.tolist())
[docs] def read_aemonpt(self): r""" reads the AEMONPT table D:\NASA\git\examples\backup\aeroelasticity\loadf.op2 """ #self.log.debug("table_name = %r" % op2.table_name) unused_table_name = self._read_table_name(rewind=False) #print('-----------------------') #print('record 1') self.read_markers([-1]) data = self._read_record() #self.show_data(data) if self.read_mode == 2: a, bi, c, d, e, f, g = unpack(self._endian + b'7i', data) assert a == 101, a assert bi in [0, 1, 3], bi assert c == 27, c assert d == 1, d assert e in [6, 11], e assert f == 0, f assert g == 0, g #print('-----------------------') #print('record 2') self.read_3_markers([-2, 1, 0]) data = self._read_record() word, = unpack(self._endian + b'8s', data) assert word in [b'AECFMON ', b'AEMON '], word #self.show_data(data) #print('-----------------------') #print('record 3') self.read_3_markers([-3, 1, 0]) data = self._read_record() #self.show_data(data) if self.read_mode == 2: ndata = len(data) assert ndata == 108, ndata n = 8 + 56 + 20 + 12 + 12 out = unpack(self._endian + b'8s 56s 5i 4s 8s 3i', data[:n]) (aero, name, comps, cp, bi, c, d, coeff, word, e, f, g) = out print('aero=%r' % aero) print('name=%r' % name) print('comps=%r cp=%s b,c,d=(%s, %s, %s)' % (comps, cp, bi, c, d)) print('coeff=%r' % coeff) print('word=%r (e, f, g)=(%s, %s, %s)' % (word, e, f, g)) # (1, 2, 0) assert cp == 2, cp assert bi == 0, bi assert c == 0, c assert d == 0, d assert e == 1, e assert f == 2, f assert g == 0, g #print('-----------------------') #print('record 4') self.read_3_markers([-4, 1, 0]) #data = self._read_record() #self.show_data(data) self.read_markers([0])
#print('-----------------------') #print('end') #self.show(200)
[docs] def read_monitor(self): r""" reads the MONITOR table; new version D:\NASA\git\examples\backup\aeroelasticity\loadf.op2""" op2 = self.op2 self.log.debug("table_name = %r" % op2.table_name) unused_table_name = self._read_table_name(rewind=False) self.read_markers([-1]) #(101, 2, 27, 0, 9, 0, 0) data = self._read_record() #self.show_data(data) if self.read_mode == 2: a, bi, c, d, e, f, g = unpack(self._endian + b'7i', data) assert a == 101, a assert bi == 1, bi assert c == 27, c assert d == 0, d assert e == 6, e assert f == 0, f assert g == 0, g self.read_3_markers([-2, 1, 0]) #b'STMON ' data = self._read_record() if self.read_mode == 2: word, = op2.struct_8s.unpack(data) assert word == b'STCFMON ', word #self.show_data(data) #print('-----------------------') #print('record 3') self.read_3_markers([-3, 1, 0]) data = self._read_record() #self.show_data(data[96:108]) if self.read_mode == 2: ndata = len(data) assert ndata == 108, ndata (unused_aero, name, comps, cp, x, y, z, unused_coeff, word, column, cd, ind_dof) = unpack(self._endian + b'8s 56s 2i 3f 4s 8s 3i', data[:108]) #print('aero=%r' % aero) #print('name=%r' % name) #print('comps=%s cp=%s (x, y, z)=(%s, %s, %s)' % (comps, cp, x, y, z)) #print('coeff=%r' % coeff) #print('word=%r (column, cd, ind_dof)=(%s, %s, %s)' % (word, column, cd, ind_dof)) assert cp == 2, cp assert x == 0.0, x assert y == 0.0, y assert d == 0.0, z assert column == 1, column assert cd == 2, cd assert ind_dof == 0, ind_dof op2.monitor_data = [{ 'name' : name, 'cp' : cp, 'cd' : cd, 'xyz' : [x, y, z], 'comps' : comps, }] #print('-----------------------') #print('record 4') self.read_3_markers([-4, 1, 0]) #data = self._read_record() #self.show_data(data) self.read_markers([0])
#print('-----------------------') #print('end') #self.show(200) def _read_dict(self): """testing the KDICT""" op2 = self.op2 if self.read_mode == 1: table_name = self._read_table_name(rewind=True) self._skip_table(table_name, warn=False) return op2.table_name = self._read_table_name(rewind=False) #self.log.debug('table_name = %r' % op2.table_name) self.read_markers([-1]) data = self._read_record() #self.show_data(data) unused_ints = unpack(self._endian + b'7i', data) #print('date? = (?, month, day, ?, ?, ?) =', ints) self.read_3_markers([-2, 1, 0]) data = self._read_record() name, = unpack(self._endian + b'8s', data) name = name.decode('ascii').strip() #print('name = %r' % name) self.read_3_markers([-3, 1, 0]) matdict = MatrixDict(name) itable = -4 while 1: markers = self.get_nmarkers(1, rewind=True) if markers == [0]: break #------------------------------------------------------------------- data = self._read_record() n0 = 0 ndata = len(data) eltype, numwids, numgrid, dof_per_grid, form = unpack(self._endian + b'5i', data[:20]) n0 += 20 #print('etype', eltype) #print('numwids', numwids) #print('numgrid', numgrid) #print('dof_per_grid', dof_per_grid) #print('form', form) eids = [] ge = [] address = [] xforms = [] sils = [] while n0 < ndata: #print("--------") #print('n0=%s ndata=%s' % (n0, ndata)) eid, unused_nactive_grid, gei, address1, address2 = unpack(self._endian + b'2i f 2i', data[n0:n0+20]) eids.append(eid) ge.append(gei) address.append([address1, address2]) n0 += 20 #print('eid', eid) #print('nactive_grid', nactive_grid) #print('ge', ge) #print('address1', address1) #print('address2', address2) if form in [3, 4, 5, 6]: nbytes = numgrid * 4 sil = unpack('%ii' % numgrid, data[n0:n0+nbytes]) n0 += nbytes #print('sil =', sil) assert min(sil) >= 0, sil assert max(sil) < 100000000, sil sils.append(sil) else: raise NotImplementedError(form) if form in [4]: xform = unpack(b'9d', data[n0:n0+36*2]) xform_array = np.array(xform, dtype='float64').reshape(3, 3) #print(xform_array) xforms.append(xform_array) n0 += 36*2 #print('xform =', xform, len(xform)) #self.show_data(data[:n0+80], types='if') if len(xforms) == 0: xforms = None eids = np.array(eids, dtype='int32') ge = np.array(ge, dtype='float32') address = np.array(address, dtype='int32') sils = np.array(sils, dtype='int32') #print('eids, address:\n', eids, '\n', address) #print('sils (etype=%s):\n%s' % (eltype, sils)) matdict.add(eltype, numwids, numgrid, dof_per_grid, form, eids, ge, address, sils, xform=xforms) #------------------------------------------------------------------- self.read_3_markers([itable, 1, 0]) itable -= 1 self.read_markers([0]) self.op2.matdicts[name] = matdict def _read_destab(self) -> None: """reads the DESTAB table""" op2 = self.op2 result_name = 'responses.desvars' if op2._results.is_not_saved(result_name): data = self._skip_table('DESTAB', warn=False) return #if self.read_mode == 1: #return ndata op2.table_name = self._read_table_name(rewind=False) #self.log.debug('table_name = %r' % op2.table_name) if self.is_debug_file: self.binary_debug.write('_read_destab - %s\n' % op2.table_name) self.read_markers([-1]) data = self._read_record() # (101, 3, 3, 0, 3, 0, 0) itable = -2 markers = self.read_3_markers([itable, 1, 0]) data = self._read_record() if self.size == 4: destab = op2.struct_8s.unpack(data)[0].rstrip() structi = Struct('2i 8s 4f') else: destab = op2.struct_16s.unpack(data)[0] destab = reshape_bytes_block(destab).rstrip() structi = Struct('2q 16s 4d') assert destab == b'DESTAB', destab itable -= 1 markers = self.read_3_markers([itable, 1, 0]) desvars = [] while 1: markers = self.get_nmarkers(1, rewind=True) if markers == [0]: break data = self._read_record() #self.show(100, types='ifs', endian=None) #self.show_data(data[:8], types='ifs', endian=None) #1 IDVID I Internal design variable identification number #2 DVID I External design variable identification number #3 LABEL1 CHAR4 First part of design Variable #4 LABEL2 CHAR4 Second part of design Variable #5 VMIN RS Lower bound #6 VMAX RS Upper bound #7 DELX RS Move limit for a design cycle # 8 ??? #C:\NASA\m4\formats\git\examples\move_tpl\accopt3.op2 #--------------------------------------------------------------------------------------------------------- #INTERNAL DESVAR LOWER UPPER #ID ID LABEL BOUND VALUE BOUND #--------------------------------------------------------------------------------------------------------- #1 1 THICK 2.0000E-02 5.0000E-02 8.0000E-02 #2 2 SPRING 1.0000E-02 6.2500E-02 7.5000E-02 #3 3 SPRING 5.0000E-02 1.2500E-01 1.5000E-01 # internal, desvar, label, lower, upper, ???, ??? # (1, 1, b'THICK ', 0.019999, 0.07999999, -0.5, 0.0) # (2, 2, b'SPRING ', 0.009999, 0.07500000, -0.5, 0.0) # (3, 3, b'SPRING ', 0.050000, 0.15000000, -0.5, 0.0) ## id label xinit xlb xub delxv #DESVAR 1 THICK .05 0.02 .08 #DESVAR 2 SPRING .0625 .01 .075 #DESVAR 3 SPRING .125 .05 .15 # C:\NASA\m4\formats\git\examples\move_tpl\betaadj.op2 #--------------------------------------------------------------------------------------------------------- #INTERNAL DESVAR LOWER UPPER #ID ID LABEL BOUND VALUE BOUND #--------------------------------------------------------------------------------------------------------- #11 20 BETA 1.0000E-03 8.0000E-01 1.0000E+20 # int, des, label, lower, upper, ???, ??? #(11, 20, b'BETA ', 0.0010000, 1.000e+20, 0.200, 0.0) # id label xinit xlb xub delxv #desvar 20 beta 0.8 0.001 xub 0.20 desvar = structi.unpack(data) #internal_id, desvar_id, label, lower, upper, delxv, dunno = desvar #print(desvar) #assert np.allclose(desvar[5], -0.5), desvar # -0.5 is the default assert np.allclose(desvar[6], 0.0), desvar desvars.append(desvar) itable -= 1 markers = self.read_3_markers([itable, 1, 0]) self.op2.op2_results.responses.desvars = Desvars(desvars) #if self.read_mode == 2: #self.log.warning('DESTAB results were read, but not saved') markers = self.read_markers([0]) def _read_cmodext(self): r""" fails if a streaming block???: - nx_spike\mnf16_0.op2 """ op2 = self.op2 op2.table_name = self._read_table_name(rewind=False) #self.log.debug('table_name = %r' % op2.table_name) if self.is_debug_file: self.binary_debug.write('_read_geom_table - %s\n' % op2.table_name) size = self.size self.read_markers([-1]) if self.is_debug_file: self.binary_debug.write('---markers = [-1]---\n') data = self._read_record() out = unpack(mapfmt(b'7i', size), data) self.log.debug(str(out)) markers = self.get_nmarkers(1, rewind=True) if self.is_debug_file: self.binary_debug.write('---marker0 = %s---\n' % markers) marker = -2 markers = self.read_markers([marker, 1, 0]) data = self._read_record() if self.size == 4: unused_table_name, oneseventy_a, oneseventy_b = unpack('8sii', data) else: table_name, oneseventy_a, oneseventy_b = unpack('16sqq', data) unused_table_name = reshape_bytes_block(table_name) assert oneseventy_a == 170, oneseventy_a assert oneseventy_b == 170, oneseventy_b #print('170*4 =', 170*4) #self.show_data(data) marker -= 1 n = op2.n while marker < 0: #marker = self._read_cmodext_helper(marker) # -3 marker, is_done = self._read_cmodext_helper(marker) #print(f'--end marker={marker}') #print(f'--end marker2={marker2}') if is_done: break marker2 = self.get_nmarkers(1, rewind=True)[0] n = op2.n #marker = self._read_cmodext_helper(marker); print(marker) #marker = self._read_cmodext_helper(marker); print(marker) #marker = self._read_cmodext_helper(marker); print(marker) #marker = self._read_cmodext_helper(marker); print(marker) #marker = self._read_cmodext_helper(marker); print(marker) #marker = self._read_cmodext_helper(marker); print(marker) #marker = self._read_cmodext_helper(marker); print(marker) #marker = self._read_cmodext_helper(marker); print(marker) print(f'table end; {marker2-1}') #marker = self._read_cmodext_helper(marker, debug=True) #op2.show_ndata(200) #sss def _read_cmodext_helper(self, marker_orig, debug=False) -> Tuple[int, bool]: r""" 64-bit: C:\MSC.Software\simcenter_nastran_2019.2\tpl_post2\mbdrecvr_c_0.op2 C:\MSC.Software\simcenter_nastran_2019.2\tpl_post1\cntlmtl05_0.op2 """ op2 = self.op2 marker = marker_orig #markers = self.read_nmarkers([marker, 1, 1]) # -3 if debug: op2.show_ndata(100) markers = self.get_nmarkers(3, rewind=False) assert markers == [marker_orig, 1, 1], markers #print('markers =', markers) #marker = self.get_nmarkers(1, rewind=False, macro_rewind=False)[0] val_old = 0 if debug: print('-----------------------------') #i = 0 #icheck = 7 #factor = self.factor size = self.size if size == 4: expected_marker = 3 sint = 'i' ifs = 'ifs' #dq = 'if' structi = Struct(b'i') struct_qd = Struct(b'i f') struct_q2d = Struct(b'i 2f') struct_q3d = Struct(b'i 3f') struct_d4q = Struct(b'i 4f') else: expected_marker = 3 sint = 'q' ifs = 'qds' #dq = 'dq' structi = Struct(b'q') struct_qd = Struct(b'q d') #struct_dq = Struct(b'd q') struct_q2d = Struct(b'q 2d') struct_q3d = Struct(b'q 3d') struct_d4q = Struct(b'd 4q') marker = self.get_nmarkers(1, rewind=True, macro_rewind=True)[0] #print('AAAAA', marker) if marker is None: asdf elif marker == 3: pass elif marker < 0: self.log.warning('finished CMODEXT :)!') done = True return None, done else: raise RuntimeError(marker) i = 0 while 1: #print('------------------------------') #print('i = %i' % i) marker = self.get_nmarkers(1, rewind=False, macro_rewind=False)[0] if marker != expected_marker: self.log.info(f'CMODEXT i={i} marker={marker}') if self.size == 4: assert marker in [expected_marker], marker else: #if marker == -4: #self.show(200, types='isq', endian=None, force=False) assert marker in [1, 2, 3, 10, 13, 16], marker data = self.read_block() ndata = len(data) nvalues = ndata // size if nvalues == 2: #self.show_data(data, types=dq) #print(ndata) #self.show_data(data, types=ifs) a, b = struct_qd.unpack(data) print(f' 2 {i}: {a:-4d} {b:.6g}') elif nvalues == 3: #self.show_data(data, types=dq) #print(ndata) #self.show_data(data, types=ifs) a, b, c = struct_q2d.unpack(data) print(f' 3 {i}: {a:-4d} {b:.6g}') elif nvalues == 4: #self.show_data(data, types=dq) #print(ndata) #self.show_data(data, types=ifs) a, b, c, d = struct_q3d.unpack(data) #print(f'4 {i}: {a:-4d} {b:10g} {c:10g} {d:10g}') elif nvalues == 5: #self.show_data(data, types=dq) #print(ndata) out = struct_d4q.unpack(data) print('5 {i}:', out) #elif ndata == 24 * factor: #self.show_data(data, types=dq) #print(ndata) #self.show_data(data, types=ifs) #a, b, c, d = struct_q2d.unpack(data) elif ndata == 11: # ints = (697, 0, 0, 1072693248, -427255041, -1128310260, -1065349346, 1019092170, -458662240, 1015082339, -1959380180, 1018327314, 863132413, -1129941844, 477962639, 992946870, -935437031, 992276971, -1286826876, -1158808745, 1765409376, 986144275) # floats = (9.767050296343975e-43, 0.0, 0.0, 1.875, -3.2255050747205135e+23, -0.023358367383480072, -4.001845359802246, 0.023207087069749832, -2.4994545586342025e+22, 0.015738194808363914, -3.509644095891333e-32, 0.02178243175148964, 5.642776912395675e-08, -0.02031930536031723, 8.375405145620162e-22, 0.0026728338561952114, -194932.390625, 0.002516860840842128, -4.76325254794574e-08, -0.0018156570149585605, 1.4054463629294865e+25, 0.001521053141914308) # doubles (float64) = (3.444e-321, 1.0, -4.350930636102116e-16, 4.1789445167220847e-16, 2.936419423485894e-17, 2.559298496168014e-16, -1.5581808467238972e-16, 1.2890303437976399e-23, 8.662650619686277e-24, -7.750115449925671e-25, 1.5100882399748836e-25) # long long (int64) = (697, 4607182418800017408, -4846055662573544705, 4376967544989290270, 4359745452588490400, 4373682512589110060, -4853063265498801411, 4264674333793526159, 4261797142378470681, -4977045659085663100, 4235457412028039776) #ints = (697, 0, 0, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z) #floats = (697, 0.0, #0.0, 1.875, #-3.2255050747205135e+23, -0.023358367383480072, -4.001845359802246, 0.023207087069749832, -2.4994545586342025e+22, 0.015738194808363914, -3.509644095891333e-32, 0.02178243175148964, 5.642776912395675e-08, -0.02031930536031723, 8.375405145620162e-22, 0.0026728338561952114, -194932.390625, 0.002516860840842128, -4.76325254794574e-08, -0.0018156570149585605, 1.4054463629294865e+25, 0.001521053141914308) #doubles (float64) = (697, 1.0, y, y, y, y, y, y, y, y, y) #long long (int64) = (697, 1.0, x, x, x, x, x, x, x, x, x) self.show_data(data, types='ifsqd') #self.show_data(data[4:], types='qd') raise RuntimeError(f'marker={marker} ndata={ndata}; nvalues={nvalues}') elif nvalues == 17: inti = structi.unpack(data[:size]) floats = np.frombuffer(data, dtype=op2.fdtype8)[1:] print(inti, floats) else: self.show_data(data, types=ifs) raise RuntimeError(f'marker={marker} ndata={ndata}; nvalues={nvalues}') sdf #ints = [ #1387, 0, -1574726656, -1076024976, 12958534, -1079706775, -1204798216, -1076795484, -674762419, -1125074255, -1234714250, 1025640630, 367990681, 1024314941, -1752243687, 1021642278, #-3, 1017741311, #-3, 1019878559, #-2, 1019293439, #-5, -1134034945, #-3, 1017733119, #-3, 1017241599] #floats = [ #1387, 0.0, -2.2168969812013176e-18, -1.7278270721435547, 1.815877379410093e-38, -1.2889224290847778, -4.201845149509609e-05, -1.6359753608703613, -439678385782784.0, -0.029385896399617195, -3.45342914442881e-06, 0.03955908864736557, 9.656856178702571e-26, 0.034620512276887894, -9.233609993079022e-25, 0.02795703336596489, #nan, 0.02069091610610485, #nan, 0.024671850726008415, #nan, 0.023581979796290398, #nan, -0.014160155318677425, #nan, 0.02067565731704235, #nan, 0.01976012997329235] #self.show_data(data, types='ifsqd') #ints = np.frombuffer(data, dtype='int32').tolist() #floats = np.frombuffer(data, dtype='float32').tolist() #print(ints) #print(floats) #np.frombuffer(data, dtype='ifsdq') print('------------------------------') self.show_data(data, types=ifs) #else: #self.show_data(data, types=ifs) val = unpack(sint, data[:size])[0] if debug: print('val=%s delta=%s' % (val, val - val_old)) #self.show_data(data, types=ifs) #self.show_data(data[4:], types=ifs) assert len(data) > size #print('i=%s val=%s delta=%s' % (i, val, val - val_old)) val_old = val marker2 = self.get_nmarkers(1, rewind=True, macro_rewind=False)[0] #print(marker2) if marker2 < 0: self.log.warning(f'breaking marker2={marker2}') self.show(300, types=ifs) break #if marker2 == 696: #self.log.warning('breaking 696') #break i += 1 if debug: print('----------------------------------------') marker = self.get_nmarkers(1, rewind=True, macro_rewind=False)[0] #if debug: print('****marker = %s' % marker) #print('****marker2 = %s' % marker2) #assert marker == 696, marker #data = self.read_block() #self.show_data(data) #marker = self.get_nmarkers(1, rewind=True, macro_rewind=False)[0] assert marker == (marker_orig - 1), f'marker={marker} marker_orig={marker_orig}' if debug: op2.show_ndata(200) done = False return marker, done #data = self._read_record() #marker -= 1 #op2.show_ndata(100) ##marker -= 1 ##marker_end = op2.get_marker1(rewind=False)
[docs] def read_cstm(self): """ Reads the CSTM table, which defines the transform from global to basic. Returns 14-column matrix 2-d array of the CSTM data: :: [ [ id1 type xo yo zo T(1,1:3) T(2,1:3) T(3,1:3) ] [ id2 type xo yo zo T(1,1:3) T(2,1:3) T(3,1:3) ] ... ] T is transformation from local to basic for the coordinate system. """ op2 = self.op2 is_geometry = op2.is_geometry unused_table_name = self._read_table_name(rewind=False) self.read_markers([-1]) data = self._read_record() #print(self.show_data(data, types='ifsqd')) # 101, 466286, 15, 1, 1, 180, 0 # 101, 466286, ncoords, 1, 1, 180, 0 factor = self.factor #if self.size == 4: #idtype = 'int32' #fdtype = 'float32' #else: #idtype = 'int64' #fdtype = 'float64' assert len(data) == 28 * factor, len(data) self.read_3_markers([-2, 1, 0]) data = self._read_record() # CSTM #print(self.show_data(data, types='s')) assert len(data) == 8 * factor, len(data) self.read_3_markers([-3, 1, 0]) coord_type_map = { 1 : 'CORD2R', 2 : '???', 3 : 'CORD2S', 5 : 'GMSURF', 7 : '???', 8 : '???', } #1. Coordinate system type: #- 0 = unknown (seriously?) #- 1 = rectangular #- 2 = cylindrical #- 3 = spherical #- 4 = convective coordinate system defined on a GMCURV+GMSURF pair #- 5 = convective coordinate system defined on a GMSURF #- 6 = convective coordinate system defined on a FEEDGE+FEFACE pair #- 7 = convective coordinate system defined on a FEFACE i = 0 itable = -4 blocks = [] while 1: markers = self.get_nmarkers(1, rewind=True) if markers == [0]: break data = self._read_record() blocks.append(data) self.read_markers([itable, 1, 0]) itable -= 1 markers = self.get_nmarkers(1, rewind=False) if not is_geometry or self.read_mode == 1 or b'GEOM1' in op2.table_names: return nblocks = len(blocks) if nblocks == 1: # vectorized ints = np.frombuffer(blocks[0], dtype=op2.idtype8) floats = np.frombuffer(blocks[0], dtype=op2.fdtype8) #doubles = np.frombuffer(blocks[1], dtype='float64') nints = len(ints) assert nints % 14 == 0, 'nints=%s' % (nints) ncstm = get_table_size_from_ncolumns('CSTM', nints, 14) ints = ints.reshape(ncstm, 14)[:, :2] floats = floats.reshape(ncstm, 14)[:, 2:] #assert ncstm == 1, 'ncoords = %s' % ncstm #print(self.coords) #for i, unused_coord in enumerate(ints): cid = ints[i, 0] coord_type_int = ints[i, 1] if coord_type_int in coord_type_map: unused_coord_type = coord_type_map[coord_type_int] else: # pragma: no cover msg = 'cid=%s coord_type_int=%s is not supported\n' % (cid, coord_type_int) if hasattr(self, 'coords'): print(op2.coords) raise RuntimeError(msg) if not is_geometry: return for intsi, valuesi in zip(ints, floats): cid = intsi[0] coord_type_int = intsi[1] assert len(valuesi) == 12, valuesi #if coord_type_int in coord_type_map: #unused_coord_type = coord_type_map[coord_type_int] #else: # pragma: no cover #msg = 'cid=%s coord_type_int=%s is not supported\n' % (cid, coord_type_int) #if hasattr(self, 'coords'): #print(op2.coords) #raise RuntimeError(msg) origin = valuesi[:3] i = valuesi[3:6] unused_j = valuesi[6:9] k = valuesi[9:12] zaxis = origin + k xzplane = origin + i assert len(origin) == 3, origin assert len(zaxis) == 3, zaxis assert len(xzplane) == 3, xzplane if coord_type_int == 1: coord = op2.add_cord2r(cid, rid=0, origin=origin, zaxis=zaxis, xzplane=xzplane, comment='') elif coord_type_int == 2: coord = op2.add_cord2c(cid, rid=0, origin=origin, zaxis=zaxis, xzplane=xzplane, comment='') elif coord_type_int == 3: coord = op2.add_cord2s(cid, rid=0, origin=origin, zaxis=zaxis, xzplane=xzplane, comment='') elif coord_type_int == 5: #- 7 = convective coordinate system defined on a FEFACE coord = None elif coord_type_int == 7: #- 7 = convective coordinate system defined on a FEFACE coord = None elif coord_type_int == 8: #- 7 = convective coordinate system defined on a FEFACE coord = None else: # pragma: no cover raise NotImplementedError(f'coord_type_int={coord_type_int}') str(coord) elif nblocks == 2: # cstm style #block4 - 4 values - cid, type, int_index, double_index #block5 - 12 values - ox, oy, oz, T11, T12, T13, T21, T22, T23, T31, T32, T33 ints = np.frombuffer(blocks[0], dtype=self.op2.idtype8) doubles = np.frombuffer(blocks[1], dtype='float64') nints = len(ints) ndoubles = len(doubles) ncoords = nints // 4 ints = ints.reshape(ncoords, 4) #print('ints =', ints.tolist()) if ncoords == ndoubles // 12: values = doubles.reshape(ncoords, 12) #print('doubles =', doubles.tolist()) else: values = np.frombuffer(blocks[1], dtype='float32').reshape(ncoords // 4, 12) #print('floats =', floats.tolist()) for intsi, valuesi in zip(ints, values): cid, cid_type, unused_int_index, unused_double_index = intsi assert len(valuesi) == 12, valuesi origin = valuesi[:3] i = valuesi[3:6] unused_j = valuesi[6:9] k = valuesi[9:12] zaxis = origin + k xzplane = origin + i assert len(origin) == 3, origin assert len(zaxis) == 3, zaxis assert len(xzplane) == 3, xzplane if cid_type == 1: coord = op2.add_cord2r(cid, rid=0, origin=origin, zaxis=zaxis, xzplane=xzplane, comment='') elif cid_type == 2: coord = op2.add_cord2c(cid, rid=0, origin=origin, zaxis=zaxis, xzplane=xzplane, comment='') elif cid_type == 3: coord = op2.add_cord2s(cid, rid=0, origin=origin, zaxis=zaxis, xzplane=xzplane, comment='') else: # pragma: no cover raise NotImplementedError(f'cid_type={cid_type}') str(coord) else: # pragma: no cover raise NotImplementedError(f'nCSTM blocks={nblocks} (not 1 or 2)')
#print(self.op2.coords) #while i < len(ints): #break #cid = ints[i] #coord_type_int = ints[i + 1] #if coord_type_int in coord_type_map: #unused_coord_type = coord_type_map[coord_type_int] #else: # pragma: no cover #msg = 'cid=%s coord_type_int=%s is not supported\n' % (cid, coord_type_int) #if hasattr(self, 'coords'): #print(op2.coords) #raise RuntimeError(msg) #if coord_type_int in [1, 2, 3]: # rectangular, cylindrical, spherical #translations_cosines = floats[i+3:i+14] #print(len(translations_cosines)) #i += 14 #else: #raise NotImplementedError('coord_type_int = %i' % coord_type_int) #if 0: ## vectorized #assert nints % 14 == 0, 'nints=%s' % (nints) #ncstm = get_table_size_from_ncolumns('CSTM', nints, 14) #ints = ints.reshape(ncstm, 14)[:, :2] #floats = floats.reshape(ncstm, 14)[:, 2:] ##assert ncstm == 1, 'ncoords = %s' % ncstm ##print(self.coords) #for i, unused_coord in enumerate(ints): #cid = ints[i, 0] #coord_type_int = ints[i, 1] #if coord_type_int in coord_type_map: #unused_coord_type = coord_type_map[coord_type_int] #else: # pragma: no cover #msg = 'cid=%s coord_type_int=%s is not supported\n' % (cid, coord_type_int) #if hasattr(self, 'coords'): #print(op2.coords) #raise RuntimeError(msg) #print(self.coords) #print('cid = ', cid) #print('coord_type = ', coord_type) #print('myints =', ints) #print('floats =', floats)
[docs] def read_qualinfo(self): r""" Reads the QUALINFO table -100001 (AUXMID=0;AFPMID=0;DESITER=0;HIGHQUAL=0;PVALID=0;DESINC=0;DISCRETE=FALSE;MASSID=0;ARBMID=0;PARTNAME=' ';TRIMID=0;MODULE=0) -100000 (AUXMID=0;AFPMID=0;DESITER=0;HIGHQUAL=0;PVALID=0;DESINC=0;ARBMID=0;PARTNAME=' ';DISCRETE=FALSE;TRIMID=0) -99999 (AUXMID=0;AFPMID=0;HIGHQUAL=0;PVALID=0;DESINC=0;PRESEQP=TRUE;ARBMID=0;PARTNAME=' ';TRIMID=0;FLXBDYID=0;DFPHASE=' ') -99998 (AUXMID=0;AFPMID=0;DESITER=0;HIGHQUAL=0;DESINC=0;DISCRETE=FALSE;ARBMID=0;MASSID=0;PARTNAME=' ';TRIMID=0) 1431 (HIGHQUAL=0;AUXMID=0;AFPMID=0;DESINC=0;ARBMID=0;PARTNAME=' ';TRIMID=0;FLXBDYID=0) 1459 (PEID=0;DESITER=0;PVALID=0;NL99=0;APRCH=' ';QCPLD=' ';HIGHQUAL=0;AUXMID=0;DESINC=0;DISCRETE=FALSE;MASSID=0;PARTNAME=' ';MODULE=0) 1461 (PEID=0;APRCH=' ';QCPLD=' ';HIGHQUAL=0;AUXMID=0;DESINC=0;PARTNAME=' ';MODULE=0) 1541 (SEID=0;PEID=0;MTEMP=0;DESITER=0;PVALID=0;APRCH=' ';QCPLD=' ';HIGHQUAL=0;P2G=' ';K2GG=' ';M2GG=' ';DELTA=FALSE;AUXMID=0;BNDSHP=FALSE;ADJOINT=FALSE;DESINC=0;DISCRETE=FALSE;CASEF06=' ';ISOLAPP=1;SUBCID=0;OSUBID=1;STEPID=0;RGYRO=0;PARTNAME=' ';SSTEPID=0;MODULE=0) Word Name Type Description 1 NAME(2) CHAR4 Datablock Name Word Name Type Description 1 DBKEY I database KEY associated with qualifiers 2 QLEN(C) I length in words of qualifiers string 3 QUALSTR CHAR4 Qualifier information string Word 3 repeats QLEN times Word Name Type Description 1 FUNIT I Fortran unit op2 file was written to 2 NUMKEYS I Number of keys 3 BIT(5) I ,{ """ # we read the table on the first pass, so if we ever see a # 64-bit table, the error message makes a bit more sense read_record_ndata = self.get_skip_read_record_ndata() op2 = self.op2 op2.table_name = self._read_table_name(rewind=False) #self.log.debug('table_name = %r' % op2.table_name) if self.is_debug_file: self.binary_debug.write('_read_geom_table - %s\n' % op2.table_name) self.read_markers([-1]) if self.is_debug_file: self.binary_debug.write('---markers = [-1]---\n') # (301, 1, 8, 0, 0, 0, 0) # (???, ?, n, ?, ?, ?, ?) data, ndata = read_record_ndata() assert ndata == 28, self.show_data(data) # 7*4 self.read_3_markers([-2, 1, 0]) # QUALINFO data, ndata = read_record_ndata() assert ndata == 8, self.show_data(data) itable = -3 while 1: self.read_3_markers([itable, 1, 0]) stop_marker = self.get_marker1(rewind=True) if stop_marker == 0: break data, ndata = read_record_ndata() if self.read_mode == 1: db_key, qlen = unpack(self._endian + b'2i', data[:8]) fmt = self._endian + b'%is' % (ndata - 8) qual_str = unpack(fmt, data[8:])[0].decode('latin1') self.log.debug(f'{db_key: 7d} {qual_str}') itable -= 1 stop_marker = self.get_marker1(rewind=False)
[docs] def read_extdb(self): r""" fails if a streaming block: - nx_spike\extse04c_0.op2 """ # C:\MSC.Software\simcenter_nastran_2019.2\tpl_post1\extse04c_cnv1_0.op2 op2 = self.op2 op2.table_name = self._read_table_name(rewind=False) #self.log.debug('table_name = %r' % op2.table_name) if self.is_debug_file: self.binary_debug.write('_read_geom_table - %s\n' % op2.table_name) self.read_markers([-1]) if self.is_debug_file: self.binary_debug.write('---markers = [-1]---\n') unused_data = self._read_record() markers = self.get_nmarkers(1, rewind=True) if self.is_debug_file: self.binary_debug.write('---marker0 = %s---\n' % markers) self.read_3_markers([-2, 1, 0]) data, ndata = self._read_record_ndata() if self.size == 4: if ndata == 8: #self.show_data(data, types='ifs', endian=None) name, = Struct(self._endian + b'8s').unpack(data) #print(name, 8) elif ndata == 16: name, int1, int2 = Struct(self._endian + b'8s 2i').unpack(data) #name = name.decode(self._encoding) #print(name, int1, int2, 16) elif ndata == 28: #self.show_data(data) name1, int1, name2, int2 = Struct(self._endian + b'8s i 12s i').unpack(data) #print(name1, int1, name2, int2, 28) else: self.show_data(data, types='ifs') raise NotImplementedError(ndata) elif self.size == 8: if ndata == 16: name, = Struct(self._endian + b'16s').unpack(data) name = reshape_bytes_block(name) elif ndata == 32: name, int1, int2 = Struct(self._endian + b'16s 2q').unpack(data) name = reshape_bytes_block(name) elif ndata == 56: self.show_data(data, types='ifsd') name1, int1, name2, int2 = Struct(self._endian + b'16s q 24s q').unpack(data) name1 = reshape_bytes_block(name1) name2 = reshape_bytes_block(name2) else: self.show_data(data, types='ifsdq') raise NotImplementedError(ndata) else: self.show_data(data, types='ifsdq') raise NotImplementedError(ndata) if 1: # old #self.show(200) marker = -3 while 1: #print('====================') #print(f'***reading {marker}') try: self.read_markers([marker, 1]) except FortranMarkerError: #op2.show_ndata(100) raise nfields1 = self.get_marker1(rewind=True) if nfields1 == 0: nfields1 = self.get_marker1(rewind=False) elif nfields1 == 1: #data, ndata = self._read_record_ndata() nfields1 = self.read_markers([1]) nfields_test = self.get_marker1(rewind=True) while nfields_test > 0: nfields = self.get_marker1(rewind=False) block = self.read_block() nblock = len(block) ndouble = (nblock - 4) // 8 fmt = mapfmt(self._endian + b'i%dd' % (ndouble), self.size) #out = Struct(self._endian + b'i 3d').unpack(block) out = Struct(fmt).unpack(block) #print(out, nblock) nfields_test = self.get_marker1(rewind=True) #print('-------') #print(f'end of marker={marker}') marker -= 1 #marker = self.get_marker1(rewind=True) continue else: raise RuntimeError('EXTDB error') #op2.show_ndata(100) nfields = self.get_marker1(rewind=True) #print('nfields =', nfields) if nfields == 0: #print('breaking...') #self.show(200) break #elif nfields == 3: #data = self._read_record() #self.show(200, types='ifs', endian=None) #aaa data, ndata = self._read_record_ndata() if ndata == 12: name, int1, int2 = Struct(self._endian + b'4s 2i').unpack(data) # b'\xff\xff\x00\x00' 65535 25535 12 ??? #print(name, int1, int2, 12) #self.show_data(data) #self.show_data(data) elif ndata > 99: pass else: self.log.warning(f'EXTDB; ndata={ndata}') self.show_data(data, types=mapfmt_str('if', self.size)) marker -= 1 #print('--------------------') unused_marker_end = self.get_marker1(rewind=False) return
[docs] def read_descyc(self): """reads the DESCYC table""" op2 = self.op2 #op2.log.debug("table_name = %r" % op2.table_name) op2.table_name = self._read_table_name(rewind=False) self.read_markers([-1]) data = self._read_record() fmt = mapfmt(self._endian + b'7i', self.size) unused_ints = Struct(fmt).unpack(data) self.read_3_markers([-2, 1, 0]) data = self._read_record() if self.size == 4: name, = Struct(self._endian + b'8s').unpack(data) else: name, = Struct(self._endian + b'16s').unpack(data) name = reshape_bytes_block(name) assert name == b'DESCYC ', name self.read_3_markers([-3, 1, 0]) data = self._read_record() if self.size == 4: design_cycle, design_cycle_type_bytes = Struct(self._endian + b'i8s').unpack(data) else: design_cycle, design_cycle_type_bytes = Struct(self._endian + b'q16s').unpack(data) design_cycle_type_bytes = reshape_bytes_block(design_cycle_type_bytes) #Design cycle type; 'D' for discretized design cycle #Blank for continuous design cycle if design_cycle_type_bytes == b' ': design_cycle_type_str = 'continuous' elif design_cycle_type_bytes == b'D ': design_cycle_type_str = 'discrete' else: raise NotImplementedError(design_cycle_type_bytes) self.read_markers([-4, 1, 0, 0])
#print('descyc') #print(' ints =', ints) #print(' name =', name) #print(f' design_cycle={design_cycle} type={design_cycle_type_str!r} count={op2._count}')
[docs] def read_dbcopt(self): """reads the DBCOPT table, which is a design variable history table""" #C:\MSC.Software\simcenter_nastran_2019.2\tpl_post1\cc577.op2 # ints = (101, 11, 10, 3, 4, 0, 0) # objective_function = [1175749.5, 711181.875, 369194.03125, 112453.1406, 229.4625, 50.9286, 50.8863, 50.8316, 50.7017, 49.7571, 49.3475] # approx = [0.0, 651307.3125, 388093.0625, 150222.453125, 5894.2626, 50.9092, 50.8834, 50.8252, 49.4544, 49.6455, 49.2533] # max_value_of_constraint = [nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan] # desvar_ids = [1, 2, 3] # cycle_1_values = [1.0, 1.0, 1.0] # cycle_n_values = [1.4, 0.6, 1.4, # 1.96, 0.36, 1.96, # 2.744, 0.216, 2.744, # 3.8416, 0.1296, 3.8416, ...] # 1 NFEA I Number of finite element analyses # 2 NAOP I Number of optimization cycles w.r.t. approximate model # 3 NDV I Number of design variables # 4 NCC I Convergence criterion # 5 UNDEF(2 ) None op2 = self.op2 op2.table_name = self._read_table_name(rewind=False) self.read_markers([-1]) data = self._read_record() fmt = mapfmt(self._endian + b'7i', self.size) num, nopt, napprox, nvars, one, zeroa, zerob = Struct(fmt).unpack(data) assert num == 101, num assert zeroa == 0, zeroa assert zerob == 0, zerob # (101, 11, 10, 3, 4, 0, 0) #self.show_data(data) self.read_3_markers([-2, 1, 0]) data = self._read_record() if self.size == 4: name, = Struct(self._endian + b'8s').unpack(data) else: name, = Struct(self._endian + b'16s').unpack(data) name = reshape_bytes_block(name) assert name == b'DBCOPT ', name self.read_3_markers([-3, 1, 0]) data = self._read_record() #ndata = len(data) // 4 if self.size == 4: fdtype = 'float32' idtype = 'int32' else: fdtype = 'float64' idtype = 'int64' objective_function = np.frombuffer(data, dtype=fdtype) # .tolist() #print(f' objective_function = {objective_function}; n={len(objective_function)}') assert len(objective_function) == nopt, f'len(objective_function)={len(objective_function)} nopt={nopt}' self.read_3_markers([-4, 1, 0]) data = self._read_record() approx = np.frombuffer(data, dtype=fdtype).copy()# .tolist() napprox_actual = len(approx) if approx[0] == 0.0: approx[0] = np.nan napprox_actual -= 1 #print(approx.tolist()) #assert napprox_actual == napprox, f'napprox_actual={napprox_actual} napprox={napprox}' #print(f' approx = {approx}; n={len(approx)}') self.read_3_markers([-5, 1, 0]) data = self._read_record() max_value_of_constraint = np.frombuffer(data, dtype=fdtype).tolist() #print(f' max_value_of_constraint = {max_va/lue_of_constraint}; n={len(max_value_of_constraint)}') self.read_3_markers([-6, 1, 0]) data = self._read_record() desvar_ids = np.frombuffer(data, dtype=idtype).tolist() assert len(desvar_ids) == nvars, f'len(desvars)={len(desvars)} nvars={nvars}' self.read_3_markers([-7, 1, 0]) data = self._read_record() cycle_1_values = np.frombuffer(data, dtype=fdtype).tolist() self.read_3_markers([-8, 1, 0]) marker0 = self.get_marker1(rewind=True) if marker0 == 0: self.read_markers([0]) return data = self._read_record() cycle_n_values = np.frombuffer(data, dtype=fdtype) cycle_n_values2 = cycle_n_values.reshape(len(cycle_n_values) // nvars, nvars) cycle_n_values3 = np.vstack([cycle_1_values, cycle_n_values2]) approx_obj_constraint = np.vstack([approx, objective_function, max_value_of_constraint]).T #print(f' desvar_ids = {desvar_ids}') #print(f' approx_obj_constraint; {approx_obj_constraint.shape}:\n{approx_obj_constraint}') #print(f' cycle_n_values {cycle_n_values3.shape}:\n{cycle_n_values3}') self.read_markers([-9, 1, 0, 0])
#data = self._read_record() #self.show_data(data) #self.show_ndata(100)
[docs] def read_dscmcol(self): """reads the DSCMCOL table, which defines the columns? for the DSCM2 table""" op2 = self.op2 op2.log.debug("table_name = %r" % op2.table_name) op2.table_name = self._read_table_name(rewind=False) self.read_markers([-1]) data = self._read_record() #fmt = mapfmt(self._endian + b'7i', self.size) #num, ndesvars, one_zero, zeroa, zerob, zeroc, zerod = Struct(fmt).unpack(data) #print(num, ndesvars, one_zero, zeroa, zerob, zeroc, zerod) # (101, 3, 1, 0, 0, 0, 0) #self.show_data(data) self.read_3_markers([-2, 1, 0]) data = self._read_record() if self.size == 4: name, = Struct(self._endian + b'8s').unpack(data) else: name, = Struct(self._endian + b'16s').unpack(data) name = reshape_bytes_block(name) assert name == b'DSCMCOL ', name self.read_3_markers([-3, 1, 0]) data = self._read_record() responses = {} if self.read_mode == 2: ints = np.frombuffer(data, dtype=op2.idtype8) floats = np.frombuffer(data, dtype=op2.fdtype8) nresponses_dresp1 = len(ints) // 9 dscmcol_dresp1(responses, nresponses_dresp1, ints, floats) #self.show_data(data[4*idata:]) self.read_3_markers([-4, 1, 0]) nfields = self.get_marker1(rewind=True) if nfields == 0: self._save_dscmcol_response(responses) self.read_markers([0]) return data = self._read_record() if self.read_mode == 2: # read the DRESP2 columns ints = np.frombuffer(data, dtype=op2.idtype8) floats = np.frombuffer(data, dtype=op2.fdtype8) nresponses_dresp2 = len(ints) // 6 dscmcol_dresp2(responses, nresponses_dresp2, ints, floats) self._save_dscmcol_response(responses) self.read_markers([-5, 1, 0, 0])
def _save_dscmcol_response(self, responses): """saves the DSCMCOL dictionary""" if self.read_mode == 2: assert len(responses) > 0 if responses: if self.op2.op2_results.responses.dscmcol is not None: self.log.warning('overwriting DSCMCOL') respi = DSCMCOL(responses) str(respi) self.op2.op2_results.responses.dscmcol = respi
[docs] def read_fol(self): """ Reads the FOL table Frequency response frequency output list tested by TestOP2.test_monpnt3 +------+---------+-------+-----------------+ | Word | Name | Type | Description | +======+=========+=======+=================+ | 1 | NAME(2) | CHAR4 | Data block name | +------+---------+-------+-----------------+ | 3 | FREQ | RS | Frequency | +------+---------+-------+-----------------+ | Word 3 repeats until End of Record | +------------------------------------------+ +------+----------+------+-----------------------------+ | Word | Name | Type | Description | +======+==========+======+=============================+ | 1 | WORD1 | I | Number of frequencies | +------+----------+------+-----------------------------+ | 2 | WORD2 | I | Frequency set record number | +------+----------+------+-----------------------------+ | 3 | WORD3 | I | Number of loads | +------+----------+------+-----------------------------+ | 4 | UNDEF(3) | None | Not used | +------+----------+------+-----------------------------+ """ op2 = self.op2 #op2.log.debug("table_name = %r" % op2.table_name) op2.table_name = self._read_table_name(rewind=False) self.read_markers([-1]) data = self._read_record() self.read_3_markers([-2, 1, 0]) data = self._read_record() ndata = len(data) subtable_name_raw, = op2.struct_8s.unpack(data[:8]) subtable_name = subtable_name_raw.strip() assert subtable_name == b'FOL', 'subtable_name=%r' % subtable_name nfloats = (ndata - 8) // 4 assert nfloats * 4 == (ndata - 8) fmt = self._endian + b'%if' % nfloats freqs = np.array(list(unpack(fmt, data[8:])), dtype='float32') if self.read_mode == 2: if op2._frequencies is not None and not np.array_equal(freqs, op2._frequencies): msg = ( 'Cannot overwrite op2._frequencies...\n' 'op2._frequencies = %s\n' 'new_freqs = %s\n' % (op2._frequencies, freqs)) raise RuntimeError(msg) op2._frequencies = freqs if self.is_debug_file: self.binary_debug.write(' recordi = [%r, freqs]\n' % (subtable_name_raw)) self.binary_debug.write(f' subtable_name={subtable_name!r}\n') self.binary_debug.write(' freqs = %s' % freqs) self._read_subtables()
[docs] def read_frl(self): """ reads the FRL (Frequency Response List) table tested by TestOP2.test_op2_good_sine_01 """ op2 = self.op2 op2.table_name = self._read_table_name(rewind=False) self.read_markers([-1]) data = self._read_record() fmt1 = mapfmt(self._endian + b'7i', self.size) idata = unpack(fmt1, data) assert idata[0] == 101, f'idata[0]={idata[0]}; idata={idata}' assert idata[1] in [1, 2, 3, 4], f'idata[1]={idata[1]}; idata={idata}' assert idata[2] == 0, f'idata[2]={idata[2]}; idata={idata}' assert idata[3] == 0, f'idata[3]={idata[3]}; idata={idata}' assert idata[4] == 0, f'idata[4]={idata[4]}; idata={idata}' assert idata[5] == 0, f'idata[5]={idata[5]}; idata={idata}' assert idata[6] == 0, f'idata[6]={idata[6]}; idata={idata}' #print(self.show_data(data)) self.read_3_markers([-2, 1, 0]) data = self._read_record() if len(data) == 12: subtable_name_raw, = op2.struct_8s.unpack(data[:8]) subtable_name = subtable_name_raw.strip() assert subtable_name in [b'FRL', b'FRL0'], 'subtable_name=%r' % subtable_name elif len(data) == 16: #(FRL, 200, 201) subtable_name_raw, = op2.struct_8s.unpack(data[:8]) subtable_name = subtable_name_raw.strip() assert subtable_name in [b'FRL', b'FRL0'], 'subtable_name=%r' % subtable_name elif len(data) == 20: #(FRL, 70, 71, 72) subtable_name_raw, = op2.struct_8s.unpack(data[:8]) subtable_name = subtable_name_raw.strip() assert subtable_name in [b'FRL', b'FRL0'], 'subtable_name=%r' % subtable_name elif len(data) == 24: #(FRL, 71, 72, 73, 74) subtable_name_raw, = op2.struct_8s.unpack(data[:8]) subtable_name = subtable_name_raw.strip() assert subtable_name in [b'FRL', b'FRL0'], 'subtable_name=%r' % subtable_name else: self.show_data(data, types='ifsd') raise RuntimeError('bad length...') self.read_3_markers([-3, 1, 0]) isubtable = -3 markers = self.get_nmarkers(1, rewind=True) while markers[0] != 0: if self.read_mode == 1: self._skip_record() else: data = self._read_record() #self.show_data(data) freqs = np.frombuffer(data, dtype=op2.fdtype).copy() #print('read_mode=%s itable=%s freqs=%s' % (self.read_mode, isubtable, freqs.tolist())) if isubtable == -3: if op2._frequencies is not None and not np.array_equal(freqs, op2._frequencies): msg = ( 'Cannot overwrite op2._frequencies...\n' 'op2._frequencies = %s\n' 'new_freqs = %s\n' % (op2._frequencies, freqs)) raise RuntimeError(msg) op2._frequencies = freqs else: #C:\MSC.Software\simcenter_nastran_2019.2\tpl_post2\rtr_mfreq41kf.op2 if op2._frequencies is not None and not np.array_equal(freqs, op2._frequencies): msg = ( 'Cannot overwrite op2._frequencies...\n' 'op2._frequencies = %s\n' 'new_freqs = %s\n' % (op2._frequencies, freqs)) self.log.warning(msg) isubtable -= 1 self.read_markers([isubtable, 1, 0]) markers = self.get_nmarkers(1, rewind=True) del isubtable self.read_markers([0])
[docs] def read_gpl(self): """ reads the GPL table (grid point list?) tested by TestOP2.test_beam_modes """ if self.read_mode == 1: read_record = self._skip_record else: read_record = self._read_record op2 = self.op2 op2.table_name = self._read_table_name(rewind=False) #self.log.debug('table_name = %r' % op2.table_name) if self.is_debug_file: self.binary_debug.write('read_geom_table - %s\n' % op2.table_name) self.read_markers([-1]) header_data = self._read_record() # (102, 117, 0, 0, 0, 0, 0) ints = np.frombuffer(header_data, op2.idtype) #seid = ints[0] # ??? nnodes = ints[1] if self.is_debug_file: self.binary_debug.write('---markers = [-1]---\n') #self.show_data(unused_data) #print('--------------------') self.read_3_markers([-2, 1, 0]) self.read_table_name(['GPL', 'GPLOUT']) #else ndata == 12: # TestOP2Matrix.test_gpspc #print('--------------------') self.read_3_markers([-3, 1, 0]) unused_data = read_record() # nids 1-117 self.read_3_markers([-4, 1, 0]) data = read_record() if self.read_mode == 2 and self.size == 4: # nids 1-117 (column 1) with nid*1000 (column 2) # # External grid or scalar identification number = node_id # Sequence number = 1000 * external identification number unused_nid_seq = np.frombuffer(data, op2.idtype).reshape(nnodes, 2) self.read_markers([-5, 1, 0, 0])
[docs] def read_gpls(self): op2 = self.op2 op2.table_name = self._read_table_name(rewind=False) self.log.debug('table_name = %r' % op2.table_name) if self.is_debug_file: self.binary_debug.write('read_geom_table - %s\n' % op2.table_name) self.read_markers([-1]) data = self._read_record() # (101, 139, 0, 0, 0, 0, 0) self.read_3_markers([-2, 1, 0]) data = self._read_record() if self.size == 4: gpl_gpls, method = Struct(self._endian + b'8si').unpack(data) else: gpl_gpls, method = Struct(self._endian + b'16sq').unpack(data) assert gpl_gpls.strip() in [b'GPL', b'GPLS'], gpl_gpls.strip() assert method in [0, 1, 2, 3, 4, 5, 6, 7, 10, 12, 13, 15, 20, 30, 40, 99, 101, 201], f'GPLS method={method}' self.read_3_markers([-3, 1, 0]) data = self._read_record() ints = np.frombuffer(data, op2.idtype) #print(ints) self.read_3_markers([-4, 1, 0]) data = self._read_record() ints = np.frombuffer(data, op2.idtype) nints = len(ints) ints = ints.reshape(nints//2, 2) #print(ints) self.read_markers([-5, 1, 0, 0])
#data = self._read_record() #self.show_data(data, types='ifs', endian=None)
[docs] def read_table_name(self, table_names: List[bytes]) -> str: if self.size == 4: return self.read_table_name4(table_names) return self.read_table_name8(table_names)
[docs] def read_table_name4(self, table_names: List[bytes]) -> str: assert isinstance(table_names, list), table_names data, ndata = self._read_record_ndata4() # GPL if ndata == 8: table_name_bytes, = self.op2.struct_8s.unpack(data) elif ndata == 12: table_name_bytes, zero = self.op2.struct_8s_i.unpack(data) assert zero == 0, self.show_data(data) else: self.show_data(data) raise SubTableReadError('cannot read table_name=%r' % table_names) table_name_str = table_name_bytes.decode('utf-8').strip() assert table_name_str in table_names, f'actual={table_name_str} allowed={table_names}' return table_name_str
[docs] def read_table_name8(self, table_names: List[bytes]) -> str: assert isinstance(table_names, list), table_names data, ndata = self._read_record_ndata8() # GPL if ndata == 16: table_name_bytes, = self.op2.struct_16s.unpack(data) elif ndata == 24: table_name_bytes, zero = self.op2.struct_16s_q.unpack(data) assert zero == 0, self.show_data(data) else: print(ndata) self.show_data(data, types='ifsq') #self.show_data(data[16:], types='ifsq') raise SubTableReadError(f'cannot read table_name={table_names}') table_name_bytes = reshape_bytes_block(table_name_bytes) table_name_str = table_name_bytes.decode('utf-8').strip() assert table_name_str in table_names, f'actual={table_name_str} allowed={table_names}' return table_name_str
[docs] def read_gpdt(self): """ reads the GPDT table tested by ??? """ #if self.read_mode == 1: #read_record = self._skip_record #else: read_record = self._read_record skip_record = self._skip_record op2 = self.op2 table_name = self._read_table_name(rewind=False) op2.table_name = table_name #self.log.debug('table_name = %r' % table_name) if self.is_debug_file: self.binary_debug.write('read_gpdt - %s\n' % table_name) self.read_markers([-1]) header_data = self._read_record() # (103, 117, 0, 0, 0, 0, 0) ints = np.frombuffer(header_data, op2.idtype8) #seid = ints[0] # ??? is this a table number> unused_nnodes = ints[1] if self.is_debug_file: self.binary_debug.write('---markers = [-1]---\n') #print('--------------------') self.read_3_markers([-2, 1, 0]) self.read_table_name(['GPDT', 'GPDTS', 'SAGPDT']) #print('--------------------') self.read_3_markers([-3, 1, 0]) ## TODO: no idea how this works... if self.read_mode == 1: data = read_record() # nid,cp,x,y,z,cd,ps xword = 4 * self.factor nvalues = len(data) // xword if nvalues % 7 == 0: # mixed ints, floats # 0 1 2 3 4 5 6 # id, cp, x1, x2, x3, cd, ps nrows = get_table_size_from_ncolumns('GPDT', nvalues, 7) ints = np.frombuffer(data, op2.idtype8).reshape(nrows, 7).copy() floats = np.frombuffer(data, op2.fdtype8).reshape(nrows, 7).copy() iints = [0, 1, 5, 6] # [1, 2, 6, 7] - 1 nid_cp_cd_ps = ints[:, iints] xyz = floats[:, 2:5] elif nvalues % 10 == 0: # mixed ints, doubles nrows = get_table_size_from_ncolumns('GPDT', nvalues, 10) iints = [0, 1, 8, 9] #ifloats = [2, 3, 4, 5, 6, 7] idoubles = [1, 2, 3] unused_izero = [1, 8, 9] #print('ints:') #print(ints) # nid cp, x, y, z, cd, ps # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] # [ , , 1, 1, 2, 2, 3, 3, , ] if self.read_mode == 1: ints = np.frombuffer(data, op2.idtype).reshape(nrows, 10).copy() #floats = np.frombuffer(data, op2.fdtype).reshape(nrows, 10).copy() doubles = np.frombuffer(data, 'float64').reshape(nrows, 5).copy() nid_cp_cd_ps = ints[:, iints] xyz = doubles[:, idoubles] else: raise NotImplementedError(nvalues) self.op2.op2_results.gpdt = GPDT(nid_cp_cd_ps, xyz) else: unused_data = skip_record() # nid,cp,x,y,z,cd,ps # 1. Scalar points are identified by CP=-1 and words X1 through # PS are zero. # 3. or fluid grid points, CD=-1. #print(nid_cp_cd_ps) #print(xyz) isubtable = -4 markers = self.get_nmarkers(1, rewind=True) if markers[0] != isubtable: self.read_markers([markers[0], 1, 0, 0]) self.show(200) self.log.error('unexpected GPDT marker marker=%s; expected=%s' % ( markers[0], isubtable)) #markers = self.get_nmarkers(1, rewind=False) return self.read_3_markers([isubtable, 1, 0]) markers = self.get_nmarkers(1, rewind=True) while markers[0] != 0: #markers = self.get_nmarkers(1, rewind=True) #self.log.debug('GPDT record; markers=%s' % str(markers)) if self.read_mode == 1: self._skip_record() else: #self.log.debug('unexpected GPDT record; markers=%s' % str(markers)) data = self._read_record() #print('read_mode=%s freqs=%s' % (self.read_mode, freqs.tolist())) markers = self.get_nmarkers(1, rewind=True) self.read_3_markers([isubtable, 1, 0]) markers = self.get_nmarkers(1, rewind=True) isubtable -= 1 del isubtable self.read_markers([0])
[docs] def read_bgpdt(self): """ reads the BGPDT, BGPDTS, BGPDTOLD tables tested by TestOP2Matrix.test_gpspc """ #if self.read_mode == 1: #read_record = self._skip_record #else: read_record = self._read_record op2 = self.op2 table_name = self._read_table_name(rewind=False) op2.table_name = table_name #self.log.debug('table_name = %r' % table_name) if self.is_debug_file: self.binary_debug.write('read_bgpdt - %s\n' % table_name) self.read_markers([-1]) header_data = self._read_record() # (105, 51, 0, 0, 0, 0, 0) ints = np.frombuffer(header_data, op2.idtype8) #seid = ints[0] # ??? is this a table number> unused_nnodes = ints[1] # validated if self.is_debug_file: self.binary_debug.write('---markers = [-1]---\n') #print('--------------------') self.read_3_markers([-2, 1, 0]) self.read_table_name(['BGPDT', 'BGPDTS', 'BGPDTOLD', 'BGPDTOUT']) #print('--------------------') self.read_3_markers([-3, 1, 0]) #C:\MSC.Software\simcenter_nastran_2019.2\tpl_post2\s402_sphere_03.op2 #GRID 1 0 0.0 0.0 0.0 0 #GRID 2 0 0.0 0.0 0.0 0 #GRID 3 0 0.0871 0.0 -0.99619 0 #D = (0.0, 5e-324, # 5e-324, 3e-322, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 3.5e-323, # 1e-323, 3e-322, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 6.4e-323, # 1.5e-323, 3e-322, 0.0, 0.0, 0.0871, 0.0, -0.99619) #L = (0, 1, # 1, 61, 0, 0, 0, 0, 0, 0, 7, # 2, 61, 0, 0, 0, 0, 0, 0, 13, # 3, 61, 0, 0, 0.0871, 0, -0.99619) #C:\MSC.Software\simcenter_nastran_2019.2\tpl_post2\s402_flxslddriver_05.op2 #doubles (float64) = (0.0, 5e-324, 5e-324, 3e-322, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 3.5e-323, 1e-323, 3e-322, 0.0, 0.0, 10.0, 0.0, 0.0, 0.0, 6.4e-323, 1.5e-323, 3e-322, 0.0, 0.0, 20.0, 0.0, 0.0, 0.0, 9.4e-323, 2e-323, 3e-322, 0.0, 0.0, 30.0, 0.0, 0.0, 0.0, 1.24e-322, 2.5e-323, 3e-322, 0.0, 0.0, 40.0, 0.0, 0.0, 0.0, 1.53e-322, 3e-323, 3e-322, 0.0, 0.0, 50.0, 0.0, 0.0, 0.0, 1.83e-322, 3.5e-323, 3e-322, 0.0, 0.0, 60.0, 0.0, 0.0, 0.0, 2.1e-322, 4e-323, 3e-322, 0.0, 0.0, 70.0, 0.0, 0.0, 0.0, 2.4e-322, 4.4e-323, 3e-322, 0.0, 0.0, 80.0, 0.0, 0.0, 0.0, 2.7e-322, 5e-323, 3e-322, 0.0, 0.0, 90.0, 0.0, 0.0, 0.0, 3e-322, 5.4e-323, 3e-322, 0.0, 0.0, 100.0, 0.0, 0.0, 0.0, 3.3e-322, 6e-323, 3e-322, 0.0, 0.0, 5.0, 0.0, 20.0, 0.0, 3.6e-322, 6.4e-323, 3e-322, 0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 3.9e-322, 7e-323, 3e-322, 0.0, 0.0, 10.0, 0.0, 0.0) #long long (int64) = ( #0, 1, #1, 61, 0, 0, 0, 0, 0, 0, 7, #2, 61, 0, 0, 4621819117588971520, 0, 0, 0, 13, #3, 61, 0, 0, 4626322717216342016, 0, 0, 0, 19, #4, 61, 0, 0, 4629137466983448576, 0, 0, 0, 25, #5, 61, 0, 0, 4630826316843712512, 0, 0, 0, 31, #6, 61, 0, 0, 4632233691727265792, 0, 0, 0, 37, #7, 61, 0, 0, 4633641066610819072, 0, 0, 0, 43, #8, 61, 0, 0, 4634626229029306368, 0, 0, 0, 49, #9, 61, 0, 0, 4635329916471083008, 0, 0, 0, 55, #10, 61, 0, 0, 4636033603912859648, 0, 0, 0, 61, #11, 61, 0, 0, 4636737291354636288, 0, 0, 0, 67, #12, 61, 0, 0, 4617315517961601024, 0, 4626322717216342016, 0, 73, #13, 61, 0, 0, 4617315517961601024, 0, 0, 0, 79, #14, 61, 0, 0, 4621819117588971520, 0, 0) if self.read_mode == 1: self._skip_record() elif self.read_mode == 2: data = read_record() # cd,x,y,z xword = 4 * self.factor nvalues = len(data) // xword if self.size == 4: nrows = get_table_size_from_ncolumns('BGPDT', nvalues, 4) ints = np.frombuffer(data, op2.idtype8).reshape(nrows, 4).copy() floats = np.frombuffer(data, op2.fdtype8).reshape(nrows, 4).copy() cd = ints[:, 0] xyz = floats[:, 1:] op2.op2_results.bgpdt = BGPDT(cd, xyz) else: #bad = [] #nvalues = len(data) // 4 #for i in [2, 3, 6]: # 2-16 checked #if nvalues % i != 0: #bad.append(i) #if bad: #print(nvalues, bad) #asdf #self.show_data(data, types='ifqd') nrows = (nvalues - 2) // 7 #print(nrows) ints = np.frombuffer(data, op2.idtype8).copy() floats = np.frombuffer(data, op2.fdtype8).copy() #print(ints) #print(floats) #print(nrows*7, len(floats)) #ints = ints[2:].reshape(nrows, 7) #floats = floats[2:].reshape(nrows, 7) #for inti, floati in zip(ints, floats): #print(inti[:-3], floats[-3:]) #print('cd = %s' % cd.tolist()) #print('xyz:\n%s' % xyz) self.read_3_markers([-4, 1, 0]) marker = self.get_nmarkers(1, rewind=True)[0] if marker == 0: self.read_markers([0]) return ## TODO: why is this needed??? (it is, but dmap is not clear) data = self._read_record() #self.show_data(data, types='i') isubtable = -5 while 1: self.read_3_markers([isubtable, 1, 0]) marker = self.get_nmarkers(1, rewind=True)[0] if marker == 0: break data = self._read_record() isubtable -= 1 self.read_markers([0])
[docs] def read_hisadd(self): """optimization history (SOL200) table""" op2 = self.op2 result_name = 'responses.convergence_data' is_saved_result = op2._results.is_saved(result_name) #read_mode = self.read_mode if is_saved_result: op2._results._found_result(result_name) else: self._skip_table('HISADD', warn=False) return is_not_saved_result = not is_saved_result #slot = op2.get_result(result_name) responses = op2.op2_results.responses op2.table_name = self._read_table_name(rewind=False) if self.read_mode == 1 or is_not_saved_result: self.read_markers([-1]) self._skip_record() self.read_3_markers([-2, 1, 0]) self._skip_record() self.read_3_markers([-3, 1, 0]) if is_saved_result and responses.convergence_data is None: data = self._read_record() ndvs = len(data) // 4 - 7 responses.convergence_data = Convergence(ndvs) #elif is_not_saved_result: #self._skip_record() else: self._skip_record() responses.convergence_data.n += 1 self.read_markers([-4, 1, 0, 0]) return if self.is_debug_file: self.binary_debug.write('_read_geom_table - %s\n' % op2.table_name) #self.log.info('----marker1----') self.read_markers([-1]) if self.is_debug_file: self.binary_debug.write('---markers = [-1]---\n') data = self._read_record() # ()102, 303, 0, 0, 0, 0, 0) date??? #print('hisadd data1') #self.show_data(data) #self.log.info('----marker2----') markers = self.get_nmarkers(1, rewind=True) if self.is_debug_file: self.binary_debug.write('---marker0 = %s---\n' % markers) self.read_3_markers([-2, 1, 0]) data = self._read_record() # ('HISADD', ) #print('hisadd data2') #self.show_data(data) #self.log.info('----marker3----') self.read_3_markers([-3, 1, 0]) data = self._read_record() fmt = mapfmt(self._endian + b'3i3fi', self.size) (design_iter, iconvergence, conv_result, obj_intial, obj_final, constraint_max, row_constraint_max) = unpack(fmt, data[:28 * self.factor]) if iconvergence == 1: iconvergence = 'soft' elif iconvergence == 2: iconvergence = 'hard' elif iconvergence == 6: self.log.warning('HISADD iconverge=6') iconvergence = '???' else: # pragma: no cover msg = 'iconvergence=%s\n' % iconvergence self.show_data(data, types='ifs', endian=None) raise NotImplementedError(msg) if conv_result == 0: conv_result = 'no' elif conv_result == 1: conv_result = 'soft' elif conv_result == 2: conv_result = 'hard' elif conv_result in [3, 4]: #self.log.warning('HISADD conv_result=%s' % conv_result) # not sure why this happens, but the field is wrong # it seems to apply to one step before this one conv_result = 'best_design' else: self.log.debug('design_iter=%s iconvergence=%s conv_result=%s obj_intial=%s ' 'obj_final=%s constraint_max=%s row_constraint_max=%s' % ( design_iter, iconvergence, conv_result, obj_intial, obj_final, constraint_max, row_constraint_max)) raise NotImplementedError('conv_result=%s' % conv_result) #self.log.debug('design_iter=%s iconvergence=%s conv_result=%s obj_intial=%s ' #'obj_final=%s constraint_max=%s row_constraint_max=%s' % ( #design_iter, iconvergence, conv_result, obj_intial, #obj_final, constraint_max, row_constraint_max)) ndvs = len(data) // 4 - 7 desvar_values = unpack('%sf' % ndvs, data[28:]) responses.convergence_data.append( design_iter, iconvergence, conv_result, obj_intial, obj_final, constraint_max, row_constraint_max, desvar_values) self.read_markers([-4, 1, 0, 0])
[docs] def read_ibulk(self): """ tested by TestOP2.test_ibulk read_mode = 1 (array sizing) read_mode = 1 (reading) """ op2 = self.op2 op2.table_name = self._read_table_name(rewind=False) #op2.log.debug('table_name = %r' % op2.table_name) if self.is_debug_file: self.binary_debug.write('read_geom_table - %s\n' % op2.table_name) self.read_markers([-1]) if self.is_debug_file: self.binary_debug.write('---markers = [-1]---\n') unused_data = self._read_record() #print(self.show_data(data)) unused_markers = self.get_nmarkers(1, rewind=True) if self._dump_deck: write_deck = True bulk_filename = 'bulk.test_op2.bdf' save_lines = False self._read_deck_section(bulk_filename, save_lines, write_deck, mode='w', read_mode=1) else: save_lines = False write_deck = False bulk_filename = 'bulk.test_op2.bdf' self._read_deck_section(bulk_filename, save_lines, write_deck, mode='a', read_mode=2)
def _read_deck_section(self, deck_filename: str, save_lines: bool, write_deck: bool, mode='w', read_mode: int=1) -> List[str]: """helper for ``read_ibulk`` and ``read_icase``""" marker = -2 if save_lines and write_deck: raise RuntimeError(f'save_lines={save_lines} write_deck={write_deck}; ' 'one or more must be False') lines = [] size = self.size if write_deck and self.read_mode == read_mode: with open(deck_filename, mode) as bdf_file: # pragma: no cover while 1: self.read_3_markers([marker, 1, 0]) nfields = self.get_marker1(rewind=True) if nfields > 0: # we're not reading the record because the IBULK/ICASE # table is literally just an unsorted echo of the # BULK/CASE data table in the BDF data = self._read_record() line = reshape_bytes_block_size(data.replace(b'\xff', b' '), size=size) bdf_file.write(line + '\n') elif nfields == 0: #op2.show_ndata(100, types='ifs') break else: raise RuntimeError('nfields=%s' % nfields) marker -= 1 elif save_lines and self.read_mode == read_mode: while 1: self.read_3_markers([marker, 1, 0]) nfields = self.get_marker1(rewind=True) if nfields > 0: # we're not reading the record because the IBULK # table is literally just an unsorted echo of the # BULK data table in the BDF data = self._read_record() line = reshape_bytes_block_size(data.replace(b'\xff', b' '), size=size) lines.append(line + '\n') elif nfields == 0: #op2.show_ndata(100, types='ifs') break else: raise RuntimeError('nfields=%s' % nfields) marker -= 1 else: while 1: self.read_3_markers([marker, 1, 0]) nfields = self.get_marker1(rewind=True) if nfields > 0: # we're not reading the record because the IBULK # table is literally just an unsorted echo of the # BULK data table in the BDF unused_data = self._skip_record() elif nfields == 0: #op2.show_ndata(100, types='ifs') break else: raise RuntimeError('nfields=%s' % nfields) marker -= 1 #print("marker = ", marker) unused_marker_end = self.get_marker1(rewind=False) return lines
[docs] def read_icase(self): """ tested by ??? read_mode = 1 (array sizing) read_mode = 1 (reading) """ op2 = self.op2 op2.table_name = self._read_table_name(rewind=False) if self.is_debug_file: self.binary_debug.write('read_geom_table - %s\n' % op2.table_name) self.read_markers([-1]) if self.is_debug_file: self.binary_debug.write('---markers = [-1]---\n') unused_data = self._read_record() unused_markers = self.get_nmarkers(1, rewind=True) save_lines = True write_deck = False bulk_filename = 'bulk.test_op2.bdf' lines = self._read_deck_section(bulk_filename, save_lines, write_deck=write_deck, mode='w', read_mode=1) if self._dump_deck: with open(bulk_filename, 'a') as bdf_file: bdf_file.writelines(lines) self._case_control_lines = lines
[docs] def read_cddata(self): """Cambell diagram summary""" op2 = self.op2 op2.table_name = self._read_table_name(rewind=False) self.read_markers([-1]) data = self._read_record() #(101, 15, 5, 7, 0, 2, 0) #(101, 118, 4, 7, 0, 2, 0) # CDDATA, 2 self.read_3_markers([-2, 1, 0]) data = self._read_record() cddata, method = Struct(self._endian + b'8si').unpack(data) marker = -3 cddata_list = [] if method == 1: while 1: #print(f'read marker={marker}...') self.read_3_markers([marker, 1, 0]) nfields = self.get_marker1(rewind=True) if nfields == 0: break #print(nfields) data, ndata = self._read_record_ndata4() if self.read_mode == 1: marker -= 1 continue #self.show_data(data, types='if', endian=None) marker -= 1 #self.show(200) elif method == 2: while 1: self.read_3_markers([marker, 1, 0]) nfields = self.get_marker1(rewind=True) if nfields == 0: break data = self._read_record() if self.read_mode == 1: marker -= 1 continue ints = np.frombuffer(data, op2.idtype) nints = len(ints) floats = np.frombuffer(data, op2.fdtype) # .reshape(nints//7, 7) # 1 NVAL I Number of values # 2 NCRV I Number of sections/solution (i.e., number of curves) # 3 KEYW I Keyword=10000+(SOLN*10)+DATTYP, # where: # SOLN=solution number # DATTYP=1 for list of rotor speeds in user-defined units # DATTYP=2 for list of eigenfrequencies in the analysis system # DATTYP=3 for list of Lehr damping values # DATTYP=4 for list of real part of eigenvalues # DATTYP=5 for list of imaginary part of eigenvalues # DATTYP=6 for list of whirl direction codes (2.0=backwards, 3.0=forward, 4.0=linear) # DATTYP=7 for list of converted frequencies in analysis system # DATTYP=8 for list of whirl directions codes for converted solution (2.0=backwards, 3.0=forward, 4.0=linear) # 4 VALS(NVAL) RS List of values # Words 1–4 repeat for NCRV curves. For DATTYP≠1, NVAL and NCRV=0 dict_map = { 1: 'RPM', 2: 'eigenfreq', 3: 'Lehr', 4: 'real eig', 5: 'imag eig', 6: 'whirl_dir', 7: 'converted_freq', 8: 'whirl_code', } i = 0 data_out = {} while i < nints: nvalues = ints[i] #ncurves = ints[i+1] keyword = ints[i+2] # 10000+(SOLN*10)+DATTYP base = keyword - 10000 # (SOLN*10)+DATTYP #solution = base // 10 datatype = base % 10 assert datatype in [1, 2, 3, 4, 5, 6, 7, 8], datatype values = floats[i+3:i+3+nvalues] if datatype in [6, 8]: values = values.astype('int32') #print(f'{nvalues}, {ncurves}, {solution}, {datatype}, {dict_map[datatype]:14s} {values}') data_out[datatype] = values i += 3 + nvalues marker -= 1 cddata_list.append(data_out) #import matplotlib.pyplot as plt #dict_map = { #1: 'RPM', #2: 'eigenfreq', #3: 'Lehr', #4: 'real eig', #5: 'imag eig', #6: 'whirl_dir', #7: 'converted_freq', #8: 'whirl_code', #} #plt.figure(2) #plt.plot(data_out[1], data_out[2]) # RPM vs. eigenfreq #plt.grid(True) #plt.figure(3) #plt.plot(data_out[1], data_out[3]) # RPM vs. Lehr #plt.grid(True) #plt.figure(4) #plt.plot(data_out[1], data_out[4]) # RPM vs. real_eig #plt.grid(True) #plt.figure(5) #plt.plot(data_out[1], data_out[5]) # RPM vs. imag_eig #plt.grid(True) #plt.figure(7) #plt.plot(data_out[1], data_out[7]) # RPM vs. converted_freq #plt.grid(True) #print('------------------------------------') else: raise NotImplementedError(f'CDDATA method={method}') if self.read_mode == 2: #plt.grid(True) #plt.show() self.op2.op2_results.cddata = cddata_list nfields = self.get_marker1(rewind=False)
[docs] def read_stdisp(self): """reads the STDISP table""" #C:\NASA\m4\formats\git\examples\backup\aeroelasticity\loadf.op2 op2 = self.op2 op2.table_name = self._read_table_name(rewind=False) self.read_markers([-1]) #(101, 1, 27, 0, 3, 1, 0) data = self._read_record() #self.show_data(data, types='ifs', endian=None) self.read_3_markers([-2, 1, 0]) data = self._read_record() assert Struct('8s').unpack(data)[0] == b'STDISP ' self.read_3_markers([-3, 1, 0]) data = self._read_record() a, b1, b2, b3, b4, b5, b6, b7, b8, b9 = Struct('64s 5i 12s 3i').unpack(data) #a 345 0 0 0 0 b'DISPSTWING ' 1 0 123 out = (b1, b2, b3, b4, b5, b6, b7, b8, b9) assert b1 == 345, out assert b2 == 0, out assert b3 == 0, out assert b4 == 0, out assert b5 == 0, out assert b6 == b'DISPSTWING ', out assert b7 == 1, out assert b8 == 0, out assert b9 == 123, out #print(a, b1, b2, b3, b4, b5, b6, b7, b8, b9) #'STWING COMPLETE STRUCTURAL WING ' #(345, 0, 0, 0, 0, 1347635524, 1230459987, 538986318, 1, 0, 123) #(4.834479701920619e-43, 0.0, 0.0, 0.0, 0.0, 14179176448.0, 881989.1875, 1.35761196e-19, 1.4012e-45, 0.0, 1.72359) #self.show_data(data[96:], types='ifs', endian=None) self.read_3_markers([-4, 1, 0]) self.read_markers([0])
[docs] def read_omm2(self): """reads the OMM2 table""" op2 = self.op2 #op2.log.debug("table_name = %r" % op2.table_name) op2.table_name = self._read_table_name(rewind=False) self.read_markers([-1]) data = self._read_record() self.read_3_markers([-2, 1, 0]) data = self._read_record() if len(data) == 28: subtable_name, month, day, year, zero, one = unpack(self._endian + b'8s5i', data) if self.is_debug_file: self.binary_debug.write(' recordi = [%r, %i, %i, %i, %i, %i]\n' % ( subtable_name, month, day, year, zero, one)) self.binary_debug.write(' subtable_name=%r\n' % subtable_name) self._print_month(month, day, year, zero, one) else: raise NotImplementedError(self.show_data(data)) self._read_subtables()
def _read_pcompts(self): """ Reads the PCOMPTS table (poorly). The PCOMPTS table stores information about the PCOMP cards??? """ self._skip_pcompts() return #if self.read_mode == 1: #return #op2.log.debug("table_name = %r" % op2.table_name) #table_name = self._read_table_name(rewind=False) #self.read_markers([-1]) #data = self._read_record() #self.read_3_markers([-2, 1, 0]) #data = self._read_record() #table_name, = op2.struct_8s.unpack(data) ##print "table_name = %r" % table_name #self.read_3_markers([-3, 1, 0]) #markers = self.get_nmarkers(1, rewind=True) #if markers != [-4]: #data = self._read_record() #self.read_3_markers([-4, 1, 0]) #markers = self.get_nmarkers(1, rewind=True) #if markers != [0]: #data = self._read_record() #else: #self.read_markers([0]) #return #self.read_3_markers([-5, 1, 0]) #data = self._read_record() #self.read_3_markers([-6, 1, 0]) #self.read_markers([0]) def _skip_pcompts(self): """ Reads the PCOMPTS table (poorly). The PCOMPTS table stores information about the PCOMP cards??? """ op2 = self.op2 op2.log.debug("table_name = %r" % op2.table_name) table_name = self._read_table_name(rewind=False) #read_record = self._skip_record if self.read_mode == 2 else self._read_record self.read_markers([-1]) # (104, 0, 1, 3, 0, 0, 0) - tpl\qrcomp.op2 PCOMPTS (length 3?) # (104, 8, 0, 0, 0, 0, 0) - tpl\lmtas1.op2 PCOMPTS (return after -4) # (104, 0, 103, 412, 0, 0, 103) - output.op2 PCOMPT (return at end) data_header = self._read_record() #self.show_data(data_header, types='ifsd', endian=None) a, bi, n4a, n5, e, f, n4b = Struct(b'<7i').unpack(data_header) self.log.debug('a=%s b=%s n4a=%s n5=%s e=%s f=%s n4b=%s' % ( a, bi, n4a, n5, e, f, n4b)) #assert n4a == n4b, 'n4a=%s n4b=%s' % (n4a, n4b) if table_name == b'PCOMPT': n4words = n4a * 4 n5words = n5 * 32 elif table_name == b'PCOMPTS': n4words = n4a * 3 n5words = n5 else: # pragma: no cover raise NotImplementedError(table_name) self.read_3_markers([-2, 1, 0]) # 'IPCOMPT ' unused_data = self._read_record() #table_name, = op2.struct_8s.unpack(data) isubtable = -3 self.read_3_markers([isubtable, 1, 0]) markers = self.get_nmarkers(1, rewind=True) if markers != [-4]: unused_data = self._read_record() self.read_3_markers([-4, 1, 0]) markers = self.get_nmarkers(1, rewind=True) if markers != [0]: # n4a=0 #self.show_data(data_header, types='ifsd') # (1, 4, 0, ' ') #(421, 4, 128, ' ') #(814, 4, 256, ' ') data = self._read_record() assert len(data) == n4words*4, 'n4words=%s len(data)=%s n4words*4=%s' % (n4words, len(data), n4words*4) if table_name == b'PCOMPTS': # (11, 3, 0) pass #self.show_data(data, types='ifs', endian=None) elif 0: # pramga: no cover i = 0 j = 0 s1 = Struct(b'< 3i 4s') while i < len(data): datai = data[i:i+16] out = s1.unpack(datai) print(out) i += 16 j += 1 print("j (-4) = %s" % j) assert i == len(data), '-4' else: self.read_markers([0]) assert n4a == 0, n4a return self.read_3_markers([-5, 1, 0]) data = self._read_record() assert len(data) == n5words * 4, 'n5words=%s len(data)=%s n5words*4=%s' % (n5words, len(data), n5words*4) if table_name == b'PCOMPTS': # (101, 102, 103) pass #self.show_data(data, types='ifs', endian=None) elif 0: # pramga: no cover i = 0 j = 0 nbytes = 128 s1 = Struct(b'< 6i fi 96s') while i < len(data): datai = data[i:i+nbytes] a, b, c, d, e, f, g, h, blank = s1.unpack(datai) print('%r %r %r %r %r %r %r %r %r ' % ( a, b, c, d, e, f, g, h, blank.rstrip())) i += nbytes j += 1 print("j (-5) = %s" % j) assert i == len(data), '-5' self.read_3_markers([-6, 1, 0]) self.read_markers([0])
[docs] def read_meff(self): """reads the MEFF table""" op2 = self.op2 op2.table_name = self._read_table_name(rewind=False) op2.log.debug('table_name = %r' % op2.table_name) if self.is_debug_file: self.binary_debug.write('read_geom_table - %s\n' % op2.table_name) self.read_markers([-1]) if self.is_debug_file: self.binary_debug.write('---markers = [-1]---\n') unused_data = self._read_record() markers = self.get_nmarkers(1, rewind=True) if self.is_debug_file: self.binary_debug.write('---marker0 = %s---\n' % markers) self.read_3_markers([-2, 1, 0]) unused_data = self._read_record() for n in [-3, -4, -5, -6, -7, -8]: self.read_3_markers([n, 1, 1]) markers = self.get_nmarkers(1, rewind=False) #print('markers =', markers) nbytes = markers[0]*4 + 12 unused_data = op2.f.read(nbytes) op2.n += nbytes n = -9 self.read_markers([n, 1, 0, 0])
[docs] def read_intmod(self): """ reads the INTMOD table tested by TestNastranGUI.test_femap_rougv1_01 """ op2 = self.op2 op2.table_name = self._read_table_name(rewind=False) #op2.log.debug('table_name = %r' % op2.table_name) if self.is_debug_file: self.binary_debug.write('read_geom_table - %s\n' % op2.table_name) self.read_markers([-1]) if self.is_debug_file: self.binary_debug.write('---markers = [-1]---\n') unused_data = self._read_record() #print('intmod data1') #self.show_data(data) markers = self.get_nmarkers(1, rewind=True) if self.is_debug_file: self.binary_debug.write('---marker0 = %s---\n' % markers) self.read_3_markers([-2, 1, 0]) unused_data = self._read_record() #print('intmod data2') #self.show_data(data) for n in [-3, -4, -5, -6, -7, -8,]: self.read_3_markers([n, 1, 1]) markers = self.get_nmarkers(1, rewind=False) #print('markers =', markers) nbytes = markers[0]*4 + 12 unused_data = op2.f.read(nbytes) #print('intmod data%i' % n) #self.show_data(data) op2.n += nbytes n = -9 self.read_markers([n, 1, 0, 0])
#self.show(50) #raise NotImplementedError(op2.table_name)
[docs] def read_r1tabrg(self): """Reads the R1TABRG design response optimization table""" op2 = self.op2 # TODO: I think this is used to handle optimization op2._count += 1 op2.table_name = self._read_table_name(rewind=False) self.read_markers([-1]) read_record_ndata = self.get_skip_read_record_ndata() # (101, 221355, 0, 0, 0, 0, 0) # (???, nvalues,?, ?, ?, ?, ?) data = self._read_record() values = unpack(mapfmt(self._endian + b'7i', self.size), data) unused_nvalues = values[1] #print(values) #self.show_data(data, types='i', endian=None) #'R1TAB ' self.read_3_markers([-2, 1, 0]) data, ndata = read_record_ndata() assert ndata == 8 * self.factor, ndata itable = -3 while 1: self.read_3_markers([itable, 1, 0]) stop_marker = self.get_marker1(rewind=True) if stop_marker == 0: break data, ndata = read_record_ndata() self._read_r1tabrg(data, ndata) itable -= 1 stop_marker = self.get_marker1(rewind=False)
[docs] def get_skip_read_record_ndata(self): """selects the read_record or skip_record depending on read_mode""" if self.read_mode == 1: read_record_ndata = self._read_record_ndata else: read_record_ndata = self._skip_record_ndata return read_record_ndata
def _read_r1tabrg(self, data: bytes, ndata: int): """ Design Responses: - Weight - Flutter Speed - Stress - Strain - Displacement """ op2 = self.op2 result_name = 'responses' if op2._results.is_not_saved(result_name): return ndata #op2._results._found_result(result_name) responses = op2.op2_results.responses # create the result object if self.read_mode == 1: assert data is not None, data assert len(data) > 12, len(data) if self.size == 4: response_type, = op2.struct_i.unpack(data[8:12]) else: response_type, = op2.struct_q.unpack(data[16:24]) #assert response_type in [1, 6, 10, 84], response_type if response_type == 1: if responses.weight_response is None: responses.weight_response = WeightResponse() else: responses.weight_response.n += 1 elif response_type == 4: #TYPE =4 EIGN or FREQ #8 MODE I Mode number #9 APRX I Approximation code pass elif response_type == 5: #TYPE =5 DISP #8 COMP I Displacement component #9 UNDEF None #10 GRID I Grid identification number if responses.displacement_response is None: responses.displacement_response = DisplacementResponse() else: responses.displacement_response.n += 1 elif response_type == 6: if responses.stress_response is None: responses.stress_response = StressResponse() else: responses.stress_response.n += 1 elif response_type == 7: if responses.strain_response is None: responses.strain_response = StrainResponse() else: responses.strain_response.n += 1 elif response_type == 8: if responses.force_response is None: responses.force_response = ForceResponse() else: responses.force_response.n += 1 elif response_type == 15: # CEIG #8 MODE I Mode number #9 ICODE I 1: Real component or 2: Imaginary component pass elif response_type == 23: if responses.flutter_response is None: responses.fractional_mass_response = FractionalMassResponse() else: responses.fractional_mass_response.n += 1 elif response_type == 84: if responses.flutter_response is None: responses.flutter_response = FlutterResponse() else: responses.flutter_response.n += 1 else: self.log.warning('skipping response_type=%d' % response_type) return ndata #else: # response not added... #pass # fill the result object read_r1tabrg = True if read_r1tabrg: #self.show_data(data, types='ifs', endian=None) fmt = self._endian + b'3i 8s 4i i 5i' if self.size == 4 else b'3q 16s 4q q 5q' out = unpack(fmt, data) # per the R1TAB DMAP page: # all indicies are downshift by 1 # indices above out[3] are off by +2 because of the 2 field response_label internal_id = out[0] dresp_id = out[1] response_type = out[2] response_label = out[3].strip() # -1 for 2 field wide response_label region = out[4] subcase = out[5] type_flag = out[12] # no meaning per MSC DMAP 2005 seid = out[13] response_label = response_label.decode(self._encoding) if response_type == 1: responses.weight_response.add_from_op2(out, self.log) elif response_type == 5: # DISP # out = (1, 101, 5, 'DISP1 ', 101, 1, 3, 0, 1, 0, 0, 0, 0, 0) comp = out[6] nid = out[8] #msg = f'DISP - label={response_label!r} region={region} subcase={subcase} nid={nid}' #print(msg) #print(out[6:]) # (3, 0, 1, 0, 0, 0, 0, 0) # (???, NA, comp, ???, ???, ???, ???, ???) responses.displacement_response.append( internal_id, dresp_id, response_label, region, subcase, type_flag, seid, nid, comp) elif response_type == 6: # STRESS # ----- STRESS RESPONSES ----- # ------------------------------------------------------------------------------------------- # INTERNAL DRESP1 RESPONSE ELEMENT VIEW COMPONENT LOWER INPUT OUTPUT UPPER # ID ID LABEL ID ELM ID NO. BOUND VALUE VALUE BOUND # ------------------------------------------------------------------------------------------- # 21 209 S09L 144747 17 N/A 4.85E+04 5.00E+04 5.00E+04 # (21, 209, 6, 'S09L ', 30, 1011, 17, 0, 144747, 0, 0, 0, 0, 0) stress_code = out[6] pid = out[8] #msg = ('STRESS - response_type=%r label=%r region=%s subcase=%s ' #'stress_code=%s pid=%s' % ( #response_type, response_label, region, subcase, #stress_code, pid)) responses.stress_response.append( internal_id, dresp_id, response_label, region, subcase, type_flag, seid, stress_code, pid) elif response_type == 7: # STRAIN strain_code = out[6] pid = out[8] responses.strain_response.append( internal_id, dresp_id, response_label, region, subcase, type_flag, seid, strain_code, pid) elif response_type == 8: # FORCE #print('internal_id=%s dresp_id=%s response_type=%s response_label=%s' #' region=%s subcase=%s type_flag=%s seid=%s' % ( #internal_id, dresp_id, response_type, response_label, #region, subcase, type_flag, seid #)) force_code = out[6] pid = out[8] #msg = 'FORCE - label=%r region=%s subcase=%s force_code=%s pid=%s' % ( #response_label, region, subcase, force_code, pid) #print(msg) #print(out) responses.force_response.append( internal_id, dresp_id, response_label, region, subcase, type_flag, seid, force_code, pid) elif response_type == 10: # CSTRESS stress_code = out[6] #ply = out[7] #pid = out[8] # is this element id? #msg = 'CSTRESS - label=%r region=%s subcase=%s stress_code=%s ply=%s pid=%s' % ( #response_label, region, subcase, stress_code, ply, pid) #print(msg) #elif response_type == 10: # CSTRAIN #pass elif response_type == 23: # fractional mass response #msg = f'??? - label={response_label!r} region={region} subcase={subcase}' #print(msg) #print(out[6:]) responses.fractional_mass_response.append( internal_id, dresp_id, response_label, region, subcase, type_flag, seid) elif response_type == 24: # FRSTRE #8 ICODE I Stress item code #9 UNDEF None #10 ELID I Element identification number #11 FREQ RS Frequency #12 IFLAG I Integrated response flag. See Remark 20 of DRESP1. #Value is -1 to -6, for SUM, AVG, SSQ, pass elif response_type == 28: # RMSACCL #8 COMP I RMS Acceleration component #9 RANDPS I RANDPS entry identification number #10 GRID I Grid identification number #11 DMFREQ RS Dummy frequency for internal use pass elif response_type == 84: # FLUTTER (iii, label, mode, (Ma, V, rho), flutter_id, fff) out = unpack(self._endian + b'iii 8s iii fff i fff', data) mode = out[6] mach = out[7] velocity = out[8] density = out[9] flutter_id = out[10] #msg = ('FLUTTER - _count=%s label=%r region=%s subcase=%s mode=%s ' #'mach=%s velocity=%s density=%s flutter_id=%s' % ( #op2._count, response_label, region, subcase, mode, #mach, velocity, density, flutter_id)) responses.flutter_response.append( internal_id, dresp_id, response_label, region, subcase, type_flag, seid, mode, mach, velocity, density, flutter_id) #print(msg) #self.log.debug(msg) #else: #self.log.debug('R1TABRG response response_type=%s not supported' % response_type) #raise NotImplementedError(response_type) assert len(out) == 14, len(out) #self.response1_table[self._count] = out return ndata
[docs] def read_sdf(self): """reads the SDF table""" op2 = self.op2 op2.log.debug("table_name = %r" % op2.table_name) op2.table_name = self._read_table_name(rewind=False) self.read_markers([-1]) data = self._read_record() self.read_3_markers([-2, 1, 0]) data, ndata = self._read_record_ndata() if ndata == 16: subtable_name, dummy_a, dummy_b = unpack(self._endian + b'8sii', data) if self.is_debug_file: self.binary_debug.write(' recordi = [%r, %i, %i]\n' % ( subtable_name, dummy_a, dummy_b)) self.binary_debug.write(f' subtable_name={subtable_name!r}\n') assert dummy_a == 170, dummy_a assert dummy_b == 170, dummy_b else: strings, ints, floats = self.show_data(data) msg = 'len(data) = %i\n' % ndata msg += 'strings = %r\n' % strings msg += 'ints = %r\n' % str(ints) msg += 'floats = %r' % str(floats) raise NotImplementedError(msg) self.read_3_markers([-3, 1, 1]) unused_markers0 = self.get_nmarkers(1, rewind=False) unused_record = self.read_block() #data = self._read_record() self.read_markers([-4, 1, 0, 0])
#self._read_subtables()
[docs] def read_tol(self): """ This is probably broken for MSC Nastran TOL --- -2 - nitimes? -3 - list of times? """ unused_table_name = self._read_table_name(rewind=False, stop_on_failure=True) self.read_markers([-1]) unused_data = self._read_record() #self.show_data(data) self.read_3_markers([-2, 1, 0]) #op2.show_ndata(440, types='if') unused_data = self._read_record() #print('----') self.read_3_markers([-3, 1, 0]) #op2.show_ndata(440, types='if') #print('----') self.read_markers([0])
#data = self._read_record() #op2.show_ndata(440, types='ifs') #self.show_data(data) def _get_matrix_row_fmt_nterms_nfloats(self, nvalues, tout): """ +------+---------------------------+ | Type | Meaning | +------+---------------------------+ | 1 | Real, single precision | | 2 | Real, double precision | | 3 | Complex, single precision | | 4 | Complex, double precision | +------+---------------------------+ """ if tout == 1: nfloats = nvalues nterms = nvalues fmt = self._endian + b'i %if' % nfloats elif tout == 2: nfloats = nvalues // 2 nterms = nvalues // 2 fmt = self._endian + b'i %id' % nfloats elif tout == 3: nfloats = nvalues nterms = nvalues // 2 fmt = self._endian + b'i %if' % nfloats elif tout == 4: nfloats = nvalues // 2 nterms = nvalues // 4 fmt = self._endian + b'i %id' % nfloats else: raise RuntimeError('tout = %s' % tout) return fmt, nfloats, nterms def _read_matrix_mat(self): """ Reads a matrix in "standard" form. The forms are:: standard: Return a matrix that looks similar to a matrix found in the OP4. Created by: ``ASSIGN output2='model.op2', UNIT=12,UNFORMATTED,DELETE`` ``OUTPUT2 KGG//0/12`` matpool: Return a matrix that looks similar to a DMIG matrix (e.g., it contains the node id and DOF). Created by: ``ASSIGN output2='model.op2', UNIT=12,UNFORMATTED,DELETE`` ``TODO: add the magic keyword...`` ``OUTPUT2 KGG//0/12`` Matrix Trailer: +------+---------------------------------------------------+ | Word | Contents | +======+===================================================+ | 1 | Number of columns in matrix | | 2 | Number of rows in matrix | | 3 | Form of the matrix | | 4 | Type of matrix | | 5 | Largest number of nonzero words among all columns | | 6 | Density of the matrix multiplied by 10000 | | 7 | Size in blocks | | 8 | Maximum string length over all strings | | 9 | Number of strings | | 10 | Average bandwidth | | 11 | Maximum bandwidth | | 12 | Number of null columns | +------+---------------------------------------------------+ +------+--------------------------------+ | Form | Meaning | +======+================================+ | 1 | Square | | 2 | Rectangular | | 3 | Diagonal | | 4 | Lower triangular factor | | 5 | Upper triangular factor | | 6 | Symmetric | | 8 | Identity | | 9 | Pseudo identity | | 10 | Cholesky factor | | 11 | Trapezoidal factor | | 13 | Sparse lower triangular factor | | 15 | Sparse upper triangular factor | +------+--------------------------------+ +------+---------------------------+ | Type | Meaning | +======+===========================+ | 1 | Real, single precision | | 2 | Real, double precision | | 3 | Complex, single precision | | 4 | Complex, double precision | +------+---------------------------+ """ op2 = self.op2 allowed_forms = [1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 13, 15] #self.log.debug('----------------------------------------------------------------') table_name = self._read_table_name(rewind=False, stop_on_failure=True) self.read_markers([-1]) data = self._read_record() # old-bad #matrix_num, form, mrows, ncols, tout, nvalues, g = unpack(self._endian + b'7i', data) fmt1 = mapfmt(self._endian + b'7i', self.size) # good good good good ??? ??? matrix_num, ncols, mrows, form, tout, nvalues, g = unpack(fmt1, data) #print('g =', g) utable_name = table_name.decode('utf-8') m = Matrix(utable_name, form=form) op2.matrices[utable_name] = m # matrix_num is a counter (101, 102, 103, ...) # 101 will be the first matrix 'A' (matrix_num=101), # then we'll read a new matrix 'B' (matrix_num=102), # etc. # # the matrix is Mrows x Ncols # # it has nvalues in it # # tout is the precision of the matrix # 0 - set precision by cell # 1 - real, single precision (float32) # 2 - real, double precision (float64) # 3 - complex, single precision (complex64) # 4 - complex, double precision (complex128) # form (bad name) # 1 - column matrix # 2 - factor matrix # 3 - factor matrix if tout == 1: dtype = 'float32' elif tout == 2: dtype = 'float64' elif tout == 3: dtype = 'complex64' elif tout == 4: dtype = 'complex128' else: dtype = '???' msg = ('unexpected tout for %s: matrix_num=%s form=%s ' 'mrows=%s ncols=%s tout=%s nvalues=%s g=%s' % ( table_name, matrix_num, form, mrows, ncols, tout, nvalues, g)) self.log.warning(msg) raise RuntimeError(msg) #self.log.error('name=%r matrix_num=%s form=%s mrows=%s ' # 'ncols=%s tout=%s nvalues=%s g=%s' % ( # table_name, matrix_num, form, mrows, ncols, tout, nvalues, g)) if form == 1: if ncols != mrows: self.log.warning('unexpected size for %s; form=%s mrows=%s ncols=%s' % ( table_name, form, mrows, ncols)) elif form not in allowed_forms: self.log.error('name=%r matrix_num=%s form=%s mrows=%s ' 'ncols=%s tout=%s nvalues=%s g=%s' % ( table_name, matrix_num, form, mrows, ncols, tout, nvalues, g)) raise RuntimeError('form=%s; allowed=%s' % (form, allowed_forms)) if self.size == 4: self.log.debug('name=%r matrix_num=%s form=%s mrows=%s ncols=%s tout=%s ' 'nvalues=%s g=%s' % ( table_name, matrix_num, form, mrows, ncols, tout, nvalues, g)) else: #if tout == 1: #tout = 2 self.log.info('name=%r matrix_num=%s form=%s mrows=%s ncols=%s tout=%s ' 'nvalues=%s g=%s' % ( table_name, matrix_num, form, mrows, ncols, tout, nvalues, g)) self.read_3_markers([-2, 1, 0]) data = self._read_record() if self.size == 4: if len(data) == 16: unused_name, ai, bi = unpack(self._endian + b'8s 2i', data) assert ai == 170, ai assert bi == 170, bi else: self.log.warning('unexpected matrix length=%s' % len(data)) #self.log.warning(self.show_data(data, types='if')) elif self.size == 8: if len(data) == 32: unused_name, ai, bi = unpack(self._endian + b'16s 2q', data) # name isn't mapped assert ai == 170, ai assert bi == 170, bi else: self.log.warning('unexpected matrix length=%s' % len(data)) #self.log.warning(self.show_data(data, types='ifsqd', endian=None)) else: raise RuntimeError(self.size) itable = -3 unused_j = None niter = 0 niter_max = 100000000 GCi = [] GCj = [] reals = [] jj = 1 while niter < niter_max: #nvalues = self.get_marker1(rewind=True) self.read_markers([itable, 1]) one = self.get_marker1(rewind=False) if one: # if keep going nvalues = self.get_marker1(rewind=True) while nvalues >= 0: nvalues = self.get_marker1(rewind=False) fmt, unused_nfloats, nterms = self._get_matrix_row_fmt_nterms_nfloats( nvalues, tout) GCjj = [jj] * nterms GCj += GCjj #----------- data = self.read_block() if self.size == 8: #self.log.warning('skipping matrix') #self.show_data(data, types='ifqd') fmt = mapfmt(fmt, self.size) #self.log.warning(fmt) #print('***itable=%s nvalues=%s fmt=%r' % (itable, nvalues, fmt)) #continue out = unpack(fmt, data) #print(out) ii = out[0] values = out[1:] #list(range(2, 10)) #[2, 3, 4, 5, 6, 7, 8, 9] GCii = list(range(ii, ii + nterms)) GCi += GCii reals += values nvalues = self.get_marker1(rewind=True) if self.debug_file: self.binary_debug.write(' GCi = %s\n' % GCii) self.binary_debug.write(' GCj = %s\n' % GCjj) self.binary_debug.write(' reals/imags = %s\n' % str(values)) assert len(GCi) == len(GCj), 'nGCi=%s nGCj=%s' % (len(GCi), len(GCj)) if self.size == 4: if tout in [1, 2]: assert len(GCi) == len(reals), 'tout=%s nGCi=%s nreals=%s' % (tout, len(GCi), len(reals)) else: assert len(GCi)*2 == len(reals), 'tout=%s nGCi=%s nreals=%s' % (tout, len(GCi)*2, len(reals)) jj += 1 else: nvalues = self.get_marker1(rewind=False) assert nvalues == 0, nvalues matrix = self._cast_matrix_mat(GCi, GCj, mrows, ncols, reals, tout, dtype) if table_name in DENSE_MATRICES: matrix = matrix.toarray() m.data = matrix if matrix is not None: op2.matrices[table_name.decode('utf-8')] = m #nvalues = self.get_marker1(rewind=True) return itable -= 1 niter += 1 raise RuntimeError('MaxIteration: this should never happen; n=%s' % niter_max) def _cast_matrix_mat(self, GCi, GCj, mrows, ncols, reals, tout, dtype): """helper method for _read_matrix_mat""" op2 = self.op2 #assert max(GCi) <= mrows, 'GCi=%s GCj=%s mrows=%s' % (GCi, GCj, mrows) #assert max(GCj) <= ncols, 'GCi=%s GCj=%s ncols=%s' % (GCi, GCj, ncols) # we subtract 1 to the indicides to account for Fortran GCi = np.array(GCi, dtype='int32') - 1 GCj = np.array(GCj, dtype='int32') - 1 try: if dtype == '???': matrix = None self.log.warning('what is the dtype?') elif tout in [1, 2]: # real real_array = np.array(reals, dtype=dtype) matrix = scipy.sparse.coo_matrix( (real_array, (GCi, GCj)), shape=(mrows, ncols), dtype=dtype) #self.log.info('created %s (real)' % self.table_name) elif tout in [3, 4]: # complex real_array = np.array(reals, dtype=dtype) nvalues_matrix = real_array.shape[0] // 2 real_complex = real_array.reshape((nvalues_matrix, 2)) real_imag = real_complex[:, 0] + real_complex[:, 1]*1j if self.binary_debug: #self.binary_debug.write('reals = %s' % real_complex[:, 0]) #self.binary_debug.write('imags = %s' % real_complex[:, 1]) self.binary_debug.write('real_imag = %s' % real_imag) matrix = scipy.sparse.coo_matrix( (real_imag, (GCi, GCj)), shape=(mrows, ncols), dtype=dtype) #msg = 'created %s (complex)' % self.table_name #self.log.debug(msg) #raise RuntimeError(msg) else: raise RuntimeError('this should never happen') except ValueError: self.log.warning('shape=(%s, %s)' % (mrows, ncols)) self.log.warning('cant make a coo/sparse matrix...trying dense') if dtype == '???': matrix = None self.log.warning('what is the dtype?') else: real_array = np.array(reals, dtype=dtype) self.log.debug('shape=%s mrows=%s ncols=%s' % ( str(real_array.shape), mrows, ncols)) if len(reals) == mrows * ncols: real_array = real_array.reshape(mrows, ncols) self.log.info('created %s' % op2.table_name) else: self.log.warning('cant reshape because invalid sizes : created %s' % op2.table_name) matrix = real_array return matrix def _skip_matrix_mat(self): """ Reads a matrix in "standard" form. Notes ----- see read_matrix_mat """ unused_table_name = self._read_table_name(rewind=False, stop_on_failure=True) self.read_markers([-1]) unused_data = self._skip_record() self.read_3_markers([-2, 1, 0]) unused_data = self._skip_record() itable = -3 niter = 0 niter_max = 100000000 #jj = 1 while niter < niter_max: #nvalues = self.get_marker1(rewind=True) #print('nvalues4a =', nvalues) self.read_markers([itable, 1]) one = self.get_marker1(rewind=False) if one: # if keep going nvalues = self.get_marker1(rewind=True) while nvalues >= 0: nvalues = self.get_marker1(rewind=False) unused_data = self._skip_block() nvalues = self.get_marker1(rewind=True) #jj += 1 else: nvalues = self.get_marker1(rewind=False) assert nvalues == 0, nvalues return itable -= 1 niter += 1 raise RuntimeError('this should never happen; n=%s' % niter_max)
[docs] def read_matrix(self, table_name): """ General method for reading matrices and MATPOOL matrices Note ---- Matrices are read on read_mode = 1 .. todo:: Doesn't support checking matrices vs. MATPOOLs """ read_mode_to_read_matrix = 1 op2 = self.op2 i = op2.f.tell() # if we skip on read_mode=1, we don't get debugging # if we just use read_mode=2, some tests fail # if self.read_mode != read_mode_to_read_matrix and not self.debug_file: try: self._skip_matrix_mat() # doesn't work for matpools except MemoryError: raise except(RuntimeError, AssertionError, ValueError): self._goto(i) self._skip_table(table_name) return try: self._read_matrix_mat() except MemoryError: raise except(RuntimeError, AssertionError, ValueError): # read matpool matrix self._goto(i) try: self._read_matrix_matpool() except(RuntimeError, AssertionError, ValueError): #raise self._goto(i) self._skip_table(op2.table_name)
def _read_matrix_matpool(self): """ Reads a MATPOOL matrix MATPOOL matrices are always sparse +------+-----------------+ | Form | Meaning | +======+=================+ | 1 | Square | | 2 | Rectangular | | 6 | Symmetric | | 9 | Pseudo identity | +------+-----------------+ Record 2 - BNDFL(9614,96,0) Record 3 - DMIAX(214,2,221) Record 4 - DMIG(114,1,120) Record 5 - DMIJ(514,5,578) Record 6 - DMIJI(614,6,579) Record 7 - DMIK(714,7,580) Record 8 - ELIST(314,3,279) Record 9 - MFLUID(414,4,284) Record 10 - RADCAV(2509,25,418) Record 11 - RADSET(8602,86,421) Record 12 - RADLST(2014,20,243) Record 13 - RADMTX(3014,30,244) """ #print('-------------------------------------') op2 = self.op2 table_name = self._read_table_name(rewind=False, stop_on_failure=True) utable_name = table_name.decode('utf-8') #print(utable_name) self.read_markers([-1]) # (104, 32768, 0, 0, 0, 0, 0) data = self._read_record() self.read_3_markers([-2, 1, 0]) # MATPOOL data = self._read_record() if self.size == 8: data = reshape_bytes_block(data) #self.show_data(data) ndata = len(data) if ndata == 8: table_name2, = op2.struct_8s.unpack(data) utable_name2 = table_name2.decode('utf-8').strip() assert utable_name == utable_name2, utable_name2 self.read_markers([-3, 1]) #self.show(100, types='iq') #if utable_name == 'DELTAK': #pass ##self.read_markers([1]) #self.show(200) #else: if self.size == 4: self.read_markers([0]) data = self._read_record() else: self.read_markers([1]) #self.show(340, types='ifqd') data = self._read_record() #self.show(36) #if utable_name == 'DELTAK': #self.show_data(data) #nvalues = len(data) // 4 assert len(data) % 4 == 0, len(data) / 4. header = unpack(self._endian + b'3i 8s 7i', data[:48]) # 48=4*12 assert header[:3] == (114, 1, 120), 'header[:3]=%s header=%s' % (header[:3], header) # ncols_gset is needed for form=9 # list of header values: # 4:5 matrix name # 6 placeholder # 7 matrix shape (1=square, 2 or 9 = rectangular, 6=symmetric) # 8 input type flag (1=single, 2=double, 3=complex single, # 4=complex double) # 9 output type flag (0=precision set by system cell, # 1=single, 2=double, 3=complex single, # 4=complex double) # 10 complex flag (0=real/imaginary, >0=magnitude/phase) # 11 placeholder # 12 number of columns in the G set # (only necessary for matrix shape 9) matrix_name, junk1, matrix_shape, tin, tout, is_phase, junk2, ncols_gset = header[3:] matrix_name = matrix_name.strip() #self.log.debug('matrix_name=%s, junk1=%s, matrix_shape=%s, tin=%s, tout=%s, ' #'is_phase=%s, junk2=%s, ncols_gset=%s' % ( #matrix_name, junk1, matrix_shape, tin, tout, #is_phase, junk2, ncols_gset)) is_complex = False if tin > 2 or tout > 2: is_complex = True assert is_phase == 0, 'is_phase=%s' % is_phase imags = [] if tout == 1: dtype = 'float32' fdtype = op2.fdtype elif tout == 2: dtype = 'float64' fdtype = op2.double_dtype elif tout == 3: dtype = 'complex64' fdtype = op2.fdtype elif tout == 4: dtype = 'complex128' fdtype = op2.double_dtype else: dtype = '???' msg = ('matrix_name=%s, junk1=%s, matrix_shape=%s, tin=%s, tout=%s, ' 'is_phase=%s, junk2=%s, ncols_gset=%s' % ( matrix_name, junk1, matrix_shape, tin, tout, is_phase, junk2, ncols_gset)) self.log.warning(msg) raise RuntimeError(msg) is_symmetric = matrix_shape == 6 #is_phase_flag = is_phase > 0 if tout in [1, 3]: # works for float32, complex64 ints = np.frombuffer(data[48:], dtype=op2.idtype).copy() floats = np.frombuffer(data[48:], dtype=op2.fdtype).copy() temp_ints = ints else: # works for float64, complex128 temp_ints = np.frombuffer(data[48:], dtype=op2.idtype).copy() # find the first index with ()-1,-1) iminus1 = np.where(temp_ints[:-1] == -1)[0] double_minus1 = (iminus1[:-1] + 1 == iminus1[1:])[:-1] # the field after our stop # we'll handle the off by 1 later with arange istop = iminus1[:-2][double_minus1] # 2 fields after is the start position # add on a 0 to the beginning to account for the starting position # istart defines icol istart = np.hstack([0, istop[:-1] + 2]) col_nids_short = temp_ints[istart] col_dofs_short = temp_ints[istart+1] #nj2 = len(istart) ## TODO: why is this wrong??? row_nids = [] row_dofs = [] col_nids = [] col_dofs = [] reals = [] imags = [] for col_nidi, col_dofi, istarti, istopi in zip( col_nids_short, col_dofs_short, istart + 2, istop): ## TODO: preallocate arrays imag = None # The float32/complex64 blocks are really simple # because we can just use the data is from the temp_ints block. # We calculate istart/istop and directly access the float data. # # The float64/complex128 blocks are more complicated. # It's easier to just use istart/istop to calculate datai # case that, and then slice it. # # In all cases, we use istart/istop to calculate row/col nid/dof # because they are always int32. Only the real/imag types change. if dtype == 'float32': irow = np.arange(istarti, istopi-1, step=3, dtype='int32') real = floats[irow + 2] elif dtype == 'complex64': irow = np.arange(istarti, istopi-1, step=4, dtype='int32') real = floats[irow + 2] imag = floats[irow + 3] elif dtype == 'float64': datai = data[48+(istarti*4) : 48+(istopi*4)] irow = np.arange(istarti, istopi-1, step=4, dtype='int32') assert len(datai) % 8 == 0, len(datai) / 8 real = np.frombuffer(datai, dtype=fdtype)[1::2].copy() elif dtype == 'complex128': datai = data[48+(istarti*4) : 48+(istopi*4)] # iword # ----- # 0 1 3 5 <---- iword # 1 1 2 2 <---- nwords # (nid, dof, real, imag) irow = np.arange(istarti, istopi-1, step=6, dtype='int32') assert len(datai) % 8 == 0, len(datai) / 8 floats = np.frombuffer(datai, dtype=fdtype).copy() # ndoubles # -------- # <---0---> 1 2 <----- iword # 1 1 1 <----- nwords # (nid, dof, real, imag) real = floats[1::3] imag = floats[2::3] else: msg = '%s is not supported' % dtype self.log.error(msg) raise RuntimeError(msg) if len(irow) != len(real): msg = 'nrow=%s nreal=%s nimag=%s' % (len(irow), len(real), len(imag)) raise RuntimeError(msg) # the row index; [1, 2, ..., 43] row_nid = temp_ints[irow] # the dof; [0, 0, ..., 0.] row_dof = temp_ints[irow + 1] urow_dof = np.unique(row_dof) for udofi in urow_dof: if udofi not in [0, 1, 2, 3, 4, 5, 6]: msg = 'udofi=%s is invalid; must be in [0, 1, 2, 3, 4, 5, 6]; dofs=%s' % ( udofi, np.asarray(urow_dof, dtype='int32').tolist()) raise ValueError(msg) ni = len(irow) col_nid = np.ones(ni, dtype='int32') * col_nidi col_dof = np.ones(ni, dtype='int32') * col_dofi row_nids.append(row_nid) row_dofs.append(row_dof) col_nids.append(col_nid) col_dofs.append(col_dof) reals.append(real) imags.append(imag) row_nids_array = np.hstack(row_nids) row_dofs_array = np.hstack(row_dofs) col_nids_array = np.hstack(col_nids) col_dofs_array = np.hstack(col_dofs) real_array = np.hstack(reals) if is_complex: complex_array = np.hstack(imags) assert len(real_array) == len(complex_array) real_imag_array = real_array + 1.j * complex_array else: real_imag_array = real_array self._cast_matrix_matpool(utable_name, real_imag_array, col_nids_array, col_dofs_array, row_nids_array, row_dofs_array, matrix_shape, dtype, is_symmetric) def _cast_matrix_matpool(self, table_name, real_imag_array, col_nids_array, col_dofs_array, row_nids_array, row_dofs_array, matrix_shape, dtype, is_symmetric): """helper method for _read_matpool_matrix""" op2 = self.op2 make_matrix_symmetric = op2.apply_symmetry and matrix_shape == 'symmetric' # TODO: this is way slower than it should be # because we didn't preallocate the data and the # grids_comp_array_to_index function needs work grids1 = col_nids_array comps1 = col_dofs_array grids2 = row_nids_array comps2 = row_dofs_array assert len(grids1) == len(comps1), 'ngrids1=%s ncomps1=%s' % (len(grids1), len(comps1)) assert len(grids1) == len(grids2), 'ngrids1=%s ngrids2=%s' % (len(grids1), len(grids2)) assert len(comps1) == len(comps2), 'ncomps1=%s ncomps2=%s' % (len(comps1), len(comps2)) j1, j2, nj1, nj2, nj = grids_comp_array_to_index( grids1, comps1, grids2, comps2, make_matrix_symmetric) assert len(j1) == len(j2), 'nj1=%s nj2=%s' % (len(j1), len(j2)) assert len(grids1) == len(real_imag_array), 'ngrids1=%s nreals=%s' % (len(j1), len(real_imag_array)) # not 100% on these, they might be flipped #ncols = len(np.unique(j1)) #mrows = len(np.unique(j2)) if is_symmetric: mrows = nj ncols = nj #print(' j1 =', j1) #print(' j2 =', j2) else: ncols = nj1 mrows = nj2 try: matrix = scipy.sparse.coo_matrix( (real_imag_array, (j2, j1)), shape=(mrows, ncols), dtype=dtype) except ValueError: msg = 'Passed all the checks; cannot build MATPOOL sparse matrix...\n' spaces = ' ' msg += '%sname=%s dtype=%s nrows=%s ncols=%s nj1=%s nj2=%s nj=%s' % ( spaces, table_name, dtype, mrows, ncols, nj1, nj2, nj) self.log.error(msg) raise # enforce symmetry if necessary if make_matrix_symmetric: # get the upper and lower triangular matrices upper_tri = scipy.sparse.triu(matrix) lower_tri = scipy.sparse.tril(matrix) # extracts a [1, 2, 3, ..., n] off the diagonal of the matrix # and make it a diagonal matrix diagi = scipy.sparse.diags(scipy.sparse.diagional(upper_tri)) # Check to see which triangle is populated. # If they both are, make sure they're equal # or average them and throw a warning lnnz = (lower_tri - diagi).nnz unnz = (upper_tri - diagi).nnz assert isinstance(lnnz, int), type(lnnz) assert isinstance(unnz, int), type(unnz) # both upper and lower triangle are populated if lnnz > 0 and unnz > 0: upper_tri_t = upper_tri.T if lower_tri == upper_tri_t: matrix = upper_tri + upper_tri_t - diagi else: self.log.warning( 'Matrix %r marked as symmetric does not contain ' 'symmetric data. Data will be symmetrized by averaging.' % table_name) matrix = (matrix + matrix.T) / 2. elif lnnz > 0: # lower triangle is populated matrix = lower_tri + lower_tri.T - diagi elif unnz > 0: # upper triangle is populated matrix = upper_tri + upper_tri_t - diagi else: # matrix is diagonal (or null) matrix = diagi data = matrix # matrix is symmetric, but is not stored as symmetric matrix_shape = 'rectangular' m = Matrix(table_name, is_matpool=True, form=matrix_shape) m.data = matrix m.col_nid = col_nids_array m.col_dof = col_dofs_array m.row_nid = row_nids_array m.row_dof = row_dofs_array m.form = matrix_shape op2.matrices[table_name] = m self.log.debug(m) self.read_3_markers([-4, 1, 0]) data = self._read_record() if len(data) == 12: self.read_markers([-5, 1, 0, 0]) return raise RuntimeError('failed on _read_matpool_matrix') #--------------------------------------------------------------------------- def _get_marker_n(self, nmarkers: int) -> List[int]: """ Gets N markers A marker is a flag that is used. It's a series of 3 ints (4, n, 4) where n changes from marker to marker. Parameters ---------- nmarkers : int the number of markers to read Returns ------- markers : List[int, int, int] a list of nmarker integers """ op2 = self.op2 markers = [] struc = Struct('3i') for unused_i in range(nmarkers): block = op2.f.read(12) marker = struc.unpack(block) markers.append(marker) return markers
[docs] def get_nmarkers(self, n: int, rewind=True, macro_rewind=False): if self.size == 4: return self.get_nmarkers4(n, rewind=rewind, macro_rewind=macro_rewind) return self.get_nmarkers8(n, rewind=rewind, macro_rewind=macro_rewind)
[docs] def get_nmarkers4(self, n: int, rewind=True, macro_rewind=False): """ Gets n markers, so if n=2, it will get 2 markers. Parameters ---------- n : int number of markers to get rewind : bool should the file be returned to the starting point Returns ------- markers : List[int] list of [1, 2, 3, ...] markers """ op2 = self.op2 ni = op2.n markers = [] for i in range(n): data = self.read_block4() marker, = op2.struct_i.unpack(data) markers.append(marker) if rewind: op2.n = ni op2.f.seek(op2.n) #for i in range(n): #self.binary_debug.write('get_nmarkers- [4, %i, 4]; macro_rewind=%s\n' % ( #i, macro_rewind or rewind)) else: #if not macro_rewind: if self.is_debug_file: for i in range(n): self.binary_debug.write('get_nmarkers- [4, %i, 4]; macro_rewind=%s\n' % ( i, macro_rewind or rewind)) return markers
[docs] def get_nmarkers8(self, n: int, rewind=True, macro_rewind=False): """ Gets n markers, so if n=2, it will get 2 markers. Parameters ---------- n : int number of markers to get rewind : bool should the file be returned to the starting point Returns ------- markers : List[int] list of [1, 2, 3, ...] markers """ op2 = self.op2 ni = op2.n markers = [] for i in range(n): data = self.read_block8() marker, = op2.struct_q.unpack(data) markers.append(marker) if rewind: op2.n = ni op2.f.seek(op2.n) #for i in range(n): #self.binary_debug.write('get_nmarkers- [4, %i, 4]; macro_rewind=%s\n' % ( #i, macro_rewind or rewind)) else: #if not macro_rewind: if self.is_debug_file: for i in range(n): self.binary_debug.write('get_nmarkers- [8, %i, 8]; macro_rewind=%s\n' % ( i, macro_rewind or rewind)) return markers
[docs] def read_markers(self, markers: List[int], macro_rewind: bool=True) -> None: if self.size == 4: return self.read_markers4(markers, macro_rewind=macro_rewind) return self.read_markers8(markers, macro_rewind=macro_rewind)
[docs] def read_markers4(self, markers: List[int], macro_rewind: bool=True) -> None: """ Gets specified markers, where a marker has the form of [4, value, 4]. The "marker" corresponds to the value, so 3 markers takes up 9 integers. These are used to indicate position in the file as well as the number of bytes to read. Because we're checking the markers vs. what we expect, we just throw the data away. Parameters ---------- markers : List[int] markers to get; markers = [-10, 1] Raises ------ FortranMarkerError if the expected table number is not found """ op2 = self.op2 for i, marker in enumerate(markers): #self.log.debug('markers[%i] = %s' % (i, marker)) data = self.read_block4() imarker, = op2.struct_i.unpack(data) if marker != imarker: #self.show_data(data) msg = 'marker=%r imarker=%r; markers=%s; i=%s; table_name=%r; iloc=%s/%s' % ( marker, imarker, markers, i, op2.table_name, op2.f.tell(), os.path.getsize(op2.op2_filename)) raise FortranMarkerError(msg) if self.is_debug_file: self.binary_debug.write(f' read_markers -> [4, {marker:d}, 4]\n')
[docs] def read_markers8(self, markers: List[int], macro_rewind: int=True) -> None: """ Gets specified markers, where a marker has the form of [4, value, 4]. The "marker" corresponds to the value, so 3 markers takes up 9 integers. These are used to indicate position in the file as well as the number of bytes to read. Because we're checking the markers vs. what we expect, we just throw the data away. Parameters ---------- markers : List[int] markers to get; markers = [-10, 1] Raises ------ FortranMarkerError if the expected table number is not found """ op2 = self.op2 for i, marker in enumerate(markers): #self.log.debug('markers[%i] = %s' % (i, marker)) data = self.read_block8() imarker, = op2.struct_q.unpack(data) if marker != imarker: #self.show_data(data, types='iq') msg = 'marker=%r imarker=%r; markers=%s; i=%s; table_name=%r; iloc=%s/%s' % ( marker, imarker, markers, i, op2.table_name, op2.f.tell(), os.path.getsize(op2.op2_filename)) raise FortranMarkerError(msg) if self.is_debug_file: self.binary_debug.write(f' read_markers -> [8, {marker:d}, 8]\n')
def _skip_table(self, table_name: str, warn: bool=True) -> None: """bypasses the next table as quickly as possible""" #if table_name in ['DIT', 'DITS']: # tables #self._read_dit() if table_name in ['PCOMPTS', 'PCOMPTS']: self._read_pcompts() else: self._skip_table_helper(warn=warn) def _print_month(self, month: int, day: int, year: int, zero: int, one: int) -> None: """ Creates the self.date attribute from the 2-digit year. Parameters ---------- month : int the month (integer <= 12) day : int the day (integer <= 31) year : int the day (integer <= 99) zero : int a dummy integer (???) one : int a dummy integer (???) """ if year > 2000: # would you believe they changed the date format? month, day = day, month else: year += 2000 month, day, year = self._set_op2_date(month, day, year) #self.log.debug("%s/%s/%4i zero=%s one=%s" % (month, day, year, zero, one)) #if self.is_debug_file: if self.is_debug_file: self.binary_debug.write(' [subtable_name, month=%i, day=%i, year=%i, ' 'zero=%i, one=%i]\n\n' % (month, day, year, zero, one)) #assert zero == 0, zero # is this the RTABLE indicator??? assert one in [0, 1], one # 0, 50 def _set_op2_date(self, month: int, day: int, year: int) -> Tuple[int, int, int]: """sets the date the job was run""" date = (month, day, year) self.op2.date = date return date #---------------------------------------------------------------------------------------- def _read_record(self, debug=True, macro_rewind=False) -> bytes: """ Reads a record. A record is defined N blocks. Blocks are split every 2^12 bytes, which is an oddity of the OP2, which is a "Fortran formatted" file. You can think of a block as a partial result. A record is a full result. If a block is small enough, it will fit into 2^12 bytes and a record is a block. """ if self.size == 4: return self._read_record_ndata4(debug=debug, macro_rewind=macro_rewind)[0] return self._read_record_ndata8(debug=debug, macro_rewind=macro_rewind)[0] def _read_record_ndata(self, debug=True, macro_rewind=False) -> Tuple[bytes, int]: """reads a record and the length of the record""" if self.size == 4: return self._read_record_ndata4(debug=debug, macro_rewind=macro_rewind) return self._read_record_ndata8(debug=debug, macro_rewind=macro_rewind) def _read_record_ndata4(self, debug=True, macro_rewind=False) -> Tuple[bytes, int]: """reads a record and the length of the record for size=4""" op2 = self.op2 markers0 = self.get_nmarkers4(1, rewind=False, macro_rewind=macro_rewind) if self.is_debug_file and debug: self.binary_debug.write('read_record - marker = [4, %i, 4]; macro_rewind=%s\n' % ( markers0[0], macro_rewind)) record, nrecord = self._read_block_ndata4() if self.is_debug_file and debug: msg = 'read_record - record = [%i, recordi, %i]; macro_rewind=%s\n' % ( nrecord, nrecord, macro_rewind) self.binary_debug.write(msg) if markers0[0]*4 != len(record): raise FortranMarkerError('markers0=%s*4 len(record)=%s; table_name=%r' % ( markers0[0]*4, len(record), op2.table_name)) markers1 = self.get_nmarkers4(1, rewind=True) if markers1[0] > 0: #nloop = 0 records = [record] while markers1[0] > 0: markers1 = self.get_nmarkers(1, rewind=False) if self.is_debug_file and debug: self.binary_debug.write('read_record - markers1 = [4, %i, 4]\n' % markers1[0]) recordi, nrecordi = self._read_block_ndata() nrecord += nrecordi records.append(recordi) #record += recordi markers1 = self.get_nmarkers(1, rewind=True) if self.is_debug_file and debug: self.binary_debug.write('read_record - markers1 = [4, %i, 4]\n' % markers1[0]) #nloop += 1 # if nloop == 0: # record = records[0] # elif nloop == 1: # record = records[0] + records[1] # else: record = b''.join(records) return record, nrecord def _read_record_ndata8(self, debug=True, macro_rewind=False) -> Tuple[bytes, int]: """reads a record and the length of the record for size=8""" op2 = self.op2 markers0 = self.get_nmarkers8(1, rewind=False, macro_rewind=macro_rewind) if self.is_debug_file and debug: self.binary_debug.write('read_record - marker = [8, %i, 8]; macro_rewind=%s\n' % ( markers0[0], macro_rewind)) record, nrecord = self._read_block_ndata8() if self.is_debug_file and debug: msg = 'read_record - record = [%i, recordi, %i]; macro_rewind=%s\n' % ( nrecord, nrecord, macro_rewind) self.binary_debug.write(msg) if markers0[0]*8 != len(record): self.show_data(record, types='ifsqd') raise FortranMarkerError('markers0=%s*8 len(record)=%s; table_name=%r' % ( markers0[0]*8, len(record), op2.table_name)) markers1 = self.get_nmarkers8(1, rewind=True) if markers1[0] > 0: #nloop = 0 records = [record] while markers1[0] > 0: markers1 = self.get_nmarkers8(1, rewind=False) if self.is_debug_file and debug: self.binary_debug.write('read_record - markers1 = [8, %i, 8]\n' % markers1[0]) recordi, nrecordi = self._read_block_ndata8() nrecord += nrecordi records.append(recordi) #record += recordi markers1 = self.get_nmarkers8(1, rewind=True) if self.is_debug_file and debug: self.binary_debug.write('read_record - markers1 = [8, %i, 8]\n' % markers1[0]) #nloop += 1 # if nloop == 0: # record = records[0] # elif nloop == 1: # record = records[0] + records[1] # else: record = b''.join(records) return record, nrecord def _read_block_ndata4(self): """ Reads a block following a pattern of: [nbytes, data, nbytes] Returns ------- data : bytes the data in binary ndata : int len(data) """ op2 = self.op2 data = op2.f.read(4) ndata, = op2.struct_i.unpack(data) data_out = op2.f.read(ndata) data = op2.f.read(4) op2.n += 8 + ndata return data_out, ndata def _read_block_ndata(self): """ Reads a block following a pattern of: [nbytes, data, nbytes] Returns ------- data : bytes the data in binary ndata : int len(data) """ if self.size == 4: return self._read_block_ndata4() return self._read_block_ndata8() def _read_block_ndata8(self): """ Reads a block following a pattern of: [nbytes, data, nbytes] Returns ------- data : bytes the data in binary ndata : int len(data) """ op2 = self.op2 data = op2.f.read(4) ndata, = op2.struct_i.unpack(data) data_out = op2.f.read(ndata) data = op2.f.read(4) op2.n += 8 + ndata return data_out, ndata #------------------------------------------------------------------
[docs] def unpack_table_name(self, data: bytes) -> bytes: if self.size == 4: return self.unpack_table_name4(data) return self.unpack_table_name8(data)
[docs] def unpack_table_name4(self, data: bytes) -> bytes: """table names can apparently be 8 or 32 characters""" if len(data) == 8: # 'GEOM4 ' structi = self.op2.struct_8s table_name, = structi.unpack(data) elif len(data) == 32: # 'GEOM1 20140 0 _y\xfe\xffGEOM1 ' # ['GEOM1 ', '20140 ', '0 ', -10000, ' GEOM1 '] structi = self.op2.struct_8s table_name, = structi.unpack(data[:8]) else: raise NotImplementedError(f'data={data!r}; n={len(data)}') return table_name.strip()
[docs] def unpack_table_name8(self, data: bytes) -> bytes: """table names can apparently be 8 or 32 characters""" if len(data) == 8: # 'GEOM4 ' structi = self.op2.struct_8s table_name, = structi.unpack(data) elif len(data) == 16: # 'GEOM4 ' #b'PVT0 ' structi = self.op2.struct_16s table_name, = structi.unpack(data) #elif len(data) == 32: # 'GEOM1 20140 0 _y\xfe\xffGEOM1 ' # ['GEOM1 ', '20140 ', '0 ', -10000, ' GEOM1 '] #structi = self.op2.struct_8s #table_name, = structi.unpack(data[:8]) else: raise NotImplementedError(f'data={data!r}; n={len(data)}') return table_name.strip()
def _read_table_name(self, last_table_name: Optional[bytes]=None, rewind: bool=False, stop_on_failure: bool=True) -> bytes: """ Reads the next OP2 table name (e.g. OUG1, OES1X1) Parameters ---------- last_table_name : bytes; default=Noen the last table name Returns ------- table_name : bytes the table name """ op2 = self.op2 table_name = None data = None if self.is_debug_file: self.binary_debug.write('_read_table_name - rewind=%s\n' % rewind) ni = op2.n if stop_on_failure: data = self._read_record(debug=False, macro_rewind=rewind) if self.size == 8: data = reshape_bytes_block(data) table_name = self.unpack_table_name(data) if self.is_debug_file and not rewind: self.binary_debug.write('marker = [4, 2, 4]\n') self.binary_debug.write('table_header = [8, %r, 8]\n\n' % table_name) table_name = table_name.strip() else: try: data = self._read_record(macro_rewind=rewind) if self.size == 8: data = reshape_bytes_block(data) table_name = self.unpack_table_name(data) except (NameError, MemoryError): raise except Exception: # struct_error: # we're done reading op2.n = ni op2.f.seek(op2.n) try: # we have a trailing 0 marker self.read_markers([0], macro_rewind=rewind) except Exception: #struct_error: # if we hit this block, we have a FATAL error is_special_nastran = op2._nastran_format.lower().startswith(('imat', 'autodesk')) if not is_special_nastran and op2.post != -4: op2.f.seek(op2.n) self.show(1000) if last_table_name: self.log.error(f'finished table_name = {last_table_name}') raise FatalError('There was a Nastran FATAL Error. Check the F06.\n' f'last table={op2.table_name!r}; post={op2.post} ' f'version={self.op2._nastran_format!r}') table_name = None # we're done reading, so we're going to ignore the rewind rewind = False if rewind: op2.n = ni op2.f.seek(op2.n) if table_name is not None: assert len(table_name) <= 8, f'table_name={table_name}; n={len(table_name)}' #if self.size == 8: #print(table_name) return table_name
[docs] def read_block(self): if self.size == 4: return self.read_block4() return self.read_block8()
[docs] def read_string_block(self) -> bytes: block = self.read_block() if self.size == 4: return block return reshape_bytes_block(block)
[docs] def read_block4(self) -> bytes: """ Reads a block following a pattern of: [nbytes, data, nbytes] Returns ------- data : bytes the data in binary Notes ----- see read_3_blocks """ op2 = self.op2 data = op2.f.read(4) ndata, = op2.struct_i.unpack(data) data_out = op2.f.read(ndata) data = op2.f.read(4) op2.n += 8 + ndata return data_out
[docs] def read_block8(self) -> bytes: """ Reads a block following a pattern of: [nbytes, data, nbytes] Returns ------- data : bytes the data in binary Notes ----- see read_3_blocks """ op2 = self.op2 data = op2.f.read(4) ndata, = op2.struct_i.unpack(data) data_out = op2.f.read(ndata) data = op2.f.read(4) op2.n += 8 + ndata return data_out
[docs] def read_3_blocks4(self) -> bytes: """ Reads a block following a pattern of: [nbytes, data, nbytes] [nbytes, data, nbytes] [nbytes, data, nbytes] This is intended to be used for reading marker triples Returns ------- data : bytes the data in binary """ op2 = self.op2 data_out = b'' for unused_i in range(3): data = op2.f.read(4) ndata, = op2.struct_i.unpack(data) data_out += op2.f.read(ndata) data = op2.f.read(4) op2.n += 8 + ndata return data_out
[docs] def read_3_markers(self, markers, macro_rewind=True) -> None: """Micro-optimizes ``read_markers`` for 3 markers.""" if self.size == 4: self.read_3_markers4(markers, macro_rewind=macro_rewind) else: self.read_markers8(markers, macro_rewind=macro_rewind)
[docs] def read_3_markers4(self, markers, macro_rewind=True) -> None: """ Micro-optimizes ``read_markers`` for 3 markers. Parameters ---------- markers : List[int, int, int] markers to get; markers = [-10, 1, 0] Raises ------ FortranMarkerError if the expected table number is not found """ #data1 = self.read_block4() #data2 = self.read_block4() #data3 = self.read_block4() #data = data1 + data2 + data3 op2 = self.op2 data = self.read_3_blocks4() markers_actual = op2.struct_3i.unpack(data) for imarker, marker, marker_actual in zip(count(), markers, markers_actual): if marker != marker_actual: raise FortranMarkerError(f'imarker={imarker}; markers={markers}; ' f'marker_actual={markers_actual} table_name={op2.table_name!r}') if self.is_debug_file: self.binary_debug.write(' read_markers -> [4, %i, 4]\n' % marker)
[docs] def get_marker1(self, rewind: bool=True, macro_rewind: bool=False) -> int: if self.size == 4: return self.get_marker1_4(rewind=rewind, macro_rewind=macro_rewind) return self.get_marker1_8(rewind=rewind, macro_rewind=macro_rewind)
[docs] def get_marker1_4(self, rewind: bool=True, macro_rewind: bool=False) -> int: """ Gets 1 marker See get_n_markers(...) Parameters ---------- rewind : bool should the file be returned to the starting point macro_rewind : bool ??? Returns ------- markers : int a single marker """ op2 = self.op2 ni = op2.n data = self.read_block4() marker, = op2.struct_i.unpack(data) if rewind: op2.n = ni op2.f.seek(op2.n) else: if self.is_debug_file: msg = 'get_marker - [4, %i, 4]; macro_rewind=%s\n' % ( marker, macro_rewind or rewind) self.binary_debug.write(msg) return marker
[docs] def get_marker1_8(self, rewind=True, macro_rewind=False) -> int: """ Gets 1 marker See get_n_markers(...) Parameters ---------- rewind : bool should the file be returned to the starting point macro_rewind : bool ??? Returns ------- markers : int a single marker """ op2 = self.op2 ni = op2.n data = self.read_block8() marker, = op2.struct_q.unpack(data) if rewind: op2.n = ni op2.f.seek(op2.n) else: if self.is_debug_file: msg = 'get_marker - [8, %i, 8]; macro_rewind=%s\n' % ( marker, macro_rewind or rewind) self.binary_debug.write(msg) return marker
#------------------------------------------------------------------ @property def is_debug_file(self) -> bool: """interface to the op2 object""" return self.op2.is_debug_file @property def binary_debug(self): """interface to the op2 object""" return self.op2.binary_debug @property def log(self): """interface to the op2 object""" return self.op2.log @property def _endian(self) -> bytes: """interface to the op2 object""" return self.op2._endian @property def _uendian(self) -> str: """interface to the op2 object""" return self.op2._uendian @property def _encoding(self) -> str: """interface to the op2 object""" return self.op2._encoding @property def read_mode(self) -> int: """interface to the op2 object""" return self.op2.read_mode @property def debug_file(self): """interface to the op2 object""" return self.op2.debug_file #------------------------------------------------------------------ # skip methods #class OP2Skip: #def __init__(self, op2): #self.op2 = op2 #@property #def is_debug_file(self): #return self.op2.is_debug_file #@property #def binary_debug(self): #return self.op2.binary_debug #@property #def log(self): #return self.op2.log def _skip_table_helper(self, warn=True): """ Skips the majority of geometry/result tables as they follow a very standard format. Other tables don't follow this format. """ op2 = self.op2 op2.table_name = self._read_table_name(rewind=False) if self.is_debug_file: self.binary_debug.write('skipping table...%r\n' % op2.table_name) if warn: self.log.warning(' skipping table_helper = %s' % op2.table_name) self.read_markers([-1]) unused_data = self._skip_record() self.read_3_markers([-2, 1, 0]) unused_data = self._skip_record() self._skip_subtables() def _skip_subtables(self): """skips a set of subtables""" op2 = self.op2 op2.isubtable = -3 self.read_3_markers([-3, 1, 0]) markers = self.get_nmarkers(1, rewind=True) while markers[0] != 0: unused_data = self._skip_record() if self.is_debug_file: self.log.debug("skipping table_name = %r" % op2.table_name) #if len(data) == 584: #self._parse_results_table3(data) #else: #data = self._parse_results_table4(data) op2.isubtable -= 1 self.read_3_markers([op2.isubtable, 1, 0]) markers = self.get_nmarkers(1, rewind=True) self.read_markers([0]) def _skip_record(self): """ the skip version of ``_read_record`` Returns ------- record : None a record of None indicates a skipped block """ unused_markers0 = self.get_nmarkers(1, rewind=False) record = self._skip_block() markers1 = self.get_nmarkers(1, rewind=True) # handling continuation blocks while markers1[0] > 0: markers1 = self.get_nmarkers(1, rewind=False) record = self._skip_block() markers1 = self.get_nmarkers(1, rewind=True) return record def _skip_record_ndata(self, debug=True, macro_rewind=False): if self.size == 4: return self._skip_record_ndata4(debug=debug, macro_rewind=macro_rewind) return self._skip_record_ndata8(debug=debug, macro_rewind=macro_rewind) def _skip_record_ndata4(self, debug=True, macro_rewind=False): """the skip version of ``_read_record_ndata``""" op2 = self.op2 marker0 = self.get_marker1_4(rewind=False, macro_rewind=macro_rewind) if self.is_debug_file and debug: self.binary_debug.write('read_record - marker = [4, %i, 4]; macro_rewind=%s\n' % ( marker0, macro_rewind)) record, nrecord = self._skip_block_ndata() if self.is_debug_file and debug: self.binary_debug.write('read_record - record = [%i, recordi, %i]; ' 'macro_rewind=%s\n' % (nrecord, nrecord, macro_rewind)) if marker0*4 != nrecord: msg = 'marker0=%s*4 len(record)=%s; table_name=%r' % ( marker0*4, nrecord, op2.table_name) raise FortranMarkerError(msg) marker1 = self.get_marker1_4(rewind=True) if marker1 > 0: while marker1 > 0: marker1 = self.get_marker1_4(rewind=False) if self.is_debug_file and debug: self.binary_debug.write(f'read_record - marker1 = [4, {marker1}, 4]\n') unused_recordi, nrecordi = self._skip_block_ndata() nrecord += nrecordi marker1 = self.get_marker1_4(rewind=True) if self.is_debug_file and debug: self.binary_debug.write(f'read_record - marker1 = [4, {marker1}, 4]\n') return record, nrecord def _skip_record_ndata8(self, debug=True, macro_rewind=False): """the skip version of ``_read_record_ndata``""" op2 = self.op2 marker0 = self.get_marker1_8(rewind=False, macro_rewind=macro_rewind) if self.is_debug_file and debug: self.binary_debug.write('read_record - marker = [8, %i, 8]; macro_rewind=%s\n' % ( marker0, macro_rewind)) record, nrecord = self._skip_block_ndata() if self.is_debug_file and debug: self.binary_debug.write('read_record - record = [%i, recordi, %i]; ' 'macro_rewind=%s\n' % (nrecord, nrecord, macro_rewind)) if marker0*8 != nrecord: msg = 'marker0=%s*8 len(record)=%s; table_name=%r' % ( marker0*8, nrecord, op2.table_name) raise FortranMarkerError(msg) marker1 = self.get_marker1_8(rewind=True) if marker1 > 0: while marker1 > 0: marker1 = self.get_marker1_8(rewind=False) if self.is_debug_file and debug: self.binary_debug.write(f'read_record - marker1 = [8, {marker1}, 8]\n') unused_recordi, nrecordi = self._skip_block_ndata() nrecord += nrecordi marker1 = self.get_marker1_8(rewind=True) if self.is_debug_file and debug: self.binary_debug.write(f'read_record - marker1 = [8, {marker1}, 8]\n') return record, nrecord def _get_record_length(self): """ The record length helps us figure out data block size, which is used to quickly size the arrays. We just need a bit of meta data and can jump around quickly. Returns ------- record_length : int the length of the data block """ op2 = self.op2 if self.is_debug_file: self.binary_debug.write('_get_record_length\n') len_record = 0 n0 = op2.n markers0 = self.get_nmarkers(1, rewind=False) if self.is_debug_file: self.binary_debug.write(' markers0=%s\n' % markers0) n = op2.n unused_record = self._skip_block() len_record += op2.n - n - 8 # -8 is for the block if self.is_debug_file: self.binary_debug.write(' len_record=%s\n' % len_record) markers1 = self.get_nmarkers(1, rewind=True) # handling continuation blocks while markers1[0] > 0: markers1 = self.get_nmarkers(1, rewind=False) if self.is_debug_file: self.binary_debug.write(' markers1=%s\n' % markers1) n = op2.n unused_record = self._skip_block() len_record += op2.n - n - 8 # -8 is for the block markers1 = self.get_nmarkers(1, rewind=True) self._goto(n0) return len_record def _skip_block(self): """ Skips a block following a pattern of: [nbytes, data, nbytes] Returns ------- data : since data can never be None, a None value indicates something bad happened. """ return self._skip_block_ndata()[0] def _skip_block_ndata(self) -> Tuple[None, int]: """ Skips a block following a pattern of: [nbytes, data, nbytes] Returns ------- data : None since data can never be None, a None value indicates something bad happened. ndata : int the length of the data block that was skipped """ op2 = self.op2 data = op2.f.read(4) ndata, = op2.struct_i.unpack(data) op2.n += 8 + ndata self._goto(op2.n) return None, ndata #--------------------------------------------------------------------------- def _goto(self, n: int) -> None: """ Jumps to position n in the file Parameters ---------- n : int the position to goto """ self.op2.n = n self.op2.f.seek(n)
[docs] def is_valid_subcase(self) -> bool: """ Lets the code check whether or not to read a subcase Returns ------- is_valid : bool should this subcase defined by self.isubcase be read? """ op2 = self.op2 if not op2.is_all_subcases: if hasattr(op2, 'isubcase') and op2.isubcase in op2.valid_subcases: return True return False return True
[docs] def read_results_table(self): """Reads a results table""" if self.size == 4: self.read_results_table4() else: self.read_results_table8()
[docs] def read_results_table4(self) -> None: """Reads a results table""" op2 = self.op2 if self.is_debug_file: self.binary_debug.write(f'read_results_table - {op2.table_name}\n') op2.table_name = self._read_table_name(rewind=False) self.read_markers([-1]) if self.is_debug_file: self.binary_debug.write('---markers = [-1]---\n') #self.binary_debug.write('marker = [4, -1, 4]\n') data = self._read_record() self.read_3_markers([-2, 1, 0]) if self.is_debug_file: self.binary_debug.write('---markers = [-2, 1, 0]---\n') data, ndata = self._read_record_ndata4() subtable_name = self.get_subtable_name4(op2, data, ndata) op2.subtable_name = subtable_name self._read_subtables()
[docs] def read_results_table8(self) -> None: """Reads a results table""" op2 = self.op2 if self.is_debug_file: self.binary_debug.write(f'read_results_table - {op2.table_name}\n') op2.table_name = self._read_table_name(rewind=False) self.read_markers8([-1]) if self.is_debug_file: self.binary_debug.write('---markers = [-1]---\n') #self.binary_debug.write('marker = [4, -1, 4]\n') data = self._read_record() self.read_markers8([-2, 1, 0]) if self.is_debug_file: self.binary_debug.write('---markers = [-2, 1, 0]---\n') data, ndata = self._read_record_ndata8() subtable_name = self.get_subtable_name8(op2, data, ndata) subtable_name = reshape_bytes_block(subtable_name) op2.subtable_name = subtable_name self._read_subtables()
[docs] def get_subtable_name8(self, op2, data: bytes, ndata: int) -> bytes: if ndata == 16: # 8*2 subtable_name = op2.struct_16s.unpack(data) subtable_name = reshape_bytes_block(subtable_name) if self.is_debug_file: self.binary_debug.write(f' recordi = [{subtable_name!r}]\n') self.binary_debug.write(f' subtable_name={subtable_name!r}\n') elif ndata == 32: # 16*2 #(name1, name2, 170, 170) subtable_name, = op2.struct_16s.unpack(data[:16]) assert len(subtable_name) == 16, len(subtable_name) subtable_name = reshape_bytes_block(subtable_name) if self.is_debug_file: self.binary_debug.write(f' recordi = [{subtable_name!r}]\n') self.binary_debug.write(f' subtable_name={subtable_name!r}\n') elif ndata == 56: # 28*2 subtable_name, month, day, year, zero, one = unpack(self._endian + b'16s5q', data) subtable_name = reshape_bytes_block(subtable_name) if self.is_debug_file: self.binary_debug.write(' recordi = [%r, %i, %i, %i, %i, %i]\n' % ( subtable_name, month, day, year, zero, one)) self.binary_debug.write(f' subtable_name={subtable_name!r}\n') self._print_month(month, day, year, zero, one) else: self.show_data(data, types='ifsqd', endian=None) raise NotImplementedError(len(data)) return subtable_name
[docs] def get_subtable_name4(self, op2, data: bytes, ndata: int) -> bytes: if ndata == 8: subtable_name = op2.struct_8s.unpack(data) if self.is_debug_file: self.binary_debug.write(f' recordi = [{subtable_name!r}]\n') self.binary_debug.write(f' subtable_name={subtable_name!r}\n') elif ndata == 12: subtable_name, unused_ten = unpack(self._endian + b'8si', data) # type: Tuple[bytes, int] subtable_name = subtable_name.strip().decode(self._encoding) #assert ten == 10, self.show_data(data, types='ifs', endian=None) assert subtable_name in ['GPL', 'GPLS'], subtable_name if self.is_debug_file: self.binary_debug.write(f' recordi = [{subtable_name!r}]\n') self.binary_debug.write(f' subtable_name={subtable_name!r}\n') elif ndata == 28: subtable_name, month, day, year, zero, one = unpack(self._endian + b'8s5i', data) if self.is_debug_file: self.binary_debug.write(' recordi = [%r, %i, %i, %i, %i, %i]\n' % ( subtable_name, month, day, year, zero, one)) self.binary_debug.write(f' subtable_name={subtable_name!r}\n') self._print_month(month, day, year, zero, one) elif ndata == 612: # ??? strings, ints, floats = self.show_data(data) msg = f'len(data) = {ndata:d}\n' #msg += 'strings = %r\n' % strings #msg += 'ints = %r\n' % str(ints) #msg += 'floats = %r' % str(floats) print(msg) subtable_name, = op2.struct_8s.unpack(data[:8]) print('subtable_name = %r' % subtable_name.strip()) elif ndata == 24 and op2.table_name == b'ICASE': subtable_name = 'CASE CONTROL SECTION' #strings = 'CASE CONTROL SECTION\xff\xff\xff\xff' else: strings, ints, floats = self.show_data(data) msg = 'len(data) = %i\n' % ndata msg += 'strings = %r\n' % strings msg += 'ints = %r\n' % str(ints) msg += 'floats = %r' % str(floats) raise NotImplementedError(msg) if hasattr(self, 'subtable_name'): raise RuntimeError('the file has not been cleaned up; subtable_name_old=%s new=%s' % ( op2.subtable_name, subtable_name)) return subtable_name
[docs] def generic_stop_table(self, data: bytes, ndata: int): # pragma: no cover """print table data when things get weird""" strings, ints, floats = self.show_data(data) msg = 'Unhandled table length error\n' msg += f'table_name = {self.op2.table_name}\n' msg += f'len(data) = {ndata:d}\n' msg += 'strings = %r\n' % strings msg += 'ints = %r\n' % str(ints) msg += 'floats = %r' % str(floats) raise NotImplementedError(msg)
[docs] def read_geom_table(self): """Reads a geometry table""" op2 = self.op2 op2.table_name = self._read_table_name(rewind=False) if self.is_debug_file: self.binary_debug.write(f'read_geom_table - {op2.table_name}\n') self.read_markers([-1]) data = self._read_record() # length=28=7*4 self.read_3_markers([-2, 1, 0]) data, ndata = self._read_record_ndata() if self.size == 4: if ndata == 8: subtable_name, = self.op2.struct_8s.unpack(data) elif ndata == 28: # date = august 2, 2019 #(b'OGPFB1 ', 8, 2, 19, 0, 1) #(b'OGPFB1 ', 8, 2, 19, 1, 1) fmt = self._endian + b'8s 3i 2i' subtable_name, month, day, year, zero, one = Struct(fmt).unpack(data) if zero != 0 or one != 1: # pragma: no cover self.log.warning(f' subtable_name={subtable_name} possible error; zero={zero} one={one}') #self.generic_stop_table(data, ndata) self._set_op2_date(month, day, year) else: self.generic_stop_table(data, ndata) else: if ndata == 16: subtable_name, = self.op2.struct_16s.unpack(data) else: self.generic_stop_table(data, ndata) op2.subtable_name = subtable_name.rstrip() self._read_subtables()
def _read_subtables(self) -> None: """reads a series of subtables""" # this parameters is used for numpy streaming op2 = self.op2 op2._table4_count = 0 op2.is_table_1 = True op2._data_factor = 1 #nstart = op2.n op2.isubtable = -3 self.read_3_markers([-3, 1, 0]) if self.is_debug_file: self.binary_debug.write(f'***isubtable = {op2.isubtable:d}\n') self.binary_debug.write('---markers = [-3, 1, 0]---\n') # get the parsing functions (table3_parser, table4_parser) # or find out we're going to be skipping the tables # # table3 - the table with the meta data (e.g. subcase_id, time, is_stress/strain) # table4 - the actual results data # # we indicate table3/4 by isubtable, which starts from -3 (so table3) and counts # down (yes down) to 4 to indicate table4. If we count down again, we end up # back at table 3 (with isubtable=-5), which will occur in the case of multiple # times/element types/results in a single macro table (e.g. OUG, OES). table_mapper = op2._get_table_mapper() table_name = op2.table_name if table_name in table_mapper: #if self.read_mode == 2: #self.log.debug("table_name = %r" % table_name) table3_parser, table4_parser = table_mapper[table_name] passer = False else: if self.read_mode == 2: self.log.info(f'skipping table_name = {table_name!r}') #raise NotImplementedError(table_name) table3_parser = None table4_parser = None passer = True # we need to check the marker, so we read it and rewind, so we don't # screw up our positioning in the file markers = self.get_nmarkers(1, rewind=True) #if markers[0] == 0: #self.log.debug(' returning early') #return if self.is_debug_file: self.binary_debug.write(f'---marker0 = {markers}---\n') # while the subtables aren't done while markers[0] != 0: op2.is_start_of_subtable = True if self.is_debug_file: self.binary_debug.write(f'***isubtable = {op2.isubtable:d}\n') try: self._read_subtable_3_4(table3_parser, table4_parser, passer) except Exception: # pragma: no cover print(f'failed reading {table_name} isubtable={op2.isubtable:d}') raise #force_table4 = self._read_subtable_3_4(table3_parser, table4_parser, passer) op2.isubtable -= 1 iloc = op2.f.tell() try: self.read_3_markers([op2.isubtable, 1, 0]) #self.log.debug('markers=%s' % [op2.isubtable, 1, 0]) except FortranMarkerError: self.log.error(f'isubtable={op2.isubtable:d}') op2.f.seek(iloc) op2.n = iloc self.show(4*3*3, types='i') self.show(500) marker0 = self.get_nmarkers(1, rewind=True)[0] #print('marker0 =', marker0) if marker0 < op2.isubtable: raise RuntimeError('marker0 < isubtable; marker0=%s isubtable=%s' % ( marker0, op2.isubtable)) #self.read_3_markers([marker0, 1, 0]) ##self.log.debug('markers=%s' % [marker0, 1, 0]) #self.show(200) #break raise markers = self.get_nmarkers(1, rewind=True) if self.is_debug_file: self.binary_debug.write(f'breaking on marker={markers}\n') # we've finished reading all subtables, but have one last marker to read marker = self.get_marker1(rewind=False, macro_rewind=False) assert marker == 0, marker op2._finish() def _read_subtable_3_4(self, table3_parser: Optional[Callable], table4_parser: Optional[Callable], passer: Optional[Callable]) -> Optional[bool]: """ Reads a series of subtable 3/4 Parameters ---------- table3_parser : bool / function None : just to break the code if we're on the array sizing step function : the table 3 reading function table4_parser :bool / function None : just to break the code if we're on the array sizing step function : the table 4 reading function passer : bool flag to see if we're skipping tables Returns ------- flag : bool True : ??? False : failed??? None : passed??? """ op2 = self.op2 if self.binary_debug: self.binary_debug.write('-' * 60 + '\n') # this is the length of the current record inside table3/table4 record_len = self._get_record_length() if self.is_debug_file: self.binary_debug.write(f'record_length = {record_len:d}\n') oes_nl = [b'OESNLXD', b'OESNL1X', b'OESNLXR'] factor = self.factor table_name = op2.table_name if record_len == 584 * factor: # table3 has a length of 584 if table_name in oes_nl and hasattr(op2, 'num_wide') and op2.num_wide == 146: data_code_old = deepcopy(op2.data_code) if self.load_as_h5: assert self.h5_file is not None, self.h5_file op2.data_code = { '_encoding' : self._encoding, 'load_as_h5' : self.load_as_h5, 'h5_file' : self.h5_file, 'size' : self.size, } op2.obj = None data, ndata = self._read_record_ndata() if not passer: try: table3_parser(data, ndata) except SortCodeError: if self.is_debug_file: self.binary_debug.write('except SortCodeError!\n') if table_name in oes_nl: update_op2_datacode(op2, data_code_old) n = table4_parser(data, ndata) #print(data_code_old) if not isinstance(n, integer_types): msg = 'n is not an integer; table_name=%s n=%s table4_parser=%s' % ( self.op2.table_name, n, table4_parser) raise TypeError(msg) if IS_TESTING: self._run_checks(table4_parser) if self.read_mode == 1: #op2_reader._goto(n) #n = op2_reader._skip_record() #if hasattr(self.op2, 'table_name'): #print('***_init_vector_counter', self.op2.table_name) #print('record_len', record_len) self.op2._init_vector_counter(record_len) else: self.op2._reset_vector_counter() #print('except...') return False raise RuntimeError(op2.code_information()) #if hasattr(op2, 'isubcase'): #print("code = ", op2._get_code()) else: if passer or not self.is_valid_subcase(): data = self._skip_record() else: if hasattr(op2, 'num_wide'): # num_wide is the result size and is usually found in # table3, but some B-list tables don't have it unused_n = op2._read_subtable_results(table4_parser, record_len) else: data, ndata = self._read_record_ndata() unused_n = table4_parser(data, ndata) if IS_TESTING: self._run_checks(table4_parser) #del n return None def _run_checks(self, table4_parser): """helper method""" if table4_parser != self.op2._table_passer: str(self.op2.code_information()) if hasattr(self, 'obj'): str(self.obj.get_stats())
[docs] def show(self, n: int, types: str='ifs', endian: Optional[str]=None, force: bool=False): # pragma: no cover """ shows the next N bytes Parameters ---------- n : int the number of bytes to show types : str; default='ifs' the data types to show endian : str; default=None -> active endian the data endian force : bool; default=False overwrite the n=2000 limiter """ op2 = self.op2 assert op2.n == op2.f.tell() data = op2.f.read(n) strings, ints, floats = self.show_data(data, types=types, endian=endian, force=force) op2.f.seek(op2.n) return strings, ints, floats
[docs] def show_data(self, data: bytes, types: str='ifs', endian: Optional[str]=None, force: bool=False): # pragma: no cover """ Shows a data block as various types Parameters ---------- data : bytes the binary string bytes types : str; default='ifs' i - int f - float s - string d - double (float64; 8 bytes) q - long long (int64; 8 bytes) l - long (int; 4 bytes) I - unsigned int (int; 4 bytes) L - unsigned long (int; 4 bytes) Q - unsigned long long (int; 8 bytes) endian : str; default=None -> auto determined somewhere else in the code the big/little endian {>, <} force : bool; default=False overwrite the n=2000 limiter .. warning:: 's' is apparently not Python 3 friendly """ #ifsdqlILQ return self._write_data(sys.stdout, data, types=types, endian=endian, force=force)
def _write_data(self, f, data: bytes, types: str='ifs', endian: Optional[str]=None, force: bool=False): # pragma: no cover """ Useful function for seeing what's going on locally when debugging. Parameters ---------- data : bytes the binary string bytes types : str; default='ifs' i - int f - float s - string d - double (float64; 8 bytes) q - long long (int64; 8 bytes) l - long (int; 4 bytes) I - unsigned int (int; 4 bytes) L - unsigned long (int; 4 bytes) Q - unsigned long long (int; 8 bytes) endian : str; default=None -> auto determined somewhere else in the code the big/little endian {>, <} force : bool; default=False overwrite the n=2000 limiter """ n = len(data) if not force and n > 2000: self.log.warning(f'limiting n={n} to 2000') n = 2000 nints = n // 4 ndoubles = n // 8 strings = None ints = None floats = None longs = None if endian is None: endian = self._uendian assert endian is not None, endian f.write(f'\nndata = {n}:\n') for typei in types: assert typei in 'sifdq lILQ', f'type={typei!r} is invalid; use sifdq lILQ' data4 = data[:nints * 4] #data8 = data[:ndoubles * 8] if 's' in types: strings = unpack('%s%is' % (endian, n), data[:n]) f.write(" strings = %s\n" % str(strings)) if 'i' in types: ints = unpack('%s%ii' % (endian, nints), data4) f.write(" ints = %s\n" % str(ints)) if 'f' in types: floats = unpack('%s%if' % (endian, nints), data4) f.write(" floats = %s\n" % str(floats)) if 'd' in types: doubles = unpack('%s%id' % (endian, ndoubles), data[:ndoubles*8]) f.write(" doubles (float64) = %s\n" % str(doubles)) if 'l' in types: longs = unpack('%s%il' % (endian, nints), data4) f.write(" long = %s\n" % str(longs)) if 'I' in types: ints2 = unpack('%s%iI' % (endian, nints), data4) f.write(" unsigned int = %s\n" % str(ints2)) if 'L' in types: longs2 = unpack('%s%iL' % (endian, nints), data4) f.write(" unsigned long = %s\n" % str(longs2)) if 'q' in types: longs = unpack('%s%iq' % (endian, ndoubles), data[:ndoubles*8]) f.write(" long long (int64) = %s\n" % str(longs)) if 'Q' in types: longs = unpack('%s%iq' % (endian, ndoubles), data[:ndoubles*8]) f.write(" unsigned long long (int64) = %s\n" % str(longs)) f.write('\n') return strings, ints, floats
[docs] def show_ndata(self, n: int, types: str='ifs'): # pragma: no cover return self._write_ndata(sys.stdout, n, types=types)
def _write_ndata(self, f, n: int, types: str='ifs'): # pragma: no cover """Useful function for seeing what's going on locally when debugging.""" op2 = self.op2 nold = op2.n data = op2.f.read(n) op2.n = nold op2.f.seek(op2.n) return self._write_data(f, data, types=types)
[docs]def grids_comp_array_to_index(grids1, comps1, grids2, comps2, make_matrix_symmetric: bool) -> Tuple[Any, Any, int, int, int]: """ Maps the dofs Returns ------- ja : ??? ??? jb : ??? ??? nja : ??? ??? njb : ??? ??? nj : ??? ??? """ #from pyNastran.femutils.utils import unique2d ai = np.vstack([grids1, comps1]).T bi = np.vstack([grids2, comps2]).T #print('grids2 =', grids2) #print('comps2 =', comps2) #c = np.vstack([a, b]) #assert c.shape[1] == 2, c.shape #urows = unique2d(c) #urows = c nid_comp_to_dof_index = {} j = 0 a_keys = set() for nid_dof in ai: #nid_dof = (int(nid), int(dof)) nid_dof = tuple(nid_dof) if nid_dof not in a_keys: a_keys.add(nid_dof) if nid_dof not in nid_comp_to_dof_index: nid_comp_to_dof_index[nid_dof] = j j += 1 nja = len(a_keys) del a_keys b_keys = set() for nid_dof in bi: nid_dof = tuple(nid_dof) if nid_dof not in b_keys: b_keys.add(nid_dof) if nid_dof not in nid_comp_to_dof_index: nid_comp_to_dof_index[nid_dof] = j j += 1 njb = len(b_keys) del b_keys nj = len(nid_comp_to_dof_index) if make_matrix_symmetric: ja = np.zeros(nj, dtype='int32') for i, nid_dof in zip(count(), ai): j[i] = nid_comp_to_dof_index[tuple(nid_dof)] for i, nid_dof in zip(count(), bi): j[i] = nid_comp_to_dof_index[tuple(nid_dof)] return j, j, nj, nj, nj else: ja = np.zeros(grids1.shape, dtype='int32') for i, nid_dof in zip(count(), ai.tolist()): ja[i] = nid_comp_to_dof_index[tuple(nid_dof)] jb = np.zeros(grids2.shape, dtype='int32') for i, nid_dof in zip(count(), bi.tolist()): jb[i] = nid_comp_to_dof_index[tuple(nid_dof)] return ja, jb, nja, njb, nj
[docs]def eqexin_to_nid_dof_doftype(eqexin1, eqexin2) -> Tuple[Any, Any, Any]: """assemble dof table""" dof = eqexin2[1::2] // 10 doftype = eqexin2[1::2] - 10 * dof nid = eqexin2[::2] # eqexin is in external sort, so sort it i = eqexin1[1::2].argsort() dof = dof[i] doftype = doftype[i] nid = nid[i] return nid, dof, doftype
[docs]def get_table_size_from_ncolumns(table_name: str, nvalues: int, ncolumns: int) -> int: nrows = nvalues // ncolumns if nvalues % ncolumns != 0: msg = 'table=%s: nrows=nvalues/ncolumns=%s/%s=%s; nrows=%s must be an int' % ( table_name, nvalues, ncolumns, nrows, nvalues / ncolumns) raise RuntimeError(msg) return nrows
[docs]def dscmcol_dresp1(responses: Dict[int, Dict[str, Any]], nresponses_dresp1: int, ints, floats) -> None: """helper for DSCMCOL""" idata = 0 if nresponses_dresp1 == 0: return for iresp in range(nresponses_dresp1): # Record – Type 1 Responses # 1 IRID I Internal response identification number # 2 RID I External response identification number # 3 RTYPE I Response Type # RTYPE=3 Buckling # 4 MODE I Mode number # 5 UNDEF None # 6 SUBCASE I Subcase identification number # 7 UNDEF(2) None # 9 SEID I Superelement identification number # RTYPE=8 Static force # 4 EID I Element identification number # 5 COMP I Force component number # 6 SUBCASE I Subcase identification number # 7 UNDEF None # 8 VIEWID I View element identification number # 9 SEID I Superelement identification number # RTYPE=10 Composite stress # 4 EID I Element identification number # 5 COMP I Stress component number # 6 SUBCASE I Subcase identification number # 7 UNDEF None # 8 PLY I Ply number # 9 SEID I Superelement identification number # RTYPE=13 Static SPC force # 4 GRID I Grid identification number # 5 COMP I SPC force component number # 6 SUBCASE I Subcase identification number # 7 UNDEF(2) None # 9 SEID I Superelement identification number # RTYPE=14 Element static strain energy # 4 EID I Element identification number # 5 COMP I Strain energy component number # 6 SUBCASE I Subcase identification number # 7 UNDEF(2) None # 9 SEID I Superelement identification number # RTYPE=17 Compliance # 4 UNDEF(2) None # 6 SUBCASE I Subcase identification number # 7 UNDEF(3) None # RTYPE=21 Frequency response velocity # 4 GRID I Grid identification number # 5 COMP I Velocity component number # 6 SUBCASE I Subcase identification number # 7 FREQ RS Frequency # 8 UNDEF None # 9 SEID I Superelement identification number # RTYPE=22 Frequency response acceleration # 4 GRID I Grid identification number # 5 COMP I Acceleration component number # 6 SUBCASE I Subcase identification number # 7 FREQ RS Frequency # 8 UNDEF None # 9 SEID I Superelement identification number # RTYPE=23 Frequency response SPC Force # 4 GRID I Grid identification number # 5 COMP I SPC Force component number # 6 SUBCASE I Subcase identification number # 7 FREQ RS Frequency # 8 UNDEF None # 9 SEID I Superelement identification number # RTYPE=24 Frequency response stress # 4 EID I Element identification number # 5 COMP I Stress component number # 6 SUBCASE I Subcase identification number # 7 FREQ RS Frequency # 8 UNDEF None # 9 SEID I Superelement identification number # RTYPE=25 Frequency response force # 4 EID I Element identification number # 5 COMP I Force component number # 6 SUBCASE I Subcase identification number # 7 FREQ RS Frequency # 8 UNDEF None # 9 SEID I Superelement identification number # RTYPE=26 RMS displacement # 4 GRID I Grid identification number # 5 COMP I RMS displacement component number # 6 SUBCASE I Subcase identification number # 7 UNDEF None # 8 RANDPS I RANDPS ID # 9 SEID I Superelement identification number # RTYPE=27 RMS velocity # 4 GRID I Grid identification number # 5 COMP I RMS velocity component number # 6 SUBCASE I Subcase identification number # 7 UNDEF None # 8 RANDPS I RANDPS ID # 9 SEID I Superelement identification number # RTYPE=28 RMS acceleration # 4 GRID I Grid identification number # 5 COMP I RMS acceleration component number # 6 SUBCASE I Subcase identification number # 7 UNDEF None # 8 RANDPS I RANDPS ID # 9 SEID I Superelement identification number # RTYPE=30 PSD velocity # 4 GRID I Grid identification number # 5 COMP I PSD velocity component number # 6 SUBCASE I Subcase identification number # 7 FREQ RS Frequency # 8 RANDPS I RANDPS ID # 9 SEID I Superelement identification number # RTYPE=60 Transient response displacement # 4 GRID I Grid identification number # 5 COMP I Displacement component number # 6 SUBCASE I Subcase identification number # 7 TIME RS Time # 8 UNDEF None # 9 SEID I Superelement identification number # RTYPE=61 Transient response velocity # 4 GRID I Grid identification number # 5 COMP I Velocity component number # 6 SUBCASE I Subcase identification number # 7 TIME RS Time # 8 UNDEF None # 9 SEID I Superelement identification number # RTYPE=62 Transient response acceleration # 4 GRID I Grid identification number # 5 COMP I Acceleration component number # 6 SUBCASE I Subcase identification number # 7 TIME RS Time # 8 UNDEF None # 9 SEID I Superelement identification number # RTYPE=63 Transient response SPC Force # 4 GRID I Grid identification number # 5 COMP I SPC force component number # 6 SUBCASE I Subcase identification number # 7 TIME RS Time # 8 UNDEF None # 9 SEID I Superelement identification number # RTYPE=64 Transient response stress # 4 EID I Element identification number # 5 COMP I Stress component number # 6 SUBCASE I Subcase identification number # 7 TIME RS Time # 8 UNDEF None # 9 SEID I Superelement identification number # RTYPE=65 Transient response force # 4 EID I Element identification number # 5 COMP I Force component number # 6 SUBCASE I Subcase identification number # 7 TIME RS Time # 8 UNDEF None # 9 SEID I Superelement identification number # RTYPE=81 Aeroelastic divergence # 4 SUBCASE I Subcase identification number # 5 UNDEF None # 6 ROOT I Root # 7 MACH RS Mach number # 8 UNDEF None # 9 SEID I Superelement identification number # RTYPE=82 Aeroelastic trim # 4 SUBCASE I Subcase identification number # 5 UNDEF None # 6 XID I XID # 7 UNDEF(2) None # 9 SEID I Superelement identification number # RTYPE=83 Aeroelastic stability derivative # 4 SUBCASE I Subcase identification number # 5 RU I R/U # 6 COMP I Component number # 7 UNDEF None # 8 XID I XID # 9 SEID I Superelement identification number # RTYPE=84 Aeroelastic flutter damping # 4 SUBCASE I Subcase identification number # 5 MODE I Mode number # 6 DENSITY RS Density # 7 MACH RS Mach number # 8 VEL RS Velocity # 9 SEID I Superelement identification number # End RTYPE internal_response_id = ints[idata] external_response_id = ints[idata+1] response_type = ints[idata+2] #print(f'internal_response_id={internal_response_id} ' #f'external_response_id={external_response_id} response_type={response_type}') if response_type == 1: # RTYPE=1 Weight # 4 UNDEF(5) None # 9 SEID I Superelement identification number seid = ints[idata+8] response = {'name': 'weight', 'seid': seid} #print(f' seid={seid} (weight)') elif response_type == 2: # RTYPE=2 Volume # 4 UNDEF(5) None # 9 SEID I Superelement identification number seid = ints[idata+8] response = {'name': 'volume', 'seid': seid} #print(f' seid={seid} (volume)') elif response_type == 4: # RTYPE=4 Normal modes # 4 MODE I Mode number # 5 UNDEF None # 6 SUBCASE I Subcase identification number # 7 UNDEF(2) None # 9 SEID I Superelement identification number mode_num = ints[idata+3] # blank subcase = ints[idata+5] seid = ints[idata+8] response = {'name': 'normal modes', 'mode_num': mode_num, 'subcase': subcase, 'seid': seid} #print(f' mode_num={mode_num} subcase={subcase} seid={seid} (normal modes)') elif response_type == 5: # RTYPE=5 Static displacement # 4 GRID I Grid identification number # 5 COMP I Displacement component number # 6 SUBCASE I Subcase identification number # 7 UNDEF(2) None # 9 SEID I Superelement identification number grid = ints[idata+3] comp = ints[idata+4] subcase = ints[idata+5] seid = ints[idata+8] response = {'name': 'static displacement', 'grid': grid, 'component': comp, 'subcase': subcase, 'seid': seid} #print(f' grid={grid} comp={comp} subcase={subcase} seid={seid} (static displacement)') elif response_type == 6: # RTYPE=6 Static stress # 4 EID I Element identification number # 5 COMP I Stress component number # 6 SUBCASE I Subcase identification number # 7 UNDEF(2) None # 9 SEID I Superelement identification number eid = ints[idata+3] comp = ints[idata+4] subcase = ints[idata+5] seid = ints[idata+8] response = {'name': 'static stress', 'eid': eid, 'component': comp, 'subcase': subcase, 'seid': seid} #print(f' eid={eid} comp={comp} subcase={subcase} seid={seid} (static stress)') elif response_type == 7: # RTYPE=7 Static strain # 4 EID I Element identification number # 5 COMP I Strain component number # 6 SUBCASE I Subcase identification number # 7 UNDEF None # 8 VIEWID I View element identification number # 9 SEID I Superelement identification number eid = ints[idata+3] comp = ints[idata+4] subcase = ints[idata+5] view_id = ints[idata+7] seid = ints[idata+8] response = {'name': 'static strain', 'eid': eid, 'component': comp, 'subcase': subcase, 'view id': view_id, 'seid': seid} #print(f' eid={eid} comp={comp} subcase={subcase} view_id={view_id} seid={seid} (static strain)') elif response_type == 9: # RTYPE=9 Composite failure # 4 EID I Element identification number # 5 COMP I Failure component number # 6 SUBCASE I Subcase identification number # 7 UNDEF None # 8 PLY I Ply number # 9 SEID I Superelement identification number eid = ints[idata+3] comp = ints[idata+4] subcase = ints[idata+5] ply = ints[idata+7] seid = ints[idata+8] response = {'name': 'composite failure', 'eid': eid, 'component': comp, 'subcase': subcase, 'ply': ply, 'seid': seid} #print(f' eid={eid} comp={comp} subcase={subcase} ply={ply} seid={seid} (composite failure)') elif response_type == 11: # RTYPE=11 Composite strain # 4 EID I Element identification number # 5 COMP I Strain component number # 6 SUBCASE I Subcase identification number # 7 UNDEF None # 8 PLY I Ply number # 9 SEID I Superelement identification number eid = ints[idata+3] comp = ints[idata+4] subcase = ints[idata+5] ply = ints[idata+7] seid = ints[idata+8] response = {'name': 'composite strain', 'eid': eid, 'component': comp, 'subcase': subcase, 'ply': ply, 'seid': seid} #print(f' eid={eid} comp={comp} subcase={subcase} ply={ply} seid={seid} (composite strain)') elif response_type == 15: # CEIG mode_num = ints[idata+3] subcase = ints[idata+5] seid = ints[idata+8] #print(ints[idata+4:idata+9]) #print(floats[idata+4:idata+9]) #print(f'internal_response_id={internal_response_id} ' #f'external_response_id={external_response_id} response_type={response_type}') #print(f' mode_num={mode_num} subcase={subcase} seid={seid} (CEIG)') response = {'name': 'ceig', 'mode_num': mode_num, 'subcase': subcase, 'seid': seid} elif response_type == 19: # RTYPE=19 Equivalent radiated power # 4 PANEL I Element identification number # 5 FLAG I A subcase ID based code. +: magnitude; –:density # 6 SUBCASE I Subcase identification number # 7 FREQUENCY RS Frequency # 8 UNDEF None # 9 SEID I Superelement identification number panel = ints[idata+3] flag = ints[idata+4] subcase = ints[idata+5] freq = floats[idata+6] seid = ints[idata+8] response = {'name': 'equivalent radiated power', 'panel': panel, 'flag': flag, 'subcase': subcase, 'freq': freq, 'seid': seid} #print(f' panel={panel} flag={flag} subcase={subcase} freq={freq} seid={seid} ' #'(equivalent radiated power)') elif response_type == 20: # RTYPE=20 Frequency response displacement # 4 GRID I Grid identification number # 5 COMP I Displacement component number # 6 SUBCASE I Subcase identification number # 7 FREQ RS Frequency # 8 UNDEF None # 9 SEID I Superelement identification number grid = ints[idata+3] comp = ints[idata+4] subcase = ints[idata+5] freq = floats[idata+6] ply = ints[idata+7] unused_freq8 = floats[idata+7] # also freq despite DMAP saying this is unused... seid = ints[idata+8] response = {'name': 'frequency response displacement', 'grid': grid, 'component': comp, 'subcase': subcase, 'ply': ply, 'seid': seid} #print(f' grid={grid} comp={comp} subcase={subcase} freq={freq} ' #f'ply={ply} seid={seid} (frequency response displacement)') elif response_type == 21: # RTYPE=21 frequency response stress??? # 4 GRID I Grid identification number # 5 COMP I Displacement component number # 6 SUBCASE I Subcase identification number # 7 FREQ RS Frequency # 8 UNDEF None # 9 SEID I Superelement identification number grid = ints[idata+3] comp = ints[idata+4] subcase = ints[idata+5] freq = floats[idata+6] #sixI = ints[idata+6] ply = ints[idata+7] seid = ints[idata+8] response = {'name': 'frequency response stress?', 'grid': grid, 'component': comp, 'subcase': subcase, 'ply': ply, 'seid': seid} #print(f' grid={grid} comp={comp} subcase={subcase} freq={freq} ' #f'ply={ply} seid={seid} (frequency response stress?)') elif response_type == 29: # RTYPE=29 PSD displacement # 4 GRID I Grid identification number # 5 COMP I PSD displacement component number # 6 SUBCASE I Subcase identification number # 7 FREQ RS Frequency # 8 RANDPS I RANDPS ID # 9 SEID I Superelement identification number grid = ints[idata+3] comp = ints[idata+4] subcase = ints[idata+5] freq = floats[idata+6] randps = ints[idata+7] seid = ints[idata+8] response = {'name': 'psd displacement', 'grid': grid, 'component': comp, 'subcase': subcase, 'freq': freq, 'randps': randps, 'seid': seid} #print(f' grid={grid} comp={comp} subcase={subcase} freq={freq} ' #f'randps={randps} seid={seid} (PSD displacement)') elif response_type == 31: # RTYPE=31 PSD acceleration # 4 GRID I Grid identification number # 5 COMP I PSD acceleration component number # 6 SUBCASE I Subcase identification number # 7 FREQ RS Frequency # 8 RANDPS I RANDPS ID # 9 SEID I Superelement identification number grid = ints[idata+3] comp = ints[idata+4] subcase = ints[idata+5] freq = floats[idata+6] randps = ints[idata+7] seid = ints[idata+8] response = {'name': 'psd acceleration', 'grid': grid, 'component': comp, 'subcase': subcase, 'freq': freq, 'randps': randps, 'seid': seid} #print(f' grid={grid} comp={comp} subcase={subcase} freq={freq} ' #f'randps={randps} seid={seid} (PSD acceleration)') else: # pragma: no cover print(f'internal_response_id={internal_response_id} ' f'external_response_id={external_response_id} response_type={response_type}') raise NotImplementedError(response_type) response['internal_response_id'] = internal_response_id response['external_response_id'] = external_response_id response['response_type'] = response_type response['iresponse'] = iresp response['response_number'] = 1 responses[iresp] = response idata += 9 return
[docs]def dscmcol_dresp2(responses: Dict[int, Dict[str, Any]], nresponses_dresp2: int, ints, floats) -> None: """helper for DSCMCOL""" if nresponses_dresp2 == 0: return nresponses = len(responses) idata = 0 for iresp in range(nresponses_dresp2): # Word Name Type Description # 1 IRID I Internal response identification number # 2 RID I External response identification number # 3 SUBCASE I Subcase identification number # 4 DFLAG I Dynamic response flag (See Note) # 5 FREQTIME RS Frequency or time step # 6 SEID I Superelement identification number internal_response_id = ints[idata] external_response_id = ints[idata+1] subcase = ints[idata+2] dflag = ints[idata+3] freqtime = floats[idata+4] seid = ints[idata+5] iresp2 = iresp + nresponses response = { 'iresponse': iresp2, 'response_number': 2, 'internal_response_id': internal_response_id, 'external_response_id': external_response_id, 'subcase': subcase, 'dflag': dflag, 'freq': freqtime, 'seid': seid} responses[iresp2] = response #print(f'internal_response_id={internal_response_id} ' #f'external_response_id={external_response_id} ' #f'subcase={subcase} dflag={dflag} freq/time={freqtime} seid={seid}') idata += 6 return
def _parse_nastran_version(data: bytes, version: bytes, encoding: bytes, log: SimpleLogger) -> str: """parses a Nastran version string""" if len(data) == 32: #self.show_data(data[:16], types='ifsdqlILQ', endian=None) #self.show_data(data[16:], types='ifsdqlILQ', endian=None) if data[:16].strip() in MSC_LONG_VERSION: # 'XXXXXXXX20140 0 \x00\x00\x00\x00 ' # 'XXXXXXXX20141 0 \x00\x00\x00\x00 ' mode = 'msc' else: raise NotImplementedError(f'check={data[:16].strip()} data={data!r}; ' f'len(data)={len(data)}') elif len(data) == 8: mode = _parse_nastran_version_8(data, version, encoding, log) elif len(data) == 16: mode = _parse_nastran_version_16(data, version, encoding, log) else: raise NotImplementedError(f'version={version!r}; n={len(data)}') return mode def _parse_nastran_version_16(data: bytes, version: bytes, encoding: str, log) -> str: """parses an 8 character version string""" if version in [b'NX20 19.0', b'NX20 19.1', b'NX20 19.2']: mode = 'nx' else: raise RuntimeError(f'unknown version={version}') return mode def _parse_nastran_version_8(data: bytes, version: bytes, encoding: str, log) -> str: """parses an 8 character version string""" if version.startswith(b'NX'): mode = 'nx' version_str = version[2:].strip().decode(encoding) if version_str not in NX_VERSIONS: log.warning(f'nx version={version_str!r} is not supported') elif version.startswith(b'MODEP'): # TODO: why is this separate? # F:\work\pyNastran\pyNastran\master2\pyNastran\bdf\test\nx_spike\out_ac11103.op2 #print('found NX table?...') #log.warning('Assuming NX Nastran') mode = 'nx' elif version.startswith(b'AEROFREQ'): # TODO: why is this separate? # C:\Users\Steve\Dropbox\pyNastran_examples\move_tpl\loadf.op2 #print('found MSC table?...') #log.warning('Assuming MSC Nastran') mode = 'msc' elif version.startswith(b'AEROTRAN'): # TODO: why is this separate? # C:\Users\Steve\Dropbox\pyNastran_examples\move_tpl\loadf.op2 #log.warning('Assuming MSC Nastran') mode = 'msc' elif version in [b'V2005R3B']: mode = 'msc' elif version in [b'XXXXXXXX']: #log.warning('Assuming MSC Nastran') mode = 'msc' elif version in OPTISTRUCT_VERSIONS: # should this be called optistruct or radioss? mode = 'optistruct' #elif data[:20] == b'XXXXXXXX20141 0 ': #self.set_as_msc() #self.set_table_type() else: raise RuntimeError(f'unknown version={version!r}') return mode
[docs]def reshape_bytes_block(block: bytes) -> bytes: nwords = len(block) // 2 block2 = b''.join([block[8*i:8*i+4] for i in range(nwords)]) return block2
[docs]def reshape_bytes_block_size(name_bytes: bytes, size: int=4) -> bytes: if size == 4: name_str = name_bytes.decode('latin1').rstrip() else: name_str = reshape_bytes_block(name_bytes).decode('latin1').rstrip() return name_str
[docs]def reshape_bytes_block_strip(name_bytes: bytes, size: int=4) -> str: if size == 4: name_str = name_bytes.decode('latin1').strip() else: name_str = reshape_bytes_block(name_bytes).decode('latin1').strip() return name_str
[docs]def mapfmt(fmt: bytes, size: int) -> bytes: if size == 4: return fmt return fmt.replace(b'i', b'q').replace(b'f', b'd')
[docs]def mapfmt_str(fmt: bytes, size: int) -> bytes: if size == 4: return fmt return fmt.replace('i', 'q').replace('f', 'd')
[docs]def update_op2_datacode(op2, data_code_old): op2.data_code = data_code_old for key, value in data_code_old.items(): if key == 'size': continue setattr(op2, key, value)