Skip to content

Commit 04d9853

Browse files
committed
bdf:
- preventing SUBCASE cards - fixing parsing of GROUP when there are + characters - export_caero_mesh now supports --xref - test_bdf now supports skip_cards to deal with the GROUP card - fixed NX pressure plotting - switching plot_144 from docopt to argparse because error messages are bad
1 parent 72f28b9 commit 04d9853

File tree

10 files changed

+223
-112
lines changed

10 files changed

+223
-112
lines changed

pyNastran/bdf/bdf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3069,7 +3069,7 @@ def reject_card_lines(self, card_name: str, card_lines: list[str],
30693069
#return
30703070

30713071
if card_name not in self.card_count:
3072-
if card_name == '#INCLUDE':
3072+
if card_name in ['#INCLUDE', 'SUBCASE']:
30733073
raise RuntimeError(card_lines)
30743074
_check_for_spaces(card_name, card_lines, comment, self.log)
30753075
#raise RuntimeError(card_name)

pyNastran/bdf/bdf_interface/utils.py

Lines changed: 55 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -158,14 +158,19 @@ def _to_fields_group(card_lines: list[str]) -> list[str]:
158158
| | ELEM | 30 | THRU | 40 | | | | |
159159
+-------+------+-----+------+-----+-----+---+---+---+
160160
| | PROP | ALL | | | | | | |
161-
+-------+------+-----+------+-----+-----+---+---+---+
161+
+-------+------+-----+------+-----+-----+---+---+---+
162+
163+
# TODO: buggy
164+
GROUP 991001 Description +
165+
+ GRID 291 293 301 302 303 304 305 +
166+
+ 306 1301 68408 68409 69144 69145 69146
162167
"""
163-
#for iline, line in enumerate(card_lines):
164-
#print(f'GROUP {iline}: {line!r}')
168+
# for iline, line in enumerate(card_lines):
169+
# print(f'GROUP {iline}: {line!r}')
165170

166171
fields = _monpnt_line1_fields(card_lines[0])
167172
for j, line in enumerate(card_lines[1:]):
168-
line_strip = line.lstrip()
173+
line_strip = line.lstrip('+ ')
169174
line = line.rstrip()
170175
if line_strip.startswith('META'):
171176
fieldsi = [
@@ -180,10 +185,15 @@ def _to_fields_group(card_lines: list[str]) -> list[str]:
180185
# fieldsi = _expand_2_values_name(line)
181186
# #print(fieldsi)
182187
else:
183-
raise NotImplementedError(line)
184-
#print(f'GROUP fields[{j}]: fields={fieldsi}')
188+
fieldsi = [
189+
line[8:16], line[16:24], line[24:32], line[32:40], line[40:48],
190+
line[48:56], line[56:64], line[64:72],
191+
]
192+
# msg = f'line:\n{line!r}\nline_strip:\n{line_strip!r}'
193+
# raise NotImplementedError(msg)
194+
# print(f'GROUP fields[{j}]: fields={fieldsi}')
185195
fields.extend(fieldsi)
186-
#print(f'GROUP: fields={fields}')
196+
# print(f'GROUP: fields={fields}')
187197
return fields
188198

189199

@@ -218,36 +228,36 @@ def _to_fields_set1(card_lines: list[str], card_name: str) -> list[str]:
218228
for iline, line in enumerate(card_lines):
219229
if '\t' in line:
220230
line = expand_tabs(line)
221-
#print(f'line = {line}')
231+
# print(f'line = {line}')
222232
line = line.rstrip('\n\r,')
223-
#print(f'line2 = {line}')
233+
# print(f'line2 = {line}')
224234
if '*' in line: # large field
225235
if ',' in line: # csv
226-
new_fields = line.split(',') #[:5]
236+
new_fields = line.split(',') # [:5]
227237
new_fields = [field.strip() for field in new_fields if field.strip()]
228238
if iline > 0:
229239
new_fields = [''] + new_fields
230240
assert len(new_fields) <= 5, new_fields
231-
#for unused_i in range(5 - len(new_fields)):
232-
#new_fields.append('')
241+
# for unused_i in range(5 - len(new_fields)):
242+
# new_fields.append('')
233243
assert len(new_fields) == 5, new_fields
234244
else: # standard
235245
new_fields = [line[0:8], line[8:24], line[24:40], line[40:56],
236246
line[56:72]]
237247
end = line[72:].rstrip('+ ')
238248
assert len(end) == 0, line
239249
else: # small field
240-
length_max = 9 #if iline == 0 else 8
250+
length_max = 9 # if iline == 0 else 8
241251
if ',' in line: # csv
242-
new_fields = line.split(',') #[:9]
252+
new_fields = line.split(',') # [:9]
243253
new_fields = [field.strip() for field in new_fields if field.strip()]
244254
if iline > 0:
245255
new_fields = [''] + new_fields
246256
if len(new_fields) >= length_max:
247257
throw_length_warning = True
248258
for unused_i in range(9 - len(new_fields)):
249259
new_fields.append('')
250-
#assert len(new_fields) == 9, f'{new_fields}; {len(new_fields)}'
260+
# assert len(new_fields) == 9, f'{new_fields}; {len(new_fields)}'
251261
else: # standard
252262
new_fields = [line[0:8], line[8:16], line[16:24], line[24:32],
253263
line[32:40], line[40:48], line[48:56], line[56:64],
@@ -557,27 +567,28 @@ def _parse_pynastran_header(line: str) -> tuple[Optional[str], Optional[str]]:
557567
return key, value
558568

559569

560-
#def clean_empty_lines(lines: list[str]) -> list[str]:
561-
#"""
562-
#Removes leading and trailing empty lines
563-
#don't remove internally blank lines
564-
#"""
565-
#found_lines = False
566-
#if len(lines) < 2:
567-
#return lines
568-
569-
#for i, line in enumerate(lines):
570-
#if not found_lines and line:
571-
#found_lines = True
572-
#n1 = i
573-
#n2 = i + 1
574-
#elif found_lines and line:
575-
#n2 = i + 1
576-
#lines2 = lines[n1:n2]
577-
#return lines2
578-
579-
580-
def print_filename(filename: PathLike | StringIO, relpath: bool=True) -> str:
570+
# def clean_empty_lines(lines: list[str]) -> list[str]:
571+
# """
572+
# Removes leading and trailing empty lines
573+
# don't remove internally blank lines
574+
# """
575+
# found_lines = False
576+
# if len(lines) < 2:
577+
# return lines
578+
#
579+
# for i, line in enumerate(lines):
580+
# if not found_lines and line:
581+
# found_lines = True
582+
# n1 = i
583+
# n2 = i + 1
584+
# elif found_lines and line:
585+
# n2 = i + 1
586+
# lines2 = lines[n1:n2]
587+
# return lines2
588+
589+
590+
def print_filename(filename: PathLike | StringIO,
591+
relpath: bool=True) -> str:
581592
"""
582593
Takes a path such as C:/work/fem.bdf and locates the file using
583594
relative paths. If it's on another drive, the path is not modified.
@@ -586,13 +597,13 @@ def print_filename(filename: PathLike | StringIO, relpath: bool=True) -> str:
586597
----------
587598
filename : str
588599
a filename string
600+
relpath: bool; default=True
601+
should the relative path be returned
589602
590603
Returns
591604
-------
592605
filename_string : str
593606
a shortened representation of the filename
594-
relpath: bool; default=True
595-
should the relative path be returned
596607
597608
"""
598609
if isinstance(filename, StringIO):
@@ -705,9 +716,9 @@ def fill_dmigs(model: BDF) -> None:
705716
def _prep_comment(comment: str) -> str:
706717
"""cleans up the comment"""
707718
return comment.rstrip()
708-
#print('comment = %r' % comment)
709-
#comment = ' this\n is\n a comment\n'
710-
#print(comment.rstrip('\n').split('\n'))
711-
#sline = [comment[1:] if len(comment) and comment[0] == ' ' else comment
712-
#for comment in comment.rstrip().split('\n')]
713-
#print('sline = ', sline)
719+
# print('comment = %r' % comment)
720+
# comment = ' this\n is\n a comment\n'
721+
# print(comment.rstrip('\n').split('\n'))
722+
# sline = [comment[1:] if len(comment) and comment[0] == ' ' else comment
723+
# for comment in comment.rstrip().split('\n')]
724+
# print('sline = ', sline)

pyNastran/bdf/mesh_utils/cmd_line/export_caero_mesh.py

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import pyNastran
55
from .utils import filter_no_args
66

7+
78
def cmd_line_export_caero_mesh(argv=None, quiet=False):
89
"""command line interface to export_caero_mesh"""
910
if argv is None: # pragma: no cover
@@ -13,7 +14,8 @@ def cmd_line_export_caero_mesh(argv=None, quiet=False):
1314
import pyNastran
1415
msg = (
1516
'Usage:\n'
16-
' bdf export_caero_mesh IN_BDF_FILENAME [-o OUT_BDF_FILENAME] [--punch] [--aerobox] [--pid PID]\n'
17+
' bdf export_caero_mesh IN_BDF_FILENAME [-o OUT_BDF_FILENAME] [--punch] [--xref]'
18+
' [--aerobox] [--pid PID]\n'
1719
' bdf export_caero_mesh -h | --help\n'
1820
' bdf export_caero_mesh -v | --version\n'
1921
'\n'
@@ -25,6 +27,7 @@ def cmd_line_export_caero_mesh(argv=None, quiet=False):
2527
'Options:\n'
2628
' -o OUT, --output OUT_CAERO_BDF_FILENAME path to output BDF file\n'
2729
' --punch flag to identify a *.pch/*.inc file\n'
30+
' -x, --xref flag to disable xref (default=False)\n'
2831
' --aerobox write the aeroboxes (default=False)\n'
2932
' --pid PID sets the pid; {aesurf, caero, paero} [default: aesurf]\n'
3033
'\n'
@@ -36,19 +39,20 @@ def cmd_line_export_caero_mesh(argv=None, quiet=False):
3639
filter_no_args(msg, argv, quiet=quiet)
3740

3841
ver = str(pyNastran.__version__)
39-
#type_defaults = {
42+
# type_defaults = {
4043
# '--nerrors' : [int, 100],
41-
#}
42-
#try:
44+
# }
45+
# try:
4346
data = docopt(msg, version=ver, argv=argv[1:])
44-
#except:
45-
#raise SystemError(msg)
47+
# except:
48+
# raise SystemError(msg)
4649

4750
if not quiet: # pragma: no cover
4851
print(data)
4952
#size = 16
5053
bdf_filename = data['IN_BDF_FILENAME']
5154
punch = data['--punch']
55+
xref = not data['--xref']
5256
caero_bdf_filename = data['--output']
5357
base = os.path.splitext(bdf_filename)[0]
5458
if caero_bdf_filename is None:
@@ -89,6 +93,9 @@ def cmd_line_export_caero_mesh(argv=None, quiet=False):
8993
]
9094
level = 'debug' if not quiet else 'warning'
9195
log = SimpleLogger(level=level, encoding='utf-8')
92-
model = read_bdf(bdf_filename, punch=punch, log=log, skip_cards=skip_cards)
96+
model = read_bdf(bdf_filename, punch=punch, xref=xref,
97+
log=log, skip_cards=skip_cards)
9398
export_caero_mesh(model, caero_bdf_filename,
94-
is_aerobox_model=is_aerobox_model, pid_method=pid_method)
99+
is_aerobox_model=is_aerobox_model,
100+
pid_method=pid_method,
101+
xref=xref)

