Skip to content

Commit

Permalink
bdf_vectorized3:
Browse files Browse the repository at this point in the history
 - adding LSEQ, DLOAD, GENEL
 - fixing weird duplicate node id bug
 - BAROR needs the model object, which breaks deepcopy :/
 - better support for buggy models
 - op2 support in gui
  • Loading branch information
SteveDoyle2 committed Oct 25, 2023
1 parent 7b03f44 commit e18c227
Show file tree
Hide file tree
Showing 22 changed files with 1,352 additions and 334 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ jobs:
if: ${{ (matrix.mode == 'latest_pyside2_gui' || matrix.mode == 'latest_pyside6_gui' ||
matrix.mode == 'latest_pyqt5_gui' || matrix.mode == 'latest_pyqt6_gui') }}
run: |
pip install imageio pillow>5.2,!=7.1.0
pip install imageio pillow>5.2,!=7.1.0,<10.1.0
- name: Install latest packages (vtk)
#if: ${{ matrix.python-version != '3.12' && (
Expand Down
9 changes: 9 additions & 0 deletions pyNastran/bdf/bdf_interface/assign_type_force.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from .bdf_card import BDFCard
from pyNastran.utils.numpy_utils import (
integer_types, float_types)
from .assign_type import integer_double_or_blank

def force_integer(card: BDFCard, ifield: int, fieldname: str) -> int:
"""see ``integer``"""
Expand Down Expand Up @@ -163,3 +164,11 @@ def force_double_or_blank(card: BDFCard, ifield: int, fieldname: str, default: O
'card=%s' % (fieldname, svalue, ifield, dtype, card))
return default

def lax_double_or_blank(card: BDFCard, ifield: int, fieldname: str,
default: Optional[float]=None,
end: str='') -> float:
value = integer_double_or_blank(card, ifield, fieldname, default=default)
if isinstance(value, int):
value = float(value)
return value

1 change: 0 additions & 1 deletion pyNastran/bdf/cards/base_card.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ def add_card(self, card, comment=''): # pragma: no cover
return BaseCard()

def __deepcopy__(self, memo_dict):
#raw_fields = self.repr_fields()
raw_fields = self.raw_fields()
card = BDFCard(raw_fields)
return self.add_card(card, comment=self.comment)
Expand Down
37 changes: 25 additions & 12 deletions pyNastran/bdf/cards/dmig.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# pylint: disable=R0902,R0904,R0914
from __future__ import annotations
from copy import deepcopy
from math import sin, cos, radians, atan2, sqrt, degrees
from itertools import count
import warnings
from typing import Any, TYPE_CHECKING

import numpy as np
from numpy import array, zeros
from scipy.sparse import coo_matrix # type: ignore

from pyNastran.utils.numpy_utils import integer_types
Expand Down Expand Up @@ -320,7 +320,7 @@ def __repr__(self) -> str:
return self.write_card(size=16)
except Exception:
print('problem printing %s card' % self.type)
print("list_fields = ", list_fields)
#print("list_fields = ", list_fields)
raise


