From 141971cb42da7620a4735400959094867c6a9498 Mon Sep 17 00:00:00 2001 From: SteveDoyle2 Date: Mon, 13 Jan 2025 21:01:08 -0800 Subject: [PATCH 1/5] updating spec file for vtk 9.4 - possibly not fixed for vtk 9.4, but I think it's ok...hard to test --- dev/pyNastranGUI.spec | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/dev/pyNastranGUI.spec b/dev/pyNastranGUI.spec index 34aafd3af..787833673 100644 --- a/dev/pyNastranGUI.spec +++ b/dev/pyNastranGUI.spec @@ -730,8 +730,18 @@ vtk_imports_all = [ # 9.3 'vtkmodules.vtkRenderingVolume', 'vtkmodules.vtkRenderingVolumeAMR', 'vtkmodules.vtkRenderingVolumeOpenGL2', 'vtkmodules.vtkRenderingVtkJS', 'vtkmodules.vtkTestingRendering', 'vtkmodules.vtkViewsContext2D', 'vtkmodules.vtkViewsCore', 'vtkmodules.vtkViewsInfovis', 'vtkmodules.vtkWebCore', 'vtkmodules.vtkWebGLExporter', + # tested - 9.4.1 + # Unable to find a valid OpenGL 3.2 or later implementation + 'vtkmodules.util.data_model', 'vtkmodules.util.execution_model', ] +import vtk +vtk_version_str = vtk.VTK_VERSION +print(f'vtk_version_str = {vtk.VTK_VERSION!r}') # '9.3.1' + +if vtk_version_str >= '9.4.0': + raise RuntimeError('use vtk<9.4') + # can we get rid of scipy.optimize? hiddenimports = [ #'vtk', 'vtk.vtkCommonPythonSIP', 'vtk.vtkFilteringPythonSIP', From 1880ae73ef355cb95f1fe188f58bd930d1d8397f Mon Sep 17 00:00:00 2001 From: SteveDoyle2 Date: Mon, 13 Jan 2025 22:45:37 -0800 Subject: [PATCH 2/5] fixing minor tests --- pyNastran/bdf/bdf_interface/add_card.py | 4 ++++ pyNastran/bdf/bdf_interface/stats.py | 2 +- pyNastran/bdf/mesh_utils/bdf_diff.py | 13 ++++++------- pyNastran/bdf/mesh_utils/cmd_line/bdf_diff.py | 9 +++++++-- pyNastran/bdf/mesh_utils/test/test_mesh_utils.py | 8 ++++---- 5 files changed, 22 insertions(+), 14 deletions(-) diff --git a/pyNastran/bdf/bdf_interface/add_card.py b/pyNastran/bdf/bdf_interface/add_card.py index 632eeeda2..2fef6b832 100644 --- a/pyNastran/bdf/bdf_interface/add_card.py +++ b/pyNastran/bdf/bdf_interface/add_card.py @@ -9098,12 +9098,16 @@ def add_dense_dmi(self, name: str, myarray: np.ndarray, elif str_form == 'rectangular': assert nrows >= 1 assert ncols >= 1 + elif str_form == 'diagonal': + assert nrows >= 1, (nrows, ncols) + assert ncols == 1, (nrows, ncols) else: # pragma: no cover raise NotImplementedError(str_form) # ncols = 2 GCi = np.repeat(list(range(1, nrows+1)), ncols, axis=0).reshape(nrows, ncols).flatten() GCj = np.repeat(list(range(1, ncols+1)), nrows, axis=0).reshape(nrows, ncols).flatten() + #self.log.warning(f'str_form = {str_form}') #self.log.warning(f'GCi = {GCi}') #self.log.warning(f'GCj = {GCj}') diff --git a/pyNastran/bdf/bdf_interface/stats.py b/pyNastran/bdf/bdf_interface/stats.py index 2d5b45bd0..c87298ee1 100644 --- a/pyNastran/bdf/bdf_interface/stats.py +++ b/pyNastran/bdf/bdf_interface/stats.py @@ -187,7 +187,7 @@ def get_bdf_stats(model: BDF, return_type: str='string', # ---- #new 'bolt', 'boltld', 'boltfor', 'boltseq', 'boltfrc', - 'use_new_deck_parser', + 'use_new_deck_parser', 'allow_overwrites_set', ] + list_attrs + card_dict_groups + scalar_attrs missed_attrs = [] diff --git a/pyNastran/bdf/mesh_utils/bdf_diff.py b/pyNastran/bdf/mesh_utils/bdf_diff.py index 889c08dfd..21236a642 100644 --- a/pyNastran/bdf/mesh_utils/bdf_diff.py +++ b/pyNastran/bdf/mesh_utils/bdf_diff.py @@ -1,6 +1,7 @@ import os from collections import defaultdict import numpy as np +from cpylog import SimpleLogger from pyNastran.utils import PathLike from pyNastran.bdf.bdf import read_bdf, BDF, CaseControlDeck, Subcase @@ -80,7 +81,7 @@ def get_diff_bdfs(bdf_filename1: PathLike, bdf_filename2: PathLike, added_bdf_filename: PathLike='', removed_bdf_filename: PathLike='', - ) -> tuple[bool, bool, BDF, BDF]: + log=None) -> tuple[bool, bool, BDF, BDF]: """ diffs two bdfs @@ -95,13 +96,11 @@ def get_diff_bdfs(bdf_filename1: PathLike, bdf_filename2: PathLike, if removed_bdf_filename == '': removed_bdf_filename = base2 + '.removed' + ext2 - old_model = read_bdf(bdf_filename1, xref=False) - new_model = read_bdf(bdf_filename2, xref=False) + old_model = read_bdf(bdf_filename1, xref=False, log=log) + new_model = read_bdf(bdf_filename2, xref=False, log=log) - from cpylog import SimpleLogger - log = SimpleLogger(level='debug') - removed_model = BDF() - added_model = BDF() + removed_model = BDF(log=log) + added_model = BDF(log=log) # dict_int_list_obj_attrs: list[str] = [ # 'spcs', 'spcadds', diff --git a/pyNastran/bdf/mesh_utils/cmd_line/bdf_diff.py b/pyNastran/bdf/mesh_utils/cmd_line/bdf_diff.py index 10fe0674c..673f0cd0f 100644 --- a/pyNastran/bdf/mesh_utils/cmd_line/bdf_diff.py +++ b/pyNastran/bdf/mesh_utils/cmd_line/bdf_diff.py @@ -50,7 +50,7 @@ def cmd_line_diff(argv=None, quiet: bool=False) -> None: #bdf_filename_out = data['--output'] #debug = data['--debug'] #assert debug in {True, False}, debug - debug = False + debug = None if quiet else True # if bdf_filename_out is None: # bdf_filename_out = 'merged.bdf' @@ -59,5 +59,10 @@ def cmd_line_diff(argv=None, quiet: bool=False) -> None: #'AERO', 'AEROS', 'PAERO1', 'PAERO2', 'MKAERO1'] #cards_to_skip = [] + from cpylog import SimpleLogger from pyNastran.bdf.mesh_utils.bdf_diff import get_diff_bdfs - added_cards, removed_cards, added_model, removed_model = get_diff_bdfs(bdf_filename1, bdf_filename2) + level = 'warning' if debug is None else 'debug' if debug else 'info' + log = SimpleLogger(level=level) + print(log) + added_cards, removed_cards, added_model, removed_model = get_diff_bdfs( + bdf_filename1, bdf_filename2, log=log) diff --git a/pyNastran/bdf/mesh_utils/test/test_mesh_utils.py b/pyNastran/bdf/mesh_utils/test/test_mesh_utils.py index e52b9db76..15a2c3b9e 100644 --- a/pyNastran/bdf/mesh_utils/test/test_mesh_utils.py +++ b/pyNastran/bdf/mesh_utils/test/test_mesh_utils.py @@ -208,8 +208,8 @@ def test_export_caero_mesh_caero1_wkk2(self): model.add_paero1(pid) model.add_aero(velocity=0., cref=1.0, rho_ref=1.0) name = 'WKK' - form = 'rectangular' - tin = tout = 1 + form = 'diagonal' + #tin = tout = 1 # nrows = 8 # ncols = 1 # GCj = [1, 1, 1, 1, 1, 1, 1, 1] @@ -233,13 +233,13 @@ def test_export_caero_mesh_caero5_wtfact(self): # main structure will be pid=1 # 'caero' : write the CAERO1 as the property id # 'paero' : write the PAERO1 as the property id - model = read_bdf(bdf_filename) + model = read_bdf(bdf_filename, debug=False) tin = tout = 'float32' nrows = 1 GCj = [101] GCi = [1] Real = [np.radians(5.)] - model.add_dmi_w2gj(tin, tin, nrows, GCj, GCi, Real) + model.add_dmi_w2gj(tin, tout, nrows, GCj, GCi, Real) #print(model.caeros) argv = ['bdf', 'export_caero_mesh', bdf_filename, '-o', path / 'ha145z.aesurf_subpanels.bdf', '--pid', 'aesurf', '--subpanels'] From 493e0cd17328ace2cec3b49c47edc7d543f3207b Mon Sep 17 00:00:00 2001 From: SteveDoyle2 Date: Mon, 13 Jan 2025 23:51:13 -0800 Subject: [PATCH 3/5] adding duplicate check --- pyNastran/dev/bdf_vectorized3/cards/base_card.py | 12 +++++++++++- .../bdf_vectorized3/cards/test/test_vector_coords.py | 9 +++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/pyNastran/dev/bdf_vectorized3/cards/base_card.py b/pyNastran/dev/bdf_vectorized3/cards/base_card.py index e753ec1b8..2ba8bd383 100644 --- a/pyNastran/dev/bdf_vectorized3/cards/base_card.py +++ b/pyNastran/dev/bdf_vectorized3/cards/base_card.py @@ -1022,7 +1022,17 @@ def sort_duplicates(card: VectorizedBaseCard) -> None: #assert (iarg - uarg).sum() == 0, (iarg - uarg).sum() is_duplicate_ids = (len(ids_sorted) != len(uids_sorted)) - if is_duplicate_ids: + model = card.model + if is_duplicate_ids and card.type in model.allow_overwrites_set: + #print(f'ids_sorted = {ids_sorted}') + #print(f'uids_sorted = {uids_sorted}') + idx = np.searchsorted(ids_sorted, uids_sorted, side='right') - 1 + assert np.array_equal(ids_sorted[idx], uids_sorted) + #print(f'idx = {idx}') + card.__apply_slice__(card, idx) + # card._is_sorted = True + # return + elif is_duplicate_ids: # Now that we've sorted the ids, we'll take the delta id with the next id. # We check the two neighoring values when there is a duplicate, # so if they're they same in xyz, cp, cd, etc., the results are the same diff --git a/pyNastran/dev/bdf_vectorized3/cards/test/test_vector_coords.py b/pyNastran/dev/bdf_vectorized3/cards/test/test_vector_coords.py index e3c186061..8ddebcf57 100644 --- a/pyNastran/dev/bdf_vectorized3/cards/test/test_vector_coords.py +++ b/pyNastran/dev/bdf_vectorized3/cards/test/test_vector_coords.py @@ -8,6 +8,15 @@ class TestCoords(unittest.TestCase): + def test_grid_repeated(self): + model = BDF(debug=False, log=None, mode='msc') + model.allow_overwrites_set = {'GRID'} + model._make_card_parser() + model.add_grid(1, [0., 0., 0.], comment='a') + model.add_grid(2, [1., 0., 0.], comment='') + model.add_grid(1, [2., 0., 0.], comment='a') + model.parse_cards() + def test_ricoord(self): model = BDF(debug=False, log=None, mode='msc') fields = ['CORD1R', '1', '1', '101', '2'] From 8b21309ce6993e75431635069d788c72a7f14b01 Mon Sep 17 00:00:00 2001 From: SteveDoyle2 Date: Tue, 14 Jan 2025 23:17:22 -0800 Subject: [PATCH 4/5] fixing tests --- pyNastran/bdf/bdf.py | 2 +- pyNastran/dev/bdf_vectorized3/bdf.py | 4 +++ pyNastran/dev/bdf_vectorized3/cards/aero.py | 37 ++++++++++++--------- 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/pyNastran/bdf/bdf.py b/pyNastran/bdf/bdf.py index f461bb9a6..2437ab096 100644 --- a/pyNastran/bdf/bdf.py +++ b/pyNastran/bdf/bdf.py @@ -622,7 +622,7 @@ def __init__(self, debug: str | bool | None=True, # False: use strict parser (default) self.is_strict_card_parser = True - # set of result types that overwrites work on + # set of card types that overwrites work on self.allow_overwrites_set: set[str] = set([]) # lines that were rejected b/c they were for a card that isn't supported diff --git a/pyNastran/dev/bdf_vectorized3/bdf.py b/pyNastran/dev/bdf_vectorized3/bdf.py index 04705e7c7..a5175a7b8 100644 --- a/pyNastran/dev/bdf_vectorized3/bdf.py +++ b/pyNastran/dev/bdf_vectorized3/bdf.py @@ -551,8 +551,12 @@ def __init__(self, debug: str | bool | None=True, self.read_includes = True self._remove_disabled_cards = False + # False: use strict parser (default) self.is_strict_card_parser = True + # set of card types that overwrites work on + self.allow_overwrites_set: set[str] = set([]) + # file management parameters self.active_filenames: list[str] = [] self.active_filename: Optional[str] = '' diff --git a/pyNastran/dev/bdf_vectorized3/cards/aero.py b/pyNastran/dev/bdf_vectorized3/cards/aero.py index 9edac3759..f223b9be1 100644 --- a/pyNastran/dev/bdf_vectorized3/cards/aero.py +++ b/pyNastran/dev/bdf_vectorized3/cards/aero.py @@ -569,7 +569,7 @@ def _save(self, element_id, property_id, igroup, p1, p4, x12, x43, cp, if ifile is None: ifile = np.zeros(ncards, dtype='int32') if len(self.element_id): - ifile = np.stack([self.ifile, ifile]) + ifile = np.hstack([self.ifile, ifile]) element_id = np.hstack([self.element_id, element_id]) property_id = np.hstack([self.property_id, property_id]) igroup = np.hstack([self.igroup, igroup]) @@ -1108,7 +1108,7 @@ def _save(self, element_id, property_id, igroup, p1, x12, if ifile is None: ifile = np.zeros(ncards, dtype='int32') if len(self.element_id): - ifile = np.stack([self.ifile, ifile]) + ifile = np.hstack([self.ifile, ifile]) element_id = np.hstack([self.element_id, element_id]) property_id = np.hstack([self.property_id, property_id]) igroup = np.hstack([self.igroup, igroup]) @@ -1781,7 +1781,7 @@ def add(self, eid: int, pid: int, a comment for the card """ - card = (eid, pid, p1, x12, p4, x43, cp, nspan, lspan, comment) + card = (eid, pid, p1, x12, p4, x43, cp, nspan, lspan, ifile, comment) self.cards.append(card) self.n += 1 return self.n - 1 @@ -1820,7 +1820,7 @@ def add_card(self, card: BDFCard, ifile: int, comment: str='') -> int: #return CAERO1(eid, pid, igroup, p1, x12, p4, x43, #cp=cp, nspan=nspan, lspan=lspan, nchord=nchord, lchord=lchord, #comment=comment) - card = (eid, pid, p1, x12, p4, x43, cp, nspan, lspan, comment) + card = (eid, pid, p1, x12, p4, x43, cp, nspan, lspan, ifile, comment) self.cards.append(card) self.n += 1 return self.n - 1 @@ -1865,7 +1865,7 @@ def _save(self, element_id, property_id, p1, p4, x12, x43, cp, if ifile is None: ifile = np.zeros(ncards, dtype='int32') if len(self.element_id): - ifile = np.stack([self.ifile, ifile]) + ifile = np.hstack([self.ifile, ifile]) element_id = np.hstack([self.element_id, element_id]) property_id = np.hstack([self.property_id, property_id]) p1 = np.vstack([self.p1, p1]) @@ -2185,7 +2185,7 @@ def add(self, eid: int, pid: int, ifile: int=0, comment: str='') -> int: """Creates a CAERO5 card""" card = (eid, pid, p1, x12, p4, x43, cp, nspan, lspan, - ntheory, nthick, comment) + ntheory, nthick, ifile, comment) self.cards.append(card) self.n += 1 return self.n - 1 @@ -2223,7 +2223,7 @@ def add_card(self, card: BDFCard, ifile: int, comment: str='') -> int: x43 = double_or_blank(card, 16, 'x43', 0.) assert len(card) <= 17, f'len(CAERO5 card) = {len(card):d}\ncard={card}' - card = (eid, pid, p1, x12, p4, x43, cp, nspan, lspan, ntheory, nthick, comment) + card = (eid, pid, p1, x12, p4, x43, cp, nspan, lspan, ntheory, nthick, ifile, comment) self.cards.append(card) self.n += 1 return self.n - 1 @@ -3168,6 +3168,7 @@ def parse_cards(self) -> None: orientation = np.zeros(ncards, dtype='|U4') thi = np.zeros((ncards, 3), dtype='int32') thn = np.zeros((ncards, 3), dtype='int32') + comment = {} for icard, card in enumerate(self.cards): (pid, orienti, widthi, AR, thii, thni, @@ -3397,7 +3398,7 @@ def parse_cards(self) -> None: ncontrol_surface = np.zeros(ncards, dtype='int32') x = np.full((ncards, 8), np.nan, dtype='float64') y = np.full((ncards, 8), np.nan, dtype='float64') - commet = {} + comment = {} for icard, card in enumerate(self.cards): (pid, nboxi, ncontrol_surfacei, xi, yi, ifilei, commenti) = card property_id[icard] = pid @@ -4029,7 +4030,7 @@ def _save(self, aelist_id, nelements, elements, if ifile is None: ifile = np.zeros(ncards, dtype='int32') if len(self.aelist_id): - ifile = np.stack([self.ifile, ifile]) + ifile = np.hstack([self.ifile, ifile]) aelist_id = np.hstack([self.aelist_id, aelist_id]) elements = np.hstack([self.elements, elements]) nelements = np.hstack([self.nelements, nelements]) @@ -4375,7 +4376,7 @@ def _save(self, aefact_id, nfractions, fractions, if ifile is None: ifile = np.zeros(ncards, dtype='int32') if len(self.aefact_id): - ifile = np.stack([self.ifile, ifile]) + ifile = np.hstack([self.ifile, ifile]) aefact_id = np.hstack([self.aefact_id, aefact_id]) nfractions = np.hstack([self.nfractions, nfractions]) fractions = np.hstack([self.fractions, fractions]) @@ -4548,7 +4549,7 @@ def _save(self, flfact_id, nfactors, factors, if ifile is None: ifile = np.zeros(ncards, dtype='int32') if len(self.flfact_id): - ifile = np.stack([self.ifile, ifile]) + ifile = np.hstack([self.ifile, ifile]) flfact_id = np.hstack([self.flfact_id, flfact_id]) factors = np.hstack([self.factors, factors]) nfactors = np.hstack([self.nfactors, nfactors]) @@ -5818,6 +5819,7 @@ def parse_cards(self) -> None: method = np.zeros(ncards, dtype='|U4') ftype = np.zeros(ncards, dtype='|U4') rcore = np.zeros(ncards, dtype='float64') + comment = {} for icard, card in enumerate(self.cards): (eid, caero, aelist, setg, thxi, thyi, dzi, dtori, cidi, usagei, methodi, ftypei, rcorei, ifilei, commenti) = card @@ -6532,7 +6534,7 @@ def add(self, aeparm_id: int, label: str, units: str, a comment for the card """ - self.cards.append((aeparm_id, label, units, comment)) + self.cards.append((aeparm_id, label, units, ifile, comment)) self.n += 1 return self.n - 1 @@ -6555,7 +6557,7 @@ def add_card(self, card: BDFCard, ifile: int, comment: str='') -> int: assert len(card) <= 4, f'len(AEPARM card) = {len(card):d}\ncard={card}' #return AEPARM(aeparm_id, label, units, comment=comment) - self.cards.append((aeparm_id, label, units, comment)) + self.cards.append((aeparm_id, label, units, ifile, comment)) self.n += 1 return self.n - 1 @@ -6700,7 +6702,7 @@ def add(self, aesurf_id: int, label: str, aelist_id2 = 0 card = (aesurf_id, label, cid1, aelist_id1, cid2, aelist_id2, eff, ldw, crefc, crefs, pllim, pulim, hmllim, hmulim, - tqllim, tqulim, comment) + tqllim, tqulim, ifile, comment) self.cards.append(card) self.n += 1 return self.n - 1 @@ -7016,6 +7018,7 @@ def parse_cards(self) -> None: label = np.zeros(ncards, dtype='|U8') list1_id = np.zeros(ncards, dtype='int32') list2_id = np.zeros(ncards, dtype='int32') + comment = {} for icard, card in enumerate(self.cards): (aesurfs_idi, labeli, list1i, list2i, ifilei, commenti) = card @@ -7182,6 +7185,7 @@ def parse_cards(self) -> None: lalpha = np.zeros(ncards, dtype='int32') lmach = np.zeros(ncards, dtype='int32') lschd = np.zeros(ncards, dtype='int32') + comment = {} for icard, card in enumerate(self.cards): (sid, aesurf_idi, lalphai, lmachi, lschdi, ifilei, commenti) = card @@ -7200,11 +7204,11 @@ def parse_cards(self) -> None: def _save(self, csschd_id, aesurf_id, lalpha, lmach, lschd, ifile=None, comment=None): - ncards = len(csschd) + ncards = len(csschd_id) if ifile is None: ifile = np.zeros(ncards, dtype='int32') if len(self.csschd_id): - ifile = np.stack([self.ifile, ifile]) + ifile = np.hstack([self.ifile, ifile]) csschd_id = np.hstack([self.csschd_id, csschd_id]) aesurf_id = np.hstack([self.aesurf_id, aesurf_id]) lalpha = np.hstack([self.lalpha, lalpha]) @@ -7383,6 +7387,7 @@ def parse_cards(self) -> None: diverg_id = np.zeros(ncards, dtype='int32') nroots = np.zeros(ncards, dtype='int32') nmach = np.zeros(ncards, dtype='int32') + comment = {} machs_list = [] for icard, card in enumerate(self.cards): From 24c04b41f5d6048eec479088de9e3d49899e8814 Mon Sep 17 00:00:00 2001 From: Shaoqi <41614543+Shaoqigit@users.noreply.github.com> Date: Wed, 15 Jan 2025 15:33:29 +0800 Subject: [PATCH 5/5] Support cweld and pweld card for MSC Nastran (#815) * support cweld and pweld * check test done * review comment correction * remove debug print * change argument name and gs check correction * correction gs to gs_ref --- pyNastran/bdf/__init__.py | 6 +- pyNastran/bdf/bdf.py | 21 ++- pyNastran/bdf/bdf_interface/add_card.py | 24 ++- pyNastran/bdf/bdf_interface/add_methods.py | 2 +- pyNastran/bdf/bdf_interface/attributes.py | 4 +- pyNastran/bdf/bdf_interface/card_groups.py | 5 +- pyNastran/bdf/cards/elements/elements.py | 172 +++++++++++++++++++ pyNastran/bdf/cards/properties/properties.py | 139 ++++++++++++++- 8 files changed, 351 insertions(+), 22 deletions(-) diff --git a/pyNastran/bdf/__init__.py b/pyNastran/bdf/__init__.py index 43e624155..41f217c93 100644 --- a/pyNastran/bdf/__init__.py +++ b/pyNastran/bdf/__init__.py @@ -53,7 +53,7 @@ 'CBUSH', 'CBUSH1D', 'CBUSH2D', # dampers 'CDAMP1', 'CDAMP2', 'CDAMP3', 'CDAMP4', 'CDAMP5', - 'CFAST', + 'CFAST', 'CWELD', 'CBAR', 'CBARAO', 'BAROR', 'CROD', 'CTUBE', 'CBEAM', 'CBEAM3', 'CONROD', 'CBEND', 'BEAMOR', @@ -78,7 +78,7 @@ ## properties 'PMASS', - 'PELAS', 'PGAP', 'PFAST', 'PLPLANE', 'PPLANE', + 'PELAS', 'PGAP', 'PFAST', 'PWELD', 'PLPLANE', 'PPLANE', 'PBUSH', 'PBUSH1D', 'PDAMP', 'PDAMP5', 'PROD', 'PBAR', 'PBARL', 'PBEAM', 'PTUBE', 'PBCOMP', 'PBRSECT', 'PBEND', @@ -312,7 +312,7 @@ ## ??? 'ACMODL', 'PANEL', 'SWLDPRM', - 'CWELD', 'PWELD', 'PWSEAM', 'CWSEAM', 'CSEAM', 'PSEAM', 'DVSHAP', 'BNDGRID', + 'PWSEAM', 'CWSEAM', 'CSEAM', 'PSEAM', 'DVSHAP', 'BNDGRID', 'MODTRAK', 'DSCONS', 'DVAR', 'DVSET', 'DYNRED', 'BNDFIX', 'BNDFIX1', 'AEFORCE', 'UXVEC', 'GUST2', diff --git a/pyNastran/bdf/bdf.py b/pyNastran/bdf/bdf.py index 2437ab096..86903ee95 100644 --- a/pyNastran/bdf/bdf.py +++ b/pyNastran/bdf/bdf.py @@ -54,9 +54,9 @@ from pyNastran.bdf.bdf_interface.model_group import ModelGroup from .cards.elements.elements import ( - CFAST, CGAP, CRAC2D, CRAC3D, GENEL, + CFAST, CWELD, CGAP, CRAC2D, CRAC3D, GENEL, PLOTEL, PLOTEL3, PLOTEL4, PLOTELs) -from .cards.properties.properties import PFAST, PGAP, PRAC2D, PRAC3D +from .cards.properties.properties import PFAST, PWELD, PGAP, PRAC2D, PRAC3D from .cards.properties.solid import PLSOLID, PSOLID, PIHEX, PCOMPS, PCOMPLS from .cards.cyclic import CYAX, CYJOIN from .cards.msgmesh import CGEN @@ -218,7 +218,7 @@ Element = ( SpringElement | DamperElement | - CVISC | CBUSH | CBUSH1D | CBUSH2D | CFAST | #CWELD + CVISC | CBUSH | CBUSH1D | CBUSH2D | CFAST | CWELD | CGAP | GENEL | CCONEAX | CROD | CTUBE | CONROD | CBAR | CBEAM | CBEAM3 | CBEND | CSHEAR | @@ -246,7 +246,7 @@ PSHEAR | PPLANE | PSHELL | PCOMP | PCOMPG | PSOLID | PLSOLID | PIHEX | PCOMPS | PCOMPLS | - PTRSHL #| PWELD + PTRSHL | PWELD ) Material = ( MAT1 | MAT2 | MAT3 | MAT8 | MAT9 | MAT10 | MAT11 | @@ -403,7 +403,6 @@ 'CSPOT', 'CFILLET', 'CBUTT', 'PCOHE', - 'CWELD', 'PWELD', ## rigid_elements 'RSPINT', 'RSPINR', 'RBE2GS', @@ -668,7 +667,8 @@ def __init__(self, debug: str | bool | None=True, 'CBUSH', 'CBUSH1D', 'CBUSH2D', # dampers 'CDAMP1', 'CDAMP2', 'CDAMP3', 'CDAMP4', 'CDAMP5', - 'CFAST', + # fasteners + 'CFAST', 'CWELD', 'CBAR', 'CBARAO', 'BAROR', 'CROD', 'CTUBE', 'CBEAM', 'CBEAM3', 'CONROD', 'CBEND', 'BEAMOR', @@ -699,7 +699,7 @@ def __init__(self, debug: str | bool | None=True, ## properties 'PMASS', - 'PELAS', 'PGAP', 'PFAST', 'PLPLANE', 'PPLANE', + 'PELAS', 'PGAP', 'PFAST', 'PWELD', 'PLPLANE', 'PPLANE', 'PBUSH', 'PBUSH1D', 'PBUSH2D', 'PDAMP', 'PDAMP5', 'PROD', 'PBAR', 'PBARL', 'PBEAM', 'PTUBE', 'PBCOMP', 'PBRSECT', 'PBEND', @@ -951,7 +951,6 @@ def __init__(self, debug: str | bool | None=True, 'CONVM', ## ??? #'PANEL', 'SWLDPRM', - #'CWELD', 'PWELD', # 'PWSEAM', 'CWSEAM', 'CSEAM', 'PSEAM', 'DVSHAP', #'CYSYM', 'CYJOIN', 'MODTRAK', 'DSCONS', 'DVAR', 'DVSET', 'DYNRED', #'AEFORCE', 'UXVEC', 'GUST2', @@ -2217,9 +2216,6 @@ def add_card(cls, card: BDFCard, comment: str=''): 'ROTORB' : (Crash, None), #'SWLDPRM' : (Crash, None), - - #'CWELD' : (Crash, None), - #'PWELD' : (Crash, None), #'PWSEAM' : (Crash, None), #'CWSEAM' : (Crash, None), #'CSEAM' : (Crash, None), @@ -2366,6 +2362,9 @@ def add_card(cls, card: BDFCard, comment: str=''): 'CFAST' : (CFAST, add_methods._add_damper_object), 'PFAST' : (PFAST, add_methods._add_property_object), + 'CWELD' : (CWELD, add_methods._add_damper_object), + 'PWELD' : (PWELD, add_methods._add_property_object), + 'CGAP' : (CGAP, add_methods._add_element_object), 'PGAP' : (PGAP, add_methods._add_property_object), diff --git a/pyNastran/bdf/bdf_interface/add_card.py b/pyNastran/bdf/bdf_interface/add_card.py index 2fef6b832..46bdb0cde 100644 --- a/pyNastran/bdf/bdf_interface/add_card.py +++ b/pyNastran/bdf/bdf_interface/add_card.py @@ -17,8 +17,8 @@ from pyNastran.bdf.cards.bolt import BOLT, BOLTSEQ, BOLTFOR, BOLTLD, BOLTFRC from pyNastran.bdf.cards.elements.elements import ( - CFAST, CGAP, CRAC2D, CRAC3D, PLOTEL, PLOTEL3, PLOTEL4, GENEL) -from pyNastran.bdf.cards.properties.properties import PFAST, PGAP, PRAC2D, PRAC3D + CFAST, CWELD, CGAP, CRAC2D, CRAC3D, PLOTEL, PLOTEL3, PLOTEL4, GENEL) +from pyNastran.bdf.cards.properties.properties import PFAST, PWELD, PGAP, PRAC2D, PRAC3D from pyNastran.bdf.cards.properties.solid import PLSOLID, PSOLID, PIHEX, PCOMPS, PCOMPLS from pyNastran.bdf.cards.cyclic import CYAX, CYJOIN #from pyNastran.bdf.cards.msgmesh import CGEN, GMCORD, GMLOAD @@ -375,6 +375,9 @@ 'CFAST' : CFAST, 'PFAST' : PFAST, + 'CWELD' : CWELD, + 'PWELD' : PWELD, + 'CGAP' : CGAP, 'PGAP' : PGAP, @@ -1566,6 +1569,23 @@ def add_pfast(self, pid: int, d: int, self._add_methods._add_property_object(prop) return prop + def add_cweld(self, eid: int, pid: int, gs: int, elemid:str, ga:int, gb:int, mcid:int, shida: int, shidb: int, x: list[float]=None, comment: str='') -> CWELD: + """ + Creates a CWELD card + + """ + elem = CWELD(eid, pid, gs, elemid, ga, gb, mcid, shida, shidb, x, comment=comment) + self._add_methods._add_element_object(elem) + return elem + + def add_pweld(self, pid: int, mid: int, d: float, mset: str=None, connect_type:str=None, ldmin: float=None, ldmax: float=None, comment: str='') -> PWELD: + """ + Creates a PWELD card + + """ + prop = PWELD(pid, mid, mid, d, mset, connect_type, ldmin, ldmax, comment=comment) + self._add_methods._add_property_object(prop) + return prop class Add1dElements: def add_conrod(self, eid: int, mid: int, nids: list[int], diff --git a/pyNastran/bdf/bdf_interface/add_methods.py b/pyNastran/bdf/bdf_interface/add_methods.py index 7c8333c6a..e19fea964 100644 --- a/pyNastran/bdf/bdf_interface/add_methods.py +++ b/pyNastran/bdf/bdf_interface/add_methods.py @@ -11,7 +11,7 @@ CAEROs, PAEROs, SPLINEs, FREQs, ) from pyNastran.bdf.cards.bolt import BOLT, BOLTFOR, BOLTSEQ, BOLTLD - from pyNastran.bdf.cards.elements.elements import CFAST, CGAP, CRAC2D, CRAC3D, PLOTELs, GENEL + from pyNastran.bdf.cards.elements.elements import CFAST, CWELD, CGAP, CRAC2D, CRAC3D, PLOTELs, GENEL #from pyNastran.bdf.cards.properties.properties import PFAST, PGAP, PRAC2D, PRAC3D #from pyNastran.bdf.cards.properties.solid import PLSOLID, PSOLID, PIHEX, PCOMPS, PCOMPLS #from pyNastran.bdf.cards.msgmesh import CGEN, GMCORD diff --git a/pyNastran/bdf/bdf_interface/attributes.py b/pyNastran/bdf/bdf_interface/attributes.py index 452345dbb..a4207f0d1 100644 --- a/pyNastran/bdf/bdf_interface/attributes.py +++ b/pyNastran/bdf/bdf_interface/attributes.py @@ -850,7 +850,7 @@ def __init_attributes(self) -> None: 'CBUSH', 'CBUSH1D', 'CBUSH2D', 'CDAMP1', 'CDAMP2', 'CDAMP3', 'CDAMP4', 'CDAMP5', - 'CFAST', 'GENEL', + 'CFAST', 'CWELD','GENEL', 'CBAR', 'CROD', 'CTUBE', 'CBEAM', 'CBEAM3', 'CONROD', 'CBEND', 'CTRIA3', 'CTRIA6', 'CTRIAR', @@ -884,7 +884,7 @@ def __init_attributes(self) -> None: 'PACABS', 'PAABSF', 'PACBAR', 'PMIC', # 0d - 'PELAS', 'PGAP', 'PFAST', + 'PELAS', 'PGAP', 'PFAST', 'PWELD', 'PBUSH', 'PBUSH1D', 'PBUSH2D', 'PDAMP', 'PDAMP5', diff --git a/pyNastran/bdf/bdf_interface/card_groups.py b/pyNastran/bdf/bdf_interface/card_groups.py index c23f27228..25ab9f1f7 100644 --- a/pyNastran/bdf/bdf_interface/card_groups.py +++ b/pyNastran/bdf/bdf_interface/card_groups.py @@ -78,7 +78,8 @@ 'CBUSH', 'CBUSH1D', 'CBUSH2D', # dampers 'CDAMP1', 'CDAMP2', 'CDAMP3', 'CDAMP4', 'CDAMP5', - 'CFAST', + # fasteners + 'CFAST', 'CWELD', 'CBAR', 'CBARAO', 'BAROR', 'CROD', 'CTUBE', 'CBEAM', 'CBEAM3', 'CONROD', 'CBEND', 'BEAMOR', @@ -94,7 +95,7 @@ ## properties 'PMASS', - 'PELAS', 'PGAP', 'PFAST', 'PLPLANE', 'PPLANE', + 'PELAS', 'PGAP', 'PFAST', 'PWELD', 'PLPLANE', 'PPLANE', 'PBUSH', 'PBUSH1D', 'PDAMP', 'PDAMP5', 'PROD', 'PBAR', 'PBARL', 'PBEAM', 'PTUBE', 'PBCOMP', 'PBRSECT', 'PBEND', diff --git a/pyNastran/bdf/cards/elements/elements.py b/pyNastran/bdf/cards/elements/elements.py index db4792725..54467a444 100644 --- a/pyNastran/bdf/cards/elements/elements.py +++ b/pyNastran/bdf/cards/elements/elements.py @@ -237,6 +237,178 @@ def write_card(self, size: int=8, is_double: bool=False) -> str: return self.comment + print_card_8(card) +class CWELD(CFAST): + """ + There are five different formats of the CWELD card as GRIDid, ELEMID, ELPAT and PARTPAT. + ELEMID format: + +-------+-----+-----+-----+--------+-----+-----+-----+-----+ + | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | + +=======+=====+=====+=====+========+=====+=====+=====+=====+ + | CWELD | EWID| PWID| GS |"ELEMID"| GA | GB | | MCID| + +-------+-----+-----+-----+--------+-----+-----+-----+-----+ + | |SHIDA|SHIDB| | | | | | | + +-------+-----+-----+-----+--------+-----+-----+-----+-----+ + or PARTPAT format: + +-------+-----+-----+-----+---------+-----+-----+-----+-----+ + | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | + +=======+=====+=====+=====+========+=====+=====+======+=====+ + | CWELD | EWID| PWID| GS |"PARTPAT"| GA | GB | |MCID | + +-------+-----+-----+-----+---------+-----+----+------+-----+ + | | PIDA|PIDB | | | | | | | + +-------+-----+-----+-----+---------+-----+----+------+-----+ + | | XS | YS | ZS | | | | | | + +-------+-----+-----+-----+---------+-----+----+------+-----+ + or ELPAT: + +-------+-----+-----+-----+--------+-----+-----+-----+-----+ + | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | + +=======+=====+=====+=====+========+=====+======+=====+=====+ + | CWELD | EWID| PWID| GS |"ELPAT" | GA | GB | | MCID| + +-------+-----+-----+-----+--------+-----+-----+-----+-----+ + | |SHIDA|SHIDB| | | | | | | + +-------+-----+-----+-----+--------+-----+-----+-----+-----+ + | | XS | YS| ZS | | | | | | + +-------+-----+-----+-----+--------+-----+-----+-----+-----+ + "ELEMID" string indicating that the connectivity of surface patch A to surface patch B is defined with two shell element identification numbers, SHIDA and SHIDB, respectively. + """ + type = 'CWELD' + _properties = ['node_ids', 'nodes'] + _field_map = { + 1: 'eid', 2:'pid', 3:'gs', 4:'connectype', 5:'ga', 6:'gb', 8:'mcid', + } + cp_name_map = { + } + + @classmethod + def _init_from_empty(cls): + eid = 1 + pid = 1 + connectype = 'ELEMID' + return CWELD(eid, pid, gs=None, connectype=connectype, ga=None, gb=None, mcid=None, shida=None, shidb=None, comment='') + + def __init__(self, eid: int, pid: int, gs: Optional[int], connectype: str, ga: int, gb: int, mcid=None, shida:Optional[int]=None, shidb:Optional[int]=None, pida:Optional[int]=None, pidb:Optional[int]=None, x:Optional[list[float]]=None, comment:str=''): + Element.__init__(self) + if comment: + self.comment = comment + if pid is None: + pid = eid + self.eid = eid + self.pid = pid + self.gs = gs + self.connectype = connectype + self.ga = ga + self.gb = gb + self.mcid = mcid + self.pida = pida + self.pidb = pidb + self.x = x + self.shida = shida + self.shidb = shidb + self.pid_ref = None + self.gs_ref = None + self.ga_ref = None + self.gb_ref = None + + def validate(self): + if self.connectype in ['GRIDID', 'ALIGN']: + msg = f'Format "GRIDID" or "ALIGN" of CWELD of element eid={self.eid} is not supported' + raise TypeError(msg) + + if self.gs is None and self.ga is None: + msg = f'The definition of CWELD; eid={self.eid} is not correct, either GS or GA must be defined' + raise ValueError(msg) + + @classmethod + def add_card(cls, card, comment=''): + """ + Adds a CWELD card from ``BDF.add_card(...)`` + + Parameters + ---------- + card : BDFCard() + a BDFCard object + comment : str; default='' + a comment for the card + + """ + eid = integer(card, 1, 'eid') + pid = integer_or_blank(card, 2, 'pid', eid) + gs = integer_or_blank(card, 3, 'gs') + connectype = string(card, 4, 'connectype') + + ga = integer(card, 5, 'ga') + gb = integer(card, 6, 'gb') + mcid = integer_or_blank(card, 8,'mcid') + shida_pida = integer_or_blank(card, 9,'shida_pida') + shidb_pidb = integer_or_blank(card, 10,'shidb_pidb') + if connectype == 'ELEMID': + x = [None, None, None] + assert len(card)<=11, f'len(CWELD card) = {len(card):d}\ncard={card}' + elif connectype == 'ELPAT': + x = [double_or_blank(card, 18, 'xs', 0.0), + double_or_blank(card, 19, 'ys', 0.0), + double_or_blank(card, 20, 'zs', 0.0)] + assert len(card)<=21, f'len(CWELD card) = {len(card):d}\ncard={card}' + elif connectype == 'PARTPAT': + x = [double_or_blank(card, 18, 'xs', 0.0), + double_or_blank(card, 19, 'ys', 0.0), + double_or_blank(card, 20, 'zs', 0.0)] + assert len(card)<=21, f'len(CWELD card) = {len(card):d}\ncard={card}' + else: + raise NameError(f'connectype={connectype!r} is not supported') + return CWELD(eid, pid, gs, connectype, ga, gb, mcid=mcid, shida=shida_pida, shidb=shidb_pidb, x=x, comment=comment) + + def cross_reference(self, model: BDF) -> None: + """ + Cross links the card so referenced cards can be extracted directly" + + Parameters + ---------- + model : BDF() + the BDF object + """ + msg = ', which is required by CWELD eid=%s' % self.eid + self.pid_ref = model.Property(self.Pid(), msg=msg) + if self.gs: + self.gs_ref = model.Node(self.Gs(), msg=msg) + if self.ga: + self.ga_ref = model.Node(self.Ga(), msg=msg) + if self.gb: + self.gb_ref = model.Node(self.Gb(), msg=msg) + + def raw_fields(self): + if self.connectype == 'ELEMID': + list_fields = ['CWELD', self.eid, self.Pid(), self.gs, self.connectype, self.Ga(), self.Gb(), self.mcid, self.shida, self.shidb] + elif self.connectype == 'ELPAT': + xs, ys, zs = self.x + list_fields = ['CWELD', self.eid, self.Pid(), self.gs, self.connectype, self.Ga(), self.Gb(), self.mcid, self.shida, self.shidb, xs, ys, zs] + elif self.connectype == 'PARTPAT': + xs, ys, zs = self.x + list_fields = ['CWELD', self.eid, self.Pid(), self.gs, self.connectype, self.Ga(), self.Gb(), self.mcid, self.pida, self.pidb, xs, ys, zs] + else: + raise NameError(f'connectype={self.connectype!r} is not supported') + return list_fields + + def Gs(self): + """Gets the GS node""" + if self.gs_ref is not None: + return self.gs_ref.nid + elif isinstance(self.gs, integer_types): + return self.gs + else: + if self.ga is None: + # If neither GS nor GA is specified, then (XS, YS, ZS) in basic must be specified. + raise RuntimeError(f'Neither Gs nor GA was not returned from CWELD\n{self.get_stats()}') + else: + return self.ga_ref.nid + + def _get_gs(self) -> Optional[int]: + if self.gs is None: + out = (self.gs) + else: + out = (self.Gs()) + return out + + class CGAP(Element): """ +------+-----+-----+-----+-----+-----+-----+------+-----+ diff --git a/pyNastran/bdf/cards/properties/properties.py b/pyNastran/bdf/cards/properties/properties.py index dcee9b0b5..14bb0eebc 100644 --- a/pyNastran/bdf/cards/properties/properties.py +++ b/pyNastran/bdf/cards/properties/properties.py @@ -15,7 +15,7 @@ from pyNastran.bdf.field_writer_8 import set_blank_if_default from pyNastran.bdf.cards.base_card import Property from pyNastran.bdf.bdf_interface.assign_type import ( - integer, integer_or_blank, double, double_or_blank) + integer, integer_or_blank, double, double_or_blank, string_or_blank) from pyNastran.bdf.field_writer_8 import print_card_8 from pyNastran.bdf.field_writer_16 import print_card_16 if TYPE_CHECKING: # pragma: no cover @@ -245,6 +245,143 @@ def write_card(self, size: int=8, is_double: bool=False) -> str: return self.comment + print_card_16(card) +class PWELD(Property): + """ + +------+-----+-----+-----+-----+-----+-----+------+-----+ + | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | + +======+=====+=====+=====+====+======+=====+======+=====+ + |PWELD | PID | MID | D | | | MSET| | TYPE| + +------+-----+-----+-----+-----+-----+-----+------+-----+ + | |LDMIN|LDMAX| | | | | | | + +------+-----+-----+-----+-----+-----+-----+------+-----+ + |PWELD | 100 | 3 | 1.0 | | | | | | + +------+-----+-----+-----+-----+-----+-----+------+-----+ + """ + type = 'PWELD' + _field_map = { + 1: 'pid', 2:'mid', 3:'d', 6:'mset', 8:'connect_type', 9:'ldmin', 10:'ldmax', + } + pname_fid_map = { + 'MID' :'mid', + 'D' : 'd', + 'LDMIN' : 'ldmin', + 'LDMAX' : 'ldmax', + } + @classmethod + def _init_from_empty(cls): + pid = 1 + mid = 2 + d = 0.1 + return PWELD(pid, mid, d, mset=None, connect_type=None, ldmin=None, ldmax=None, comment='') + + def __init__(self, pid: int, mid: int, d: float, mset:str=None, connect_type: str=None, ldmin:float=None, ldmax:float=None, comment: str='') -> PWELD: + """ + Creates a PWELD card + Parameters + ---------- + pid : int + property id + mid : int + material id + d : float + diameter of the weld + mset : str; default='OFF' + flag to eliminate m-set degrees-of-freedom (DOFs) + ldmin : float; default=None + smallest ratio of length to diameter for stiffness calculation + ldmax : float; default=None + largest ratio of length to diameter for stiffness calculation + comment : str; default='' + a comment for the card + """ + Property.__init__(self) + if comment: + self.comment = comment + #: Property ID + self.pid = pid + #: Material ID + self.mid = mid + self.mid_ref = None + #: Diameter of the weld + self.d = d + #: M-set flag + self.mset = mset + #: Type of weld + self.connect_type = connect_type + #: Minimum length of the weld + self.ldmin = ldmin + #: Maximum length of the weld + self.ldmax = ldmax + + @classmethod + def add_card(cls, card, comment=''): + """ + Adds a PWELD card from ``BDF.add_card(...)`` + Parameters + ---------- + card : BDFCard() + a BDFCard object + comment : str; default='' + a comment for the card + """ + pid = integer(card, 1, 'pid') + mid = integer(card, 2,'mid') + d = double(card, 3, 'd') + mset = string_or_blank(card, 6,'mset', 'OFF') + connect_type = string_or_blank(card, 8, 'connect_type') + ldmin = double_or_blank(card, 9, 'ldmin') + ldmax = double_or_blank(card, 10, 'ldmax') + assert len(card) <= 11, f'len(PWELD card) = {len(card):d}\ncard={card}' + return PWELD(pid, mid, d, mset=mset, connect_type=connect_type, ldmin=ldmin, ldmax=ldmax, comment=comment) + + @classmethod + def add_op2_data(cls, data, comment=''): + """ + Adds a PWELD card from the OP2 + Parameters + ---------- + data : list[varies] + a list of fields defined in OP2 format + comment : str; default='' + a comment for the card + """ + (pid, mid, d, mset, connect_type, ldmin, ldmax) = data + return PWELD(pid, mid, d, mset=mset, connect_type=connect_type, ldmin=ldmin, ldmax=ldmax, comment=comment) + + def cross_reference(self, model: BDF) -> None: + """ + Cross links the card so referenced cards can be extracted directly + + Parameters + ---------- + model : BDF() + the BDF object + + """ + msg = ', which is required by PWELD pid=%s' % self.pid + self.mid_ref = model.Material(self.mid, msg=msg) + + def uncross_reference(self) -> None: + """Removes cross-reference links""" + self.mid = self.Mid() + self.mid_ref = None + + def raw_fields(self): + fields = ['PWELD', self.pid, self.Mid(), self.d, + self.mset, self.connect_type, self.ldmin, self.ldmax] + return fields + + def repr_fields(self): + mset = set_blank_if_default(self.mset, 'OFF') + fields = ['PWELD', self.pid, self.Mid(), self.d, mset, self.connect_type, self.ldmin, self.ldmax] + return fields + + def write_card(self, size: int=8, is_double: bool=False) -> str: + card = self.repr_fields() + if size == 8: + return self.comment + print_card_8(card) + return self.comment + print_card_16(card) + class PGAP(Property): """ +------+------+-------+-------+------+------+------+------+------+