pyNastran/bdf/mesh_utils/export_caero_mesh.py

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
55
"""
66
import math
7-
from typing import TextIO, TYPE_CHECKING
7+
from typing import TextIO
88
import numpy as np
99

1010
from pyNastran.utils import PathLike
@@ -19,7 +19,8 @@ def export_caero_mesh(bdf_filename: PathLike | BDF,
1919
is_aerobox_model: bool=True,
2020
pid_method: str='aesurf',
2121
rotate_panel_angle_deg: float=0.0,
22-
write_panel_xyz: bool=True) -> None:
22+
write_panel_xyz: bool=True,
23+
xref: bool=True) -> None:
2324
"""
2425
Write the CAERO cards as CQUAD4s that can be visualized
2526
@@ -50,15 +51,16 @@ def export_caero_mesh(bdf_filename: PathLike | BDF,
5051
'PAERO1', 'PAERO2', 'PAERO3', 'PAERO4', 'PAERO5',
5152
'SET1', 'SET2', 'SET3',
5253
'SPLINE1', 'SPLINE2', 'SPLINE3', 'SPLINE4', 'SPLINE5',
53-
'AELIST',
54+
'AELIST', 'AESURF',
5455
# for aero ooord
5556
'AEROS', 'AERO',
5657
'CORD1R', 'CORD1S', 'CORD1C',
5758
'CORD2R', 'CORD2S', 'CORD2C',
5859
'GRID',
5960
]
6061
model = get_bdf_model(
61-
bdf_filename, cards_to_include=cards_to_include,
62+
bdf_filename, xref=xref,
63+
cards_to_include=cards_to_include,
6264
log=None, debug=False)
6365
if isinstance(model, PathLike):
6466
model = read_bdf(model)
@@ -449,30 +451,30 @@ def _write_subcases_loads(model: BDF,
449451
)
450452
isubcase += 2
451453

