Skip to content

Commit

Permalink
more testing of gui objects
Browse files Browse the repository at this point in the history
  • Loading branch information
SteveDoyle2 committed Feb 13, 2024
1 parent f56750c commit 7a9f7ae
Show file tree
Hide file tree
Showing 7 changed files with 264 additions and 25 deletions.
5 changes: 3 additions & 2 deletions pyNastran/converters/nastran/gui/nastran_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -434,8 +434,9 @@ def _get_model_unvectorized(self,
self.model_type = 'nastran'
return model, xref_nodes

def load_nastran_geometry(self, bdf_filename, name='main',
plot=True, **kwargs):
def load_nastran_geometry(self, bdf_filename: Union[str, BDF],
name: str='main',
plot: bool=True, **kwargs):
"""
The entry point for Nastran geometry loading.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from typing import Optional, TYPE_CHECKING

from pyNastran.gui.gui_objects.gui_result import GuiResultCommon
from pyNastran.femutils.utils import pivot_table, abs_nan_min_max # abs_min_max
from pyNastran.femutils.utils import pivot_table, abs_nan_min_max, safe_nanstd # abs_min_max
from pyNastran.bdf.utils import write_patran_syntax_dict

from .vector_results import VectorResultsCommon, filter_ids
Expand Down Expand Up @@ -502,9 +502,9 @@ def _get_fringe_sparse_centroidal(self, case_tuple: CaseTuple) -> tuple[np.ndarr
elif self.min_max_method == 'Mean': # (Derive/Average)???
data4 = np.nanmean(data3, axis=axis)
elif self.min_max_method == 'Std. Dev.':
data4 = np.nanstd(data3, axis=axis)
data4 = safe_nanstd(data3, axis=axis)
elif self.min_max_method == 'Difference':
data4 = nan_difference(data, axis)
data4 = nan_difference(data3, axis)
#elif self.min_max_method == 'Max Over Time':
#data4 = np.nanmax(data3, axis=axis) - np.nanmin(data2, axis=axis)
#elif self.min_max_method == 'Derive/Average':
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ def get_vector_result_by_scale_phase(self, i: int, res_name: str,
else:
assert isinstance(i, int), (i, phase)
assert isinstance(phase, float), (i, phase)
dxyz, unused_idxs = self._get_complex_displacements_by_phase(i, phase)
dxyz, unused_idxs = self._get_complex_displacements_by_phase(i, res_name, phase)
deflected_xyz = self.xyz + scale * dxyz
assert len(deflected_xyz.shape) == 2, deflected_xyz.shape
return self.xyz, deflected_xyz
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from collections import defaultdict
import numpy as np

from pyNastran.femutils.utils import abs_nan_min_max
from pyNastran.femutils.utils import abs_nan_min_max, safe_nanstd


def nan_difference(x: np.ndarray, axis: int) -> np.ndarray:
Expand All @@ -16,7 +16,7 @@ def nan_difference(x: np.ndarray, axis: int) -> np.ndarray:
'Max': np.nanmax,
'Min': np.nanmin,
'Difference': nan_difference,
'Std. Dev.': np.nanstd,
'Std. Dev.': safe_nanstd,
}

def abs_max_scalar(x: np.ndarray) -> np.ndarray:
Expand All @@ -29,14 +29,16 @@ def abs_max_scalar(x: np.ndarray) -> np.ndarray:
def difference_scalar(x: np.ndarray) -> np.ndarray:
out = np.nanmax(x) - np.nanmin(x)
return out
def safe_nanstdi(x: np.ndarray) -> np.ndarray:
return safe_nanstd(x, axis=None)

nodal_combine_map: dict[str, Callable[[np.ndarray], np.ndarray]]= {
'Absolute Max': abs_max_scalar,
'Mean': np.nanmean,
'Max': np.nanmax,
'Min': np.nanmin,
'Difference': difference_scalar, # nan-subtract
'Std. Dev.': np.nanstd,
'Std. Dev.': safe_nanstdi,
}

def nodal_average(nodal_combine_func: Callable[[np.ndarray], np.ndarray],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from typing import Union, Optional, Any, TYPE_CHECKING

from pyNastran.utils.mathematics import get_abs_max
from pyNastran.femutils.utils import abs_nan_min_max
from pyNastran.femutils.utils import abs_nan_min_max, safe_nanstd

from .vector_results import VectorResultsCommon, filter_ids
from .stress_reduction import von_mises_2d, max_shear
Expand Down Expand Up @@ -234,17 +234,9 @@ def set_sidebar_args(self,
nodal_combine: str='', # Centroid
**kwargs) -> None:
assert len(kwargs) == 0, kwargs
transforms = self.has_coord_transform(itime, res_name)[1]
min_max_methods = self.has_derivation_transform(itime, res_name)[1]['derivation']
combine_methods = self.has_nodal_combine_transform(itime, res_name)[1]

transform = transform if transform else transforms[0]
min_max_method = min_max_method if min_max_method else min_max_methods[0]
nodal_combine = nodal_combine if nodal_combine else combine_methods[0]

assert transform in transforms, transform
assert min_max_method in min_max_methods, min_max_method
assert nodal_combine in combine_methods, nodal_combine
transform, min_max_method, nodal_combine = _check_sidebar_args(
self, itime, res_name,
transform, min_max_method, nodal_combine)

#sidebar_kwargs = {
#'min_max_method': min_max_method,
Expand All @@ -270,8 +262,6 @@ def set_sidebar_args(self,
#self.layer_indices = (1, )

# doesn't matter cause it's already nodal
assert min_max_method in min_max_methods, min_max_method
assert nodal_combine in combine_methods, nodal_combine
self.min_max_method = min_max_method
self.nodal_combine = nodal_combine
self.transform = transform
Expand Down Expand Up @@ -446,7 +436,7 @@ def _squash_layers(self, data: np.ndarray, min_max_method: str) -> np.ndarray:
elif min_max_method == 'Mean': # (Derive/Average)???
data2 = np.nanmean(data, axis=axis)
elif min_max_method == 'Std. Dev.':
data2 = np.nanstd(data, axis=axis)
data2 = safe_nanstd(data, axis=axis)
elif min_max_method == 'Difference':
data2 = np.nanmax(data, axis=axis) - np.nanmin(data, axis=axis)
#elif min_max_method == 'Max Over Time':
Expand Down Expand Up @@ -904,3 +894,21 @@ def setup_centroid_node_data(eid_to_nid_map: dict[int, list[int]],
element_node = np.vstack(element_node_list)
node_data = np.hstack(node_data_list)
return centroid_eids, centroid_data, element_node, node_data

def _check_sidebar_args(plate: PlateStrainStressResults2,
itime: int, res_name: tuple,
transform: str, # Material
min_max_method: str, # Absolute Max
nodal_combine: str): # Centroid
transforms = plate.has_coord_transform(itime, res_name)[1]
min_max_methods = plate.has_derivation_transform(itime, res_name)[1]['derivation']
combine_methods = plate.has_nodal_combine_transform(itime, res_name)[1]

transform = transform if transform else transforms[0]
min_max_method = min_max_method if min_max_method else min_max_methods[0]
nodal_combine = nodal_combine if nodal_combine else combine_methods[0]

assert transform in transforms, transform
assert min_max_method in min_max_methods, min_max_method
assert nodal_combine in combine_methods, nodal_combine
return transform, min_max_method, nodal_combine
212 changes: 212 additions & 0 deletions pyNastran/converters/nastran/test_nastran_gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
import os
import sys
from copy import deepcopy
from collections import defaultdict
import unittest
from typing import Union

import numpy as np
try:
Expand All @@ -20,6 +22,7 @@

import pyNastran
from pyNastran.bdf.bdf import BDF, read_bdf
from pyNastran.op2.op2 import OP2
from pyNastran.bdf.cards.test.test_aero import get_zona_model
from pyNastran.bdf.errors import DuplicateIDsError

Expand All @@ -34,6 +37,17 @@
from pyNastran.converters.nastran.gui.nastran_io import NastranIO
from pyNastran.converters.nastran.nastran_to_vtk import nastran_to_vtk
from pyNastran.converters.nastran.gui.stress import get_composite_sort

from pyNastran.gui.gui_objects.gui_result import GuiResult, NormalResult, GridPointForceResult
from pyNastran.gui.gui_objects.displacements import DisplacementResults, ForceTableResults, ElementalTableResults
from pyNastran.converters.nastran.gui.result_objects.simple_table_results import SimpleTableResults
from pyNastran.converters.nastran.gui.result_objects.layered_table_results import LayeredTableResults
from pyNastran.converters.nastran.gui.result_objects.force_results import ForceResults2
from pyNastran.converters.nastran.gui.result_objects.displacement_results import DisplacementResults2
from pyNastran.converters.nastran.gui.result_objects.composite_stress_results import CompositeStrainStressResults2
from pyNastran.converters.nastran.gui.result_objects.plate_stress_results import PlateStrainStressResults2
from pyNastran.converters.nastran.gui.result_objects.solid_stress_results import SolidStrainStressResults2

RED = (1., 0., 0.)


Expand All @@ -44,6 +58,19 @@ def __init__(self, inputs=None):
self.build_fmts(['nastran'], stop_on_failure=True)
self.stop_on_failure = True

def load_nastran_geometry(self, bdf_filename: Union[str, BDF],
name: str='main',
plot: bool=True,
stop_on_failure: bool=False):
super().load_nastran_geometry(
bdf_filename, name=name,
plot=plot, stop_on_failure=stop_on_failure)
self.validate_result_object_methods()

def load_nastran_results(self, op2_filename: Union[str, OP2]):
super().load_nastran_results(op2_filename)
self.validate_result_object_methods()

def write_result_cases(self): # pramga: no cover
case_id0 = 0
for case_id, (result_case, flag) in self.result_cases.items():
Expand All @@ -67,6 +94,191 @@ def write_result_cases(self): # pramga: no cover
assert case_id == case_id0, (case_id, case_id0)
case_id0 += 1

def validate_result_object_methods(self):
scale = 10.
checks = defaultdict(bool)
#'GuiResult': True,
#'NormalResult': True,
#'GridPointForceResult': True,
#'CompositeStrainStressResults2': False,
#'PlateStrainStressResults2': False,
#'CompositeStrainStressResults2': False,
#'SolidStrainStressResults2': False,
#'PlateStrainStressResults2': False,
#'PlateStrainStressResults2': False,
#}
for icase, (res, (itime, res_name)) in self.result_cases.items():
# make one check per result type.
# We check each term (e.g., for SolidStress, check oxx, oyy, von Mises, ...)
is_complex = res.is_complex
legend_title = res.get_legend_title(itime, res_name)
key = (res.class_name, is_complex, legend_title)

is_analyzed = checks[key]
if is_analyzed: # don't analyze the same object type twice
continue

res.get_data_format(itime, res_name)
is_min = 'Min' in legend_title
is_max = 'Max' in legend_title
if isinstance(res, (GuiResult, SimpleTableResults, LayeredTableResults)):
res.get_fringe_result(itime, res_name)
res.get_fringe_vector_result(itime, res_name)
res.get_annotation(itime, res_name)
res.get_default_min_max(itime, res_name)
res.get_imin_imax(itime, res_name)
elif isinstance(res, NormalResult):
res.get_annotation(itime, res_name)
elif isinstance(res, GridPointForceResult):
pass
elif isinstance(res, (DisplacementResults, ForceTableResults)): # ElementalTableResults
res.get_annotation(itime, res_name)
res.get_arrow_scale(itime, res_name)
#res.get_case_flag(itime, res_name)

#res.get_data_type(itime, res_name)
res.get_fringe_result(itime, res_name)
res.get_fringe_vector_result(itime, res_name)
res.get_vector_result(itime, res_name)
deflects = res.deflects(itime, res_name)
if is_complex and deflects:
res.get_vector_result_by_scale_phase(itime, res_name, scale, phase=45.)
res.get_default_arrow_scale(itime, res_name)
res.get_default_min_max(itime, res_name)
res.get_imin_imax(itime, res_name)

elif isinstance(res, (ForceResults2, DisplacementResults2)):
force_disp_flags = [
# transform, method_keys, nodal_combine
('Global', None, ''),
('Global', [0], ''),
('Global', [0, 1], ''),
('Global', [1, 2], ''),
('Global', [0, 1, 2], ''),
]
res.get_annotation(itime, res_name)
res.get_arrow_scale(itime, res_name)
res.get_case_flag(itime, res_name)

for transform, method_keys, nodal_combine in force_disp_flags:
res.set_sidebar_args(itime, res_name,
#min_max_method=min_max_method,
transform=transform,
#methods_keys=method_keys,
nodal_combine='')
#res.get_data_type(itime, res_name)
res.get_fringe_result(itime, res_name)
res.get_fringe_vector_result(itime, res_name)
res.get_vector_result(itime, res_name)
deflects = res.deflects(itime, res_name)
if is_complex and deflects:
res.get_vector_result_by_scale_phase(itime, res_name, scale, phase=45.)
res.get_default_arrow_scale(itime, res_name)
res.get_default_min_max(itime, res_name)
res.get_imin_imax(itime, res_name)

elif isinstance(res, CompositeStrainStressResults2):
composite_flags = [
# min_max_method, transform, method_keys, nodal_combine
('Absolute Max', 'Material', None, ''),
('Mean', 'Material', None, ''),
('Std. Dev.', 'Material', None, ''),
('Difference', 'Material', None, ''),
('Max', 'Material', [1, 2], ''),
('Min', 'Material', [1, 2], ''),
]
res.get_arrow_scale(itime, res_name)
res.get_case_flag(itime, res_name)
#res.get_data_type(itime, res_name)
for min_max_method, transform, method_keys, nodal_combine in composite_flags:
if (is_min, min_max_method) == (True, 'Max') or (is_max, min_max_method) == (True, 'Min'):
continue
res.set_sidebar_args(itime, res_name,
min_max_method=min_max_method,
transform=transform,
methods_keys=method_keys,
nodal_combine='')
res.get_annotation(itime, res_name)
res.get_fringe_result(itime, res_name)
res.get_fringe_vector_result(itime, res_name)
#res.get_vector_result(itime, res_name)
if is_complex:
res.get_vector_result_by_scale_phase(itime, res_name, scale, phase=45.)
res.get_default_arrow_scale(itime, res_name)
res.get_default_min_max(itime, res_name)
res.get_imin_imax(itime, res_name)

elif isinstance(res, PlateStrainStressResults2):
plate_flags = [
# min_max_method, transform, method_keys, nodal_combine
('Absolute Max', 'Material', None, 'Absolute Max'),
('Mean', 'Material', None, 'Mean'),
('Min', 'Material', None, 'Min'),
('Max', 'Material', None, 'Max'),
('Std. Dev.', 'Material', None, 'Std. Dev.'),
('Difference', 'Material', None, 'Difference'),
('Max', 'Material', [0], 'Max'),
('Max', 'Material', [1], 'Max'),
('Max', 'Material', [2], 'Max'),
]
res.get_arrow_scale(itime, res_name)
res.get_case_flag(itime, res_name)
#res.get_data_type(itime, res_name)
for min_max_method, transform, method_keys, nodal_combine in plate_flags:
if (is_min, min_max_method) == (True, 'Max') or (is_max, min_max_method) == (True, 'Min'):
continue
res.set_sidebar_args(itime, res_name,
min_max_method=min_max_method,
transform=transform,
methods_keys=method_keys,
nodal_combine='')
res.get_annotation(itime, res_name)
res.get_fringe_result(itime, res_name)
res.get_fringe_vector_result(itime, res_name)
#res.get_vector_result(itime, res_name)
if is_complex:
res.get_vector_result_by_scale_phase(itime, res_name, scale, phase=45.)
res.get_default_arrow_scale(itime, res_name)
res.get_default_min_max(itime, res_name)
res.get_imin_imax(itime, res_name)

elif isinstance(res, SolidStrainStressResults2):
solid_flags = [
# min_max_method, transform, method_keys, nodal_combine
('Absolute Max', 'Material', None, 'Absolute Max'),
('Mean', 'Material', None, 'Mean'),
('Min', 'Material', None, 'Min'),
('Max', 'Material', None, 'Max'),
('Std. Dev.', 'Material', None, 'Std. Dev.'),
('Difference', 'Material', None, 'Difference'),
('Max', 'Material', [0], 'Max'),
('Max', 'Material', [1], 'Max'),
]
res.get_arrow_scale(itime, res_name)
res.get_case_flag(itime, res_name)
#res.get_data_type(itime, res_name)
for min_max_method, transform, method_keys, nodal_combine in solid_flags:
if (is_min, min_max_method) == (True, 'Max') or (is_max, min_max_method) == (True, 'Min'):
continue
res.set_sidebar_args(itime, res_name,
min_max_method=min_max_method,
transform=transform,
methods_keys=method_keys,
nodal_combine='')
res.get_annotation(itime, res_name)
res.get_fringe_result(itime, res_name)
res.get_fringe_vector_result(itime, res_name)
#res.get_vector_result(itime, res_name)
if is_complex:
res.get_vector_result_by_scale_phase(itime, res_name, scale, phase=45.)
res.get_default_arrow_scale(itime, res_name)
res.get_default_min_max(itime, res_name)
res.get_imin_imax(itime, res_name)
else:
raise NotImplementedError(res)
checks[key] = True
return

PKG_PATH = pyNastran.__path__[0]
STL_PATH = os.path.join(PKG_PATH, 'converters', 'stl')
MODEL_PATH = os.path.join(PKG_PATH, '..', 'models')
Expand Down
Loading

0 comments on commit 7a9f7ae

Please sign in to comment.