"""
defines readers for BDF objects in the OP2 EPT/EPTS table
"""
#pylint: disable=C0103,R0914
from struct import unpack, Struct
from typing import Tuple, List
import numpy as np
#from pyNastran import is_release
from pyNastran.bdf.cards.properties.mass import PMASS, NSM, NSML
from pyNastran.bdf.cards.properties.bars import PBAR, PBARL, PBEND
from pyNastran.bdf.cards.properties.beam import PBEAM, PBEAML, PBCOMP
from pyNastran.bdf.cards.properties.bush import PBUSH, PBUSHT
from pyNastran.bdf.cards.properties.damper import PDAMP, PVISC
from pyNastran.bdf.cards.properties.properties import PFAST, PGAP
from pyNastran.bdf.cards.properties.rods import PROD, PTUBE
from pyNastran.bdf.cards.properties.shell import PSHEAR, PSHELL, PCOMP
from pyNastran.bdf.cards.properties.solid import PSOLID
from pyNastran.bdf.cards.properties.springs import PELAS, PELAST
from pyNastran.bdf.cards.thermal.thermal import PCONV, PHBDY, PCONVM
# PCOMPG, PBUSH1D, PBEAML, PBEAM3
from pyNastran.op2.tables.geom.geom_common import GeomCommon
from pyNastran.op2.op2_interface.op2_reader import (
mapfmt, reshape_bytes_block, reshape_bytes_block_size)
[docs]class EPT(GeomCommon):
"""defines methods for reading op2 properties"""
def _read_ept_4(self, data, ndata):
return self._read_geom_4(self._ept_map, data, ndata)
def __init__(self):
GeomCommon.__init__(self)
self.big_properties = {}
self._ept_map = {
(3201, 32, 55): ['NSM', self._read_nsm], # record 2
(52, 20, 181): ['PBAR', self._read_pbar], # record 11 - buggy
(9102, 91, 52): ['PBARL', self._read_pbarl], # record 12 - almost there...
(2706, 27, 287): ['PCOMP', self._read_pcomp], # record 22 - buggy
(302, 3, 46): ['PELAS', self._read_pelas], # record 39
(2102, 21, 121): ['PGAP', self._read_pgap], # record 42
(902, 9, 29): ['PROD', self._read_prod], # record 49
(1002, 10, 42): ['PSHEAR', self._read_pshear], # record 50
(2402, 24, 281): ['PSOLID', self._read_psolid], # record 51
(2302, 23, 283): ['PSHELL', self._read_pshell], # record 52
(1602, 16, 30): ['PTUBE', self._read_ptube], # record 56
(5402, 54, 262): ['PBEAM', self._read_pbeam], # record 14 - not done
(9202, 92, 53): ['PBEAML', self._read_pbeaml], # record 15
(2502, 25, 248): ['PBEND', self._read_pbend], # record 16 - not done
(1402, 14, 37): ['PBUSH', self._read_pbush], # record 19 - not done
(3101, 31, 219): ['PBUSH1D', self._read_pbush1d], # record 20 - not done
(152, 19, 147): ['PCONEAX', self._read_pconeax], # record 24 - not done
(11001, 110, 411): ['PCONV', self._read_pconv], # record 25 - not done
# record 26
(202, 2, 45): ['PDAMP', self._read_pdamp], # record 27 - not done
(2802, 28, 236): ['PHBDY', self._read_phbdy], # record 43 - not done
(402, 4, 44): ['PMASS', self._read_pmass], # record 48
(1802, 18, 31): ['PVISC', self._read_pvisc], # record 59
(10201, 102, 400): ['PVAL', self._read_pval], # record 58 - not done
(2606, 26, 289): ['VIEW', self._read_view], # record 62 - not done
(3201, 32, 991) : ['NSM', self._read_fake], # record
(3301, 33, 992) : ['NSM1', self._read_fake], # record
(3701, 37, 995) : ['NSML1', self._read_fake], # record
(3601, 36, 62): ['NSML1', self._read_fake], # record 7
(15006, 150, 604): ['PCOMPG', self._read_pcompg], # record
(702, 7, 38): ['PBUSHT', self._read_pbusht], # record 1
(3301, 33, 56): ['NSM1', self._read_fake], # record 3
(3401, 34, 57) : ['NSMADD', self._read_fake], # record 5
(3501, 35, 58): ['NSML', self._read_fake], # record 6
(3501, 35, 994) : ['NSML', self._read_fake],
(1502, 15, 36): ['PAABSF', self._read_fake], # record 8
(8300, 83, 382): ['PACABS', self._read_fake], # record 9
(8500, 85, 384): ['PACBAR', self._read_fake], # record 10
(5403, 55, 349): ['PBCOMP', self._read_pbcomp], # record 13
(13301, 133, 509): ['PBMSECT', self._read_fake], # record 17
(2902, 29, 420): ['PCONVM', self._read_pconvm], # record 26
(1202, 12, 33): ['PDAMPT', self._read_pdampt], # record 28
(8702, 87, 412): ['PDAMP5', self._read_pdamp5], # record 29
(6802, 68, 164): ['PDUM8', self._read_fake], # record 37
(6902, 69, 165): ['PDUM9', self._read_fake], # record 38
(1302, 13, 34): ['PELAST', self._read_pelast], # record 41
(12001, 120, 480): ['PINTC', self._read_fake], # record 44
(12101, 121, 484): ['PINTS', self._read_fake], # record 45
(4606, 46, 375): ['PLPLANE', self._read_plplane], # record 46
(4706, 47, 376): ['PLSOLID', self._read_plsolid], # record 47
(10301, 103, 399): ['PSET', self._read_pset], # record 57
(3002, 30, 415): ['VIEW3D', self._read_fake], # record 63
(13501, 135, 510) : ['PFAST', self._read_pfast_msc], # MSC-specific
(3601, 36, 55) : ['PFAST', self._read_pfast_nx], # NX-specific
(3801, 38, 979) : ['PPLANE', self._read_fake],
(11801, 118, 560) : ['PWELD', self._read_fake],
(3401, 34, 993) : ['NSMADD', self._read_fake],
(9300, 93, 684) : ['ELAR', self._read_fake],
(9400, 94, 685) : ['ELAR2', self._read_fake],
(16006, 160, 903) : ['PCOMPS', self._read_fake],
# MSC-specific
(14602, 146, 692): ['PSLDN1', self._read_fake],
(16502, 165, 916): ['PAXSYMH', self._read_fake],
(13201, 132, 513): ['PBRSECT', self._read_fake],
(13701, 137, 638): ['PWSEAM', self._read_fake],
(7001, 70, 632): ['???', self._read_fake],
(15106, 151, 953): ['PCOMPG1', self._read_fake],
(3901, 39, 969): ['PSHL3D', self._read_fake],
(17006, 170, 901): ['MATCID', self._read_fake],
(9601, 96, 691): ['PJOINT', self._read_fake],
(16502, 165, 916): ['???', self._read_fake],
(9701, 97, 692): ['PJOINT2', self._read_fake],
(13401, 134, 611): ['PBEAM3', self._read_fake],
(8901, 89, 905): ['PSOLCZ', self._read_fake],
(9801, 98, 698): ['DESC', self._read_fake],
}
def _add_op2_property(self, prop):
"""helper method for op2"""
#if prop.pid > 100000000:
#raise RuntimeError('bad parsing; pid > 100000000...%s' % str(prop))
#print(str(prop)[:-1])
ntables = self.table_names.count(b'EPT') + self.table_names.count(b'EPTS')
pid = prop.pid
allow_overwrites = (
ntables > 1 and
pid in self.properties and
self.properties[pid].type == prop.type)
self._add_property_object(prop, allow_overwrites=allow_overwrites)
def _add_op2_property_mass(self, prop):
"""helper method for op2"""
#if prop.pid > 100000000:
#raise RuntimeError('bad parsing; pid > 100000000...%s' % str(prop))
#print(str(prop)[:-1])
ntables = self.table_names.count(b'EPT') + self.table_names.count(b'EPTS')
pid = prop.pid
allow_overwrites = (
ntables > 1 and
pid in self.properties_mass and
self.properties_mass[pid].type == prop.type)
self._add_property_mass_object(prop, allow_overwrites=allow_overwrites)
def _add_pconv(self, prop):
if prop.pconid > 100000000:
raise RuntimeError('bad parsing pconid > 100000000...%s' % str(prop))
self._add_convection_property_object(prop)
# HGSUPPR
def _read_nsm(self, data: bytes, n: int) -> int:
"""NSM"""
n = self._read_dual_card(data, n, self._read_nsm_nx, self._read_nsm_msc,
'NSM', self._add_nsm_object)
return n
def _read_nsm_msc(self, data: bytes, n: int) -> int:
"""
NSM(3201,32,55) - the marker for Record 2
MSC
1 SID I Set identification number
2 PROP CHAR4 Set of property or elements
3 ID I Property or element identification number
4 VALUE RS Nonstructural mass value
ORIGIN=0 NSM Bulk Data entry
5 ID I Property or element ID
6 VALUE RS Nonstructural mass value
Words 5 through 6 repeat until End of Record
ORIGIN=2 NSML Bulk Data entry
5 ID I Property or element ID
6 VALUE RS Nonstructural mass value
Words 5 through 6 repeat until End of Record
Words 3 through 4 repeat until End of Record
"""
properties = []
struct1 = Struct(self._endian + b'i 4s if')
ndelta = 16
i = 0
ints = np.frombuffer(data[n:], self.idtype).copy()
floats = np.frombuffer(data[n:], self.fdtype).copy()
while n < len(data):
edata = data[n:n+ndelta]
out = struct1.unpack(edata)
(sid, prop_set, pid, value) = out
# 538976312
assert pid < 100000000
i += 4
n += ndelta
prop_set = prop_set.decode('utf8').rstrip(' ') # \x00
values = [value]
#print('ints[i:]=', ints[i:])
while ints[i] != -1:
value2 = floats[i]
values.append(value2)
n += 4
i += 1
self.log.info("MSC: NSM-sid=%s prop_set=%s pid=%s values=%s" % (
sid, prop_set, pid, values))
prop = NSM.add_op2_data([sid, prop_set, pid, value])
#self._add_nsm_object(prop)
properties.append(prop)
# handle the trailing -1
i += 1
n += 4
return n, properties
def _read_nsm_nx(self, data: bytes, n: int) -> int:
"""
NSM(3201,32,55) - the marker for Record 2
1 SID I Set identification number
2 PROP(2) CHAR4 Set of properties or elements
4 ORIGIN I Entry origin
5 ID I Property or element identification number
6 VALUE RS Nonstructural mass value
Words 5 through 6 repeat until End of Record
"""
properties = []
#NX: C:\Users\sdoyle\Dropbox\move_tpl\nsmlcr2s.op2
struct1 = Struct(self._endian + b'i 8s ii f')
ndelta = 24
#self.show_data(data[12:], 'ifs')
i = 0
ints = np.frombuffer(data[n:], self.idtype).copy()
floats = np.frombuffer(data[n:], self.fdtype).copy()
unused_packs = break_by_minus1(ints)
#for pack in packs:
#print(pack)
#ipack = 0
while n < len(data):
#print('ints[i:]=', ints[i:].tolist())
#i1, i2 = packs[ipack]
#print('idata=%s' % idata[i1:i2])
#print('fdata=%s' % fdata[i1:i2])
#print(idata[i1:i2])
edata = data[n:n+ndelta]
out = struct1.unpack(edata)
(sid, prop_set, origin, pid, value) = out
# 538976312
assert pid < 100000000
i += 6
n += ndelta
prop_set = prop_set.decode('utf8').rstrip(' ') # \x00
pids = [pid]
values = [value]
#print('ints[i:]=', ints[i:].tolist())
while ints[i] != -1:
pid = ints[i]
value2 = floats[i+1]
assert pid != -1
pids.append(pid)
values.append(value2)
n += 8
i += 2
for pid, value in zip(pids, values):
if origin == 0:
#self.log.info("NX: NSM-sid=%s prop_set=%s pid=%s values=%s" % (
#sid, prop_set, pid, values))
prop = NSM.add_op2_data([sid, prop_set, pid, value])
elif origin == 2:
#self.log.info("NX: NSML-sid=%s prop_set=%s pid=%s values=%s" % (
#sid, prop_set, pid, values))
prop = NSML.add_op2_data([sid, prop_set, pid, value])
#print(prop.rstrip(), pid, value)
#self._add_nsm_object(prop)
properties.append(prop)
#print('----')
# handle the trailing -1
i += 1
n += 4
#ipack += 1
return n, properties
# NSM1
# NSML1
# NSMADD
# NSML
# NSML1
# PAABSF
# PACABS
# PACBAR
def _read_pbar(self, data: bytes, n: int) -> int:
"""
PBAR(52,20,181) - the marker for Record 11
.. warning:: this makes a funny property...
MSC 2016/NX10
Word Name Type Description
1 PID I Property identification number
2 MID I Material identification number
3 A RS Area
4 I1 RS Area moment of inertia in plane 1
5 I2 RS Area moment of inertia in plane 2
6 J RS Torsional constant
7 NSM RS Nonstructural mass per unit length
8 FE RS
9 C1 RS Stress recovery location at point C in element y-axis
10 C2 RS Stress recovery location at point C in element z-axis
11 D1 RS Stress recovery location at point D in element y-axis
12 D2 RS Stress recovery location at point D in element z-axis
13 E1 RS Stress recovery location at point E in element y-axis
14 E2 RS Stress recovery location at point E in element z-axis
15 F1 RS Stress recovery location at point F in element y-axis
16 F2 RS Stress recovery location at point F in element z-axis
17 K1 RS Area factor for shear in plane 1
18 K2 RS Area factor for shear in plane 2
19 I12 RS Area product of inertia for plane 1 and 2
"""
ntotal = 76 * self.factor # 19*4
struct1 = Struct(mapfmt(self._endian + b'2i17f', self.size))
nentries = (len(data) - n) // ntotal
for unused_i in range(nentries):
edata = data[n:n+ntotal]
out = struct1.unpack(edata)
#(pid, mid, a, I1, I2, J, nsm, fe, c1, c2, d1, d2,
#e1, e2, f1, f2, k1, k2, I12) = out
prop = PBAR.add_op2_data(out)
self._add_op2_property(prop)
n += ntotal
self.card_count['PBAR'] = nentries
return n
def _read_pbarl(self, data: bytes, n: int) -> int:
"""
PBARL(9102,91,52) - the marker for Record 12
TODO: buggy
It's possible to have a PBARL and a PBAR at the same time.
NSM is at the end of the element.
"""
valid_types = {
'ROD': 1,
'TUBE': 2,
'TUBE2': 2,
'I': 6,
'CHAN': 4,
'T': 4,
'BOX': 4,
'BAR': 2,
'CROSS': 4,
'H': 4,
'T1': 4,
'I1': 4,
'CHAN1': 4,
'Z': 4,
'CHAN2': 4,
"T2": 4,
'BOX1': 6,
'HEXA': 3,
'HAT': 4,
'HAT1': 5,
'DBOX': 10, # was 12
#'MLO TUBE' : 2,
} # for GROUP="MSCBML0"
size = self.size
ntotal = 28 * self.factor # 7*4 - ROD - shortest entry...could be buggy... # TODO fix this
if size == 4:
struct1 = Struct(self._endian + b'2i 8s 8s f')
else:
struct1 = Struct(self._endian + b'2q 16s 16s d')
#nentries = (len(data) - n) // ntotal
#print(self.show_ndata(80))
ndata = len(data)
while ndata - n > ntotal:
edata = data[n:n+ntotal]
n += ntotal
out = struct1.unpack(edata)
(pid, mid, group, beam_type, value) = out
if pid > 100000000 or pid < 1:
self.log.debug(" pid=%s mid=%s group=%r beam_type=%r value=%s" % (
pid, mid, group, beam_type, value))
raise RuntimeError('bad parsing...')
beam_type = reshape_bytes_block_size(beam_type, size=size)
group = reshape_bytes_block_size(group, size=size)
data_in = [pid, mid, group, beam_type, value]
expected_length = valid_types[beam_type]
iformat = self._endian + b'%if' % expected_length
ndelta = expected_length * 4
dims_nsm = list(unpack(iformat, data[n:n+ndelta]))
data_in += dims_nsm
#print(" pid=%s mid=%s group=%r beam_type=%r value=%s dims_nsm=%s" % (
#pid, mid, group, beam_type, value, dims_nsm))
# TODO why do i need the +4???
# is that for the nsm?
#min_len = expected_length * 4 + 4
#if len(data)
#data = data[n + expected_length * 4 + 4:]
n += ndelta
#prin( "len(out) = ",len(out)))
#print("PBARL = %s" % data_in)
prop = PBARL.add_op2_data(data_in) # last value is nsm
pid = prop.pid
if pid in self.properties:
#self.log.debug("removing:\n%s" % self.properties[pid])
self._type_to_id_map['PBAR'].remove(pid)
del self.properties[pid]
self._add_op2_property(prop)
#self.properties[pid] = prop
#print(prop.get_stats())
#print(self.show_data(data[n-8:-100]))
# the PBARL ends with a -1 flag
#value, = unpack(self._endian + b'i', data[n:n+4])
n += 4 * self.factor
if len(self._type_to_id_map['PBAR']) == 0 and 'PBAR' in self.card_count:
del self._type_to_id_map['PBAR']
del self.card_count['PBAR']
self.increase_card_count('PBARL')
#assert len(data) == n
return n
def _read_pbcomp(self, data: bytes, n: int) -> int:
"""
PBCOMP(5403, 55, 349)
pid mid A I1 I2 I12 J NSM
PBCOMP 3 2 2.00E-4 6.67E-9 1.67E-9 0.0 4.58E-9 0.0 +
pid mid
floats = (3, 2, 0.0002, 6.67e-09, 1.67e-09, 0.0, 4.58e-09, 0.0, 1.0, 1.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, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
ints = (3, 2, 0.0002, 6.67E-9, 1.67E-9, 0, 4.58E-9, 0, 1.0, 1.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)
"""
struct1 = Struct(mapfmt(self._endian + b'2i 12f i', self.size))
struct2 = Struct(mapfmt(self._endian + b'3f 2i', self.size))
nproperties = 0
ntotal1 = 60 * self.factor # 4*15
ntotal2 = 20 * self.factor
ndata = len(data)
#print(ntotal1, ntotal2)
if self.factor == 2:
self.show_data(data[12*self.factor:], types='qd')
#print(len(data[12*self.factor:]))
while n < ndata:
self.log.debug(f"n={n} ndata={ndata}")
edata = data[n:n+ntotal1]
#if len(edata) == ntotal1:
data1 = struct1.unpack(edata)
#else:
#self.show_data(edata, types='qdi')
#n += ntotal2
#continue
nsections = data1[-1]
if self.is_debug_file:
(pid, mid, a, i1, i2, i12, j, nsm, k1, k2,
m1, m2, n1, n2, unused_nsections) = data1
self.log.info(f'PBCOMP pid={pid} mid={mid} nsections={nsections} '
f'k1={k1} k2={k2} m=({m1},{m2}) n=({n1},{n2})\n')
#if pid > 0 and nsections == 0:
#print('n1')
#n += ntotal1
#continue
#if pid == 0 and nsections == 0:
#print('n2')
#n += ntotal2
#continue
data2 = []
n += ntotal1
if nsections in [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]:
# 16 Y RS Lumped area location along element's y-axis
# 17 Z RS Lumped area location along element's z-axis
# 18 C RS Fraction of the total area for the lumped area
# 19 MID I Material identification number
# 20 UNDEF None
# Words 16 through 20 repeat NSECT times
for unused_i in range(nsections):
datai = data[n:n+ntotal2]
xi, yi, ci, mid, unused_null = struct2.unpack(datai)
data2.append((xi, yi, ci, mid))
n += ntotal2
else:
raise NotImplementedError('PBCOMP nsections=%r' % nsections)
if self.is_debug_file:
self.binary_debug.write(' PBCOMP: %s\n' % str([data1, data2]))
msg = (
' i=%-2s so=%s xxb=%.1f a=%g i1=%g i2=%g i12=%g j=%g nsm=%g '
'c=[%s,%s] d=[%s,%s] e=[%s,%s] f=[%s,%s]' % (
nsections, None, -9999., a, i1, i2, i12, j, nsm,
None, None, None, None, None, None, None, None,)
)
self.log.debug(msg)
self.log.debug(data1)
self.log.debug(data2)
data_in = [data1, data2]
prop = PBCOMP.add_op2_data(data_in)
pid = data1[0]
if pid in self.properties:
self._type_to_id_map['PBEAM'].remove(pid)
del self.properties[pid]
self._add_op2_property(prop)
nproperties += 1
#print(f"n={n} ndata={ndata}")
assert nproperties > 0, 'PBCOMP nproperties=%s' % (nproperties)
if len(self._type_to_id_map['PBEAM']) == 0 and 'PBEAM' in self.card_count:
del self._type_to_id_map['PBEAM']
del self.card_count['PBEAM']
self.card_count['PBCOMP'] = nproperties
return n
def _read_pbeam(self, data: bytes, n: int) -> int:
"""
PBEAM(5402,54,262) - the marker for Record 14
.. todo:: add object
"""
cross_section_type_map = {
0 : 'variable',
1 : 'constant',
2 : '???',
}
struct1 = Struct(mapfmt(self._endian + b'4if', self.size))
struct2 = Struct(mapfmt(self._endian + b'16f', self.size))
struct3 = Struct(mapfmt(self._endian + b'16f', self.size))
unused_ntotal = 768 # 4*(5+16*12)
#nproperties = (len(data) - n) // ntotal
#assert nproperties > 0, 'ndata-n=%s n=%s datai\n%s' % (len(data)-n, n, self.show_data(data[n:100+n]))
ndata = len(data)
#self.show_data(data[12:], 'if')
#assert ndata % ntotal == 0, 'ndata-n=%s n=%s ndata%%ntotal=%s' % (len(data)-n, n, ndata % ntotal)
nproperties = 0
ntotal1 = 20 * self.factor
ntotal2 = 64 * self.factor
while n < ndata:
#while 1: #for i in range(nproperties):
edata = data[n:n+ntotal1]
n += ntotal1
data_in = list(struct1.unpack(edata))
#if self.is_debug_file:
#self.log.info('PBEAM pid=%s mid=%s nsegments=%s ccf=%s x=%s\n' % tuple(data_in))
(pid, unused_mid, unused_nsegments, ccf, unused_x) = data_in
#self.log.info('PBEAM pid=%s mid=%s nsegments=%s ccf=%s x=%s' % tuple(data_in))
# Constant cross-section flag: 1=yes and 0=no
# what is 2?
if ccf not in [0, 1, 2]:
msg = (' PBEAM pid=%s mid=%s nsegments=%s ccf=%s x=%s; '
'ccf must be in [0, 1, 2]\n' % tuple(data_in))
raise ValueError(msg)
cross_section_type = cross_section_type_map[ccf]
#print('cross_section_type = %s' % cross_section_type)
is_pbcomp = False
for i in range(11):
edata = data[n:n+ntotal2]
if len(edata) != ntotal2:
endpack = []
raise RuntimeError('PBEAM unexpected length i=%s...' % i)
n += ntotal2
pack = struct2.unpack(edata)
(soi, xxb, a, i1, i2, i12, j, nsm, c1, c2,
d1, d2, e1, e2, f1, f2) = pack
if soi == 0.0:
so_str = 'NO'
elif soi == 1.0:
so_str = 'YES'
else:
if soi < 0.:
msg = 'PBEAM pid=%s i=%s x/xb=%s soi=%s; soi not in 0.0 or 1.0; assuming PBCOMP & dropping' % (
pid, i, xxb, soi)
self.log.error(msg)
is_pbcomp = True
so_str = str(soi)
#msg = 'PBEAM pid=%s i=%s x/xb=%s soi=%s; soi not in 0.0 or 1.0' % (
#pid, i, xxb, soi)
#raise NotImplementedError(msg)
#if xxb != 0.0:
#msg = 'PBEAM pid=%s i=%s x/xb=%s soi=%s; xxb not in 0.0 or 1.0' % (
#pid, i, xxb, soi)
#raise NotImplementedError(msg)
pack2 = (so_str, xxb, a, i1, i2, i12, j, nsm, c1, c2,
d1, d2, e1, e2, f1, f2)
data_in.append(pack2)
if self.is_debug_file:
self.binary_debug.write(' %s\n' % str(pack))
msg = (
' i=%-2s' % i + ' so=%s xxb=%.1f a=%g i1=%g i2=%g i12=%g j=%g nsm=%g '
'c=[%s,%s] d=[%s,%s] e=[%s,%s] f=[%s,%s]' % (tuple(pack2))
)
self.binary_debug.write(msg)
#msg = (
#' i=%-2s' % i + ' so=%s xxb=%.1f a=%g i1=%g i2=%g i12=%g j=%g nsm=%g '
#'c=[%s,%s] d=[%s,%s] e=[%s,%s] f=[%s,%s]' % (tuple(pack2))
#)
#print(msg)
edata = data[n:n+ntotal2]
if len(edata) != ntotal2:
endpack = []
raise RuntimeError('PBEAM unexpected length 2...')
endpack = struct3.unpack(edata)
n += ntotal2
assert len(endpack) == 16, endpack
#(k1, k2, s1, s2, nsia, nsib, cwa, cwb, # 8
#m1a, m2a, m1b, m2b, n1a, n2a, n1b, n2b) = endpack # 8 -> 16
if self.is_debug_file:
self.binary_debug.write(' k=[%s,%s] s=[%s,%s] nsi=[%s,%s] cw=[%s,%s] '
'ma=[%s,%s] mb=[%s,%s] na=[%s,%s] nb=[%s,%s]' % (
tuple(endpack)))
data_in.append(endpack)
if is_pbcomp:
continue
if pid in self.properties:
if self.properties[pid].type == 'PBCOMP':
continue
prop = PBEAM.add_op2_data(data_in)
nproperties += 1
self._add_op2_property(prop)
if nproperties:
self.card_count['PBEAM'] = nproperties
return n
def _read_pbeaml(self, data: bytes, n: int) -> int:
"""
PBEAML(9202,92,53)
Word Name Type Description
1 PID I Property identification number
2 MID I Material identification number
3 GROUP(2) CHAR4 Cross-section group name
5 TYPE(2) CHAR4 Cross section type
7 VALUE RS Cross section values for XXB, SO, NSM, and dimensions
Word 7 repeats until (-1) occurs
"""
#strs = numpy.core.defchararray.reshapesplit(data, sep=",")
#ints = np.frombuffer(data[n:], self._uendian + 'i').copy()
#floats = np.frombuffer(data[n:], self._uendian + 'f').copy()
ints = np.frombuffer(data[n:], self.idtype8).copy()
floats = np.frombuffer(data[n:], self.fdtype8).copy()
iminus1 = np.where(ints == -1)[0]
istart = [0] + list(iminus1[:-1] + 1)
iend = iminus1
size = self.size
nproperties = len(istart)
if size == 4:
struct1 = Struct(self._endian + b'2i 8s 8s')
else:
struct1 = Struct(self._endian + b'2q 16s 16s')
for unused_i, (istarti, iendi) in enumerate(zip(istart, iend)):
idata = data[n+istarti*size : n+(istarti+6)*size]
pid, mid, group, beam_type = struct1.unpack(idata)
group = group.decode('latin1').strip()
beam_type = beam_type.decode('latin1').strip()
fvalues = floats[istarti+6: iendi]
if self.is_debug_file:
self.binary_debug.write(' %s\n' % str(fvalues))
self.log.debug(f'pid={pid:d} mid={mid:d} group={group} beam_type={beam_type}')
self.log.debug(fvalues)
#self.log.debug(f'pid={pid:d} mid={mid:d} group={group} beam_type={beam_type}')
data_in = [pid, mid, group, beam_type, fvalues]
prop = PBEAML.add_op2_data(data_in)
if pid in self.properties:
# this is a fake PSHELL
propi = self.properties[pid]
assert propi.type in ['PBEAM'], propi.get_stats()
nproperties -= 1
continue
self._add_op2_property(prop)
if nproperties:
self.card_count['PBEAML'] = nproperties
return len(data)
def _read_pbend(self, data: bytes, n: int) -> int:
"""PBEND"""
n = self._read_dual_card(data, n, self._read_pbend_nx, self._read_pbend_msc,
'PBEND', self._add_property_object)
return n
def _read_pbend_msc(self, data: bytes, n: int) -> int:
"""
PBEND
1 PID I Property identification number
2 MID I Material identification number
3 A RS Area
4 I1 RS Area moment of inertia in plane 1
5 I2 RS Area moment of inertia in plane 2
6 J RS Torsional constant
7 FSI I flexibility and stress intensification factors
8 RM RS Mean cross-sectional radius of the curved pipe
9 T RS Wall thickness of the curved pipe
10 P RS Internal pressure
11 RB RS Bend radius of the line of centroids
12 THETAB RS Arc angle of element
13 C1 RS Stress recovery location at point C in element y-axis
14 C2 RS Stress recovery location at point C in element z-axis
15 D1 RS Stress recovery location at point D in element y-axis
16 D2 RS Stress recovery location at point D in element z-axis
17 E1 RS Stress recovery location at point E in element y-axis
18 E2 RS Stress recovery location at point E in element z-axis
19 F1 RS Stress recovery location at point F in element y-axis
20 F2 RS Stress recovery location at point F in element z-axis
21 K1 RS Area factor for shear in plane 1
22 K2 RS Area factor for shear in plane 2
23 NSM RS Nonstructural mass per unit length
24 RC RS Radial offset of the geometric centroid
25 ZC RS Offset of the geometric centroid
26 DELTAN I Radial offset of the neutral axis from the geometric
centroid
"""
ntotal = 104 # 26*4
struct1 = Struct(self._endian + b'2i 4f i 18f f') # delta_n is a float, not an integer
nproperties = (len(data) - n) // ntotal
assert (len(data) - n) % ntotal == 0
assert nproperties > 0, 'table=%r len=%s' % (self.table_name, len(data) - n)
properties = []
for unused_i in range(nproperties):
edata = data[n:n+104]
out = struct1.unpack(edata)
(pid, mid, area, i1, i2, j, fsi, rm, t, p, rb, theta_b,
c1, c2, d1, d2, e1, e2, f1, f2, k1, k2, nsm, rc, zc,
delta_n) = out
beam_type = fsi
if (area, rm, t, p) == (0., 0., 0., 0.):
area = None
rm = None
t = None
p = None
delta_n = None
beam_type = 2
if delta_n == 0:
#: Radial offset of the neutral axis from the geometric
#: centroid, positive is toward the center of curvature
delta_n = None
pbend = PBEND(pid, mid, beam_type, area, i1, i2, j,
c1, c2, d1, d2, e1, e2, f1, f2, k1, k2,
nsm, rc, zc, delta_n, fsi, rm, t, p, rb, theta_b)
#print(pbend)
pbend.validate()
properties.append(pbend)
n += ntotal
return n, properties
def _read_pbend_nx(self, data: bytes, n: int) -> int:
"""
PBEND
1 PID I Property identification number
2 MID I Material identification number
3 A RS Area
4 I1 RS Area moment of inertia in plane 1
5 I2 RS Area moment of inertia in plane 2
6 J RS Torsional constant
7 FSI I Flexibility and stress intensification factors
8 RM RS Mean cross-sectional radius of the curved pipe
9 T RS Wall thickness of the curved pipe
10 P RS Internal pressure
11 RB RS Bend radius of the line of centroids
12 THETAB RS Arc angle of element
13 C1 RS Stress recovery location at point C in element y-axis
14 C2 RS Stress recovery location at point C in element z-axis
15 D1 RS Stress recovery location at point D in element y-axis
16 D2 RS Stress recovery location at point D in element z-axis
17 E1 RS Stress recovery location at point E in element y-axis
18 E2 RS Stress recovery location at point E in element z-axis
19 F1 RS Stress recovery location at point F in element y-axis
20 F2 RS Stress recovery location at point F in element z-axis
21 K1 RS Area factor for shear in plane 1
22 K2 RS Area factor for shear in plane 2
23 NSM RS Nonstructural mass per unit length
24 RC RS Radial offset of the geometric centroid
25 ZC RS Offset of the geometric centroid
26 DELTAN RS Radial offset of the neutral axis from the geometric
centroid
27 SACL RS Miter spacing at center line.
28 ALPHA RS One-half angle between the adjacent miter axis
(Degrees).
29 FLANGE I For FSI=5, defines the number of flanges attached.
30 KX RS For FSI=6, the user defined flexibility factor for the
torsional moment.
31 KY RS For FSI=6, the user defined flexibility factor for the
out-of-plane bending moment.
32 KZ RS For FSI=6, the user defined flexbility factor for the
in-plane bending moment.
33 Not used
"""
#self.log.info('skipping PBEND in EPT')
#return len(data)
ntotal = 132 # 33*4
struct1 = Struct(self._endian + b'2i 4f i 21f i 4f')
nproperties = (len(data) - n) // ntotal
assert (len(data) - n) % ntotal == 0
assert nproperties > 0, 'table=%r len=%s' % (self.table_name, len(data) - n)
properties = []
for unused_i in range(nproperties):
edata = data[n:n+132]
out = struct1.unpack(edata)
(pid, mid, area, i1, i2, j, fsi, rm, t, p, rb, theta_b,
c1, c2, d1, d2, e1, e2, f1, f2, k1, k2, nsm, rc, zc,
delta_n, unused_sacl, unused_alpha, unused_flange,
unused_kx, unused_ky, unused_kz, unused_junk,) = out
beam_type = fsi
pbend = PBEND(pid, mid, beam_type, area, i1, i2, j,
c1, c2, d1, d2, e1, e2, f1, f2, k1, k2,
nsm, rc, zc, delta_n, fsi, rm, t, p, rb, theta_b)
pbend.validate()
properties.append(pbend)
n += ntotal
return n, properties
# PBMSECT
# PBRSECT
def _read_pbush(self, data: bytes, n: int) -> int:
"""
The PBUSH card is different between MSC and NX Nastran.
DMAP NX 11
----------
NX has 23 fields in NX 11 (supported)
NX has 18 fields in the pre-2001 format (supported)
DMAP MSC 2005
-------------
MSC has 23 fields in 2005 (supported)
MSC has 18 fields in the pre-2001 format (supported)
DMAP MSC 2016
-------------
TODO: MSC has 24 fields in 2016.1 (not supported)
MSC has 18 fields in the pre-2001 format (supported)
"""
# we're listing nx twice because NX/MSC used to be consistent
# the new form for MSC is not supported
n = self._read_dual_card(data, n, self._read_pbush_nx, self._read_pbush_msc,
'PBUSH', self._add_op2_property)
return n
def _read_pbush_nx(self, data: bytes, n: int) -> int:
"""PBUSH(1402,14,37) - 18 fields"""
ntotal = 72 * self.factor
struct1 = Struct(mapfmt(self._endian + b'i17f', self.size))
ndata = len(data) - n
nentries = ndata // ntotal
assert nentries > 0, 'table={self.table_name} len={ndata}'
assert ndata % ntotal == 0, f'table={self.table_name} leftover = {ndata} % {ntotal} = {ndata % ntotal}'
props = []
for unused_i in range(nentries):
edata = data[n:n+ntotal]
out = struct1.unpack(edata)
(pid, k1, k2, k3, k4, k5, k6, b1, b2, b3, b4, b5, b6,
g1, sa, st, ea, et) = out
#self.log.debug(out)
g2 = g3 = g4 = g5 = g6 = g1
data_in = (pid, k1, k2, k3, k4, k5, k6, b1, b2, b3, b4, b5, b6,
g1, g2, g3, g4, g5, g6, sa, st, ea, et)
prop = PBUSH.add_op2_data(data_in)
props.append(prop)
n += ntotal
return n, props
def _read_pbush_msc(self, data: bytes, n: int) -> int:
"""PBUSH(1402,14,37) - 23 fields"""
ntotal = 92 * self.factor # 23*4
struct1 = Struct(mapfmt(self._endian + b'i22f', self.size))
ndata = len(data) - n
nentries = ndata // ntotal
assert nentries > 0, 'table={self.table_name} len={ndata}'
assert ndata % ntotal == 0, f'table={self.table_name} leftover = {ndata} % {ntotal} = {ndata % ntotal}'
props = []
for unused_i in range(nentries):
edata = data[n:n+ntotal]
out = struct1.unpack(edata)
#(pid, k1, k2, k3, k4, k5, k6, b1, b2, b3, b4, b5, b6,
#g1, g2, g3, g4, g5, g6, sa, st, ea, et) = out
prop = PBUSH.add_op2_data(out)
props.append(prop)
n += ntotal
return n, props
def _read_pbush1d(self, data: bytes, n: int) -> int:
"""
Record 18 -- PBUSH1D(3101,31,219)
1 PID I Property identification number
2 K RS Stiffness
3 C RS Viscous Damping
4 M RS Mass
5 ALPHA RS Temperature coefficient
6 SA RS Stress recovery coefficient
7 EA/SE RS Strain recovery coefficient
8 TYPEA I Shock data type:0=Null, 1=Table, 2=Equation
9 CVT RS Coefficient of translation velocity tension
10 CVC RS Coefficient of translation velocity compression
11 EXPVT RS Exponent of velocity tension
12 EXPVC RS Exponent of velocity compression
13 IDTSU I TABLEDi or DEQATN entry identification number for scale factor vs displacement
14 IDTCU I DEQATN entry identification number for scale factor vs displacement
15 IDTSUD I DEQATN entry identification number for derivative tension
16 IDCSUD I DEQATN entry identification number for derivative compression
17 TYPES I Spring data type: 0=Null, 1=Table, 2=Equation
18 IDTS I TABLEDi or DEQATN entry identification number for tension compression
19 IDCS I DEQATN entry identification number for compression
20 IDTDU I DEQATN entry identification number for scale factor vs displacement
21 IDCDU I DEQATN entry identification number for force vs displacement
22 TYPED I Damper data type: 0=Null, 1=Table, 2=Equation
23 IDTD I TABLEDi or DEQATN entry identification number for tension compression
24 IDCD I DEQATN entry identification number for compression
25 IDTDV I DEQATN entry identification number for scale factor versus velocity
26 IDCDV I DEQATN entry identification number for force versus velocity
27 TYPEG I General data type: 0=Null, 1=Table, 2=Equation
28 IDTG I TABLEDi or DEQATN entry identification number for tension compression
29 IDCG I DEQATN entry identification number for compression
30 IDTDU I DEQATN entry identification number for scale factor versus displacement
31 IDCDU I DEQATN entry identification number for force versus displacement
32 IDTDV I DEQATN entry identification number for scale factor versus velocity
33 IDCDV I DEQATN entry identification number for force vs velocity
34 TYPEF I Fuse data type: 0=Null, 1=Table
35 IDTF I TABLEDi entry identification number for tension
36 IDCF I TABLEDi entry identification number for compression
37 UT RS Ultimate tension
38 UC RS Ultimate compression
"""
type_map = {
0 : None, # NULL
1 : 'TABLE',
2 : 'EQUAT',
}
ntotal = 152 * self.factor # 38*4
struct1 = Struct(mapfmt(self._endian + b'i 6f i 4f 24i 2f', self.size))
nentries = (len(data) - n) // ntotal
for unused_i in range(nentries):
edata = data[n:n+ntotal]
out = struct1.unpack(edata)
(pid, k, c, m, unused_alpha, sa, se,
typea, cvt, cvc, expvt, expvc, idtsu, idtcu, idtsud, idcsud,
types, idts, idcs, idtdus, idcdus,
typed, idtd, idcd, idtdvd, idcdvd,
typeg, idtg, idcg, idtdug, idcdug, idtdvg, idcdvg,
typef, idtf, idcf,
unused_ut, unused_uc) = out
# test_op2_other_05
#pbush1d, 204, 1.e+5, 1000., , , , , , +pb1
#+pb1, spring, table, 205, , , , , , +pb2
#+pb2, damper, table, 206
#pid=204 k=100000.0 c=1000.0 m=0.0 sa=nan se=nan
msg = f'PBUSH1D pid={pid} k={k} c={c} m={m} sa={sa} se={se}'
optional_vars = {}
typea_str = type_map[typea]
types_str = type_map[types]
typed_str = type_map[typed]
unused_typeg_str = type_map[typeg]
unused_typef_str = type_map[typef]
if min([typea, types, typed, typeg, typef]) < 0:
raise RuntimeError(f'typea={typea} types={types} typed={typed} typeg={typeg} typef={typef}')
if typea in [1, 2]: # SHOCKA?
#pbush1d, 204, 1.e+5, 1000., , , , , , +pb4
#+pb4, shocka, table, 1000., , 1., , 214, , +pb41
#+pb41, spring, table, 205
idts = idtsu # if typea_str == 'TABLE' else 0
idets = idtsu # if typea_str == 'EQUAT' else 0
optional_vars['SHOCKA'] = [typea_str, cvt, cvc, expvt, expvc,
idts, idets, idtcu, idtsud, idcsud]
#(shock_type, shock_cvt, shock_cvc, shock_exp_vt, shock_exp_vc,
#shock_idts, shock_idets, shock_idecs, shock_idetsd, shock_idecsd
#)
#print('shock_idts, shock_idets', typea_str, idtsu, idtsu)
msg += (
f' SHOCKA type={typea} cvt={cvt} cvc={cvc} expvt={expvt} expvc={expvc}\n'
f' idtsu={idtsu} (idts={idts} idets={idets}) idtcu={idtcu} idtsud={idtsud} idcsud={idcsud}')
if types in [1, 2]: # SPRING: Spring data type: 0=Null, 1=Table, 2=Equation
#(spring_type, spring_idt, spring_idc, spring_idtdu, spring_idcdu) = values
# SPRING, TYPE IDT IDC IDTDU IDCDU
optional_vars['SPRING'] = [types_str, idts, idcs, idtdus, idcdus]
msg += f' SPRING type={types} idt={idts} idc={idcs} idtdu={idtdus} idcdu={idcdus}'
if typed in [1, 2]: # Damper data type: 0=Null, 1=Table, 2=Equation
optional_vars['DAMPER'] = [typed_str, idtd, idcd, idtdvd, idcdvd]
msg += f' DAMPER type={typed} idt={idtd} idc={idtd} idtdv={idtdvd} idcdv={idcdvd}'
if typeg in [1, 2]: # general, GENER?: 0=Null, 1=Table 2=Equation
# C:\NASA\m4\formats\git\examples\move_tpl\ar29scbt.bdf
#pbush1d, 206, 1.e+3, 10., , , , , , +pb6
#+pb6, gener, equat, 315, , 3015, , 3016
msg += f' GENER type={typeg} idt={idtg} idc={idcg} idtdu={idtdug} idcdu={idcdug} idtdv={idtdvg} idcdv={idcdvg}'
optional_vars['GENER'] = [idtg, idcg, idtdug, idcdug, idtdvg, idcdvg]
if typef in [1, 2]: # Fuse data type: 0=Null, 1=Table
raise NotImplementedError(f'typef={typef} idtf={idtf} idcf={idcf}')
if self.is_debug_file:
self.binary_debug.write(msg)
self.add_pbush1d(pid, k=k, c=c, m=m, sa=sa, se=se,
optional_vars=optional_vars,)
n += ntotal
self.card_count['PBUSH1D'] = nentries
return n
def _read_pbusht(self, data: bytes, n: int) -> int:
"""reads the PBUSHT"""
n, props = self._read_pbusht_nx(data, n)
for prop in props:
#print(prop)
self._add_pbusht_object(prop)
return n
def _read_pbusht_nx(self, data: bytes, n: int) -> int:
"""
NX 12 / MSC 2005
Word Name Type Description
1 PID I Property identification number
2 TKID(6) I TABLEDi entry identification numbers for stiffness
8 TBID(6) I TABLEDi entry identification numbers for viscous damping
14 TGEID(6) I TABLEDi entry identification number for structural damping
20 TKNID(6) I TABLEDi entry identification numbers for force versus deflection
old style
Word Name Type Description
1 PID I Property identification number
2 TKID(6) I TABLEDi entry identification numbers for stiffness
8 TBID(6) I TABLEDi entry identification numbers for viscous damping
14 TGEID I TABLEDi entry identification number for structural damping
15 TKNID(6) I TABLEDi entry IDs for force versus deflection
"""
#self.show_data(data[12:])
ndata = (len(data) - n) // self.factor
if ndata % 100 == 0 and ndata % 80 == 0:
self.log.warning(f"skipping PBUSHT in EPT because nfields={ndata//4}, which is "
'nproperties*25 or nproperties*20')
return len(data), []
if ndata % 100 == 0:
n, props = self._read_pbusht_100(data, n)
elif ndata % 80 == 0:
n, props = self._read_pbusht_80(data, n)
return n, props
def _read_pbusht_80(self, data: bytes, n: int) -> int:
"""
Word Name Type Description
1 PID I Property identification number
2 TKID(6) I TABLEDi entry identification numbers for stiffness
8 TBID(6) I TABLEDi entry identification numbers for viscous damping
14 TGEID I TABLEDi entry identification number for structural damping
15 TKNID(6) I TABLEDi entry identification numbers for force versus deflection
16,17,18,19,20
???
"""
ntotal = 80 * self.factor
struct1 = Struct(self._endian + b'20i')
nentries = (len(data) - n) // ntotal
assert nentries > 0, 'table=%r len=%s' % (self.table_name, len(data) - n)
props = []
for unused_i in range(nentries):
edata = data[n:n+ntotal]
out = struct1.unpack(edata)
#(pid,
#k1, k2, k3, k4, k5, k6,
#b1, b2, b3, b4, b5, b6,
#g1, sa, st, ea, et) = out
(pid,
k1, k2, k3, k4, k5, k6,
b1, b2, b3, b4, b5, b6,
g1,
n1, n2, n3, n4, n5, n6) = out
g2 = g3 = g4 = g5 = g6 = g1
k_tables = [k1, k2, k3, k4, k5, k6]
b_tables = [b1, b2, b3, b4, b5, b6]
ge_tables = [g1, g2, g3, g4, g5, g6]
kn_tables = [n1, n2, n3, n4, n5, n6]
prop = PBUSHT(pid, k_tables, b_tables, ge_tables, kn_tables)
props.append(prop)
n += ntotal
return n, props
def _read_pbusht_100(self, data: bytes, n: int) -> int:
props = []
ntotal = 100 * self.factor
struct1 = Struct(mapfmt(self._endian + b'25i', self.size))
nentries = (len(data) - n) // ntotal
assert nentries > 0, 'table=%r len=%s' % (self.table_name, len(data) - n)
for unused_i in range(nentries):
edata = data[n:n+ntotal]
out = struct1.unpack(edata)
(pid,
k1, k2, k3, k4, k5, k6,
b1, b2, b3, b4, b5, b6,
g1, g2, g3, g4, g5, g6,
n1, n2, n3, n4, n5, n6) = out
k_tables = [k1, k2, k3, k4, k5, k6]
b_tables = [b1, b2, b3, b4, b5, b6]
ge_tables = [g1, g2, g3, g4, g5, g6]
kn_tables = [n1, n2, n3, n4, n5, n6]
prop = PBUSHT(pid, k_tables, b_tables, ge_tables, kn_tables)
props.append(prop)
n += ntotal
return n, props
def _read_pcomp(self, data: bytes, n: int) -> int:
"""PCOMP(2706,27,287) - the marker for Record 22
standard:
EPTS; 64-bit: C:\MSC.Software\simcenter_nastran_2019.2\tpl_post1\cqrdbxdra3lg.op2
"""
if self.size == 4:
n2, props = self._read_pcomp_32_bit(data, n)
nproperties = len(props)
for prop in props:
self._add_op2_property(prop)
self.card_count['PCOMP'] = nproperties
else:
n2 = self._read_dual_card(data, n, self._read_pcomp_32_bit,
self._read_pcomp_64_bit,
'PCOMP', self._add_op2_property)
return n2
def _read_pcomp_64_bit(self, data: bytes, n: int) -> Tuple[int, List[PCOMP]]:
"""
PCOMP(2706,27,287) - the marker for Record 22
1 PID I Property identification number
2 N(C) I Number of plies
3 Z0 RS Distance from the reference plane to the bottom surface
4 NSM RS Nonstructural mass per unit area
5 SB RS Allowable shear stress of the bonding material
6 FT I Failure theory
7 TREF RS Reference temperature
8 GE RS Damping coefficient
9 MID I Material identification number
10 T RS Thicknesses of the ply
11 THETA RS Orientation angle of the longitudinal direction of the ply
12 SOUT I Stress or strain output request of the ply
Words 9 through 12 repeat N times
TODO:
64-bit bug: why is the number of plies 0???
doubles (float64) = (
1, 0.0, 1.7368e-18, 0.0, 1.0, 1.5e-323, 0.0, 0.0,
1, 0.11, 0, 1,
1, 0.11, 0, 1,
1, 0.11, 0, 1,
-1, -1, -1, -1,
21, 0.0, 1.7368e-18, 0.0, 1.0, 1.5e-323, 0.0, 0.0,
1, 0.11, 0, 1,
1, 0.11, 0, 1,
1, 0.11, 0, 1,
1, 0.11, 0, 1,
-1, -1, -1, -1)
long long (int64) = (
1, 0, 1.7368e-18, 0, 1.0, 3, 0, 0, 1, 4592590756007337001, 0, 1,
1, 0.11, 0, 1,
1, 0.11, 0, 1,
1, 0.11, 0, 1,
-1, -1, -1, -1,
21, 0, 4341475431749739292, 0, 4607182418800017408, 3, 0, 0,
1, 0.11, 0, 1,
1, 0.11, 0, 1,
1, 0.11, 0, 1,
1, 0.11, 0, 1,
-1, -1, -1, -1)
doubles (float64) = (5e-324, 0.0, -0.005, 0.0, 0.0, 0.0, 0.0, 0.0,
4e-323, 0.005, 0.0, 5e-324,
4e-323, 0.005, 0.0, 5e-324,
nan, nan, nan, nan)
long long (int64) = (1, 0, -4650957407178058629, 0, 0, 0, 0, 0,
8, 4572414629676717179, 0, 1,
8, 4572414629676717179, 0, 1,
-1, -1, -1, -1)
"""
self.to_nx()
nproperties = 0
s1 = Struct(mapfmt(self._endian + b'2i3fi2f', self.size))
ntotal1 = 32 * self.factor
s2 = Struct(mapfmt(self._endian + b'i2fi', self.size))
four_minus1 = Struct(mapfmt(self._endian + b'4i', self.size))
ndata = len(data)
ntotal2 = 16 * self.factor
props = []
while n < (ndata - ntotal1):
out = s1.unpack(data[n:n+ntotal1])
(pid, nlayers, z0, nsm, sb, ft, tref, ge) = out
assert pid > 0
if self.binary_debug:
self.binary_debug.write(f'PCOMP pid={pid} nlayers={nlayers} z0={z0} nsm={nsm} '
f'sb={sb} ft={ft} Tref={tref} ge={ge}')
assert isinstance(nlayers, int), out
#print(f'PCOMP pid={pid} nlayers={nlayers} z0={z0} nsm={nsm} '
#f'sb={sb} ft={ft} Tref={tref} ge={ge}')
n += ntotal1
# None, 'SYM', 'MEM', 'BEND', 'SMEAR', 'SMCORE', 'NO'
is_symmetrical = 'NO'
#if nlayers < 0:
#is_symmetrical = 'SYM'
#nlayers = abs(nlayers)
mids = []
T = []
thetas = []
souts = []
edata2 = data[n:n+ntotal2]
idata = four_minus1.unpack(edata2)
while idata != (-1, -1, -1, -1):
(mid, t, theta, sout) = s2.unpack(edata2)
mids.append(mid)
T.append(t)
thetas.append(theta)
souts.append(sout)
if self.is_debug_file:
self.binary_debug.write(f' mid={mid} t={t} theta={theta} sout={sout}\n')
n += ntotal2
#print(f' mid={mid} t={t} theta={theta} sout={sout}')
edata2 = data[n:n+ntotal2]
idata = four_minus1.unpack(edata2)
if self.size == 4:
assert 0 < nlayers < 100, 'pid=%s nlayers=%s z0=%s nms=%s sb=%s ft=%s Tref=%s ge=%s' % (
pid, nlayers, z0, nsm, sb, ft, tref, ge)
else:
assert nlayers == 0, nlayers
nlayers = len(mids)
data_in = [
pid, z0, nsm, sb, ft, tref, ge,
is_symmetrical, mids, T, thetas, souts]
prop = PCOMP.add_op2_data(data_in)
nproperties += 1
n += ntotal2
props.append(prop)
return n, props
def _read_pcomp_32_bit(self, data: bytes, n: int) -> Tuple[int, List[PCOMP]]: # pragma: no cover
"""PCOMP(2706,27,287) - the marker for Record 22"""
nproperties = 0
s1 = Struct(mapfmt(self._endian + b'2i3fi2f', self.size))
ntotal1 = 32 * self.factor
s2 = Struct(mapfmt(self._endian + b'i2fi', self.size))
ndata = len(data)
ntotal2 = 16 * self.factor
props = []
while n < (ndata - ntotal1):
out = s1.unpack(data[n:n+ntotal1])
(pid, nlayers, z0, nsm, sb, ft, tref, ge) = out
assert pid > 0
if self.binary_debug:
self.binary_debug.write(f'PCOMP pid={pid} nlayers={nlayers} z0={z0} nsm={nsm} '
f'sb={sb} ft={ft} Tref={tref} ge={ge}')
assert isinstance(nlayers, int), out
#print(f'PCOMP pid={pid} nlayers={nlayers} z0={z0} nsm={nsm} '
#f'sb={sb} ft={ft} Tref={tref} ge={ge}')
n += ntotal1
mids = []
T = []
thetas = []
souts = []
# None, 'SYM', 'MEM', 'BEND', 'SMEAR', 'SMCORE', 'NO'
is_symmetrical = 'NO'
if nlayers < 0:
is_symmetrical = 'SYM'
nlayers = abs(nlayers)
assert nlayers > 0, out
assert 0 < nlayers < 100, 'pid=%s nlayers=%s z0=%s nms=%s sb=%s ft=%s Tref=%s ge=%s' % (
pid, nlayers, z0, nsm, sb, ft, tref, ge)
if self.is_debug_file:
self.binary_debug.write(' pid=%s nlayers=%s z0=%s nms=%s sb=%s ft=%s Tref=%s ge=%s\n' % (
pid, nlayers, z0, nsm, sb, ft, tref, ge))
for unused_ilayer in range(nlayers):
(mid, t, theta, sout) = s2.unpack(data[n:n+ntotal2])
mids.append(mid)
assert mid > 0
T.append(t)
thetas.append(theta)
souts.append(sout)
if self.is_debug_file:
self.binary_debug.write(f' mid={mid} t={t} theta={theta} sout={sout}\n')
n += ntotal2
#print(f' mid={mid} t={t} theta={theta} sout={sout}\n')
data_in = [
pid, z0, nsm, sb, ft, tref, ge,
is_symmetrical, mids, T, thetas, souts]
prop = PCOMP.add_op2_data(data_in)
props.append(prop)
nproperties += 1
return n, props
def _read_pcompg(self, data: bytes, n: int) -> int:
"""
PCOMP(2706,27,287)
1 PID I Property identification number
2 LAMOPT I Laminate option
3 Z0 RS Distance from the reference plane to the bottom surface
4 NSM RS Nonstructural mass per unit area
5 SB RS Allowable shear stress of the bonding material
6 FT I Failure theory
7 TREF RS Reference temperature
8 GE RS Damping coefficient
9 GPLYIDi I Global ply IDs.
10 MID I Material identification number
11 T RS Thicknesses of the ply
12 THETA RS Orientation angle of the longitudinal direction of the ply
13 SOUT I Stress or strain output request of the ply
Words 9 through 13 repeat N times (until -1, -1, -1, -1, -1 as Nplies doesn't exist...)
float = (15006, 150, 604,
5, 0.0, 1.7368e-18, 0.0, 0.0, 0.0, 20.0, 0.0,
5e-324, 5e-324, 2.0, 0.0, 0.0,
1e-323, 1e-323, 3.0, 0.0, 0.0,
1.5e-323, 1e-323, 3.0, 0.0, 0.0,
2e-323, 5e-324, 2.0, 0.0, 0.0,
nan, nan, nan, nan, nan)
int = (15006, 150, 604,
5, 0, 1.7368e-18, 0, 0, 0, 20.0, 0,
1, 1, 4611686018427387904, 0, 0,
2, 2, 4613937818241073152, 0, 0,
3, 2, 4613937818241073152, 0, 0,
4, 1, 4611686018427387904, 0, 0,
-1, -1, -1, -1, -1)
"""
nproperties = 0
s1 = Struct(mapfmt(self._endian + b'2i 3f i 2f', self.size))
s2 = Struct(mapfmt(self._endian + b'2i 2f i', self.size))
struct_i5 = Struct(mapfmt(self._endian + b'5i', self.size))
# lam - SYM, MEM, BEND, SMEAR, SMCORE, None
lam_map = {
0 : None,
# MEM
# BEND
# SMEAR
# SMCORE
}
# ft - HILL, HOFF, TSAI, STRN, None
ft_map = {
0 : None,
# HILL
# HOFF
3 : 'TSAI',
# STRN
}
# sout - YES, NO
sout_map = {
0 : 'NO',
1 : 'YES',
}
ndata = len(data)
#self.show_data(data, types='qd')
ntotal1 = 32 * self.factor
ntotal2 = 20 * self.factor
while n < (ndata - ntotal1):
out = s1.unpack(data[n:n+ntotal1])
(pid, lam_int, z0, nsm, sb, ft_int, tref, ge) = out
if self.binary_debug:
self.binary_debug.write(f'PCOMPG pid={pid} lam_int={lam_int} z0={z0} nsm={nsm} '
f'sb={sb} ft_int={ft_int} tref={tref} ge={ge}')
#print(f'PCOMPG pid={pid} lam_int={lam_int} z0={z0} nsm={nsm} sb={sb} '
#f'ft_int={ft_int} tref={tref} ge={ge}')
assert isinstance(lam_int, int), out
assert pid > -1, out
n += ntotal1
mids = []
thicknesses = []
thetas = []
souts = []
global_ply_ids = []
# None, 'SYM', 'MEM', 'BEND', 'SMEAR', 'SMCORE', 'NO'
#is_symmetrical = 'NO'
#if nlayers < 0:
#is_symmetrical = 'SYM'
#nlayers = abs(nlayers)
#assert nlayers > 0, out
#assert 0 < nlayers < 100, 'pid=%s nlayers=%s z0=%s nms=%s sb=%s ft=%s tref=%s ge=%s' % (
#pid, nlayers, z0, nsm, sb, ft, tref, ge)
#if self.is_debug_file:
#self.binary_debug.write(' pid=%s nlayers=%s z0=%s nms=%s sb=%s ft=%s tref=%s ge=%s\n' % (
#pid, nlayers, z0, nsm, sb, ft, tref, ge))
ilayer = 0
while ilayer < 1000:
ints5 = struct_i5.unpack(data[n:n+ntotal2])
if ints5 == (-1, -1, -1, -1, -1):
if self.is_debug_file:
self.binary_debug.write(' global_ply=%-1 mid=%-1 t=%-1 theta=%-1 sout=-1\n')
break
(global_ply, mid, t, theta, sout_int) = s2.unpack(data[n:n+ntotal2])
#print(' ', (global_ply, mid, t, theta, sout_int))
try:
sout = sout_map[sout_int]
except KeyError:
self.log.error('cant parse global_ply=%s sout=%s; assuming 0=NO' % (
global_ply, sout_int))
sout = 'NO'
global_ply_ids.append(global_ply)
mids.append(mid)
thicknesses.append(t)
thetas.append(theta)
souts.append(sout)
if self.is_debug_file:
self.binary_debug.write(' global_ply=%s mid=%s t=%s theta=%s sout_int=%s sout=%r\n' % (
global_ply, mid, t, theta, sout_int, sout))
n += ntotal2
ilayer += 1
n += ntotal2
try:
ft = ft_map[ft_int]
except KeyError:
self.log.error('pid=%s cant parse ft=%s; should be HILL, HOFF, TSAI, STRN'
'...skipping' % (pid, ft_int))
continue
try:
lam = lam_map[lam_int]
except KeyError:
self.log.error('pid=%s cant parse lam=%s; should be HILL, HOFF, TSAI, STRN'
'...skipping' % (pid, lam_int))
continue
# apparently Nastran makes duplicate property ids...
if pid in self.properties and self.properties[pid].type == 'PCOMP':
del self.properties[pid]
self.add_pcompg(pid, global_ply_ids, mids, thicknesses, thetas=thetas, souts=souts,
nsm=nsm, sb=sb, ft=ft, tref=tref, ge=ge, lam=lam, z0=z0, comment='')
nproperties += 1
self.card_count['PCOMPG'] = nproperties
return n
# PCOMPA
def _read_pconeax(self, data: bytes, n: int) -> int:
"""
(152,19,147) - Record 24
"""
self.log.info('skipping PCONEAX in EPT')
return len(data)
def _read_pconv(self, data: bytes, n: int) -> int:
"""common method for reading PCONVs"""
n = self._read_dual_card(data, n, self._read_pconv_nx, self._read_pconv_msc,
'PCONV', self._add_pconv)
return n
def _read_pconv_nx(self, data: bytes, n: int) -> int:
"""
(11001,110,411)- NX version
"""
ntotal = 16 # 4*4
struct_3if = Struct(self._endian + b'3if')
nentries = (len(data) - n) // ntotal
assert (len(data) - n) % ntotal == 0
props = []
for unused_i in range(nentries):
out = struct_3if.unpack(data[n:n+ntotal])
(pconid, mid, form, expf) = out
ftype = tid = chlen = gidin = ce = e1 = e2 = e3 = None
data_in = (pconid, mid, form, expf, ftype, tid, chlen,
gidin, ce, e1, e2, e3)
prop = PCONV.add_op2_data(data_in)
props.append(prop)
n += ntotal
return n, props
def _read_pconv_msc(self, data: bytes, n: int) -> int:
"""
(11001,110,411)- MSC version - Record 25
"""
ntotal = 56 # 14*4
s = Struct(self._endian + b'3if 4i fii 3f')
nentries = (len(data) - n) // ntotal
assert (len(data) - n) % ntotal == 0
props = []
for unused_i in range(nentries):
out = s.unpack(data[n:n+ntotal])
(pconid, mid, form, expf, ftype, tid, unused_undef1, unused_undef2, chlen,
gidin, ce, e1, e2, e3) = out
data_in = (pconid, mid, form, expf, ftype, tid, chlen,
gidin, ce, e1, e2, e3)
prop = PCONV.add_op2_data(data_in)
props.append(prop)
n += ntotal
return n, props
def _read_pconvm(self, data: bytes, n: int) -> int:
"""Record 24 -- PCONVM(2902,29,420)
1 PID I Property identification number
2 MID I Material identification number
3 FORM I Type of formula used for free convection
4 FLAG I Flag for mass flow convection
5 COEF RS Constant coefficient used for forced convection
6 EXPR RS Reynolds number convection exponent
7 EXPPI RS Prandtl number convection exponent into the working fluid
8 EXPPO RS Prandtl number convection exponent out of the working fluid
"""
ntotal = 32 # 8*4
structi = Struct(self._endian + b'4i 4f')
nentries = (len(data) - n) // ntotal
for unused_i in range(nentries):
out = structi.unpack(data[n:n+ntotal])
if out != (0, 0, 0, 0, 0., 0., 0., 0.):
(pconid, mid, form, flag, coeff, expr, expri, exppo) = out
#print(out)
prop = PCONVM(pconid, mid, coeff, form=form, flag=flag,
expr=expr, exppi=expri, exppo=exppo, comment='')
self._add_convection_property_object(prop)
n += ntotal
self.card_count['PCONVM'] = nentries
return n
def _read_pdamp(self, data: bytes, n: int) -> int:
"""
PDAMP(202,2,45) - the marker for Record ???
"""
ntotal = 8 * self.factor # 2*4
struct_if = Struct(mapfmt(self._endian + b'if', self.size))
nentries = (len(data) - n) // ntotal
for unused_i in range(nentries):
out = struct_if.unpack(data[n:n+ntotal])
#(pid, b) = out
prop = PDAMP.add_op2_data(out)
self._add_op2_property(prop)
n += ntotal
self.card_count['PDAMP'] = nentries
return n
def _read_pdampt(self, data: bytes, n: int) -> int: # 26
self.log.info('skipping PDAMPT in EPT')
return len(data)
def _read_pdamp5(self, data: bytes, n: int) -> int: # 26
self.log.info('skipping PDAMP5 in EPT')
return len(data)
# PDUM1
# PDUM2
# PDUM3
# PDUM4
# PDUM5
# PDUM6
# PDUM7
# PDUM8
# PDUM9
def _read_pelas(self, data: bytes, n: int) -> int:
"""PELAS(302,3,46) - the marker for Record 39"""
ntotal = 16 * self.factor # 4*4
nproperties = (len(data) - n) // ntotal
struct_i3f = Struct(mapfmt(self._endian + b'i3f', self.size))
for unused_i in range(nproperties):
edata = data[n:n+ntotal]
out = struct_i3f.unpack(edata)
#(pid, k, ge, s) = out
if self.is_debug_file:
self.binary_debug.write(' PELAS=%s\n' % str(out))
prop = PELAS.add_op2_data(out)
self._add_op2_property(prop)
n += ntotal
self.card_count['PELAS'] = nproperties
return n
def _read_pfast_msc(self, data: bytes, n: int) -> int:
ntotal = 92 # 23*4
struct1 = Struct(self._endian + b'ifii 4f')
nproperties = (len(data) - n) // ntotal
for unused_i in range(nproperties):
edata = data[n:n+ntotal]
out = struct1.unpack(edata)
if self.is_debug_file:
self.binary_debug.write(' PFAST=%s\n' % str(out))
(pid, d, mcid, unused_connbeh, unused_conntype, unused_extcon,
unused_condtype, unused_weldtype, unused_minlen, unused_maxlen,
unused_gmcheck, unused_spcgs, mass, ge,
unused_aa, unused_bb, unused_cc, mcid, mflag,
kt1, kt2, kt3, kr1, kr2, kr3) = out
data_in = (pid, d, mcid, mflag, kt1, kt2, kt3,
kr1, kr2, kr3, mass, ge)
prop = PFAST.add_op2_data(data_in)
self._add_op2_property(prop)
n += ntotal
self.card_count['PFAST'] = nproperties
return n
def _read_pfast_nx(self, data: bytes, n: int) -> int:
"""
PFAST(3601,36,55)
NX only
"""
self.to_nx()
ntotal = 48
nproperties = (len(data) - n) // ntotal
delta = (len(data) - n) % ntotal
assert delta == 0, 'len(data)-n=%s n=%s' % (len(data) - n, (len(data) - n) / 48.)
struct1 = Struct(self._endian + b'ifii 8f')
for unused_i in range(nproperties):
edata = data[n:n+ntotal]
out = struct1.unpack(edata)
if self.is_debug_file:
self.binary_debug.write(' PFAST=%s\n' % str(out))
(pid, d, mcid, mflag, kt1, kt2, kt3, kr1, kr2, kr3, mass, ge) = out
data_in = (pid, d, mcid, mflag, kt1, kt2, kt3,
kr1, kr2, kr3, mass, ge)
prop = PFAST.add_op2_data(data_in)
self._add_op2_property(prop)
n += ntotal
self.card_count['PFAST'] = nproperties
return n
def _read_pelast(self, data: bytes, n: int) -> int:
"""
Record 41 -- PELAST(1302,13,34)
1 PID I Property identification number
2 TKID I TABLEDi entry identification number for stiffness
3 TGEID I TABLEDi entry identification number for structural
damping
4 TKNID I TABLEDi entry
"""
ntotal = 16 * self.factor
struct_4i = Struct(mapfmt(self._endian + b'4i', self.size))
nproperties = (len(data) - n) // ntotal
for unused_i in range(nproperties):
edata = data[n:n+ntotal]
out = struct_4i.unpack(edata)
if self.is_debug_file:
self.binary_debug.write(' PELAST=%s\n' % str(out))
#(pid, tkid, tgeid, tknid) = out
prop = PELAST.add_op2_data(out)
self._add_pelast_object(prop)
n += ntotal
self.card_count['PELAST'] = nproperties
return n
def _read_pgap(self, data: bytes, n: int) -> int:
"""
PGAP(2102,21,121) - the marker for Record 42
"""
ntotal = 44 * self.factor
struct_i10f = Struct(mapfmt(self._endian + b'i10f', self.size))
nproperties = (len(data) - n) // ntotal
for unused_i in range(nproperties):
edata = data[n:n+ntotal]
out = struct_i10f.unpack(edata)
if self.is_debug_file:
self.binary_debug.write(' PGAP=%s\n' % str(out))
#(pid,u0,f0,ka,kb,kt,mu1,mu2,tmax,mar,trmin) = out
prop = PGAP.add_op2_data(out)
self._add_op2_property(prop)
n += ntotal
self.card_count['PGAP'] = nproperties
return n
def _read_phbdy(self, data: bytes, n: int) -> int:
"""
PHBDY(2802,28,236) - the marker for Record 43
"""
struct_i3f = Struct(self._endian + b'ifff')
nproperties = (len(data) - n) // 16
for unused_i in range(nproperties):
edata = data[n:n+16]
out = struct_i3f.unpack(edata)
if self.is_debug_file:
self.binary_debug.write(' PHBDY=%s\n' % str(out))
#(pid, af, d1, d2) = out
prop = PHBDY.add_op2_data(out)
self._add_phbdy_object(prop)
n += 16
self.card_count['PHBDY'] = nproperties
return n
def _read_pintc(self, data: bytes, n: int) -> int:
self.log.info('skipping PINTC in EPT')
return len(data)
def _read_pints(self, data: bytes, n: int) -> int:
self.log.info('skipping PINTS in EPT')
return len(data)
def _read_plplane(self, data: bytes, n: int) -> int:
"""
PLPLANE(4606,46,375)
NX 10
1 PID I Property identification number
2 MID I Material identification number
3 CID I Coordinate system identification number
4 STR CHAR4 Location of stress and strain output
5 T RS Default membrane thickness for Ti on the connection entry
6 CSOPT I Reserved for coordinate system definition of plane
7 UNDEF(5) None
MSC 2016
PID I Property identification number
2 MID I Material identification number
3 CID I Coordinate system identification number
4 STR CHAR4 Location of stress and strain output
5 UNDEF(7 ) none Not used
.. warning:: CSOPT ad T are not supported
"""
ntotal = 44 * self.factor # 4*11
if self.size == 4:
s = Struct(self._endian + b'3i 4s f 6i')
else:
s = Struct(self._endian + b'3q 8s d 6q')
nentries = (len(data) - n) // ntotal
for unused_i in range(nentries):
out = s.unpack(data[n:n+ntotal])
pid, mid, cid, location, unused_t, unused_csopt = out[:6]
location = location.decode('latin1')
#self.show_data(data[n:n+ntotal], 'ifs')
self.add_plplane(pid, mid, cid=cid, stress_strain_output_location=location)
n += ntotal
self.card_count['PLPLANE'] = nentries
return n
def _read_plsolid(self, data: bytes, n: int) -> int:
"""
MSC 2016
1 PID I Property identification number
2 MID I Material identification number
3 STR CHAR4 Location of stress and strain output
4 UNDEF(4 ) none Not used
NX 10
1 PID I Property identification number
2 MID I Material identification number
3 STR CHAR4 Location of stress and strain output
4 CSOPT I Reserved for coordinate system definition of plane
5 UNDEF(3) None
.. warning:: CSOPT is not supported
"""
ntotal = 28 * self.factor # 4*7
if self.size == 4:
struct1 = Struct(self._endian + b'2i 4s 4i')
else:
struct1 = Struct(self._endian + b'2q 8s 4q')
nentries = (len(data) - n) // ntotal
for unused_i in range(nentries):
out = struct1.unpack(data[n:n+ntotal])
pid, mid, location, unused_csopt, unused_null_a, unused_null_b, unused_null_c = out
location = location.decode('latin1')
#self.show_data(data[n:n+ntotal], 'ifs')
self.add_plsolid(pid, mid, stress_strain=location, ge=0.)
n += ntotal
self.card_count['PLSOLID'] = nentries
return n
def _read_pmass(self, data: bytes, n: int) -> int:
"""
PMASS(402,4,44) - the marker for Record 48
"""
ntotal = 8 * self.factor # 2*4
nentries = (len(data) - n) // ntotal
struct_if = Struct(mapfmt(self._endian + b'if', self.size))
for unused_i in range(nentries):
edata = data[n:n + ntotal]
out = struct_if.unpack(edata)
#out = (pid, mass)
if self.is_debug_file:
self.binary_debug.write(' PMASS=%s\n' % str(out))
prop = PMASS.add_op2_data(out)
self._add_op2_property_mass(prop)
n += ntotal
return n
def _read_prod(self, data: bytes, n: int) -> int:
"""
PROD(902,9,29) - the marker for Record 49
"""
ntotal = 24 * self.factor # 6*4
struct_2i4f = Struct(mapfmt(self._endian + b'2i4f', self.size))
nproperties = (len(data) - n) // ntotal
for unused_i in range(nproperties):
edata = data[n:n+ntotal]
out = struct_2i4f.unpack(edata)
#(pid, mid, a, j, c, nsm) = out
prop = PROD.add_op2_data(out)
if self.is_debug_file:
self.binary_debug.write(' PROD=%s\n' % str(out))
self._add_op2_property(prop)
n += ntotal
self.card_count['PROD'] = nproperties
return n
def _read_pshear(self, data: bytes, n: int) -> int:
"""
PSHEAR(1002,10,42) - the marker for Record 50
"""
ntotal = 24 * self.factor
nproperties = (len(data) - n) // ntotal
struct_2i4f = Struct(mapfmt(self._endian + b'2i4f', self.size))
for unused_i in range(nproperties):
edata = data[n:n+ntotal]
out = struct_2i4f.unpack(edata)
#(pid, mid, t, nsm, f1, f2) = out
if self.is_debug_file:
self.binary_debug.write(' PSHEAR=%s\n' % str(out))
prop = PSHEAR.add_op2_data(out)
self._add_op2_property(prop)
n += ntotal
self.card_count['PSHEAR'] = nproperties
return n
def _read_pshell(self, data: bytes, n: int) -> int:
"""
PSHELL(2302,23,283) - the marker for Record 51
"""
ntotal = 44 * self.factor # 11*4
nproperties = (len(data) - n) // ntotal
s = Struct(mapfmt(self._endian + b'iififi4fi', self.size))
for unused_i in range(nproperties):
edata = data[n:n+ntotal]
out = s.unpack(edata)
(pid, mid1, unused_t, mid2, unused_bk, mid3, unused_ts,
unused_nsm, unused_z1, unused_z2, mid4) = out
if self.is_debug_file:
self.binary_debug.write(' PSHELL=%s\n' % str(out))
prop = PSHELL.add_op2_data(out)
n += ntotal
if pid in self.properties:
# this is a fake PSHELL
propi = self.properties[pid]
if prop == propi:
self.log.warning('Fake PSHELL (skipping):\n%s' % propi)
nproperties -= 1
continue
assert propi.type in ['PCOMP', 'PCOMPG'], propi.get_stats()
self.log.warning(f'PSHELL is also PCOMP (skipping PSHELL):\n{propi}{prop}')
nproperties -= 1
continue
if max(pid, mid1, mid2, mid3, mid4) > 1e8:
self.big_properties[pid] = prop
else:
self._add_op2_property(prop)
if nproperties:
self.card_count['PSHELL'] = nproperties
return n
def _read_psolid(self, data: bytes, n: int) -> int:
"""
PSOLID(2402,24,281) - the marker for Record 52
"""
#print("reading PSOLID")
if self.size == 4:
ntotal = 28 # 7*4
struct_6i4s = Struct(self._endian + b'6i4s')
else:
ntotal = 28 * 2
struct_6i4s = Struct(self._endian + b'6q8s')
nproperties = (len(data) - n) // ntotal
for unused_i in range(nproperties):
edata = data[n:n+ntotal]
out = struct_6i4s.unpack(edata)
#(pid, mid, cid, inp, stress, isop, fctn) = out
#data_in = [pid, mid, cid, inp, stress, isop, fctn]
if self.is_debug_file:
self.binary_debug.write(' PSOLID=%s\n' % str(out))
prop = PSOLID.add_op2_data(out)
self._add_op2_property(prop)
n += ntotal
self.card_count['PSOLID'] = nproperties
return n
# PSOLIDL
# PTRIA6
# PTSHELL
def _read_ptube(self, data: bytes, n: int) -> int:
"""
PTUBE(1602,16,30) - the marker for Record 56
.. todo:: OD2 only exists for heat transfer...
how do i know if there's heat transfer at this point?
I could store all the tubes and add them later,
but what about themal/non-thermal subcases?
.. warning:: assuming OD2 is not written (only done for thermal)
"""
ntotal = 20 * self.factor # 5*4
nproperties = (len(data) - n) // ntotal
struct_2i3f = Struct(self._endian + b'2i3f')
for unused_i in range(nproperties):
edata = data[n:n+20] # or 24???
out = struct_2i3f.unpack(edata)
(pid, mid, OD, t, nsm) = out
data_in = [pid, mid, OD, t, nsm]
if self.is_debug_file:
self.binary_debug.write(' PTUBE=%s\n' % str(out))
prop = PTUBE.add_op2_data(data_in)
self._add_op2_property(prop)
n += 20
self.card_count['PTUBE'] = nproperties
return n
def _read_pset(self, data: bytes, n: int) -> int:
struct_5i4si = Struct(self._endian + b'5i4si')
nentries = 0
while n < len(data):
edata = data[n:n+28]
out = struct_5i4si.unpack(edata)
#print(out)
idi, poly1, poly2, poly3, cid, typei, typeid = out
typei = typei.rstrip().decode('latin1')
assert typei in ['SET', 'ELID'], (idi, poly1, poly2, poly3, cid, typei, typeid)
if self.is_debug_file:
self.binary_debug.write(' PVAL=%s\n' % str(out))
#print(idi, poly1, poly2, poly3, cid, typei, typeid)
typeids = []
n += 28
while typeid != -1:
typeids.append(typeid)
typeid, = self.struct_i.unpack(data[n:n+4])
n += 4
#print(val)
#print(typeids)
# PSET ID POLY1 POLY2 POLY3 CID SETTYP ID
self.add_pset(idi, poly1, poly2, poly3, cid, typei, typeids)
self.card_count['PSET'] = nentries
return n
def _read_pval(self, data: bytes, n: int) -> int:
"""
PVAL(10201,102,400)
Word Name Type Description
1 ID I p-value set identification number
2 POLY1 I Polynomial order in 1 direction of the CID system
3 POLY2 I Polynomial order in 2 direction of the CID system
4 POLY3 I Polynomial order in 2 direction of the CID system
5 CID I Coordinate system identification number
6 TYPE CHAR4 Type of set provided: "SET" or "ELID"
7 TYPEID I SET identification number or element identification
number with this p-value specification.
Words 1 through 7 repeat until End of Record
"""
#self.show_data(data[n:])
if self.size == 4:
struct_5i4si = Struct(self._endian + b'5i 4s i')
struct_i = self.struct_i
else:
struct_5i4si = Struct(self._endian + b'5q 8s q')
struct_i = self.struct_q
nentries = 0
ntotal = 28 * self.factor
size = self.size
while n < len(data):
edata = data[n:n+ntotal]
out = struct_5i4si.unpack(edata)
#print(out)
idi, poly1, poly2, poly3, cid, typei, typeid = out
typei = typei.rstrip().decode('latin1')
assert typei in ['SET', 'ELID'], f'idi={idi} poly1={poly1} poly2={poly2} poly3={poly3} cid={cid} typei={typei} typeid={typeid}'
if self.is_debug_file:
self.binary_debug.write(' PVAL=%s\n' % str(out))
#print(idi, poly1, poly2, poly3, cid, typei, typeid)
typeids = []
n += ntotal
while typeid != -1:
typeids.append(typeid)
typeid, = struct_i.unpack(data[n:n+size])
n += size
#print(val)
#print(typeids)
# PVAL ID POLY1 POLY2 POLY3 CID SETTYP ID
self.add_pval(idi, poly1, poly2, poly3, cid, typei, typeids)
self.card_count['PVAL'] = nentries
return n
def _read_pvisc(self, data: bytes, n: int) -> int:
"""PVISC(1802,18,31) - the marker for Record 39"""
struct_i2f = Struct(self._endian + b'i2f')
nproperties = (len(data) - n) // 12
for unused_i in range(nproperties):
edata = data[n:n+12]
out = struct_i2f.unpack(edata)
if self.is_debug_file:
self.binary_debug.write(' PVISC=%s\n' % str(out))
#(pid, ce, cr) = out
prop = PVISC.add_op2_data(out)
self._add_op2_property(prop)
n += 12
self.card_count['PVISC'] = nproperties
return n
# PWELD
# PWSEAM
def _read_view(self, data: bytes, n: int) -> int:
self.log.info('geom skipping VIEW in EPT')
return len(data)
def _read_view3d(self, data: bytes, n: int) -> int:
self.log.info('geom skipping VIEW3D in EPT')
return len(data)
[docs]def break_by_minus1(idata):
"""helper for ``read_nsm_nx``"""
i1 = 0
i = 0
i2 = None
packs = []
for idatai in idata:
#print('data[i:] = ', data[i:])
if idatai == -1:
i2 = i
packs.append((i1, i2))
i1 = i2 + 1
i += 1
continue
i += 1
#print(packs)
return packs