452-
## TODO: assume first column is forces & second column is moments...verify
453-
#loads += f'$ {name} - FORCE\n'
454-
#loads += '$ PLOAD2 SID P EID1\n'
455-
#for ieid, value in enumerate(data[:, 0].ravel()):
456-
#eid = aero_eid_map[ieid]
457-
#loads += f'PLOAD2,{isubcase},{value},{eid}\n'
458-
#isubcase += 1
459-
460-
#subcases += (
461-
#f'SUBCASE {isubcase}\n'
462-
#f' SUBTITLE = DMI {name} - MOMENT\n'
463-
#f' LOAD = {isubcase}\n')
464-
#loads += f'$ {name} - MOMENT\n'
465-
#loads += '$ PLOAD2 SID P EID1\n'
466-
#for irow, value in enumerate(data[:, 1].ravel()):
467-
#row = rows[irow]
468-
#eid = row[0]
469-
#loads += f'PLOAD2,{isubcase},{value},{eid}\n'
454+
# TODO: assume first column is forces & second column is moments...verify
455+
# loads += f'$ {name} - FORCE\n'
456+
# loads += '$ PLOAD2 SID P EID1\n'
457+
# for ieid, value in enumerate(data[:, 0].ravel()):
458+
# eid = aero_eid_map[ieid]
459+
# loads += f'PLOAD2,{isubcase},{value},{eid}\n'
460+
# isubcase += 1
461+
#
462+
# subcases += (
463+
# f'SUBCASE {isubcase}\n'
464+
# f' SUBTITLE = DMI {name} - MOMENT\n'
465+
# f' LOAD = {isubcase}\n')
466+
# loads += f'$ {name} - MOMENT\n'
467+
# loads += '$ PLOAD2 SID P EID1\n'
468+
# for irow, value in enumerate(data[:, 1].ravel()):
469+
# row = rows[irow]
470+
# eid = row[0]
471+
# loads += f'PLOAD2,{isubcase},{value},{eid}\n'
470472
else:
471473
raise NotImplementedError(msg)
472474

473475
if not is_aerobox_model:
474476
# we put this here to test
475-
#model.log.warning('cannot export "loads" because not an aerobox model')
477+
model.log.warning('cannot export "loads" because not an aerobox model')
476478
subcases = ''
477479
loads = ''
478480
return subcases, loads

0 commit comments

Comments
 (0)