Skip to content

Commit da3a660

Browse files
authored
Add PGPLSN card support (#849)
* Add PGPLSN card support (bdf/op2 reading/writing) * Add unit test for PGPLSN functionality * reverse unintended code of separate pull request (MATS1 update)
1 parent 544d404 commit da3a660

File tree

9 files changed

+300
-7
lines changed

9 files changed

+300
-7
lines changed

pyNastran/bdf/bdf.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@
9090
CPLSTS3, CPLSTS4, CPLSTS6, CPLSTS8,
9191
SNORM,)
9292

93-
from .cards.properties.shell import PSHELL, PCOMP, PCOMPG, PSHEAR, PLPLANE, PPLANE, PTRSHL
93+
from .cards.properties.shell import PSHELL, PCOMP, PCOMPG, PSHEAR, PLPLANE, PPLANE, PGPLSN, PTRSHL
9494
from .cards.elements.acoustic import (
9595
CHACAB, CAABSF, CHACBR, PACABS, PAABSF, PACBAR,
9696
ACMODL, PMIC, ACPLNW, AMLREG, MATPOR, MICPNT)
@@ -251,7 +251,7 @@
251251
PBAR | PBARL | PBEAM | PBRSECT |
252252
PBEAML | PBCOMP | PBMSECT |
253253
PBEND | PBEAM3 |
254-
PSHEAR | PPLANE |
254+
PSHEAR | PPLANE | PGPLSN |
255255
PSHELL | PCOMP | PCOMPG |
256256
PSOLID | PLSOLID | PCOMPS | PCOMPLS |
257257
PWELD
@@ -722,7 +722,7 @@ def __init__(self, debug: str | bool | None=True,
722722

723723
## properties
724724
'PMASS',
725-
'PELAS', 'PGAP', 'PFAST', 'PWELD', 'PLPLANE', 'PPLANE',
725+
'PELAS', 'PGAP', 'PFAST', 'PWELD', 'PLPLANE', 'PPLANE', 'PGPLSN',
726726
'PBUSH', 'PBUSH1D', 'PBUSH2D',
727727
'PDAMP', 'PDAMP5',
728728
'PROD', 'PBAR', 'PBARL', 'PBEAM', 'PTUBE', 'PBCOMP', 'PBRSECT', 'PBEND',
@@ -2601,6 +2601,7 @@ def add_card(cls, card: BDFCard, comment: str=''):
26012601
'CPLSTS6': (CPLSTS6, add_methods.add_element_object),
26022602
'CPLSTS8': (CPLSTS8, add_methods.add_element_object),
26032603
'PPLANE': (PPLANE, add_methods.add_property_object),
2604+
'PGPLSN': (PGPLSN, add_methods.add_property_object),
26042605

26052606
'CSHEAR': (CSHEAR, add_methods.add_element_object),
26062607
'PSHEAR': (PSHEAR, add_methods.add_property_object),

pyNastran/bdf/bdf_interface/add_card.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
from pyNastran.bdf.cards.elements.acoustic import (
5656
CHACAB, CAABSF, CHACBR, PACABS, PAABSF, PACBAR,
5757
ACMODL, ACPLNW, AMLREG, PMIC, MICPNT, MATPOR)
58-
from pyNastran.bdf.cards.properties.shell import PSHELL, PCOMP, PCOMPG, PSHEAR, PLPLANE, PPLANE
58+
from pyNastran.bdf.cards.properties.shell import PSHELL, PCOMP, PCOMPG, PSHEAR, PLPLANE, PPLANE, PGPLSN
5959
from pyNastran.bdf.cards.elements.bush import CBUSH, CBUSH1D, CBUSH2D
6060
from pyNastran.bdf.cards.properties.bush import (
6161
PBUSH, PBUSH1D, PBUSHT, PBUSH2D, PBUSH_OPTISTRUCT)
@@ -338,6 +338,8 @@
338338
'CPLSTS8': CPLSTS8,
339339
'PPLANE': PPLANE,
340340

341+
'PGPLSN': PGPLSN,
342+
341343
'CSHEAR': CSHEAR,
342344
'PSHEAR': PSHEAR,
343345

@@ -7194,6 +7196,15 @@ def add_pplane(self, pid: int, mid: int, t: float=0.0, nsm: float=0.0,
71947196
self._add_methods.add_property_object(prop)
71957197
return prop
71967198

7199+
def add_pgplsn(self, pid: int, mid: int, cgid: int, t: float,
7200+
kn: float | int = 0., kr1: float | int = 0., kr2: float | int = 0.,
7201+
comment: str='') -> PGPLSN:
7202+
"""Creates a PGPLSN card"""
7203+
prop = PGPLSN(pid, mid, cgid=cgid, t=t, kn=kn, kr1=kr1, kr2=kr2, comment=comment)
7204+
7205+
self._add_methods.add_property_object(prop)
7206+
return prop
7207+
71977208
def add_cplstn3(self, eid, pid, nids, theta=0.0, comment='') -> CPLSTN3:
71987209
"""Creates a CPLSTN4 card"""
71997210
elem = CPLSTN3(eid, pid, nids, theta=theta, comment=comment)

pyNastran/bdf/bdf_interface/attributes.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@
199199
'PBEAM3',
200200

201201
# 2d
202-
'PLPLANE', 'PPLANE',
202+
'PLPLANE', 'PPLANE', 'PGPLSN',
203203
'PSHELL', 'PCOMP', 'PCOMPG', 'PSHEAR',
204204
'PSOLID', 'PLSOLID', 'PVISC', 'PRAC2D', 'PRAC3D',
205205
'PCOMPS', 'PCOMPLS',

pyNastran/bdf/cards/properties/shell.py

Lines changed: 131 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
from pyNastran.bdf.cards.materials import get_mat_props_S
2727
from pyNastran.bdf.bdf_interface.internal_get import coord_id, material_id
2828
from pyNastran.bdf.bdf_interface.assign_type import (
29-
integer, integer_or_blank, double, double_or_blank, string_or_blank,
29+
integer, integer_or_blank, double, double_or_blank, string_or_blank, integer_double_or_blank
3030
)
3131
from pyNastran.bdf.bdf_interface.assign_type_force import force_double_or_blank
3232
from pyNastran.bdf.field_writer_8 import print_card_8
@@ -2018,6 +2018,136 @@ def write_card(self, size: int=8, is_double: bool=False) -> str:
20182018
return self.comment + print_card_8(card)
20192019

20202020

2021+
class PGPLSN(Property):
2022+
type = 'PGPLSN'
2023+
_field_map = {1: 'pid',
2024+
2:'mid',
2025+
3:'cgid',
2026+
4:'t',
2027+
5:'kn',
2028+
6: 'kr1',
2029+
7: 'kr2',
2030+
}
2031+
2032+
@classmethod
2033+
def _init_from_empty(cls):
2034+
return PGPLSN(pid=1, mid=1, cgid=1, t=1.)
2035+
2036+
def __init__(self, pid: int, mid: int, cgid: int, t: float,
2037+
kn: float | int = 0., kr1: float | int = 0., kr2: float | int = 0.,
2038+
comment: str=''):
2039+
2040+
"""
2041+
Generalized Plane Strain Element Property for SOL 401 (NX Nastran)
2042+
:param pid: Property identification number. (Integer > 0)
2043+
:param mid: Identification number of a MAT1 or MAT11 entry. (Integer > 0; No default)
2044+
:param cgid: Identification number of control grid point. (Integer > 0; No default)
2045+
:param t: Undeformed element thickness (Real > 0.0; No default)
2046+
:param kn: Optional user-specified additive normal stiffness relative to the planar area defined by the mesh of
2047+
generalized plane strain elements. (Real ≥ 0.0 or Integer > 0; Default = 0.0)
2048+
If real entry, value of stiffness at all times.
2049+
If integer entry, identification number of a TABLEDi entry that contains value of stiffness as a
2050+
function of time.
2051+
:param kr1, kr2: Optional user-specified additive rotational stiffness in the units moment/radian about the
2052+
ith-axis of the displacement coordinate system for the control grid point. See Remark 3.
2053+
(Real ≥ 0.0 or Integer > 0; Default = 0.0)
2054+
If real entry, value of stiffness at all times.
2055+
If integer entry, identification number of a TABLEDi entry that contains value of stiffness as a function of
2056+
time.
2057+
"""
2058+
2059+
Property.__init__(self)
2060+
if comment:
2061+
self.comment = comment
2062+
2063+
self.pid = pid
2064+
self.mid = mid
2065+
self.cgid = cgid
2066+
self.t = t
2067+
self.kn = kn
2068+
self.kr1, self.kr2 = kr1, kr2
2069+
2070+
self.mid_ref = None # for cross-referencing
2071+
2072+
@classmethod
2073+
def add_card(cls, card, comment=''):
2074+
"""
2075+
Adds a PGPLSN card from ``BDF.add_card(...)``
2076+
2077+
Parameters
2078+
----------
2079+
card : BDFCard()
2080+
a BDFCard object
2081+
comment : str; default=''
2082+
a comment for the card
2083+
2084+
"""
2085+
pid = integer(card, 1, 'pid')
2086+
mid = integer(card, 2, 'mid') # MAT1, MAT11
2087+
cgid = integer(card, 3, 'cgid')
2088+
2089+
t = double(card, 4, 't')
2090+
kn = integer_double_or_blank(card, 5, 'kn', default=0.)
2091+
kr1 = integer_double_or_blank(card, 6, 'kr1', default=0.)
2092+
kr2 = integer_double_or_blank(card, 7, 'kr2', default=0.)
2093+
2094+
return PGPLSN(pid, mid, cgid=cgid, t=t, kn=kn, kr1=kr1, kr2=kr2, comment=comment)
2095+
2096+
def cross_reference(self, model: BDF) -> None:
2097+
"""
2098+
Cross links the card so referenced cards can be extracted directly
2099+
2100+
Parameters
2101+
----------
2102+
model : BDF()
2103+
the BDF object
2104+
2105+
"""
2106+
msg = ', which is required by PGPLSN pid=%s' % self.pid
2107+
self.mid_ref = model.Material(self.mid, msg)
2108+
2109+
def safe_cross_reference(self, model: BDF, xref_errors) -> None:
2110+
"""
2111+
Cross links the card so referenced cards can be extracted directly
2112+
2113+
Parameters
2114+
----------
2115+
model : BDF()
2116+
the BDF object
2117+
2118+
"""
2119+
msg = ', which is required by PGPLSN pid=%s' % self.pid
2120+
self.mid_ref = model.safe_material(self.mid, self.pid, xref_errors, msg)
2121+
2122+
def uncross_reference(self) -> None:
2123+
"""Removes cross-reference links"""
2124+
self.mid = self.Mid()
2125+
self.mid_ref = None
2126+
2127+
def _verify(self, xref):
2128+
unused_pid = self.Pid()
2129+
unused_mid = self.Mid()
2130+
#stress_strain_output_location = self.stress_strain_output_location
2131+
if xref:
2132+
assert self.mid_ref.type in ['MAT1', 'MAT11'], 'PGPLSN: mid.type=%s' % self.mid_ref.type
2133+
2134+
def Mid(self) -> int:
2135+
"""returns the material id"""
2136+
return material_id(self.mid_ref, self.mid)
2137+
2138+
def raw_fields(self) -> list:
2139+
list_fields = ['PGPLSN', self.pid, self.Mid(), self.cgid, self.t, self.kn, self.kr1, self.kr2]
2140+
return list_fields
2141+
2142+
def repr_fields(self) -> list:
2143+
list_fields = ['PGPLSN', self.pid, self.Mid(), self.cgid, self.t, self.kn, self.kr1, self.kr2]
2144+
return list_fields
2145+
2146+
def write_card(self, size: int=8, is_double: bool=False) -> str:
2147+
card = self.repr_fields()
2148+
return self.comment + print_card_8(card)
2149+
2150+
20212151
class PSHEAR(Property):
20222152
"""
20232153
Defines the properties of a shear panel (CSHEAR entry).

pyNastran/bdf/cards/test/test_shells.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -887,6 +887,31 @@ def test_ctriar_cquadr(self):
887887

888888
save_load_deck(model)
889889

890+
def test_pgplsn(self):
891+
"""tests a PGPLSN property card"""
892+
log = SimpleLogger(level='warning')
893+
model = BDF(log=log)
894+
895+
# create control grid point, mat1 material and pgplsn property
896+
# test both integer and float-valued knr properties
897+
for knr in (1, 0.):
898+
model = BDF(log=log)
899+
900+
cgrid = model.add_grid(1, [0., 0., 0.])
901+
mat1 = model.add_mat1(mid=1, E=1e7, G=None, nu=0.3)
902+
pgplsn = model.add_pgplsn(pid=1, mid=mat1.mid, cgid=cgrid.nid,
903+
t=1.0, kn=knr, kr1=knr, kr2=knr,)
904+
905+
model.validate()
906+
model._verify_bdf(xref=False)
907+
pgplsn.write_card(size=8)
908+
model.cross_reference()
909+
model.pop_xref_errors()
910+
911+
model.uncross_reference()
912+
model.safe_cross_reference()
913+
save_load_deck(model)
914+
890915
def test_cplsts3(self):
891916
log = SimpleLogger(level='warning')
892917
model = BDF(log=log)

pyNastran/bdf/mesh_utils/convert.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -586,7 +586,7 @@ def _convert_properties(model: BDF,
586586
'PSOLID', 'PLSOLID', 'PLPLANE',
587587

588588
# TODO: NX-verify
589-
'PPLANE',
589+
'PPLANE', 'PGPLSN',
590590

591591
# acoustic
592592
'PACABS', 'PMIC',

pyNastran/bdf/mesh_utils/remove_unused.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,11 @@ def remove_unused(bdf_filename: PathLike,
290290
for pid in ids:
291291
prop = model.properties[pid]
292292
mids_used.add(prop.Mid())
293+
elif card_type == 'PGPLSN':
294+
for pid in ids:
295+
prop = model.properties[pid]
296+
mids_used.add(prop.Mid())
297+
nids_used.add(prop.cgid)
293298

294299
elif card_type in {'PLOTEL', 'PLOTEL3', 'PLOTEL4',
295300
'PLOTEL6', 'PLOTEL8'}:

pyNastran/op2/tables/geom/ept.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ def __init__(self, op2: OP2Geom):
113113
(13501, 135, 510): ['PFAST', self.read_pfast_msc], # MSC-specific
114114
(3601, 36, 55): ['PFAST', self.read_pfast_nx], # NX-specific
115115
(3801, 38, 979): ['PPLANE', self.read_pplane],
116+
(4102,41,904): ['PGPLSN', self.read_pgplsn],
116117
(11801, 118, 560): ['PWELD', self.read_fake],
117118
(3401, 34, 993): ['NSMADD', self.read_nsmadd],
118119
(9300, 93, 684): ['ELAR', self.read_fake],
@@ -3370,6 +3371,56 @@ def read_pplane(self, data: bytes, n: int) -> int:
33703371
op2.card_count['PLPLANE'] = nentries
33713372
return n
33723373

3374+
def read_pgplsn(self, data: bytes, n: int) -> int:
3375+
"""
3376+
RECORD – PGPLSN(4102,41,904)
3377+
3378+
Word Name Type Description
3379+
1 PID I Property identification number
3380+
2 MID I Material identification number
3381+
3 CGID I Control grid point identification number
3382+
4 T RS Default membrane thickness for Ti on the connection entry
3383+
5-8 UNDEF(4)
3384+
9 TYPE I Integer flag indicating the data type for KNR (word 10)
3385+
TYPE=0, KNR will be undefined
3386+
TYPE=1, KNR will be an integer
3387+
TYPE=2, KNR will be a real value
3388+
10 KNR I, RS, blank I: Table ID for time dependent user specified stiffness
3389+
RS: User specified additive stiffness
3390+
Words 9 and 10 repeat 3 times
3391+
15 CSOPT I Reserved for coordinate system definition of plane
3392+
16 UNDEF
3393+
"""
3394+
op2: OP2Geom = self.op2
3395+
ntotal = 64 * self.factor # 16*4
3396+
struct_i = Struct(mapfmt(op2._endian + b'3i 1f 12i', self.size))
3397+
struct_f = Struct(mapfmt(op2._endian + b'3i 1f 5i 1f 1i 1f 1i 1f 2i', self.size))
3398+
3399+
ndatai = len(data) - n
3400+
nentries = ndatai // ntotal
3401+
assert ndatai % ntotal == 0
3402+
for unused_i in range(nentries):
3403+
out_i = struct_i.unpack(data[n:n+ntotal])
3404+
out_f = struct_f.unpack(data[n:n+ntotal])
3405+
3406+
pid, mid, cgid = out_i[:3]
3407+
t = out_f[4]
3408+
3409+
kn_type, kr1_type, kr2_type, csopt = out_i[8], out_i[10], out_i[12], out_i[14]
3410+
kn = out_i[9] if kn_type != 2 else out_f[9]
3411+
kr1 = out_i[11] if kr1_type != 2 else out_f[11]
3412+
kr2 = out_i[13] if kr2_type != 2 else out_f[13]
3413+
3414+
#print(out)
3415+
assert csopt == 0, csopt
3416+
pgplsn = op2.add_pgplsn(pid, mid, cgid=cgid, t=t, kn=kn, kr1=kr1, kr2=kr2)
3417+
pgplsn.validate()
3418+
#print(pplane)
3419+
str(pgplsn)
3420+
n += ntotal
3421+
op2.card_count['PGPLSN'] = nentries
3422+
return n
3423+
33733424
def read_plplane(self, data: bytes, n: int) -> int:
33743425
"""
33753426
PLPLANE(4606,46,375)

0 commit comments

Comments
 (0)