diff --git a/pyNastran/bdf/bdf_interface/assign_type_force.py b/pyNastran/bdf/bdf_interface/assign_type_force.py index 495f2a81f..b92101711 100644 --- a/pyNastran/bdf/bdf_interface/assign_type_force.py +++ b/pyNastran/bdf/bdf_interface/assign_type_force.py @@ -164,6 +164,55 @@ def force_double_or_blank(card: BDFCard, ifield: int, fieldname: str, default: O 'card=%s' % (fieldname, svalue, ifield, dtype, card)) return default +def force_double_or_string(card: BDFCard, ifield: int, fieldname: str, default: Optional[float]=None): + """see ``double_or_string``""" + svalue = card.field(ifield) + + if isinstance(svalue, float_types): + return svalue + elif isinstance(svalue, integer_types): + fvalue = float(svalue) + warnings.warn('%s = %r (field #%s) on card must be a float or string (not an integer) -> %s.\n' + 'card=%s' % (fieldname, svalue, ifield, card)) + return fvalue + elif isinstance(svalue, str): + if len(svalue) == 0: + warnings.warn('%s = %r (field #%s) on card must be a float or string (not an blank) -> %s.\n' + 'card=%s' % (fieldname, svalue, ifield, card)) + raise RuntimeError('no blanks allowed') + + try: + # float + fvalue = force_double(card, ifield, fieldname) + return fvalue + except SyntaxError: + pass + + #print(svalue) + raise NotImplementedError(svalue) + #try: + #ivalue = int(svalue) + #fvalue = float(ivalue) + #warnings.warn('%s = %r (field #%s) on card must be a float or blank (not an integer) -> %s.\n' + #'card=%s' % (fieldname, svalue, ifield, fvalue, card)) + #return fvalue + #except Exception: + #svalue = svalue.strip().upper() + #if not svalue: + #return default + #try: + #return double(card, ifield, fieldname) + #except Exception: + #if svalue == '.': + #return 0. + #dtype = _get_dtype(svalue) + #raise SyntaxError('%s = %r (field #%s) on card must be a float or blank (not %s).\n' + #'card=%s' % (fieldname, svalue, ifield, dtype, card)) + else: + raise SyntaxError('%s = %r (field #%s) on card must be a float or blank (not an integer) -> %s.\n' + 'card=%s' % (fieldname, svalue, ifield, card)) + return default + def lax_double_or_blank(card: BDFCard, ifield: int, fieldname: str, default: Optional[float]=None, end: str='') -> float: diff --git a/pyNastran/bdf/cards/bdf_tables.py b/pyNastran/bdf/cards/bdf_tables.py index 74aab0bc0..2215b4a2a 100644 --- a/pyNastran/bdf/cards/bdf_tables.py +++ b/pyNastran/bdf/cards/bdf_tables.py @@ -34,6 +34,7 @@ from pyNastran.bdf.bdf_interface.assign_type import ( integer, integer_or_blank, double, string, string_or_blank, double_or_string, double_or_blank, integer_or_string) +from pyNastran.bdf.bdf_interface.assign_type_force import force_double_or_string if TYPE_CHECKING: from pyNastran.bdf.bdf import BDF @@ -253,7 +254,7 @@ def __init__(self, tid: int, x: np.ndarray, y: np.ndarray, assert self.yaxis in ['LINEAR', 'LOG'], 'yaxis=%r' % (self.yaxis) @classmethod - def add_card(cls, card, comment=''): + def add_card(cls, card: BDFCard, comment: str=''): """ Adds a TABLED1 card from ``BDF.add_card(...)`` @@ -273,6 +274,27 @@ def add_card(cls, card, comment=''): x, y = read_table(card, table_id, 'TABLED1') return TABLED1(table_id, x, y, xaxis=xaxis, yaxis=yaxis, extrap=extrap, comment=comment) + @classmethod + def add_card_lax(cls, card: BDFCard, comment: str=''): + """ + Adds a TABLED1 card from ``BDF.add_card(...)`` + + Parameters + ---------- + card : BDFCard() + a BDFCard object + comment : str; default='' + a comment for the card + + """ + table_id = integer(card, 1, 'tid') + xaxis = string_or_blank(card, 2, 'xaxis', 'LINEAR') + yaxis = string_or_blank(card, 3, 'yaxis', 'LINEAR') + extrap = integer_or_blank(card, 4, 'yaxis', 0) + + x, y = read_table_lax(card, table_id, 'TABLED1') + return TABLED1(table_id, x, y, xaxis=xaxis, yaxis=yaxis, extrap=extrap, comment=comment) + @classmethod def add_op2_data(cls, data, comment=''): table_id = data[0] @@ -397,7 +419,7 @@ def __init__(self, tid: int, x1: float, self.y = np.asarray(y, dtype='float64') @classmethod - def add_card(cls, card, comment=''): + def add_card(cls, card: BDFCard, comment: str=''): """ Adds a TABLED2 card from ``BDF.add_card(...)`` @@ -415,6 +437,25 @@ def add_card(cls, card, comment=''): x, y = read_table(card, table_id, 'TABLED2') return TABLED2(table_id, x1, x, y, extrap=extrap, comment=comment) + @classmethod + def add_card_lax(cls, card: BDFCard, comment: str=''): + """ + Adds a TABLED2 card from ``BDF.add_card(...)`` + + Parameters + ---------- + card : BDFCard() + a BDFCard object + comment : str; default='' + a comment for the card + + """ + table_id = integer(card, 1, 'tid') + x1 = double(card, 2, 'x1') + extrap = integer_or_blank(card, 3, 'extrap', default=0) + x, y = read_table_lax(card, table_id, 'TABLED2') + return TABLED2(table_id, x1, x, y, extrap=extrap, comment=comment) + @classmethod def add_op2_data(cls, data, comment=''): table_id = data[0] @@ -547,6 +588,26 @@ def add_card(cls, card, comment=''): x, y = read_table(card, table_id, 'TABLED3') return TABLED3(table_id, x1, x2, x, y, extrap=extrap, comment=comment) + @classmethod + def add_card_lax(cls, card, comment=''): + """ + Adds a TABLED3 card from ``BDF.add_card(...)`` + + Parameters + ---------- + card : BDFCard() + a BDFCard object + comment : str; default='' + a comment for the card + + """ + table_id = integer(card, 1, 'tid') + x1 = double(card, 2, 'x1') + x2 = double(card, 3, 'x2') + extrap = integer_or_blank(card, 4, 'extrap', default=0) + x, y = read_table_lax(card, table_id, 'TABLED3') + return TABLED3(table_id, x1, x2, x, y, extrap=extrap, comment=comment) + @classmethod def add_op2_data(cls, data, comment=''): table_id = data[0] @@ -828,6 +889,24 @@ def add_card(cls, card, comment=''): x, y = read_table(card, table_id, 'TABDMP1') return TABDMP1(table_id, x, y, Type=Type, comment=comment) + @classmethod + def add_card_lax(cls, card, comment=''): + """ + Adds a TABDMP1 card from ``BDF.add_card(...)`` + + Parameters + ---------- + card : BDFCard() + a BDFCard object + comment : str; default='' + a comment for the card + + """ + table_id = integer(card, 1, 'tid') + Type = string_or_blank(card, 2, 'Type', 'G') + x, y = read_table_lax(card, table_id, 'TABDMP1') + return TABDMP1(table_id, x, y, Type=Type, comment=comment) + @classmethod def add_op2_data(cls, data, comment=''): table_id = data[0] @@ -919,6 +998,25 @@ def add_card(cls, card, comment=''): x, y = read_table(card, table_id, 'TABLEM1') return TABLEM1(table_id, x, y, xaxis=xaxis, yaxis=yaxis, comment=comment) + @classmethod + def add_card_lax(cls, card, comment=''): + """ + Adds a TABLEM1 card from ``BDF.add_card(...)`` + + Parameters + ---------- + card : BDFCard() + a BDFCard object + comment : str; default='' + a comment for the card + + """ + table_id = integer(card, 1, 'tid') + xaxis = string_or_blank(card, 2, 'xaxis', 'LINEAR') + yaxis = string_or_blank(card, 3, 'yaxis', 'LINEAR') + x, y = read_table_lax(card, table_id, 'TABLEM1') + return TABLEM1(table_id, x, y, xaxis=xaxis, yaxis=yaxis, comment=comment) + @classmethod def add_op2_data(cls, data, comment=''): table_id = data[0] @@ -1007,6 +1105,28 @@ def add_card(cls, card, comment=''): x, y = read_table(card, table_id, 'TABLEM2') return TABLEM2(table_id, x1, x, y, extrap=extrap, comment=comment) + @classmethod + def add_card_lax(cls, card, comment=''): + """ + Adds a TABLEM2 card from ``BDF.add_card(...)`` + + Parameters + ---------- + card : BDFCard() + a BDFCard object + comment : str; default='' + a comment for the card + """ + table_id = integer(card, 1, 'tid') + + # defined in MSC as an integer and used as a float...int > 0 + # defined in NX as a float; real + # no default given in either, but from context, let's assume 0.0 + x1 = double_or_blank(card, 2, 'x1', 0.0) + extrap = integer_or_blank(card, 3, 'EXTRAP', default=0) + x, y = read_table_lax(card, table_id, 'TABLEM2') + return TABLEM2(table_id, x1, x, y, extrap=extrap, comment=comment) + @classmethod def add_op2_data(cls, data, comment=''): table_id = data[0] @@ -1096,6 +1216,26 @@ def add_card(cls, card, comment=''): x, y = read_table(card, table_id, 'TABLEM3') return TABLEM3(table_id, x1, x2, x, y, extrap=extrap, comment=comment) + @classmethod + def add_card_lax(cls, card, comment=''): + """ + Adds a TABLEM3 card from ``BDF.add_card(...)`` + + Parameters + ---------- + card : BDFCard() + a BDFCard object + comment : str; default='' + a comment for the card + + """ + table_id = integer(card, 1, 'tid') + x1 = double(card, 2, 'x1') + x2 = double(card, 3, 'x2') + extrap = integer_or_blank(card, 4, 'extrap', default=0) + x, y = read_table_lax(card, table_id, 'TABLEM3') + return TABLEM3(table_id, x1, x2, x, y, extrap=extrap, comment=comment) + @classmethod def add_op2_data(cls, data, comment=''): table_id = data[0] @@ -1298,6 +1438,24 @@ def add_card(cls, card, comment=''): x, y = read_table(card, table_id, 'TABLES1') return TABLES1(table_id, x, y, Type=Type, comment=comment) + @classmethod + def add_card_lax(cls, card, comment=''): + """ + Adds a TABLES1 card from ``BDF.add_card(...)`` + + Parameters + ---------- + card : BDFCard() + a BDFCard object + comment : str; default='' + a comment for the card + + """ + table_id = integer(card, 1, 'tid') + Type = integer_or_blank(card, 2, 'Type', 1) + x, y = read_table_lax(card, table_id, 'TABLES1') + return TABLES1(table_id, x, y, Type=Type, comment=comment) + @classmethod def add_op2_data(cls, data, comment=''): """ @@ -1381,6 +1539,23 @@ def add_card(cls, card, comment=''): x, y = read_table(card, table_id, 'TABLEST') return TABLEST(table_id, x, y, comment=comment) + @classmethod + def add_card_lax(cls, card, comment=''): + """ + Adds a TABLEST card from ``BDF.add_card(...)`` + + Parameters + ---------- + card : BDFCard() + a BDFCard object + comment : str; default='' + a comment for the card + + """ + table_id = integer(card, 1, 'tid') + x, y = read_table_lax(card, table_id, 'TABLEST') + return TABLEST(table_id, x, y, comment=comment) + @classmethod def add_op2_data(cls, data, comment=''): """ @@ -1482,6 +1657,23 @@ def add_card(cls, card, comment=''): x, y = read_table(card, table_id, 'TABLEH1') return TABLEH1(table_id, x, y, comment=comment) + @classmethod + def add_card_lax(cls, card, comment=''): + """ + Adds a TABLEH1 card from ``BDF.add_card(...)`` + + Parameters + ---------- + card : BDFCard() + a BDFCard object + comment : str; default='' + a comment for the card + + """ + table_id = integer(card, 1, 'tid') + x, y = read_table_lax(card, table_id, 'TABLEH1') + return TABLEH1(table_id, x, y, comment=comment) + @classmethod def add_op2_data(cls, data, comment=''): """ @@ -1664,6 +1856,25 @@ def add_card(cls, card, comment=''): x, y = read_table(card, table_id, 'TABRND1') return TABRND1(table_id, x, y, xaxis=xaxis, yaxis=yaxis, comment=comment) + @classmethod + def add_card_lax(cls, card, comment=''): + """ + Adds a TABRND1 card from ``BDF.add_card(...)`` + + Parameters + ---------- + card : BDFCard() + a BDFCard object + comment : str; default='' + a comment for the card + + """ + table_id = integer(card, 1, 'tid') + xaxis = string_or_blank(card, 2, 'xaxis', 'LINEAR') + yaxis = string_or_blank(card, 3, 'yaxis', 'LINEAR') + x, y = read_table_lax(card, table_id, 'TABRND1') + return TABRND1(table_id, x, y, xaxis=xaxis, yaxis=yaxis, comment=comment) + @classmethod def add_op2_data(cls, data, comment=''): """ @@ -1796,7 +2007,7 @@ def _map_axis(axis): raise ValueError('axis=%r' % axis) return axis_type -def read_table(card, table_id, table_type): +def read_table(card, table_id: int, table_type: str) -> tuple[np.ndarray, np.ndarray]: """common method for reading tables that handles SKIP""" nfields = len(card) - 1 nterms = (nfields - 9) // 2 @@ -1817,6 +2028,27 @@ def read_table(card, table_id, table_type): x, y = make_xy(table_id, table_type, xy) return x, y +def read_table_lax(card, table_id: int, table_type: str) -> tuple[np.ndarray, np.ndarray]: + """common method for reading tables that handles SKIP""" + nfields = len(card) - 1 + nterms = (nfields - 9) // 2 + if nterms < 0: + raise SyntaxError('%r card is too short' % table_type) + + xy = [] + for i in range(nterms): + n = 9 + i * 2 + if card.field(n) == 'ENDT' or card.field(n+1) == 'ENDT': + break + xi = force_double_or_string(card, n, 'x' + str(i + 1)) + yi = force_double_or_string(card, n + 1, 'y' + str(i + 1)) + if xi == 'SKIP' or yi == 'SKIP': + continue + xy.append([xi, yi]) + string(card, nfields, 'ENDT') + x, y = make_xy(table_id, table_type, xy) + return x, y + def read_table_float_int(card, table_id, table_type): """common method for reading tables that handles SKIP""" nfields = len(card) - 1 diff --git a/pyNastran/dev/bdf_vectorized3/cards/elements/plate_stress_strain.py b/pyNastran/dev/bdf_vectorized3/cards/elements/plate_stress_strain.py index 3f79d52d9..1a9f4c3a4 100644 --- a/pyNastran/dev/bdf_vectorized3/cards/elements/plate_stress_strain.py +++ b/pyNastran/dev/bdf_vectorized3/cards/elements/plate_stress_strain.py @@ -1368,11 +1368,12 @@ def write_file(self, bdf_file: TextIOLike, size: int=8, property_id = array_str(self.property_id, size=size) nodes = array_str(self.nodes, size=size) tflags = array_default_int(self.tflag, size=size, default=0) + thicknesses = array_float_nan(self.thickness, size=size, is_double=False) for eid, pid, (n1, n2, n3, n4, n5, n6), theta, tflag, thickness in zip_longest( - element_id, property_id, nodes, self.theta, tflags, self.thickness): + element_id, property_id, nodes, self.theta, tflags, thicknesses): list_fields = ['CPLSTS6', eid, pid, n1, n2, n3, n4, n5, n6, '', '', theta, tflag] - if not np.all(np.isnan(thickness)): + if not np.all(thickness == ''): t1, t2, t3, t4, t5, t6 = thickness list_fields.extend([t1, t2, t3, '', '', '', '', '', t4, t5, t6]) bdf_file.write(print_card(list_fields)) @@ -1525,11 +1526,12 @@ def write_file(self, bdf_file: TextIOLike, size: int=8, property_id = array_str(self.property_id, size=size) nodes = array_str(self.nodes, size=size) tflags = array_default_int(self.tflag, size=size, default=0) + thicknesses = array_float_nan(self.thickness, size=size) for eid, pid, (n1, n2, n3, n4, n5, n6, n7, n8), theta, tflag, thickness, in zip_longest( - element_id, property_id, nodes, self.theta, tflags, self.thickness): + element_id, property_id, nodes, self.theta, tflags, thicknesses): list_fields = ['CPLSTS8', eid, pid, n1, n2, n3, n4, n5, n6, n7, n8, theta, tflag] - if not np.all(np.isnan(thickness)): + if not np.all(thickness == ''): t1, t2, t3, t4, t5, t6, t7, t8 = thickness list_fields.extend([t1, t2, t3, t4, '', '', '', '', t5, t6, t7, t8]) bdf_file.write(print_card(list_fields)) diff --git a/pyNastran/dev/bdf_vectorized3/cards/elements/shell.py b/pyNastran/dev/bdf_vectorized3/cards/elements/shell.py index 4a3653949..7ff2f0709 100644 --- a/pyNastran/dev/bdf_vectorized3/cards/elements/shell.py +++ b/pyNastran/dev/bdf_vectorized3/cards/elements/shell.py @@ -2228,6 +2228,13 @@ def convert(self, xyz_scale: float=1.0, **kwargs): itflag = (self.tflag == 0) self.T[itflag] *= xyz_scale + def card_headers(self, size: int=8) -> list[str]: + theta_mcid = 'th_mcid' if size == 8 else 'theta_mcid' + headers = ['CQUAD8', 'eid', 'pid', 'node1', 'node2', 'node3', 'node4', 'node5', 'node6', + 'node7', 'node8', 'T1', 'T2', 'T3', 'T4', theta_mcid, 'zoffset', + 'tflag', ] + return headers + @property def max_id(self) -> int: return max(self.element_id.max(), self.property_id.max(), @@ -2244,32 +2251,36 @@ def write_file(self, bdf_file: TextIOLike, #) element_id = array_str(self.element_id, size=size) property_id = array_str(self.property_id, size=size) - mcids = array_default_int(self.mcid, default=-1, size=size) + #mcids = array_default_int(self.mcid, default=-1, size=size) + tflags = array_default_int(self.tflag, default=0, size=size) + nodes_ = array_default_int(self.nodes, default=0, size=size).tolist() #no_zoffset = np.all(np.isnan(self.zoffset)) #no_mcid = np.all(mcids == '') #CQUAD4 307517 105 247597 262585 262586 247591 -1 0.0 + zoffsets = array_default_float(self.zoffset, default=0., size=size, is_double=False) + Ts = array_default_float(self.T, default=0., size=size, is_double=False) theta_mcids = combine_int_float_array( self.mcid, self.theta, int_default=-1, float_default=0.0, size=size) for eid, pid, nodes, theta_mcid, zoffset, tflag, T in zip_longest( - element_id, property_id, self.nodes, theta_mcids, - self.zoffset, self.tflag, self.T): - zoffset = '' if np.isnan(zoffset) else zoffset + element_id, property_id, nodes_, theta_mcids, + zoffsets, tflags, Ts): + #zoffset = '' if np.isnan(zoffset) else zoffset T1, T2, T3, T4 = T #if np.isnan(theta): #theta_mcid = '%8s' % mcid #else: #theta_mcid = print_field_8(theta) - zoffset = set_blank_if_default(zoffset, 0.0) - tflag = set_blank_if_default(tflag, 0) - T1 = set_blank_if_default(T1, 1.0) - T2 = set_blank_if_default(T2, 1.0) - T3 = set_blank_if_default(T3, 1.0) - T4 = set_blank_if_default(T4, 1.0) - nodes2 = [None if node == 0 else node for node in nodes] - list_fields = ['CQUAD8', eid, pid] + nodes2 + [ + #zoffset = set_blank_if_default(zoffset, 0.0) + #tflag = set_blank_if_default(tflag, 0) + #T1 = set_blank_if_default(T1, 1.0) + #T2 = set_blank_if_default(T2, 1.0) + #T3 = set_blank_if_default(T3, 1.0) + #T4 = set_blank_if_default(T4, 1.0) + #nodes2 = [None if node == 0 else node for node in nodes] + list_fields = ['CQUAD8', eid, pid] + nodes + [ T1, T2, T3, T4, theta_mcid, zoffset, tflag] bdf_file.write(print_card(list_fields)) return diff --git a/pyNastran/dev/bdf_vectorized3/nastran_io3.py b/pyNastran/dev/bdf_vectorized3/nastran_io3.py index 7996591e6..84fef0b00 100644 --- a/pyNastran/dev/bdf_vectorized3/nastran_io3.py +++ b/pyNastran/dev/bdf_vectorized3/nastran_io3.py @@ -74,7 +74,7 @@ def get_nastran3_wildcard_geometry_results_functions(self) -> tuple: ) return data - def load_op2_results(self, op2_filename: str, plot: bool=True) -> None: + def load_op2_results(self, op2_filename: PathLike, plot: bool=True) -> None: """loads results from an op2 file""" assert isinstance(op2_filename, (str, PurePath)), op2_filename model = OP2(debug=True, log=None, mode='msc') @@ -94,7 +94,7 @@ def load_h5_results(self, h5_filename: PathLike, plot: bool=True) -> None: def _load_op2_results(self, model: OP2, plot: bool) -> None: """loads results from a filled OP2 object (for op2/h5)""" name = 'main' - gui = self.gui + gui: MainWindow = self.gui cases: Cases = gui.result_cases form: Form = gui.get_form() icase = len(cases) @@ -102,7 +102,7 @@ def _load_op2_results(self, model: OP2, plot: bool) -> None: model, form, cases, icase, name, plot) - self.gui._finish_results_io2(name, form, cases) + gui._finish_results_io2(name, form, cases) def load_nastran3_geometry(self, bdf_filename: PathLike, name: str='main', plot: bool=True): @@ -110,10 +110,13 @@ def load_nastran3_geometry(self, bdf_filename: PathLike, bdf_filename_lower = bdf_filename.lower() print(bdf_filename) if bdf_filename_lower.endswith('.op2'): - return self.load_op2_geometry(bdf_filename) + geo = self.load_op2_geometry(bdf_filename) elif bdf_filename_lower.endswith('.h5'): - return self.load_h5_geometry(bdf_filename) - return self.load_bdf_geometry(bdf_filename) + geo = self.load_h5_geometry(bdf_filename) + else: + geo = self.load_bdf_geometry(bdf_filename) + self.xyz_cid0 + return geo def load_nastran3_results(self, results_filename: PathLike, name: str='main', plot: bool=True) -> vtkUnstructuredGrid: @@ -152,6 +155,7 @@ def _load_results_from_model(self, model: OP2, xyz_cid0 = self.xyz_cid0 node_id = self.node_id + element_id = self.element_id mmax = xyz_cid0.max(axis=0) mmin = xyz_cid0.min(axis=0) dim_max = (mmax - mmin).max() @@ -163,13 +167,17 @@ def _load_results_from_model(self, model: OP2, #prop_res = GuiResult(subcase_id, header=result_name, title=result_name, #location='centroid', scalar=property_id, mask_value=0) + #results = model.res name_results = [ ('Displacement', model.displacements), ('Eigenvector', model.eigenvectors), + ('Temperature', model.temperatures), + ('Velocity', model.velocities), + ('Acceleration', model.accelerations), ] subcases = set([]) - for (name, results) in name_results: + for (res_name, results) in name_results: for key, case in results.items(): subcases.add(key) @@ -182,6 +190,30 @@ def _load_results_from_model(self, model: OP2, key, subcase, subcase_form, cases, icase, node_id, xyz_cid0, dim_max) + icase = _load_stress_strain( + self.element_cards, + model, name, + key, subcase, subcase_form, + cases, icase, + element_id, is_stress=True) + icase = _load_stress_strain( + self.element_cards, + model, name, + key, subcase, subcase_form, + cases, icase, + element_id, is_stress=False) + + #('Geometry', None, geometry_form), + + #e = ('Subcase 1', None, + #[('Displacement', None, [('Static', 13, [])]), + #[('Stress', None, + #[('oxx', 14, []), ('oyy', 15, []), ('ozz', 16, []), + #('txy', 17, []), ('txz', 18, []), ('tyz', 19, []), + #('omax', 20, []), ('omin', 21, []), ('Von Mises', 22, [])] + #) + #]]) + return icase def load_h5_geometry(self, h5_filename: PathLike, @@ -251,6 +283,8 @@ def _load_geometry_from_model(self, model: BDF, name: str, plot: bool, gui._add_alt_actors(gui.alt_grids) element_id, property_id = self.load_elements(ugrid, model, node_id) + self.element_id = element_id + #print(f'nelements = {len(element_id)}') form, cases, icase = self.save_results(model, node_id, element_id, property_id) @@ -274,6 +308,9 @@ def save_results(self, # I think we specifically look up NodeID, ELementID, # but I think we want to look up by Index here + self.node_id = node_id + self.element_id = element_id + gui.node_ids = node_id # TODO: should this be node_id/index gui.element_ids = element_id # TODO: should this be element_id/index gui.nnodes = len(node_id) @@ -605,6 +642,7 @@ def load_elements(self, This makes it easier to fill the geometry/results, but harder to lookup a specific element id. """ + include_mass_in_geometry = self.include_mass_in_geometry log = model.log property_ids: list[np.ndarray] = [] element_ids: list[np.ndarray] = [] @@ -640,6 +678,7 @@ def load_elements(self, self.gui_elements = gui_elements element_cards = [card for card in model.element_cards if card.n] + self.element_cards = element_cards nelement0 = 0 for element in element_cards: nelement = element.n @@ -779,7 +818,7 @@ def load_elements(self, elif etype in solid_elements: - #model.log.debug(' solid') + #log.debug(' solid') cell_offset0, n_nodesi, cell_typei, cell_offseti = _create_solid_vtk_arrays( element, grid_id, cell_offset0) @@ -790,7 +829,7 @@ def load_elements(self, cell_offset_.append(cell_offseti) del n_nodesi, cell_typei, cell_offseti - elif self.include_mass_in_geometry and etype == 'CONM2' and 0: + elif include_mass_in_geometry and etype == 'CONM2' and 0: cell_type = cell_type_point property_ids.append(np.full(nelement, -1)) @@ -824,7 +863,7 @@ def load_elements(self, cell_offset0 += nelement * (dnode + 1) else: # more complicated element - model.log.warning(f' dropping {element}') + log.warning(f' dropping {element}') continue #raise NotImplementedError(element.type) self.card_index[etype] = (nelement0, nelement0 + nelement) @@ -990,9 +1029,203 @@ def _set_quality(icase: int, cases: dict[int, Any], return mean_edge_length, icase, quality_form +def _load_stress_strain(element_cards: list, + model: OP2, + name: str, + key: tuple[int, int, int, int, int, str, str], + subcase: Subcase, + subcase_form: Form, + cases: Cases, icase: int, + all_element_ids: np.ndarray, + is_stress: bool=True) -> int: + """ + loads: + """ + is_strain = not is_stress + # collect all the stresses + result_form = [] + if is_stress: + stress_form = ('Stress', None, result_form) + name_results = { + # name, result_dicts + 'CELAS1' : (model.celas1_stress, ), + 'CELAS2' : (model.celas2_stress, ), + 'CELAS3' : (model.celas3_stress, ), + 'CELAS4' : (model.celas4_stress, ), + + #('CDAMP1', model.cdamp1_stress), + #('CDAMP2', model.cdamp2_stress), + #('CDAMP3', model.cdamp3_stress), + #('CDAMP4', model.cdamp4_stress), + + 'CROD' : (model.crod_stress, ), + 'CTUBE': (model.ctube_stress, ), + 'CONROD': (model.conrod_stress, ), + + 'CBAR': (model.cbar_stress, ), + 'CBEAM': (model.cbeam_stress, ), + + 'CTRIA3': (model.ctria3_stress, model.ctria3_composite_stress), + 'CTRIA6': (model.ctria6_stress, model.ctria6_composite_stress), + 'CTRIAR': (model.ctriar_stress, model.ctriar_composite_stress), + + 'CQUAD4': (model.cquad4_stress, model.cquad4_composite_stress), + 'CQUAD8': (model.cquad8_stress, model.cquad8_composite_stress), + 'CQUADR': (model.cquadr_stress, model.cquadr_composite_stress), + + 'CTETRA': (model.ctetra_stress, ), + 'CPENTA': (model.cpenta_stress, ), + 'CPYRAM': (model.cpyram_stress, ), + 'CHEXA': (model.chexa_stress, ), + + #('cplstn3', self.cplstn3_stress), + #('cplstn4', self.cplstn4_stress), + #('cplstn6', self.cplstn6_stress), + #('cplstn8', self.cplstn8_stress), + #('cplsts3', self.cplsts3_stress), + #('cplsts4', self.cplsts4_stress), + #('cplsts6', self.cplsts6_stress), + #('cplsts8', self.cplsts8_stress), + } + else: + stress_form = ('Strain', None, result_form) + name_results = { + # name, result_dicts + 'CELAS1' : (model.celas1_strain, ), + 'CELAS2' : (model.celas2_strain, ), + 'CELAS3' : (model.celas3_strain, ), + 'CELAS4' : (model.celas4_strain, ), + + #('CDAMP1', model.cdamp1_strain), + #('CDAMP2', model.cdamp2_strain), + #('CDAMP3', model.cdamp3_strain), + #('CDAMP4', model.cdamp4_strain), + + 'CROD' : (model.crod_strain, ), + 'CTUBE': (model.ctube_strain, ), + 'CONROD': (model.conrod_strain, ), + + 'CBAR': (model.cbar_strain, ), + 'CBEAM': (model.cbeam_strain, ), + + 'CTRIA3': (model.ctria3_strain, model.ctria3_composite_strain), + 'CTRIA6': (model.ctria6_strain, model.ctria6_composite_strain), + 'CTRIAR': (model.ctriar_strain, model.ctriar_composite_strain), + + 'CQUAD4': (model.cquad4_strain, model.cquad4_composite_strain), + 'CQUAD8': (model.cquad8_strain, model.cquad8_composite_strain), + 'CQUADR': (model.cquadr_strain, model.cquadr_composite_strain), + + 'CTETRA': (model.ctetra_strain, ), + 'CPENTA': (model.cpenta_strain, ), + 'CPYRAM': (model.cpyram_strain, ), + 'CHEXA': (model.chexa_strain, ), + + #('cplstn3', self.cplstn3_strain), + #('cplstn4', self.cplstn4_strain), + #('cplstn6', self.cplstn6_strain), + #('cplstn8', self.cplstn8_strain), + #('cplsts3', self.cplsts3_strain), + #('cplsts4', self.cplsts4_strain), + #('cplsts6', self.cplsts6_strain), + #('cplsts8', self.cplsts8_strain), + } + + name_results_dict = {} + for name, results_dicts in name_results.items(): + results_dicts2 = [] + for result_dict in results_dicts: + if key in result_dict: + results_dicts2.append(result_dict[key]) + if len(results_dicts2): + name_results_dict[name] = results_dicts2 + + assert np.array_equal(all_element_ids, np.unique(all_element_ids)) + nelement0 = 0 + nelements = len(all_element_ids) + oxx = np.full(nelements, np.nan, dtype='float64') + oyy = np.full(nelements, np.nan, dtype='float64') + ozz = np.full(nelements, np.nan, dtype='float64') + txy = np.full(nelements, np.nan, dtype='float64') + txz = np.full(nelements, np.nan, dtype='float64') + tyz = np.full(nelements, np.nan, dtype='float64') + omax = np.full(nelements, np.nan, dtype='float64') + omin = np.full(nelements, np.nan, dtype='float64') + von_mises = np.full(nelements, np.nan, dtype='float64') + + is_von_mises = True + for element in element_cards: + etype = element.type + if etype in name_results_dict: + results_cases = name_results_dict[etype] + #print(element) + if etype in {'CTETRA', 'CHEXA', 'CPENTA', 'CPYRAM'}: + #oxx, oyy, ozz, txy, tyz, txz, omax, omid, omin, von_mises + for result in results_cases: + is_von_mises = result.is_von_mises + #if isinstance(result, RealSolidStressArray): + elements = result.element_cid[:, 0] + ielement = np.searchsorted(all_element_ids, elements) + stress = result.data[:, ielement*5, :] + stressi = stress[0, :, :] + oxx[ielement] = stressi[:, 0] + oyy[ielement] = stressi[:, 1] + ozz[ielement] = stressi[:, 2] + txy[ielement] = stressi[:, 3] + tyz[ielement] = stressi[:, 4] + txz[ielement] = stressi[:, 5] + omax[ielement] = stressi[:, 6] + #omid[ielement] = stressi[:, 7] + omin[ielement] = stressi[:, 8] + von_mises[ielement] = stressi[:, 9] + else: + raise NotImplementedError(etype) + nelement0 += element.n + x = 1 + + vm_word = 'Von Mises' if is_von_mises else 'Max Shear' + subcase_id = 1 + + o = 'ϵ' if is_strain else 'σ' + t = 'ϵ' if is_strain else '𝜏' + icase = _add_finite_centroidal_gui_result( + icase, cases, result_form, subcase_id, + o+'xx', oxx) + icase = _add_finite_centroidal_gui_result( + icase, cases, result_form, subcase_id, + o+'oyy', oyy) + icase = _add_finite_centroidal_gui_result( + icase, cases, result_form, subcase_id, + o+'zz', ozz) + icase = _add_finite_centroidal_gui_result( + icase, cases, result_form, subcase_id, + t+'xy', txy) + icase = _add_finite_centroidal_gui_result( + icase, cases, result_form, subcase_id, + t+'xz', txz) + icase = _add_finite_centroidal_gui_result( + icase, cases, result_form, subcase_id, + t+'yz', tyz) + icase = _add_finite_centroidal_gui_result( + icase, cases, result_form, subcase_id, + o+'max', omax) + icase = _add_finite_centroidal_gui_result( + icase, cases, result_form, subcase_id, + o+'min', omax) + icase = _add_finite_centroidal_gui_result( + icase, cases, result_form, subcase_id, + o+vm_word, von_mises) + #del name_results + if len(result_form): + formi = subcase_form + formi.append(stress_form) + return icase + #x = 1 + def _load_oug(model: OP2, - name: str, name_results, - key, + name: str, + name_results: list[tuple[str, Any]], + key: tuple[int, int, int, int, int, str, str], subcase: Subcase, subcase_form: Form, cases: Cases, icase: int, @@ -1007,11 +1240,11 @@ def _load_oug(model: OP2, - temperature """ - for (name, results) in name_results: + for (res_name, results) in name_results: if subcase not in results: continue res_form: Form = [] - subcase_form.append((name, None, res_form)) + subcase_form.append((res_name, None, res_form)) case = results[subcase] scale_per_time, header_names = get_case_headers(case) diff --git a/pyNastran/dev/bdf_vectorized3/test/test_vector_gui_models.py b/pyNastran/dev/bdf_vectorized3/test/test_vector_gui_models.py index be4816f87..33b7ee266 100644 --- a/pyNastran/dev/bdf_vectorized3/test/test_vector_gui_models.py +++ b/pyNastran/dev/bdf_vectorized3/test/test_vector_gui_models.py @@ -23,7 +23,8 @@ def __init__(self, inputs=None): Nastran3.__init__(self, self) self.build_fmts(['nastran3'], stop_on_failure=True) -def run_nastran_gui(filename: str, load_results: bool=True): +def run_nastran_gui(filename: str, + load_results: bool=True): assert os.path.exists(filename), filename filename = str(filename) test = NastranGUI() @@ -33,6 +34,18 @@ def run_nastran_gui(filename: str, load_results: bool=True): test.cycle_results() test.on_rcycle_results() +def run_nastran_gui_results(input_filename: str, + output_filename: str): + assert os.path.exists(input_filename), input_filename + assert os.path.exists(output_filename), output_filename + input_filename = str(input_filename) + output_filename = str(output_filename) + test = NastranGUI() + test.load_nastran3_geometry(input_filename) + test.load_nastran3_results(output_filename) + test.cycle_results() + test.on_rcycle_results() + class TestGuiModels(unittest.TestCase): def test_h5_freq(self): @@ -114,7 +127,9 @@ def test_bwb(self): run_nastran_gui(bdf_filename) def test_solid_bending(self): bdf_filename = MODEL_PATH / 'solid_bending' / 'solid_bending.bdf' - run_nastran_gui(bdf_filename) + op2_filename = MODEL_PATH / 'solid_bending' / 'solid_bending.op2' + #run_nastran_gui(bdf_filename) + run_nastran_gui_results(bdf_filename, op2_filename) def test_isat1(self): bdf_filename = MODEL_PATH / 'iSat' / 'ISat_Dploy_Sm.dat' run_nastran_gui(bdf_filename) diff --git a/pyNastran/gui/qt_files/load_actions.py b/pyNastran/gui/qt_files/load_actions.py index 6324f04a6..a33dab9d8 100644 --- a/pyNastran/gui/qt_files/load_actions.py +++ b/pyNastran/gui/qt_files/load_actions.py @@ -51,6 +51,9 @@ def on_load_geometry(self, infile_name=None, geometry_format=None, name='main', if is_failed: return + if not hasattr(self, 'model_objs'): + self.model_objs = {} + has_results = False infile_name, load_function, filter_index, formats, geometry_format2 = out if load_function is not None: @@ -104,6 +107,7 @@ def on_load_geometry(self, infile_name=None, geometry_format=None, name='main', function_name2 = 'load_%s_geometry' % geometry_format2 load_function2 = getattr(cls, function_name2) has_results = load_function2(infile_name, name=name, plot=plot) + self.model_objs[name] = cls else: # nastran assert 'nastran' in geometry_format2 @@ -294,6 +298,13 @@ def on_load_results(self, out_filename=None): #raise IOError(msg) self.gui.last_dir = os.path.split(out_filenamei)[0] + name = 'main' + if name in self.model_objs: + model = self.model_objs[name] + if fmt[0] == 'nastran3': + fmti, geo1, geo2, res1, res2 = model.get_nastran3_wildcard_geometry_results_functions() + load_function = res2 + try: load_function(out_filenamei) except Exception: # as e