from typing import List, Dict, Union, Set, Any
from pyNastran.bdf.bdf_interface.subcase_utils import write_set
from pyNastran.utils.numpy_utils import bytes_type
[docs]def decode_bytes_list(bytes_list, encoding):
out = [bytes_str.decode(encoding) if isinstance(bytes_str, bytes_type) else bytes_str
for bytes_str in bytes_list]
return out
[docs]class CaseControlCard:
"""basic card similar to the BaseCard class for the BDF"""
def __iter__(self):
"""temporary method to emulate the old list access style"""
value = self
options = None
param_type = 'OBJ-type'
return iter([value, options, param_type])
#-------------------------------------------------------------------------------
[docs]class IntCard(CaseControlCard):
"""
interface for cards of the form:
NAME = 10
"""
type = 'IntCard'
def __init__(self, value):
"""
Creates an IntCard
Parameters
----------
value : int
the value for the card
"""
super(IntCard, self).__init__()
self.value = int(value)
def __iter__(self):
"""temporary method to emulate the old list access style"""
value = self
options = []
#param_type = 'STRESS-type'
param_type = 'OBJ-type'
return iter([value, options, param_type])
[docs] @classmethod
def add_from_case_control(cls, line, line_upper, lines, i):
"""
Creates a card from the Case Control Deck
Parameters
----------
line : str
the line of the card
line_upper : str
unused
lines : List[str]
unused
i : int
unused
"""
value = line_upper.split('=')[1]
try:
out = cls(value)
except ValueError:
print(line)
raise
return out
[docs] def export_to_hdf5(self, h5_file, encoding):
h5_file.create_dataset('value', data=self.value)
[docs] @classmethod
def load_hdf5(cls, h5_file, encoding):
from pyNastran.utils.dict_to_h5py import _cast
value = h5_file['value']
value2 = _cast(value)
return cls(value2), []
def __repr__(self):
"""writes a card"""
return '%s = %i\n' % (self.type, self.value)
[docs] def write(self, spaces):
"""writes a card with spaces"""
return spaces + str(self)
[docs]class IntStrCard(IntCard):
"""
interface for cards of the form:
NAME = 10
NAME = ALL
"""
type = 'IntStrCard'
allowed_strings = set([]) # type: Set[str]
def __init__(self, value):
"""
Creates an IntStrCard
Parameters
----------
value : int/str
the value for the card
"""
#super(IntStrCard, self).__init__()
try:
self.value = int(value)
except ValueError:
value = value.strip()
if value not in self.allowed_strings:
msg = 'value=%r not in [%s]' % (
value, ', '.join(self.allowed_strings))
raise ValueError(msg)
self.value = value
[docs] def export_to_hdf5(self, h5_file, encoding):
value_bytes = self.value.encode(encoding) if isinstance(self.value, str) else self.value
#sub_group = h5_file.create_group(self.type)
h5_file.create_dataset('value', data=value_bytes)
[docs] @classmethod
def load_hdf5(cls, h5_file, encoding):
from pyNastran.utils.dict_to_h5py import _cast
value = h5_file['value']
casted_value = _cast(value)
if isinstance(casted_value, int):
value2 = casted_value
else:
value2 = casted_value.decode(encoding)# if isinstance(value, bytes) else value
return cls(value2), []
def __repr__(self):
"""writes a card"""
return '%s = %s\n' % (self.type, self.value)
[docs]class ADACT(IntStrCard):
type = 'ADACT'
allowed_strings = {'ALL', 'NONE'}
def __init__(self, value):
super().__init__(value)
[docs]class AEROF(IntStrCard):
type = 'AEROF'
allowed_strings = {'ALL'}
def __init__(self, value):
super().__init__(value)
[docs]class APRES(IntStrCard):
type = 'APRES'
allowed_strings = {'ALL'}
def __init__(self, value):
super().__init__(value)
[docs]class GPRSORT(IntStrCard):
type = 'GPRSORT'
allowed_strings = {'ALL'}
def __init__(self, value):
super().__init__(value)
[docs]class GPSDCON(IntStrCard):
type = 'GPSDCON'
allowed_strings = {'ALL'}
def __init__(self, value):
super().__init__(value)
[docs]class HARMONICS(IntStrCard):
type = 'HARMONICS'
allowed_strings = {'ALL', 'NONE'}
def __init__(self, value):
super().__init__(value)
[docs]class OFREQUENCY(IntStrCard):
type = 'OFREQUENCY'
alternate_names = {'OFREQ'}
allowed_strings = {'ALL'}
def __init__(self, value):
super().__init__(value)
[docs]class OMODES(IntStrCard):
type = 'OMODES'
allowed_strings = {'ALL'}
def __init__(self, value):
super().__init__(value)
[docs]class SUPER(IntStrCard):
type = 'SUPER'
allowed_strings = {'ALL'}
#def __init__(self, value):
#super().__init__(value)
#----------------------------
[docs]class GPSTRESS(IntStrCard):
type = 'GPSTRESS'
allowed_strings = {'ALL'}
def __init__(self, value):
super().__init__(value)
[docs]class SEALL(IntStrCard):
type = 'SEALL'
allowed_strings = {'ALL'}
def __init__(self, value):
super().__init__(value)
[docs]class SEDR(IntStrCard):
type = 'SEDR'
allowed_strings = {'ALL'}
def __init__(self, value):
super().__init__(value)
[docs]class GPKE(IntStrCard):
type = 'GPKE'
allowed_strings = {'ALL'}
def __init__(self, value):
super().__init__(value)
INTSTR_CARDS = [
ADACT, AEROF, APRES, GPRSORT, GPSDCON, HARMONICS, OFREQUENCY, OMODES,
SUPER, SEALL, SEDR,
] + [GPSTRESS, GPKE, ]
INTSTR_CARD_DICT = {card.type : card for card in INTSTR_CARDS}
INTSTR_CARD_NAMES = tuple([card.type for card in INTSTR_CARDS])
#-------------------------------------------------------------------------------
[docs]class StringCard(CaseControlCard):
type = 'StringCard'
allowed_values = [] # type: List[str]
def __init__(self, value, validate=True):
super(StringCard, self).__init__()
self.value = value.strip()
if validate:
self.validate()
[docs] @classmethod
def add_from_case_control(cls, line, line_upper, lines, i):
"""add method used by the CaseControl class"""
value = line_upper.split('=')[1]
return cls(value)
[docs] def validate(self):
if self.value not in self.allowed_values:
msg = '%s: value=%r not in [%s]' % (
self.type, self.value, ', '.join(self.allowed_values))
raise ValueError(msg)
def __repr__(self):
"""writes a card"""
return '%s = %s\n' % (self.type, self.value)
[docs] def write(self, spaces):
return spaces + str(self)
[docs] def export_to_hdf5(self, h5_file, encoding):
value_bytes = self.value.encode(encoding)
#sub_group = h5_file.create_group(self.type)
h5_file.create_dataset('value', data=value_bytes)
[docs] @classmethod
def load_hdf5(cls, h5_file, encoding):
from pyNastran.utils.dict_to_h5py import _cast
value = h5_file['value']
try:
value2 = _cast(value).decode(encoding)
except AttributeError:
print(cls.type, _cast(value))
raise
return cls(value2), []
#-------------------------------------------------------------------------------
[docs]class SET(CaseControlCard):
type = 'SET'
def __init__(self, set_id, values):
super(SET, self).__init__()
self.set_id = int(set_id)
#values2 = expand_thru_case_control(values)
self.value = values
@property
def key(self):
"""temporary method to emulate the old key attribute"""
return '%s %s' % (self.type, self.set_id)
def __iter__(self):
"""temporary method to emulate the old list access style"""
value = self
options = None
param_type = 'OBJ-type'
return iter([value, options, param_type])
[docs] @classmethod
def add_from_case_control(cls, line_upper, lines, i):
"""add method used by the CaseControl class"""
line = lines[i]
sline = line_upper.split('=')
assert len(sline) == 2, sline
key, value = sline
try:
(key, set_id) = key.split()
except Exception:
raise RuntimeError(key)
assert key.upper() == key, key
unused_options = int(set_id)
#if self.debug:
#self.log.debug('SET-type key=%r set_id=%r' % (key, set_id))
fivalues = value.rstrip(' ,').split(',') # float/int values
#: .. todo:: should be more efficient multiline reader...
# read more lines....
if line[-1].strip() == ',':
i += 1
#print("rawSETLine = %r" % (lines[i]))
while 1:
if lines[i].strip()[-1] == ',':
fivalues += lines[i][:-1].split(',')
else: # last case
fivalues += lines[i].split(',')
#print("fivalues last = i=%s %r" % (i, lines[i]))
i += 1
break
i += 1
#print("len(fivalues) = %s" % len(fivalues))
return cls(set_id, fivalues)
[docs] def write(self, spaces):
"""
writes
SET 80 = 3926, 3927, 3928, 4141, 4142, 4143, 4356, 4357, 4358, 4571,
4572, 4573, 3323 THRU 3462, 3464 THRU 3603, 3605 THRU 3683,
3910 THRU 3921, 4125 THRU 4136, 4340 THRU 4351
"""
return write_set(self.set_id, self.value, spaces=spaces)
def __repr__(self):
"""see `write`"""
return write_set(self.set_id, self.value)
[docs]class SETMC(SET):
"""
SETMC 121 = ACCE/99(T3),1200(T1),1399(R2)
SETMC 222 = STRESS/134(22)
SETMC 343 = ACCE/99(T3),1200(T1),1399(R2),STRESS/134(22)
SETMC 122 = DISP/45(T1) 45(T2) 45(T3),
38(T1) 38(T2) 38(T3),
VELO/45(T1) 45(T2) 45(T3),
38(T1) 38(T2) 38(T3),
ACCE/45(T1) 45(T2) 45(T3),
38(T1) 38(T2) 38(T3)
"""
type = 'SETMC'
def __init__(self, set_id, values):
super(SETMC, self).__init__(set_id, values)
[docs]class CheckCard(CaseControlCard):
"""
Creates a card that validates the input
GROUNDCHECK=YES
GROUNDCHECK(GRID=12,SET=(G,N,A),THRESH=1.E-5,DATAREC=YES)=YES
GROUNDCHECK(SET=ALL)=YES
WEIGHTCHECK=YES
WEIGHTCHECK(GRID=12,SET=(G,N,A),MASS)=YES
WEIGHTCHECK(SET=ALL)=YES
"""
type = 'CheckCard'
allowed_keys = set([]) # type: Set[str]
# key:(type, allowed_values)
allowed_values = {} # type: Dict[str, Union[float, str]]
# the allowed value for the key, options, value approach
allowed_strings = set([]) # type: Set[str]
# maps something like INIT to INITIAL
duplicate_names = {} # type: Dict[Any, Any]
# enables values as integers instead of just strings
allow_ints = False
# 'OUTPUT(PLOT)' instead of 'OUTPUT(PLOT)=YES'
allow_equals = True
def __init__(self, key, value, options):
"""
Creates a card of the form:
key(options) = value
Parameters
----------
key : str
the name of the card
value : List[str]
the options
value : str
the response value
"""
super(CheckCard, self).__init__()
self.key = key
self.options = options
self.data = []
for key_value in options:
if key_value.upper().startswith('SET'):
key = self._parse_set(key_value, options)
else:
key = self._parse(key_value, options)
if key in self.duplicate_names:
key = self.duplicate_names[key]
if key not in self.allowed_keys:
msg = '%s: key=%r allowed_keys=[%r]' % (
self.type, key, ', '.join(self.allowed_keys))
raise KeyError(msg)
if isinstance(value, str):
value = value.strip().upper()
if self.allow_equals:
if self.allow_ints:
try:
value = int(value)
except ValueError:
if value not in self.allowed_strings:
msg = '%s: value=%r not in [%s]; options=%s' % (
self.type, value, ', '.join(self.allowed_strings), options)
raise ValueError(msg)
else:
if value not in self.allowed_strings:
msg = '%s: value=%r not in [%s]; options=%s' % (
self.type, value, ', '.join(self.allowed_strings), options)
raise ValueError(msg)
else:
assert value is None, value
self.value = value
[docs] def _parse(self, key_value, options):
if '=' in key_value:
assert self.allow_equals is True, key_value
key, valuei = key_value.split('=')
key = key.strip()
valuei = valuei.strip()
if key in self.duplicate_names:
key = self.duplicate_names[key]
if key in self.allowed_values:
key_type, allowed_values = self.allowed_values[key]
try:
valuei = key_type(valuei)
except ValueError:
msg = 'cannot make %r a %s in %r' % (valuei, key_type, key_value)
raise ValueError(msg)
except TypeError:
msg = 'cannot make %r a %s in %r' % (valuei, key_type, key_value)
raise TypeError(msg)
# parse the value
# SET=(G,N,A)
if allowed_values is not None:
try:
sline = valuei.strip('(,)').split(',')
except AttributeError:
msg = 'cannot make %r a %s in %r of the form SET=(G,N,A)' % (
valuei, key_type, key_value)
raise ValueError(msg)
for val in sline:
if val not in allowed_values:
msg = '%s: key=%r value=%r allowed_values=[%r]' % (
self.type, key, val, ', '.join(allowed_values))
msg += '\noptions = %r' % options
raise ValueError(msg)
key = key.upper()
if isinstance(valuei, str):
valuei = valuei.upper()
self.data.append((key, valuei))
else:
key = key_value.upper()
self.data.append((key, None))
return key
[docs] def _parse_set(self, key_value, options):
"""SET=(G,N,N+AUTOSPC,F,A)"""
if '=' in key_value:
key, valuei = key_value.split('=')
key = key.strip()
valuei = valuei.strip()
if key in self.duplicate_names:
key = self.duplicate_names[key]
if key in self.allowed_values:
key_type, allowed_values = self.allowed_values[key]
try:
valuei = key_type(valuei)
except ValueError:
msg = 'cannot make %r a %s in %r' % (valuei, key_type, key_value)
raise ValueError(msg)
except TypeError:
msg = 'cannot make %r a %s in %r' % (valuei, key_type, key_value)
raise TypeError(msg)
# parse the value
# SET=(G,N,A)
if allowed_values is not None:
try:
sline = valuei.strip('(,)').split(',')
except AttributeError:
msg = 'cannot make %r a %s in %r of the form SET=(G,N,A)' % (
valuei, key_type, key_value)
raise ValueError(msg)
for val in sline:
if '+' not in val or 'ALL' in val.upper():
# typical case
if val not in allowed_values:
msg = '%s: key=%r value=%r allowed_values=[%r]' % (
self.type, key, val, ', '.join(allowed_values))
msg += '\noptions = %r' % options
raise ValueError(msg)
else:
vals = val.split('+')
# N+AUTOSPC
for vali in vals:
if vali not in allowed_values:
msg = '%s: key=%r value=%r allowed_values=[%r]' % (
self.type, key, val, ', '.join(allowed_values))
msg += '\noptions = %r' % options
raise ValueError(msg)
self.data.append((key, valuei))
else:
key = key_value
self.data.append((key, None))
key = key.upper()
return key
[docs] @classmethod
def add_from_case_control(cls, line, line_upper, lines, i):
"""add method used by the CaseControl class"""
equals_count = line.count('=')
if cls.allow_equals:
if equals_count == 1:
line_upper = line_upper.replace(' ', '')
# GROUNDCHECK=YES
# WEIGHTCHECK=YES
key, value, options = cls._parse_single_equals(line, line_upper, lines, i)
elif equals_count >= 2 and '(' in line:
#GROUNDCHECK(PRINT,SET=(G,N,N+AUTOSPC,F,A),DATAREC=NO)=YES
#WEIGHTCHECK(PRINT,SET=(G,N,F,A),CGI=NO,WEIGHT)=YES
key, value, options = cls._parse_multi_equals(line, line_upper, lines, i)
#elif equals_count == 2:
#GROUNDCHECK(SET=ALL)=YES
#WEIGHTCHECK(SET=ALL, PRINT, THRESH=0.01, DATAREC=NO)=YES
else:
raise RuntimeError('equals_count=%s; line = %r' % (equals_count, line))
else:
value = None
if '(' in line_upper:
(class_name, options_str) = line_upper.strip(')').split('(')
options = options_str.split(',')
else:
class_name = line_upper
assert class_name == 'OUTPUT', class_name
options = []
key = class_name
#print(f'options_str = {options_str!r}')
return cls(key, value, options)
[docs] @classmethod
def _parse_single_equals(cls, line, line_upper, lines, i):
"""
GROUNDCHECK=YES
WEIGHTCHECK=YES
"""
if '=' in line:
(key, value) = line_upper.strip().split('=')
else:
msg = 'expected item of form "name = value" line=%r' % line.strip()
raise RuntimeError(msg)
key = key.strip().upper()
value = value.strip()
#if self.debug:
#self.log.debug("key=%r value=%r" % (key, value))
#param_type = 'STRESS-type'
assert key.upper() == key, key
if '(' in key: # comma may be in line - STRESS-type
#param_type = 'STRESS-type'
sline = key.strip(')').split('(')
key = sline[0]
options = sline[1].split(',')
# handle TEMPERATURE(INITIAL) and TEMPERATURE(LOAD) cards
if key in ['TEMPERATURE', 'TEMP']:
option = options[0]
if option == '':
option = 'BOTH'
key = 'TEMPERATURE'
options = [option]
else:
# DISPLACEMENT = ALL
options = []
return key, value, options
[docs] @classmethod
def _parse_multi_equals(cls, line, line_upper, lines, i):
"""
#GROUNDCHECK(PRINT,SET=(G,N,N+AUTOSPC,F,A),DATAREC=NO)=YES
#WEIGHTCHECK(PRINT,SET=(G,N,F,A),CGI=NO,WEIGHT)=YES
"""
assert len(lines) == 1, lines
line = lines[0]
try:
key, value_options = line.split('(', 1)
#GROUNDCHECK, PRINT,SET=(G,N,N+AUTOSPC,F,A),DATAREC=NO)=YES
#WEIGHTCHECK, PRINT,SET=(G,N,F,A),CGI=NO,WEIGHT)=YES
except ValueError:
msg = 'Expected a "(", but did not find one.\n'
msg += 'Looking for something of the form:\n'
msg += ' GROUNDCHECK(PRINT,SET=(G,N,N+AUTOSPC,F,A),DATAREC=NO)=YES\n'
msg += '%r' % line
raise ValueError(msg)
try:
options_paren, value = value_options.rsplit('=', 1)
#'GROUNDCHECK', 'PRINT,SET=(G,N,N+AUTOSPC,F,A),DATAREC=NO)', 'YES'
#'WEIGHTCHECK', 'PRINT,SET=(G,N,F,A),CGI=NO,WEIGHT)', 'YES'
except ValueError:
msg = 'Expected a "=", but did not find one.\n'
msg += 'Looking for something of the form:\n'
msg += ' GROUNDCHECK(PRINT,SET=(G,N,N+AUTOSPC,F,A),DATAREC=NO)=YES\n'
msg += 'value_options=%r\n' % value_options
msg += '%r' % line
raise ValueError(msg)
options_paren = options_paren.strip()
value = value.strip()
if value.isdigit():
value = int(value)
if not options_paren.endswith(')'):
raise RuntimeError(line)
str_options = options_paren[:-1]
#'GROUNDCHECK', 'PRINT,SET=(G,N,N+AUTOSPC,F,A),DATAREC=NO', 'YES'
#'WEIGHTCHECK', 'PRINT,SET=(G,N,F,A),CGI=NO,WEIGHT', 'YES'
if '(' in str_options:
options = split_by_mixed_commas_parentheses(str_options)
else:
options = str_options.split(',')
#param_type = 'STRESS-type'
key = key.upper()
return key, value, options
[docs] def write(self, spaces):
msg = spaces + str(self)
return msg
def __repr__(self):
"""writes a card"""
msg = '%s' % self.type
if self.data:
msg += '('
for key, value in self.data:
if value is None:
msg += '%s, ' % key
else:
msg += '%s=%s, ' % (key, value)
msg = msg.strip(', ') + ') = %s' % self.value
else:
msg += ' = %s' % self.value
return msg + '\n'
[docs]def split_by_mixed_commas_parentheses(str_options: str) -> List[str]:
"""
Excessively complicated function to split something excessively
complicated. Thankfully, it only has one set of parentheses
and no nested blocks.
Parameters
----------
str_options : str
a nasty section of a case control line
'PRINT,SET=(G,N,N+AUTOSPC,F,A),DATAREC=NO'
'PRINT,SET=(G,N,F,A),CGI=NO,WEIGHT'
Returns
-------
options : List[str]
something that's actually parseable
['PRINT', 'SET=(G,N,N+AUTOSPC,F,A)', 'DATAREC=NO']
['PRINT', 'SET=(G,N,F,A)', 'CGI=NO', 'WEIGHT']
"""
options_start = []
options_end = []
options_start_new = [] # type: List[str]
options_end_new = [] # type: List[str]
# search for ',' until one is '(' closer to the beginning
# of the string; put it in options_start
icomma = str_options.index(',')
iparen = str_options.index('(')
#print('icomma=%s iparen=%s' % (icomma, iparen))
while icomma < iparen:
base, str_options = str_options.split(',', 1)
str_options = str_options.strip()
icomma = str_options.index(',')
iparen = str_options.index('(')
options_start.append(base.strip())
#print(' icomma=%s iparen=%s' % (icomma, iparen))
#print(' options_start=%s' % options_start)
# search for ',' until one is ')' closer to the end
# of the string; put it in options_end
icomma = str_options.rindex(',')
iparen = str_options.rindex(')')
#print('icomma=%s iparen=%s' % (icomma, iparen))
while icomma > iparen:
str_options, end = str_options.rsplit(')', 1)
str_options = str_options.strip() + ')'
iparen = str_options.rindex(')')
if ',' in str_options:
icomma = str_options.rindex(',')
else:
icomma = -1
options_end.append(end.strip(' ,'))
#print(' icomma=%s iparen=%s' % (icomma, iparen))
#print(' options_end=%s' % options_end[::-1])
#print()
#print('options_start=%s' % options_start)
#print('options_end=%s' % options_end)
#print('leftover = %r' % str_options)
# clean up the block and make sure we didn't mess up parsing the line
for option in options_start:
assert '(' not in option, option
assert ')' not in option, option
options_start_new += [optioni.strip() for optioni in option.split(',')]
# we created options_end from right to left, so we need to reverse it
for option in options_end[::-1]:
assert '(' not in option, option
assert ')' not in option, option
options_end_new += [optioni.strip() for optioni in option.split(',')]
options = options_start_new + [str_options] + options_end_new
return options
[docs]class GROUNDCHECK(CheckCard):
"""
GROUNDCHECK=YES
GROUNDCHECK(GRID=12,SET=(G,N,A),THRESH=1.E-5,DATAREC=YES)=YES
"""
type = 'GROUNDCHECK'
allowed_keys = {'GRID', 'SET', 'PRINT', 'NOPRINT', 'THRESH', 'DATAREC', 'RTHRESH'}
allowed_strings = {'YES'}
allowed_values = {
'CGI' : (str, ['YES', 'NO']),
'SET' : (str, ['G', 'N', 'AUTOSPC', 'F', 'A', 'ALL']),
'THRESH' : (float, None),
'DATAREC' : (str, ['YES', 'NO']),
'RTHRESH' : (float, None),
'GRID' : (int, None),
}
def __init__(self, key, value, options):
CheckCard.__init__(self, key, value, options)
[docs] def export_to_hdf5(self, hdf5_file, encoding):
export_to_hdf5_check(self, hdf5_file, encoding)
[docs]class MEFFMASS(CheckCard):
"""
MEFFMASS
MEFFMASS(GRID=12,SUMMARY,PARTFAC)
MEFFMASS(PLOT,ALL,THRESH=0.001)=YES
"""
type = 'MEFFMASS'
allowed_keys = {
'PRINT', 'PLOT', 'PUNCH',
'MINT1', 'MINT2', 'MINT3', 'MAXIT',
'THRESH', 'GRID',
'SUMMARY', 'PARTFAC', 'MEFFM', 'MEFFW', 'FRACSUM', 'ALL'}
allowed_strings = {'YES', 'NO'}
alternate_names = {'MEFF'}
allowed_values = {
'GRID' : (int, None),
'MINT1' : (int, None),
'MINT2' : (int, None),
'MINT3' : (int, None),
'MAXIT' : (int, None),
'THRESH' : (float, None),
} # type: Dict[str, Union[str, int]]
#alternate_names = {'PRES'}
#allow_ints = True
#def __init__(self, key, value, options):
#CheckCard.__init__(self, key, value, options)
[docs] def export_to_hdf5(self, hdf5_file, encoding):
export_to_hdf5_check(self, hdf5_file, encoding)
[docs]class WEIGHTCHECK(CheckCard):
"""
WEIGHTCHECK=YES
WEIGHTCHECK(GRID=12,SET=(G,N,A),MASS)=YES
"""
type = 'WEIGHTCHECK'
allowed_keys = {'GRID', 'SET', 'PRINT', 'NOPRINT', 'CGI', 'MASS', 'WEIGHT'}
allowed_strings = {'YES'}
allowed_values = {
'CGI': (str, ['YES', 'NO']),
'SET': (str, ['G', 'N', 'AUTOSPC', 'F', 'A', 'V', 'ALL']),
'GRID' : (int, None),
}
def __init__(self, key, value, options):
CheckCard.__init__(self, key, value, options)
[docs] def export_to_hdf5(self, hdf5_file, encoding):
export_to_hdf5_check(self, hdf5_file, encoding)
[docs]class DSAPRT(CheckCard):
"""
DSAPRT(END=SENS)=ALL
DSAPRT(FORMATTED,EXPORT)
DSAPRT(FORMATTED,START=FIRST,BY=3,END=LAST)=101
DSAPRT(UNFORMATTED,START=FIRST)
DSAPRT(UNFORMATTED,EXPORT)
DSAPRT(FORMATTED,END=4)=ALL
DSAPRT(UNFORMATTED,END=SENS)=ALL
DSAPRT(NOPRINT, EXPORT)
"""
# not done...
type = 'DSAPRT'
allowed_keys = {
'FORMATTED', 'UNFORMATTED', 'EXPORT',
'START', 'BY', 'END',}
allowed_strings = {'ALL'}
allowed_values = {
'START' : (str, ['FIRST']),
'BY' : (int, None),
'END' : (str, ['SENS', 'LAST']),
}
def __init__(self, key, value, options):
CheckCard.__init__(self, key, value, options)
[docs] def export_to_hdf5(self, hdf5_file, encoding):
export_to_hdf5_check(self, hdf5_file, encoding)
[docs]class MODCON(CheckCard):
"""
MODCON=123
MODCON(SORT1,PHASE,PRINT,PUNCH,BOTH,TOPS=5)=ALL
"""
type = 'MODCON'
allowed_keys = {'SORT1', 'SORT2', 'REAL', 'IMAG', 'PHASE', 'PRINT', 'NOPRINT',
'PUNCH', 'ABS', 'NORM', 'BOTH', 'TOPS', 'TOPF', 'SOLUTION',
'PANELMC'}
duplicate_names = {
'TOP' : 'TOPS',
'SOLU' : 'SOLUTION',
'PANE' : 'PANELMC',
}
allowed_strings = {'ALL', 'NONE'}
allow_ints = True
allowed_values = {
'TOPS': (int, None),
'TOPF': (int, None),
'SOLUTION' : (int, None), ## TODO: is this right???
}
def __init__(self, key, value, options):
CheckCard.__init__(self, key, value, options)
[docs]class EXTSEOUT(CaseControlCard):
"""
EXTSEOUT
EXTSEOUT(ASMBULK,EXTID=100)
EXTSEOUT(ASMBULK,EXTBULK,EXTID=200)
EXTSEOUT(EXTBULK,EXTID=300)
EXTSEOUT(DMIGDB)
EXTSEOUT(ASMBULK,EXTID=400,DMIGOP2=21)
EXTSEOUT(EXTID=500,DMIGPCH)
EXTSEOUT(ASMBULK,EXTBULK,EXTID=500,DMIGSFIX=XSE500,DMIGPCH)
EXTSEOUT(ASMBULK,EXTBULK,EXTID=500,DMIGSFIX=EXTID,DMIGPCH)
EXTSEOUT(STIF,MASS,DAMP,EXTID=600,ASMBULK,EXTBULK,MATDB)
EXTSEOUT(STIF,MASS,DAMP,GEOM,EXTID=600)
"""
type = 'EXTSEOUT'
allowed_keys = {'EXTID', 'ASMBULK', 'EXTBULK', 'MATDB', 'MATRIXDB',
'GEOM', 'DMIGSFIX', 'DMIGDB',
'STIFF', 'STIFFNESS', 'MASS',
'DAMP', 'DAMPING', 'K4DAMP',
'LOADS',
'DMIGOP2', 'DMIGPCH',
'MATOP4', 'MATRIXOP4'}
def __init__(self, data):
super(EXTSEOUT, self).__init__()
self.data = data
[docs] def export_to_hdf5(self, hdf5_file, encoding):
if isinstance(self.data, list):
data_group = hdf5_file.create_group('data')
values = []
keys = []
keys_none = []
for (key, value) in self.data:
if value is None:
keys_none.append(key)
else:
keys.append(key)
values.append(value)
if keys_none:
keys_none_bytes = [key.encode(encoding) for key in keys_none]
data_group.create_dataset('keys_none', data=keys_none_bytes)
if keys:
keys_bytes = [key.encode(encoding) for key in keys]
values_bytes = [value.encode(encoding) if isinstance(value, str) else value
for value in values]
data_group.create_dataset('keys', data=keys_bytes)
data_group.create_dataset('values', data=values_bytes)
else:
raise NotImplementedError(self.data)
[docs] @classmethod
def load_hdf5(self, subgroup, encoding):
"""loads EXTSEOUT from an h5py HDF5 file"""
from pyNastran.utils.dict_to_h5py import _cast
for key in subgroup.keys():
subgroupi = subgroup[key]
if key == 'data':
data_keys = _cast(subgroupi['keys'])
data_keys = decode_bytes_list(data_keys, encoding)
keys_none = subgroupi['keys_none']
keys_none = decode_bytes_list(keys_none, encoding)
data_values = _cast(subgroupi['values'])
data_values = decode_bytes_list(data_values, encoding)
keys = data_keys + keys_none
values = data_values + [None] * len(keys_none)
data = [(key, value) for (key, value) in zip(keys, values)]
else:
raise NotImplementedError(key)
return EXTSEOUT(data), []
[docs] @classmethod
def add_from_case_control(cls, line):
"""add method used by the CaseControl class"""
data_list = []
if '(' not in line:
assert line == 'EXTSEOUT', line
else:
assert line.startswith('EXTSEOUT('), line
assert line.endswith(')'), line
data = line[9:-1].split(',')
#print('data EXTSEOUT =', data)
for key_value in data:
key_value = key_value.strip()
if '=' in key_value:
key, value = key_value.split('=')
key = cls._update_key(key)
value = value.strip()
data_list.append((key, value))
else:
key = cls._update_key(key_value)
data_list.append((key, None))
if key not in cls.allowed_keys:
msg = 'EXTSEOUT: key=%r allowed_keys=[%s]' % (key, ', '.join(cls.allowed_keys))
raise KeyError(msg)
return EXTSEOUT(data_list)
[docs] @staticmethod
def _update_key(key):
"""
STIFFNESS, DAMPING, K4DAMP, and LOADS may be abbreviated to STIF,
DAMP, K4DA, and LOAD, respectively.
"""
key = key.strip()
if key == 'STIF':
key = 'STIFFNESS'
elif key == 'DAMP':
key = 'DAMPING'
elif key == 'K4DA':
key = 'K4DAMP'
elif key == 'LOAD':
key = 'LOADS'
return key
[docs] def write(self, spaces):
msg = spaces + str(self)
return msg
def __repr__(self):
"""writes a card"""
msg = 'EXTSEOUT'
if self.data:
msg += '('
for key, value in self.data:
if value is None:
msg += '%s, ' % key
else:
msg += '%s=%s, ' % (key, value)
msg = msg.strip(', ') + ')'
return msg + '\n'
[docs]class VOLUME(CaseControlCard):
"""
VOLUME 21 SET 2
VOLUME id SET sid, [PRINCIPAL, DIRECT STRESS] [SYSTEM {ELEMENT, CORD cid, BASIC}]
"""
type = 'VOLUME'
def __init__(self, data):
super().__init__()
self.data = data
#def export_to_hdf5(self, hdf5_file, encoding):
#if isinstance(self.data, list):
#data_group = hdf5_file.create_group('data')
#keys = []
#values = []
#for (key, value) in self.data:
#keys.append(key)
#values.append(value)
##print('keys = ', keys)
##print('values = ', values)
#keys_bytes = [
#key.encode(encoding) if isinstance(key, str) else key
#for key in keys]
#values_bytes = [
#value.encode(encoding) if isinstance(value, str) else value
#for value in values]
#data_group.create_dataset('keys', data=keys_bytes)
#if None in values_bytes:
#value_group = data_group.create_group('values')
#for i, value in enumerate(values):
#if value is None:
#continue
#value_group.create_dataset(str(i), data=value)
#else:
#data_group.create_dataset('values', data=values_bytes)
##hdf5_file.create_dataset('data', data=data_bytes)
#else:
#raise NotImplementedError(self.data)
[docs] @classmethod
def add_from_case_control(cls, line):
"""add method used by the CaseControl class"""
sline = line.split()
i = 0
data = {}
while i < len(sline):
word = sline[i]
if word == 'VOLUME':
value = sline[i+1]
data[word] = int(value)
i += 2
elif word == 'SET':
value = sline[i+1]
data[word] = int(value)
i += 2
elif word == 'DIRECT':
# this is confusing...
value = 'NONE'
if i+1 < len(sline):
#print(sline)
value = sline[i+1]
#data[word] = None
data[word] = value
assert value in ['NONE'], 'DIRECT value=%r' % value
i += 2
else:
raise RuntimeError(f'VOLUME: {word}; {sline}\n{line}')
return VOLUME(data)
[docs] def write(self, spaces):
msg = spaces + str(self)
return msg
def __repr__(self):
"""writes a card"""
msg = 'VOLUME %i' % self.data['VOLUME']
for key, value in sorted(self.data.items()):
if key == 'VOLUME':
continue
msg += ' %s %s' % (key, value)
return msg + '\n'
[docs]class SURFACE(CaseControlCard):
"""
SURFACE 10 SET 9 NORMAL X3
SURFACE 41 SET 42 FIBRE ALL NORMAL Z
VOLUME id SET sid, [PRINCIPAL, DIRECT STRESS] [SYSTEM {ELEMENT, CORD cid, BASIC}]
"""
type = 'VOLUME'
def __init__(self, data):
super().__init__()
self.data = data
#def export_to_hdf5(self, hdf5_file, encoding):
#if isinstance(self.data, list):
#data_group = hdf5_file.create_group('data')
#keys = []
#values = []
#for (key, value) in self.data:
#keys.append(key)
#values.append(value)
##print('keys = ', keys)
##print('values = ', values)
#keys_bytes = [
#key.encode(encoding) if isinstance(key, str) else key
#for key in keys]
#values_bytes = [
#value.encode(encoding) if isinstance(value, str) else value
#for value in values]
#data_group.create_dataset('keys', data=keys_bytes)
#if None in values_bytes:
#value_group = data_group.create_group('values')
#for i, value in enumerate(values):
#if value is None:
#continue
#value_group.create_dataset(str(i), data=value)
#else:
#data_group.create_dataset('values', data=values_bytes)
##hdf5_file.create_dataset('data', data=data_bytes)
#else:
#raise NotImplementedError(self.data)
[docs] @classmethod
def add_from_case_control(cls, line):
"""add method used by the CaseControl class"""
sline = line.split()
i = 0
data = {}
while i < len(sline):
word = sline[i]
if word == 'SURFACE':
value = sline[i+1]
data[word] = int(value)
i += 2
elif word == 'SET':
value = sline[i+1]
data[word] = int(value)
i += 2
elif word == 'FIBRE':
value = sline[i+1]
data[word] = value
assert value in ['ALL'], 'SURFACE: %r=%r' % (word, value)
i += 2
elif word == 'NORMAL':
value = sline[i+1]
data[word] = value
assert value in ['Z', 'X1', 'X2', 'X3'], 'SURFACE: %r=%r' % (word, value)
i += 2
else:
raise RuntimeError(word)
return SURFACE(data)
[docs] def write(self, spaces):
msg = spaces + str(self)
return msg
def __repr__(self):
"""writes a card"""
msg = 'SURFACE %i' % self.data['SURFACE']
for key, value in sorted(self.data.items()):
if key == 'SURFACE':
continue
msg += ' %s %s' % (key, value)
return msg + '\n'
[docs]class CSCALE(CaseControlCard):
"""
CSCALE 1.3
"""
type = 'CSCALE'
def __init__(self, data):
super().__init__()
self.data = data
#def export_to_hdf5(self, hdf5_file, encoding):
#if isinstance(self.data, list):
#data_group = hdf5_file.create_group('data')
#keys = []
#values = []
#for (key, value) in self.data:
#keys.append(key)
#values.append(value)
##print('keys = ', keys)
##print('values = ', values)
#keys_bytes = [
#key.encode(encoding) if isinstance(key, str) else key
#for key in keys]
#values_bytes = [
#value.encode(encoding) if isinstance(value, str) else value
#for value in values]
#data_group.create_dataset('keys', data=keys_bytes)
#if None in values_bytes:
#value_group = data_group.create_group('values')
#for i, value in enumerate(values):
#if value is None:
#continue
#value_group.create_dataset(str(i), data=value)
#else:
#data_group.create_dataset('values', data=values_bytes)
##hdf5_file.create_dataset('data', data=data_bytes)
#else:
#raise NotImplementedError(self.data)
[docs] @classmethod
def add_from_case_control(cls, line):
"""add method used by the CaseControl class"""
sline = line.split()
value = float(sline[1])
return CSCALE(value)
[docs] def write(self, spaces):
msg = spaces + str(self)
return msg
def __repr__(self):
"""writes a card"""
msg = 'CSCALE %s\n' % self.value
return msg
[docs]def export_to_hdf5_check(self, hdf5_file, encoding):
#print(hdf5_file)
#print('values* =', self.value)
#print('options* =', self.options)
if isinstance(self.options, list):
options_bytes = [
option.encode(encoding) if isinstance(option, str) else option
for option in self.options]
#print('optins =', options_bytes)
hdf5_file.create_dataset('options', data=options_bytes)
else:
raise NotImplementedError(self.options)
#else:
#sub_group.create_dataset('options', data=self.options)
if isinstance(self.data, list):
data_group = hdf5_file.create_group('data')
keys = []
values = []
for (key, value) in self.data:
keys.append(key)
values.append(value)
#print('keys = ', keys)
#print('values = ', values)
keys_bytes = [
key.encode(encoding) if isinstance(key, str) else key
for key in keys]
values_bytes = [
value.encode(encoding) if isinstance(value, str) else value
for value in values]
data_group.create_dataset('keys', data=keys_bytes)
data_group.create_dataset('values', data=values_bytes)
#hdf5_file.create_dataset('data', data=data_bytes)
else:
raise NotImplementedError(self.data)
hdf5_file.create_dataset('key', data=self.key)
hdf5_file.create_dataset('value', data=self.value)
#hdf5_file.create_dataset('options', data=self.options)
#hdf5_file.create_dataset('data', data=self.data)
#-------------------------------------------------------------------------------