# pylint: disable=C0301,R0913,R0914,R0904,C0111,R0201,R0902
from itertools import count
import numpy as np
from numpy import zeros, where, searchsorted
from pyNastran.utils.numpy_utils import integer_types
from pyNastran.op2.tables.oes_stressStrain.real.oes_objects import StressObject, StrainObject, OES_Object
from pyNastran.f06.f06_formatting import write_floats_13e, _eigenvalue_header
from pyNastran.op2.result_objects.op2_objects import get_times_dtype
[docs]
class RandomSolidArray(OES_Object):
def __init__(self, data_code, is_sort1, isubcase, dt):
OES_Object.__init__(self, data_code, isubcase, apply_data_code=False)
#self.code = [self.format_code, self.sort_code, self.s_code]
#self.ntimes = 0 # or frequency/mode
#self.ntotal = 0
self.nelements = 0 # result specific
@property
def is_real(self) -> bool:
return True
@property
def is_complex(self) -> bool:
return False
[docs]
def get_headers(self):
raise NotImplementedError()
def _reset_indices(self) -> None:
self.itotal = 0
self.ielement = 0
[docs]
def build(self):
"""sizes the vectorized attributes of the RealSolidArray"""
#print('ntimes=%s nelements=%s ntotal=%s' % (self.ntimes, self.nelements, self.ntotal))
assert self.ntimes > 0, 'ntimes=%s' % self.ntimes
assert self.nelements > 0, 'nelements=%s' % self.nelements
assert self.ntotal > 0, 'ntotal=%s' % self.ntotal
#self.names = []
self.nelements //= self.ntimes
self.itime = 0
self.ielement = 0
self.itotal = 0
#self.ntimes = 0
#self.nelements = 0
#print("ntimes=%s nelements=%s ntotal=%s" % (self.ntimes, self.nelements, self.ntotal))
dtype, idtype, fdtype = get_times_dtype(self.nonlinear_factor, self.size, self.analysis_fmt)
if self.is_sort1:
ntimes = self.ntimes
nelements = self.nelements
ntotal = self.ntotal
else:
nelements = self.ntimes
ntimes = self.nelements
ntotal = self.ntotal
dtype = self._get_analysis_code_dtype()
self._times = zeros(ntimes, dtype=self.analysis_fmt)
# TODO: could be more efficient by using nelements for cid
self.element_node = zeros((ntotal, 2), dtype=idtype)
self.element_cid = zeros((nelements, 2), dtype=idtype)
#if self.element_name == 'CTETRA':
#nnodes = 4
#elif self.element_name == 'CPENTA':
#nnodes = 6
#elif self.element_name == 'CHEXA':
#nnodes = 8
#self.element_node = zeros((self.ntotal, nnodes, 2), 'int32')
#[oxx, oyy, ozz, txy, tyz, txz]
self.data = zeros((self.ntimes, self.ntotal, 6), 'float32')
self.nnodes = self.element_node.shape[0] // self.nelements
#self.data = zeros((self.ntimes, self.nelements, nnodes+1, 10), 'float32')
[docs]
def build_dataframe(self):
"""creates a pandas dataframe"""
import pandas as pd
headers = self.get_headers()
# TODO: cid?
element_node = [self.element_node[:, 0], self.element_node[:, 1]]
if self.nonlinear_factor not in (None, np.nan):
column_names, column_values = self._build_dataframe_transient_header()
self.data_frame = pd.Panel(self.data, items=column_values,
major_axis=element_node, minor_axis=headers).to_frame()
self.data_frame.columns.names = column_names
self.data_frame.index.names = ['ElementID', 'NodeID', 'Item']
else:
self.data_frame = pd.Panel(self.data, major_axis=element_node, minor_axis=headers).to_frame()
self.data_frame.columns.names = ['Static']
self.data_frame.index.names = ['ElementID', 'NodeID', 'Item']
[docs]
def add_eid_sort1(self, unused_etype, cid, dt, eid, unused_node_id,
oxx, oyy, ozz, txy, tyz, txz):
assert cid >= -2, cid
assert eid >= 0, eid
#print "dt=%s eid=%s eType=%s" %(dt,eid,eType)
self._times[self.itime] = dt
self.element_node[self.itotal, :] = [eid, 0] # 0 is center
self.data[self.itime, self.itotal, :] = [oxx, oyy, ozz, txy, tyz, txz]
#self.data[self.itime, self.ielement, 0, :] = [oxx, oyy, ozz, txy, tyz, txz]
#print('element_cid[%i, :] = [%s, %s]' % (self.ielement, eid, cid))
if self.ielement == self.nelements:
self.ielement = 0
self.element_cid[self.ielement, :] = [eid, cid]
self.itotal += 1
self.ielement += 1
def __eq__(self, table): # pragma: no cover
assert self.is_sort1 == table.is_sort1
self._eq_header(table)
if not np.array_equal(self.data, table.data):
msg = 'table_name=%r class_name=%s\n' % (self.table_name, self.__class__.__name__)
msg += '%s\n' % str(self.code_information())
i = 0
for itime in range(self.ntimes):
for ieid, eid_nid in enumerate(self.element_node):
(eid, nid) = eid_nid
t1 = self.data[itime, ieid, :]
t2 = table.data[itime, ieid, :]
(oxx1, oyy1, ozz1, txy1, tyz1, txz1) = t1
(oxx2, oyy2, ozz2, txy2, tyz2, txz2) = t2
if not np.array_equal(t1, t2):
msg += (
'(%s, %s) (%s, %s, %s, %s, %s, %s)\n'
'%s (%s, %s, %s, %s, %s, %s)\n' % (
eid, nid,
oxx1, oyy1, ozz1, txy1, tyz1, txz1,
' ' * (len(str(eid)) + len(str(nid)) + 2),
oxx2, oyy2, ozz2, txy2, tyz2, txz2))
i += 1
if i > 10:
print(msg)
raise ValueError(msg)
#print(msg)
if i > 0:
raise ValueError(msg)
return True
[docs]
def add_node_sort1(self, dt, eid, unused_inode, node_id, oxx, oyy, ozz, txy, tyz, txz):
self.data[self.itime, self.itotal, :] = [oxx, oyy, ozz, txy, tyz, txz]
#print('data[%s, %s, :] = %s' % (self.itime, self.itotal, str(self.data[self.itime, self.itotal, :])))
#self.data[self.itime, self.ielement-1, self.inode, :] = [oxx, oyy, ozz, txy, tyz, txz]
#print('eid=%i node_id=%i exx=%s' % (eid, node_id, str(oxx)))
self.element_node[self.itotal, :] = [eid, node_id]
#self.element_node[self.ielement-1, self.inode-1, :] = [eid, node_id]
self.itotal += 1
@property
def nnodes_per_element(self):
if self.element_type == 39: # CTETRA
nnodes = 4
elif self.element_type == 67: # CHEXA
nnodes = 8
elif self.element_type == 68: # CPENTA
nnodes = 6
else:
raise NotImplementedError('element_name=%s self.element_type=%s' % (self.element_name, self.element_type))
return nnodes
[docs]
def get_stats(self, short: bool=False) -> list[str]:
if not self.is_built:
return [
f'<{self.__class__.__name__}>; table_name={self.table_name!r}\n',
f' ntimes: {self.ntimes:d}\n',
f' ntotal: {self.ntotal:d}\n',
]
nelements = self.nelements
ntimes = self.ntimes
#ntotal = self.ntotal
try:
nnodes_per_element = self.element_node.shape[0] // nelements
except ZeroDivisionError:
nnodes_per_element = '???'
nnodes = self.element_node.shape[0]
msg = []
if self.nonlinear_factor not in (None, np.nan): # transient
msg.append(' type=%s ntimes=%i nelements=%i nnodes=%i\n nnodes_per_element=%s (including centroid)\n'
% (self.__class__.__name__, ntimes, nelements, nnodes, nnodes_per_element))
ntimes_word = 'ntimes'
else:
msg.append(' type=%s nelements=%i nnodes=%i\n nodes_per_element=%i (including centroid)\n'
% (self.__class__.__name__, nelements, nnodes, nnodes_per_element))
ntimes_word = '1'
msg.append(' eType, cid\n')
headers = self.get_headers()
n = len(headers)
msg.append(' data: [%s, nnodes, %i] where %i=[%s]\n' % (ntimes_word, n, n, str(', '.join(headers))))
msg.append(f' element_node.shape = {self.element_node.shape}\n')
msg.append(f' element_cid.shape = {self.element_cid.shape}\n')
msg.append(f' data.shape = {self.data.shape}\n')
msg.append(' element name: %s\n' % self.element_name)
msg += self.get_data_code()
#print(''.join(msg))
return msg
[docs]
def get_element_index(self, eids):
# elements are always sorted; nodes are not
itot = searchsorted(eids, self.element_node[:, 0]) #[0]
return itot
[docs]
def eid_to_element_node_index(self, eids):
#ind = ravel([searchsorted(self.element_node[:, 0] == eid) for eid in eids])
ind = searchsorted(eids, self.element_node[:, 0])
#ind = ind.reshape(ind.size)
#ind.sort()
return ind
[docs]
def write_f06(self, f06_file, header=None, page_stamp: str='PAGE %s', page_num: int=1, is_mag_phase: bool=False, is_sort1: bool=True):
if header is None:
header = []
nnodes, msg_temp = _get_f06_header_nnodes(self, is_mag_phase)
# write the f06
ntimes = self.data.shape[0]
eids2 = self.element_node[:, 0]
nodes = self.element_node[:, 1]
eids3 = self.element_cid[:, 0]
unused_cids3 = self.element_cid[:, 1]
for itime in range(ntimes):
dt = self._times[itime]
header = _eigenvalue_header(self, header, itime, ntimes, dt)
f06_file.write(''.join(header + msg_temp))
#print("self.data.shape=%s itime=%s ieids=%s" % (str(self.data.shape), itime, str(ieids)))
oxx = self.data[itime, :, 0]
oyy = self.data[itime, :, 1]
ozz = self.data[itime, :, 2]
txy = self.data[itime, :, 3]
tyz = self.data[itime, :, 4]
txz = self.data[itime, :, 5]
cnnodes = nnodes + 1
for i, deid, node_id, doxx, doyy, dozz, dtxy, dtyz, dtxz in zip(
count(), eids2, nodes, oxx, oyy, ozz, txy, tyz, txz):
unused_j = where(eids3 == deid)[0]
#cid = cids3[j]
cid = 0
[oxxi, oyyi, ozzi, txyi, tyzi, txzi] = write_floats_13e(
[doxx, doyy, dozz, dtxy, dtyz, dtxz])
if i % cnnodes == 0:
#print('deid, cid, nnodes = %s, %s, %s' % (deid, cid, nnodes))
f06_file.write('0 %8s %8iGRID CS %i GP\n' % (deid, cid, nnodes))
f06_file.write(
# center oxx oyy ozz txy tyz txz
'0 %8s %-13s %-13s %-13s %-13s %-13s %-13s\n'
% ('CENTER', oxxi, oyyi, ozzi, txyi, tyzi, txzi))
else:
f06_file.write(
'0 %8s %-13s %-13s %-13s %-13s %-13s %-13s\n'
% (node_id, oxxi, oyyi, ozzi, txyi, tyzi, txzi))
i += 1
f06_file.write(page_stamp % page_num)
page_num += 1
return page_num - 1
[docs]
class RandomSolidStressArray(RandomSolidArray, StressObject):
def __init__(self, data_code, is_sort1, isubcase, dt):
RandomSolidArray.__init__(self, data_code, is_sort1, isubcase, dt)
StressObject.__init__(self, data_code, isubcase)
[docs]
def get_headers(self) -> list[str]:
headers = ['oxx', 'oyy', 'ozz', 'txy', 'tyz', 'txz']
return headers
[docs]
class RandomSolidStrainArray(RandomSolidArray, StrainObject):
def __init__(self, data_code, is_sort1, isubcase, dt):
RandomSolidArray.__init__(self, data_code, is_sort1, isubcase, dt)
StrainObject.__init__(self, data_code, isubcase)
[docs]
def get_headers(self) -> list[str]:
headers = ['exx', 'eyy', 'ezz', 'exy', 'eyz', 'exz']
return headers
def _get_solid_msgs(self):
assert self.table_name in ['OESATO1', 'OSTRATO1'], self.table_name
if self.is_stress:
base_msg = [
'0 CORNER ------CENTER AND CORNER POINT STRESSES--------- DIR. COSINES MEAN \n',
' ELEMENT-ID GRID-ID NORMAL SHEAR PRINCIPAL -A- -B- -C- PRESSURE \n']
tetra_msg = [' S T R E S S E S I N T E T R A H E D R O N S O L I D E L E M E N T S ( C T E T R A )\n', ]
penta_msg = [' S T R E S S E S I N P E N T A H E D R O N S O L I D E L E M E N T S ( P E N T A )\n', ]
hexa_msg = [' S T R E S S E S I N H E X A H E D R O N S O L I D E L E M E N T S ( H E X A )\n', ]
else:
base_msg = [
'0 CORNER ------CENTER AND CORNER POINT STRAINS--------- DIR. COSINES MEAN \n',
' ELEMENT-ID GRID-ID NORMAL SHEAR PRINCIPAL -A- -B- -C- PRESSURE \n']
tetra_msg = [' S T R A I N S I N T E T R A H E D R O N S O L I D E L E M E N T S ( C T E T R A )\n', ]
penta_msg = [' S T R A I N S I N P E N T A H E D R O N S O L I D E L E M E N T S ( P E N T A )\n', ]
hexa_msg = [' S T R A I N S I N H E X A H E D R O N S O L I D E L E M E N T S ( H E X A )\n', ]
tetra_msg += base_msg
penta_msg += base_msg
hexa_msg += base_msg
return tetra_msg, penta_msg, hexa_msg
def _get_f06_header_nnodes(self, is_mag_phase=True):
tetra_msg, penta_msg, hexa_msg = _get_solid_msgs(self)
if self.element_type == 39: # CTETRA
msg = tetra_msg
nnodes = 4
elif self.element_type == 67: # CHEXA
msg = hexa_msg
nnodes = 8
elif self.element_type == 68: # CPENTA
msg = penta_msg
nnodes = 6
else: # pragma: no cover
msg = 'element_name=%s self.element_type=%s' % (self.element_name, self.element_type)
raise NotImplementedError(msg)
return nnodes, msg