#pylint: disable=C0326,C0301
from __future__ import annotations
from typing import TYPE_CHECKING
from struct import Struct
import numpy as np
from pyNastran.op2.tables.utils import get_is_slot_saved, get_eid_dt_from_eid_device
from pyNastran.op2.tables.oee_energy.oee_objects import (
RealStrainEnergyArray, ComplexStrainEnergyArray,
RealKineticEnergyArray,)
from pyNastran.op2.op2_interface.op2_reader import mapfmt, reshape_bytes_block
if TYPE_CHECKING: # pragma: no cover
from pyNastran.op2.op2 import OP2
RESULT_NAME_MAP = {
'BAR': 'cbar',
'BEAM': 'cbeam',
'BEND': 'cbend',
'BEAM3': 'cbeam3',
'ROD': 'crod',
'TUBE': 'ctube',
'CONROD': 'conrod',
'TRIA3': 'ctria3',
'TRIAFD': 'ctria3',
'TRIA3FD': 'ctria3',
'TRIA6': 'ctria6',
'TRIAX6': 'ctriax6',
'CTRIA6N': 'ctria6', # per JG
'TRIAR': 'ctriar',
'TRIAX3FD': 'ctriax',
'TRIAXFD': 'ctriax',
'QUAD4': 'cquad4',
'QUADFD': 'cquad4',
'QUAD4FD': 'cquad4',
'QUAD8': 'cquad8',
'CQUAD8N': 'cquad8', # guessed per JG
# TODO: this will probably be a problem someday...cquad8_nonlinear_strain_energy
'QUAD8N': 'cquad8',
'QUADR': 'cquadr',
'QUADXFD': 'cquadx',
'QUADX4FD': 'cquadx',
'SHEAR': 'cshear',
'TETRA': 'ctetra',
'TETRAFD': 'ctetra',
'TETRA4FD': 'ctetra',
'PENTA': 'cpenta',
'PENTAFD': 'cpenta',
'PENTA6FD': 'cpenta',
'HEXA': 'chexa',
'HEXAFD': 'chexa',
'HEXA8FD': 'chexa',
'PYRAM': 'cpyram',
'PYRA': 'cpyram',
'GAP': 'cgap',
'BUSH': 'cbush',
'BUSH1D': 'cbush1d',
'BUSH2D': 'cbush2d',
'ELAS1': 'celas1',
'ELAS2': 'celas2',
'ELAS3': 'celas3',
'ELAS4': 'celas4',
'MASS1': 'cmass1',
'MASS2': 'cmass2',
'MASS3': 'cmass3',
'MASS4': 'cmass4',
'DUM8': 'cdum8',
'DMIG': 'dmig',
'GENEL': 'genel',
'CONM2': 'conm2',
'RBE1': 'rbe1',
'RBE3': 'rbe3',
'WELDP': 'cweld',
'WELDC': 'cweld',
'WELD': 'cweld',
'FASTP': 'cfast',
'SEAMP': 'cseam',
'CPLSTN3': 'cplstn3',
'CPLSTN4': 'cplstn4',
'CPLSTN6': 'cplstn6',
'CPLSTN8': 'cplstn8',
'CPLSTS3': 'cplsts3',
'CPLSTS4': 'cplsts4',
'CPLSTS6': 'cplsts6',
'CPLSTS8': 'cplsts8',
}
[docs]
class ONR:
def __init__(self, op2: OP2):
self.op2 = op2
#op2.words = None
#op2.num_wide = None
[docs]
def get_onr_prefix_postfix(self) -> tuple[str, str]:
"""
Creates the prefix/postfix that splits off ATO, CRM, PSD, nonlinear,
etc. results. We also fix some of the sort bits as typing:
STRESS(PLOT,SORT1,RALL) = ALL
will actually create the OESRMS2 table (depending on what else
is in your case control). However, it's in an OESATO2 table, so
we know it's really SORT2.
Also, if you're validating the sort_bit flags, *RMS2 and *NO2 are
actually SORT1 tables.
NX Case Control Block Description
=============== ========== ===========
NLSTRESS OESNLXR Nonlinear static stresses
BOUTPUT OESNLBR Slideline stresses
STRESS OESNLXD Nonlinear Transient Stresses
STRESS OES1C/OSTR1C Ply stresses/strains
STRESS OES1X Element stresses with intermediate (CBAR and CBEAM)
station stresses and stresses on nonlinear elements
STRESS OES/OESVM Element stresses (linear elements only)
STRAIN OSTR1 Element strains
STRESS/STRAIN DOES1/DOSTR1 Scaled Response Spectra
MODCON OSTRMC Modal contributions
"""
op2 = self.op2
#prefix = ''
postfix = ''
if op2.table_name in [b'ONRGY1', b'ONRGY2', b'ONRGY']:
prefix = 'strain_energy.'
elif op2.table_name in [b'OEKE1']:
prefix = 'kinetic_energy.'
elif op2.table_name in [b'RANEATC']: #, b'OSTRMS1C']:
op2.format_code = 1
op2.sort_bits[0] = 0 # real
prefix = 'RANEATC.'
elif op2.table_name in [b'RANCONS']: #, b'OSTRMS1C']:
op2.format_code = 1
op2.sort_bits[0] = 0 # real
prefix = 'RANCONS.'
else: # pragma: no cover
raise NotImplementedError(op2.table_name)
op2.data_code['sort_bits'] = op2.sort_bits
op2.data_code['nonlinear_factor'] = op2.nonlinear_factor
return prefix, postfix
def _read_onr1_3(self, data: bytes, ndata: int):
"""
reads ONRGY1 subtable 3
"""
op2 = self.op2
op2._analysis_code_fmt = b'i'
op2.words = [
'aCode', 'tCode', 'etotal', 'isubcase',
'???', '???', 'element_name', 'load_set',
'format_code', 'num_wide', 'cvalres', 'set_id',
'eign', 'eigr', 'eigi', 'rmssf',
'etotpos', 'etotneg', 'thresh', '???',
'???', '???', '???', '???',
'???', 'Title', 'subtitle', 'label']
#aCode = self.get_block_int_entry(data, 1)
## total energy of all elements in isubcase/mode
self.etotal = op2.parse_approach_code(data)
if op2.is_debug_file:
op2.binary_debug.flush()
self._onr_element_name(data)
#: Load set or zero
op2.load_set = op2.add_data_parameter(data, 'load_set', b'i', 8, False)
#: format code
op2.format_code = op2.add_data_parameter(data, 'format_code', b'i', 9, False)
#: number of words per entry in record
#: .. note:: is this needed for this table ???
op2.num_wide = op2.add_data_parameter(data, 'num_wide', b'i', 10, False)
## C
op2.cvalres = op2.add_data_parameter(data, 'cvalres', b'i', 11, False)
#: Set identification number Number
op2.set_id = op2.add_data_parameter(data, 'set_id', b'i', 13, False)
#: Natural eigenvalue - real part
#op2.eigen_real = op2.add_data_parameter(data, 'eigen_real', b'f', 14, False)
#: Natural eigenvalue - imaginary part
#op2.eigen_imag = op2.add_data_parameter(data, 'eigen_imag', b'f', 15, False)
#: Natural frequency
#op2.freq = op2.add_data_parameter(data, 'freq', b'f', 16, False)
#: RMS and CRMS scale factor - NX
op2.rmssf = op2.add_data_parameter(data, 'rmssf', b'f', 17)
#: Total positive energy
op2.etotpos = op2.add_data_parameter(data, 'etotpos', b'f', 18)
#: Total negative energy
op2.etotneg = op2.add_data_parameter(data, 'etotneg', b'f', 19, False)
#: Energy Threshold - NX
op2.thresh = op2.add_data_parameter(data, 'thresh', b'f', 17)
if not op2.is_sort1:
raise NotImplementedError('sort2...')
if op2.analysis_code == 1: # statics / displacement / heat flux
#del op2.data_code['nonlinear_factor']
op2.lsdvmn = op2.add_data_parameter(data, 'lsdvmn', b'i', 5, False)
op2.data_names = op2.apply_data_code_value('data_names', ['lsdvmn'])
op2.setNullNonlinearFactor()
elif op2.analysis_code == 2: # real eigenvalues
op2.mode = op2.add_data_parameter(data, 'mode', b'i', 5) ## mode number
op2.eign = op2.add_data_parameter(data, 'eign', b'f', 6, False)
op2.mode_cycle = op2.add_data_parameter(data, 'mode_cycle', b'f', 7, False) # radians
#self.show_data(data)
#print(f'mode={op2.mode} eign={op2.eign} mode_cycle={op2.mode_cycle}')
op2._op2_readers.reader_oug.update_mode_cycle('mode_cycle')
#print(f'{op2.isubcase}: mode={op2.mode} eign={op2.eign:g} mode_cycle={op2.mode_cycle:g}')
op2.data_names = op2.apply_data_code_value('data_names', ['mode', 'eign', 'mode_cycle'])
#print("mode(5)=%s eign(6)=%s mode_cycle(7)=%s" % (
#op2.mode, self.eign, op2.mode_cycle))
#elif op2.analysis_code == 3: # differential stiffness
#op2.lsdvmn = self.get_values(data,'i',5) ## load set number
#op2.data_code['lsdvmn'] = op2.lsdvmn
#elif op2.analysis_code == 4: # differential stiffness
#op2.lsdvmn = self.get_values(data,'i',5) ## load set number
elif op2.analysis_code == 5: # frequency
op2.freq = op2.add_data_parameter(data, 'freq', b'f', 5) ## frequency
op2.data_names = op2.apply_data_code_value('data_names', ['freq'])
elif op2.analysis_code == 6: # transient
op2.time = op2.add_data_parameter(data, 'time', b'f', 5) ## time step
op2.data_names = op2.apply_data_code_value('data_names', ['time'])
#elif op2.analysis_code == 7: # pre-buckling
#op2.data_names = op2.apply_data_code_value('data_names',['lsdvmn'])
elif op2.analysis_code == 8: # post-buckling
op2.mode = op2.add_data_parameter(data, 'mode', b'i', 5) ## mode number
op2.data_names = op2.apply_data_code_value('data_names', ['mode'])
elif op2.analysis_code == 9: # complex eigenvalues
op2.mode = op2.add_data_parameter(data, 'mode', b'i', 5) ## mode number
op2.eigr = op2.add_data_parameter(data, 'eigr', b'f', 14, False)
op2.eigi = op2.add_data_parameter(data, 'eigi', b'f', 15, False)
op2.data_names = op2.apply_data_code_value('data_names', ['mode', 'eigr', 'eigi'])
elif op2.analysis_code == 10: # nonlinear statics
self.load_factor = op2.add_data_parameter(data, 'load_factor', b'f', 5) ## load factor
op2.data_names = op2.apply_data_code_value('data_names', ['load_factor'])
#elif op2.analysis_code == 11: # old geometric nonlinear statics
#op2.data_names = op2.apply_data_code_value('data_names',['lsdvmn'])
elif op2.analysis_code == 12: # contran ? (may appear as aCode=6) --> straight from DMAP...grrr...
op2.time = op2.add_data_parameter(data, 'time', b'f', 5) ## time step
op2.data_names = op2.apply_data_code_value('data_names', ['time'])
else: # pragma: no cover
raise RuntimeError('invalid analysis_code...analysis_code=%s' %
op2.analysis_code)
op2.fix_format_code()
if op2.is_debug_file:
op2.binary_debug.write(' approach_code = %r\n' % op2.approach_code)
op2.binary_debug.write(' tCode = %r\n' % op2.tCode)
op2.binary_debug.write(' isubcase = %r\n' % op2.isubcase)
op2._read_title(data)
op2._write_debug_bits()
def _onr_element_name(self, data: bytes) -> None:
op2 = self.op2
#field_num = 6
#datai = data[4 * (field_num - 1) : 4 * (field_num + 1)]
#assert len(datai) == 8, len(datai)
#print(4 * (field_num - 1), 4 * (field_num + 1))
#element_name, = op2.struct_8s.unpack(data[24:32]) # changed on 11/30/2015; was this for a long time...
#self.show_data(data[:28])
if op2.size == 4:
element_name, = op2.struct_8s.unpack(data[20:28])
else:
element_name, = op2.struct_16s.unpack(data[40:56])
element_name = reshape_bytes_block(element_name)
#print("element_name = %s" % (element_name))
try:
element_name = element_name.decode('utf-8').strip() # element name
except UnicodeDecodeError:
#self.log.warning("element_name = %s" % str(element_name))
op2.log.warning("element_name - UnicodeDecodeError")
#self.show_data(data)
raise
if element_name.isalnum():
op2.data_code['element_name'] = element_name
else:
#print("element_name = %r" % (element_name))
op2.data_code['element_name'] = 'UnicodeDecodeError???'
op2.log.warning('data[20:28]=%r instead of data[24:32]' % data[20:28])
def _read_onr2_3(self, data: bytes, ndata: int):
"""reads the SORT2 version of table 4 (the data table)"""
op2 = self.op2
op2.nonlinear_factor = np.nan
op2.is_table_1 = False
op2.is_table_2 = True
op2.parse_approach_code(data)
op2.words = [
'aCode', 'tCode', 'etotal', 'isubcase',
'???', '???', 'element_name', 'load_set',
'format_code', 'num_wide', 'cvalres', 'set_id',
'eign', 'eigr', 'eigi', 'rmssf',
'etotpos', 'etotneg', 'thresh', '???',
'???', '???', '???', '???',
'???', 'Title', 'subtitle', 'label']
self._onr_element_name(data)
#: Load set or zero
op2.load_set = op2.add_data_parameter(data, 'load_set', b'i', 8, False)
#: format code
op2.format_code = op2.add_data_parameter(data, 'format_code', b'i', 9, False)
#: number of words per entry in record
#: .. note:: is this needed for this table ???
op2.num_wide = op2.add_data_parameter(data, 'num_wide', b'i', 10, False)
## C
op2.cvalres = op2.add_data_parameter(data, 'cvalres', b'i', 11, False)
#: Set identification number Number
op2.set_id = op2.add_data_parameter(data, 'set_id', b'i', 13, False)
#: Natural eigenvalue - real part
#op2.eigen_real = op2.add_data_parameter(data, 'eigen_real', b'f', 14, False)
#: Natural eigenvalue - imaginary part
#op2.eigen_imag = op2.add_data_parameter(data, 'eigen_imag', b'f', 15, False)
#: Natural frequency
op2.freq = op2.add_data_parameter(data, 'freq', b'f', 16, False)
#: RMS and CRMS scale factor - NX
op2.rmssf = op2.add_data_parameter(data, 'rmssf', b'f', 17)
#: Total positive energy
op2.etotpos = op2.add_data_parameter(data, 'etotpos', b'f', 18)
#: Total negative energy
op2.etotneg = op2.add_data_parameter(data, 'etotneg', b'f', 19, False)
#: Energy Threshold - NX
op2.thresh = op2.add_data_parameter(data, 'thresh', b'f', 17)
op2.element_id = op2.add_data_parameter(data, 'node_id', b'i', 5, fix_device_code=True)
#if op2.analysis_code == 1: # statics / displacement / heat flux
## load set number
#op2.lsdvmn = op2.add_data_parameter(data, 'lsdvmn', b'i', 5, False)
#op2.data_names = op2.apply_data_code_value('data_names', ['node_id'])
#op2.setNullNonlinearFactor()
if op2.analysis_code == 1: # static...because reasons.
op2._analysis_code_fmt = b'i'
op2.data_names = op2.apply_data_code_value('data_names', ['node_id'])
op2.apply_data_code_value('analysis_method', 'N/A')
elif op2.analysis_code == 2: # real eigenvalues
## mode number
op2.mode = op2.add_data_parameter(data, 'mode', b'i', 5)
op2._analysis_code_fmt = b'i'
## real eigenvalue
op2.eigr = op2.add_data_parameter(data, 'eign', b'f', 6, False)
op2.mode_cycle = op2.add_data_parameter(data, 'mode_cycle', b'f', 7, False)
op2.data_names = op2.apply_data_code_value('data_names',
['node_id', 'eign', 'mode_cycle'])
op2.apply_data_code_value('analysis_method', 'mode')
#elif op2.analysis_code == 3: # differential stiffness
#op2.lsdvmn = self.get_values(data, b'i', 5) ## load set number
#op2.data_names = op2.data_code['lsdvmn'] = op2.lsdvmn
#elif op2.analysis_code == 4: # differential stiffness
#op2.lsdvmn = self.get_values(data, b'i', 5) ## load set number
elif op2.analysis_code == 5: # frequency
## frequency
#op2.freq = op2.add_data_parameter(data, 'freq', b'f', 5)
op2._analysis_code_fmt = b'f'
op2.data_names = op2.apply_data_code_value('data_names', ['node_id'])
op2.apply_data_code_value('analysis_method', 'freq')
elif op2.analysis_code == 6: # transient
## time step
#op2.dt = op2.add_data_parameter(data, 'dt', b'f', 5)
op2._analysis_code_fmt = b'f'
op2.data_names = op2.apply_data_code_value('data_names', ['node_id'])
op2.apply_data_code_value('analysis_method', 'dt')
elif op2.analysis_code == 7: # pre-buckling
## load set number
#op2.lsdvmn = op2.add_data_parameter(data, 'lsdvmn', b'i', 5)
op2._analysis_code_fmt = b'i'
op2.data_names = op2.apply_data_code_value('data_names', ['node_id'])
op2.apply_data_code_value('analysis_method', 'lsdvmn')
elif op2.analysis_code == 8: # post-buckling
## load set number
#op2.lsdvmn = op2.add_data_parameter(data, 'lsdvmn', b'i', 5)
op2._analysis_code_fmt = b'i'
## real eigenvalue
op2.eigr = op2.add_data_parameter(data, 'eigr', b'f', 6, False)
op2.data_names = op2.apply_data_code_value('data_names', ['node_id', 'eigr'])
op2.apply_data_code_value('analysis_method', 'eigr')
elif op2.analysis_code == 9: # complex eigenvalues
## mode number
op2.mode = op2.add_data_parameter(data, 'mode', b'i', 5)
op2._analysis_code_fmt = b'i'
## real eigenvalue
#op2.eigr = op2.add_data_parameter(data, 'eigr', b'f', 6, False)
## imaginary eigenvalue
op2.eigi = op2.add_data_parameter(data, 'eigi', b'f', 7, False)
op2.data_names = op2.apply_data_code_value('data_names', ['node_id', 'eigr', 'eigi'])
op2.apply_data_code_value('analysis_method', 'mode')
elif op2.analysis_code == 10: # nonlinear statics
## load step
#self.lftsfq = op2.add_data_parameter(data, 'lftsfq', b'f', 5)
op2._analysis_code_fmt = b'f'
op2.data_names = op2.apply_data_code_value('data_names', ['node_id'])
op2.apply_data_code_value('analysis_method', 'lftsfq')
elif op2.analysis_code == 11: # old geometric nonlinear statics
## load set number
#op2.lsdvmn = op2.add_data_parameter(data, 'lsdvmn', b'i', 5)
op2._analysis_code_fmt = b'f'
op2.data_names = op2.apply_data_code_value('data_names', ['node_id'])
elif op2.analysis_code == 12:
# contran ? (may appear as aCode=6) --> straight from DMAP...grrr...
## load set number
#op2.lsdvmn = op2.add_data_parameter(data, 'lsdvmn', b'i', 5)
op2._analysis_code_fmt = b'i'
op2.data_names = op2.apply_data_code_value('data_names', ['node_id'])
op2.apply_data_code_value('analysis_method', 'lsdvmn')
else: # pragma: no cover
msg = 'invalid analysis_code...analysis_code=%s' % op2.analysis_code
raise RuntimeError(msg)
op2.fix_format_code()
if op2.num_wide == 8:
op2.format_code = 1
op2.data_code['format_code'] = 1
else:
#op2.fix_format_code()
if op2.format_code == 1:
op2.format_code = 2
op2.data_code['format_code'] = 2
assert op2.format_code in [2, 3], op2.code_information()
if op2.is_debug_file:
op2.binary_debug.write(' approach_code = %r\n' % op2.approach_code)
op2.binary_debug.write(' tCode = %r\n' % op2.tCode)
op2.binary_debug.write(' isubcase = %r\n' % op2.isubcase)
op2._read_title(data)
op2._write_debug_bits()
def _read_onr1_4(self, data: bytes, ndata: int) -> int:
"""
reads ONRGY1 subtable 4
"""
op2 = self.op2
if op2.table_code == 18: # element strain energy
if op2.table_name not in [b'ONRGY', b'ONRGY1', b'ONRGY2']:
msg = f'table_name={op2.table_name} table_code={op2.table_code}'
raise NotImplementedError(msg)
n = self._read_element_strain_energy(data, ndata, result_name_suffix='_strain_energy')
elif op2.table_code == 36: # element kinetic energy
if op2.table_name not in [b'OEKE1']:
msg = f'table_name={op2.table_name} table_code={op2.table_code}'
raise NotImplementedError(msg)
n = self._read_element_strain_energy(data, ndata, result_name_suffix='_kinetic_energy')
else: # pragma: no cover
raise NotImplementedError(op2.table_code)
return n
def _read_element_strain_energy(self, data: bytes, ndata: int,
result_name_suffix: str) -> int:
"""
table_code = 19 : ONR/OEE - element strain energy density
table_code = 36 : EKE - element kinetic energy density
"""
op2 = self.op2
dt = op2.nonlinear_factor
n = 0
element_name = op2.data_code['element_name']
try:
result_name = RESULT_NAME_MAP[element_name]
except KeyError: # pragma: no cover
raise NotImplementedError(f'element_name1={element_name!r} element_name={op2.data_code["element_name"]!r}')
prefix, postfix = self.get_onr_prefix_postfix()
# strain_energy.cbar_strain_energy
# kinetic_energy.cbar_kinetic_energy
result_name = f'{prefix}{result_name}{result_name_suffix}{postfix}'
#result_name = 'strain_energy'
is_saved, slot = get_is_slot_saved(op2, result_name)
if not is_saved:
return ndata
if 'strain_energy' in result_name:
real_cls = RealStrainEnergyArray
complex_cls = ComplexStrainEnergyArray
elif 'kinetic_energy' in result_name:
real_cls = RealKineticEnergyArray
complex_cls = None
else:
raise NotImplementedError(result_name)
#auto_return = False
if op2.is_debug_file:
op2.binary_debug.write('cvalares = %s\n' % op2.cvalres)
factor = op2.factor
if op2.format_code in [1, 2] and op2.num_wide == 4:
assert op2.cvalres in [0, 1], op2.cvalres
assert op2.num_wide == 4
ntotal = 16 * factor # 4*4=16
nelements = ndata // ntotal
auto_return, is_vectorized = op2._create_oes_object4(
nelements, result_name, slot, real_cls)
if auto_return:
#if obj.dt_temp is None or obj.itime is None and obj.dt_temp == dt:
#element_name = op2.data_code['element_name']
#if element_name in obj.element_name_count:
#obj.element_name_count[element_name] += nelements
#else:
#obj.element_name_count[element_name] = nelements
#obj.dt_temp = dt
return nelements * ntotal
#itime = obj.itime #// obj.nelement_types
#op2.show_data(data, types='if')
obj = op2.obj
itime = obj.itime
if op2.is_debug_file:
op2.binary_debug.write(' [cap, element1, element2, ..., cap]\n')
op2.binary_debug.write(f' cap = {ndata:d} # assume 1 cap when there could have been multiple\n')
op2.binary_debug.write(' #elementi = [eid_device, energy, percent, density]\n')
op2.binary_debug.write(f' nelements={nelements:d}\n')
if op2.is_optistruct:
op2.use_vector = False
if op2.use_vector and op2.sort_method == 1: # and op2.is_sort1:
n = nelements * ntotal
ielement = obj.ielement
ielement2 = obj.ielement + nelements
itotal = obj.itotal
itotal2 = obj.itotal + nelements * 4
floats = np.frombuffer(data, dtype=op2.fdtype8).reshape(nelements, 4)
obj._times[itime] = dt
#if obj.itime == 0:
ints = np.frombuffer(data, dtype=op2.idtype8).reshape(nelements, 4)
eids = ints[:, 0] // 10
assert eids.min() > 0, f'etype={element_name} isubtable={op2.isubtable} eids.min()={eids.min()}'
obj.element[itime, ielement:ielement2] = eids
#[energy, percent, density]
obj.data[itime, ielement:ielement2, :] = floats[:, 1:].copy()
obj.itotal2 = itotal2
obj.ielement = ielement2
else:
n = real_strain_energy_4(op2, obj, data,
n, ntotal, nelements, dt)
elif op2.format_code == 1 and op2.num_wide == 5: # complex
assert op2.cvalres in [0, 1, 2], op2.cvalres # 0??
ntotal = 20 * factor
nnodes = ndata // ntotal
nelements = nnodes
auto_return, is_vectorized = op2._create_oes_object4(
nelements, result_name, slot, real_cls)
if auto_return:
return nelements * op2.num_wide * 4
obj = op2.obj
if op2.use_vector:
n = nelements * ntotal
itotal = obj.ielement
ielement2 = obj.itotal + nelements
itotal2 = ielement2
floats = np.frombuffer(data, dtype=op2.fdtype).reshape(nelements, 5).copy()
obj._times[obj.itime] = dt
strings = np.frombuffer(data, dtype=op2._uendian + 'S4').reshape(nelements, 5)
if obj.itime == 0:
ints = np.frombuffer(data, dtype=op2.idtype).reshape(nelements, 5)
if obj.element_name == 'DMIG':
s = np.array([(s1+s2).decode('latin1').strip()
for s1, s2 in zip(strings[:, 0], strings[:, 1])], dtype='|U8')
obj.element[itotal:itotal2] = s
else:
eids = ints[:, 0] // 10
assert eids.min() > 0, eids.min()
s = np.array([s1+s2 for s1, s2 in zip(strings[:, 1], strings[:, 2])])
obj.element[itotal:itotal2] = eids
obj.element_type[obj.itime, itotal:itotal2, :] = s
#[energy, percent, density]
if obj.element_name == 'DMIG':
obj.data[obj.itime, itotal:itotal2, :] = floats[:, 2:]
else:
obj.data[obj.itime, itotal:itotal2, :] = floats[:, 3:]
obj.itotal = itotal2
obj.ielement = ielement2
else:
n = complex_strain_energy_4(op2, obj, data, op2.sort_method,
n, ntotal, nelements, dt)
elif op2.format_code in [2, 3] and op2.num_wide == 5:
#ELEMENT-ID STRAIN-ENERGY (MAG/PHASE) PERCENT OF TOTAL STRAIN-ENERGY-DENSITY
# 5 2.027844E-10 / 0.0 1.2581 2.027844E-09
assert complex_cls is not None, op2.code_information()
ntotal = 20 * factor
nelements = ndata // ntotal
auto_return, is_vectorized = op2._create_oes_object4(
nelements, result_name, slot, complex_cls)
if auto_return:
return nelements * ntotal
obj = op2.obj
if op2.use_vector:
n = nelements * 4 * op2.num_wide
itotal = obj.ielement
ielement2 = obj.itotal + nelements
itotal2 = ielement2
floats = np.frombuffer(data, dtype=op2.fdtype).reshape(nelements, 5)
obj._times[obj.itime] = dt
#if obj.itime == 0:
ints = np.frombuffer(data, dtype=op2.idtype).reshape(nelements, 5)
eids = ints[:, 0] // 10
assert eids.min() > 0, eids.min()
obj.element[itotal:itotal2] = eids
#obj.element_type[obj.itime, itotal:itotal2, :] = s
#[energyr, energyi, percent, density]
obj.element[obj.itime, itotal:itotal2] = eids
obj.data[obj.itime, itotal:itotal2, :] = floats[:, 1:].copy()
obj.itotal = itotal2
obj.ielement = ielement2
else:
n = complex_strain_energy_5(op2, obj, data,
n, ntotal, nelements, dt)
elif op2.format_code == 1 and op2.num_wide == 6:
## TODO: figure this out...
ntotal = 24 * factor
nelements = ndata // ntotal
auto_return, is_vectorized = op2._create_oes_object4(
nelements, result_name, slot, RealStrainEnergyArray)
if auto_return:
return nelements * ntotal
obj = op2.obj
if op2.use_vector:
n = nelements * ntotal
itotal = obj.ielement
ielement2 = obj.itotal + nelements
itotal2 = ielement2
floats = np.frombuffer(data, dtype=op2.fdtype).reshape(nelements, 5)
obj._times[obj.itime] = dt
if obj.itime == 0:
strings = np.frombuffer(data, dtype=op2._uendian + 'S4').reshape(nelements, 6)
s = np.array([s1+s2 for s1, s2 in zip(strings[:, 1], strings[:, 2])])
ints = np.frombuffer(data, dtype=op2.idtype).reshape(nelements, 6)
eids = ints[:, 0] // 10
assert eids.min() > 0, eids.min()
obj.element[itotal:itotal2] = eids
obj.element_type[obj.itime, itotal:itotal2, :] = s
#[energy, percent, density]
obj.data[obj.itime, itotal:itotal2, :] = floats[:, 4:].copy()
obj.itotal = itotal2
obj.ielement = ielement2
else:
n = real_strain_energy_6(
op2, obj, data,
n, ntotal, nelements, dt)
elif op2.format_code in [2, 3] and op2.num_wide == 4:
#
# FREQUENCY = 1.000000E+01
# E L E M E N T S T R A I N E N E R G I E S ( A V E R A G E )
#
# ELEMENT-TYPE = QUADR * TOTAL ENERGY OF ALL ELEMENTS IN PROBLEM = 3.662188E+06
# SUBCASE 1 * TOTAL ENERGY OF ALL ELEMENTS IN SET 9 = 1.853189E+05
#
# ELEMENT-ID STRAIN-ENERGY PERCENT OF TOTAL STRAIN-ENERGY-DENSITY
# 9 8.723258E+03 0.2382 5.815505E+00
# 10 7.815898E+03 0.2134 5.210599E+00
# 11 8.512115E+04 2.3243 5.674743E+01
# 12 5.200864E+04 1.4202 3.467243E+01
#
# TYPE = QUADR SUBTOTAL 1.536690E+05 4.1961
#
#device_code = 1 Print
#analysis_code = 5 Frequency
#table_code = 18 ONRGY1-OEE - Element strain energy
#format_code = 2 Real/Imaginary
#sort_method = 1
#sort_code = 0
#sort_bits = (0, 0, 0)
#data_format = 0 Real
#sort_type = 0 Sort1
#is_random = 0 Sorted Responses
#random_code = 0
#s_code = None ???
#num_wide = 4
#isubcase = 1
#MSC Nastran
raise NotImplementedError('onr')
else:
msg = op2.code_information()
return op2._not_implemented_or_skip(data, ndata, msg)
#raise NotImplementedError(op2.code_information())
return n
[docs]
def real_strain_energy_6(op2: OP2,
obj: RealStrainEnergyArray,
data: bytes,
n: int,
ntotal: int,
nelements: int,
dt) -> int:
if op2.size == 4:
struct1 = Struct(op2._endian + b'i8s3f')
else:
struct1 = Struct(op2._endian + b'q16s3d')
for unused_i in range(nelements): # TODO: is this nnodes?
edata = data[n:n + ntotal]
out = struct1.unpack(edata)
(word, energy, percent, density) = out # TODO: this has to be wrong...
word = word.strip()
# print "eType=%s" % (eType)
# print "%s" %(self.get_element_type(self.element_type)), data_in
# eid = op2.obj.add_new_eid_sort1(out)
if op2.is_debug_file:
op2.binary_debug.write(' word=%s; %s\n' % (word, str(out)))
obj.add_sort1(dt, word, energy, percent, density)
n += ntotal
return n
[docs]
def complex_strain_energy_5(op2: OP2,
obj: ComplexStrainEnergyArray,
data: bytes,
n: int,
ntotal: int, nelements: int, dt) -> int:
#fmt = mapfmt(op2._endian + op2._analysis_code_fmt + b'3f', size)
fmt = op2._endian + mapfmt(b'i4f', op2.size)
struct1 = Struct(fmt)
for unused_i in range(nelements):
edata = data[n:n + ntotal]
out = struct1.unpack(edata)
(eid_device, energyr, energyi, percent, density) = out
eid, dt = get_eid_dt_from_eid_device(
eid_device, op2.nonlinear_factor, op2.sort_method)
# if is_magnitude_phase:
# energy = polar_to_real_imag(energyr, energyi)
# else:
# energy = complex(energyr, energyi)
if op2.is_debug_file:
op2.binary_debug.write(' eid=%i; %s\n' % (eid, str(out)))
# dt, eid, energyi, percenti, densityi
obj.add_sort1(dt, eid, energyr, energyi, percent, density)
n += ntotal
return n
[docs]
def real_strain_energy_4(op2: OP2,
obj: RealStrainEnergyArray | RealKineticEnergyArray,
data: bytes,
n: int,
ntotal: int,
nelements: int,
dt: int | float) -> int:
"""
(eid_device eid energy percent density)
(11 1 0.0114 0.1983 0.01147) typical
( 0 0 0 0 -1) optistruct - final
(1000000000 100000000 sum sum NaN) nx/msc - final
"""
fmt = op2._endian + mapfmt(op2._analysis_code_fmt + b'3f', op2.size)
struct1 = Struct(fmt)
if op2.is_optistruct:
fmt2 = mapfmt(op2._endian + op2._analysis_code_fmt + b'2f i', op2.size)
struct2 = Struct(fmt2)
edata = data[n:n+ntotal]
sum_energy = 0.
sum_percent = 0.
for unused_i in range(nelements-1):
edata = data[n:n+ntotal]
out = struct1.unpack(edata)
(eid_device, energy, percent, density) = out
eid, dt = get_eid_dt_from_eid_device(
eid_device, op2.nonlinear_factor, op2.sort_method)
# print(f'adding dt={dt:g} eid_device={eid_device} eid={eid} '
# f'energy={energy:g} percent={percent:g} density={density:g}')
if op2.is_debug_file:
op2.binary_debug.write(' eid=%i; %s\n' % (eid, str(out)))
sum_energy += energy
sum_percent += percent
obj.add_sort1(dt, eid, energy, percent, density)
n += ntotal
edata = data[n:n+ntotal]
out = struct2.unpack(edata)
(eid_device, energy, percent, density) = out
assert eid_device == 0, eid_device
eid, dt = get_eid_dt_from_eid_device(
eid_device, op2.nonlinear_factor, op2.sort_method)
# print(f'adding dt={dt:g} eid_device={eid_device} eid={eid} '
# f'energy={energy:g} percent={percent:g} density={density:g}')
#if op2.is_debug_file:
#op2.binary_debug.write(' eid=%i; %s\n' % (eid, str(out)))
eid = 100000000
obj.add_sort1(dt, eid, sum_energy, sum_percent, np.nan)
n += ntotal
else:
for unused_i in range(nelements):
edata = data[n:n+ntotal]
out = struct1.unpack(edata)
(eid_device, energy, percent, density) = out
eid, dt = get_eid_dt_from_eid_device(
eid_device, op2.nonlinear_factor, op2.sort_method)
# print(f'adding dt={dt:g} eid_device={eid_device} eid={eid} '
# f'energy={energy} percent={percent:g} density={density:g}')
if op2.is_debug_file:
op2.binary_debug.write(' eid=%i; %s\n' % (eid, str(out)))
obj.add_sort1(dt, eid, energy, percent, density)
n += ntotal
return n
[docs]
def complex_strain_energy_4(op2: OP2,
obj: ComplexStrainEnergyArray,
data: bytes, sort_method: int,
n: int,
ntotal: int, nnodes: int, dt) -> int:
if op2.size == 4:
structi = Struct(op2._endian + b'8s3f')
else:
structi = Struct(op2._endian + b'16s3d')
for unused_i in range(nnodes):
edata = data[n:n+ntotal]
out = structi.unpack(edata)
(word, energy, percent, density) = out
word = word.strip()
if op2.is_debug_file:
op2.binary_debug.write(' eid/word=%r; %s\n' % (word, str(out)))
#dt, eid, energyr, energyi, percenti, densityi
obj.add_sort1(dt, word, energy, percent, density)
n += ntotal
return n