"""
Defines various utilities for replicated BDF parsing including:
- to_fields
"""
from typing import Optional
from pyNastran.bdf.bdf_interface.utils import expand_tabs
from pyNastran.bdf.cards.utils import wipe_empty_fields
from pyNastran.bdf.errors import ReplicationError
[docs]
def to_fields_replication(card_lines: list[str]) -> list[Optional[str]]:
"""
Converts a series of lines in a card into string versions of the field.
Handles large, small, and CSV formatted cards. Same as to_fields, but
uses a different method to determine if it's large or small field format.
Parameters
----------
lines : list[str]
the lines of the BDF card object
Returns
-------
fields : list[str]
the string formatted fields of the card
.. warning:: this function is used by the reader and isn't intended
to be called by a separate process
.. code-block:: python
>>> card_lines = ['GRID,1,,1.0,2.0,3.0']
>>> card_name = 'GRID'
>>> fields = to_fields_replication(lines)
>>> fields
['GRID', '1', '', '1.0', '2.0', '3.0']
"""
#print('to_fields_replicationA =', card_lines)
#line0 = card_lines[0]
fields = []
for iline, line in enumerate(card_lines):
line = line.rstrip()
if '\t' in line:
line = expand_tabs(line)
#print(' line = %r' % line)
if ',' in line:
assert '\t' not in line, '%r' % line
sline = line.split(',')
#print('sline = ', iline, sline)
if iline == 0:
card_name = sline[0]
#assert card_name != '=', card_lines
fields.append(card_name)
if '*' in sline[0]:
fields.extend(sline[1:5])
for unused_i in range(5 - len(sline)):
fields.append('')
else:
fields.extend(sline[1:9])
for unused_i in range(9 - len(sline)):
fields.append('')
else:
assert '\t' not in line, line
if iline == 0:
card_name = line[0:8]
assert card_name != '=', card_lines
fields.append(card_name)
if '*' in card_name:
fields.extend([line[8:24], line[24:40], line[40:56],
line[56:72]])
else:
fields.extend([line[8:16], line[16:24], line[24:32],
line[32:40], line[40:48], line[48:56], line[56:64],
line[64:72]])
if '*' in card_name:
raise ReplicationError(f'* found in unexpected position; {card_name!r}\nlines = {card_lines}')
wiped_fields = wipe_empty_fields(fields)
for field in fields:
sfield = field.strip()
#while '= ' in sfield:
#sfield = field.replace('= ','=')
#print('sfield=%r' % sfield)
if ' ' in sfield:
raise RuntimeError(f'field={sfield!r} has embedded blanks '
f'(mixed comma/space separated fields)\nfields={fields}')
return wiped_fields
[docs]
def get_nrepeats(field: str, old_card: list[str], new_card: list[str]) -> int:
"""=4, =(11)"""
msg = f'field={field!r}; expected =(1), =2, ...\nold_card={old_card}\nnew_card={new_card}'
assert field[0] == '=', msg
assert '.' not in field, msg
assert '*' not in field, msg
if '(' in field or ')' in field:
assert field[1] == '(', msg
assert field[-1] == ')', msg
fieldi = field[2:-1]
assert '(' not in fieldi, msg
assert ')' not in fieldi, msg
else:
assert '(' not in field, msg
assert ')' not in field, msg
fieldi = field[1:]
nrepeats = int(fieldi)
return nrepeats
[docs]
def float_replication(field: str, old_field: str) -> float:
"""*4., *(11.5)"""
msg = f'field={field!r}; expected *(1.), *2., ..., *11.'
assert field[0] == '*', msg
assert '.' in field, msg
assert len(field) >= 3, msg
if '(' in field:
assert field[1] == '(', msg
assert field[-1] == ')', msg
fieldi = field[2:-1]
assert '(' not in fieldi, msg
assert ')' not in fieldi, msg
else:
assert '(' not in field, msg
assert ')' not in field, msg
fieldi = field[1:]
nfloat = float(fieldi)
field2 = nfloat + float(old_field)
return field2
[docs]
def int_replication(field: str, old_field: str) -> int:
"""*4, *(11)"""
msg = f'field={field!r}; expected *(1), *2, ..., *11'
assert field[0] == '*', msg
assert '.' not in field, msg
if '(' in field:
assert field[1] == '(', msg
assert field[-1] == ')', msg
fieldi = field[2:-1]
assert '(' not in fieldi, msg
assert ')' not in fieldi, msg
else:
assert '(' not in field, msg
assert ')' not in field, msg
fieldi = field[1:]
assert '*' not in fieldi, msg
assert len(field) >= 2, msg
#assert len(field) == 2, 'field=%r; expected *1, *2, *3, ..., *9' % field
# integer
nint = int(fieldi)
field2 = nint + int(old_field)
return field2
[docs]
def _field(old_card: list[str], ifield: int) -> str:
"""helper for replication"""
#if isinstance(old_card, list):
#print(old_card, ifield)
field2 = old_card[ifield]
#else:
#field2 = old_card.field(ifield)
return field2
[docs]
def repeat_cards(old_card: list[str], new_card: list[str]) -> list[list[str]]:
"""helper for replication"""
card = []
cards = []
#print('*old_card = %s' % old_card)
#print('*new_card = %s' % new_card)
assert old_card != new_card
for ifield, field in enumerate(new_card):
if field is None:
field2 = _field(old_card, ifield)
#field2 = old_card.field(ifield)
#print(' %i: %r -> %r' % (ifield, field, field2))
#assert field2 is None, 'field=%s field2=%s' % (field, field2)
card.append(field2)
continue
#1. Duplication of fields from the preceding entry is accomplished
# by coding the symbol =.
#2. Duplication of all trailing fields from the preceding entry is
# accomplished by coding the symbol
if field == '':
field2 = field
elif field == '=':
field2 = _field(old_card, ifield)
elif field == '==':
# just append the remaining fields
#print(' %s : extending %s' % (ifield, old_card[ifield:]))
card.extend(old_card[ifield:])
break
elif '*' in field:
# this is an increment, not multiplication...
old_field = _field(old_card, ifield)
#old_field = old_card.field(ifield)
if '.' in field:
assert old_field is not None, f'old_card:{old_card}\nnew_card:\n{new_card}'
field2 = float_replication(field, old_field)
else:
assert old_field is not None, f'old_card:{old_card}\nnew_card:\n{new_card}'
field2 = int_replication(field, old_field)
else:
msg = f'field={field!r}\nold_card={old_card}\nnew_card={new_card}'
assert '(' not in field, msg
assert '*' not in field, msg
assert '=' not in field, msg
field = field2
#print(' %i: %r -> %r' % (ifield, field, field2))
card.append(field2)
#print(' appending %s' % card)
cards.append(card)
return cards