.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "gallery/analyses/cyclic/example_cyclic_mode_family.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code. .. rst-class:: sphx-glr-example-title .. _sphx_glr_gallery_analyses_cyclic_example_cyclic_mode_family.py: Cyclic-symmetry mode family across every harmonic ================================================== A 12-sector annular disk's modal spectrum decomposes per harmonic index :math:`k \in \{0, 1, \ldots, N/2\}`. Each harmonic's lowest non-rigid mode picks out a distinct nodal diameter pattern: :math:`k = 0` is the breathing (axisymmetric) mode, :math:`k = 1` is the rigid-tilt-like mode, :math:`k = 2` is the diametrical-2 (two stationary radial nodes), :math:`k = 3` adds a third nodal diameter, and so on up to :math:`k = N / 2 = 6`, the highest harmonic sustainable on a 12-sector rotor. This example sweeps every harmonic, picks the lowest non- rigid mode at each :math:`k`, and renders all seven side-by- side in a single 4×2 viewport grid — the **cyclic-symmetry mode family** of the disk. References ---------- * Thomas, D. L. (1979) "Dynamics of rotationally periodic structures," *J. Sound Vib.* 66 (4), 585–597. * Bathe, K.-J. (2014) *Finite Element Procedures*, 2nd ed., §10.3.4 (cyclic-symmetry modal). * Wildheim, S. J. (1979) "Excitation of rotationally periodic structures," *J. Appl. Mech.* 46, 891–893. * Singh, M. P. and Vakakis, A. F. (1993) "On the dynamics of cyclic-symmetric structures," *Mechanism and Machine Theory* 28 (5), 627–637 (mode classification by harmonic index). .. GENERATED FROM PYTHON SOURCE LINES 34-43 .. code-block:: Python from __future__ import annotations import numpy as np import pyvista as pv import femorph_solver from femorph_solver import ELEMENTS .. GENERATED FROM PYTHON SOURCE LINES 44-46 Geometry — 12-sector annular disk --------------------------------- .. GENERATED FROM PYTHON SOURCE LINES 46-70 .. code-block:: Python N_SECTORS = 12 ALPHA = 2.0 * np.pi / N_SECTORS R_INNER = 0.30 R_OUTER = 0.55 T_DISK = 0.02 N_T, N_R, N_Z = 6, 4, 1 E = 2.0e11 NU = 0.3 RHO = 7850.0 theta = np.linspace(0.0, ALPHA, N_T + 1) r = np.linspace(R_INNER, R_OUTER, N_R + 1) z = np.linspace(0.0, T_DISK, N_Z + 1) R, T, Z = np.meshgrid(r, theta, z, indexing="ij") X = R * np.cos(T) Y = R * np.sin(T) grid = pv.StructuredGrid(X, Y, Z).cast_to_unstructured_grid() m = femorph_solver.Model.from_grid(grid) m.assign(ELEMENTS.HEX8, material={"EX": E, "PRXY": NU, "DENS": RHO}) .. GENERATED FROM PYTHON SOURCE LINES 71-73 Cyclic-face node pairing ------------------------ .. GENERATED FROM PYTHON SOURCE LINES 73-90 .. code-block:: Python pts = np.asarray(grid.points) node_nums = np.asarray(grid.point_data["ansys_node_num"], dtype=np.int64) angle = np.arctan2(pts[:, 1], pts[:, 0]) tol = 1e-6 low_mask = np.abs(angle) < tol high_mask = np.abs(angle - ALPHA) < tol low_pts, high_pts = pts[low_mask], pts[high_mask] order_low = np.lexsort( np.column_stack([np.linalg.norm(low_pts[:, :2], axis=1), low_pts[:, 2]]).T[::-1] ) order_high = np.lexsort( np.column_stack([np.linalg.norm(high_pts[:, :2], axis=1), high_pts[:, 2]]).T[::-1] ) low_paired = node_nums[low_mask][order_low] high_paired = node_nums[high_mask][order_high] .. GENERATED FROM PYTHON SOURCE LINES 91-93 Run the harmonic sweep ---------------------- .. GENERATED FROM PYTHON SOURCE LINES 93-101 .. code-block:: Python results = m.cyclic_modal_solve( low_face=low_paired, high_face=high_paired, n_sectors=N_SECTORS, n_modes=4, ) .. GENERATED FROM PYTHON SOURCE LINES 102-104 Pick the lowest non-rigid mode per harmonic -------------------------------------------- .. GENERATED FROM PYTHON SOURCE LINES 104-119 .. code-block:: Python family: list[tuple[int, float, np.ndarray]] = [] for r_k in results: freqs = np.asarray(r_k.frequency, dtype=np.float64) shapes = np.asarray(r_k.mode_shapes) keep = np.where(freqs > 1.0)[0] if keep.size: idx = int(keep[0]) phi = shapes[:, idx].reshape(-1, 3) family.append((r_k.harmonic_index, float(freqs[idx]), phi)) print(f"recovered {len(family)} non-rigid modes (one per harmonic):") for k, f, _ in family: print(f" k = {k:>2} f = {f:8.2f} Hz") .. rst-class:: sphx-glr-script-out .. code-block:: none recovered 7 non-rigid modes (one per harmonic): k = 0 f = 207.35 Hz k = 1 f = 307.51 Hz k = 2 f = 86.37 Hz k = 3 f = 240.57 Hz k = 4 f = 456.45 Hz k = 5 f = 731.79 Hz k = 6 f = 1065.60 Hz .. GENERATED FROM PYTHON SOURCE LINES 120-126 Render all harmonics in a single 4 × 2 viewport grid ---------------------------------------------------- For visual consistency, normalise each mode shape to unit peak amplitude so the warp factor reads the same regardless of the eigsolver's mass-orthonormalisation scaling. .. GENERATED FROM PYTHON SOURCE LINES 126-152 .. code-block:: Python n_panels = len(family) rows = (n_panels + 1) // 2 plotter = pv.Plotter(shape=(rows, 2), off_screen=True, window_size=(960, 240 * rows)) for idx, (k, f, phi) in enumerate(family): row, col = divmod(idx, 2) plotter.subplot(row, col) phi_re = np.real(phi) peak = float(np.max(np.abs(phi_re))) or 1.0 warp = grid.copy() warp.points = grid.points + (T_DISK * 4.0 / peak) * phi_re warp["UZ"] = phi_re[:, 2] plotter.add_mesh(grid, style="wireframe", color="grey", opacity=0.4) plotter.add_mesh(warp, scalars="UZ", cmap="coolwarm", show_edges=False, show_scalar_bar=False) plotter.add_text(f"k = {k}: f = {f:.0f} Hz", position="upper_edge", font_size=10) # Hide any unused viewports. for empty_idx in range(n_panels, rows * 2): row, col = divmod(empty_idx, 2) plotter.subplot(row, col) plotter.add_text("(unused)", position="upper_edge", font_size=8, color="white") plotter.link_views() plotter.view_isometric() plotter.show() .. image-sg:: /gallery/analyses/cyclic/images/sphx_glr_example_cyclic_mode_family_001.png :alt: example cyclic mode family :srcset: /gallery/analyses/cyclic/images/sphx_glr_example_cyclic_mode_family_001.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 1.238 seconds) .. _sphx_glr_download_gallery_analyses_cyclic_example_cyclic_mode_family.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: example_cyclic_mode_family.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: example_cyclic_mode_family.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: example_cyclic_mode_family.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_