Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions pyNastran/bdf/bdf.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@
CPLSTS3, CPLSTS4, CPLSTS6, CPLSTS8,
SNORM,)

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

## properties
'PMASS',
'PELAS', 'PGAP', 'PFAST', 'PWELD', 'PLPLANE', 'PPLANE',
'PELAS', 'PGAP', 'PFAST', 'PWELD', 'PLPLANE', 'PPLANE', 'PGPLSN',
'PBUSH', 'PBUSH1D', 'PBUSH2D',
'PDAMP', 'PDAMP5',
'PROD', 'PBAR', 'PBARL', 'PBEAM', 'PTUBE', 'PBCOMP', 'PBRSECT', 'PBEND',
Expand Down Expand Up @@ -2601,6 +2601,7 @@ def add_card(cls, card: BDFCard, comment: str=''):
'CPLSTS6': (CPLSTS6, add_methods.add_element_object),
'CPLSTS8': (CPLSTS8, add_methods.add_element_object),
'PPLANE': (PPLANE, add_methods.add_property_object),
'PGPLSN': (PGPLSN, add_methods.add_property_object),

'CSHEAR': (CSHEAR, add_methods.add_element_object),
'PSHEAR': (PSHEAR, add_methods.add_property_object),
Expand Down
13 changes: 12 additions & 1 deletion pyNastran/bdf/bdf_interface/add_card.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
from pyNastran.bdf.cards.elements.acoustic import (
CHACAB, CAABSF, CHACBR, PACABS, PAABSF, PACBAR,
ACMODL, ACPLNW, AMLREG, PMIC, MICPNT, MATPOR)
from pyNastran.bdf.cards.properties.shell import PSHELL, PCOMP, PCOMPG, PSHEAR, PLPLANE, PPLANE
from pyNastran.bdf.cards.properties.shell import PSHELL, PCOMP, PCOMPG, PSHEAR, PLPLANE, PPLANE, PGPLSN
from pyNastran.bdf.cards.elements.bush import CBUSH, CBUSH1D, CBUSH2D
from pyNastran.bdf.cards.properties.bush import (
PBUSH, PBUSH1D, PBUSHT, PBUSH2D, PBUSH_OPTISTRUCT)
Expand Down Expand Up @@ -338,6 +338,8 @@
'CPLSTS8': CPLSTS8,
'PPLANE': PPLANE,

'PGPLSN': PGPLSN,

'CSHEAR': CSHEAR,
'PSHEAR': PSHEAR,

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

def add_pgplsn(self, pid: int, mid: int, cgid: int, t: float,
kn: float | int = 0., kr1: float | int = 0., kr2: float | int = 0.,
comment: str='') -> PGPLSN:
"""Creates a PGPLSN card"""
prop = PGPLSN(pid, mid, cgid=cgid, t=t, kn=kn, kr1=kr1, kr2=kr2, comment=comment)

self._add_methods.add_property_object(prop)
return prop

def add_cplstn3(self, eid, pid, nids, theta=0.0, comment='') -> CPLSTN3:
"""Creates a CPLSTN4 card"""
elem = CPLSTN3(eid, pid, nids, theta=theta, comment=comment)
Expand Down
2 changes: 1 addition & 1 deletion pyNastran/bdf/bdf_interface/attributes.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@
'PBEAM3',

# 2d
'PLPLANE', 'PPLANE',
'PLPLANE', 'PPLANE', 'PGPLSN',
'PSHELL', 'PCOMP', 'PCOMPG', 'PSHEAR',
'PSOLID', 'PLSOLID', 'PVISC', 'PRAC2D', 'PRAC3D',
'PCOMPS', 'PCOMPLS',
Expand Down
132 changes: 131 additions & 1 deletion pyNastran/bdf/cards/properties/shell.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
from pyNastran.bdf.cards.materials import get_mat_props_S
from pyNastran.bdf.bdf_interface.internal_get import coord_id, material_id
from pyNastran.bdf.bdf_interface.assign_type import (
integer, integer_or_blank, double, double_or_blank, string_or_blank,
integer, integer_or_blank, double, double_or_blank, string_or_blank, integer_double_or_blank
)
from pyNastran.bdf.bdf_interface.assign_type_force import force_double_or_blank
from pyNastran.bdf.field_writer_8 import print_card_8
Expand Down Expand Up @@ -2018,6 +2018,136 @@ def write_card(self, size: int=8, is_double: bool=False) -> str:
return self.comment + print_card_8(card)


class PGPLSN(Property):
type = 'PGPLSN'
_field_map = {1: 'pid',
2:'mid',
3:'cgid',
4:'t',
5:'kn',
6: 'kr1',
7: 'kr2',
}

