Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 12 additions & 8 deletions src/ospgrillage/osp_grillage.py
Original file line number Diff line number Diff line change
Expand Up @@ -1577,7 +1577,11 @@ def _assign_load_to_four_node(self, point, mag, shape_func="linear"):
if shape_func == "hermite":
# Three-node regions use a DKT-style condensed point-load distributor so
# skew-edge/corner triangles remain compatible with the higher-order path.
Nv, node_mx_shape, node_mz_shape = ShapeFunction.dkt_triangle_shape_function(
(
Nv,
node_mx_shape,
node_mz_shape,
) = ShapeFunction.dkt_triangle_shape_function(
x=point[0],
z=point[2],
x1=sorted_list[0].x,
Expand Down Expand Up @@ -2290,9 +2294,7 @@ def _embed_geometry(self, ds):
# --- node coordinates DataArray ---
node_spec = self.Mesh_obj.node_spec
node_tags = sorted(node_spec.keys())
coord_data = np.array(
[node_spec[n]["coordinate"] for n in node_tags]
)
coord_data = np.array([node_spec[n]["coordinate"] for n in node_tags])
ds["node_coordinates"] = xr.DataArray(
coord_data,
dims=("Node", "Axis"),
Expand Down Expand Up @@ -3244,7 +3246,8 @@ def extract_analysis(
for ele_num, stresses in analysis_obj.ele_stresses.items():
ele_stress_dict[ele_num] = stresses
self.basic_load_case_record_stresses.setdefault(
analysis_obj.analysis_name, ele_stress_dict,
analysis_obj.analysis_name,
ele_stress_dict,
)

# if moving load, input is a list of analysis obj
Expand Down Expand Up @@ -3540,10 +3543,11 @@ def compile_data_array(self, local_force_option=True, main_ele_tags=None):
if self.basic_load_case_record_stresses:
stress_list = []
for lc_name in basic_load_case_coord:
lc_stresses = self.basic_load_case_record_stresses.get(lc_name, {})
lc_stresses = self.basic_load_case_record_stresses.get(
lc_name, {}
)
lc_row = [
lc_stresses.get(tag, [0.0] * 32)
for tag in ele_tag_shell
lc_stresses.get(tag, [0.0] * 32) for tag in ele_tag_shell
]
stress_list.append(lc_row)
stress_array = np.array(stress_list)
Expand Down
38 changes: 28 additions & 10 deletions src/ospgrillage/ospgui.py
Original file line number Diff line number Diff line change
Expand Up @@ -753,8 +753,25 @@ def __init__(self):
self.contour_group = QGroupBox("Shell Contour")
contour_layout = QFormLayout()
self.contour_component_combo = QComboBox()
for comp in ("Mx", "My", "Mz", "Vx", "Vy", "Vz", "Dx", "Dy", "Dz",
"N11", "N22", "N12", "M11", "M22", "M12", "Q13", "Q23"):
for comp in (
"Mx",
"My",
"Mz",
"Vx",
"Vy",
"Vz",
"Dx",
"Dy",
"Dz",
"N11",
"N22",
"N12",
"M11",
"M22",
"M12",
"Q13",
"Q23",
):
self.contour_component_combo.addItem(comp)
contour_layout.addRow("Component:", self.contour_component_combo)
self.contour_colorscale_combo = QComboBox()
Expand Down Expand Up @@ -973,10 +990,10 @@ def __init__(self):
self.generated_code = ""

# Results viewer state
self._mode = "wizard" # "wizard" or "results"
self._model_proxy = None # _ModelProxy from loaded results
self._results = None # xarray Dataset
self._stale_tabs = set() # result tab names needing re-render
self._mode = "wizard" # "wizard" or "results"
self._model_proxy = None # _ModelProxy from loaded results
self._results = None # xarray Dataset
self._stale_tabs = set() # result tab names needing re-render

# Create UI components
self.create_menu_bar()
Expand Down Expand Up @@ -1641,9 +1658,7 @@ def _open_results_file(self):
)
return
except Exception as e:
QMessageBox.critical(
self, "Error", f"Could not load results file:\n{e}"
)
QMessageBox.critical(self, "Error", f"Could not load results file:\n{e}")
return

self._model_proxy = proxy
Expand Down Expand Up @@ -1791,7 +1806,10 @@ def _refresh_current_result_tab(self):
from PyQt6.QtCore import QUrl

tmp = tempfile.NamedTemporaryFile(
suffix=".html", delete=False, mode="w", encoding="utf-8",
suffix=".html",
delete=False,
mode="w",
encoding="utf-8",
)
tmp.write(fig.to_html(include_plotlyjs=True))
tmp.close()
Expand Down
58 changes: 38 additions & 20 deletions src/ospgrillage/postprocessing.py
Original file line number Diff line number Diff line change
Expand Up @@ -331,8 +331,7 @@ def get(self):
# ``forces_shell`` aligned with the ``ele_nodes_shell`` Nodes dimension.
_SHELL_COMPONENTS = ("Vx", "Vy", "Vz", "Mx", "My", "Mz")
_SHELL_COMP_COLUMNS = {
comp: [f"{comp}_{s}" for s in ("i", "j", "k", "l")]
for comp in _SHELL_COMPONENTS
comp: [f"{comp}_{s}" for s in ("i", "j", "k", "l")] for comp in _SHELL_COMPONENTS
}

# Displacement components for shell contour. User-facing names map to
Expand All @@ -349,9 +348,7 @@ def get(self):

# All components accepted by plot_srf
_SRF_COMPONENTS = (
_SHELL_COMPONENTS
+ tuple(_DISP_COMPONENTS.keys())
+ _STRESS_RESULTANTS
_SHELL_COMPONENTS + tuple(_DISP_COMPONENTS.keys()) + _STRESS_RESULTANTS
)


Expand Down Expand Up @@ -527,7 +524,9 @@ def _extract_def_data(
# ---------------------------------------------------------------------------
# Shell contour data extraction
# ---------------------------------------------------------------------------
def _extract_shell_contour_data(result_obj, component, loadcase=None, *, averaging="nodal"):
def _extract_shell_contour_data(
result_obj, component, loadcase=None, *, averaging="nodal"
):
"""Extract per-node contour values for a shell stress resultant.

Parameters
Expand Down Expand Up @@ -736,9 +735,9 @@ def _triangulate_shell_mesh(node_coords, element_quads):
vx, vy, vz = [], [], []
for tag in ordered_tags:
c = node_coords[tag]
vx.append(c[0]) # model x -> plotly x
vy.append(c[2]) # model z -> plotly y
vz.append(-c[1]) # model y -> plotly z (negated)
vx.append(c[0]) # model x -> plotly x
vy.append(c[2]) # model z -> plotly y
vz.append(-c[1]) # model y -> plotly z (negated)

# Triangle indices (each quad -> 2 triangles)
i_idx, j_idx, k_idx = [], [], []
Expand Down Expand Up @@ -1281,15 +1280,22 @@ def _plotly_3d_shell_contour(
# Extract data — dispatch to force or displacement extraction
if component in _DISP_COMPONENTS:
node_values, element_quads = _extract_shell_disp_data(
result_obj, component, loadcase,
result_obj,
component,
loadcase,
)
elif component in _STRESS_RESULTANTS:
node_values, element_quads = _extract_shell_stress_data(
result_obj, component, loadcase,
result_obj,
component,
loadcase,
)
else:
node_values, element_quads = _extract_shell_contour_data(
result_obj, component, loadcase, averaging=averaging,
result_obj,
component,
loadcase,
averaging=averaging,
)

# Build node coordinate dict from Dataset
Expand All @@ -1300,7 +1306,8 @@ def _plotly_3d_shell_contour(

# Triangulate
vx, vy, vz, i_idx, j_idx, k_idx, tag_to_vidx = _triangulate_shell_mesh(
node_coords, element_quads,
node_coords,
element_quads,
)

# Build intensity array aligned with vertex order
Expand All @@ -1318,12 +1325,17 @@ def _plotly_3d_shell_contour(
k=k_idx,
intensity=intensity,
colorscale=colorscale,
colorbar=dict(title=component, x=-0.05, xanchor="right") if show_colorbar else None,
colorbar=dict(title=component, x=-0.05, xanchor="right")
if show_colorbar
else None,
showscale=show_colorbar,
opacity=opacity,
flatshading=True,
lighting=dict(
ambient=1.0, diffuse=0.0, specular=0.0, fresnel=0.0,
ambient=1.0,
diffuse=0.0,
specular=0.0,
fresnel=0.0,
),
name=f"shell_{component}",
hovertemplate=f"{component}: %{{intensity:.3g}}<extra></extra>",
Expand Down Expand Up @@ -1394,15 +1406,22 @@ def _plot_shell_contour_mpl(

if component in _DISP_COMPONENTS:
node_values, element_quads = _extract_shell_disp_data(
result_obj, component, loadcase,
result_obj,
component,
loadcase,
)
elif component in _STRESS_RESULTANTS:
node_values, element_quads = _extract_shell_stress_data(
result_obj, component, loadcase,
result_obj,
component,
loadcase,
)
else:
node_values, element_quads = _extract_shell_contour_data(
result_obj, component, loadcase, averaging=averaging,
result_obj,
component,
loadcase,
averaging=averaging,
)

# Build node coordinate dict
Expand Down Expand Up @@ -2205,8 +2224,7 @@ def plot_srf(
"""
if component not in _SRF_COMPONENTS:
raise ValueError(
f"Unknown component {component!r}. "
f"Expected one of {_SRF_COMPONENTS}."
f"Unknown component {component!r}. " f"Expected one of {_SRF_COMPONENTS}."
)
if "ele_nodes_shell" not in result_obj:
raise ValueError(
Expand Down
Loading