Source code for pyNastran.op2.tables.oes_stressStrain.real.oes_objects

from typing import Any
import numpy as np
from pyNastran.op2.result_objects.op2_objects import BaseElement, set_as_sort1
from pyNastran.op2.op2_interface.write_utils import set_table3_field
from pyNastran.op2.writer.utils import fix_table3_types

TABLE_NAME_TO_TABLE_CODE = {
    # stress
    'OES1': 5,
    'OES1C': 5,
    'OES1X': 5,
    'OES1X1': 5,
    'OES2': 5,

    # strain
    'OSTR1': 5,
    'OSTR1X': 5,
    'OSTR2': 5,

    'OSTR1C': 5,
}

[docs] class OES_Object(BaseElement): def __init__(self, data_code, isubcase, apply_data_code=True): self.element_type = None self.element_name = None self.nonlinear_factor = np.nan self._times = None BaseElement.__init__(self, data_code, isubcase, apply_data_code=apply_data_code) #self.log.debug("starting OES...element_name=%-6s isubcase=%s" % (self.element_name, self.isubcase)) #print self.data_code
[docs] def finalize(self): """it's required that the object be in SORT1""" self.set_as_sort1()
def _get_sort2_itime_ielement_from_itotal(self) -> tuple[int, int]: #print(f'itime={self.itime} ielement={self.ielement} nelements={self.nelements}') # self.itotal #itime = self.itotal % self.nelements #ielement = self.itime #print(f'itime={itime} ielement={ielement} nelements={self.nelements}') # self.itotal #itime = self.itotal % self.nelements #return itime, ielement # ------------------ itime = self.ielement #itotal = self.itotal ielement = self.itime #print(f'itime={self.itime} ielement={self.ielement} nelements={self.nelements}') # self.itotal return itime, ielement
[docs] def set_as_sort1(self): """the data is in SORT1, but the flags are wrong""" set_as_sort1(self)
#update_stress_force_time_word(self) def _get_analysis_code_dtype(self) -> str: if self.analysis_code in [5, 6]: if self.size == 4: dtype = 'float32' else: dtype = 'float64' else: raise NotImplementedError(self.data_code) return dtype @property def is_curvature(self) -> bool: if self.is_stress: curvature_flag = False else: # strain only curvature_flag = True if self.stress_bits[2] == 0 else False if self.s_code in [10, 11, 20, 27]: assert curvature_flag, curvature_flag return True assert not curvature_flag, curvature_flag return False @property def is_fiber_distance(self) -> bool: return not self.is_curvature @property def is_von_mises(self) -> bool: return not self.is_max_shear @property def is_max_shear(self): return self.stress_bits[4] == 0 def _get_headers(self): raise NotImplementedError(f'overwrite this {self.class_name}') @property def is_stress(self): raise NotImplementedError(f'overwrite this in {self.class_name}') def _write_table_3(self, op2_file, op2_ascii, new_result, itable, itime): #, itable=-3, itime=0): import inspect from struct import pack frame = inspect.currentframe() call_frame = inspect.getouterframes(frame, 2) op2_ascii.write('%s.write_table_3: %s\n' % (self.__class__.__name__, call_frame[1][3])) #if itable == -3: #print('*writing itable=%s' % itable) if new_result and itable != -3: header = [ 4, 146, 4, ] else: header = [ 4, itable, 4, 4, 1, 4, 4, 0, 4, 4, 146, 4, ] op2_file.write(pack(b'%ii' % len(header), *header)) op2_ascii.write('table_3_header = %s\n' % header) #op2_file.write(pack('12i', *header)) #else: #print('***writing itable=%s' % itable) #op2_file.write(pack('3i', *[ ##4, itable, 4, ##4, 1, 4, ##4, 0, 4, #4, 146, 4, #])) approach_code = self.approach_code table_code = self.table_code isubcase = self.isubcase element_type = self.element_type #[ #'aCode', 'tCode', 'element_type', 'isubcase', #'???', '???', '???', 'load_set' #'format_code', 'num_wide', 's_code', '???', #'???', '???', '???', '???', #'???', '???', '???', '???', #'???', '???', '???', '???', #'???', 'Title', 'subtitle', 'label'] #random_code = self.random_code format_code = self.format_code s_code = self.s_code num_wide = self.num_wide acoustic_flag = 0 thermal = self.thermal title = b'%-128s' % self.title.encode('ascii') subtitle = b'%-128s' % self.subtitle.encode('ascii') label = b'%-128s' % self.label.encode('ascii') ftable3 = b'50i 128s 128s 128s' unused_oCode = 0 ftable3 = b'i' * 50 + b'128s 128s 128s' field6 = 0 field7 = 0 if self.analysis_code == 1: field5 = self.lsdvmns[itime] if np.isnan(field5): # poor sort2 -> sort1 raise RuntimeError('field5 in a static case is nan...; do you have SORT2?') #field5 = 1 elif self.analysis_code == 2: field5 = self.modes[itime] field6 = self.eigns[itime] field7 = self.cycles[itime] assert isinstance(field6, float), type(field6) assert isinstance(field7, float), type(field7) ftable3 = set_table3_field(ftable3, 6, b'f') # field 6 ftable3 = set_table3_field(ftable3, 7, b'f') # field 7 #elif self.analysis_code == 3: #field5 = self.freqs[itime] elif self.analysis_code == 5: field5 = self.freqs[itime] ftable3 = set_table3_field(ftable3, 5, b'f') # field 5 elif self.analysis_code == 6: field5 = self.dts[itime] ftable3 = set_table3_field(ftable3, 5, b'f') # field 5 elif self.analysis_code == 7: # pre-buckling field5 = self.lsdvmns[itime] # load set number elif self.analysis_code == 8: # post-buckling field5 = self.lsdvmns[itime] # load set number #if hasattr(self, 'eigns'): if hasattr(self, 'eigens'): field6 = self.eigns[itime] elif hasattr(self, 'eigrs'): field6 = self.eigrs[itime] else: # pragma: no cover print(self.get_stats()) raise NotImplementedError('cant find eigns or eigrs on analysis_code=8') ftable3 = set_table3_field(ftable3, 6, b'f') # field 6 elif self.analysis_code == 9: # complex eigenvalues field5 = self.modes[itime] if hasattr(self, 'eigns'): field6 = self.eigns[itime] elif hasattr(self, 'eigrs'): field6 = self.eigrs[itime] else: # pragma: no cover print(self.get_stats()) raise NotImplementedError('cant find eigns or eigrs on analysis_code=9') ftable3 = set_table3_field(ftable3, 6, b'f') # field 6 field7 = self.eigis[itime] ftable3 = set_table3_field(ftable3, 7, b'f') # field 7 elif self.analysis_code == 10: # nonlinear statics field5 = self.lftsfqs[itime] ftable3 = set_table3_field(ftable3, 5, b'f') # field 5; load step elif self.analysis_code == 11: # old geometric nonlinear statics field5 = self.lsdvmns[itime] # load set number else: raise NotImplementedError(self.analysis_code) table3 = [ approach_code, table_code, element_type, isubcase, field5, field6, field7, self.load_set, format_code, num_wide, s_code, acoustic_flag, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, thermal, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, title, subtitle, label, ] assert table3[22] == thermal table3 = fix_table3_types(table3, size=4) data = [584] + table3 + [584] fmt = b'i' + ftable3 + b'i' #print(fmt) #print(data) #f.write(pack(fascii, '%s header 3c' % self.table_name, fmt, data)) op2_ascii.write('%s header 3c = %s\n' % (self.table_name, data)) op2_file.write(pack(fmt, *data))
[docs] class StressObject(OES_Object): def __init__(self, data_code, isubcase): OES_Object.__init__(self, data_code, isubcase) assert self.is_stress, self.code_information() assert not self.is_strain, self.code_information()
[docs] def update_dt(self, data_code, dt): self.data_code = data_code self.apply_data_code() #assert dt >= 0. self.element_name = self.data_code['element_name'] if dt is not None: #print("updating stress...%s=%s element_name=%s" % # (self.data_code['name'], dt, self.element_name)) self.dt = dt self.add_new_transient(dt)
@property def is_strain(self) -> bool: class_name = self.__class__.__name__ assert self.stress_bits[1] == 0, 'class_name=%s scode=%s stress_bits=%s' % (class_name, self.s_code, self.stress_bits) if self.table_name_str != 'OES1A': assert self.stress_bits[1] == self.stress_bits[3], 'class_name=%s scode=%s stress_bits=%s' % (class_name, self.s_code, self.stress_bits) return False @property def is_stress(self) -> bool: class_name = self.__class__.__name__ assert self.stress_bits[1] == 0, 'class_name=%s scode=%s stress_bits=%s' % (class_name, self.s_code, self.stress_bits) if self.table_name_str != 'OES1A': assert self.stress_bits[1] == self.stress_bits[3], 'class_name=%s scode=%s stress_bits=%s' % (class_name, self.s_code, self.stress_bits) return True
[docs] class StrainObject(OES_Object): def __init__(self, data_code, isubcase): OES_Object.__init__(self, data_code, isubcase) assert self.is_strain, self.code_information() assert not self.is_stress, self.code_information()
[docs] def update_dt(self, data_code, dt): self.data_code = data_code self.apply_data_code() self.element_name = self.data_code['element_name'] if dt is not None: #print("updating strain...%s=%s element_name=%s" % # (self.data_code['name'], dt, self.element_name)) self.dt = dt self.add_new_transient(dt)
@property def is_strain(self) -> bool: class_name = self.__class__.__name__ assert self.stress_bits[1] == 1, 'class_name=%s scode=%s stress_bits=%s; table_name=%r' % (class_name, self.s_code, self.stress_bits, self.table_name) assert self.stress_bits[1] == self.stress_bits[3], 'class_name=%s scode=%s stress_bits=%s; table_name=%r' % (class_name, self.s_code, self.stress_bits, self.table_name) return True @property def is_stress(self) -> bool: class_name = self.__class__.__name__ assert self.stress_bits[1] == 1, 'class_name=%s is_stress=False scode=%s stress_bits=%s; element_type=%s element_name=%s; table_name=%r' % (class_name, self.s_code, self.stress_bits, self.element_type, self.element_name, self.table_name) assert self.stress_bits[1] == self.stress_bits[3], 'class_name=%s scode=%s stress_bits=%s; table_name=%r' % (class_name, self.s_code, self.stress_bits, self.table_name) return False
[docs] def get_scode(stress_bits: list[int]) -> int: scode = 0 for i, bit in enumerate(stress_bits): scode += 2 ** i * bit return scode
[docs] def oes_complex_data_code(table_name: str, element_name: str, num_wide: int, is_sort1: bool=True, is_random: bool=False, random_code=0, title='', subtitle='', label='', is_msc=True): dtype_code = 1 # complex data_code = _oes_data_code(table_name, element_name, num_wide, dtype_code, is_sort1=is_sort1, is_random=is_random, random_code=random_code, title=title, subtitle=subtitle, label=label, is_msc=is_msc) return data_code
[docs] def oes_real_data_code(table_name: str, element_name: str, num_wide: int, is_sort1: bool=True, is_random: bool=False, random_code=0, title='', subtitle='', label='', is_msc=True): dtype_code = 0 # real assert isinstance(element_name, str), element_name data_code = _oes_data_code(table_name, element_name, num_wide, dtype_code, is_sort1=is_sort1, is_random=is_random, random_code=random_code, title=title, subtitle=subtitle, label=label, is_msc=is_msc) return data_code
def _oes_data_code(table_name: str, element_name: str, num_wide: int, dtype_code: int, is_sort1: bool=True, is_random: bool=False, random_code=0, title='', subtitle='', label='', is_msc=True): """ Parameters ---------- dtype_code : int 0 : real 1 : complex 2 : random """ sort1_sort_bit = 0 if is_sort1 else 1 random_sort_bit = 1 if is_random else 0 sort_method = 1 if is_sort1 else 2 #if format_code == 1: #format_word = "Real" #elif format_code == 2: #format_word = "Real/Imaginary" #elif format_code == 3: #format_word = "Magnitude/Phase" #DEVICE_CODE_MAP = { #1 : "Print", #2 : "Plot", #3 : "Print and Plot", #4 : "Punch", #5 : "Print and Punch", #6 : "Plot and Punch", #7 : "Print, Plot, and Punch", #} table_code = TABLE_NAME_TO_TABLE_CODE[table_name] sort_code = 1 # TODO: what should this be??? #table_code = tCode % 1000 #sort_code = tCode // 1000 tCode = table_code * 1000 + sort_code device_code = 2 # Plot #approach_code = analysis_code * 10 + device_code #print(f'approach_code={approach_code} analysis_code={analysis_code} device_code={device_code}') data_code = { 'nonlinear_factor': None, #'approach_code' : approach_code, #'analysis_code' : analysis_code, 'sort_bits': [dtype_code, sort1_sort_bit, random_sort_bit], # real, sort1, random 'sort_method' : sort_method, 'is_msc': is_msc, #'is_nasa95': is_nasa95, 'format_code': 1, # real 'table_code': table_code, 'tCode': tCode, 'table_name': table_name, ## TODO: should this be a string? 'device_code' : device_code, 'random_code' : random_code, 'thermal': 0, 'title' : title, 'subtitle': subtitle, 'label': label, 'num_wide': num_wide, 'element_name': element_name, #'num_wide' : 8, # displacement-style table } return data_code
[docs] def set_approach_code(analysis_code: int, device_code: int): approach_code = analysis_code * 10 + device_code return approach_code
def _check_num_wide(data_code: dict[str, Any]): if 'num_wide' not in data_code: if 'element_name' in data_code: element_name = data_code['element_name'] raise RuntimeError(f'missing num_wide for {element_name}') else: raise RuntimeError(f'missing num_wide')
[docs] def set_static_case(cls, is_sort1, isubcase, data_code, func, args): data_code['lsdvmns'] = [0] # TODO: ??? data_code['data_names'] = [] data_code['load_set'] = 1 data_code['analysis_code'] = 1 data_code['approach_code'] = set_approach_code(data_code['analysis_code'], data_code['device_code']) times = [None] _check_num_wide(data_code) obj = func(cls, data_code, is_sort1, isubcase, *args, times) obj.is_built = True obj.get_stats() return obj
[docs] def set_modal_case(cls, is_sort1, isubcase, data_code, func, args, modes, eigns, cycles): data_code['data_names'] = ['modes', 'eigns', 'mode_cycles'] data_code['load_set'] = 1 #data_code['lsdvmns'] = [0] # TODO: ??? data_code['analysis_code'] = 2 # modal data_code['approach_code'] = set_approach_code(data_code['analysis_code'], data_code['device_code']) _check_num_wide(data_code) obj = func(cls, data_code, is_sort1, isubcase, *args, modes) obj.modes = modes obj.eigns = eigns obj.mode_cycles = cycles obj.cycles = cycles obj.is_built = True obj.get_stats() return obj
[docs] def set_transient_case(cls, is_sort1: bool, isubcase: int, data_code, func, args, times: np.ndarray): data_code['lsdvmns'] = [0] # TODO: ??? data_code['data_names'] = ['dt'] data_code['load_set'] = 1 data_code['analysis_code'] = 6 data_code['approach_code'] = set_approach_code(data_code['analysis_code'], data_code['device_code']) _check_num_wide(data_code) obj = func(cls, data_code, is_sort1, isubcase, *args, times) obj.times = times obj.dts = times obj.is_built = True obj.get_stats() return obj
[docs] def set_post_buckling_case(cls, is_sort1, isubcase, data_code, func, args, modes, eigrs, eigis): data_code['lsdvmns'] = [0] # TODO: ??? data_code['data_names'] = ['modes', 'eigrs', 'eigis'] data_code['load_set'] = 1 data_code['analysis_code'] = 8 data_code['approach_code'] = set_approach_code(data_code['analysis_code'], data_code['device_code']) _check_num_wide(data_code) obj = func(cls, data_code, is_sort1, isubcase, *args, modes) obj.dts = modes obj.modes = modes obj.eigrs = eigrs obj.eigis = eigis obj.is_built = True obj.get_stats() return obj
[docs] def set_freq_case(cls, is_sort1, isubcase, data_code, func, args, freqs): #data_code['lsdvmns'] = [0] # TODO: ??? #data_code['data_names'] = ['dt'] #data_code['load_set'] = 1 data_code['load_set'] = 1 data_code['analysis_code'] = 5 data_code['approach_code'] = set_approach_code(data_code['analysis_code'], data_code['device_code']) _check_num_wide(data_code) data_code['data_names'] = ['freq'] data_code['name'] = 'FREQ' obj = func(cls, data_code, is_sort1, isubcase, *args, freqs) obj.freqs = freqs obj.is_built = True obj.get_stats() return obj
[docs] def set_complex_modes_case(cls, is_sort1, isubcase, data_code, func, args, modes, eigrs, eigis): #data_code['lsdvmns'] = [0] # TODO: ??? #data_code['data_names'] = ['dt'] #data_code['load_set'] = 1 data_code['load_set'] = 1 data_code['analysis_code'] = 9 # complex eigenvalues data_code['approach_code'] = set_approach_code(data_code['analysis_code'], data_code['device_code']) _check_num_wide(data_code) data_code['data_names'] = ['modes', 'eigrs', 'eigis'] data_code['name'] = 'mode' obj = func(cls, data_code, is_sort1, isubcase, *args, modes) obj.modes = modes obj.eigrs = eigrs obj.eigis = eigis obj.is_built = True obj.get_stats() return obj
[docs] def set_element_case(cls, data_code, is_sort1, isubcase, element, data, times): """ CBAR CROD, CONROD, CTUBE CELAS1-4, CDAMP1-4 CSHEAR """ assert element.ndim == 1, element.shape ntimes = data.shape[0] nnodes = data.shape[1] dt = times[0] obj = cls(data_code, is_sort1, isubcase, dt) obj.element = element obj.data = data obj.ntimes = ntimes obj.ntotal = nnodes obj.nelements = nnodes obj._times = times return obj
[docs] def set_element_node_xxb_case(cls, data_code, is_sort1, isubcase, element_node, xxb, data, times): """CBEAM""" assert element_node.ndim == 2, element_node.shape ntimes = data.shape[0] nelement_nnodes = data.shape[1] dt = times[0] obj = cls(data_code, is_sort1, isubcase, dt) obj.nnodes = 11 obj.element = element_node[:, 0] obj.xxb = xxb obj.element_node = element_node obj.data = data assert element_node.shape == (nelement_nnodes, 2) obj.ntimes = ntimes obj.ntotal = nelement_nnodes obj.nelements = nelement_nnodes obj._times = times return obj
[docs] def update_stress_force_time_word(obj) -> None: if obj.analysis_code == 1: name = 'lsdvmn' obj._times = np.full(1, np.nan, dtype=obj.data.dtype) obj.nonlinear_factor = obj._times[0] else: try: name = obj.analysis_method except AttributeError: msg = str(obj.get_stats()) msg += obj.object_stats() raise RuntimeError(msg) from e #print(f'\n{self.class_name}: name = {name}') #_analysis_code_fmt #if self.analysis_code == 5: #name = 'freq' #elif self.analysis_code == 6: #name = 'dt' #elif self.analysis_code == 10: #name = 'dt' #else: #raise NotImplementedError(self.data_code) names = name + 's' obj.data_code['name'] = name obj.data_code['data_names'][0] = name #print(self.element_ids) del obj.element_id, obj.element_ids #print('timesA =', self._times) old_times = None if 1: old_times = obj._times setattr(obj, names, obj._times) #print('timesB =', self._times) if obj.analysis_code == 1: assert len(obj._times) == 1, obj.data.shape elif len(obj._times) > 1: class_name = obj.__class__.__name__
#assert obj._times.min() != obj._times.max(), f'{class_name}: old_times={old_times} -> times={obj._times}; data.shape={obj.data.shape}\n{obj.code_information()}' #print(obj.object_attributes())