@classmethod
def _init_from_empty(cls):
return PGPLSN(pid=1, mid=1, cgid=1, t=1.)

def __init__(self, pid: int, mid: int, cgid: int, t: float,
kn: float | int = 0., kr1: float | int = 0., kr2: float | int = 0.,
comment: str=''):

"""
Generalized Plane Strain Element Property for SOL 401 (NX Nastran)
:param pid: Property identification number. (Integer > 0)
:param mid: Identification number of a MAT1 or MAT11 entry. (Integer > 0; No default)
:param cgid: Identification number of control grid point. (Integer > 0; No default)
:param t: Undeformed element thickness (Real > 0.0; No default)
:param kn: Optional user-specified additive normal stiffness relative to the planar area defined by the mesh of
generalized plane strain elements. (Real ≥ 0.0 or Integer > 0; Default = 0.0)
If real entry, value of stiffness at all times.
If integer entry, identification number of a TABLEDi entry that contains value of stiffness as a
function of time.
:param kr1, kr2: Optional user-specified additive rotational stiffness in the units moment/radian about the
ith-axis of the displacement coordinate system for the control grid point. See Remark 3.
(Real ≥ 0.0 or Integer > 0; Default = 0.0)
If real entry, value of stiffness at all times.
If integer entry, identification number of a TABLEDi entry that contains value of stiffness as a function of
time.
"""

Property.__init__(self)
if comment:
self.comment = comment

self.pid = pid
self.mid = mid
self.cgid = cgid
self.t = t
self.kn = kn
self.kr1, self.kr2 = kr1, kr2

self.mid_ref = None # for cross-referencing

@classmethod
def add_card(cls, card, comment=''):
"""
Adds a PGPLSN card from ``BDF.add_card(...)``

Parameters
----------
card : BDFCard()
a BDFCard object
comment : str; default=''
a comment for the card

"""
pid = integer(card, 1, 'pid')
mid = integer(card, 2, 'mid') # MAT1, MAT11
cgid = integer(card, 3, 'cgid')

t = double(card, 4, 't')
kn = integer_double_or_blank(card, 5, 'kn', default=0.)
kr1 = integer_double_or_blank(card, 6, 'kr1', default=0.)
kr2 = integer_double_or_blank(card, 7, 'kr2', default=0.)

return PGPLSN(pid, mid, cgid=cgid, t=t, kn=kn, kr1=kr1, kr2=kr2, comment=comment)

def cross_reference(self, model: BDF) -> None:
"""
Cross links the card so referenced cards can be extracted directly

Parameters
----------
model : BDF()
the BDF object

"""
msg = ', which is required by PGPLSN pid=%s' % self.pid
self.mid_ref = model.Material(self.mid, msg)

def safe_cross_reference(self, model: BDF, xref_errors) -> None:
"""
Cross links the card so referenced cards can be extracted directly

Parameters
----------
model : BDF()
the BDF object

"""
msg = ', which is required by PGPLSN pid=%s' % self.pid
self.mid_ref = model.safe_material(self.mid, self.pid, xref_errors, msg)

def uncross_reference(self) -> None:
"""Removes cross-reference links"""
self.mid = self.Mid()
self.mid_ref = None

def _verify(self, xref):
unused_pid = self.Pid()
unused_mid = self.Mid()
#stress_strain_output_location = self.stress_strain_output_location
if xref:
assert self.mid_ref.type in ['MAT1', 'MAT11'], 'PGPLSN: mid.type=%s' % self.mid_ref.type

def Mid(self) -> int:
"""returns the material id"""
return material_id(self.mid_ref, self.mid)

def raw_fields(self) -> list:
list_fields = ['PGPLSN', self.pid, self.Mid(), self.cgid, self.t, self.kn, self.kr1, self.kr2]
return list_fields

def repr_fields(self) -> list:
list_fields = ['PGPLSN', self.pid, self.Mid(), self.cgid, self.t, self.kn, self.kr1, self.kr2]
return list_fields

def write_card(self, size: int=8, is_double: bool=False) -> str:
card = self.repr_fields()
return self.comment + print_card_8(card)


