Result objects ============== Every solver returns a lightweight :class:`~dataclasses.dataclass` carrying the full-length arrays for every DOF of the original model — even the ones that were prescribed or fell out as rigid-body. That keeps downstream indexing simple: a mode shape of length ``N`` lines up 1-to-1 with :meth:`Model.dof_map`, and slicing by node number Just Works. StaticResult ------------ Returned by :func:`~femorph_solver.solvers.static.solve_static` and :meth:`Model.solve`: .. list-table:: :widths: 25 25 50 :header-rows: 1 * - Field - Shape - Meaning * - ``displacement`` - ``(N,)`` - Global displacement at every DOF; zeros at Dirichlet-fixed DOFs. * - ``reaction`` - ``(N,)`` - Reaction force at constrained DOFs, zeros elsewhere. * - ``free_mask`` - ``(N,)`` bool - ``True`` where the DOF was solved (not Dirichlet, non-trivial diagonal). .. code-block:: python result = solve_static(K, F, prescribed={0: 0.0, 1: 0.0, 2: 0.0}) u_tip = result.displacement[dof_map_tip] R_total_y = result.reaction[1::3].sum() # Σ of all UY reactions ModalResult ----------- Returned by :func:`~femorph_solver.solvers.modal.solve_modal` and :meth:`Model.modal_solve`: .. list-table:: :widths: 25 25 50 :header-rows: 1 * - Field - Shape - Meaning * - ``omega_sq`` - ``(n_modes,)`` - Eigenvalues :math:`\omega^2 = (2\pi f)^2`; numerically negative values are clipped to 0. * - ``frequency`` - ``(n_modes,)`` - Cyclic frequencies :math:`f` in Hz (:math:`\sqrt{\omega^2} / (2\pi)`). * - ``mode_shapes`` - ``(N, n_modes)`` - Each column is a full-length eigenvector. * - ``free_mask`` - ``(N,)`` bool - ``True`` where the DOF participated in the eigenproblem. .. code-block:: python result = solve_modal(K, M, prescribed=fixed, n_modes=10, eigen_solver="arpack", sigma=-1.0) first_bending = result.mode_shapes[:, 6].reshape(-1, 3) # 6 rigid-body modes skipped f1 = result.frequency[6] TransientResult --------------- Returned by :func:`~femorph_solver.solvers.transient.solve_transient` and :meth:`Model.transient_solve`: .. list-table:: :widths: 25 25 50 :header-rows: 1 * - Field - Shape - Meaning * - ``time`` - ``(n_steps + 1,)`` - Time grid including :math:`t = 0`. * - ``displacement`` - ``(n_steps + 1, N)`` - Displacement history. * - ``velocity`` - ``(n_steps + 1, N)`` - Velocity history. * - ``acceleration`` - ``(n_steps + 1, N)`` - Acceleration history. .. code-block:: python result = solve_transient(K, M, F=load, dt=1e-4, n_steps=1000, prescribed=fixed) u_tip_t = result.displacement[:, dof_map_tip] # tip vs time CyclicModalResult ----------------- Returned by :func:`~femorph_solver.solvers.cyclic.solve_cyclic_modal` — one per requested harmonic index. See :doc:`/user-guide/solving/cyclic`. .. list-table:: :widths: 25 25 50 :header-rows: 1 * - Field - Shape - Meaning * - ``harmonic_index`` - ``int`` - The k for this result. * - ``n_sectors`` - ``int`` - Number of sectors in the full rotor. * - ``omega_sq`` / ``frequency`` - ``(n_modes,)`` - Eigenvalues and Hz frequencies at this k. * - ``mode_shapes`` - ``(N, n_modes)`` complex - Base-sector complex mode shape; imaginary part is identically 0 for k=0 and k=N/2. See also -------- - :doc:`strain-stress` — deriving :math:`\varepsilon` and :math:`\sigma` from ``displacement``. - :doc:`visualisation` — getting the arrays into pyvista for plotting. - :doc:`/user-guide/pre-processing/model` — what :meth:`Model.dof_map` returns.