Skip to content

Commit d7989da

Browse files
authored
Update mats1 card (#848)
* Add card format to MATS1 class description * LIMIT1 and LIMIT2 can be real or blank, update MATS1 class to reflect this. * Add STRMEAS field to MATS1 class * Add STRMEAS field to MATS1 class. * Add STRMEAS field to MATS1 class * implement backwards compatibility
1 parent 32be618 commit d7989da

File tree

5 files changed

+123
-33
lines changed

5 files changed

+123
-33
lines changed

pyNastran/bdf/bdf_interface/add_card.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3805,10 +3805,10 @@ def add_mathp(self, mid: int,
38053805
return mat
38063806

38073807
def add_mats1(self, mid: int, nl_type: str,
3808-
h, hr, yf, limit1, limit2,
3808+
h, hr, yf, limit1, limit2, strmeas: str | None = None,
38093809
tid: int=0, comment: str='') -> MATS1:
38103810
"""Creates a MATS1 card"""
3811-
mat = MATS1(mid, nl_type, h, hr, yf, limit1, limit2,
3811+
mat = MATS1(mid, nl_type, h, hr, yf, limit1, limit2, strmeas,
38123812
tid=tid, comment=comment)
38133813
self._add_methods.add_material_dependence_object(mat)
38143814
return mat

pyNastran/bdf/cards/material_deps.py

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
from pyNastran.bdf.cards.base_card import BaseCard
2323
from pyNastran.bdf.bdf_interface.internal_get import material_id, table_id
2424
from pyNastran.bdf.bdf_interface.assign_type import (
25-
integer, integer_or_blank, double, double_or_blank, string)
25+
integer, integer_or_blank, double, double_or_blank, string, string_or_blank)
2626
from pyNastran.bdf.field_writer_8 import print_card_8
2727
from pyNastran.bdf.field_writer_16 import print_card_16
2828
if TYPE_CHECKING: # pragma: no cover
@@ -87,12 +87,22 @@ class MATS1(MaterialDependence):
8787
entry is specified with the same MID in a nonlinear solution sequence
8888
(SOLs 106 and 129).
8989
90+
Format (NX Nastran):
91+
+--------+---------+-------+-------+------+-----+-----+--------+--------+
92+
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
93+
+========+=========+=======+=======+======+=====+=====+========+========+
94+
| MATS1 | MID | TID | TYPE | H | YF | HR | LIMIT1 | LIMIT2 |
95+
+--------+---------+-------+-------+------+-----+-----+--------+--------+
96+
| | STRMEAS | | | | | | | |
97+
+--------+---------+-------+-------+------+-----+-----+--------+--------+
98+
9099
"""
91100
type = 'MATS1'
92101

93102
def __init__(self, mid: int, nl_type: Optional[str],
94103
h: float, hr: float, yf: float,
95-
limit1: float, limit2: float,
104+
limit1: Optional[float], limit2: Optional[float],
105+
strmeas: Optional[str] = None,
96106
tid: int=0, comment: str=''):
97107
MaterialDependence.__init__(self)
98108
if comment:
@@ -136,6 +146,11 @@ def __init__(self, mid: int, nl_type: Optional[str],
136146
#: Internal friction angle, measured in degrees, for the
137147
#: Mohr-Coulomb and Drucker-Prager yield criteria
138148
self.limit2 = limit2
149+
150+
#: Stress/strain measure of the TABLES1 or TABLEST data referenced by the TID field.
151+
#: Valid for NX Nastran SOL 401 and SOL 402 only.
152+
self.strmeas = strmeas
153+
139154
self.tid_ref = None
140155
self.mid_ref = None
141156
assert tid is not None
@@ -150,7 +165,8 @@ def _init_from_empty(cls):
150165
yf = None
151166
limit1 = None
152167
limit2 = None
153-
return MATS1(mid, nl_type, h, hr, yf, limit1, limit2, tid=tid, comment='')
168+
strmeas = None
169+
return MATS1(mid, nl_type, h, hr, yf, limit1, limit2, strmeas, tid=tid, comment='')
154170

155171
def validate(self) -> None:
156172
if self.nl_type not in ['NLELAST', 'PLASTIC', 'PLSTRN']:
@@ -191,15 +207,21 @@ def add_card(cls, card: BDFCard, comment: str=''):
191207
h = double_or_blank(card, 4, 'H')
192208
yf = integer_or_blank(card, 5, 'yf', default=1)
193209
hr = integer_or_blank(card, 6, 'hr', default=1)
194-
limit1 = double(card, 7, 'limit1')
210+
limit1 = double_or_blank(card, 7, 'limit1')
195211

196212
if yf in [3, 4]:
197213
limit2 = double(card, 8, 'limit2')
198214
else:
199215
#limit2 = blank(card, 8, 'limit2')
200216
limit2 = None
201-
assert len(card) <= 9, f'len(MATS1 card) = {len(card):d}\ncard={card}'
202-
return MATS1(mid, nl_type, h, hr, yf, limit1, limit2, tid=tid, comment=comment)
217+
218+
if len(card) > 9:
219+
strmeas = string_or_blank(card, 9, 'strmeas')
220+
else:
221+
strmeas = None
222+
223+
assert len(card) <= 10, f'len(MATS1 card) = {len(card):d}\ncard={card}'
224+
return MATS1(mid, nl_type, h, hr, yf, limit1, limit2, strmeas, tid=tid, comment=comment)
203225

204226
@classmethod
205227
def add_op2_data(cls, data, comment: str=''):
@@ -214,7 +236,21 @@ def add_op2_data(cls, data, comment: str=''):
214236
a comment for the card
215237
216238
"""
217-
(mid, tid, nl_type_int, h, yf, hr, limit1, limit2) = data
239+
240+
if len(data) < 9:
241+
(mid, tid, nl_type_int, h, yf, hr, limit1, limit2) = data
242+
strmeas = None
243+
else:
244+
(mid, tid, nl_type_int, h, yf, hr, limit1, limit2, strmeas_int) = data
245+
strmeas_map = {
246+
0: None, # NULL
247+
1: 'UNDEF',
248+
2: 'ENG',
249+
3: 'TRUE',
250+
4: 'CAUCHY',
251+
}
252+
strmeas = strmeas_map[strmeas_int]
253+
218254
if nl_type_int == 1:
219255
nl_type = 'NLELAST'
220256
elif nl_type_int == 2:
@@ -224,7 +260,8 @@ def add_op2_data(cls, data, comment: str=''):
224260
else: # pragma: no cover
225261
raise RuntimeError(f'Invalid Type: mid={mid}; Type={nl_type_int}; must be 1=NLELAST, '
226262
'2=PLASTIC, or 3=PLSTRN')
227-
return MATS1(mid, nl_type, h, hr, yf, limit1, limit2, tid=tid, comment=comment)
263+
264+
return MATS1(mid, nl_type, h, hr, yf, limit1, limit2, strmeas, tid=tid, comment=comment)
228265

229266
def Yf(self) -> str:
230267
d = {1: 'VonMises', 2: 'Tresca', 3: 'MohrCoulomb', 4: 'Drucker-Prager'}
@@ -298,7 +335,7 @@ def Tid(self) -> int:
298335

299336
def raw_fields(self) -> list:
300337
list_fields = ['MATS1', self.Mid(), self.Tid(), self.nl_type,
301-
self.h, self.yf, self.hr, self.limit1, self.limit2]
338+
self.h, self.yf, self.hr, self.limit1, self.limit2, self.strmeas]
302339
return list_fields
303340

304341
def repr_fields(self) -> list:

pyNastran/bdf/cards/test/test_materials.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -587,24 +587,30 @@ def test_mat3d(self):
587587
def test_mats1(self):
588588
"""tests MATS1"""
589589
log = get_logger(level='warning')
590-
model = BDF(log=log)
590+
591+
# MAT1 card properties
591592
mid = 10
592593
E = 3.0e7
593594
G = None
594595
nu = 0.3
595-
model.add_mat1(mid, E, G, nu)
596596

597+
# MATS1 card properties
597598
tid = 0
598599
nl_type = 'NLELAST'
599600
h = None
600601
hr = None
601602
yf = None
602603
limit1 = None
603604
limit2 = None
604-
unused_mats1 = model.add_mats1(
605-
mid, nl_type, h, hr, yf, limit1, limit2,
606-
tid=tid, comment='mats1')
607-
save_load_deck(model, xref='standard', punch=True, run_remove_unused=False)
605+
606+
# Test model with and without STRMEAS entry
607+
for strmeas in ('ENG', None):
608+
model = BDF(log=log)
609+
model.add_mat1(mid, E, G, nu)
610+
model.add_mats1(mid, nl_type, h, hr, yf, limit1, limit2, strmeas, tid=tid, comment='mats1')
611+
deck = save_load_deck(model, xref='standard', punch=True, run_remove_unused=False)
612+
613+
self.assertEqual(strmeas, deck.MATS1[mid].strmeas)
608614

609615
def test_matdmg(self):
610616
"""tests MATDMG"""

pyNastran/op2/tables/geom/mpt.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -837,17 +837,32 @@ def read_mats1(self, data: bytes, n: int) -> int:
837837
MATS1(503,5,90) - record 12
838838
"""
839839
op2: OP2Geom = self.op2
840-
ntotal = 44 * self.factor # 11*4
841-
s = Struct(mapfmt(op2._endian + b'3ifiiff3i', self.size))
840+
841+
ntotal = 48 * self.factor # 12*4
842+
if (len(data) - n) % ntotal != 0: # MATS1 card format has no STRMEAS entry, reduce ntotal
843+
use_strmeas = False
844+
ntotal = 44 * self.factor # 11 * 4
845+
s = Struct(mapfmt(op2._endian + b'3ifiiff3i', self.size))
846+
else:
847+
use_strmeas = True
848+
s = Struct(mapfmt(op2._endian + b'3ifiiff4i', self.size))
849+
842850
nmaterials = (len(data) - n) // ntotal
843851
for unused_i in range(nmaterials):
844852
edata = data[n:n+ntotal]
845853
out = s.unpack(edata)
846-
(mid, tid, Type, h, yf, hr, limit1, limit2, a, bmat, c) = out
854+
855+
if use_strmeas:
856+
(mid, tid, Type, h, yf, hr, limit1, limit2, strmeas, a, bmat, c) = out
857+
data_in = [mid, tid, Type, h, yf, hr, limit1, limit2, strmeas]
858+
else:
859+
(mid, tid, Type, h, yf, hr, limit1, limit2, a, bmat, c) = out
860+
data_in = [mid, tid, Type, h, yf, hr, limit1, limit2]
861+
847862
assert a == 0, a
848863
assert bmat == 0, bmat
849864
assert c == 0, c
850-
data_in = [mid, tid, Type, h, yf, hr, limit1, limit2]
865+
851866
if op2.is_debug_file:
852867
op2.binary_debug.write(' MATS1=%s\n' % str(out))
853868
mat = MATS1.add_op2_data(data_in)

pyNastran/op2/writer/mpt_writer.py

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -468,9 +468,24 @@ def write_mat11(model: BDF, name: str, mids: list[int], nmaterials: int,
468468
def write_mats1(model: BDF, name, mids, nmaterials,
469469
op2_file, op2_ascii, endian):
470470
"""writes the MATS1"""
471+
472+
# check if strmeas entry should be written
473+
# strategy: check random MATS1 card. if STRMEAS field is blank, do not write it for backwards compatibility
474+
test_mat = model.MATS1[mids[0]]
475+
write_strmeas = False if test_mat.strmeas is None else True
476+
477+
strmeas_map = {
478+
None : 0, # NULL
479+
'UNDEF' : 1,
480+
'ENG' : 2,
481+
'TRUE': 3,
482+
'CAUCHY': 4,
483+
}
484+
471485
key = (503, 5, 90)
472-
nfields = 11
473-
spack = Struct(endian + b'3ifiiff3i')
486+
nfields = 12 if write_strmeas else 11
487+
spack = Struct(endian + b'3ifiiff4i') if write_strmeas else Struct(endian + b'3ifiiff3i')
488+
474489
nbytes = write_header(name, nfields, nmaterials, key, op2_file, op2_ascii)
475490
for mid in sorted(mids):
476491
mat = model.MATS1[mid]
@@ -488,16 +503,33 @@ def write_mats1(model: BDF, name, mids, nmaterials,
488503
else: # pragma: no cover
489504
raise RuntimeError(f'Invalid Type: Type={mat.nl_type}; must be 1=NLELAST '
490505
'2=PLASTIC or 3=PLSTRN')
491-
data = [mid,
492-
# not sure
493-
mat.tid,
494-
nl_type_int,
495-
0.0 if mat.h is None else mat.h,
496-
0 if mat.yf is None else mat.yf,
497-
0 if mat.hr is None else mat.hr,
498-
0.0 if mat.limit1 is None else mat.limit1,
499-
0.0 if mat.limit2 is None else mat.limit2,
500-
a, bmat, c]
506+
507+
if write_strmeas:
508+
data = [mid,
509+
# not sure
510+
mat.tid,
511+
nl_type_int,
512+
0.0 if mat.h is None else mat.h,
513+
0 if mat.yf is None else mat.yf,
514+
0 if mat.hr is None else mat.hr,
515+
0.0 if mat.limit1 is None else mat.limit1,
516+
0.0 if mat.limit2 is None else mat.limit2,
517+
strmeas_map[mat.strmeas],
518+
519+
a, bmat, c]
520+
else:
521+
data = [mid,
522+
# not sure
523+
mat.tid,
524+
nl_type_int,
525+
0.0 if mat.h is None else mat.h,
526+
0 if mat.yf is None else mat.yf,
527+
0 if mat.hr is None else mat.hr,
528+
0.0 if mat.limit1 is None else mat.limit1,
529+
0.0 if mat.limit2 is None else mat.limit2,
530+
531+
a, bmat, c]
532+
501533
assert None not in data, f'MATS1 {data}'
502534
assert len(data) == nfields
503535
op2_ascii.write(' mid=%s data=%s\n' % (mid, data[1:]))

0 commit comments

Comments
 (0)