class PSHEAR(Property):
"""
Defines the properties of a shear panel (CSHEAR entry).
Expand Down
25 changes: 25 additions & 0 deletions pyNastran/bdf/cards/test/test_shells.py
Original file line number Diff line number Diff line change
Expand Up @@ -887,6 +887,31 @@ def test_ctriar_cquadr(self):

save_load_deck(model)

def test_pgplsn(self):
"""tests a PGPLSN property card"""
log = SimpleLogger(level='warning')
model = BDF(log=log)

# create control grid point, mat1 material and pgplsn property
# test both integer and float-valued knr properties
for knr in (1, 0.):
model = BDF(log=log)

cgrid = model.add_grid(1, [0., 0., 0.])
mat1 = model.add_mat1(mid=1, E=1e7, G=None, nu=0.3)
pgplsn = model.add_pgplsn(pid=1, mid=mat1.mid, cgid=cgrid.nid,
t=1.0, kn=knr, kr1=knr, kr2=knr,)

model.validate()
model._verify_bdf(xref=False)
pgplsn.write_card(size=8)
model.cross_reference()
model.pop_xref_errors()

model.uncross_reference()
model.safe_cross_reference()
save_load_deck(model)

def test_cplsts3(self):
log = SimpleLogger(level='warning')
model = BDF(log=log)
Expand Down
2 changes: 1 addition & 1 deletion pyNastran/bdf/mesh_utils/convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -586,7 +586,7 @@ def _convert_properties(model: BDF,
'PSOLID', 'PLSOLID', 'PLPLANE',

# TODO: NX-verify
'PPLANE',
'PPLANE', 'PGPLSN',

# acoustic
'PACABS', 'PMIC',
Expand Down
5 changes: 5 additions & 0 deletions pyNastran/bdf/mesh_utils/remove_unused.py
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,11 @@ def remove_unused(bdf_filename: PathLike,
for pid in ids:
prop = model.properties[pid]
mids_used.add(prop.Mid())
elif card_type == 'PGPLSN':
for pid in ids:
prop = model.properties[pid]
mids_used.add(prop.Mid())
nids_used.add(prop.cgid)

elif card_type in {'PLOTEL', 'PLOTEL3', 'PLOTEL4',
'PLOTEL6', 'PLOTEL8'}:
Expand Down
51 changes: 51 additions & 0 deletions pyNastran/op2/tables/geom/ept.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ def __init__(self, op2: OP2Geom):
(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_pplane],
(4102,41,904): ['PGPLSN', self.read_pgplsn],
(11801, 118, 560): ['PWELD', self.read_fake],
(3401, 34, 993): ['NSMADD', self.read_nsmadd],
(9300, 93, 684): ['ELAR', self.read_fake],
Expand Down Expand Up @@ -3370,6 +3371,56 @@ def read_pplane(self, data: bytes, n: int) -> int:
op2.card_count['PLPLANE'] = nentries
return n

def read_pgplsn(self, data: bytes, n: int) -> int:
"""
RECORD – PGPLSN(4102,41,904)

Word Name Type Description
1 PID I Property identification number
2 MID I Material identification number
3 CGID I Control grid point identification number
4 T RS Default membrane thickness for Ti on the connection entry
5-8 UNDEF(4)
9 TYPE I Integer flag indicating the data type for KNR (word 10)
TYPE=0, KNR will be undefined
TYPE=1, KNR will be an integer
TYPE=2, KNR will be a real value
10 KNR I, RS, blank I: Table ID for time dependent user specified stiffness
RS: User specified additive stiffness
Words 9 and 10 repeat 3 times
15 CSOPT I Reserved for coordinate system definition of plane
16 UNDEF
"""
op2: OP2Geom = self.op2
ntotal = 64 * self.factor # 16*4
struct_i = Struct(mapfmt(op2._endian + b'3i 1f 12i', self.size))
struct_f = Struct(mapfmt(op2._endian + b'3i 1f 5i 1f 1i 1f 1i 1f 2i', self.size))

ndatai = len(data) - n
nentries = ndatai // ntotal
assert ndatai % ntotal == 0
for unused_i in range(nentries):
out_i = struct_i.unpack(data[n:n+ntotal])
out_f = struct_f.unpack(data[n:n+ntotal])

pid, mid, cgid = out_i[:3]
t = out_f[4]

kn_type, kr1_type, kr2_type, csopt = out_i[8], out_i[10], out_i[12], out_i[14]
kn = out_i[9] if kn_type != 2 else out_f[9]
kr1 = out_i[11] if kr1_type != 2 else out_f[11]
kr2 = out_i[13] if kr2_type != 2 else out_f[13]

#print(out)
assert csopt == 0, csopt
pgplsn = op2.add_pgplsn(pid, mid, cgid=cgid, t=t, kn=kn, kr1=kr1, kr2=kr2)
pgplsn.validate()
#print(pplane)
str(pgplsn)
n += ntotal
op2.card_count['PGPLSN'] = nentries
return n

def read_plplane(self, data: bytes, n: int) -> int:
"""
PLPLANE(4606,46,375)
Expand Down
Loading
Loading