Expand Down Expand Up @@ -431,6 +431,19 @@ def __init__(self, name: str, matrix_form: int,
if finalize:
self.finalize()

def __deepcopy__(self, memo):
"""doesn't copy the label_actors to speed things up?"""
#keys = ['name', '_color', 'display', 'line_width', 'point_size', '_opacity',
#'_representation', 'is_visible', 'bar_scale', 'is_pickable']
cls = self.__class__
result = cls.__new__(cls)
idi = id(self)
memo[idi] = result
for key in list(self.__dict__.keys()):
value = self.__dict__[key]
setattr(result, key, deepcopy(value, memo))
return result

@classmethod
def add_card(cls, card, comment=''):
"""
Expand Down Expand Up @@ -2340,8 +2353,8 @@ def _fill_sparse_matrix(matrix: DMIG, nrows: int, ncols: int,
assert matrix.GCj.ndim == 1, matrix.GCj.ndim
rows = matrix.GCi
cols = matrix.GCj
GCj = array(matrix.GCj, dtype='int32') - 1
GCi = array(matrix.GCi, dtype='int32') - 1
GCj = np.array(matrix.GCj, dtype='int32') - 1
GCi = np.array(matrix.GCi, dtype='int32') - 1
# TODO: matrix size: is this correct?
nrows = max(GCi) + 1
ncols = max(GCj) + 1
Expand Down Expand Up @@ -2375,12 +2388,12 @@ def _fill_sparse_matrix(matrix: DMIG, nrows: int, ncols: int,
#ncols = unique2d(cols).shape[0]

float_dtype = _get_real_dtype(matrix.tin)
reals = array(matrix.Real, dtype=float_dtype)
reals = np.array(matrix.Real, dtype=float_dtype)

dtype = _get_dtype(matrix.is_complex, matrix.tin)

if matrix.is_complex:
complexs = array(matrix.Complex, dtype=float_dtype)
complexs = np.array(matrix.Complex, dtype=float_dtype)
data = reals + 1j * complexs
else:
data = reals
Expand Down Expand Up @@ -2450,7 +2463,7 @@ def _fill_dense_rectangular_matrix_complex(matrix: DMIG,
rows: dict[Any, int], cols: dict[Any, int],
apply_symmetry: bool) -> np.ndarray:
"""helper method for ``_fill_dense_rectangular_matrix``"""
dense_mat = zeros((nrows, ncols), dtype=matrix.tin_dtype)
dense_mat = np.zeros((nrows, ncols), dtype=matrix.tin_dtype)
real_imag = matrix.Real + 1j * matrix.Complex
if matrix.matrix_form == 6 and apply_symmetry: # symmetric
is_diagonal, not_diagonal = _get_diagonal_symmetric(matrix)
Expand Down Expand Up @@ -2486,7 +2499,7 @@ def _fill_dense_rectangular_matrix_real(matrix: DMIG,
rows: dict[Any, int], cols: dict[Any, int],
apply_symmetry: bool) -> np.ndarray:
"""helper method for ``_fill_dense_rectangular_matrix``"""
dense_mat = zeros((nrows, ncols), dtype=matrix.tin_dtype)
dense_mat = np.zeros((nrows, ncols), dtype=matrix.tin_dtype)
if matrix.matrix_form == 6 and apply_symmetry: # symmetric
is_diagonal, not_diagonal = _get_diagonal_symmetric(matrix)
try:
Expand Down Expand Up @@ -2581,7 +2594,7 @@ def _fill_dense_column_matrix_real(matrix: DMIG,
What does symmetry mean for a column matrix?!!!
"""
#print('nrows=%s ncols=%s' % (nrows, ncols))
dense_mat = zeros((nrows, ncols), dtype=matrix.tin_dtype)
dense_mat = np.zeros((nrows, ncols), dtype=matrix.tin_dtype)
if matrix.matrix_form == 6 and apply_symmetry: # symmetric
assert nrows == ncols, 'nrows=%s ncols=%s' % (nrows, ncols)
raise RuntimeError('What does symmetry mean for a column matrix?!!!')
Expand Down Expand Up @@ -2616,7 +2629,7 @@ def _fill_dense_column_matrix_complex(matrix: DMIG,
What does symmetry mean for a column matrix?!!!
"""
dense_mat = zeros((nrows, ncols), dtype=matrix.tin_dtype)
dense_mat = np.zeros((nrows, ncols), dtype=matrix.tin_dtype)
if matrix.matrix_form == 6 and apply_symmetry: # symmetric
assert nrows == ncols, 'nrows=%s ncols=%s' % (nrows, ncols)
raise RuntimeError('What does symmetry mean for a column matrix?!!!')
Expand Down Expand Up @@ -2680,8 +2693,8 @@ def get_dmi_matrix(matrix: DMI,
#print(matrix)
#print('GCi =', matrix.GCi)
#print('GCj =', matrix.GCj)
GCj = array(matrix.GCj, dtype='int32') - 1
GCi = array(matrix.GCi, dtype='int32') - 1
GCj = np.array(matrix.GCj, dtype='int32') - 1
GCi = np.array(matrix.GCi, dtype='int32') - 1

dtype = matrix.tin_dtype

Expand Down
101 changes: 68 additions & 33 deletions pyNastran/dev/bdf_vectorized3/alt_actor_builder.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
from __future__ import annotations
#import os
from itertools import count
from typing import TYPE_CHECKING

import numpy as np
#import vtk
from pyNastran.gui.vtk_common_core import vtkUnsignedCharArray, vtkPoints, VTK_ID_TYPE
from pyNastran.gui.vtk_interface import vtkUnstructuredGrid, vtkCellArray, vtkVertex

Expand All @@ -31,10 +29,10 @@

if TYPE_CHECKING: # pragma: no cover
from pyNastran.dev.op2_vectorized3.bdf import BDF
from pyNastran.dev.op2_vectorized3.bdf_interface.bdf_attributes import AECOMP, AECOMPL, SET1
#from pyNastran.dev.op2_vectorized3.op2_geom import OP2Geom
from pyNastran.dev.op2_vectorized3.bdf_interface.bdf_attributes import (
AECOMP, AECOMPL, SET1, RBE2, RBE3 #, GRID
)
from pyNastran.gui.main_window import MainWindow
from pyNastran.dev.op2_vectorized3.bdf_interface.bdf_attributes import RBE2, RBE3 #, GRID
from .nastran_io3 import Nastran3 as NastranIO


Expand All @@ -48,7 +46,7 @@ def create_alt_conm2_grids(gui: MainWindow,
mass_total, cg, inertia = model.inertia_sum()
except Exception as e:
model.log.error(f'cannot build mass actors\n{str(e)}')
raise
#raise
mass_total = 0.

if mass_total != 0.0:
Expand All @@ -58,24 +56,29 @@ def create_alt_conm2_grids(gui: MainWindow,
#print('inertia =', inertia)
_build_dot(gui, name, cg)

if element.n > 0:
if element.n == 0:
return

try:
mass = element.mass()
centroid = element.centroid()
except AssertionError:
return

# total - cg & all
conm2_mass_total = mass.sum()
cg_mass_total = (mass[:, np.newaxis] * centroid).sum(axis=0) / conm2_mass_total
assert len(cg_mass_total) == 3, cg_mass_total
name = f'All CONM2s CG mass={conm2_mass_total:g} xyz=[{cg_mass_total[0]:g}, {cg_mass_total[1]:g}, {cg_mass_total[2]:g}]'
_build_dot(gui, name, cg_mass_total)
# total - cg & all
conm2_mass_total = mass.sum()
cg_mass_total = (mass[:, np.newaxis] * centroid).sum(axis=0) / conm2_mass_total
assert len(cg_mass_total) == 3, cg_mass_total
name = f'All CONM2s CG mass={conm2_mass_total:g} xyz=[{cg_mass_total[0]:g}, {cg_mass_total[1]:g}, {cg_mass_total[2]:g}]'
_build_dot(gui, name, cg_mass_total)

name = f'All CONM2s mass={conm2_mass_total:g}'
_build_dots(gui, name, centroid)
name = f'All CONM2s mass={conm2_mass_total:g}'
_build_dots(gui, name, centroid)

# individual
for eid, nid, massi, xyzi in zip(element.element_id, element.node_id, mass, centroid):
name = f'CONM2 {eid} nid={nid} mass={massi:g} xyz=[{xyzi[0]:g}, {xyzi[1]:g}, {xyzi[2]:g}]'
_build_dot(gui, name, xyzi)
# individual
for eid, nid, massi, xyzi in zip(element.element_id, element.node_id, mass, centroid):
name = f'CONM2 {eid} nid={nid} mass={massi:g} xyz=[{xyzi[0]:g}, {xyzi[1]:g}, {xyzi[2]:g}]'
_build_dot(gui, name, xyzi)

def create_alt_rbe3_grids(gui: MainWindow,
model: BDF,
Expand All @@ -93,7 +96,10 @@ def create_alt_rbe3_grids(gui: MainWindow,

name = f'RBE3 Reference dependents'
inid_all_dependent = np.searchsorted(grid_id, elem.ref_grid)
ref_xyz_dependents = xyz_cid0[inid_all_dependent, :]
try:
ref_xyz_dependents = xyz_cid0[inid_all_dependent, :]
except IndexError:
return
_build_dots(gui, name, ref_xyz_dependents, color=RED_FLOAT)

all_dep_nodes = elem.dependent_nodes
Expand Down Expand Up @@ -170,6 +176,18 @@ def create_alt_axes(self: NastranIO,
model: BDF,
grid_id: np.ndarray,
xyz_cid0: np.ndarray):
"""
creates:
- shell element coordinate systems
- shell material coordinate systems
creates orientation vectors for:
- CBAR
- CBEAM
- CBUSH
- CGAP
"""
assert gui is not None
if not hasattr(gui, 'bar_eids') or gui.bar_eids is None:
gui.bar_eids = {}
Expand All @@ -178,17 +196,25 @@ def create_alt_axes(self: NastranIO,
#from pyNastran.utils import object_attributes
#print('gui attrs', object_attributes(gui))
#print('gui type = ', type(gui))
_create_alt_axes(self, gui, model, grid_id, xyz_cid0, model.cbush, 'CBUSH')
_create_alt_axes(self, gui, model, grid_id, xyz_cid0, model.cgap, 'CGAP')
_create_alt_axes(self, gui, model, grid_id, xyz_cid0, model.cbar, 'CBAR')
_create_alt_axes(self, gui, model, grid_id, xyz_cid0, model.cbeam, 'CBEAM')
_create_shell_axes(self, gui, model, grid_id, xyz_cid0)
try:
_create_shell_axes(self, gui, model, grid_id, xyz_cid0)
_create_alt_axes(self, gui, model, grid_id, xyz_cid0, model.cbar, 'CBAR')
_create_alt_axes(self, gui, model, grid_id, xyz_cid0, model.cbeam, 'CBEAM')
_create_alt_axes(self, gui, model, grid_id, xyz_cid0, model.cbush, 'CBUSH')
_create_alt_axes(self, gui, model, grid_id, xyz_cid0, model.cgap, 'CGAP')
except IndexError:
pass

def _create_shell_axes(self: NastranIO,
gui: MainWindow,
model: BDF,
grid_id: np.ndarray,
xyz_cid0: np.ndarray) -> None:
"""
creates:
- shell element coordinate systems
- shell material coordinate systems
"""
name_func = [
('eleement', get_shell_material_coordinate_system),
('material', get_shell_element_coordinate_system),
Expand Down Expand Up @@ -235,6 +261,12 @@ def _create_alt_axes(self: NastranIO,
xyz_cid0: np.ndarray,
elem, card_name: str) -> None:
"""
creates orientation vectors for:
- CBAR
- CBEAM
- CBUSH
- CGAP
Parameters
----------
self : NastranIO
Expand Down Expand Up @@ -358,7 +390,10 @@ def create_alt_rbe2_grids(gui: MainWindow,
return

i_independent = np.searchsorted(grid_id, elem.independent_node)
xyz_independents = xyz_cid0[i_independent, :]
try:
xyz_independents = xyz_cid0[i_independent, :]
except IndexError:
return

name = f'RBE2 independents'
_build_dots(gui, name, xyz_independents, color=BLUE_FLOAT)
Expand Down Expand Up @@ -695,7 +730,7 @@ def create_monpnt1(gui: MainWindow,
#name, label, aecomp_name, xyz_global)
elif list_type == 'CAERO':
log.warning(f'skipping MONPNT1={name!r} because AECOMP={aecomp_name!r} has a list_type=CAERO') # \nkeys={keys}
else:
else: # pragma: no cover
log.warning(f'skipping MONPNT1={name!r} because AECOMP={aecomp_name!r} has a list_type={list_type!r}') # \nkeys={keys}
raise RuntimeError(f'skipping MONPNT1={name!r} because AECOMP={aecomp_name!r} has a list_type={list_type!r}') # \nkeys={keys}
elif aecomp_name in all_aecompl_names:
Expand All @@ -719,7 +754,7 @@ def create_monpnt1(gui: MainWindow,
log.warning(f'skipping MONPNT1={name!r} because AECOMPs={aecomp_names} has a list_type=AELIST') # \nkeys={keys}
elif list_type == 'CAERO':
log.warning(f'skipping MONPNT1={name!r} because AECOMPs={aecomp_names} has a list_type=CAERO') # \nkeys={keys}
else:
else: # pragma: no cover
raise RuntimeError(f'skipping MONPNT1={name!r} because AECOMPs={aecomp_names} has a list_type={list_type!r}') # \nkeys={keys}

else: # pragma: no cover
Expand Down Expand Up @@ -752,7 +787,7 @@ def get_aecomp_from_aecompl(aecomp_name: str,
elif label in all_aecompl_names:
assert label not in used_aecompl_names, f'AECOMPL label={label!r} was already used; circular reference'
aecompls.append(label)
else:
else: # pragma: no cover
raise RuntimeError(label)

all_labels = []
Expand Down Expand Up @@ -873,7 +908,7 @@ def _build_dot(gui: MainWindow, name: str, xyzi: np.ndarray,


def _build_dots(gui: MainWindow, name: str, xyzs: np.ndarray,
point_size: int=3, color=RED_FLOAT, is_visible: bool=False):
point_size: int=3, color=RED_FLOAT, is_visible: bool=False) -> None:
assert len(xyzs.shape) == 2, xyzs.shape
gui.create_alternate_vtk_grid(
name, color=color, point_size=point_size, opacity=1.0,
Expand All @@ -898,7 +933,7 @@ def _build_lines(gui: MainWindow, name: str,
nodes_index: np.ndarray,
line_width: int=3, color=RED_FLOAT,
representation: str = 'wire',
is_visible: bool=True):
is_visible: bool=True) -> None:
assert len(xyzs.shape) == 2, xyzs.shape
assert len(nodes_index.shape) == 2, nodes_index.shape
nelement = nodes_index.shape[0]
Expand All @@ -925,7 +960,7 @@ def _build_quads(gui: MainWindow, name: str,
line_width: int=3, color=RED_FLOAT,
opacity: float=1.0,
is_visible: bool=True,
representation: str='wire+surf'):
representation: str='wire+surf') -> None:
assert len(xyzs.shape) == 2, xyzs.shape
assert len(nodes_index.shape) == 2, nodes_index.shape
assert nodes_index.shape[1] == 4, nodes_index.shape
Expand All @@ -951,7 +986,7 @@ def _build_vtk_data_from_dnode(alt_grid: vtkUnstructuredGrid,
xyz: np.ndarray,
nnodes: np.ndarray,
nodes_index: np.ndarray,
nelement: int, cell_typei: int, dnode: int):
nelement: int, cell_typei: int, dnode: int) -> None:
points = numpy_to_vtk_points(xyz)

cell_type = np.ones(nelement, dtype='int64') * cell_typei
Expand Down
Loading

0 comments on commit e18c227

Please sign in to comment.