Cyclic-symmetry analysis ======================== When to use ----------- Cyclic-symmetry analysis exploits **N-fold rotational symmetry** to recover the full-rotor spectrum from a single base-sector model. Use it when: - The structure has identical sectors arranged around an axis (impellers, vaned diffusers, cylinder arrays, reciprocating-engine blocks). - You'd otherwise be solving an N-times-larger problem on the full geometry — cyclic reduces the DOF count by a factor of :math:`N` while recovering exactly the same spectrum. - The full-rotor problem doesn't fit in RAM / wall-time budget but a sector does. For non-cyclic geometries use the standard :doc:`modal` path. Cyclic doesn't apply if the rotor has any deviation from N-fold symmetry (mistuning, intentional asymmetry, broken-blade analysis). Boundary conditions and loads ----------------------------- - **Dirichlet constraints on the sector** — pin the hub / shaft attachment as you would in a regular modal solve. - **Cyclic-pairing constraint** — auto-applied by :class:`~femorph_solver.CyclicModel` from the rotation axis + sector angle. No manual DOF-pair list. - **No applied loads.** Like :doc:`modal`, cyclic-symmetry modal analysis is unforced free vibration. The math (one paragraph) ------------------------ Cyclic-symmetry modal solves the per-harmonic eigenproblem .. math:: \mathbf{K}_k\, \boldsymbol{\phi}_k = \omega_k^{2}\, \mathbf{M}_k\, \boldsymbol{\phi}_k, \qquad k = 0, 1, \ldots, \lfloor N/2 \rfloor, where :math:`\mathbf{K}_k` and :math:`\mathbf{M}_k` are the sector matrices augmented with the harmonic-:math:`k` cyclic-pairing constraint :math:`\mathbf{u}_\text{high} = e^{i\, k\, \alpha}\, \mathbf{R}(\alpha)\, \mathbf{u}_\text{low}`. The Grimes-Lewis-Simon real-2n augmentation (:doc:`/reference/theory/eigenproblem`) keeps each per- harmonic eigenproblem real-symmetric. Sweeping :math:`k` from 0 to :math:`\lfloor N/2 \rfloor` recovers the full- rotor spectrum. Running the solve ----------------- .. code-block:: python cyc = femorph_solver.CyclicModel( m, n_sectors=16, axis="z", ) results = cyc.solve_modal(n_modes=4) ``results`` is a list of :class:`~femorph_solver.solvers.cyclic.CyclicModalResult` instances, one per harmonic 0 … N/2. Each carries: - ``res.harmonic_index`` — the :math:`k` value. - ``res.frequency`` — ``(n_modes,)`` frequencies at this harmonic. - ``res.mode_shapes`` — sector-sized eigenvectors (the full-rotor mode is reconstructed via the cyclic-pairing rule). For a focused recipe, see :ref:`sphx_glr_gallery_analyses_cyclic_example_rotor_sector.py`. Travelling-wave mode pairs -------------------------- At every :math:`k > 0` the eigensolver returns mode shapes in **pairs** at the same frequency. Real and imaginary parts of the complex eigenvector are quarter-period travelling-wave snapshots — the standing-wave / travelling- wave decomposition of Crandall & Mark 1963 §3.5. See :ref:`sphx_glr_gallery_analyses_cyclic_example_cyclic_modes_bladed_rotor.py` for the visualisation. Engine-order resonance check ---------------------------- For a rotor running at angular speed :math:`\Omega`, only mode shapes with harmonic index :math:`k` matching the engine order :math:`m` (modulo N) couple to the excitation (Wildheim 1979). The Campbell-diagram clearance check walks every :math:`(m, k)` pair and flags resonances within a design-margin band. See :ref:`sphx_glr_gallery_tutorials_tutorial_05_cyclic_rotor.py` for the full design check. Common gotchas -------------- - **Cyclic-face auto-detection failure.** The ``CyclicModel`` constructor auto-detects the low / high cyclic faces from the rotation axis + sector angle. If the geometry is mis-aligned with the axis (off-axis centroid) or the sector angle doesn't match the geometry, the auto-detector raises. Pass explicit ``low_face`` / ``high_face`` node-set arrays as a manual override. - **Mistuned rotors** — cyclic-symmetry assumes *exactly* identical sectors. Real rotors have manufacturing variation that breaks the symmetry; the cyclic spectrum is an idealisation. Mistuning analysis is on the planned roadmap. - **Forgetting harmonic 0.** ``k = 0`` modes are the axisymmetric / breathing-mode family. The clearance check must include them — engine-order ``m = N, 2N, 3N, …`` excite ``k = 0`` modes. End-to-end tutorial ------------------- Tutorial 5 walks the cyclic-symmetry workflow end-to-end: :ref:`sphx_glr_gallery_tutorials_tutorial_05_cyclic_rotor.py`. Verification + gallery ---------------------- - :ref:`sphx_glr_gallery_analyses_cyclic_example_rotor_sector.py` — sector-only modal - :ref:`sphx_glr_gallery_analyses_cyclic_example_cyclic_modes_bladed_rotor.py` — travelling-wave pair - :ref:`sphx_glr_gallery_analyses_cyclic_example_cyclic_mode_family.py` — mode-family classification Solver mechanics + performance ------------------------------ For Grimes-Lewis-Simon augmentation details, per-harmonic factor reuse, and the sector-DOF reduction maths, see :doc:`/user-guide/solving/cyclic` — that page is the solver-engineering deep-dive on the same ``CyclicModel.solve_modal()`` invocation.