From 83e01f1f7b38899ddd4efec0cc4ad09157588c9e Mon Sep 17 00:00:00 2001 From: ccaprani <31228546+ccaprani@users.noreply.github.com> Date: Wed, 15 Apr 2026 05:35:40 +0000 Subject: [PATCH] :art: Format Python code with psf/black --- src/ospgrillage/osp_grillage.py | 20 ++++--- src/ospgrillage/ospgui.py | 38 ++++++++---- src/ospgrillage/postprocessing.py | 58 +++++++++++------- tests/generate_test_results.py | 98 ++++++++++++++++++++++--------- tests/test_load.py | 8 +-- tests/test_postprocessing.py | 6 +- 6 files changed, 155 insertions(+), 73 deletions(-) diff --git a/src/ospgrillage/osp_grillage.py b/src/ospgrillage/osp_grillage.py index d401da31..b6e5ffbe 100644 --- a/src/ospgrillage/osp_grillage.py +++ b/src/ospgrillage/osp_grillage.py @@ -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, @@ -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"), @@ -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 @@ -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) diff --git a/src/ospgrillage/ospgui.py b/src/ospgrillage/ospgui.py index ba2bec10..3bfe4674 100644 --- a/src/ospgrillage/ospgui.py +++ b/src/ospgrillage/ospgui.py @@ -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() @@ -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() @@ -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 @@ -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() diff --git a/src/ospgrillage/postprocessing.py b/src/ospgrillage/postprocessing.py index 9cb6a58b..83a82337 100644 --- a/src/ospgrillage/postprocessing.py +++ b/src/ospgrillage/postprocessing.py @@ -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 @@ -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 ) @@ -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 @@ -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 = [], [], [] @@ -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 @@ -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 @@ -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}}", @@ -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 @@ -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( diff --git a/tests/generate_test_results.py b/tests/generate_test_results.py index f71bc88e..f6213e2f 100644 --- a/tests/generate_test_results.py +++ b/tests/generate_test_results.py @@ -33,28 +33,44 @@ # -- Materials & sections -------------------------------------------------- -concrete = og.create_material( - material="concrete", code="AS5100-2017", grade="65MPa" -) +concrete = og.create_material(material="concrete", code="AS5100-2017", grade="65MPa") concrete_shell = og.create_material( material="concrete", code="AS5100-2017", grade="50MPa", rho=2400 ) long_sec = og.create_section( - A=0.034 * m2, J=2.08e-3 * m3, Iz=6.77e-3 * m4, - Iy=2.04e-3 * m4, Az=6.10e-3 * m2, Ay=3.99e-3 * m2, + A=0.034 * m2, + J=2.08e-3 * m3, + Iz=6.77e-3 * m4, + Iy=2.04e-3 * m4, + Az=6.10e-3 * m2, + Ay=3.99e-3 * m2, ) edge_sec = og.create_section( - A=0.034 * m2, J=2.08e-3 * m3, Iz=6.77e-3 * m4, - Iy=2.04e-3 * m4, Az=6.10e-3 * m2, Ay=3.99e-3 * m2, + A=0.034 * m2, + J=2.08e-3 * m3, + Iz=6.77e-3 * m4, + Iy=2.04e-3 * m4, + Az=6.10e-3 * m2, + Ay=3.99e-3 * m2, ) trans_sec = og.create_section( - A=0.504 * m2, J=5.22303e-3 * m3, Iy=0.32928 * m4, - Iz=1.3608e-3 * m4, Ay=0.42 * m2, Az=0.42 * m2, unit_width=True, + A=0.504 * m2, + J=5.22303e-3 * m3, + Iy=0.32928 * m4, + Iz=1.3608e-3 * m4, + Ay=0.42 * m2, + Az=0.42 * m2, + unit_width=True, ) end_sec = og.create_section( - A=0.504 / 2 * m2, J=2.5e-3 * m3, Iy=2.73e-2 * m4, - Iz=6.8e-4 * m4, Ay=0.21 * m2, Az=0.21 * m2, unit_width=True, + A=0.504 / 2 * m2, + J=2.5e-3 * m3, + Iy=2.73e-2 * m4, + Iz=6.8e-4 * m4, + Ay=0.21 * m2, + Az=0.21 * m2, + unit_width=True, ) shell_sec = og.create_section(h=0.2) @@ -90,9 +106,7 @@ def _add_loads(model): for z_pos in model.Mesh_obj.noz[1:-1]: p1 = og.create_load_vertex(x=0, z=z_pos, p=22.4 * kN / m) p2 = og.create_load_vertex(x=L, z=z_pos, p=22.4 * kN / m) - DL.add_load( - og.create_load(loadtype="line", point1=p1, point2=p2, name="SW") - ) + DL.add_load(og.create_load(loadtype="line", point1=p1, point2=p2, name="SW")) model.add_load_case(DL) overlay = og.create_load( @@ -115,8 +129,13 @@ def _add_loads(model): ( "test_beam_oblique.nc", dict( - bridge_name="Beam Oblique (skew 20)", long_dim=L, width=w, skew=20, - num_long_grid=7, num_trans_grid=11, edge_beam_dist=1.0 * m, + bridge_name="Beam Oblique (skew 20)", + long_dim=L, + width=w, + skew=20, + num_long_grid=7, + num_trans_grid=11, + edge_beam_dist=1.0 * m, mesh_type="Oblique", ), _assign_beam_members, @@ -124,8 +143,13 @@ def _add_loads(model): ( "test_beam_ortho.nc", dict( - bridge_name="Beam Ortho (skew 15)", long_dim=L, width=w, skew=15, - num_long_grid=7, num_trans_grid=11, edge_beam_dist=1.0 * m, + bridge_name="Beam Ortho (skew 15)", + long_dim=L, + width=w, + skew=15, + num_long_grid=7, + num_trans_grid=11, + edge_beam_dist=1.0 * m, mesh_type="Ortho", ), _assign_beam_members, @@ -134,10 +158,18 @@ def _add_loads(model): ( "test_beam_link.nc", dict( - bridge_name="Beam Link", long_dim=L, width=w, skew=-12, - num_long_grid=7, num_trans_grid=5, edge_beam_dist=1.0 * m, - mesh_type="Ortho", model_type="beam_link", - beam_width=1.0, web_thick=0.02, centroid_dist_y=0.499, + bridge_name="Beam Link", + long_dim=L, + width=w, + skew=-12, + num_long_grid=7, + num_trans_grid=5, + edge_beam_dist=1.0 * m, + mesh_type="Ortho", + model_type="beam_link", + beam_width=1.0, + web_thick=0.02, + centroid_dist_y=0.499, ), _assign_beam_members, ), @@ -145,11 +177,19 @@ def _add_loads(model): ( "test_shell_beam.nc", dict( - bridge_name="Shell Beam", long_dim=L, width=w, skew=0, - num_long_grid=7, num_trans_grid=11, edge_beam_dist=1.0 * m, - mesh_type="Orth", model_type="shell_beam", - max_mesh_size_z=1.0, max_mesh_size_x=1.0, - offset_beam_y_dist=0.499, beam_width=0.89, + bridge_name="Shell Beam", + long_dim=L, + width=w, + skew=0, + num_long_grid=7, + num_trans_grid=11, + edge_beam_dist=1.0 * m, + mesh_type="Orth", + model_type="shell_beam", + max_mesh_size_z=1.0, + max_mesh_size_x=1.0, + offset_beam_y_dist=0.499, + beam_width=0.89, ), _assign_shell_members, ), @@ -161,7 +201,9 @@ def main(): model_type = kwargs.get("model_type", "beam") mesh_type = kwargs.get("mesh_type", "?") skew = kwargs.get("skew", 0) - print(f"Generating {filename} (type={model_type}, mesh={mesh_type}, skew={skew})...") + print( + f"Generating {filename} (type={model_type}, mesh={mesh_type}, skew={skew})..." + ) model = og.create_grillage(**kwargs) assign_fn(model) model.create_osp_model(pyfile=False) diff --git a/tests/test_load.py b/tests/test_load.py index 45c0a872..ad3d56d2 100644 --- a/tests/test_load.py +++ b/tests/test_load.py @@ -1452,9 +1452,7 @@ def test_dkt_triangle_shape_function_reproduces_linear_fields(): nodal_w = [a * x1 + b * z1 + c, a * x2 + b * z2 + c, a * x3 + b * z3 + c] interpolated_w = ( - sum(n * w for n, w in zip(Nv, nodal_w)) - + a * sum(Nmz) - + b * sum(Nmx) + sum(n * w for n, w in zip(Nv, nodal_w)) + a * sum(Nmz) + b * sum(Nmx) ) assert np.isclose(interpolated_w, a * x + b * z + c) @@ -1479,7 +1477,9 @@ def test_hermite_triangle_region_uses_dkt_style_distribution(bridge_model_42_neg sum(coord[2] for coord in coords) / 3, ] - load_cmd = bridge._assign_load_to_four_node(point=point, mag=1.0, shape_func="hermite") + load_cmd = bridge._assign_load_to_four_node( + point=point, mag=1.0, shape_func="hermite" + ) assert len(load_cmd) == 3 vertical_sum = sum(command[1][2] for command in load_cmd) diff --git a/tests/test_postprocessing.py b/tests/test_postprocessing.py index 56e58eea..e1f9d618 100644 --- a/tests/test_postprocessing.py +++ b/tests/test_postprocessing.py @@ -960,9 +960,7 @@ def test_plot_srf_custom_colorscale(shell_link_bridge): """Custom colorscale is applied to the Mesh3d trace.""" go = pytest.importorskip("plotly.graph_objects") result = _shell_results(shell_link_bridge) - fig = og.plot_srf( - result, "Mx", backend="plotly", show=False, colorscale="Viridis" - ) + fig = og.plot_srf(result, "Mx", backend="plotly", show=False, colorscale="Viridis") mesh = [t for t in fig.data if isinstance(t, go.Mesh3d)][0] assert mesh.colorscale is not None @@ -980,6 +978,8 @@ def test_srf_coexistence_with_bmd(shell_link_bridge): has_mesh = any(isinstance(t, go.Mesh3d) for t in fig.data) has_scatter = any(isinstance(t, go.Scatter3d) for t in fig.data) assert has_mesh and has_scatter + + # Cross-model-type coverage (beam_link, shell_beam) # --------------------------------------------------------------------------- def test_plot_model_beam_link_matplotlib(beam_link_bridge):